update details
This commit is contained in:
parent
c2da413522
commit
187fe3a7c9
|
|
@ -5,6 +5,7 @@ import Link from "next/link";
|
||||||
import {
|
import {
|
||||||
getArticleById,
|
getArticleById,
|
||||||
getArticleBySlug,
|
getArticleBySlug,
|
||||||
|
getArticleFiles,
|
||||||
getListArticle,
|
getListArticle,
|
||||||
} from "@/service/article";
|
} from "@/service/article";
|
||||||
import { close, error, loading } from "@/config/swal";
|
import { close, error, loading } from "@/config/swal";
|
||||||
|
|
@ -75,13 +76,13 @@ export default function DetailContent() {
|
||||||
startDate: null,
|
startDate: null,
|
||||||
endDate: null,
|
endDate: null,
|
||||||
});
|
});
|
||||||
const [detailfiles, setDetailFiles] = useState<any>([]);
|
const [detailFiles, setDetailFiles] = useState<any[]>([]);
|
||||||
const [mainImage, setMainImage] = useState(0);
|
const [mainImage, setMainImage] = useState(0);
|
||||||
const [thumbnail, setThumbnail] = useState("-");
|
const [thumbnail, setThumbnail] = useState("-");
|
||||||
const [diseId, setDiseId] = useState(0);
|
const [diseId, setDiseId] = useState(0);
|
||||||
const [thumbnailImg, setThumbnailImg] = useState<File[]>([]);
|
const [thumbnailImg, setThumbnailImg] = useState<File[]>([]);
|
||||||
const [selectedMainImage, setSelectedMainImage] = useState<number | null>(
|
const [selectedMainImage, setSelectedMainImage] = useState<number | null>(
|
||||||
null
|
null,
|
||||||
);
|
);
|
||||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||||
|
|
||||||
|
|
@ -297,18 +298,39 @@ export default function DetailContent() {
|
||||||
initStateData();
|
initStateData();
|
||||||
}, [listCategory]);
|
}, [listCategory]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSelectedIndex(0);
|
||||||
|
}, [detailFiles]);
|
||||||
|
|
||||||
async function initStateData() {
|
async function initStateData() {
|
||||||
loading();
|
loading();
|
||||||
|
try {
|
||||||
|
// 1️⃣ Ambil artikel by slug
|
||||||
const res = await getArticleBySlug(slug);
|
const res = await getArticleBySlug(slug);
|
||||||
const data = res?.data?.data;
|
const data = res?.data?.data;
|
||||||
|
|
||||||
setThumbnail(data?.thumbnailUrl);
|
if (!data?.id) return;
|
||||||
setDiseId(data?.aiArticleId);
|
|
||||||
setDetailFiles(data?.files);
|
setArticleDetail(data);
|
||||||
setArticleDetail(data); // <-- Add this
|
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();
|
close();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// if (!articleDetail?.files || articleDetail?.files?.length === 0) {
|
// if (!articleDetail?.files || articleDetail?.files?.length === 0) {
|
||||||
// return (
|
// return (
|
||||||
// <div className="w-full h-[400px] bg-gray-100 flex items-center justify-center rounded-lg">
|
// <div className="w-full h-[400px] bg-gray-100 flex items-center justify-center rounded-lg">
|
||||||
|
|
@ -367,15 +389,18 @@ export default function DetailContent() {
|
||||||
</span>
|
</span>
|
||||||
<span>•</span>
|
<span>•</span>
|
||||||
<span>
|
<span>
|
||||||
<span>
|
{new Date(articleDetail?.publishedAt ?? articleDetail?.createdAt)
|
||||||
{new Date(
|
.toLocaleString("id-ID", {
|
||||||
articleDetail?.publishedAt ?? articleDetail?.createdAt
|
|
||||||
).toLocaleDateString("id-ID", {
|
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
month: "long",
|
month: "long",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
})}
|
hour: "2-digit",
|
||||||
</span>
|
minute: "2-digit",
|
||||||
|
hour12: false,
|
||||||
|
timeZone: "Asia/Jakarta",
|
||||||
|
})
|
||||||
|
.replace("pukul ", "")}{" "}
|
||||||
|
WIB
|
||||||
</span>
|
</span>
|
||||||
<span>•</span>
|
<span>•</span>
|
||||||
<span>{articleDetail?.categories?.[0]?.title}</span>
|
<span>{articleDetail?.categories?.[0]?.title}</span>
|
||||||
|
|
@ -383,36 +408,30 @@ export default function DetailContent() {
|
||||||
|
|
||||||
<div className="w-full h-auto mb-6">
|
<div className="w-full h-auto mb-6">
|
||||||
{/* Gambar utama */}
|
{/* Gambar utama */}
|
||||||
{articleDetail?.files && articleDetail.files.length > 0 ? (
|
{detailFiles.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
{/* Gambar utama */}
|
|
||||||
<div className="w-full">
|
|
||||||
<Image
|
<Image
|
||||||
src={articleDetail.files[selectedIndex]?.fileUrl}
|
src={detailFiles[selectedIndex]?.fileUrl}
|
||||||
alt={
|
alt={detailFiles[selectedIndex]?.fileAlt || "Berita"}
|
||||||
articleDetail.files[selectedIndex]?.fileAlt || "Berita"
|
|
||||||
}
|
|
||||||
width={800}
|
width={800}
|
||||||
height={400}
|
height={400}
|
||||||
className="rounded-lg w-full object-cover"
|
className="rounded-lg w-full object-cover"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Thumbnail */}
|
|
||||||
<div className="flex gap-2 mt-3 overflow-x-auto">
|
<div className="flex gap-2 mt-3 overflow-x-auto">
|
||||||
{articleDetail.files.map((file: any, index: number) => (
|
{detailFiles.map((file, index) => (
|
||||||
<button
|
<button
|
||||||
key={file?.id || index}
|
key={file.id}
|
||||||
onClick={() => setSelectedIndex(index)}
|
onClick={() => setSelectedIndex(index)}
|
||||||
className={`border-2 rounded-lg overflow-hidden ${
|
className={`border-2 rounded-lg ${
|
||||||
selectedIndex === index
|
selectedIndex === index
|
||||||
? "border-red-500"
|
? "border-red-500"
|
||||||
: "border-transparent"
|
: "border-transparent"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
src={file?.fileUrl}
|
src={file.fileUrl}
|
||||||
alt={file?.fileAlt || "Thumbnail"}
|
alt={file.fileAlt || "Thumbnail"}
|
||||||
width={100}
|
width={100}
|
||||||
height={80}
|
height={80}
|
||||||
className="object-cover"
|
className="object-cover"
|
||||||
|
|
@ -422,9 +441,8 @@ export default function DetailContent() {
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
// Jika file kosong/null tapi tetap render data lainnya
|
<div className="h-[400px] flex items-center justify-center bg-gray-100 rounded-lg">
|
||||||
<div className="w-full h-[400px] bg-gray-100 flex items-center justify-center rounded-lg">
|
<p className="text-gray-400">Gambar tidak tersedia</p>
|
||||||
<p className="text-gray-400 text-sm">Gambar tidak tersedia</p>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -504,7 +522,7 @@ export default function DetailContent() {
|
||||||
<div
|
<div
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: decodeHtmlString(
|
__html: decodeHtmlString(
|
||||||
articleDetail?.htmlDescription || ""
|
articleDetail?.htmlDescription || "",
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -814,7 +832,7 @@ export default function DetailContent() {
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
month: "long",
|
month: "long",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
}
|
},
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -846,7 +864,7 @@ export default function DetailContent() {
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
month: "long",
|
month: "long",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
}
|
},
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -514,7 +514,7 @@ export default function CreateArticleForm() {
|
||||||
id="title"
|
id="title"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Masukkan judul artikel"
|
placeholder="Masukkan judul artikel"
|
||||||
className="w-full border rounded-lg dark:border-gray-400"
|
className="h-16 px-4 text-2xl leading-tight"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import {
|
||||||
deleteArticleFiles,
|
deleteArticleFiles,
|
||||||
getArticleByCategory,
|
getArticleByCategory,
|
||||||
getArticleById,
|
getArticleById,
|
||||||
|
getArticleFiles,
|
||||||
submitApproval,
|
submitApproval,
|
||||||
unPublishArticle,
|
unPublishArticle,
|
||||||
updateArticle,
|
updateArticle,
|
||||||
|
|
@ -196,28 +197,50 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
|
||||||
|
|
||||||
async function initState() {
|
async function initState() {
|
||||||
loading();
|
loading();
|
||||||
const res = await getArticleById(id);
|
try {
|
||||||
const data = res.data?.data;
|
// 1️⃣ Ambil ARTICLE
|
||||||
setDetailData(data);
|
const articleRes = await getArticleById(id);
|
||||||
setValue("title", data?.title);
|
const articleData = articleRes.data?.data;
|
||||||
setValue("customCreatorName", data?.customCreatorName);
|
|
||||||
setValue("slug", data?.slug);
|
if (!articleData) return;
|
||||||
setValue("source", data?.source);
|
|
||||||
const cleanDescription = data?.htmlDescription
|
// ===== ARTICLE DATA =====
|
||||||
? data.htmlDescription
|
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(/\\"/g, '"')
|
||||||
.replace(/\\n/g, "\n", "\\")
|
.replace(/\\n/g, "\n")
|
||||||
.trim()
|
.trim()
|
||||||
: "";
|
: "";
|
||||||
setValue("description", cleanDescription);
|
|
||||||
setValue("tags", data?.tags ? data.tags.split(",") : []);
|
|
||||||
setThumbnail(data?.thumbnailUrl);
|
|
||||||
setDiseId(data?.aiArticleId);
|
|
||||||
setDetailFiles(data?.files);
|
|
||||||
|
|
||||||
setupInitCategory(data?.categories);
|
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();
|
close();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const setupInitCategory = (data: any) => {
|
const setupInitCategory = (data: any) => {
|
||||||
const temp: CategoryType[] = [];
|
const temp: CategoryType[] = [];
|
||||||
|
|
@ -667,9 +690,10 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
|
||||||
name="title"
|
name="title"
|
||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<label htmlFor="title" className="block text-sm font-medium mb-1">
|
<label htmlFor="title" className="block text-xl font-medium mb-2">
|
||||||
Judul
|
Judul
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
id="title"
|
id="title"
|
||||||
|
|
@ -677,7 +701,7 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
|
||||||
value={value ?? ""}
|
value={value ?? ""}
|
||||||
readOnly={isDetail}
|
readOnly={isDetail}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
className="w-full border rounded-lg"
|
className="h-16 px-4 text-2xl leading-tight"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,13 @@ export async function uploadArticleFile(id: string, data: any) {
|
||||||
return await httpPostInterceptor(`/article-files/${id}`, data, headers);
|
return await httpPostInterceptor(`/article-files/${id}`, data, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getArticleFiles() {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
return await httpGet(`/article-files`, headers);
|
||||||
|
}
|
||||||
|
|
||||||
export async function uploadArticleThumbnail(id: string, data: any) {
|
export async function uploadArticleThumbnail(id: string, data: any) {
|
||||||
const headers = {
|
const headers = {
|
||||||
"content-type": "multipart/form-data",
|
"content-type": "multipart/form-data",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue