From a36f2297eae7fcbf0283dfe2ea1db0066cd617e8 Mon Sep 17 00:00:00 2001 From: Anang Yusman Date: Sun, 12 Oct 2025 20:45:30 +0800 Subject: [PATCH] update --- components/details/details-content.tsx | 73 ++++++++++++++-- .../form/article/create-article-form.tsx | 72 +++++++++++++--- components/landing-page/breaking-news.tsx | 71 ++++++++++++++-- components/landing-page/news.tsx | 84 +++++++++++++++---- components/landing-page/opini.tsx | 72 ++++++++++++++-- components/landing-page/popular-news.tsx | 72 ++++++++++++++-- 6 files changed, 387 insertions(+), 57 deletions(-) diff --git a/components/details/details-content.tsx b/components/details/details-content.tsx index fc856c5..c578d27 100644 --- a/components/details/details-content.tsx +++ b/components/details/details-content.tsx @@ -7,6 +7,7 @@ import { close, loading } from "@/config/swal"; import { useParams } from "next/navigation"; import Author from "../landing-page/author"; import { Link2, MailIcon } from "lucide-react"; +import { getAdvertise } from "@/service/advertisement"; type TabKey = "trending" | "comments" | "latest"; @@ -33,6 +34,15 @@ interface CategoryType { value: number; } +type Advertise = { + id: number; + title: string; + description: string; + placement: string; + contentFileUrl: string; + redirectLink: string; +}; + export default function DetailContent() { const params = useParams(); const id = params?.id; @@ -69,6 +79,36 @@ export default function DetailContent() { { id: "latest", label: "Latest" }, ]; + const [bannerAd, setBannerAd] = useState(null); + + useEffect(() => { + initStateAdver(); + }, []); + + async function initStateAdver() { + const req = { + limit: 100, + page: 1, + sort: "desc", + sortBy: "created_at", + isPublish: true, + }; + + try { + const res = await getAdvertise(req); + const data: Advertise[] = res?.data?.data || [1]; + + // filter iklan dengan placement = "banner" + const banner = data.find((ad) => ad.placement === "jumbotron"); + + if (banner) { + setBannerAd(banner); + } + } catch (err) { + console.error("Error fetching advertisement:", err); + } + } + useEffect(() => { fetchTabArticles(); }, [activeTab]); @@ -519,13 +559,32 @@ export default function DetailContent() {
- Iklan + {bannerAd ? ( + +
+ {bannerAd.title +
+
+ ) : ( + Berita Utama + )} diff --git a/components/form/article/create-article-form.tsx b/components/form/article/create-article-form.tsx index 4ef5c90..a8fbe78 100644 --- a/components/form/article/create-article-form.tsx +++ b/components/form/article/create-article-form.tsx @@ -9,7 +9,7 @@ import { CloudUploadIcon, TimesIcon } from "@/components/icons"; import Image from "next/image"; import ReactSelect from "react-select"; import makeAnimated from "react-select/animated"; -import { htmlToString } from "@/utils/global"; +import { convertDateFormatNoTime, htmlToString } from "@/utils/global"; import { close, error, loading, successToast } from "@/config/swal"; import { useRouter } from "next/navigation"; import Link from "next/link"; @@ -44,6 +44,13 @@ import GenerateSingleArticleForm from "./generate-ai-single-form"; import GenerateContentRewriteForm from "./generate-ai-content-rewrite-form"; import { Textarea } from "@/components/ui/textarea"; import { Badge } from "@/components/ui/badge"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { Calendar } from "@/components/ui/calendar"; +import DatePicker from "react-datepicker"; const CustomEditor = dynamic( () => { @@ -121,8 +128,8 @@ export default function CreateArticleForm() { "publish" ); const [isScheduled, setIsScheduled] = useState(false); - - const [startDateValue, setStartDateValue] = useState(null); + const [startDateValue, setStartDateValue] = useState(); + const [startTimeValue, setStartTimeValue] = useState(""); const { getRootProps, getInputProps } = useDropzone({ onDrop: (acceptedFiles) => { @@ -332,12 +339,34 @@ export default function CreateArticleForm() { } } - if (status === "scheduled") { + if (status === "scheduled" && startDateValue) { + // ambil waktu, default 00:00 jika belum diisi + const [hours, minutes] = startTimeValue + ? startTimeValue.split(":").map(Number) + : [0, 0]; + + // gabungkan tanggal + waktu + const combinedDate = new Date(startDateValue); + combinedDate.setHours(hours, minutes, 0, 0); + + // format: 2025-10-08 14:30:00 + const formattedDateTime = `${combinedDate.getFullYear()}-${String( + combinedDate.getMonth() + 1 + ).padStart(2, "0")}-${String(combinedDate.getDate()).padStart( + 2, + "0" + )} ${String(combinedDate.getHours()).padStart(2, "0")}:${String( + combinedDate.getMinutes() + ).padStart(2, "0")}:00`; + const request = { id: articleId, - date: `${startDateValue?.year}-${startDateValue?.month}-${startDateValue?.day}`, + date: formattedDateTime, }; + + console.log("📤 Sending schedule request:", request); const res = await createArticleSchedule(request); + console.log("✅ Schedule response:", res); } close(); @@ -812,32 +841,49 @@ export default function CreateArticleForm() {
- {/* {isScheduled && ( -
-
+ {isScheduled && ( +
+ {/* Pilih tanggal */} +

Tanggal

- + setStartDateValue(date ?? undefined) + } + dateFormat="yyyy-MM-dd" + className="w-full border rounded-lg px-2 py-1 text-black cursor-pointer h-[150px]" + placeholderText="Pilih tanggal" />
+ + {/* Pilih waktu */} +
+

Waktu

+ setStartTimeValue(e.target.value)} + className="w-full border rounded-lg px-2 py-[6px] text-black" + /> +
- )} */} + )}
diff --git a/components/landing-page/breaking-news.tsx b/components/landing-page/breaking-news.tsx index ee61bb7..1530f4d 100644 --- a/components/landing-page/breaking-news.tsx +++ b/components/landing-page/breaking-news.tsx @@ -4,6 +4,7 @@ import React, { useEffect, useState } from "react"; import Image from "next/image"; import { getListArticle } from "@/service/article"; import Link from "next/link"; +import { getAdvertise } from "@/service/advertisement"; type Article = { id: number; @@ -22,10 +23,47 @@ type Article = { }[]; }; +type Advertise = { + id: number; + title: string; + description: string; + placement: string; + contentFileUrl: string; + redirectLink: string; +}; + export default function BreakingNews() { const [articles, setArticles] = useState([]); const [popular, setPopular] = useState([]); + const [bannerAd, setBannerAd] = useState(null); + useEffect(() => { + initStateAdver(); + }, []); + + async function initStateAdver() { + const req = { + limit: 100, + page: 1, + sort: "desc", + sortBy: "created_at", + isPublish: true, + }; + + try { + const res = await getAdvertise(req); + const data: Advertise[] = res?.data?.data || [1]; + + // filter iklan dengan placement = "banner" + const banner = data.find((ad) => ad.placement === "jumbotron"); + + if (banner) { + setBannerAd(banner); + } + } catch (err) { + console.error("Error fetching advertisement:", err); + } + } useEffect(() => { fetchArticles(); fetchPopular(); @@ -199,13 +237,32 @@ export default function BreakingNews() { {/* Advert */}
- Advertisement + {bannerAd ? ( + +
+ {bannerAd.title +
+
+ ) : ( + Berita Utama + )}
diff --git a/components/landing-page/news.tsx b/components/landing-page/news.tsx index a4e0747..6167634 100644 --- a/components/landing-page/news.tsx +++ b/components/landing-page/news.tsx @@ -13,6 +13,7 @@ import Image from "next/image"; import { useEffect, useState } from "react"; import { getListArticle } from "@/service/article"; import Link from "next/link"; +import { getAdvertise } from "@/service/advertisement"; type Article = { id: number; @@ -31,6 +32,15 @@ type Article = { }[]; }; +type Advertise = { + id: number; + title: string; + description: string; + placement: string; + contentFileUrl: string; + redirectLink: string; +}; + export default function News() { const [page, setPage] = useState(1); const [totalPage, setTotalPage] = useState(1); @@ -43,6 +53,36 @@ export default function News() { endDate: null, }); + const [bannerAd, setBannerAd] = useState(null); + + useEffect(() => { + initStateAdver(); + }, []); + + async function initStateAdver() { + const req = { + limit: 100, + page: 1, + sort: "desc", + sortBy: "created_at", + isPublish: true, + }; + + try { + const res = await getAdvertise(req); + const data: Advertise[] = res?.data?.data || [1]; + + // filter iklan dengan placement = "banner" + const banner = data.find((ad) => ad.placement === "jumbotron"); + + if (banner) { + setBannerAd(banner); + } + } catch (err) { + console.error("Error fetching advertisement:", err); + } + } + useEffect(() => { initState(); }, [page, showData, startDateValue, selectedCategories]); @@ -167,14 +207,14 @@ export default function News() {
{/* Banner */} -
+ {/*
Berita Utama -
+
*/} {/* Right Sidebar */} @@ -237,20 +277,32 @@ export default function News() { {/* Sidebar banners */}
- Berita Utama -
-
- Berita Utama + {bannerAd ? ( + +
+ {bannerAd.title +
+
+ ) : ( + Berita Utama + )}
diff --git a/components/landing-page/opini.tsx b/components/landing-page/opini.tsx index 85b49cc..d3cf06c 100644 --- a/components/landing-page/opini.tsx +++ b/components/landing-page/opini.tsx @@ -4,6 +4,7 @@ import { useEffect, useState } from "react"; import Image from "next/image"; import { getListArticle } from "@/service/article"; import Link from "next/link"; +import { getAdvertise } from "@/service/advertisement"; type Article = { id: number; @@ -22,12 +23,49 @@ type Article = { }[]; }; +type Advertise = { + id: number; + title: string; + description: string; + placement: string; + contentFileUrl: string; + redirectLink: string; +}; + export default function Opini() { const [opini, setOpini] = useState([]); const [jagaNegeri, setJagaNegeri] = useState([]); const [showDataOpini, setShowDataOpini] = useState("4"); const [showData, setShowData] = useState("3"); + const [bannerAd, setBannerAd] = useState(null); + useEffect(() => { + initStateAdver(); + }, []); + + async function initStateAdver() { + const req = { + limit: 100, + page: 1, + sort: "desc", + sortBy: "created_at", + isPublish: true, + }; + + try { + const res = await getAdvertise(req); + const data: Advertise[] = res?.data?.data || [1]; + + // filter iklan dengan placement = "banner" + const banner = data.find((ad) => ad.placement === "banner"); + + if (banner) { + setBannerAd(banner); + } + } catch (err) { + console.error("Error fetching advertisement:", err); + } + } useEffect(() => { fetchOpini(); fetchJagaNegeri(); @@ -197,13 +235,33 @@ export default function Opini() { -
- Berita Utama +
+ {bannerAd ? ( + +
+ {bannerAd.title +
+
+ ) : ( + Berita Utama + )}
); diff --git a/components/landing-page/popular-news.tsx b/components/landing-page/popular-news.tsx index 67aef36..fb8738b 100644 --- a/components/landing-page/popular-news.tsx +++ b/components/landing-page/popular-news.tsx @@ -4,6 +4,7 @@ import { useEffect, useState } from "react"; import Image from "next/image"; import { getListArticle } from "@/service/article"; import Link from "next/link"; +import { getAdvertise } from "@/service/advertisement"; type Article = { id: number; @@ -22,10 +23,47 @@ type Article = { }[]; }; +type Advertise = { + id: number; + title: string; + description: string; + placement: string; + contentFileUrl: string; + redirectLink: string; +}; + export default function PopularNews() { const [popularNews, setPopularNews] = useState([]); const [showData, setShowData] = useState("5"); + const [bannerAd, setBannerAd] = useState(null); + useEffect(() => { + initStateAdver(); + }, []); + + async function initStateAdver() { + const req = { + limit: 100, + page: 1, + sort: "desc", + sortBy: "created_at", + isPublish: true, + }; + + try { + const res = await getAdvertise(req); + const data: Advertise[] = res?.data?.data || [1]; + + // filter iklan dengan placement = "banner" + const banner = data.find((ad) => ad.placement === "banner"); + + if (banner) { + setBannerAd(banner); + } + } catch (err) { + console.error("Error fetching advertisement:", err); + } + } useEffect(() => { fetchPopularNews(); }, []); @@ -107,13 +145,33 @@ export default function PopularNews() {
{/* Banner */} -
- Berita Utama +
+ {bannerAd ? ( + +
+ {bannerAd.title +
+
+ ) : ( + Berita Utama + )}
);