diff --git a/app/Http/Controllers/BlogController.php b/app/Http/Controllers/BlogController.php
index 68eb947..9ee6bab 100644
--- a/app/Http/Controllers/BlogController.php
+++ b/app/Http/Controllers/BlogController.php
@@ -20,7 +20,7 @@ public function index()
// 'message' => 'Blog list fetched successfully',
// 'datas' => $blogs,
// ]);
- return inertia('Blogs/Index', [
+ return inertia('Blog/Index', [
'blogs' => $blogs,
]);
}
@@ -47,13 +47,14 @@ public function store(Request $request)
public function show(string $slug)
{
$blog = Blog::where('slug', $slug)->firstOrFail();
- // return response()->json([
- // 'success' => true,
- // 'message' => 'Blog detail fetched successfully',
- // 'datas' => $blog,
- // ]);
- return inertia('Blogs/Show', [
+ $blogs = Blog::select('title', 'slug', 'cover')
+ ->where('id', '!=', $blog->id)
+ ->latest()
+ ->take(5)
+ ->get();
+ return inertia('Blog/Show', [
'blog' => $blog,
+ 'blogs' => $blogs,
]);
}
diff --git a/resources/js/Components/Cards/HorizontalArticle.tsx b/resources/js/Components/Cards/HorizontalArticle.tsx
index f58b9ee..40226db 100644
--- a/resources/js/Components/Cards/HorizontalArticle.tsx
+++ b/resources/js/Components/Cards/HorizontalArticle.tsx
@@ -1,4 +1,5 @@
import { Article } from '@/models/Article';
+import { Blog } from '@/models/Blog';
import { formatDateWithTime } from '@/tools/formatDate';
import { Link } from '@inertiajs/react';
import { IconRocketFill } from 'justd-icons';
@@ -6,28 +7,35 @@ import { IconRocketFill } from 'justd-icons';
export default function HorizontalArticleCardComponent({
props,
}: {
- props: Article;
+ props: Article | Blog;
}) {
+ // Cek apakah props berasal dari Article (punya course)
+ const isArticle = (props as Article).course !== undefined;
+
+ // Tentukan URL dinamis berdasarkan tipe
+ const url = isArticle ? `/articles/${props.slug}` : `/blogs/${props.slug}`;
+
return (
- {props.course ? (
+ {/* Jika article, tampilkan informasi course */}
+ {isArticle && (props as Article).course ? (
- {props.course.visibility == 'private' && (
+ {(props as Article).course.visibility === 'private' && (
)}
- {props.course.title}
+ {(props as Article).course.title}
🞄
@@ -45,18 +53,18 @@ export default function HorizontalArticleCardComponent({
) : (
- ''
- )}
-
- {props.title}
-
- {!props.course ? (
+ // Jika Blog (tidak punya course)
{formatDateWithTime(props.created_at || '')}
- ) : (
- ''
)}
+
+ {/* Judul */}
+
+ {props.title}
+
+
+ {/* Deskripsi */}
{props.description}
diff --git a/resources/js/Components/Cards/SimpleBlog.tsx b/resources/js/Components/Cards/SimpleBlog.tsx
new file mode 100644
index 0000000..0c75a51
--- /dev/null
+++ b/resources/js/Components/Cards/SimpleBlog.tsx
@@ -0,0 +1,34 @@
+import { Blog } from '@/models/Blog';
+import { Link } from '@inertiajs/react';
+
+export default function SimpleBlogCardComponent({
+ props,
+ withoutBorder = false,
+}: {
+ props: Blog;
+ withoutBorder?: boolean;
+}) {
+ return (
+
+

+
+
+ );
+}
diff --git a/resources/js/Components/Navbar.tsx b/resources/js/Components/Navbar.tsx
index fa7183e..3736b58 100644
--- a/resources/js/Components/Navbar.tsx
+++ b/resources/js/Components/Navbar.tsx
@@ -16,6 +16,7 @@ export default function NavbarComponent() {
{ name: 'Home', href: '/' },
{ name: 'Course', href: '/courses' },
{ name: 'Article', href: '/articles' },
+ { name: 'Blog', href: '/blogs' },
{ name: 'Video', href: '/videos/pendahuluan' },
];
diff --git a/resources/js/Pages/Blog/Index.tsx b/resources/js/Pages/Blog/Index.tsx
new file mode 100644
index 0000000..549d628
--- /dev/null
+++ b/resources/js/Pages/Blog/Index.tsx
@@ -0,0 +1,134 @@
+import BannerHorizontalComponent from '@/Components/Banners/Horizontal';
+import BreadcrumbComponent from '@/Components/Breadcrumb';
+import HorizontalArticleCardComponent from '@/Components/Cards/HorizontalArticle';
+import FooterComponent from '@/Components/Footer';
+import NavbarComponent from '@/Components/Navbar';
+import { Blog } from '@/models/Blog';
+import SideBlogsSection from '@/Sections/SideBlogs';
+import { PaginatedResponse } from '@/types/PaginateResponse';
+import { Inertia, Method } from '@inertiajs/inertia';
+import { Head, router, usePage } from '@inertiajs/react';
+
+import 'glider-js/glider.min.css';
+import { IconChevronLeft, IconChevronRight } from 'justd-icons';
+import { useEffect, useState } from 'react';
+
+export default function BlogIndexPage({
+ blogs,
+}: {
+ blogs: PaginatedResponse
;
+}) {
+ const { props } = usePage();
+ const searchQuery = (props as any).search || '';
+ const [query, setQuery] = useState(searchQuery);
+
+ const handleSearch = (e: React.KeyboardEvent) => {
+ if (e.key === 'Enter') {
+ Inertia.visit(route('blogs.index'), {
+ method: Method.GET,
+ data: { q: query },
+ preserveState: true,
+ preserveScroll: true,
+ replace: true,
+ only: ['blogs'],
+ });
+ }
+ };
+
+ useEffect(() => {
+ setQuery(searchQuery);
+ console.log('search q', searchQuery);
+ }, [searchQuery]);
+
+ const goToPage = (url: string | null) => {
+ if (url) {
+ router.visit(url);
+ }
+ };
+
+ const goToPageNumber = (page: number) => {
+ router.visit(`${blogs.path}?page=${page}`);
+ };
+
+ return (
+ <>
+
+
+
+
+ {/* Background shapes */}
+
+
+
+
+
+
+
+
+
+ {/* Daftar Blog */}
+
+ {blogs.data.map((blog, index) => (
+
+ ))}
+
+
+ {/* Pagination */}
+
+
+
+ {Array.from({ length: blogs.last_page }, (_, i) => i + 1).map(
+ (page) => (
+
+ ),
+ )}
+
+
+
+
+
+ {/* Sidebar */}
+
+
+
+
+ >
+ );
+}
diff --git a/resources/js/Pages/Blog/Show.tsx b/resources/js/Pages/Blog/Show.tsx
new file mode 100644
index 0000000..309677a
--- /dev/null
+++ b/resources/js/Pages/Blog/Show.tsx
@@ -0,0 +1,74 @@
+import FooterComponent from '@/Components/Footer';
+import NavbarComponent from '@/Components/Navbar';
+import { Head } from '@inertiajs/react';
+
+import BreadcrumbComponent from '@/Components/Breadcrumb';
+import { Blog } from '@/models/Blog';
+import SideBlogsSection from '@/Sections/SideBlogs';
+import strLimit from '@/tools/strLimit';
+import '../../../css/bodyContent.css';
+import { useEffect } from 'react';
+
+export default function BlogShowPage({
+ blog,
+ blogs,
+}: {
+ blog: Blog;
+ blogs: Blog[];
+}) {
+
+ useEffect(() => {
+ console.log('blogs', blogs);
+ }, [blogs]);
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {blog.title}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/resources/js/Pages/Course/Index.tsx b/resources/js/Pages/Course/Index.tsx
index 5ec69b0..c365d0f 100644
--- a/resources/js/Pages/Course/Index.tsx
+++ b/resources/js/Pages/Course/Index.tsx
@@ -58,7 +58,7 @@ export default function CourseIndexPage({
/>
))}
-
+
{course.title}
diff --git a/resources/js/Pages/TooltipDetail/Show.tsx b/resources/js/Pages/TooltipDetail/Show.tsx
index 721f7db..7e1bda5 100644
--- a/resources/js/Pages/TooltipDetail/Show.tsx
+++ b/resources/js/Pages/TooltipDetail/Show.tsx
@@ -35,7 +35,7 @@ export default function Show({ glosary }: GlosaryDetailProps) {
+
+ // Blog Terbaru
+
+
+ {blogs.map(
+ (blog, index) =>
+ index < 5 && (
+
+
+ {blog.title}
+
+
+ ),
+ )}
+
+
+
+ // Sorotan
+
+ {blogs.map(
+ (blog, index) =>
+ index < 2 && (
+
+ ),
+ )}
+
+
+ );
+}
diff --git a/resources/js/models/Blog.ts b/resources/js/models/Blog.ts
new file mode 100644
index 0000000..9805555
--- /dev/null
+++ b/resources/js/models/Blog.ts
@@ -0,0 +1,9 @@
+export type Blog = {
+ id: string;
+ slug: string;
+ title: string;
+ description: string;
+ cover: string;
+ body: string;
+ created_at?: string;
+};
diff --git a/routes/web.php b/routes/web.php
index f3175a1..465714c 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -27,6 +27,8 @@
Route::resource('/courses', CourseController::class);
Route::resource('/videos', VideoController::class);
Route::get('/glosarium/{slug}', [GlossaryController::class, 'show'])->name('glosarium.show');
+Route::get('/blogs', [BlogController::class, 'index'])->name('blogs.index');
+Route::get('/blogs/{slug}', [BlogController::class, 'show'])->name('blogs.show');
Route::resource('/blogs', BlogController::class);
// Route::get('/glosarium', [GlossaryController::class, 'index'])->name('glosarium.index');