From 439cf1b665f07a0bff37b3badaa12cb28dcc8920 Mon Sep 17 00:00:00 2001 From: Anang Yusman Date: Wed, 14 Jan 2026 12:04:14 +0800 Subject: [PATCH] update --- components/details/details-content.tsx | 123 ++++++++++++------ .../form/article/create-article-form.tsx | 2 +- components/form/article/edit-article-form.tsx | 68 ++++++---- service/article.ts | 7 + tsconfig.json | 24 +++- 5 files changed, 157 insertions(+), 67 deletions(-) diff --git a/components/details/details-content.tsx b/components/details/details-content.tsx index 51e74bb..afcab47 100644 --- a/components/details/details-content.tsx +++ b/components/details/details-content.tsx @@ -5,6 +5,7 @@ import Link from "next/link"; import { getArticleById, getArticleBySlug, + getArticleFiles, getListArticle, } from "@/service/article"; import { close, error, loading } from "@/config/swal"; @@ -74,7 +75,7 @@ export default function DetailContent() { startDate: null, endDate: null, }); - const [detailfiles, setDetailFiles] = useState([]); + const [detailFiles, setDetailFiles] = useState([]); const [mainImage, setMainImage] = useState(0); const [thumbnail, setThumbnail] = useState("-"); const [diseId, setDiseId] = useState(0); @@ -257,16 +258,55 @@ export default function DetailContent() { initStateData(); }, [listCategory]); + useEffect(() => { + setSelectedIndex(0); + }, [detailFiles]); + async function initStateData() { loading(); - const res = await getArticleBySlug(slug); - const data = res?.data?.data; + try { + // 1️⃣ Ambil artikel by slug + const res = await getArticleBySlug(slug); + const data = res?.data?.data; - setThumbnail(data?.thumbnailUrl); - setDiseId(data?.aiArticleId); - setDetailFiles(data?.files); - setArticleDetail(data); // <-- Add this - close(); + if (!data?.id) return; + + setArticleDetail(data); + setThumbnail(data.thumbnailUrl); + setDiseId(data.aiArticleId); + + // 2️⃣ Ambil SEMUA article files + const filesRes = await getArticleFiles(); + const allFiles = filesRes?.data?.data ?? []; + + // 3️⃣ FILTER sesuai articleId + const filteredFiles = allFiles.filter( + (file: any) => file.articleId === data.id + ); + + setDetailFiles(filteredFiles); + } catch (error) { + console.error("Init state detail error:", error); + } finally { + close(); + } + } + + function decodeHtmlString(raw: string = "") { + if (!raw) return ""; + + // 1️⃣ Hapus newline escape, backslash, dsb + let decoded = raw + .replace(/\\n/g, "\n") + .replace(/\\"/g, '"') // ubah \" jadi " + .replace(/\\'/g, "'") // ubah \' jadi ' + .replace(/\\\\/g, "\\") // ubah \\ jadi \ + .trim(); + + // 2️⃣ Decode entity HTML (misal ") + const el = document.createElement("textarea"); + el.innerHTML = decoded; + return el.value; } return ( @@ -324,38 +364,43 @@ export default function DetailContent() {
-
- {articleDetail?.files[selectedIndex].fileAlt -
+ {detailFiles.length > 0 ? ( + <> + {detailFiles[selectedIndex]?.fileAlt - {/* Thumbnail */} -
- {articleDetail?.files.map((file: any, index: number) => ( - - ))} -
+
+ {detailFiles.map((file, index) => ( + + ))} +
+ + ) : ( +
+

Gambar tidak tersedia

+
+ )}
diff --git a/components/form/article/create-article-form.tsx b/components/form/article/create-article-form.tsx index d920ed7..2df8011 100644 --- a/components/form/article/create-article-form.tsx +++ b/components/form/article/create-article-form.tsx @@ -514,7 +514,7 @@ export default function CreateArticleForm() { id="title" type="text" placeholder="Masukkan judul artikel" - className="w-full border rounded-lg dark:border-gray-400" + className="h-16 px-4 text-2xl leading-tight" {...field} /> )} diff --git a/components/form/article/edit-article-form.tsx b/components/form/article/edit-article-form.tsx index b28e391..7e1c271 100644 --- a/components/form/article/edit-article-form.tsx +++ b/components/form/article/edit-article-form.tsx @@ -23,6 +23,7 @@ import { deleteArticleFiles, getArticleByCategory, getArticleById, + getArticleFiles, submitApproval, unPublishArticle, updateArticle, @@ -196,27 +197,49 @@ export default function EditArticleForm(props: { isDetail: boolean }) { async function initState() { loading(); - const res = await getArticleById(id); - const data = res.data?.data; - setDetailData(data); - setValue("title", data?.title); - setValue("customCreatorName", data?.customCreatorName); - setValue("slug", data?.slug); - setValue("source", data?.source); - const cleanDescription = data?.htmlDescription - ? data.htmlDescription - .replace(/\\"/g, '"') - .replace(/\\n/g, "\n", "\\") - .trim() - : ""; - setValue("description", cleanDescription); - setValue("tags", data?.tags ? data.tags.split(",") : []); - setThumbnail(data?.thumbnailUrl); - setDiseId(data?.aiArticleId); - setDetailFiles(data?.files); + try { + // 1️⃣ Ambil ARTICLE + const articleRes = await getArticleById(id); + const articleData = articleRes.data?.data; - setupInitCategory(data?.categories); - close(); + if (!articleData) return; + + // ===== ARTICLE DATA ===== + setDetailData(articleData); + setValue("title", articleData.title); + setValue("customCreatorName", articleData.customCreatorName); + setValue("slug", articleData.slug); + setValue("source", articleData.source); + + const cleanDescription = articleData.htmlDescription + ? articleData.htmlDescription + .replace(/\\"/g, '"') + .replace(/\\n/g, "\n") + .trim() + : ""; + + setValue("description", cleanDescription); + setValue("tags", articleData.tags ? articleData.tags.split(",") : []); + + setThumbnail(articleData.thumbnailUrl); + setDiseId(articleData.aiArticleId); + setupInitCategory(articleData.categories); + + // 2️⃣ Ambil SEMUA article files + const filesRes = await getArticleFiles(); + const allFiles = filesRes.data?.data ?? []; + + // 3️⃣ FILTER berdasarkan ARTICLE ID yang sedang dibuka + const filteredFiles = allFiles.filter( + (file: any) => file.articleId === articleData.id + ); + + setDetailFiles(filteredFiles); + } catch (error) { + console.error("Init state error:", error); + } finally { + close(); + } } const setupInitCategory = (data: any) => { @@ -667,9 +690,10 @@ export default function EditArticleForm(props: { isDetail: boolean }) { name="title" render={({ field: { onChange, value } }) => (
-
)} diff --git a/service/article.ts b/service/article.ts index 4f338cd..6bc9376 100644 --- a/service/article.ts +++ b/service/article.ts @@ -129,6 +129,13 @@ export async function getCategoryPagination(data: any) { ); } +export async function getArticleFiles() { + const headers = { + "content-type": "application/json", + }; + return await httpGet(`/article-files`, headers); +} + export async function uploadArticleFile(id: string, data: any) { const headers = { "content-type": "multipart/form-data", diff --git a/tsconfig.json b/tsconfig.json index d8b9323..e7ff3a2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,11 @@ { "compilerOptions": { "target": "ES2017", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -11,7 +15,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { @@ -19,9 +23,19 @@ } ], "paths": { - "@/*": ["./*"] + "@/*": [ + "./*" + ] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] }