fix: detail article in admin page
This commit is contained in:
parent
2e86d97aee
commit
0deb587a82
|
|
@ -77,12 +77,21 @@ const useTableColumns = () => {
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// accessorKey: "creatorName",
|
||||||
|
// header: "Creator Group",
|
||||||
|
// cell: ({ row }) => (
|
||||||
|
// <span className="whitespace-nowrap">
|
||||||
|
// {row.getValue("creatorName") || row.getValue("createdByName")}
|
||||||
|
// </span>
|
||||||
|
// ),
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
accessorKey: "creatorName",
|
accessorKey: "creatorName",
|
||||||
header: "Creator Group",
|
header: "Creator Group",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span className="whitespace-nowrap">
|
<span className="whitespace-nowrap">
|
||||||
{row.getValue("creatorName") || row.getValue("createdByName")}
|
{row.original.creatorName || row.original.createdByName || "-"}
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
import FormAudioDetail from "@/components/form/content/audio/audio-detail-form";
|
import FormAudioDetail from "@/components/form/content/audio/audio-detail-form";
|
||||||
|
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||||
|
|
||||||
const AudioDetailPage = async () => {
|
const AudioDetailPage = async () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="space-y-4">
|
<SiteBreadcrumb />
|
||||||
|
<div className="space-y-4 bg-slate-100">
|
||||||
<FormAudioDetail />
|
<FormAudioDetail />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -77,12 +77,21 @@ const useTableColumns = () => {
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// accessorKey: "creatorName",
|
||||||
|
// header: "Creator Group",
|
||||||
|
// cell: ({ row }) => (
|
||||||
|
// <span className="whitespace-nowrap">
|
||||||
|
// {row.getValue("creatorName") || row.getValue("createdByName")}
|
||||||
|
// </span>
|
||||||
|
// ),
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
accessorKey: "creatorName",
|
accessorKey: "creatorName",
|
||||||
header: "Creator Group",
|
header: "Creator Group",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span className="whitespace-nowrap">
|
<span className="whitespace-nowrap">
|
||||||
{row.getValue("creatorName") || row.getValue("createdByName")}
|
{row.original.creatorName || row.original.createdByName || "-"}
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,6 @@ import useTableColumns from "./columns";
|
||||||
const TableTeks = () => {
|
const TableTeks = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||||
const [totalData, setTotalData] = React.useState<number>(1);
|
const [totalData, setTotalData] = React.useState<number>(1);
|
||||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||||
|
|
@ -76,18 +75,14 @@ const TableTeks = () => {
|
||||||
const [columnVisibility, setColumnVisibility] =
|
const [columnVisibility, setColumnVisibility] =
|
||||||
React.useState<VisibilityState>({});
|
React.useState<VisibilityState>({});
|
||||||
const [rowSelection, setRowSelection] = React.useState({});
|
const [rowSelection, setRowSelection] = React.useState({});
|
||||||
const [showData, setShowData] = React.useState("50");
|
const [showData, setShowData] = React.useState("10");
|
||||||
const [pagination, setPagination] = React.useState<PaginationState>({
|
const [pagination, setPagination] = React.useState<PaginationState>({
|
||||||
pageIndex: 0,
|
pageIndex: 0,
|
||||||
pageSize: Number(showData),
|
pageSize: Number(showData),
|
||||||
});
|
});
|
||||||
const [page, setPage] = React.useState(1);
|
const [page, setPage] = React.useState(1);
|
||||||
const [totalPage, setTotalPage] = React.useState(1);
|
const [totalPage, setTotalPage] = React.useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
const userId = getCookiesDecrypt("uie");
|
|
||||||
const userLevelId = getCookiesDecrypt("ulie");
|
|
||||||
|
|
||||||
const [categories, setCategories] = React.useState<any[]>([]);
|
const [categories, setCategories] = React.useState<any[]>([]);
|
||||||
const [selectedCategories, setSelectedCategories] = React.useState<number[]>(
|
const [selectedCategories, setSelectedCategories] = React.useState<number[]>(
|
||||||
[]
|
[]
|
||||||
|
|
@ -99,7 +94,6 @@ const TableTeks = () => {
|
||||||
const [filterByCreator, setFilterByCreator] = React.useState("");
|
const [filterByCreator, setFilterByCreator] = React.useState("");
|
||||||
const [filterBySource, setFilterBySource] = React.useState("");
|
const [filterBySource, setFilterBySource] = React.useState("");
|
||||||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
const columns = useTableColumns();
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
|
|
@ -179,13 +173,12 @@ const TableTeks = () => {
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Using the new interface-based approach for video content
|
|
||||||
const filters: ArticleFilters = {
|
const filters: ArticleFilters = {
|
||||||
page: page,
|
page,
|
||||||
totalPage: Number(showData),
|
totalPage: Number(showData),
|
||||||
title: search || undefined,
|
title: search || undefined,
|
||||||
categoryId: categoryFilter ? Number(categoryFilter) : undefined,
|
categoryId: categoryFilter ? Number(categoryFilter) : undefined,
|
||||||
typeId: 3,
|
typeId: 3, // 🔹 text content
|
||||||
statusId:
|
statusId:
|
||||||
statusFilter?.length > 0 ? Number(statusFilter[0]) : undefined,
|
statusFilter?.length > 0 ? Number(statusFilter[0]) : undefined,
|
||||||
startDate: formattedStartDate || undefined,
|
startDate: formattedStartDate || undefined,
|
||||||
|
|
@ -194,14 +187,17 @@ const TableTeks = () => {
|
||||||
|
|
||||||
const res = await listArticlesWithFilters(filters);
|
const res = await listArticlesWithFilters(filters);
|
||||||
const data = res?.data?.data;
|
const data = res?.data?.data;
|
||||||
|
const meta = res?.data?.meta;
|
||||||
|
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
data.forEach((item: any, index: number) => {
|
data.forEach((item: any, index: number) => {
|
||||||
item.no = (page - 1) * Number(showData) + index + 1;
|
item.no = (page - 1) * Number(showData) + index + 1;
|
||||||
});
|
});
|
||||||
setDataTable(data);
|
setDataTable(data);
|
||||||
setTotalData(data.length);
|
setTotalData(meta?.count ?? data.length);
|
||||||
setTotalPage(Math.ceil(data.length / Number(showData)));
|
setTotalPage(
|
||||||
|
meta?.totalPage ?? Math.ceil(data.length / Number(showData))
|
||||||
|
);
|
||||||
} else if (Array.isArray(data?.content)) {
|
} else if (Array.isArray(data?.content)) {
|
||||||
const contentData = data.content;
|
const contentData = data.content;
|
||||||
contentData.forEach((item: any, index: number) => {
|
contentData.forEach((item: any, index: number) => {
|
||||||
|
|
@ -218,7 +214,7 @@ const TableTeks = () => {
|
||||||
setTotalPage(1);
|
setTotalPage(1);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching tasks:", error);
|
console.error("Error fetching text content:", error);
|
||||||
setDataTable([]);
|
setDataTable([]);
|
||||||
setTotalData(0);
|
setTotalData(0);
|
||||||
setTotalPage(1);
|
setTotalPage(1);
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import FormTeks from "@/components/form/content/document/teks-form";
|
import FormTeks from "@/components/form/content/document/teks-form";
|
||||||
|
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||||
|
|
||||||
const TeksCreatePage = async () => {
|
const TeksCreatePage = async () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{/* <SiteBreadcrumb /> */}
|
<SiteBreadcrumb />
|
||||||
<div className="space-y-4">
|
<div className="space-y-4 bg-slate-100">
|
||||||
<FormTeks />
|
<FormTeks />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import FormTeksDetail from "@/components/form/content/document/teks-detail-form";
|
import FormTeksDetail from "@/components/form/content/document/teks-detail-form";
|
||||||
|
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||||
|
|
||||||
const TeksDetailPage = async () => {
|
const TeksDetailPage = async () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{/* <SiteBreadcrumb /> */}
|
<SiteBreadcrumb />
|
||||||
<div className="space-y-4">
|
<div className="space-y-4 bg-slate-100">
|
||||||
<FormTeksDetail />
|
<FormTeksDetail />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,6 @@ import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import {
|
import {
|
||||||
getArticleDetail,
|
getArticleDetail,
|
||||||
getTagsBySubCategoryId,
|
|
||||||
listEnableCategory,
|
|
||||||
publishMedia,
|
publishMedia,
|
||||||
submitApproval,
|
submitApproval,
|
||||||
} from "@/service/content/content";
|
} from "@/service/content/content";
|
||||||
|
|
@ -47,7 +45,6 @@ import { getCookiesDecrypt } from "@/lib/utils";
|
||||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||||
import { error } from "@/lib/swal";
|
import { error } from "@/lib/swal";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import SuggestionModal from "@/components/modal/suggestions-modal";
|
|
||||||
import { formatDateToIndonesian } from "@/utils/globals";
|
import { formatDateToIndonesian } from "@/utils/globals";
|
||||||
import ApprovalHistoryModal from "@/components/modal/approval-history-modal";
|
import ApprovalHistoryModal from "@/components/modal/approval-history-modal";
|
||||||
import { listArticleCategories } from "@/service/content";
|
import { listArticleCategories } from "@/service/content";
|
||||||
|
|
@ -62,19 +59,13 @@ const ViewEditor = dynamic(() => import("@/components/editor/view-editor"), {
|
||||||
ssr: false,
|
ssr: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
type Category = {
|
type Category = { id: string; title: string };
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type FileType = {
|
type FileType = {
|
||||||
id: number;
|
id: number;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
fileUrl?: string;
|
fileUrl?: string;
|
||||||
fileThumbnail?: string;
|
fileThumbnail?: string;
|
||||||
format?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type Detail = {
|
type Detail = {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
|
|
@ -137,46 +128,28 @@ export default function FormVideoDetail() {
|
||||||
const MySwal = withReactContent(Swal);
|
const MySwal = withReactContent(Swal);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { id } = useParams() as { id: string };
|
const { id } = useParams() as { id: string };
|
||||||
|
|
||||||
const userId = getCookiesDecrypt("uie");
|
const userId = getCookiesDecrypt("uie");
|
||||||
const userLevelId = getCookiesDecrypt("ulie");
|
const userLevelId = getCookiesDecrypt("ulie");
|
||||||
const userLevelName = Cookies.get("state");
|
const userLevelName = Cookies.get("state");
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
|
||||||
const [detail, setDetail] = useState<Detail | null>(null);
|
const [detail, setDetail] = useState<Detail | null>(null);
|
||||||
const [categories, setCategories] = useState<Category[]>([]);
|
const [categories, setCategories] = useState<Category[]>([]);
|
||||||
const [files, setFiles] = useState<FileType[]>([]);
|
const [files, setFiles] = useState<FileType[]>([]);
|
||||||
const [thumbsSwiper, setThumbsSwiper] = useState<any>(null);
|
const [thumbsSwiper, setThumbsSwiper] = useState<any>(null);
|
||||||
const [approval, setApproval] = useState<any>();
|
const [approval, setApproval] = useState<any>();
|
||||||
const [selectedPublishers, setSelectedPublishers] = useState<number[]>([]);
|
const [selectedPublishers, setSelectedPublishers] = useState<number[]>([]);
|
||||||
|
const [isUserMabesApprover, setIsUserMabesApprover] = useState(false);
|
||||||
const [modalOpen, setModalOpen] = useState(false);
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
const [status, setStatus] = useState("");
|
const [status, setStatus] = useState("");
|
||||||
const [description, setDescription] = useState("");
|
const [description, setDescription] = useState("");
|
||||||
const [filePlacements, setFilePlacements] = useState<string[][]>([]);
|
const [filePlacements, setFilePlacements] = useState<string[][]>([]);
|
||||||
const [isUserMabesApprover, setIsUserMabesApprover] = useState(false);
|
|
||||||
const [refresh, setRefresh] = useState(false);
|
|
||||||
const [detailVideos, setDetailVideos] = useState<string[]>([]);
|
|
||||||
const [selectedCategory, setSelectedCategory] = useState<string>("");
|
|
||||||
|
|
||||||
const {
|
const { control } = useForm({ resolver: zodResolver(videoSchema) });
|
||||||
control,
|
|
||||||
formState: { errors },
|
|
||||||
} = useForm({
|
|
||||||
resolver: zodResolver(videoSchema),
|
|
||||||
});
|
|
||||||
|
|
||||||
const getStatusName = (statusId: number): string => {
|
|
||||||
const statusMap: { [key: number]: string } = {
|
|
||||||
1: "Menunggu Review",
|
|
||||||
2: "Diterima",
|
|
||||||
3: "Minta Update",
|
|
||||||
4: "Ditolak",
|
|
||||||
};
|
|
||||||
return statusMap[statusId] || "Unknown";
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (userLevelId == "216" && roleId == "3") {
|
if (userLevelId == "216" && roleId == "3") setIsUserMabesApprover(true);
|
||||||
setIsUserMabesApprover(true);
|
|
||||||
}
|
|
||||||
}, [userLevelId, roleId]);
|
}, [userLevelId, roleId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -193,29 +166,16 @@ export default function FormVideoDetail() {
|
||||||
try {
|
try {
|
||||||
const response = await getArticleDetail(Number(id));
|
const response = await getArticleDetail(Number(id));
|
||||||
const details = response?.data?.data;
|
const details = response?.data?.data;
|
||||||
setSelectedCategory(String(details.categories[0].id));
|
|
||||||
const mappedDetail: Detail = {
|
const mappedDetail: Detail = {
|
||||||
...details,
|
...details,
|
||||||
|
statusId: details?.statusId,
|
||||||
categoryId: details?.categories?.[0]?.id,
|
categoryId: details?.categories?.[0]?.id,
|
||||||
htmlDescription: details?.htmlDescription,
|
htmlDescription: details?.htmlDescription,
|
||||||
statusName: getStatusName(details?.statusId),
|
|
||||||
uploadedById: details?.createdById,
|
uploadedById: details?.createdById,
|
||||||
files: details?.files || [],
|
files: details?.files || [],
|
||||||
categories: details?.categories || [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mappedFiles =
|
|
||||||
details?.files?.map((f: any) => ({
|
|
||||||
id: f.id,
|
|
||||||
fileName: f.fileName,
|
|
||||||
fileUrl: f.fileUrl,
|
|
||||||
fileThumbnail: f.fileThumbnail,
|
|
||||||
format: f.format || "mp4",
|
|
||||||
})) || [];
|
|
||||||
|
|
||||||
setDetail(mappedDetail);
|
setDetail(mappedDetail);
|
||||||
setFiles(mappedFiles);
|
setFiles(details?.files || []);
|
||||||
setDetailVideos(mappedFiles.map((f: any) => f.fileUrl || ""));
|
|
||||||
const approvals = await getDataApprovalByMediaUpload(mappedDetail.id);
|
const approvals = await getDataApprovalByMediaUpload(mappedDetail.id);
|
||||||
setApproval(approvals?.data?.data);
|
setApproval(approvals?.data?.data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -223,33 +183,32 @@ export default function FormVideoDetail() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchDetail();
|
fetchDetail();
|
||||||
}, [id, refresh]);
|
}, [id]);
|
||||||
|
|
||||||
|
const getStatusName = (statusId: number) => {
|
||||||
|
const map: Record<number, string> = {
|
||||||
|
1: "Menunggu Review",
|
||||||
|
2: "Diterima",
|
||||||
|
3: "Minta Update",
|
||||||
|
4: "Ditolak",
|
||||||
|
};
|
||||||
|
return map[statusId] || "Unknown";
|
||||||
|
};
|
||||||
|
|
||||||
const handleCheckboxChange = (id: number) => {
|
const handleCheckboxChange = (id: number) => {
|
||||||
setSelectedPublishers((prev) =>
|
setSelectedPublishers((prev) =>
|
||||||
prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id]
|
prev.includes(id) ? prev.filter((i) => i !== id) : [...prev, id]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const actionApproval = (e: string) => {
|
const actionApproval = (type: string) => {
|
||||||
const temp = [];
|
const placements = files.map(() => []);
|
||||||
for (const element of files) temp.push([]);
|
setFilePlacements(placements);
|
||||||
setFilePlacements(temp);
|
setStatus(type);
|
||||||
setStatus(e);
|
|
||||||
setDescription("");
|
setDescription("");
|
||||||
setModalOpen(true);
|
setModalOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const submit = async () => {
|
|
||||||
if (
|
|
||||||
(description?.length > 1 && Number(status) == 3) ||
|
|
||||||
Number(status) == 2 ||
|
|
||||||
Number(status) == 4
|
|
||||||
) {
|
|
||||||
await save();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
const data = {
|
const data = {
|
||||||
action: status == "2" ? "approve" : status == "3" ? "revision" : "reject",
|
action: status == "2" ? "approve" : status == "3" ? "revision" : "reject",
|
||||||
|
|
@ -257,8 +216,8 @@ export default function FormVideoDetail() {
|
||||||
};
|
};
|
||||||
setModalOpen(false);
|
setModalOpen(false);
|
||||||
loading();
|
loading();
|
||||||
const response = await submitApproval(id, data);
|
const res = await submitApproval(id, data);
|
||||||
if (response?.error) return error(response.message);
|
if (res?.error) return error(res.message);
|
||||||
close();
|
close();
|
||||||
MySwal.fire({
|
MySwal.fire({
|
||||||
title: "Sukses",
|
title: "Sukses",
|
||||||
|
|
@ -272,23 +231,15 @@ export default function FormVideoDetail() {
|
||||||
successCallback();
|
successCallback();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!detail) {
|
if (!detail) return <div className="p-10 text-gray-500">Memuat data...</div>;
|
||||||
return (
|
|
||||||
<div className="text-center py-20 text-gray-500">
|
|
||||||
Memuat detail video...
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form>
|
<form>
|
||||||
<div className="flex flex-col lg:flex-row gap-10 border rounded-lg">
|
<div className="flex flex-col lg:flex-row gap-10 border rounded-lg">
|
||||||
{/* LEFT SIDE */}
|
|
||||||
<Card className="w-full lg:w-8/12 m-2">
|
<Card className="w-full lg:w-8/12 m-2">
|
||||||
<div className="px-6 py-6">
|
<div className="px-6 py-6">
|
||||||
<p className="text-lg font-semibold mb-3">Form Video</p>
|
<p className="text-lg font-semibold mb-3">Form Video</p>
|
||||||
|
|
||||||
{/* Title */}
|
|
||||||
<div className="space-y-2 py-3">
|
<div className="space-y-2 py-3">
|
||||||
<Label>Title</Label>
|
<Label>Title</Label>
|
||||||
<Controller
|
<Controller
|
||||||
|
|
@ -296,31 +247,22 @@ export default function FormVideoDetail() {
|
||||||
name="title"
|
name="title"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
value={detail.title}
|
||||||
value={detail?.title}
|
|
||||||
onChange={field.onChange}
|
onChange={field.onChange}
|
||||||
placeholder="Enter Title"
|
disabled
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{/* {errors.title?.message && (
|
|
||||||
<p className="text-red-400 text-sm">{errors.title.message}</p>
|
|
||||||
)} */}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Category */}
|
|
||||||
<div className="py-3 w-full space-y-2">
|
<div className="py-3 w-full space-y-2">
|
||||||
<Label>Category</Label>
|
<Label>Category</Label>
|
||||||
<Select
|
<Select disabled value={String(detail.categoryId)}>
|
||||||
value={selectedCategory}
|
|
||||||
onValueChange={setSelectedCategory}
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Pilih kategori" />
|
<SelectValue placeholder="Pilih kategori" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{categories?.map((cat) => (
|
{categories.map((cat) => (
|
||||||
<SelectItem key={cat.id} value={String(cat.id)}>
|
<SelectItem key={cat.id} value={String(cat.id)}>
|
||||||
{cat.title}
|
{cat.title}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
|
@ -328,29 +270,12 @@ export default function FormVideoDetail() {
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="py-3 space-y-2">
|
|
||||||
<Label>Category</Label>
|
|
||||||
<Select disabled value={String(detail.categoryId)}>
|
|
||||||
<SelectTrigger>
|
|
||||||
<SelectValue placeholder="Pilih" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
{categories.map((cat) => (
|
|
||||||
<SelectItem key={cat.id} value={String(cat.id)}>
|
|
||||||
{cat.name}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div> */}
|
|
||||||
|
|
||||||
{/* Description */}
|
|
||||||
<div className="py-3 space-y-2">
|
<div className="py-3 space-y-2">
|
||||||
<Label>Description</Label>
|
<Label>Description</Label>
|
||||||
<ViewEditor initialData={detail.htmlDescription} />
|
<ViewEditor initialData={detail.htmlDescription} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Video Files */}
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label className="text-xl">File Media</Label>
|
<Label className="text-xl">File Media</Label>
|
||||||
<Swiper
|
<Swiper
|
||||||
|
|
@ -391,24 +316,19 @@ export default function FormVideoDetail() {
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* RIGHT SIDE */}
|
|
||||||
<div className="w-full lg:w-4/12 m-2">
|
<div className="w-full lg:w-4/12 m-2">
|
||||||
<Card className="pb-3">
|
<Card className="pb-3">
|
||||||
<div className="px-3 py-3">
|
<div className="px-3 py-3">
|
||||||
<Label>Creator</Label>
|
<Label>Creator</Label>
|
||||||
<Input
|
<Input value={detail.createdByName} disabled />
|
||||||
value={detail.createdByName}
|
|
||||||
disabled
|
|
||||||
placeholder="Creator"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-3 px-3 space-y-2">
|
<div className="mt-3 px-3 space-y-2">
|
||||||
<Label>Preview</Label>
|
<Label>Preview</Label>
|
||||||
<Card className="mt-2 w-fit">
|
<Card className="mt-2 w-fit">
|
||||||
<img
|
<img
|
||||||
src={detail.thumbnailUrl}
|
src={detail.thumbnailUrl || detail.thumbnailLink}
|
||||||
alt="Thumbnail"
|
alt="Thumbnail Gambar Utama"
|
||||||
className="h-[200px] rounded"
|
className="h-[200px] rounded"
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
@ -417,10 +337,10 @@ export default function FormVideoDetail() {
|
||||||
<div className="px-3 py-3">
|
<div className="px-3 py-3">
|
||||||
<Label>Tags</Label>
|
<Label>Tags</Label>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{detail.tags?.split(",").map((tag: string, index: number) => (
|
{detail.tags?.split(",").map((tag, i) => (
|
||||||
<Badge
|
<Badge
|
||||||
key={index}
|
key={i}
|
||||||
className="border rounded-md bg-black text-white px-2 py-2"
|
className="border bg-black text-white px-2 py-2"
|
||||||
>
|
>
|
||||||
{tag.trim()}
|
{tag.trim()}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|
@ -436,24 +356,18 @@ export default function FormVideoDetail() {
|
||||||
id={String(target)}
|
id={String(target)}
|
||||||
checked={selectedPublishers.includes(target)}
|
checked={selectedPublishers.includes(target)}
|
||||||
onChange={() => handleCheckboxChange(target)}
|
onChange={() => handleCheckboxChange(target)}
|
||||||
className="border"
|
|
||||||
/>
|
/>
|
||||||
<Label htmlFor={String(target)}>
|
<Label htmlFor={String(target)}>
|
||||||
{target === 5 ? "UMUM" : target === 6 ? "JOURNALIS" : ""}
|
{target === 5 ? "UMUM" : "JOURNALIS"}
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* <SuggestionModal
|
|
||||||
id={Number(id)}
|
|
||||||
numberOfSuggestion={detail?.numberOfSuggestion}
|
|
||||||
/> */}
|
|
||||||
|
|
||||||
<div className="px-3 py-3 border mx-3">
|
<div className="px-3 py-3 border mx-3">
|
||||||
<p>Information:</p>
|
<p>Information:</p>
|
||||||
<p className="text-sm text-slate-400">
|
<p className="text-sm text-slate-400">
|
||||||
{detail.statusName || getStatusName(detail.statusId)}
|
{detail.statusId && getStatusName(detail.statusId)}
|
||||||
</p>
|
</p>
|
||||||
<p>Komentar</p>
|
<p>Komentar</p>
|
||||||
<p>{approval?.message}</p>
|
<p>{approval?.message}</p>
|
||||||
|
|
@ -471,6 +385,108 @@ export default function FormVideoDetail() {
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{(Number(detail.needApprovalFromLevel || 0) ==
|
||||||
|
Number(userLevelId) ||
|
||||||
|
(detail.isPublish === false && detail.statusId == 1)) &&
|
||||||
|
Number(detail.uploadedById || detail.createdById) !=
|
||||||
|
Number(userId) ? (
|
||||||
|
<div className="flex flex-col gap-2 p-3">
|
||||||
|
<Button
|
||||||
|
onClick={() => actionApproval("2")}
|
||||||
|
color="primary"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Icon icon="fa:check" className="mr-3" /> Accept
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => actionApproval("3")}
|
||||||
|
className="bg-orange-400 hover:bg-orange-300"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Icon icon="fa:comment-o" className="mr-3" /> Revision
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => actionApproval("4")}
|
||||||
|
color="destructive"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Icon icon="fa:times" className="mr-3" /> Reject
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<Dialog open={modalOpen} onOpenChange={setModalOpen}>
|
||||||
|
<DialogContent className="max-h-[600px] overflow-y-auto">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Leave Comment</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
{status === "2" &&
|
||||||
|
files.map((file, i) => (
|
||||||
|
<div key={i} className="flex items-center gap-4 mb-3">
|
||||||
|
<video
|
||||||
|
src={file.fileUrl}
|
||||||
|
className="w-[200px] h-[120px]"
|
||||||
|
controls
|
||||||
|
/>
|
||||||
|
<span>{file.fileName}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
placeholder="Tulis komentar Anda..."
|
||||||
|
value={description}
|
||||||
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="flex flex-wrap gap-2 mt-2">
|
||||||
|
{status === "3" || status === "4" ? (
|
||||||
|
<>
|
||||||
|
{[
|
||||||
|
"Kualitas media kurang baik",
|
||||||
|
"Deskripsi kurang lengkap",
|
||||||
|
"Judul kurang tepat",
|
||||||
|
].map((text) => (
|
||||||
|
<Button
|
||||||
|
key={text}
|
||||||
|
size="sm"
|
||||||
|
variant={description === text ? "default" : "outline"}
|
||||||
|
onClick={() => setDescription(text)}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{["Konten sangat bagus", "Konten menarik"].map((text) => (
|
||||||
|
<Button
|
||||||
|
key={text}
|
||||||
|
size="sm"
|
||||||
|
variant={description === text ? "default" : "outline"}
|
||||||
|
onClick={() => setDescription(text)}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DialogFooter className="mt-4 flex justify-end gap-3">
|
||||||
|
<Button onClick={() => save()} color="primary">
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
color="destructive"
|
||||||
|
onClick={() => setModalOpen(false)}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -256,8 +256,11 @@ export default function FormAudioDetail() {
|
||||||
|
|
||||||
setDetail(details);
|
setDetail(details);
|
||||||
setMain({
|
setMain({
|
||||||
type: details?.fileType.name,
|
type:
|
||||||
url: details?.files[0]?.url,
|
details?.fileType?.name ||
|
||||||
|
details?.fileTypeName || // kalau backend pakai nama ini
|
||||||
|
details?.typeName || // atau nama alternatif
|
||||||
|
"Audio", // fallback aman url: details?.files[0]?.url,
|
||||||
names: details?.files[0]?.fileName,
|
names: details?.files[0]?.fileName,
|
||||||
format: details?.files[0]?.format,
|
format: details?.files[0]?.format,
|
||||||
});
|
});
|
||||||
|
|
@ -448,8 +451,8 @@ export default function FormAudioDetail() {
|
||||||
return (
|
return (
|
||||||
<form>
|
<form>
|
||||||
{detail !== undefined ? (
|
{detail !== undefined ? (
|
||||||
<div className="flex flex-col lg:flex-row gap-10">
|
<div className="flex flex-col lg:flex-row gap-10 border rounded-lg">
|
||||||
<Card className="w-full lg:w-8/12">
|
<Card className="w-full lg:w-8/12 m-2">
|
||||||
<div className="px-6 py-6">
|
<div className="px-6 py-6">
|
||||||
<p className="text-lg font-semibold mb-3">Form Audio</p>
|
<p className="text-lg font-semibold mb-3">Form Audio</p>
|
||||||
<div className="gap-5 mb-5">
|
<div className="gap-5 mb-5">
|
||||||
|
|
@ -533,31 +536,12 @@ export default function FormAudioDetail() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
<div className="w-full lg:w-4/12">
|
<div className="w-full lg:w-4/12 m-2">
|
||||||
<Card className="pb-3">
|
<Card className="pb-3">
|
||||||
<div className="px-3 py-3">
|
<div className="px-3 py-3">
|
||||||
<div className="space-y-2">
|
<Label>Creator</Label>
|
||||||
<Label>Creator</Label>
|
<Input value={detail.createdByName} disabled />
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
name="creatorName"
|
|
||||||
render={({ field }) => (
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
value={detail?.creatorName}
|
|
||||||
onChange={field.onChange}
|
|
||||||
placeholder="Enter Title"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{errors.creatorName?.message && (
|
|
||||||
<p className="text-red-400 text-sm">
|
|
||||||
{errors.creatorName.message}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="px-3 py-3">
|
<div className="px-3 py-3">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Tags</Label>
|
<Label>Tags</Label>
|
||||||
|
|
@ -567,7 +551,7 @@ export default function FormAudioDetail() {
|
||||||
.map((tag: string, index: number) => (
|
.map((tag: string, index: number) => (
|
||||||
<Badge
|
<Badge
|
||||||
key={index}
|
key={index}
|
||||||
className="border rounded-md px-2 py-2"
|
className="border rounded-md bg-black text-white px-2 py-2"
|
||||||
>
|
>
|
||||||
{tag.trim()}
|
{tag.trim()}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|
@ -576,40 +560,26 @@ export default function FormAudioDetail() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-3 py-3">
|
<div className="px-3 py-3">
|
||||||
<div className="flex flex-col gap-6 space-y-2">
|
<div className="flex flex-col gap-2 space-y-2">
|
||||||
<Label>Publish Target</Label>
|
<Label>Publish Target</Label>
|
||||||
<div className="flex gap-2 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="5"
|
id="4"
|
||||||
checked={selectedPublishers.includes(5)}
|
checked={selectedPublishers.includes(5)}
|
||||||
onChange={() => handleCheckboxChange(5)}
|
onChange={() => handleCheckboxChange(5)}
|
||||||
|
className="border"
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="5">UMUM</Label>
|
<Label htmlFor="5">UMUM</Label>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="6"
|
id="5"
|
||||||
checked={selectedPublishers.includes(6)}
|
checked={selectedPublishers.includes(6)}
|
||||||
onChange={() => handleCheckboxChange(6)}
|
onChange={() => handleCheckboxChange(6)}
|
||||||
|
className="border"
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="6">JOURNALIS</Label>
|
<Label htmlFor="6">JOURNALIS</Label>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2 items-center">
|
|
||||||
<Checkbox
|
|
||||||
id="7"
|
|
||||||
checked={selectedPublishers.includes(7)}
|
|
||||||
onChange={() => handleCheckboxChange(7)}
|
|
||||||
/>
|
|
||||||
<Label htmlFor="7">POLRI</Label>
|
|
||||||
</div>
|
|
||||||
<div className="flex gap-2 items-center">
|
|
||||||
<Checkbox
|
|
||||||
id="8"
|
|
||||||
checked={selectedPublishers.includes(8)}
|
|
||||||
onChange={() => handleCheckboxChange(8)}
|
|
||||||
/>
|
|
||||||
<Label htmlFor="8">KSP</Label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<SuggestionModal
|
<SuggestionModal
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,11 @@ import FileTextPreview from "../file-preview-text";
|
||||||
import FileTextThumbnail from "../file-text-thumbnail";
|
import FileTextThumbnail from "../file-text-thumbnail";
|
||||||
import { listArticleCategories } from "@/service/content";
|
import { listArticleCategories } from "@/service/content";
|
||||||
|
|
||||||
|
type Option = {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
|
||||||
const imageSchema = z.object({
|
const imageSchema = z.object({
|
||||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
description: z
|
description: z
|
||||||
|
|
@ -120,13 +125,11 @@ export default function FormTeksDetail() {
|
||||||
const userId = getCookiesDecrypt("uie");
|
const userId = getCookiesDecrypt("uie");
|
||||||
const userLevelId = getCookiesDecrypt("ulie");
|
const userLevelId = getCookiesDecrypt("ulie");
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
|
||||||
const [modalOpen, setModalOpen] = useState(false);
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
const { id } = useParams() as { id: string };
|
const { id } = useParams() as { id: string };
|
||||||
console.log(id);
|
console.log(id);
|
||||||
const editor = useRef(null);
|
const editor = useRef(null);
|
||||||
type ImageSchema = z.infer<typeof imageSchema>;
|
type ImageSchema = z.infer<typeof imageSchema>;
|
||||||
|
|
||||||
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
||||||
const taskId = Cookies.get("taskId");
|
const taskId = Cookies.get("taskId");
|
||||||
const scheduleId = Cookies.get("scheduleId");
|
const scheduleId = Cookies.get("scheduleId");
|
||||||
|
|
@ -146,11 +149,16 @@ export default function FormTeksDetail() {
|
||||||
const [files, setFiles] = useState<FileType[]>([]);
|
const [files, setFiles] = useState<FileType[]>([]);
|
||||||
const [rejectedFiles, setRejectedFiles] = useState<number[]>([]);
|
const [rejectedFiles, setRejectedFiles] = useState<number[]>([]);
|
||||||
const [isMabesApprover, setIsMabesApprover] = useState(false);
|
const [isMabesApprover, setIsMabesApprover] = useState(false);
|
||||||
|
|
||||||
const [filePlacements, setFilePlacements] = useState<string[][]>([]);
|
const [filePlacements, setFilePlacements] = useState<string[][]>([]);
|
||||||
const [isUserMabesApprover, setIsUserMabesApprover] = useState(false);
|
const [isUserMabesApprover, setIsUserMabesApprover] = useState(false);
|
||||||
|
|
||||||
const [approval, setApproval] = useState<any>();
|
const [approval, setApproval] = useState<any>();
|
||||||
|
const [publishedFor, setPublishedFor] = useState<string[]>([]);
|
||||||
|
|
||||||
|
const options: Option[] = [
|
||||||
|
{ id: "all", label: "SEMUA" },
|
||||||
|
{ id: "4", label: "UMUM" },
|
||||||
|
{ id: "5", label: "JOURNALIS" },
|
||||||
|
];
|
||||||
|
|
||||||
let fileTypeId = "3";
|
let fileTypeId = "3";
|
||||||
|
|
||||||
|
|
@ -218,43 +226,63 @@ export default function FormTeksDetail() {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function initState() {
|
async function initState() {
|
||||||
if (id) {
|
if (!id) return;
|
||||||
|
|
||||||
|
try {
|
||||||
const response = await getArticleDetail(Number(id));
|
const response = await getArticleDetail(Number(id));
|
||||||
const details = response?.data?.data;
|
const details = response?.data?.data;
|
||||||
console.log("detail", details);
|
if (!details) return;
|
||||||
setSelectedCategory(String(details.categories[0].id));
|
|
||||||
|
|
||||||
setFiles(details?.files);
|
// ✅ Aman untuk categories
|
||||||
|
const firstCategoryId =
|
||||||
|
details?.categories && details.categories.length > 0
|
||||||
|
? String(details.categories[0].id)
|
||||||
|
: "";
|
||||||
|
|
||||||
|
setSelectedCategory(firstCategoryId);
|
||||||
|
setFiles(details?.files || []);
|
||||||
setDetail(details);
|
setDetail(details);
|
||||||
|
|
||||||
|
// ✅ Aman untuk fileType
|
||||||
setMain({
|
setMain({
|
||||||
type: details?.fileType.name,
|
type: details?.fileType?.name || "Unknown",
|
||||||
url: details?.files[0]?.url,
|
url: details?.files?.[0]?.url || "",
|
||||||
names: details?.files[0]?.fileName,
|
names: details?.files?.[0]?.fileName || "",
|
||||||
format: details?.files[0]?.format,
|
format: details?.files?.[0]?.format || "",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (details.publishedForObject) {
|
if (details?.publishedForObject) {
|
||||||
const publisherIds = details.publishedForObject.map(
|
const publisherIds = details.publishedForObject.map(
|
||||||
(obj: any) => obj.id
|
(obj: any) => obj.id
|
||||||
);
|
);
|
||||||
setSelectedPublishers(publisherIds);
|
setSelectedPublishers(publisherIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the selected target to the category ID from details
|
setSelectedTarget(String(details?.category?.id || ""));
|
||||||
setSelectedTarget(String(details.category.id));
|
|
||||||
|
const filesData = details?.files || [];
|
||||||
|
const fileUrls = filesData.map((file: any) => {
|
||||||
|
const ext = file?.fileName?.includes(".")
|
||||||
|
? "." + file.fileName.split(".").pop()
|
||||||
|
: file?.type || "";
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: file?.url || file?.secondaryUrl || "default-image.jpg",
|
||||||
|
format: ext?.toLowerCase(),
|
||||||
|
fileName: file?.fileName || "Unknown file",
|
||||||
|
type: file?.type || "",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const filesData = details.files || [];
|
|
||||||
const fileUrls = filesData.map((file: any) => ({
|
|
||||||
url: file.secondaryUrl || "default-image.jpg",
|
|
||||||
format: file.format,
|
|
||||||
fileName: file.fileName,
|
|
||||||
}));
|
|
||||||
setDetailThumb(fileUrls);
|
setDetailThumb(fileUrls);
|
||||||
|
|
||||||
const approvals = await getDataApprovalByMediaUpload(details?.id);
|
const approvals = await getDataApprovalByMediaUpload(details?.id);
|
||||||
setApproval(approvals?.data?.data);
|
setApproval(approvals?.data?.data);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error loading article details:", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initState();
|
initState();
|
||||||
}, [refresh, setValue]);
|
}, [refresh, setValue]);
|
||||||
|
|
||||||
|
|
@ -392,15 +420,15 @@ export default function FormTeksDetail() {
|
||||||
confirmButtonColor: "#3085d6",
|
confirmButtonColor: "#3085d6",
|
||||||
confirmButtonText: "OK",
|
confirmButtonText: "OK",
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
router.push("/admin/content/document");
|
router.push("/admin/content/text");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form>
|
<form>
|
||||||
{detail !== undefined ? (
|
{detail !== undefined ? (
|
||||||
<div className="flex flex-col lg:flex-row gap-10">
|
<div className="flex flex-col lg:flex-row gap-10 border rounded-lg">
|
||||||
<Card className="w-full lg:w-8/12">
|
<Card className="w-full lg:w-8/12 m-2">
|
||||||
<div className="px-6 py-6">
|
<div className="px-6 py-6">
|
||||||
<p className="text-lg font-semibold mb-3">Form Text</p>
|
<p className="text-lg font-semibold mb-3">Form Text</p>
|
||||||
<div className="gap-5 mb-5">
|
<div className="gap-5 mb-5">
|
||||||
|
|
@ -463,7 +491,7 @@ export default function FormTeksDetail() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label className="text-xl">File Media </Label>
|
<Label className="text-xl">File Media</Label>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<Swiper
|
<Swiper
|
||||||
thumbs={{ swiper: thumbsSwiper }}
|
thumbs={{ swiper: thumbsSwiper }}
|
||||||
|
|
@ -498,30 +526,12 @@ export default function FormTeksDetail() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
<div className="w-full lg:w-4/12">
|
<div className="w-full lg:w-4/12 m-2">
|
||||||
<Card className="pb-3">
|
<Card className="pb-3">
|
||||||
<div className="px-3 py-3">
|
<div className="px-3 py-3">
|
||||||
<div className="space-y-2">
|
|
||||||
<Label>Creator</Label>
|
<Label>Creator</Label>
|
||||||
<Controller
|
<Input value={detail.createdByName} disabled />
|
||||||
control={control}
|
|
||||||
name="creatorName"
|
|
||||||
render={({ field }) => (
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
value={detail?.creatorName}
|
|
||||||
onChange={field.onChange}
|
|
||||||
placeholder="Enter Title"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{errors.creatorName?.message && (
|
|
||||||
<p className="text-red-400 text-sm">
|
|
||||||
{errors.creatorName.message}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{/* <div className="mt-3 px-3">
|
{/* <div className="mt-3 px-3">
|
||||||
<Label>Pratinjau Gambar Utama</Label>
|
<Label>Pratinjau Gambar Utama</Label>
|
||||||
<Card className="mt-2">
|
<Card className="mt-2">
|
||||||
|
|
@ -541,7 +551,7 @@ export default function FormTeksDetail() {
|
||||||
.map((tag: string, index: number) => (
|
.map((tag: string, index: number) => (
|
||||||
<Badge
|
<Badge
|
||||||
key={index}
|
key={index}
|
||||||
className="border rounded-md px-2 py-2"
|
className="border rounded-md bg-black text-white px-2 py-2"
|
||||||
>
|
>
|
||||||
{tag.trim()}
|
{tag.trim()}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|
@ -550,40 +560,26 @@ export default function FormTeksDetail() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-3 py-3">
|
<div className="px-3 py-3">
|
||||||
<div className="flex flex-col gap-6 space-y-2">
|
<div className="flex flex-col gap-2 space-y-2">
|
||||||
<Label>Publish Target</Label>
|
<Label>Publish Target</Label>
|
||||||
<div className="flex gap-2 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="5"
|
id="4"
|
||||||
checked={selectedPublishers.includes(5)}
|
checked={selectedPublishers.includes(5)}
|
||||||
onChange={() => handleCheckboxChange(5)}
|
onChange={() => handleCheckboxChange(5)}
|
||||||
|
className="border"
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="5">UMUM</Label>
|
<Label htmlFor="5">UMUM</Label>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="6"
|
id="5"
|
||||||
checked={selectedPublishers.includes(6)}
|
checked={selectedPublishers.includes(6)}
|
||||||
onChange={() => handleCheckboxChange(6)}
|
onChange={() => handleCheckboxChange(6)}
|
||||||
|
className="border"
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="6">JOURNALIS</Label>
|
<Label htmlFor="6">JOURNALIS</Label>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2 items-center">
|
|
||||||
<Checkbox
|
|
||||||
id="7"
|
|
||||||
checked={selectedPublishers.includes(7)}
|
|
||||||
onChange={() => handleCheckboxChange(7)}
|
|
||||||
/>
|
|
||||||
<Label htmlFor="7">POLRI</Label>
|
|
||||||
</div>
|
|
||||||
<div className="flex gap-2 items-center">
|
|
||||||
<Checkbox
|
|
||||||
id="8"
|
|
||||||
checked={selectedPublishers.includes(8)}
|
|
||||||
onChange={() => handleCheckboxChange(8)}
|
|
||||||
/>
|
|
||||||
<Label htmlFor="8">KSP</Label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<SuggestionModal
|
<SuggestionModal
|
||||||
|
|
@ -821,10 +817,10 @@ export default function FormTeksDetail() {
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Card>
|
</Card>
|
||||||
{Number(detail?.needApprovalFromLevel) == Number(userLevelId) ? (
|
{/* {Number(detail?.needApprovalFromLevel) == Number(userLevelId) ? (
|
||||||
Number(detail?.uploadedById) == Number(userId) ? (
|
Number(detail?.uploadedById) == Number(userId) ? (
|
||||||
""
|
""
|
||||||
) : (
|
) : ( */}
|
||||||
<div className="flex flex-col gap-2 p-3">
|
<div className="flex flex-col gap-2 p-3">
|
||||||
<Button
|
<Button
|
||||||
onClick={() => actionApproval("2")}
|
onClick={() => actionApproval("2")}
|
||||||
|
|
@ -849,10 +845,10 @@ export default function FormTeksDetail() {
|
||||||
Reject
|
Reject
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)
|
{/* )
|
||||||
) : (
|
) : (
|
||||||
""
|
""
|
||||||
)}
|
)} */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
|
|
@ -144,10 +144,8 @@ export default function FormTeks() {
|
||||||
const [publishedFor, setPublishedFor] = useState<string[]>([]);
|
const [publishedFor, setPublishedFor] = useState<string[]>([]);
|
||||||
const options: Option[] = [
|
const options: Option[] = [
|
||||||
{ id: "all", label: "SEMUA" },
|
{ id: "all", label: "SEMUA" },
|
||||||
{ id: "5", label: "UMUM" },
|
{ id: "4", label: "UMUM" },
|
||||||
{ id: "6", label: "JOURNALIS" },
|
{ id: "5", label: "JOURNALIS" },
|
||||||
{ id: "7", label: "POLRI" },
|
|
||||||
{ id: "8", label: "KSP" },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const { getRootProps, getInputProps } = useDropzone({
|
const { getRootProps, getInputProps } = useDropzone({
|
||||||
|
|
@ -638,12 +636,11 @@ export default function FormTeks() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id == undefined) {
|
if (id == undefined) {
|
||||||
// New Articles API request data structure
|
|
||||||
const articleData: CreateArticleData = {
|
const articleData: CreateArticleData = {
|
||||||
aiArticleId: 0, // default 0
|
aiArticleId: 0,
|
||||||
categoryIds: selectedCategory.toString(),
|
categoryIds: selectedCategory.toString(),
|
||||||
createdAt: formatDateForBackend(new Date()), // ✅ format sesuai backend
|
createdAt: formatDateForBackend(new Date()),
|
||||||
createdById: Number(userId), // isi dengan userId valid
|
createdById: Number(userId),
|
||||||
description: htmlToString(finalDescription),
|
description: htmlToString(finalDescription),
|
||||||
htmlDescription: finalDescription,
|
htmlDescription: finalDescription,
|
||||||
isDraft: true,
|
isDraft: true,
|
||||||
|
|
@ -655,9 +652,8 @@ export default function FormTeks() {
|
||||||
.replace(/[^a-z0-9-]/g, ""),
|
.replace(/[^a-z0-9-]/g, ""),
|
||||||
tags: finalTags,
|
tags: finalTags,
|
||||||
title: finalTitle,
|
title: finalTitle,
|
||||||
typeId: 1, // Image content type
|
typeId: 3,
|
||||||
};
|
};
|
||||||
// Use new Articles API
|
|
||||||
const response = await createArticle(articleData);
|
const response = await createArticle(articleData);
|
||||||
console.log("Article Data Submitted:", articleData);
|
console.log("Article Data Submitted:", articleData);
|
||||||
console.log("Article API Response:", response);
|
console.log("Article API Response:", response);
|
||||||
|
|
@ -670,16 +666,12 @@ export default function FormTeks() {
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the article ID from the new API response
|
|
||||||
const articleId = response?.data?.data?.id;
|
const articleId = response?.data?.data?.id;
|
||||||
Cookies.set("idCreate", articleId, { expires: 1 });
|
Cookies.set("idCreate", articleId, { expires: 1 });
|
||||||
id = articleId;
|
id = articleId;
|
||||||
|
|
||||||
// Upload files using new article-files API
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
||||||
// Add all files to FormData
|
|
||||||
files.forEach((file, index) => {
|
files.forEach((file, index) => {
|
||||||
formData.append("files", file);
|
formData.append("files", file);
|
||||||
});
|
});
|
||||||
|
|
@ -701,10 +693,9 @@ export default function FormTeks() {
|
||||||
|
|
||||||
console.log("Files uploaded successfully:", uploadResponse);
|
console.log("Files uploaded successfully:", uploadResponse);
|
||||||
|
|
||||||
// Upload thumbnail using first file as thumbnail
|
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
const thumbnailFormData = new FormData();
|
const thumbnailFormData = new FormData();
|
||||||
thumbnailFormData.append("files", files[0]); // Use first file as thumbnail
|
thumbnailFormData.append("files", files[0]);
|
||||||
|
|
||||||
console.log("Uploading thumbnail for article:", articleId);
|
console.log("Uploading thumbnail for article:", articleId);
|
||||||
|
|
||||||
|
|
@ -719,7 +710,6 @@ export default function FormTeks() {
|
||||||
"Thumbnail upload failed:",
|
"Thumbnail upload failed:",
|
||||||
thumbnailResponse.message
|
thumbnailResponse.message
|
||||||
);
|
);
|
||||||
// Don't fail the whole process if thumbnail upload fails
|
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
console.log(
|
||||||
"Thumbnail uploaded successfully:",
|
"Thumbnail uploaded successfully:",
|
||||||
|
|
@ -728,7 +718,6 @@ export default function FormTeks() {
|
||||||
}
|
}
|
||||||
} catch (thumbnailError) {
|
} catch (thumbnailError) {
|
||||||
console.warn("Thumbnail upload error:", thumbnailError);
|
console.warn("Thumbnail upload error:", thumbnailError);
|
||||||
// Don't fail the whole process if thumbnail upload fails
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (uploadError) {
|
} catch (uploadError) {
|
||||||
|
|
@ -741,7 +730,6 @@ export default function FormTeks() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show success message
|
|
||||||
MySwal.fire({
|
MySwal.fire({
|
||||||
title: "Sukses",
|
title: "Sukses",
|
||||||
text: "Article dan files berhasil disimpan.",
|
text: "Article dan files berhasil disimpan.",
|
||||||
|
|
@ -749,7 +737,7 @@ export default function FormTeks() {
|
||||||
confirmButtonColor: "#3085d6",
|
confirmButtonColor: "#3085d6",
|
||||||
confirmButtonText: "OK",
|
confirmButtonText: "OK",
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
router.push("/admin/content/document");
|
router.push("/admin/content/text");
|
||||||
});
|
});
|
||||||
|
|
||||||
Cookies.remove("idCreate");
|
Cookies.remove("idCreate");
|
||||||
|
|
@ -980,8 +968,8 @@ export default function FormTeks() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div className="flex flex-col lg:flex-row gap-10">
|
<div className="flex flex-col lg:flex-row gap-10 border rounded-lg">
|
||||||
<Card className="w-full lg:w-8/12">
|
<Card className="w-full lg:w-8/12 m-2">
|
||||||
<div className="px-6 py-6">
|
<div className="px-6 py-6">
|
||||||
<p className="text-lg font-semibold mb-3">Form Document</p>
|
<p className="text-lg font-semibold mb-3">Form Document</p>
|
||||||
<div className="gap-5 mb-5">
|
<div className="gap-5 mb-5">
|
||||||
|
|
@ -1428,7 +1416,7 @@ export default function FormTeks() {
|
||||||
{/* Submit Button */}
|
{/* Submit Button */}
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
<div className="w-full lg:w-4/12">
|
<div className="w-full lg:w-4/12 m-2">
|
||||||
<Card className=" h-[500px]">
|
<Card className=" h-[500px]">
|
||||||
<div className="px-3 py-3">
|
<div className="px-3 py-3">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
|
|
@ -1561,6 +1549,7 @@ export default function FormTeks() {
|
||||||
id={option.id}
|
id={option.id}
|
||||||
checked={isChecked}
|
checked={isChecked}
|
||||||
onCheckedChange={handleChange}
|
onCheckedChange={handleChange}
|
||||||
|
className="border"
|
||||||
/>
|
/>
|
||||||
<Label htmlFor={option.id}>{option.label}</Label>
|
<Label htmlFor={option.id}>{option.label}</Label>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@ import React from "react";
|
||||||
|
|
||||||
type FileData = {
|
type FileData = {
|
||||||
url: string;
|
url: string;
|
||||||
format: string; // extension with dot, e.g. ".pdf"
|
format: string; // bisa ".pdf" atau "mp4" atau "image/jpeg"
|
||||||
fileName?: string;
|
fileName?: string;
|
||||||
|
type?: string; // optional dari API (misal: video/mp4)
|
||||||
};
|
};
|
||||||
|
|
||||||
interface FilePreviewProps {
|
interface FilePreviewProps {
|
||||||
|
|
@ -11,48 +12,102 @@ interface FilePreviewProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const FileTextPreview: React.FC<FilePreviewProps> = ({ file }) => {
|
const FileTextPreview: React.FC<FilePreviewProps> = ({ file }) => {
|
||||||
const format = file.format.toLowerCase();
|
const format = (file.format || "").toLowerCase();
|
||||||
|
const type = (file.type || "").toLowerCase();
|
||||||
|
|
||||||
if ([".jpg", ".jpeg", ".png", ".webp"].includes(format)) {
|
// 🖼️ Gambar
|
||||||
|
if (
|
||||||
|
[".jpg", ".jpeg", ".png", ".webp", ".gif"].some((ext) =>
|
||||||
|
format.includes(ext)
|
||||||
|
) ||
|
||||||
|
type.includes("image")
|
||||||
|
) {
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
className="object-fill h-full w-full rounded-md"
|
className="object-contain h-[500px] w-full rounded-md bg-black"
|
||||||
src={file.url}
|
src={file.url}
|
||||||
alt={file.fileName || "File"}
|
alt={file.fileName || "Image File"}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format === ".pdf") {
|
// 🎬 Video
|
||||||
|
if (
|
||||||
|
["mp4", "mov", "avi", ".mp4", ".mov", ".avi"].some((ext) =>
|
||||||
|
format.includes(ext)
|
||||||
|
) ||
|
||||||
|
type.includes("video")
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<video
|
||||||
|
className="object-contain h-[500px] w-full rounded-md bg-black"
|
||||||
|
controls
|
||||||
|
>
|
||||||
|
<source src={file.url} type={type || "video/mp4"} />
|
||||||
|
Browser Anda tidak mendukung video tag.
|
||||||
|
</video>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🎧 Audio
|
||||||
|
if (
|
||||||
|
["mp3", "wav", "ogg", ".mp3", ".wav", ".ogg"].some((ext) =>
|
||||||
|
format.includes(ext)
|
||||||
|
) ||
|
||||||
|
type.includes("audio")
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center h-[200px] bg-gray-100 rounded-md">
|
||||||
|
<audio controls className="w-full max-w-[90%]">
|
||||||
|
<source src={file.url} type={type || "audio/mpeg"} />
|
||||||
|
Browser Anda tidak mendukung audio tag.
|
||||||
|
</audio>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 📄 PDF
|
||||||
|
if (format.includes(".pdf") || type.includes("pdf")) {
|
||||||
return (
|
return (
|
||||||
<iframe
|
<iframe
|
||||||
className="w-full h-96 rounded-md"
|
className="w-full h-[600px] rounded-md"
|
||||||
src={`https://drive.google.com/viewerng/viewer?embedded=true&url=${encodeURIComponent(file.url)}`}
|
src={`https://drive.google.com/viewerng/viewer?embedded=true&url=${encodeURIComponent(
|
||||||
|
file.url
|
||||||
|
)}`}
|
||||||
title={file.fileName || "PDF File"}
|
title={file.fileName || "PDF File"}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([".doc", ".docx", ".ppt", ".pptx", ".xls", ".xlsx"].includes(format)) {
|
// 🧾 Dokumen Office
|
||||||
|
if (
|
||||||
|
[".doc", ".docx", ".ppt", ".pptx", ".xls", ".xlsx"].some((ext) =>
|
||||||
|
format.includes(ext)
|
||||||
|
)
|
||||||
|
) {
|
||||||
return (
|
return (
|
||||||
<iframe
|
<iframe
|
||||||
className="w-full h-96 rounded-md"
|
className="w-full h-[600px] rounded-md"
|
||||||
src={`https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(file.url)}`}
|
src={`https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(
|
||||||
title={file.fileName || "Document"}
|
file.url
|
||||||
|
)}`}
|
||||||
|
title={file.fileName || "Office Document"}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback → unknown format
|
// 🔗 Default fallback → link download
|
||||||
return (
|
return (
|
||||||
<a
|
<div className="text-center py-20">
|
||||||
href={file.url}
|
<a
|
||||||
target="_blank"
|
href={file.url}
|
||||||
rel="noopener noreferrer"
|
target="_blank"
|
||||||
className="block text-blue-500 underline"
|
rel="noopener noreferrer"
|
||||||
>
|
className="text-blue-500 underline"
|
||||||
View {file.fileName || "File"}
|
>
|
||||||
</a>
|
Lihat {file.fileName || "File"}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,32 +117,52 @@ export default function MediaUpdate() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (contentType === "all") {
|
||||||
|
// setFilteredData(dataToRender);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
// Function to filter data by content type
|
// Function to filter data by content type
|
||||||
|
|
||||||
|
// function filterDataByContentType() {
|
||||||
|
// const filtered = dataToRender.filter((item) => {
|
||||||
|
// // Determine content type based on item properties
|
||||||
|
// const hasVideo = item.videoUrl || item.videoPath;
|
||||||
|
// const hasAudio = item.audioUrl || item.audioPath;
|
||||||
|
// const hasImage =
|
||||||
|
// item.smallThumbnailLink || item.thumbnailUrl || item.imageUrl;
|
||||||
|
// const hasText = item.content || item.description;
|
||||||
|
|
||||||
|
// switch (contentType) {
|
||||||
|
// case "audiovisual":
|
||||||
|
// return hasVideo;
|
||||||
|
// case "audio":
|
||||||
|
// return hasAudio && !hasVideo;
|
||||||
|
// case "foto":
|
||||||
|
// return hasImage && !hasVideo && !hasAudio;
|
||||||
|
// case "text":
|
||||||
|
// return hasText && !hasVideo && !hasAudio && !hasImage;
|
||||||
|
// default:
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// setFilteredData(filtered);
|
||||||
|
// }
|
||||||
|
|
||||||
function filterDataByContentType() {
|
function filterDataByContentType() {
|
||||||
// if (contentType === "all") {
|
|
||||||
// setFilteredData(dataToRender);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
const filtered = dataToRender.filter((item) => {
|
const filtered = dataToRender.filter((item) => {
|
||||||
// Determine content type based on item properties
|
|
||||||
const hasVideo = item.videoUrl || item.videoPath;
|
|
||||||
const hasAudio = item.audioUrl || item.audioPath;
|
|
||||||
const hasImage =
|
|
||||||
item.smallThumbnailLink || item.thumbnailUrl || item.imageUrl;
|
|
||||||
const hasText = item.content || item.description;
|
|
||||||
|
|
||||||
switch (contentType) {
|
switch (contentType) {
|
||||||
case "audiovisual":
|
case "audiovisual":
|
||||||
return hasVideo && (hasAudio || hasImage);
|
return item.typeId === 2; // Video
|
||||||
case "audio":
|
case "audio":
|
||||||
return hasAudio && !hasVideo;
|
return item.typeId === 4; // Audio
|
||||||
case "foto":
|
case "foto":
|
||||||
return hasImage && !hasVideo && !hasAudio;
|
return item.typeId === 1; // Image
|
||||||
case "text":
|
case "text":
|
||||||
return hasText && !hasVideo && !hasAudio && !hasImage;
|
return item.typeId === 3; // Text
|
||||||
default:
|
default:
|
||||||
return true;
|
return true; // Semua jenis
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue