This commit is contained in:
Anang Yusman 2025-09-02 11:22:35 +08:00
parent 902f734d68
commit 95b6acccd9
12 changed files with 872 additions and 639 deletions

View File

@ -10,7 +10,10 @@ import withReactContent from "sweetalert2-react-content";
import { useDropzone } from "react-dropzone";
import { close, error, loading } from "@/config/swal";
import useDisclosure from "@/components/useDisclosure";
import { createAdvertise } from "@/service/advertisement";
import {
createAdvertise,
createMediaFileAdvertise,
} from "@/service/advertisement";
import { Button } from "@/components/ui/button";
import {
Dialog,
@ -72,24 +75,32 @@ export default function AdvertisePage() {
const onSubmit = async (values: z.infer<typeof createArticleSchema>) => {
loading();
const formData = {
title: values.title,
description: values.description,
placement: placement,
redirectLink: values.url,
const payload = {
Title: values.title,
Description: values.description,
Placement: placement,
RedirectLink: values.url,
};
const res = await createAdvertise(formData);
const res = await createAdvertise(payload);
if (res?.error) {
error(res?.message);
return false;
}
// const idNow = res?.data?.data?.id;
const idNow = res?.data?.data?.id;
if (files.length > 0) {
if (files.length > 0 && idNow) {
const formFiles = new FormData();
formFiles.append("file", files[0]);
// const resFile = await createMediaFileAdvertise(idNow, formFiles);
const resFile = await createMediaFileAdvertise(idNow, formFiles);
if (resFile?.error) {
error(resFile?.message);
return false;
}
}
close();

View File

@ -5,6 +5,7 @@ import Latest from "@/components/landing-page/latest";
import LatestandPopular from "@/components/landing-page/latest-and-popular";
import Navbar from "@/components/landing-page/navbar";
import News from "@/components/landing-page/news";
import { id } from "date-fns/locale";
import Image from "next/image";
export default function Home() {
@ -27,7 +28,7 @@ export default function Home() {
<div className="flex-1">
<Header />
</div>
<Latest />
<Latest id={2} />
<News />
<Author />
<LatestandPopular />

View File

@ -101,6 +101,9 @@ export default function Login() {
Cookies.set("username", profile?.data?.data?.username, {
expires: 1,
});
Cookies.set("fullname", profile?.data?.data?.fullname, {
expires: 1,
});
Cookies.set("urie", profile?.data?.data?.roleId, {
expires: 1,
});
@ -192,16 +195,18 @@ export default function Login() {
<div className="text-center">
<Link href={"/"}>
<div className="bg-white/10 backdrop-blur-sm rounded-2xl p-8 shadow-2xl border border-white/20">
<img
src="/mikul.png"
alt="Mikul News Logo"
<img
src="/mikul.png"
alt="Mikul News Logo"
className="max-w-xs h-auto drop-shadow-lg"
/>
</div>
</Link>
<div className="mt-8 text-white/90">
<h2 className="text-2xl font-bold mb-2">Portal Mikul News</h2>
<p className="text-sm opacity-80">Platform berita terpercaya untuk informasi terkini</p>
<p className="text-sm opacity-80">
Platform berita terpercaya untuk informasi terkini
</p>
</div>
</div>
</div>
@ -216,9 +221,9 @@ export default function Login() {
{/* Mobile Logo */}
<div className="lg:hidden text-center mb-8">
<Link href={"/"}>
<img
src="/mikul.png"
alt="Mikul News Logo"
<img
src="/mikul.png"
alt="Mikul News Logo"
className="h-12 mx-auto"
/>
</Link>
@ -228,17 +233,32 @@ export default function Login() {
<div className="bg-white rounded-2xl shadow-xl p-8 border border-gray-100">
<div className="text-center mb-8">
<div className="w-16 h-16 bg-orange-100 rounded-full flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-orange-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
<svg
className="w-8 h-8 text-orange-600"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
/>
</svg>
</div>
<h2 className="text-2xl font-bold text-gray-900 mb-2">Setup Akun</h2>
<h2 className="text-2xl font-bold text-gray-900 mb-2">
Setup Akun
</h2>
<p className="text-gray-600">Lengkapi informasi email Anda</p>
</div>
<div className="space-y-6">
<div>
<Label htmlFor="old-email" className="text-sm font-medium text-gray-700 mb-2 block">
<Label
htmlFor="old-email"
className="text-sm font-medium text-gray-700 mb-2 block"
>
Email Lama
</Label>
<Input
@ -253,7 +273,10 @@ export default function Login() {
</div>
<div>
<Label htmlFor="new-email" className="text-sm font-medium text-gray-700 mb-2 block">
<Label
htmlFor="new-email"
className="text-sm font-medium text-gray-700 mb-2 block"
>
Email Baru
</Label>
<Input
@ -280,29 +303,60 @@ export default function Login() {
<div className="bg-white rounded-2xl shadow-xl p-8 border border-gray-100">
<div className="text-center">
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
<svg
className="w-8 h-8 text-blue-600"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
</div>
<h2 className="text-2xl font-bold text-gray-900 mb-2">Verifikasi OTP</h2>
<p className="text-gray-600">Masukkan kode OTP yang telah dikirim</p>
<h2 className="text-2xl font-bold text-gray-900 mb-2">
Verifikasi OTP
</h2>
<p className="text-gray-600">
Masukkan kode OTP yang telah dikirim
</p>
</div>
</div>
) : isResetPassword ? (
<div className="bg-white rounded-2xl shadow-xl p-8 border border-gray-100">
<div className="text-center mb-8">
<div className="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
<svg
className="w-8 h-8 text-red-600"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
/>
</svg>
</div>
<h2 className="text-2xl font-bold text-gray-900 mb-2">Reset Password</h2>
<p className="text-gray-600">Masukkan username untuk reset password</p>
<h2 className="text-2xl font-bold text-gray-900 mb-2">
Reset Password
</h2>
<p className="text-gray-600">
Masukkan username untuk reset password
</p>
</div>
<div className="space-y-6">
<div>
<Label htmlFor="reset-username" className="text-sm font-medium text-gray-700 mb-2 block">
<Label
htmlFor="reset-username"
className="text-sm font-medium text-gray-700 mb-2 block"
>
Username
</Label>
<Input
@ -312,9 +366,15 @@ export default function Login() {
placeholder="Masukkan username"
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-red-500 focus:border-red-500 transition-colors"
value={checkUsernameValue}
onChange={(e) => setCheckUsernameValue(e.target.value.trim())}
onPaste={(e) => setCheckUsernameValue(e.currentTarget.value.trim())}
onCopy={(e) => setCheckUsernameValue(e.currentTarget.value.trim())}
onChange={(e) =>
setCheckUsernameValue(e.target.value.trim())
}
onPaste={(e) =>
setCheckUsernameValue(e.currentTarget.value.trim())
}
onCopy={(e) =>
setCheckUsernameValue(e.currentTarget.value.trim())
}
/>
</div>
@ -348,17 +408,34 @@ export default function Login() {
<div className="bg-white rounded-2xl shadow-xl p-8 border border-gray-100">
<div className="text-center mb-8">
<div className="w-16 h-16 bg-emerald-100 rounded-full flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
<svg
className="w-8 h-8 text-emerald-600"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"
/>
</svg>
</div>
<h2 className="text-2xl font-bold text-gray-900 mb-2">Selamat Datang</h2>
<p className="text-gray-600">Portal Mikul News - Platform berita terpercaya</p>
<h2 className="text-2xl font-bold text-gray-900 mb-2">
Selamat Datang
</h2>
<p className="text-gray-600">
Portal Mikul News - Platform berita terpercaya
</p>
</div>
<div className="space-y-6">
<div>
<Label htmlFor="username" className="text-sm font-medium text-gray-700 mb-2 block">
<Label
htmlFor="username"
className="text-sm font-medium text-gray-700 mb-2 block"
>
Username
</Label>
<Input
@ -369,13 +446,18 @@ export default function Login() {
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500 transition-colors"
value={username}
onChange={(e) => setValUsername(e.target.value.trim())}
onPaste={(e) => setValUsername(e.currentTarget.value.trim())}
onPaste={(e) =>
setValUsername(e.currentTarget.value.trim())
}
onCopy={(e) => setValUsername(e.currentTarget.value.trim())}
/>
</div>
<div>
<Label htmlFor="password" className="text-sm font-medium text-gray-700 mb-2 block">
<Label
htmlFor="password"
className="text-sm font-medium text-gray-700 mb-2 block"
>
Password
</Label>
<div className="relative">

View File

@ -4,6 +4,7 @@ import Image from "next/image";
import { usePathname } from "next/navigation";
import { useEffect, useState } from "react";
import news from "../news";
import Link from "next/link";
type Article = {
id: number;
@ -90,39 +91,44 @@ export default function DevelopmentNews() {
{/* Left Content */}
<div className="lg:col-span-2 space-y-10">
{articles.map((item) => (
<div key={item.id} className="flex flex-col md:flex-row gap-6">
{/* Image + Category */}
<div className="relative w-full md:w-1/2 h-64">
<Image
src={item.thumbnailUrl || "/placeholder.png"}
alt={item.title}
fill
className="object-cover rounded"
/>
<span className="absolute top-3 left-3 bg-yellow-400 text-black px-3 py-1 text-xs font-bold">
{item.categories[0]?.title || categoryLabel}
</span>
</div>
{/* Content */}
<div className="flex-1">
<h2 className="text-xl font-bold text-[#16324F] hover:text-green-600 cursor-pointer">
{item.title}
</h2>
<div className="text-sm text-gray-600 mt-2">
BY{" "}
<span className="text-green-600 font-semibold">
{item.createdByName || "Admin"}
</span>{" "}
{new Date(item.createdAt).toLocaleDateString("id-ID")}
<div key={item.id}>
<Link
className="flex flex-col md:flex-row gap-6"
href={`/detail/${item?.id}`}
>
{/* Image + Category */}
<div className="relative w-full md:w-1/2 h-64">
<Image
src={item.thumbnailUrl || "/placeholder.png"}
alt={item.title}
fill
className="object-cover rounded"
/>
<span className="absolute top-3 left-3 bg-yellow-400 text-black px-3 py-1 text-xs font-bold">
{item.categories[0]?.title || categoryLabel}
</span>
</div>
<p className="mt-3 text-gray-700">
{truncateText(item.description, 20)}
</p>
<button className="mt-4 px-4 py-2 border border-gray-400 text-gray-700 hover:bg-black hover:text-white transition">
READ MORE
</button>
</div>
{/* Content */}
<div className="flex-1">
<h2 className="text-xl font-bold text-[#16324F] hover:text-green-600 cursor-pointer">
{item.title}
</h2>
<div className="text-sm text-gray-600 mt-2">
BY{" "}
<span className="text-green-600 font-semibold">
{item.createdByName || "Admin"}
</span>{" "}
{new Date(item.createdAt).toLocaleDateString("id-ID")}
</div>
<p className="mt-3 text-gray-700">
{truncateText(item.description, 20)}
</p>
<button className="mt-4 px-4 py-2 border border-gray-400 text-gray-700 hover:bg-black hover:text-white transition">
READ MORE
</button>
</div>
</Link>
</div>
))}
@ -198,19 +204,24 @@ export default function DevelopmentNews() {
<div className="mt-4 space-y-4">
{articles.map((item) => (
<div key={item.id} className="flex gap-3 items-center">
<Image
src={item.thumbnailUrl || "/no-image.jpg"}
alt={item.title}
width={80}
height={60}
className="object-cover rounded"
/>
<div>
<h3 className="font-semibold text-sm">{item.title}</h3>
<p className="text-xs text-gray-500">
{new Date(item.createdAt).toLocaleDateString()}
</p>
</div>
<Link
className="flex gap-3 items-center"
href={`/detail/${item?.id}`}
>
<Image
src={item.thumbnailUrl || "/no-image.jpg"}
alt={item.title}
width={80}
height={60}
className="object-cover rounded"
/>
<div>
<h3 className="font-semibold text-sm">{item.title}</h3>
<p className="text-xs text-gray-500">
{new Date(item.createdAt).toLocaleDateString()}
</p>
</div>
</Link>
</div>
))}
</div>
@ -220,93 +231,100 @@ export default function DevelopmentNews() {
</h2>
<div className=" w-full">
<div className="relative w-full aspect-video mb-5">
<Image
src={
articles[0]?.thumbnailUrl ||
articles[0]?.files?.[0]?.file_url ||
"/default-image.jpg"
}
alt={"articles[0]?.title"}
fill
sizes="(max-width: 1024px) 100vw, 33vw"
className="object-cover"
/>
<div className="absolute inset-0 bg-black/30" />
<div className="absolute bottom-0.5 left-2 text-white">
<h3 className=" font-semibold text-base mb-1">
{articles[0]?.title}
</h3>
<p className=" text-xs mb-2 flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
</p>
</div>
<Link href={`/detail/${articles[0]?.id}`}>
<Image
src={
articles[0]?.thumbnailUrl ||
articles[0]?.files?.[0]?.file_url ||
"/default-image.jpg"
}
alt={"articles[0]?.title"}
fill
sizes="(max-width: 1024px) 100vw, 33vw"
className="object-cover"
/>
<div className="absolute inset-0 bg-black/30" />
<div className="absolute bottom-0.5 left-2 text-white">
<h3 className=" font-semibold text-base mb-1">
{articles[0]?.title}
</h3>
<p className=" text-xs mb-2 flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
</p>
</div>
</Link>
</div>
<div className="space-y-5">
{articles?.slice(1, 4).map((article, index) => (
<div key={index} className="flex gap-3">
<div className="relative w-[120px] h-[86px] shrink-0">
<Image
src={
article?.thumbnailUrl ||
article?.files?.[0]?.file_url ||
"/default-image.jpg"
}
alt={"article?.title"}
fill
className="object-cover"
/>
</div>
<div>
<h4 className="text-sm font-semibold mb-3">
{article?.title}
</h4>
<p className="text-xs text-gray-500 flex gap-2 items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
<div key={index}>
<Link
className="flex gap-3"
href={`/detail/${article?.id}`}
>
<div className="relative w-[120px] h-[86px] shrink-0">
<Image
src={
article?.thumbnailUrl ||
article?.files?.[0]?.file_url ||
"/default-image.jpg"
}
)}
</p>
</div>
alt={"article?.title"}
fill
className="object-cover"
/>
</div>
<div>
<h4 className="text-sm font-semibold mb-3">
{article?.title}
</h4>
<p className="text-xs text-gray-500 flex gap-2 items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
</p>
</div>
</Link>
</div>
))}
</div>

View File

@ -1,5 +1,6 @@
// components/Footer.tsx
import Image from "next/image";
import Link from "next/link";
export default function Footer() {
@ -8,34 +9,48 @@ export default function Footer() {
<div className="max-w-7xl mx-auto py-10 bg-[#09282C] px-8">
{/* Top Menu Links */}
<div className="flex flex-col md:flex-row justify-center md:justify-between gap-3">
<div className="w-full md:w-2/12">
{/* <div className="w-full md:w-2/12">
<p className="text-sm text-gray-400 mt-5">
© 2025{" "}
<span className="text-xs text-white font-semibold">JNews</span>-
Premium WordPress news & magazine theme by{" "}
<span className="text-white font-semibold">Jegtheme</span>
</p>
</div> */}
<div className="flex items-center overflow-hidden mb-4 py-6 px-8">
<Image
src="/mikul.png"
alt="Background"
width={272}
height={90}
className="w-full md:w-[272px] h-[90px] object-cover border"
priority
/>
</div>
<div className="w-full md:w-6/12">
<h2 className="border-b-2 mb-5"></h2>
<div className="flex items-start flex-wrap justify-start md:justify-start gap-2 md:gap-3 text-xs text-white font-semibold">
{["Beranda ", "Pembangunan", "Kesehatan", "Berita Warga"].map(
(item, idx, arr) => (
<span
key={idx}
className="flex items-center gap-2 whitespace-nowrap"
>
<a href="#" className="hover:underline">
{item}
</a>
{idx !== arr.length - 1 && (
<span className="text-white">/</span>
)}
</span>
)
)}
{[
{ label: "Beranda", href: "#" },
{ label: "Pembangunan", href: "/category/development" },
{ label: "Kesehatan", href: "/category/health" },
{ label: "Berita Warga", href: "/category/citizen-news" },
].map((item, idx, arr) => (
<span
key={idx}
className="flex items-center gap-2 whitespace-nowrap"
>
<a href={item.href} className="hover:underline">
{item.label}
</a>
{idx !== arr.length - 1 && (
<span className="text-white">/</span>
)}
</span>
))}
</div>
</div>
<div className=" w-full md:w-3/12">
<div className="flex flex-col justify-center md:justify-end gap-2 md:gap-3 text-xs text-[#FFFFFF]">
<p className="text-xs font-bold text-red-600 mb-2 md:mb-0 w-10/12 text-start">

View File

@ -142,7 +142,7 @@ export default function HeroNewsSection() {
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/70 via-black/40 to-transparent p-4 flex flex-col justify-end">
<span className="text-xs bg-yellow-400 text-black px-2 py-0.5 inline-block uppercase w-[130px]">
{article.categoryName || "TANPA KATEGORI"}
{article?.categories?.[0]?.title || "TANPA KATEGORI"}
</span>
<h3 className="text-sm font-semibold text-white leading-snug mb-1">
{article.title}

View File

@ -1,6 +1,7 @@
"use client";
import { getListArticle } from "@/service/article";
import Image from "next/image";
import Link from "next/link";
import { useEffect, useState } from "react";
const data1 = {
@ -249,80 +250,82 @@ export default function LatestandPopular() {
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
{currentArticles.map((article, index) => (
<div key={index}>
<div className="relative w-full aspect-video mb-3">
<Image
src={
article?.thumbnailUrl ||
article?.files?.[0]?.file_url ||
"/default-image.jpg"
}
alt={article?.title || "No title"}
fill
sizes="(max-width: 1024px) 100vw, 33vw"
className="object-cover rounded"
/>
<div className="absolute inset-0 bg-black/20" />
<span className="absolute bottom-1 left-1 bg-[#FFC600] text-black text-[11px] px-2 py-1 uppercase">
{article?.categories?.map((cat) => cat.title).join(", ")}
</span>
</div>
<div className="text-black">
<h3 className="font-semibold text-base mb-1">
{article.title}
</h3>
<p className="text-[#999999] text-sm font-serif">
{article.description.length > 100
? `${article.description.slice(0, 100)}...`
: article.description}
</p>
<div className="text-xs text-[#999999] mb-2 flex items-center gap-2">
by{" "}
<span className="text-[#31942E]">
{article.createdByName}
</span>{" "}
|{" "}
<div className="text-xs mt-1.5 text-[#A0A0A0] space-x-2 flex items-center">
{/* Clock Icon + Date */}
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<Link href={`/detail/${article?.id}`}>
<div className="relative w-full aspect-video mb-3">
<Image
src={
article?.thumbnailUrl ||
article?.files?.[0]?.file_url ||
"/default-image.jpg"
}
alt={article?.title || "No title"}
fill
sizes="(max-width: 1024px) 100vw, 33vw"
className="object-cover rounded"
/>
<div className="absolute inset-0 bg-black/20" />
<span className="absolute bottom-1 left-1 bg-[#FFC600] text-black text-[11px] px-2 py-1 uppercase">
{article?.categories?.map((cat) => cat.title).join(", ")}
</span>
</div>
<div className="text-black">
<h3 className="font-semibold text-base mb-1">
{article.title}
</h3>
<p className="text-[#999999] text-sm font-serif">
{article.description.length > 100
? `${article.description.slice(0, 100)}...`
: article.description}
</p>
<div className="text-xs text-[#999999] mb-2 flex items-center gap-2">
by{" "}
<span className="text-[#31942E]">
{article.createdByName}
</span>{" "}
|{" "}
<div className="text-xs mt-1.5 text-[#A0A0A0] space-x-2 flex items-center">
{/* Clock Icon + Date */}
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(article?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
/>
</g>
</svg>{" "}
{new Date(article?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
/>
</svg>{" "}
0
</svg>{" "}
0
</div>
</div>
</div>
</div>
</Link>
</div>
))}
</div>
@ -364,93 +367,100 @@ export default function LatestandPopular() {
</h2>
<div className=" w-full">
<div className="relative w-full aspect-video mb-5">
<Image
src={
articles[0]?.thumbnailUrl ||
articles[0]?.files?.[0]?.file_url ||
"/default-image.jpg"
}
alt={"articles[0]?.title"}
fill
sizes="(max-width: 1024px) 100vw, 33vw"
className="object-cover"
/>
<div className="absolute inset-0 bg-black/30" />
<div className="absolute bottom-0.5 left-2 text-white">
<h3 className=" font-semibold text-base mb-1">
{articles[0]?.title}
</h3>
<p className=" text-xs mb-2 flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
</p>
</div>
<Link href={`/detail/${articles[0]?.id}`}>
<Image
src={
articles[0]?.thumbnailUrl ||
articles[0]?.files?.[0]?.file_url ||
"/default-image.jpg"
}
alt={"articles[0]?.title"}
fill
sizes="(max-width: 1024px) 100vw, 33vw"
className="object-cover"
/>
<div className="absolute inset-0 bg-black/30" />
<div className="absolute bottom-0.5 left-2 text-white">
<h3 className=" font-semibold text-base mb-1">
{articles[0]?.title}
</h3>
<p className=" text-xs mb-2 flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
</p>
</div>
</Link>
</div>
<div className="space-y-5">
{articles?.slice(1, 4).map((article, index) => (
<div key={index} className="flex gap-3">
<div className="relative w-[120px] h-[86px] shrink-0">
<Image
src={
article?.thumbnailUrl ||
article?.files?.[0]?.file_url ||
"/default-image.jpg"
}
alt={"article?.title"}
fill
className="object-cover"
/>
</div>
<div>
<h4 className="text-sm font-semibold mb-3">
{article?.title}
</h4>
<p className="text-xs text-gray-500 flex gap-2 items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
<Link
className="flex gap-3"
href={`/detail/${article?.id}`}
>
<div className="relative w-[120px] h-[86px] shrink-0">
<Image
src={
article?.thumbnailUrl ||
article?.files?.[0]?.file_url ||
"/default-image.jpg"
}
)}
</p>
</div>
alt={"article?.title"}
fill
className="object-cover"
/>
</div>
<div>
<h4 className="text-sm font-semibold mb-3">
{article?.title}
</h4>
<p className="text-xs text-gray-500 flex gap-2 items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
</p>
</div>
</Link>
</div>
))}
</div>

View File

@ -1,7 +1,10 @@
"use client";
import { getAdvertiseById } from "@/service/advertisement";
import { getListArticle } from "@/service/article";
import { id } from "date-fns/locale";
import Image from "next/image";
import Link from "next/link";
import { useEffect, useState } from "react";
const data1 = {
@ -186,7 +189,7 @@ type Article = {
}[];
};
export default function Latest() {
export default function Latest({ id }: { id: number }) {
const [page, setPage] = useState(1);
const [totalPage, setTotalPage] = useState(1);
const [articles, setArticles] = useState<Article[]>([]);
@ -199,6 +202,17 @@ export default function Latest() {
endDate: null,
});
const [data, setData] = useState<any>(null);
useEffect(() => {
const fetchData = async () => {
const res = await getAdvertiseById(Number(id));
const result = res?.data?.data;
setData(result);
};
fetchData();
}, [id]);
useEffect(() => {
initState();
}, [page, showData, startDateValue, selectedCategories]);
@ -235,85 +249,92 @@ export default function Latest() {
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 ">
<div className=" w-full">
<div className="relative w-full aspect-video mb-5">
<Image
src={articles[0]?.files?.[0]?.file_url || "/nodata.png"}
alt={"articles[0]?.title"}
fill
sizes="(max-width: 1024px) 100vw, 33vw"
className="object-cover"
/>
<div className="absolute inset-0 bg-black/20" />
<div className="absolute bottom-0.5 left-2 text-white">
<h3 className=" font-semibold text-base mb-1">
{articles[0]?.title}
</h3>
<p className=" text-xs mb-2 flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
</p>
</div>
<Link href={`/detail/${articles[0]?.id}`}>
<Image
src={articles[0]?.files?.[0]?.file_url || "/nodata.png"}
alt={"articles[0]?.title"}
fill
sizes="(max-width: 1024px) 100vw, 33vw"
className="object-cover"
/>
<div className="absolute inset-0 bg-black/20" />
<div className="absolute bottom-0.5 left-2 text-white">
<h3 className=" font-semibold text-base mb-1">
{articles[0]?.title}
</h3>
<p className=" text-xs mb-2 flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
</p>
</div>
</Link>
</div>
<div className="space-y-5">
{articles.slice(1, 5).map((article, index) => (
<div key={index} className="flex gap-3">
<div className="relative w-[120px] h-[86px] shrink-0">
<Image
src={article?.thumbnailUrl || "/nodata.png"}
alt={"article?.title"}
fill
className="object-cover"
/>
</div>
<div>
<h4 className="text-sm font-semibold mb-3">
{article.title}
</h4>
<p className="text-xs text-gray-500 flex gap-2 articles-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
</p>
</div>
<Link
className="flex gap-3"
href={`/detail/${article?.id}`}
>
<div className="relative w-[120px] h-[86px] shrink-0">
<Image
src={article?.thumbnailUrl || "/nodata.png"}
alt={"article?.title"}
fill
className="object-cover"
/>
</div>
<div>
<h4 className="text-sm font-semibold mb-3">
{article.title}
</h4>
<p className="text-xs text-gray-500 flex gap-2 articles-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
</p>
</div>
</Link>
</div>
))}
</div>
@ -321,93 +342,100 @@ export default function Latest() {
<div className="w-full">
<div className="relative w-full aspect-video mb-5">
<Image
src={
articles[0]?.files?.[0]?.file_url || "/default-image.jpg"
}
alt={"articles[0]?.title"}
fill
sizes="(max-width: 1024px) 100vw, 33vw"
className="object-cover "
/>
<div className="absolute inset-0 bg-black/20" />
<div className="absolute bottom-0.5 left-2 text-white">
<h3 className=" font-semibold text-base mb-1">
{articles[0]?.title}
</h3>
<p className=" text-xs mb-2 flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
</p>
</div>
<Link href={`/detail/${articles[0]?.id}`}>
<Image
src={
articles[0]?.files?.[0]?.file_url || "/default-image.jpg"
}
alt={"articles[0]?.title"}
fill
sizes="(max-width: 1024px) 100vw, 33vw"
className="object-cover "
/>
<div className="absolute inset-0 bg-black/20" />
<div className="absolute bottom-0.5 left-2 text-white">
<h3 className=" font-semibold text-base mb-1">
{articles[0]?.title}
</h3>
<p className=" text-xs mb-2 flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
</p>
</div>
</Link>
</div>
<div className="space-y-5">
{articles.slice(1, 5).map((article, index) => (
<div key={index} className="flex gap-3">
<div className="relative w-[120px] h-[86px] shrink-0">
<Image
src={article?.thumbnailUrl || "/nodata.png"}
alt={"article?.title"}
fill
className="object-cover "
/>
</div>
<div>
<h4 className="text-sm font-semibold mb-3">
{article?.title}
</h4>
<p className="text-xs text-gray-500 flex gap-2 articles-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
</p>
</div>
<Link
className="flex gap-3"
href={`/detail/${article?.id}`}
>
<div className="relative w-[120px] h-[86px] shrink-0">
<Image
src={article?.thumbnailUrl || "/nodata.png"}
alt={"article?.title"}
fill
className="object-cover "
/>
</div>
<div>
<h4 className="text-sm font-semibold mb-3">
{article?.title}
</h4>
<p className="text-xs text-gray-500 flex gap-2 articles-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
</p>
</div>
</Link>
</div>
))}
</div>
</div>
</div>
<div className="relative my-5 max-w-full h-[125px] overflow-hidden flex items-center mx-auto border">
{/* <div className="relative my-5 max-w-full h-[125px] overflow-hidden flex items-center mx-auto border">
<Image
src="/image-kolom.png"
alt="Berita Utama"
@ -434,7 +462,7 @@ export default function Latest() {
</h2>
<div className="w-full border bg-[#FAFAFA] h-[64px] flex justify-center items-center">
<p className="text-center ">No Content Available</p>
</div>
</div> */}
</div>
<aside className="w-full lg:w-[345px]">
@ -446,86 +474,94 @@ export default function Latest() {
<div className="space-y-8">
{popularPosts.slice(1, 5).map((post, index) => (
<div key={index} className="space-y-3">
<div
className={`flex gap-4 ${
post.files?.[0]?.file_url
? "flex-col md:flex-row"
: "flex-col"
}`}
>
<div className="flex-1">
<h3 className="text-base sm:text-lg md:text-sm font-bold leading-tight">
{post?.title}
</h3>
<div className="text-xs mt-1.5 text-[#A0A0A0] space-x-2 flex items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<Link href={`/detail/${post?.id}`}>
<div
className={`flex gap-4 ${
post.files?.[0]?.file_url
? "flex-col md:flex-row"
: "flex-col"
}`}
>
<div className="flex-1">
<h3 className="text-base sm:text-lg md:text-sm font-bold leading-tight">
{post?.title}
</h3>
<div className="text-xs mt-1.5 text-[#A0A0A0] space-x-2 flex items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
fill="currentColor"
d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2m0 2a8 8 0 1 0 0 16a8 8 0 0 0 0-16m0 2a1 1 0 0 1 .993.883L13 7v4.586l2.707 2.707a1 1 0 0 1-1.32 1.497l-.094-.083l-3-3a1 1 0 0 1-.284-.576L11 12V7a1 1 0 0 1 1-1"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
/>
</g>
</svg>{" "}
{new Date(articles[0]?.createdAt).toLocaleDateString(
"id-ID",
{
day: "numeric",
month: "long",
year: "numeric",
}
)}
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
/>
</svg>{" "}
0
</div>
</div>
{post.thumbnailUrl && (
<div className="w-full md:w-1/3 relative">
<div className="w-full aspect-[4/3] sm:w-[260px] sm:h-[157px] md:max-w-[320px] md:h-[220px] lg:max-w-[120px] lg:h-[87px] relative ml-auto">
<Image
src={post?.thumbnailUrl}
alt={"post?.title"}
fill
className="object-cover rounded"
/>
</svg>{" "}
0
</div>
</div>
)}
</div>
<p className="text-[13px] text-[#3D4248] line-clamp-2 mb-3">
{post.description}
</p>
{post.thumbnailUrl && (
<div className="w-full md:w-1/3 relative">
<div className="w-full aspect-[4/3] sm:w-[260px] sm:h-[157px] md:max-w-[320px] md:h-[220px] lg:max-w-[120px] lg:h-[87px] relative ml-auto">
<Image
src={post?.thumbnailUrl}
alt={"post?.title"}
fill
className="object-cover rounded"
/>
</div>
</div>
)}
</div>
<p className="text-[13px] text-[#3D4248] line-clamp-2 mb-3">
{post.description}
</p>
</Link>
</div>
))}
</div>
</div>
<div className="relative w-[1111px] max-w-full h-[300px] overflow-hidden flex items-center mx-auto border my-6 rounded">
<Image
src="/kolom.png"
alt="Berita Utama"
fill
className="object-contain rounded"
/>
{data?.contentFileUrl ? (
<Image
src={data.contentFileUrl}
alt={data?.title || "Berita Utama"}
fill
className="object-cover rounded"
/>
) : (
<div className="w-full h-full flex items-center justify-center text-gray-400">
Loading...
</div>
)}
</div>
</aside>
</div>

View File

@ -2,6 +2,7 @@
import { getListArticle } from "@/service/article";
import { Clock } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
import { useEffect, useState } from "react";
type postsData = {
@ -60,52 +61,52 @@ export default function Beranda() {
return (
<section className="max-w-7xl mx-auto px-10 py-5 bg-white">
<div className="flex flex-col md:flex-row md:items-center md:justify-between mb-8 pb-1 gap-2 bg-white border-b-2 pt-2 ">
<h2 className="text-sm font-bold">Football</h2>
<h2 className="text-sm font-bold">Pembangunan</h2>
<div className="flex flex-wrap gap-2 text-xs text-gray-600">
<button className="hover:text-green-500">ALL</button>
<button className="hover:text-green-500">Premier League</button>
<button className="hover:text-green-500">The Presidents Cup</button>
<button className="hover:text-green-500">Super Bowl</button>
<button className="hover:text-green-500">Pembangunan</button>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 md:gap-10 pt-4 ">
{posts.slice(1, 5).map((posts, index) => (
<div key={index} className="bg-white overflow-hidden">
<div className="relative">
<Image
src={
posts.thumbnailUrl ||
posts?.files?.[0]?.file_url ||
"/default-image.jpg"
}
alt={posts.title}
width={500}
height={300}
className="w-full h-52 md:h-56 object-cover"
/>
<div className="absolute inset-0 bg-black/20" />
<span className="absolute top-1 left-1 bg-[#FFC600] text-black text-[11px] px-2 py-1 uppercase">
{posts.categories?.[0]?.title}
</span>
<div className="p-3 md:p-2 absolute bottom-1 left-1 text-white">
<h3 className="font-bold text-sm md:text-base leading-snug mb-1">
{posts.title}
</h3>
<Link href={`/detail/${posts?.id}`}>
<div className="relative">
<Image
src={
posts.thumbnailUrl ||
posts?.files?.[0]?.file_url ||
"/default-image.jpg"
}
alt={posts.title}
width={500}
height={300}
className="w-full h-52 md:h-56 object-cover"
/>
<div className="absolute inset-0 bg-black/20" />
<span className="absolute top-1 left-1 bg-[#FFC600] text-black text-[11px] px-2 py-1 uppercase">
{posts.categories?.[0]?.title}
</span>
<div className="p-3 md:p-2 absolute bottom-1 left-1 text-white">
<h3 className="font-bold text-sm md:text-base leading-snug mb-1">
{posts.title}
</h3>
<div className="text-xs flex items-center gap-2">
<Clock className="w-3 h-3 " />
<span className=" ">
{posts.createdByName} -{" "}
{new Date(posts.createdAt).toLocaleDateString("id-ID", {
day: "numeric",
month: "long",
year: "numeric",
})}
</span>
<div className="text-xs flex items-center gap-2">
<Clock className="w-3 h-3 " />
<span className=" ">
{posts.createdByName} -{" "}
{new Date(posts.createdAt).toLocaleDateString("id-ID", {
day: "numeric",
month: "long",
year: "numeric",
})}
</span>
</div>
</div>
</div>
</div>
</Link>
</div>
))}
</div>

View File

@ -126,7 +126,10 @@ export const RetractingSidebar = ({
className="hidden md:flex fixed top-4 left-20 z-40 p-3 bg-white rounded-xl shadow-lg border border-slate-200/60 hover:shadow-xl transition-all duration-200 hover:bg-slate-50"
onClick={() => updateSidebarData(true)}
>
<Icon icon="heroicons:chevron-right" className="w-5 h-5 text-slate-600" />
<Icon
icon="heroicons:chevron-right"
className="w-5 h-5 text-slate-600"
/>
</motion.button>
)}
</AnimatePresence>
@ -142,7 +145,10 @@ export const RetractingSidebar = ({
className="md:hidden fixed top-4 left-4 z-50 p-3 bg-white dark:bg-slate-800 rounded-xl shadow-lg border border-slate-200/60 dark:border-slate-700/60 hover:shadow-xl transition-all duration-200"
onClick={() => updateSidebarData(true)}
>
<Icon icon="heroicons:chevron-right" className="w-6 h-6 text-slate-600" />
<Icon
icon="heroicons:chevron-right"
className="w-6 h-6 text-slate-600"
/>
</motion.button>
)}
</AnimatePresence>
@ -183,6 +189,17 @@ const SidebarContent = ({
updateSidebarData: (newData: boolean) => void;
}) => {
const { theme, toggleTheme } = useTheme();
const [username, setUsername] = useState("");
useEffect(() => {
// Ambil cookie secara client-side
const cookies = document.cookie.split("; ").reduce((acc: any, cur) => {
const [key, value] = cur.split("=");
acc[key] = value;
return acc;
}, {});
setUsername(cookies.username || "Guest");
}, []);
return (
<div className="flex flex-col h-full">
{/* SCROLLABLE TOP SECTION */}
@ -193,7 +210,10 @@ const SidebarContent = ({
<div className="flex items-center justify-between px-4 py-6">
<Link href="/" className="flex items-center space-x-3">
<div className="relative">
<img src="/mikul.png" className="w-10 h-10 rounded-lg shadow-sm" />
<img
src="/mikul.png"
className="w-10 h-10 rounded-lg shadow-sm"
/>
<div className="absolute -inset-1 bg-gradient-to-r from-blue-500 to-purple-500 rounded-lg opacity-20 blur-sm"></div>
</div>
{open && (
@ -210,7 +230,7 @@ const SidebarContent = ({
</motion.div>
)}
</Link>
{open && (
<motion.button
initial={{ opacity: 0, scale: 0.8 }}
@ -219,9 +239,9 @@ const SidebarContent = ({
className="p-2 rounded-lg hover:bg-slate-100 transition-colors duration-200 group"
onClick={() => updateSidebarData(false)}
>
<Icon
icon="heroicons:chevron-left"
className="w-5 h-5 text-slate-500 group-hover:text-slate-700 transition-colors"
<Icon
icon="heroicons:chevron-left"
className="w-5 h-5 text-slate-500 group-hover:text-slate-700 transition-colors"
/>
</motion.button>
)}
@ -230,7 +250,7 @@ const SidebarContent = ({
{/* Navigation Sections */}
<div className="space-y-3 px-3 pb-6">
{sidebarSections.map((section, sectionIndex) => (
<motion.div
<motion.div
key={section.title}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
@ -238,7 +258,7 @@ const SidebarContent = ({
className="space-y-3"
>
{open && (
<motion.h3
<motion.h3
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.2 + sectionIndex * 0.1 }}
@ -271,32 +291,34 @@ const SidebarContent = ({
{/* <div className="px-3 pb-2">
<div className="h-px bg-gradient-to-r from-transparent via-slate-300 to-transparent"></div>
</div> */}
{/* Theme Toggle */}
<div className="px-3 pt-1">
<motion.button
onClick={toggleTheme}
className={`relative flex h-12 w-full items-center rounded-xl transition-all duration-200 cursor-pointer group ${
open ? 'px-3' : 'justify-center'
open ? "px-3" : "justify-center"
} ${
theme === 'dark'
? "bg-gradient-to-r from-emerald-500 to-green-500 text-white shadow-lg shadow-emerald-500/25"
theme === "dark"
? "bg-gradient-to-r from-emerald-500 to-green-500 text-white shadow-lg shadow-emerald-500/25"
: "text-slate-600 hover:bg-gradient-to-r hover:from-slate-100 hover:to-slate-200/50 hover:text-slate-800 dark:text-slate-300 dark:hover:bg-slate-700/50"
}`}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
<motion.div
<motion.div
className={`h-full flex items-center justify-center ${
open ? "w-12" : "w-full"
}`}
>
<div className={`text-lg transition-all duration-200 ${
theme === 'dark'
? "text-white"
: "text-slate-500 group-hover:text-slate-700 dark:text-slate-400 dark:group-hover:text-slate-200"
}`}>
{theme === 'dark' ? (
<div
className={`text-lg transition-all duration-200 ${
theme === "dark"
? "text-white"
: "text-slate-500 group-hover:text-slate-700 dark:text-slate-400 dark:group-hover:text-slate-200"
}`}
>
{theme === "dark" ? (
<Icon icon="solar:sun-bold" className="text-lg" />
) : (
<Icon icon="solar:moon-bold" className="text-lg" />
@ -305,15 +327,17 @@ const SidebarContent = ({
</motion.div>
{open && (
<motion.span
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.1, duration: 0.2 }}
<motion.span
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.1, duration: 0.2 }}
className={`text-sm font-medium transition-colors duration-200 ${
theme === 'dark' ? "text-white" : "text-slate-700 dark:text-slate-300"
theme === "dark"
? "text-white"
: "text-slate-700 dark:text-slate-300"
}`}
>
{theme === 'dark' ? 'Light Mode' : 'Dark Mode'}
{theme === "dark" ? "Light Mode" : "Dark Mode"}
</motion.span>
)}
</motion.button>
@ -334,13 +358,19 @@ const SidebarContent = ({
</div>
{/* User Profile */}
<motion.div
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.4 }}
className="px-3 py-3 border-t border-slate-200/60"
>
<div className={`${open ? 'flex items-center space-x-3' : 'flex items-center justify-center'} p-3 rounded-xl bg-gradient-to-r from-slate-50 to-slate-100/50 hover:from-slate-100 hover:to-slate-200/50 transition-all duration-200 cursor-pointer group`}>
<div
className={`${
open
? "flex items-center space-x-3"
: "flex items-center justify-center"
} p-3 rounded-xl bg-gradient-to-r from-slate-50 to-slate-100/50 hover:from-slate-100 hover:to-slate-200/50 transition-all duration-200 cursor-pointer group`}
>
<div className="relative">
<div className="w-10 h-10 rounded-full bg-gradient-to-r from-blue-500 to-purple-500 flex items-center justify-center text-white font-semibold text-sm shadow-lg">
A
@ -348,13 +378,15 @@ const SidebarContent = ({
<div className="absolute -bottom-1 -right-1 w-4 h-4 bg-green-500 rounded-full border-2 border-white"></div>
</div>
{open && (
<motion.div
<motion.div
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.5 }}
className="flex-1 min-w-0"
>
<p className="text-sm font-medium text-slate-800 truncate">admin-mabes</p>
<p className="text-sm font-medium text-slate-800 truncate">
{username}
</p>
<Link href="/auth">
<p className="text-xs text-slate-500 hover:text-blue-600 transition-colors duration-200">
Sign out
@ -394,6 +426,17 @@ const SidebarContent = ({
const Sidebar = () => {
const [open, setOpen] = useState(true);
const pathname = usePathname();
const [username, setUsername] = useState("");
useEffect(() => {
// Ambil cookie secara client-side
const cookies = document.cookie.split("; ").reduce((acc: any, cur) => {
const [key, value] = cur.split("=");
acc[key] = value;
return acc;
}, {});
setUsername(cookies.username || "Guest");
}, []);
return (
<motion.nav
@ -512,7 +555,7 @@ const Sidebar = () => {
</g>
</svg>
<div className="flex flex-col gap-0.5 text-xs">
<p>admin-mabes</p>
<p>{username}</p>
<p className="underline">Logout</p>
</div>
</div>

View File

@ -1,5 +1,9 @@
import Cookies from "js-cookie";
import { httpDeleteInterceptor, httpPostInterceptor, httpPutInterceptor } from "./http-config/http-interceptor-services";
import {
httpDeleteInterceptor,
httpPostInterceptor,
httpPutInterceptor,
} from "./http-config/http-interceptor-services";
import { httpGet } from "./http-config/http-base-services";
const token = Cookies.get("access_token");
@ -8,16 +12,19 @@ export async function createAdvertise(data: any) {
const pathUrl = `/advertisement`;
return await httpPostInterceptor(pathUrl, data);
}
export async function createMediaFileAdvertise(id: string | number, data: any) {
const headers = {
"content-type": "multipart/form-data",
"Content-Type": "multipart/form-data",
};
const pathUrl = `/advertisement/upload/${id}`;
return await httpPostInterceptor(pathUrl, data, headers);
}
export async function getAdvertise(data: any) {
const pathUrl = `/advertisement?page=${data?.page || 1}&limit=${data?.limit || ""}&placement=${data?.placement || ""}&isPublish=${data.isPublish || ""}`;
const pathUrl = `/advertisement?page=${data?.page || 1}&limit=${
data?.limit || ""
}&placement=${data?.placement || ""}&isPublish=${data.isPublish || ""}`;
return await httpGet(pathUrl);
}

View File

@ -1,6 +1,12 @@
import Cookies from "js-cookie";
import { httpGet, httpPost } from "./http-config/http-base-services";
import { httpDeleteInterceptor, httpGetInterceptor, httpPostInterceptor, httpPutInterceptor } from "./http-config/http-interceptor-services";
import {
httpDeleteInterceptor,
httpGetInterceptor,
httpPostInterceptor,
httpPutInterceptor,
} from "./http-config/http-interceptor-services";
import { hex } from "framer-motion";
const token = Cookies.get("access_token");
const id = Cookies.get("uie");
@ -32,12 +38,12 @@ export async function getDetailMasterUsers(id: string) {
}
export async function editMasterUsers(data: any, id: string) {
const pathUrl = `/users/${id}`
const pathUrl = `/users/${id}`;
return await httpPutInterceptor(pathUrl, data);
}
export async function deleteMasterUser(id: string) {
const pathUrl = `/users/${id}`
const pathUrl = `/users/${id}`;
return await httpDeleteInterceptor(pathUrl);
}
@ -49,7 +55,7 @@ export async function postSignIn(data: any) {
export async function getProfile(token?: string) {
const headers = {
"content-type": "application/json",
"Authorization": `Bearer ${token}`,
Authorization: `Bearer ${token}`,
};
const pathUrl = `/users/info`;
return await httpGet(pathUrl, headers);
@ -60,7 +66,7 @@ export async function updateProfile(data: any) {
return await httpPutInterceptor(pathUrl, data);
}
export async function savePassword(data: any) {
const pathUrl = `/users/save-password`
const pathUrl = `/users/save-password`;
return await httpPostInterceptor(pathUrl, data);
}
@ -84,8 +90,8 @@ export async function otpRequest(email: string, name: string) {
}
export async function otpValidation(email: string, otpCode: string) {
const pathUrl = `/users/otp-validation`
return await httpPost(pathUrl, { email, otpCode });
const pathUrl = `/users/otp-validation`;
return await httpPost(pathUrl, { email, otpCode });
}
export async function postArticleComment(data: any) {
@ -111,11 +117,14 @@ export async function getArticleComment(id: string) {
}
export async function deleteArticleComment(id: number) {
const pathUrl = `/article-comments/${id}`
const pathUrl = `/article-comments/${id}`;
return await httpDeleteInterceptor(pathUrl);
}
export async function getCsrfToken() {
const pathUrl = "csrf-token";
return httpGet(pathUrl);
}
const headers = {
"content-type": "application/json",
};
return httpGet(pathUrl, headers);
}