This commit is contained in:
hanif salafi 2025-10-03 22:37:29 +07:00
commit 6871934fe6
20 changed files with 1330 additions and 152 deletions

View File

@ -106,7 +106,7 @@ const columns: ColumnDef<any>[] = [
<DropdownMenuContent className="p-0" align="end"> <DropdownMenuContent className="p-0" align="end">
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none"> <DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
<Link <Link
href={`/admin/broadcast/campaign-list/account-list/edit/${row.original.id}`} href={`/admin/broadcast/campaign-list/account-list/edit/${row.original.mediaBlastAccountId}`}
> >
Edit Edit
</Link> </Link>

View File

@ -37,46 +37,74 @@ import { Checkbox } from "@/components/ui/checkbox";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { useParams } from "next/navigation"; import { useParams } from "next/navigation";
import { useEffect } from "react"; import { useEffect } from "react";
import {
getUserById,
saveUserInternal,
} from "@/service/management-user/management-user";
// const FormSchema = z.object({
// fullname: z.string({
// required_error: "Required",
// }),
// // accountType: z
// // .array(z.string())
// // .refine((value) => value.some((item) => item), {
// // message: "Required",
// // }),
// // accountCategory: z.enum(["polri", "jurnalis", "umum", "ksp"], {
// // required_error: "Required",
// // }),
// email: z.string({
// required_error: "Required",
// }),
// phoneNumber: z.string({
// required_error: "Required",
// }),
// });
const FormSchema = z.object({ const FormSchema = z.object({
name: z.string({ fullname: z.string({ required_error: "Required" }),
required_error: "Required", email: z.string({ required_error: "Required" }),
}), phoneNumber: z.string({ required_error: "Required" }),
accountType: z username: z.string().optional(),
.array(z.string()) role: z.string().optional(),
.refine((value) => value.some((item) => item), { level: z.string().optional(),
message: "Required", nrp: z.string().optional(),
}), address: z.string().optional(),
accountCategory: z.enum(["polri", "jurnalis", "umumu", "ksp"], { password: z.string().optional(),
required_error: "Required", confirmPassword: z.string().optional(),
}),
email: z.string({
required_error: "Required",
}),
whatsapp: z.string({
required_error: "Required",
}),
}); });
export default function EditAccountForBroadcast() { export default function EditAccountForBroadcast() {
const id = useParams()?.id; const id = useParams()?.id;
const MySwal = withReactContent(Swal); const MySwal = withReactContent(Swal);
const router = useRouter(); const router = useRouter();
const form = useForm<z.infer<typeof FormSchema>>({ const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema), resolver: zodResolver(FormSchema),
defaultValues: { accountType: [] }, // defaultValues: { accountType: [] },
}); });
useEffect(() => { useEffect(() => {
async function getDetailData() { async function getDetailData() {
const response = await getMediaBlastAccount(String(id)); const response = await getUserById(String(id));
const details = response?.data?.data; const details = response?.data?.data;
// console.log("new", details); console.log("Response full:", response);
form.setValue("name", details.accountName); form.setValue("fullname", details?.fullname);
form.setValue("email", details?.emailAddress); form.setValue("username", details?.username);
form.setValue("whatsapp", details?.whatsappNumber); form.setValue("phoneNumber", details?.phoneNumber);
form.setValue("accountCategory", details?.accountCategory); // form.setValue("nrp", details?.memberIdentity);
form.setValue("accountType", details?.accountType.split(",")); // form.setValue("address", details?.address);
form.setValue("email", details?.email);
form.setValue("role", details?.role?.code);
// form.setValue("level", String(details?.userLevelId));
// form.setValue("name", details?.accountName);
// form.setValue("fullname", details?.fullname);
// form.setValue("email", details?.email);
// form.setValue("phoneNumber", details?.phoneNumber);
// form.setValue("whatsapp", details?.whatsappNumber);
// form.setValue("accountCategory", details?.accountCategory);
// form.setValue("accountType", details?.accountType.split(","));
} }
getDetailData(); getDetailData();
@ -106,7 +134,7 @@ export default function EditAccountForBroadcast() {
confirmButtonText: "OK", confirmButtonText: "OK",
}).then((result) => { }).then((result) => {
if (result.isConfirmed) { if (result.isConfirmed) {
router.push("/admin/broadcast/campaign-list/account-list"); router.push("/admin/broadcast/campaign-list");
} }
}); });
} }
@ -114,15 +142,24 @@ export default function EditAccountForBroadcast() {
const save = async (data: z.infer<typeof FormSchema>) => { const save = async (data: z.infer<typeof FormSchema>) => {
const reqData = { const reqData = {
id: String(id), id: String(id),
accountName: data.name, // accountName: data.fullname,
accountType: data.accountType.join(","), // accountType: data.accountType.join(","),
accountCategory: data.accountCategory, // accountCategory: data.accountCategory,
emailAddress: data.email, // emailAddress: data.email,
whatsappNumber: data.whatsapp, phoneNumber: data.phoneNumber,
firstName: data.fullname,
username: data.username,
roleId: data.role,
// userLevelId: Number(data.level),
// memberIdentity: data.nrp,
// address: data.address,
email: data.email,
isDefault: false,
isAdmin: true,
}; };
// console.log("data", data); // console.log("data", data);
const response = await saveMediaBlastAccount(reqData); const response = await saveUserInternal(reqData);
if (response?.error) { if (response?.error) {
error(response.message); error(response.message);
return false; return false;
@ -141,7 +178,7 @@ export default function EditAccountForBroadcast() {
<p className="fonnt-semibold">Account</p> <p className="fonnt-semibold">Account</p>
<FormField <FormField
control={form.control} control={form.control}
name="name" name="fullname"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Nama</FormLabel> <FormLabel>Nama</FormLabel>
@ -155,7 +192,7 @@ export default function EditAccountForBroadcast() {
</FormItem> </FormItem>
)} )}
/> />
<FormField {/* <FormField
control={form.control} control={form.control}
name="accountType" name="accountType"
render={() => ( render={() => (
@ -227,8 +264,8 @@ export default function EditAccountForBroadcast() {
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
)} )}
/> /> */}
<FormField {/* <FormField
control={form.control} control={form.control}
name="accountCategory" name="accountCategory"
render={({ field }) => ( render={({ field }) => (
@ -269,13 +306,13 @@ export default function EditAccountForBroadcast() {
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
)} )}
/> /> */}
<FormField <FormField
control={form.control} control={form.control}
name="email" name="email"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Nama</FormLabel> <FormLabel>Email</FormLabel>
<Input <Input
type="email" type="email"
value={field.value} value={field.value}
@ -289,14 +326,14 @@ export default function EditAccountForBroadcast() {
/> />
<FormField <FormField
control={form.control} control={form.control}
name="whatsapp" name="phoneNumber"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Nama</FormLabel> <FormLabel>Nomor Whatsapp</FormLabel>
<Input <Input
type="number" type="number"
value={field.value} value={field.value}
placeholder="Masukkan whatsapp" placeholder="Masukkan nomor whatsapp"
onChange={field.onChange} onChange={field.onChange}
/> />

View File

@ -11,7 +11,6 @@ import {
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Link, useRouter } from "@/i18n/routing"; import { Link, useRouter } from "@/i18n/routing";
import { close, error, loading, success } from "@/config/swal"; import { close, error, loading, success } from "@/config/swal";
import { deleteMediaBlastCampaign } from "@/service/broadcast/broadcast"; import { deleteMediaBlastCampaign } from "@/service/broadcast/broadcast";
@ -62,38 +61,47 @@ const columns: ColumnDef<any>[] = [
{ {
id: "actions", id: "actions",
accessorKey: "action",
header: "Actions", header: "Actions",
enableHiding: false, cell: ({ row, onDeleteSuccess }: any) => {
cell: ({ row }) => {
const MySwal = withReactContent(Swal); const MySwal = withReactContent(Swal);
const handleDelete = (id: any) => { const handleDelete = (id: number) => {
MySwal.fire({ MySwal.fire({
title: "Apakah anda ingin menghapus data?", title: "Apakah anda ingin menghapus data?",
showCancelButton: true, showCancelButton: true,
confirmButtonColor: "#dc3545", confirmButtonColor: "#dc3545",
confirmButtonText: "Iya", confirmButtonText: "Iya",
cancelButtonText: "Tidak", cancelButtonText: "Tidak",
}).then((result: any) => { }).then((result) => {
if (result.isConfirmed) { if (result.isConfirmed) {
doDeleteAccount(id); doDeleteAccount(id);
} }
}); });
}; };
async function doDeleteAccount(id: any) { async function doDeleteAccount(id: number) {
loading(); loading();
const response = await deleteMediaBlastCampaign(id); const response = await deleteMediaBlastCampaign(id);
close(); close();
if (response.error) { if (response.error) {
error(response.message); error(response.message);
return false; return false;
} }
// success(); console.log("Delete response:", response);
MySwal.fire({
icon: "success",
title: "Berhasil!",
text: "Data berhasil dihapus.",
confirmButtonColor: "#3085d6",
timer: 2000,
timerProgressBar: true,
});
// ✅ panggil callback dari parent
onDeleteSuccess?.(id);
} }
return ( return (
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
@ -119,14 +127,99 @@ const columns: ColumnDef<any>[] = [
Edit Edit
</DropdownMenuItem> </DropdownMenuItem>
</Link> </Link>
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none cursor-pointer"> <DropdownMenuItem
<a>Delete</a> onClick={() => handleDelete(row.original.id)}
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none cursor-pointer"
>
Delete
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
); );
}, },
}, },
// {
// id: "actions",
// accessorKey: "action",
// header: "Actions",
// enableHiding: false,
// cell: ({ row, onDeleteSuccess }: any) => {
// const MySwal = withReactContent(Swal);
// const handleDelete = (id: any) => {
// MySwal.fire({
// title: "Apakah anda ingin menghapus data?",
// showCancelButton: true,
// confirmButtonColor: "#dc3545",
// confirmButtonText: "Iya",
// cancelButtonText: "Tidak",
// }).then((result: any) => {
// if (result.isConfirmed) {
// doDeleteAccount(id);
// }
// });
// };
// async function doDeleteAccount(id: any) {
// loading();
// const response = await deleteMediaBlastCampaign(id);
// close();
// if (response.error) {
// error(response.message);
// return false;
// }
// console.log("Delete response:", response);
// MySwal.fire({
// icon: "success",
// title: "Berhasil!",
// text: "Data berhasil dihapus.",
// confirmButtonColor: "#3085d6",
// timer: 2000,
// timerProgressBar: true,
// });
// // ✅ langsung hapus dari state
// onDeleteSuccess?.(id);
// }
// return (
// <DropdownMenu>
// <DropdownMenuTrigger asChild>
// <Button
// size="icon"
// className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
// >
// <MoreVertical className="h-4 w-4 text-default-800" />
// </Button>
// </DropdownMenuTrigger>
// <DropdownMenuContent className="p-0" align="end">
// <Link
// href={`/admin/broadcast/campaign-list/detail/${row.original.id}`}
// >
// <DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none cursor-pointer">
// Detail
// </DropdownMenuItem>
// </Link>
// <Link
// href={`//admin/broadcast/campaign-list/edit/${row.original.id}`}
// >
// <DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none cursor-pointer">
// Edit
// </DropdownMenuItem>
// </Link>
// <DropdownMenuItem
// onClick={() => handleDelete(row.original.id)}
// className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none cursor-pointer"
// >
// Delete
// </DropdownMenuItem>
// </DropdownMenuContent>
// </DropdownMenu>
// );
// },
// },
]; ];
export default columns; export default columns;

View File

@ -89,6 +89,11 @@ const CampaignListTable = () => {
const [page, setPage] = React.useState(1); const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1); const [totalPage, setTotalPage] = React.useState(1);
function handleDeleteSuccess(id: number) {
setDataTable((prev) => prev.filter((item) => item.id !== id));
}
const table = useReactTable({ const table = useReactTable({
data: dataTable, data: dataTable,
columns, columns,
@ -189,7 +194,15 @@ const CampaignListTable = () => {
> >
{row.getVisibleCells().map((cell) => ( {row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}> <TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())} {/* {flexRender(cell.column.columnDef.cell, cell.getContext())} */}
{flexRender(cell.column.columnDef.cell, {
...cell.getContext(),
onDeleteSuccess: (id: number) => {
setDataTable((prev) =>
prev.filter((item) => item.id !== id)
);
},
})}
</TableCell> </TableCell>
))} ))}
</TableRow> </TableRow>

View File

@ -221,7 +221,6 @@ export default function EditUserForm() {
form.setValue("level", String(res?.userLevelId)); form.setValue("level", String(res?.userLevelId));
} else { } else {
initFetch(); initFetch();
// console.log("sadad", res?.role?.code);
form.setValue("fullname", res?.fullname); form.setValue("fullname", res?.fullname);
form.setValue("username", res?.username); form.setValue("username", res?.username);
form.setValue("phoneNumber", res?.phoneNumber); form.setValue("phoneNumber", res?.phoneNumber);

View File

@ -10,15 +10,34 @@ export default function StatusToogle(props: {
}) { }) {
const { id, initValue } = props; const { id, initValue } = props;
const router = useRouter(); const router = useRouter();
// const publishCategory = async (id: number, status: string) => {
// const response = await publishUnpublishCategory(id, status);
// console.log(response);
// if (response?.error) {
// error(response.message);
// return false;
// }
// router.push("/admin/settings/category?dataChange=true");
// };
const publishCategory = async (id: number, status: string) => { const publishCategory = async (id: number, status: string) => {
const response = await publishUnpublishCategory(id, status); const response = await publishUnpublishCategory(id, status);
// console.log(response); console.log("API Response:", response);
// cek error interceptor
if (response?.error) { if (response?.error) {
error(response.message); error(response.message || "Terjadi kesalahan");
return false; return false;
} }
// cek flag success asli dari backend
if (response?.data?.success === false) {
error(response?.data?.message || "Terjadi kesalahan");
return false;
}
router.push("/admin/settings/category?dataChange=true"); router.push("/admin/settings/category?dataChange=true");
}; };
return ( return (
<Switch <Switch
id={String(id)} id={String(id)}

View File

@ -27,22 +27,10 @@ import {
import { useSearchParams } from "next/navigation"; import { useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination"; import TablePagination from "@/components/table/table-pagination";
import columns from "./column";
import { listEnableCategory } from "@/service/content/content";
import { Checkbox } from "@/components/ui/checkbox"; import { Checkbox } from "@/components/ui/checkbox";
import { close, loading } from "@/config/swal"; import { close, loading } from "@/config/swal";
import { Link, useRouter } from "@/i18n/routing"; import { Link, useRouter } from "@/i18n/routing";
import { NewCampaignIcon } from "@/components/icon";
import { getCategories } from "@/service/settings/settings"; import { getCategories } from "@/service/settings/settings";
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { import {
Popover, Popover,

View File

@ -0,0 +1,186 @@
import AllContentPage from "@/components/landing-page/all-content-page";
const regions = [
{ name: "Polda Aceh", slug: "aceh", logo: "/logo/polda/polda-aceh.png" },
{ name: "Polda Bali", slug: "bali", logo: "/logo/polda/polda-bali.png" },
{
name: "Polda Bangka Belitung",
slug: "bangka-belitung",
logo: "/logo/polda/polda-bangka-belitung.png",
},
{
name: "Polda Banten",
slug: "banten",
logo: "/logo/polda/polda-banten.png",
},
{
name: "Polda Bengkulu",
slug: "bengkulu",
logo: "/logo/polda/polda-bengkulu.png",
},
{
name: "Polda DIY",
slug: "jogja",
logo: "/logo/polda/polda-jogja.png",
},
{
name: "Polda Gorontalo",
slug: "gorontalo",
logo: "/logo/polda/polda-gorontalo.png",
},
{ name: "Polda Jambi", slug: "jambi", logo: "/logo/polda/polda-jambi.png" },
{
name: "Polda Jawa Barat",
slug: "jawa-barat",
logo: "/logo/polda/polda-jawa-barat.png",
},
{
name: "Polda Jawa Tengah",
slug: "jawa-tengah",
logo: "/logo/polda/polda-jawa-tengah.png",
},
{
name: "Polda Jawa Timur",
slug: "jawa-timur",
logo: "/logo/polda/polda-jawa-timur.png",
},
{
name: "Polda Kalimantan Barat",
slug: "kalimantan-barat",
logo: "/logo/polda/polda-kalimantan-barat.png",
},
{
name: "Polda Kalimantan Selatan",
slug: "kalimantan-selatan",
logo: "/logo/polda/polda-kalimantan-selatan.png",
},
{
name: "Polda Kalimantan Tengah",
slug: "kalimantan-tengah",
logo: "/logo/polda/polda-kalimantan-tengah.png",
},
{
name: "Polda Kalimantan Timur",
slug: "kalimantan-timur",
logo: "/logo/polda/polda-kalimantan-timur.png",
},
{
name: "Polda Kalimantan Utara",
slug: "kalimantan-utara",
logo: "/logo/polda/polda-kalimantan-utara.png",
},
{
name: "Polda Kepulauan Riau",
slug: "kepulauan-riau",
logo: "/logo/polda/polda-kepulauan-riau.png",
},
{
name: "Polda Lampung",
slug: "lampung",
logo: "/logo/polda/polda-lampung.png",
},
{
name: "Polda Maluku",
slug: "maluku",
logo: "/logo/polda/polda-maluku.png",
},
{
name: "Polda Maluku Utara",
slug: "maluku-utara",
logo: "/logo/polda/polda-maluku-utara.png",
},
{
name: "Polda Metro Jaya",
slug: "metro-jaya",
logo: "/logo/polda/polda-metro-jaya.png",
},
{
name: "Polda NTB",
slug: "ntb",
logo: "/logo/polda/polda-ntb.png",
},
{
name: "Polda NTT",
slug: "ntt",
logo: "/logo/polda/polda-ntt.png",
},
{ name: "Polda Papua", slug: "papua", logo: "/logo/polda/polda-papua.png" },
{
name: "Polda Papua Barat",
slug: "papua-barat",
logo: "/logo/polda/polda-papua-barat.png",
},
{
name: "Polda Papua Barat Daya",
slug: "papua-barat-daya",
logo: "/logo/polda/polda-papua-barat-daya.png",
},
{
name: "Polda Papua Tengah",
slug: "papua-tengah",
logo: "/logo/polda/polda-papua-tengah.png",
},
{ name: "Polda Riau", slug: "riau", logo: "/logo/polda/polda-riau.png" },
{
name: "Polda Sulawesi Barat",
slug: "sulawesi-barat",
logo: "/logo/polda/polda-sulawesi-barat.png",
},
{
name: "Polda Sulawesi Selatan",
slug: "sulawesi-selatan",
logo: "/logo/polda/polda-sulawesi-selatan.png",
},
{
name: "Polda Sulawesi Tengah",
slug: "sulawesi-tengah",
logo: "/logo/polda/polda-sulawesi-tengah.png",
},
{
name: "Polda Sulawesi Tenggara",
slug: "sulawesi-tenggara",
logo: "/logo/polda/polda-sulawesi-tenggara.png",
},
{
name: "Polda Sulawesi Utara",
slug: "sulawesi-utara",
logo: "/logo/polda/polda-sulawesi-utara.png",
},
{
name: "Polda Sumatera Barat",
slug: "sumatera-barat",
logo: "/logo/polda/polda-sumatera-barat.png",
},
{
name: "Polda Sumatera Selatan",
slug: "sumatera-selatan",
logo: "/logo/polda/polda-sumatera-selatan.png",
},
{
name: "Polda Sumatera Utara",
slug: "sumatera-utara",
logo: "/logo/polda/polda-sumatera-utara.png",
},
// {
// name: "Satuan Kerja POLRI",
// slug: "satker-polri",
// logo: "/logo/satker/SATUAN-KERJA-POLRI.png",
// },
// {
// name: "Internasional",
// slug: "internasional",
// logo: "/assets/polda/internasional.png",
// },
];
export default function PoldaAllAudioPage() {
return (
<AllContentPage
typeId="4"
title="Semua Konten Audio per Polda"
basePath="audio"
mode="polda"
dataList={regions}
/>
);
}

View File

@ -0,0 +1,186 @@
import AllContentPage from "@/components/landing-page/all-content-page";
const regions = [
{ name: "Polda Aceh", slug: "aceh", logo: "/logo/polda/polda-aceh.png" },
{ name: "Polda Bali", slug: "bali", logo: "/logo/polda/polda-bali.png" },
{
name: "Polda Bangka Belitung",
slug: "bangka-belitung",
logo: "/logo/polda/polda-bangka-belitung.png",
},
{
name: "Polda Banten",
slug: "banten",
logo: "/logo/polda/polda-banten.png",
},
{
name: "Polda Bengkulu",
slug: "bengkulu",
logo: "/logo/polda/polda-bengkulu.png",
},
{
name: "Polda DIY",
slug: "jogja",
logo: "/logo/polda/polda-jogja.png",
},
{
name: "Polda Gorontalo",
slug: "gorontalo",
logo: "/logo/polda/polda-gorontalo.png",
},
{ name: "Polda Jambi", slug: "jambi", logo: "/logo/polda/polda-jambi.png" },
{
name: "Polda Jawa Barat",
slug: "jawa-barat",
logo: "/logo/polda/polda-jawa-barat.png",
},
{
name: "Polda Jawa Tengah",
slug: "jawa-tengah",
logo: "/logo/polda/polda-jawa-tengah.png",
},
{
name: "Polda Jawa Timur",
slug: "jawa-timur",
logo: "/logo/polda/polda-jawa-timur.png",
},
{
name: "Polda Kalimantan Barat",
slug: "kalimantan-barat",
logo: "/logo/polda/polda-kalimantan-barat.png",
},
{
name: "Polda Kalimantan Selatan",
slug: "kalimantan-selatan",
logo: "/logo/polda/polda-kalimantan-selatan.png",
},
{
name: "Polda Kalimantan Tengah",
slug: "kalimantan-tengah",
logo: "/logo/polda/polda-kalimantan-tengah.png",
},
{
name: "Polda Kalimantan Timur",
slug: "kalimantan-timur",
logo: "/logo/polda/polda-kalimantan-timur.png",
},
{
name: "Polda Kalimantan Utara",
slug: "kalimantan-utara",
logo: "/logo/polda/polda-kalimantan-utara.png",
},
{
name: "Polda Kepulauan Riau",
slug: "kepulauan-riau",
logo: "/logo/polda/polda-kepulauan-riau.png",
},
{
name: "Polda Lampung",
slug: "lampung",
logo: "/logo/polda/polda-lampung.png",
},
{
name: "Polda Maluku",
slug: "maluku",
logo: "/logo/polda/polda-maluku.png",
},
{
name: "Polda Maluku Utara",
slug: "maluku-utara",
logo: "/logo/polda/polda-maluku-utara.png",
},
{
name: "Polda Metro Jaya",
slug: "metro-jaya",
logo: "/logo/polda/polda-metro-jaya.png",
},
{
name: "Polda NTB",
slug: "ntb",
logo: "/logo/polda/polda-ntb.png",
},
{
name: "Polda NTT",
slug: "ntt",
logo: "/logo/polda/polda-ntt.png",
},
{ name: "Polda Papua", slug: "papua", logo: "/logo/polda/polda-papua.png" },
{
name: "Polda Papua Barat",
slug: "papua-barat",
logo: "/logo/polda/polda-papua-barat.png",
},
{
name: "Polda Papua Barat Daya",
slug: "papua-barat-daya",
logo: "/logo/polda/polda-papua-barat-daya.png",
},
{
name: "Polda Papua Tengah",
slug: "papua-tengah",
logo: "/logo/polda/polda-papua-tengah.png",
},
{ name: "Polda Riau", slug: "riau", logo: "/logo/polda/polda-riau.png" },
{
name: "Polda Sulawesi Barat",
slug: "sulawesi-barat",
logo: "/logo/polda/polda-sulawesi-barat.png",
},
{
name: "Polda Sulawesi Selatan",
slug: "sulawesi-selatan",
logo: "/logo/polda/polda-sulawesi-selatan.png",
},
{
name: "Polda Sulawesi Tengah",
slug: "sulawesi-tengah",
logo: "/logo/polda/polda-sulawesi-tengah.png",
},
{
name: "Polda Sulawesi Tenggara",
slug: "sulawesi-tenggara",
logo: "/logo/polda/polda-sulawesi-tenggara.png",
},
{
name: "Polda Sulawesi Utara",
slug: "sulawesi-utara",
logo: "/logo/polda/polda-sulawesi-utara.png",
},
{
name: "Polda Sumatera Barat",
slug: "sumatera-barat",
logo: "/logo/polda/polda-sumatera-barat.png",
},
{
name: "Polda Sumatera Selatan",
slug: "sumatera-selatan",
logo: "/logo/polda/polda-sumatera-selatan.png",
},
{
name: "Polda Sumatera Utara",
slug: "sumatera-utara",
logo: "/logo/polda/polda-sumatera-utara.png",
},
// {
// name: "Satuan Kerja POLRI",
// slug: "satker-polri",
// logo: "/logo/satker/SATUAN-KERJA-POLRI.png",
// },
// {
// name: "Internasional",
// slug: "internasional",
// logo: "/assets/polda/internasional.png",
// },
];
export default function PoldaAllDocumentPage() {
return (
<AllContentPage
typeId="3"
title="Semua Konten Teks per Polda"
basePath="document"
mode="polda"
dataList={regions}
/>
);
}

View File

@ -0,0 +1,186 @@
import AllContentPage from "@/components/landing-page/all-content-page";
const regions = [
{ name: "Polda Aceh", slug: "aceh", logo: "/logo/polda/polda-aceh.png" },
{ name: "Polda Bali", slug: "bali", logo: "/logo/polda/polda-bali.png" },
{
name: "Polda Bangka Belitung",
slug: "bangka-belitung",
logo: "/logo/polda/polda-bangka-belitung.png",
},
{
name: "Polda Banten",
slug: "banten",
logo: "/logo/polda/polda-banten.png",
},
{
name: "Polda Bengkulu",
slug: "bengkulu",
logo: "/logo/polda/polda-bengkulu.png",
},
{
name: "Polda DIY",
slug: "jogja",
logo: "/logo/polda/polda-jogja.png",
},
{
name: "Polda Gorontalo",
slug: "gorontalo",
logo: "/logo/polda/polda-gorontalo.png",
},
{ name: "Polda Jambi", slug: "jambi", logo: "/logo/polda/polda-jambi.png" },
{
name: "Polda Jawa Barat",
slug: "jawa-barat",
logo: "/logo/polda/polda-jawa-barat.png",
},
{
name: "Polda Jawa Tengah",
slug: "jawa-tengah",
logo: "/logo/polda/polda-jawa-tengah.png",
},
{
name: "Polda Jawa Timur",
slug: "jawa-timur",
logo: "/logo/polda/polda-jawa-timur.png",
},
{
name: "Polda Kalimantan Barat",
slug: "kalimantan-barat",
logo: "/logo/polda/polda-kalimantan-barat.png",
},
{
name: "Polda Kalimantan Selatan",
slug: "kalimantan-selatan",
logo: "/logo/polda/polda-kalimantan-selatan.png",
},
{
name: "Polda Kalimantan Tengah",
slug: "kalimantan-tengah",
logo: "/logo/polda/polda-kalimantan-tengah.png",
},
{
name: "Polda Kalimantan Timur",
slug: "kalimantan-timur",
logo: "/logo/polda/polda-kalimantan-timur.png",
},
{
name: "Polda Kalimantan Utara",
slug: "kalimantan-utara",
logo: "/logo/polda/polda-kalimantan-utara.png",
},
{
name: "Polda Kepulauan Riau",
slug: "kepulauan-riau",
logo: "/logo/polda/polda-kepulauan-riau.png",
},
{
name: "Polda Lampung",
slug: "lampung",
logo: "/logo/polda/polda-lampung.png",
},
{
name: "Polda Maluku",
slug: "maluku",
logo: "/logo/polda/polda-maluku.png",
},
{
name: "Polda Maluku Utara",
slug: "maluku-utara",
logo: "/logo/polda/polda-maluku-utara.png",
},
{
name: "Polda Metro Jaya",
slug: "metro-jaya",
logo: "/logo/polda/polda-metro-jaya.png",
},
{
name: "Polda NTB",
slug: "ntb",
logo: "/logo/polda/polda-ntb.png",
},
{
name: "Polda NTT",
slug: "ntt",
logo: "/logo/polda/polda-ntt.png",
},
{ name: "Polda Papua", slug: "papua", logo: "/logo/polda/polda-papua.png" },
{
name: "Polda Papua Barat",
slug: "papua-barat",
logo: "/logo/polda/polda-papua-barat.png",
},
{
name: "Polda Papua Barat Daya",
slug: "papua-barat-daya",
logo: "/logo/polda/polda-papua-barat-daya.png",
},
{
name: "Polda Papua Tengah",
slug: "papua-tengah",
logo: "/logo/polda/polda-papua-tengah.png",
},
{ name: "Polda Riau", slug: "riau", logo: "/logo/polda/polda-riau.png" },
{
name: "Polda Sulawesi Barat",
slug: "sulawesi-barat",
logo: "/logo/polda/polda-sulawesi-barat.png",
},
{
name: "Polda Sulawesi Selatan",
slug: "sulawesi-selatan",
logo: "/logo/polda/polda-sulawesi-selatan.png",
},
{
name: "Polda Sulawesi Tengah",
slug: "sulawesi-tengah",
logo: "/logo/polda/polda-sulawesi-tengah.png",
},
{
name: "Polda Sulawesi Tenggara",
slug: "sulawesi-tenggara",
logo: "/logo/polda/polda-sulawesi-tenggara.png",
},
{
name: "Polda Sulawesi Utara",
slug: "sulawesi-utara",
logo: "/logo/polda/polda-sulawesi-utara.png",
},
{
name: "Polda Sumatera Barat",
slug: "sumatera-barat",
logo: "/logo/polda/polda-sumatera-barat.png",
},
{
name: "Polda Sumatera Selatan",
slug: "sumatera-selatan",
logo: "/logo/polda/polda-sumatera-selatan.png",
},
{
name: "Polda Sumatera Utara",
slug: "sumatera-utara",
logo: "/logo/polda/polda-sumatera-utara.png",
},
// {
// name: "Satuan Kerja POLRI",
// slug: "satker-polri",
// logo: "/logo/satker/SATUAN-KERJA-POLRI.png",
// },
// {
// name: "Internasional",
// slug: "internasional",
// logo: "/assets/polda/internasional.png",
// },
];
export default function PoldaAllImagePage() {
return (
<AllContentPage
typeId="1"
title="Semua Foto per Polda"
basePath="image"
mode="polda"
dataList={regions}
/>
);
}

View File

@ -0,0 +1,186 @@
import AllContentPage from "@/components/landing-page/all-content-page";
const regions = [
{ name: "Polda Aceh", slug: "aceh", logo: "/logo/polda/polda-aceh.png" },
{ name: "Polda Bali", slug: "bali", logo: "/logo/polda/polda-bali.png" },
{
name: "Polda Bangka Belitung",
slug: "bangka-belitung",
logo: "/logo/polda/polda-bangka-belitung.png",
},
{
name: "Polda Banten",
slug: "banten",
logo: "/logo/polda/polda-banten.png",
},
{
name: "Polda Bengkulu",
slug: "bengkulu",
logo: "/logo/polda/polda-bengkulu.png",
},
{
name: "Polda DIY",
slug: "jogja",
logo: "/logo/polda/polda-jogja.png",
},
{
name: "Polda Gorontalo",
slug: "gorontalo",
logo: "/logo/polda/polda-gorontalo.png",
},
{ name: "Polda Jambi", slug: "jambi", logo: "/logo/polda/polda-jambi.png" },
{
name: "Polda Jawa Barat",
slug: "jawa-barat",
logo: "/logo/polda/polda-jawa-barat.png",
},
{
name: "Polda Jawa Tengah",
slug: "jawa-tengah",
logo: "/logo/polda/polda-jawa-tengah.png",
},
{
name: "Polda Jawa Timur",
slug: "jawa-timur",
logo: "/logo/polda/polda-jawa-timur.png",
},
{
name: "Polda Kalimantan Barat",
slug: "kalimantan-barat",
logo: "/logo/polda/polda-kalimantan-barat.png",
},
{
name: "Polda Kalimantan Selatan",
slug: "kalimantan-selatan",
logo: "/logo/polda/polda-kalimantan-selatan.png",
},
{
name: "Polda Kalimantan Tengah",
slug: "kalimantan-tengah",
logo: "/logo/polda/polda-kalimantan-tengah.png",
},
{
name: "Polda Kalimantan Timur",
slug: "kalimantan-timur",
logo: "/logo/polda/polda-kalimantan-timur.png",
},
{
name: "Polda Kalimantan Utara",
slug: "kalimantan-utara",
logo: "/logo/polda/polda-kalimantan-utara.png",
},
{
name: "Polda Kepulauan Riau",
slug: "kepulauan-riau",
logo: "/logo/polda/polda-kepulauan-riau.png",
},
{
name: "Polda Lampung",
slug: "lampung",
logo: "/logo/polda/polda-lampung.png",
},
{
name: "Polda Maluku",
slug: "maluku",
logo: "/logo/polda/polda-maluku.png",
},
{
name: "Polda Maluku Utara",
slug: "maluku-utara",
logo: "/logo/polda/polda-maluku-utara.png",
},
{
name: "Polda Metro Jaya",
slug: "metro-jaya",
logo: "/logo/polda/polda-metro-jaya.png",
},
{
name: "Polda NTB",
slug: "ntb",
logo: "/logo/polda/polda-ntb.png",
},
{
name: "Polda NTT",
slug: "ntt",
logo: "/logo/polda/polda-ntt.png",
},
{ name: "Polda Papua", slug: "papua", logo: "/logo/polda/polda-papua.png" },
{
name: "Polda Papua Barat",
slug: "papua-barat",
logo: "/logo/polda/polda-papua-barat.png",
},
{
name: "Polda Papua Barat Daya",
slug: "papua-barat-daya",
logo: "/logo/polda/polda-papua-barat-daya.png",
},
{
name: "Polda Papua Tengah",
slug: "papua-tengah",
logo: "/logo/polda/polda-papua-tengah.png",
},
{ name: "Polda Riau", slug: "riau", logo: "/logo/polda/polda-riau.png" },
{
name: "Polda Sulawesi Barat",
slug: "sulawesi-barat",
logo: "/logo/polda/polda-sulawesi-barat.png",
},
{
name: "Polda Sulawesi Selatan",
slug: "sulawesi-selatan",
logo: "/logo/polda/polda-sulawesi-selatan.png",
},
{
name: "Polda Sulawesi Tengah",
slug: "sulawesi-tengah",
logo: "/logo/polda/polda-sulawesi-tengah.png",
},
{
name: "Polda Sulawesi Tenggara",
slug: "sulawesi-tenggara",
logo: "/logo/polda/polda-sulawesi-tenggara.png",
},
{
name: "Polda Sulawesi Utara",
slug: "sulawesi-utara",
logo: "/logo/polda/polda-sulawesi-utara.png",
},
{
name: "Polda Sumatera Barat",
slug: "sumatera-barat",
logo: "/logo/polda/polda-sumatera-barat.png",
},
{
name: "Polda Sumatera Selatan",
slug: "sumatera-selatan",
logo: "/logo/polda/polda-sumatera-selatan.png",
},
{
name: "Polda Sumatera Utara",
slug: "sumatera-utara",
logo: "/logo/polda/polda-sumatera-utara.png",
},
// {
// name: "Satuan Kerja POLRI",
// slug: "satker-polri",
// logo: "/logo/satker/SATUAN-KERJA-POLRI.png",
// },
// {
// name: "Internasional",
// slug: "internasional",
// logo: "/assets/polda/internasional.png",
// },
];
export default function PoldaAllVideoPage() {
return (
<AllContentPage
typeId="2"
title="Semua Konten Audio Visual per Polda"
basePath="video"
mode="polda"
dataList={regions}
/>
);
}

View File

@ -451,6 +451,7 @@ export default function FormImage() {
"" ""
); );
const articleImagesData = articleData?.imagesUrl?.split(","); const articleImagesData = articleData?.imagesUrl?.split(",");
setArticleBody(cleanArticleBody || "");
setValue("description", cleanArticleBody || ""); setValue("description", cleanArticleBody || "");
setDetailData(articleData); setDetailData(articleData);
setSelectedArticleId(id); setSelectedArticleId(id);
@ -1738,7 +1739,7 @@ export default function FormImage() {
{/* <Button type="submit" color="primary"> {/* <Button type="submit" color="primary">
{t("submit", { defaultValue: "Submit" })} {t("submit", { defaultValue: "Submit" })}
</Button> */} </Button> */}
{levelNumber !== "2" && levelNumber !== "3" && ( {levelNumber !== "2" && (
<Button type="submit" color="primary"> <Button type="submit" color="primary">
{t("submit", { defaultValue: "Submit" })} {t("submit", { defaultValue: "Submit" })}
</Button> </Button>

View File

@ -7,8 +7,6 @@ import { useParams, useRouter } from "next/navigation";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
// UI Components
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
@ -26,8 +24,6 @@ import {
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Checkbox } from "@/components/ui/checkbox"; import { Checkbox } from "@/components/ui/checkbox";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
// Icons
import { import {
AlertCircle, AlertCircle,
FileText, FileText,
@ -44,8 +40,6 @@ import {
CheckCircle, CheckCircle,
XCircle, XCircle,
} from "lucide-react"; } from "lucide-react";
// Swiper
import { Swiper, SwiperSlide } from "swiper/react"; import { Swiper, SwiperSlide } from "swiper/react";
import { Swiper as SwiperType } from "swiper"; import { Swiper as SwiperType } from "swiper";
import "swiper/css"; import "swiper/css";
@ -54,8 +48,6 @@ import "swiper/css/navigation";
import "swiper/css/pagination"; import "swiper/css/pagination";
import "swiper/css/thumbs"; import "swiper/css/thumbs";
import { FreeMode, Navigation, Pagination, Thumbs } from "swiper/modules"; import { FreeMode, Navigation, Pagination, Thumbs } from "swiper/modules";
// Services
import { import {
convertSPIT, convertSPIT,
deleteSPIT, deleteSPIT,
@ -64,15 +56,12 @@ import {
listEnableCategory, listEnableCategory,
} from "@/service/content/content"; } from "@/service/content/content";
import { generateDataRewrite, getDetailArticle } from "@/service/content/ai"; import { generateDataRewrite, getDetailArticle } from "@/service/content/ai";
// Utils
import { getCookiesDecrypt } from "@/lib/utils"; import { getCookiesDecrypt } from "@/lib/utils";
import { error } from "@/lib/swal"; import { error } from "@/lib/swal";
import Swal from "sweetalert2"; import Swal from "sweetalert2";
import withReactContent from "sweetalert2-react-content"; import withReactContent from "sweetalert2-react-content";
import { close, loading } from "@/config/swal"; import { close, loading } from "@/config/swal";
// Types
interface Category { interface Category {
id: number; id: number;
name: string; name: string;
@ -289,9 +278,7 @@ export default function FormConvertSPIT() {
try { try {
const response = await getTagsBySubCategoryId(categoryId); const response = await getTagsBySubCategoryId(categoryId);
if (response?.data?.data?.length > 0) { if (response?.data?.data?.length > 0) {
// Extract tag names from the response objects
const apiTags = response?.data?.data?.map((tag: any) => tag.tagName); const apiTags = response?.data?.data?.map((tag: any) => tag.tagName);
// Merge with existing tags, ensuring uniqueness
const tagsMerge = Array.from(new Set([...tags, ...apiTags])); const tagsMerge = Array.from(new Set([...tags, ...apiTags]));
setTags(tagsMerge); setTags(tagsMerge);
} }
@ -313,7 +300,6 @@ export default function FormConvertSPIT() {
setDetail(details); setDetail(details);
// <-- use API contentList objects directly -->
const contentList: FileType[] = (details.contentList || []).map( const contentList: FileType[] = (details.contentList || []).map(
(it: any) => ({ (it: any) => ({
contentId: it.contentId, contentId: it.contentId,
@ -329,11 +315,9 @@ export default function FormConvertSPIT() {
setFiles(contentList); setFiles(contentList);
setDetailThumb(contentList); setDetailThumb(contentList);
// Initialize file placements
const fileCount = contentList.length || 0; const fileCount = contentList.length || 0;
setFilePlacements(Array(fileCount).fill([])); setFilePlacements(Array(fileCount).fill([]));
// Set form values
setValue("contentTitle", details.contentTitle || ""); setValue("contentTitle", details.contentTitle || "");
setValue("contentDescription", details.contentDescription || ""); setValue("contentDescription", details.contentDescription || "");
setValue("contentCreator", details.contentCreator || ""); setValue("contentCreator", details.contentCreator || "");
@ -342,16 +326,16 @@ export default function FormConvertSPIT() {
(details as any).contentRewriteDescription || "" (details as any).contentRewriteDescription || ""
); );
// Set category and load category tags
if (details.categoryId) { if (details.categoryId) {
setSelectedCategoryId(details.categoryId); setSelectedCategoryId(details.categoryId);
await loadTags(details.categoryId); await loadTags(details.categoryId);
} }
// Set content tags and merge with category tags
if (details.contentTag) { if (details.contentTag) {
const contentTags = details.contentTag.split(",").map((tag: string) => tag.trim()); const contentTags = details.contentTag
setTags(prev => Array.from(new Set([...prev, ...contentTags]))); .split(",")
.map((tag: string) => tag.trim());
setTags((prev) => Array.from(new Set([...prev, ...contentTags])));
} }
} catch (error) { } catch (error) {
console.error("Failed to load detail:", error); console.error("Failed to load detail:", error);
@ -552,14 +536,24 @@ export default function FormConvertSPIT() {
); );
}; };
const getPlacementData = () => { const getPlacementData = (type: string) => {
const placementData: PlacementData[] = []; const placementData: PlacementData[] = [];
for (let i = 0; i < filePlacements.length; i++) { if (type == "mabes") {
if (filePlacements[i].length > 0) { for (let i = 0; i < filePlacements.length; i++) {
const placements = filePlacements[i]; if (filePlacements[i].length > 0) {
const placements = filePlacements[i];
placementData.push({
mediaFileId: files[i].contentId,
placements: placements.join(","),
});
}
}
} else {
for (let i = 0; i < files.length; i++) {
placementData.push({ placementData.push({
mediaFileId: files[i].contentId, mediaFileId: files[i].contentId,
placements: placements.join(","), placements: "polda",
}); });
} }
} }
@ -578,7 +572,6 @@ export default function FormConvertSPIT() {
return temp; return temp;
}; };
// Form submission
const onSubmit = async (data: FormData) => { const onSubmit = async (data: FormData) => {
const pnmhTags = tags.filter((tag) => tag.toLowerCase().includes("pnmh")); const pnmhTags = tags.filter((tag) => tag.toLowerCase().includes("pnmh"));
@ -624,7 +617,9 @@ export default function FormConvertSPIT() {
categoryId: selectedCategoryId, categoryId: selectedCategoryId,
publishedFor: publishedFor.join(","), publishedFor: publishedFor.join(","),
creator: data.contentCreator, creator: data.contentCreator,
files: isUserMabesApprover ? getPlacementData() : [], files: isUserMabesApprover
? getPlacementData("mabes")
: getPlacementData("polda"),
}; };
await convertSPIT(requestData); await convertSPIT(requestData);
@ -978,7 +973,10 @@ export default function FormConvertSPIT() {
centeredSlides={true} centeredSlides={true}
> >
{detailThumb.map((item) => ( {detailThumb.map((item) => (
<SwiperSlide key={item.contentId} className="!w-full"> <SwiperSlide
key={item.contentId}
className="!w-full"
>
{item.contentType === "VIDEO" ? ( {item.contentType === "VIDEO" ? (
<div className="relative w-full h-96 overflow-hidden rounded-lg"> <div className="relative w-full h-96 overflow-hidden rounded-lg">
<video <video
@ -989,8 +987,8 @@ export default function FormConvertSPIT() {
poster={item.thumbnailFileUrl || undefined} poster={item.thumbnailFileUrl || undefined}
title={`Video ${item.contentId}`} title={`Video ${item.contentId}`}
onError={(e) => { onError={(e) => {
console.error('Video load error:', e); console.error("Video load error:", e);
e.currentTarget.style.display = 'none'; e.currentTarget.style.display = "none";
}} }}
/> />
</div> </div>
@ -1000,10 +998,13 @@ export default function FormConvertSPIT() {
src={item.contentFile} src={item.contentFile}
alt={`Media ${item.contentId}`} alt={`Media ${item.contentId}`}
className="max-w-full max-h-full object-contain rounded-lg" className="max-w-full max-h-full object-contain rounded-lg"
style={{ maxWidth: '100%', maxHeight: '100%' }} style={{
maxWidth: "100%",
maxHeight: "100%",
}}
onError={(e) => { onError={(e) => {
console.error('Image load error:', e); console.error("Image load error:", e);
e.currentTarget.style.display = 'none'; e.currentTarget.style.display = "none";
}} }}
/> />
</div> </div>
@ -1047,7 +1048,10 @@ export default function FormConvertSPIT() {
preventClicksPropagation={false} preventClicksPropagation={false}
> >
{detailThumb.map((item) => ( {detailThumb.map((item) => (
<SwiperSlide key={`thumb-${item.contentId}`} className="!w-auto flex-shrink-0"> <SwiperSlide
key={`thumb-${item.contentId}`}
className="!w-auto flex-shrink-0"
>
{item.contentType === "VIDEO" ? ( {item.contentType === "VIDEO" ? (
<div className="relative w-20 h-16 rounded cursor-pointer overflow-hidden flex-shrink-0"> <div className="relative w-20 h-16 rounded cursor-pointer overflow-hidden flex-shrink-0">
{/* use preload metadata so browser doesn't download full video */} {/* use preload metadata so browser doesn't download full video */}
@ -1059,8 +1063,11 @@ export default function FormConvertSPIT() {
playsInline playsInline
tabIndex={-1} tabIndex={-1}
onError={(e) => { onError={(e) => {
console.error('Thumbnail video load error:', e); console.error(
e.currentTarget.style.display = 'none'; "Thumbnail video load error:",
e
);
e.currentTarget.style.display = "none";
}} }}
/> />
<div className="absolute inset-0 flex items-center justify-center bg-black/30 pointer-events-none"> <div className="absolute inset-0 flex items-center justify-center bg-black/30 pointer-events-none">
@ -1081,8 +1088,11 @@ export default function FormConvertSPIT() {
alt={`Thumbnail ${item.contentId}`} alt={`Thumbnail ${item.contentId}`}
className="w-full h-full object-cover" className="w-full h-full object-cover"
onError={(e) => { onError={(e) => {
console.error('Thumbnail image load error:', e); console.error(
e.currentTarget.style.display = 'none'; "Thumbnail image load error:",
e
);
e.currentTarget.style.display = "none";
}} }}
/> />
</div> </div>
@ -1138,7 +1148,6 @@ export default function FormConvertSPIT() {
key={file.contentId} key={file.contentId}
className="flex gap-4 p-4 border rounded-lg" className="flex gap-4 p-4 border rounded-lg"
> >
{/* show thumbnail or video preview */}
{file.contentType === "VIDEO" ? ( {file.contentType === "VIDEO" ? (
<video <video
src={file.contentFile} src={file.contentFile}

View File

@ -0,0 +1,211 @@
"use client";
import { useEffect, useState } from "react";
import Image from "next/image";
import Link from "next/link";
import { listDataRegional } from "@/service/landing/landing";
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel";
interface ContentItem {
id: number;
slug: string;
title: string;
thumbnailLink?: string;
categoryName?: string;
}
interface RegionOrSatker {
name: string;
slug: string;
logo: string;
}
interface AllContentPageProps {
typeId: string; // 1 = image, 2 = video, 3 = text, 4 = audio
title: string;
basePath: "image" | "video" | "document" | "audio";
mode: "polda" | "satker";
dataList: RegionOrSatker[];
}
export default function AllContentPage({
typeId,
title,
basePath,
mode,
dataList,
}: AllContentPageProps) {
const [contents, setContents] = useState<Record<string, ContentItem[]>>({});
useEffect(() => {
async function fetchData() {
const promises = dataList.map(async (region) => {
try {
const res = await listDataRegional(
typeId,
"",
"",
"",
"",
"",
"",
"",
"",
10,
0,
"createdAt"
);
return { slug: region.slug, data: res?.data?.data?.content || [] };
} catch {
return { slug: region.slug, data: [] };
}
});
const resultsArray = await Promise.all(promises);
const results: Record<string, ContentItem[]> = {};
resultsArray.forEach((r) => {
results[r.slug] = r.data;
});
setContents(results);
}
fetchData();
}, [typeId, dataList]);
function renderCard(item: ContentItem, regionSlug: string) {
const href = `/${mode}/${regionSlug}/${basePath}/detail/${item.slug}`;
// 🖼 Image & 🎥 Video sama
if (basePath === "image" || basePath === "video") {
return (
<Link
href={href}
className="block border rounded-md overflow-hidden hover:shadow-md transition"
>
{item.thumbnailLink && (
<Image
src={item.thumbnailLink}
alt={item.title}
width={400}
height={250}
className="w-full h-40 object-cover"
/>
)}
<div className="p-2 text-sm font-medium truncate">{item.title}</div>
</Link>
);
}
// 📄 Document
if (basePath === "document") {
return (
<Link
href={href}
className="cursor-pointer rounded-lg shadow-md overflow-hidden bg-white dark:bg-black dark:border dark:border-gray-500 block"
>
<div className="bg-[#e0c350] flex items-center justify-center h-[170px] text-white">
<svg
xmlns="http://www.w3.org/2000/svg"
width="80"
height="80"
viewBox="0 0 16 16"
>
<path
fill="currentColor"
d="M5 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V5.4a1.5 1.5 0 0 0-.44-1.06L9.6 1.4A1.5 1.5 0 0 0 8.6 1z"
/>
</svg>
</div>
<div className="p-4">
<div className="text-[12px] font-bold text-red-600 uppercase">
{item.categoryName?.toUpperCase() ?? "Document"}
</div>
<div className="font-semibold text-gray-900 dark:text-white text-xl leading-snug line-clamp-3">
{item.title}
</div>
</div>
</Link>
);
}
// 🎧 Audio
if (basePath === "audio") {
return (
<Link
href={href}
className="cursor-pointer bg-white dark:bg-black dark:border dark:border-gray-500 rounded-xl shadow-md hover:shadow-lg transition overflow-hidden block"
>
<div className="flex items-center justify-center bg-[#bb3523] w-full h-[170px] text-white">
<svg
xmlns="http://www.w3.org/2000/svg"
width="80"
height="80"
viewBox="0 0 20 20"
>
<path
fill="currentColor"
d="M14.7 2.2A1 1 0 0 1 16 3.2v6L8 11v6.5a2.5 2.5 0 1 1-1-2V5.4a1 1 0 0 1 .7-1z"
/>
</svg>
</div>
<div className="p-4">
<p className="text-[12px] font-bold text-[#bb3523] uppercase mb-1">
{item.categoryName?.toUpperCase() ?? "Audio"}
</p>
<p className="text-xl font-semibold text-black dark:text-white line-clamp-3">
{item.title}
</p>
</div>
</Link>
);
}
}
return (
<div className="max-w-7xl mx-auto px-4 py-8">
<h1 className="text-2xl font-bold mb-6">{title}</h1>
{dataList.map((region) => (
<div key={region.slug} className="mb-12">
{/* Header */}
<div className="flex items-center gap-3 mb-4">
<Image
src={region.logo}
alt={region.name}
width={40}
height={40}
className="rounded-full"
/>
<h2 className="text-lg font-semibold">{region.name}</h2>
</div>
{/* Carousel Konten */}
{contents[region.slug]?.length > 0 ? (
<Carousel className="w-full">
<CarouselContent>
{contents[region.slug].map((item) => (
<CarouselItem
key={item.id}
className="basis-2/3 md:basis-1/3 lg:basis-1/4"
>
{renderCard(item, region.slug)}
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
) : (
<p className="text-gray-500">Tidak ada konten di {region.name}</p>
)}
</div>
))}
</div>
);
}

View File

@ -196,6 +196,24 @@ export default function FilterAudioComponent(props: {
} }
} }
const basePath = asPath.includes("/polda/")
? `/${asPath.split("/")[1]}/${asPath.split("/")[2]}`
: "";
const type = group || asPath.includes("/polda/") ? "regional?" : "filter?";
const sort = sortByOpt === "popular" ? "sortBy=popular" : "sortBy=latest";
const titleParam = title ? `&title=${title?.toLowerCase()}` : "";
const categoryParam = categorie ? `&category=${categorie}` : "";
const fullQuery = `${type}${sort}${titleParam}${categoryParam}${
startDateString ? `&startDate=${startDateString}` : ""
}${endDateString ? `&endDate=${endDateString}` : ""}`;
const href = `${basePath}/image/${fullQuery}`;
return newContent?.length > 0 ? ( return newContent?.length > 0 ? (
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<p>{`Audio (${totalContent})`}</p> <p>{`Audio (${totalContent})`}</p>
@ -287,17 +305,18 @@ export default function FilterAudioComponent(props: {
</Carousel> </Carousel>
<div className="flex justify-center mt-1 mb-6"> <div className="flex justify-center mt-1 mb-6">
<Link <Link
href={ // href={
`${ // `${
asPath.includes("/polda/") // asPath.includes("/polda/")
? `/${asPath.split("/")[1]}/${asPath.split("/")[2]}` // ? `/${asPath.split("/")[1]}/${asPath.split("/")[2]}`
: "" // : ""
}/audio/` + // }/audio/` +
`${group ? "regional?" : "filter?"}` + // `${group ? "regional?" : "filter?"}` +
`sortBy=${sortBy === "popular" ? "popular" : "latest"}` + // `sortBy=${sortBy === "popular" ? "popular" : "latest"}` +
`${title ? `&title=${title.toLowerCase()}` : ""}` + // `${title ? `&title=${title.toLowerCase()}` : ""}` +
`${categorie ? `&category=${categorie}` : ""}` // `${categorie ? `&category=${categorie}` : ""}`
} // }
href={isRegional ? `/regional/all-polda/audio/all` : href}
className="border border-red-500 text-red-500 hover:bg-red-500 hover:text-white transition-colors duration-200 px-4 py-2 rounded-md text-sm" className="border border-red-500 text-red-500 hover:bg-red-500 hover:text-white transition-colors duration-200 px-4 py-2 rounded-md text-sm"
> >
Lihat Semua Lihat Semua

View File

@ -153,6 +153,24 @@ export default function FilterDocumentComponent(props: {
setTotalContent(data?.totalElements); setTotalContent(data?.totalElements);
} }
const basePath = asPath.includes("/polda/")
? `/${asPath.split("/")[1]}/${asPath.split("/")[2]}`
: "";
const type = group || asPath.includes("/polda/") ? "regional?" : "filter?";
const sort = sortByOpt === "popular" ? "sortBy=popular" : "sortBy=latest";
const titleParam = title ? `&title=${title?.toLowerCase()}` : "";
const categoryParam = categorie ? `&category=${categorie}` : "";
const fullQuery = `${type}${sort}${titleParam}${categoryParam}${
startDateString ? `&startDate=${startDateString}` : ""
}${endDateString ? `&endDate=${endDateString}` : ""}`;
const href = `${basePath}/image/${fullQuery}`;
return newContent?.length > 0 ? ( return newContent?.length > 0 ? (
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<p>{`Document (${totalContent})`}</p> <p>{`Document (${totalContent})`}</p>
@ -214,7 +232,7 @@ export default function FilterDocumentComponent(props: {
{newContent?.map((text: any) => ( {newContent?.map((text: any) => (
<CarouselItem key={text?.id} className="md:basis-1/2 lg:basis-1/3"> <CarouselItem key={text?.id} className="md:basis-1/2 lg:basis-1/3">
<Link <Link
href={`${prefixPath}/document/detail/${text?.slug href={`${prefixPath}/document/detail/${text?.slug
?.split("/") ?.split("/")
.pop()}`} .pop()}`}
// href={`${prefixPath}/document/detail/${text?.slug}`} // href={`${prefixPath}/document/detail/${text?.slug}`}
@ -260,15 +278,17 @@ export default function FilterDocumentComponent(props: {
</Carousel> </Carousel>
<div className="flex justify-center mt-1 mb-6"> <div className="flex justify-center mt-1 mb-6">
<Link <Link
href={`${ // href={`${
asPath.includes("/polda/") // asPath.includes("/polda/")
? `/${asPath.split("/")[1]}/${asPath.split("/")[2]}` // ? `/${asPath.split("/")[1]}/${asPath.split("/")[2]}`
: "" // : ""
}/document/${group ? "filter" : "regional"}?sortBy=${ // }/document/${group ? "filter" : "regional"}?sortBy=${
sortBy || "latest" // sortBy || "latest"
}${title ? `&title=${title.toLowerCase()}` : ""}${ // }${title ? `&title=${title.toLowerCase()}` : ""}${
categorie ? `&category=${categorie}` : "" // categorie ? `&category=${categorie}` : ""
}${group ? `&group=${group}` : ""}`} // }${group ? `&group=${group}` : ""}`}
href={isRegional ? `/regional/all-polda/document/all` : href}
className="border border-red-500 text-red-500 hover:bg-red-500 hover:text-white transition-colors duration-200 px-4 py-2 rounded-md text-sm" className="border border-red-500 text-red-500 hover:bg-red-500 hover:text-white transition-colors duration-200 px-4 py-2 rounded-md text-sm"
> >
Lihat Semua Lihat Semua

View File

@ -149,12 +149,17 @@ export default function FilterImageComponent(props: {
: ""; : "";
const type = group || asPath.includes("/polda/") ? "regional?" : "filter?"; const type = group || asPath.includes("/polda/") ? "regional?" : "filter?";
const sort = sortByOpt === "popular" ? "sortBy=popular" : "sortBy=latest"; const sort = sortByOpt === "popular" ? "sortBy=popular" : "sortBy=latest";
const titleParam = title ? `&title=${title?.toLowerCase()}` : ""; const titleParam = title ? `&title=${title?.toLowerCase()}` : "";
const categoryParam = categorie ? `&category=${categorie}` : ""; const categoryParam = categorie ? `&category=${categorie}` : "";
const fullQuery = `${type}${sort}${titleParam}${categoryParam}${ const fullQuery = `${type}${sort}${titleParam}${categoryParam}${
startDateString ? `&startDate=${startDateString}` : "" startDateString ? `&startDate=${startDateString}` : ""
}${endDateString ? `&endDate=${endDateString}` : ""}`; }${endDateString ? `&endDate=${endDateString}` : ""}`;
const href = `${basePath}/image/${fullQuery}`; const href = `${basePath}/image/${fullQuery}`;
let prefixPath = poldaName let prefixPath = poldaName
@ -284,7 +289,7 @@ export default function FilterImageComponent(props: {
</Carousel> </Carousel>
<div className="flex justify-center mt-1 mb-6"> <div className="flex justify-center mt-1 mb-6">
<Link <Link
href={href} href={isRegional ? `/regional/all-polda/image/all` : href}
className="border border-red-500 text-red-500 hover:bg-red-500 text-sm hover:text-white px-4 py-2 rounded transition duration-200" className="border border-red-500 text-red-500 hover:bg-red-500 text-sm hover:text-white px-4 py-2 rounded transition duration-200"
> >
Lihat Semua Lihat Semua

View File

@ -131,7 +131,7 @@ export default function IndeksCarouselComponent(props: {
try { try {
loading(); loading();
const response = await getIndeksDataFilter( const response = await getIndeksDataFilter(
"4", "",
name, name,
filter, filter,
12, 12,

View File

@ -153,6 +153,24 @@ export default function FilterVideoComponent(props: {
setTotalContent(response?.data?.data?.totalElements); setTotalContent(response?.data?.data?.totalElements);
} }
const basePath = asPath.includes("/polda/")
? `/${asPath.split("/")[1]}/${asPath.split("/")[2]}`
: "";
const type = group || asPath.includes("/polda/") ? "regional?" : "filter?";
const sort = sortByOpt === "popular" ? "sortBy=popular" : "sortBy=latest";
const titleParam = title ? `&title=${title?.toLowerCase()}` : "";
const categoryParam = categorie ? `&category=${categorie}` : "";
const fullQuery = `${type}${sort}${titleParam}${categoryParam}${
startDateString ? `&startDate=${startDateString}` : ""
}${endDateString ? `&endDate=${endDateString}` : ""}`;
const href = `${basePath}/image/${fullQuery}`;
return newContent?.length > 0 ? ( return newContent?.length > 0 ? (
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<p>{`Audio Visual (${totalContent})`}</p> <p>{`Audio Visual (${totalContent})`}</p>
@ -240,25 +258,27 @@ export default function FilterVideoComponent(props: {
</Carousel> </Carousel>
<div className="flex justify-center mt-1 mb-6"> <div className="flex justify-center mt-1 mb-6">
<Link <Link
href={`${ // href={`${
asPath.includes("/polda/") // asPath.includes("/polda/")
? `/${asPath.split("/")[1]}/${asPath.split("/")[2]}` // ? `/${asPath.split("/")[1]}/${asPath.split("/")[2]}`
: "" // : ""
}/video/${ // }/video/${
group || asPath.includes("/polda/") ? "regional?" : "filter?" // group || asPath.includes("/polda/") ? "regional?" : "filter?"
}${sortByOpt === "popular" ? "sortBy=popular" : "sortBy=latest"}${ // }${sortByOpt === "popular" ? "sortBy=popular" : "sortBy=latest"}${
title ? `&title=${title.toLowerCase()}` : "" // title ? `&title=${title.toLowerCase()}` : ""
}${categorie ? `&category=${categorie}` : ""}${ // }${categorie ? `&category=${categorie}` : ""}${
startDateString ? `&startDate=${startDateString}` : "" // startDateString ? `&startDate=${startDateString}` : ""
}${endDateString ? `&endDate=${endDateString}` : ""}${ // }${endDateString ? `&endDate=${endDateString}` : ""}${
monthYearFilter // monthYearFilter
? `&month=${getOnlyMonthAndYear(monthYearFilter)?.split("/")[0]}` // ? `&month=${getOnlyMonthAndYear(monthYearFilter)?.split("/")[0]}`
: "" // : ""
}${ // }${
monthYearFilter // monthYearFilter
? `&year=${getOnlyMonthAndYear(monthYearFilter)?.split("/")[1]}` // ? `&year=${getOnlyMonthAndYear(monthYearFilter)?.split("/")[1]}`
: "" // : ""
}`} // }`}
href={isRegional ? `/regional/all-polda/video/all` : href}
className="border border-red-500 text-red-500 hover:bg-red-500 hover:text-white px-4 py-2 text-sm rounded transition duration-200" className="border border-red-500 text-red-500 hover:bg-red-500 hover:text-white px-4 py-2 text-sm rounded transition duration-200"
> >
Lihat Semua Lihat Semua

View File

@ -85,7 +85,7 @@ export async function getMediaBlastCampaignList() {
export async function deleteMediaBlastCampaign(id: string | number): Promise<any> { export async function deleteMediaBlastCampaign(id: string | number): Promise<any> {
const url = `media/blast/campaign?id=${id}`; const url = `media/blast/campaign?id=${id}`;
return httpDeleteInterceptor({ url }); return httpDeleteInterceptor( url );
} }
export async function detailMediaSummary(id: string) { export async function detailMediaSummary(id: string) {