This commit is contained in:
hanif salafi 2025-07-31 12:46:10 +07:00
commit f854cb7385
13 changed files with 163 additions and 102 deletions

View File

@ -13,6 +13,10 @@ import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Link, useRouter } from "@/i18n/routing";
import { close, error, loading, success } from "@/config/swal";
import { deleteMediaBlastCampaign } from "@/service/broadcast/broadcast";
import Swal from "sweetalert2";
import withReactContent from "sweetalert2-react-content";
const columns: ColumnDef<any>[] = [
{
@ -62,6 +66,34 @@ const columns: ColumnDef<any>[] = [
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
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;
}
// success();
}
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>

View File

@ -423,7 +423,7 @@ const ContentListBanner = () => {
checked={selectedItems.length === data.length}
onCheckedChange={handleSelectAll}
/>
<span>Pilih Semua</span>
<span className="text-black dark:text-white">Pilih Semua</span>
</div>
{selectedItems.length > 0 && (
<Button color="primary" onClick={() => handleBanner(selectedItems)}>

View File

@ -13,7 +13,7 @@ export default function AdminBanner() {
return (
<div>
<SiteBreadcrumb />
<div className="w-full overflow-x-auto bg-white p-4 rounded-sm space-y-3">
<div className="w-full overflow-x-auto bg-white dark:bg-black p-4 rounded-sm space-y-3">
<div className="flex justify-between">
{selectedTab === "content" ? "List Media" : " List Banner"}

View File

@ -162,11 +162,11 @@ export default function EditCategoryModal(props: {
}, [id]);
function removeAndReturn(inputString: string, toRemove: number[]) {
const numbers = inputString.split(",").map(Number);
const numbers = inputString?.split(",").map(Number);
const filteredNumbers = numbers.filter((num) => !toRemove.includes(num));
const filteredNumbers = numbers?.filter((num) => !toRemove?.includes(num));
return filteredNumbers.map(String);
return filteredNumbers?.map(String);
}
function filterString(inputString: string, type: string) {

View File

@ -8,8 +8,8 @@ const ImageCreatePage = async () => {
return (
<div>
<SiteBreadcrumb />
<div className="space-y-4">
<FormImage />
<div className="space-y-4 ">
<FormImage />
</div>
</div>
);

View File

@ -8,6 +8,7 @@ import {
Trash2,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
DropdownMenu,
DropdownMenuContent,
@ -21,9 +22,33 @@ import withReactContent from "sweetalert2-react-content";
import Swal from "sweetalert2";
const useTableColumns = () => {
const t = useTranslations("Table"); // Panggil di dalam hook
const t = useTranslations("Table");
const MySwal = withReactContent(Swal);
const columns: ColumnDef<any>[] = [
{
id: "select",
header: ({ table }) => (
<Checkbox
checked={
table.getIsAllPageRowsSelected() ||
(table.getIsSomePageRowsSelected() && "indeterminate")
}
onCheckedChange={(val) => table.toggleAllPageRowsSelected(!!val)}
aria-label="Pilih semua pada halaman ini"
/>
),
cell: ({ row }) => (
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(val) => row.toggleSelected(!!val)}
aria-label="Pilih baris"
/>
),
enableSorting: false,
enableHiding: false,
},
{
accessorKey: "no",
header: t("no", { defaultValue: "No" }),
@ -56,7 +81,6 @@ const useTableColumns = () => {
<span className="whitespace-nowrap">{row.getValue("contentTag")}</span>
),
},
{
accessorKey: "contentType",
header: t("type-content", { defaultValue: "Type Content" }),
@ -73,7 +97,6 @@ const useTableColumns = () => {
</span>
),
},
{
accessorKey: "isPublish",
header: "Status",
@ -95,7 +118,6 @@ const useTableColumns = () => {
);
},
},
{
accessorKey: "contentCreatedDate",
header: t("upload-date", { defaultValue: "Upload Date" }),
@ -104,7 +126,6 @@ const useTableColumns = () => {
| string
| number
| undefined;
const formattedDate =
createdAt && !isNaN(new Date(createdAt).getTime())
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
@ -118,8 +139,7 @@ const useTableColumns = () => {
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
const isDisabled = row.original.isPublish; // Check the isPublish value
const isDisabled = row.original.isPublish;
return (
<DropdownMenu>
<DropdownMenuTrigger asChild disabled={isDisabled}>
@ -128,7 +148,7 @@ const useTableColumns = () => {
className={`bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent ${
isDisabled ? "cursor-not-allowed opacity-50" : ""
}`}
disabled={isDisabled} // Disable button if isPublish is true
disabled={isDisabled}
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
@ -142,7 +162,7 @@ const useTableColumns = () => {
className={`p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none ${
isDisabled ? "cursor-not-allowed opacity-50" : ""
}`}
disabled={isDisabled} // Disable dropdown item if isPublish is true
disabled={isDisabled}
>
<MoveDownRight className="w-4 h-4 me-1.5" />
Pindah Ke Mediahub

View File

@ -823,7 +823,7 @@ const FilterPage = () => {
<Link href={`/image/detail/${image?.slug}`}>
{/* <img src={image?.thumbnailLink} className="h-60 object-cover items-center justify-center cursor-pointer rounded-lg" /> */}
<div className="img-container h-60 bg-[#e9e9e9] cursor-pointer rounded-lg">
<ImageBlurry
{/* <ImageBlurry
src={
image?.smallThumbnailLink ||
image?.thumbnailLink
@ -834,6 +834,16 @@ const FilterPage = () => {
width: "100%",
height: "100%",
}}
/> */}
<Image
width={2560}
height={1440}
src={
image?.smallThumbnailLink ||
image?.thumbnailLink
}
alt={image?.title}
className="w-full h-full object-cover rounded-t-lg"
/>
</div>
<div className="flex flex-row items-center gap-2 text-[10px] mx-1 mt-2">

View File

@ -833,7 +833,7 @@ const FilterPage = () => {
<Link href={`/video/detail/${video?.slug}`}>
{/* <img src={video?.thumbnailLink} className="h-60 object-cover items-center justify-center cursor-pointer rounded-lg place-self-center" /> */}
<div className="img-container h-60 bg-[#e9e9e9] cursor-pointer rounded-lg">
<ImageBlurry
{/* <ImageBlurry
src={
video?.smallThumbnailLink ||
video?.thumbnailLink
@ -844,6 +844,16 @@ const FilterPage = () => {
width: "100%",
height: "100%",
}}
/> */}
<Image
width={2560}
height={1440}
src={
video?.smallThumbnailLink ||
video?.thumbnailLink
}
alt={video?.title}
className="w-full h-full object-cover rounded-t-lg"
/>
</div>
<div className="flex flex-row items-center gap-2 text-[10px] mx-2">

View File

@ -167,6 +167,7 @@ export default function FormImage() {
"image/png": [],
"image/jpg": [],
},
multiple: true,
onDrop: (acceptedFiles) => {
const validFiles = acceptedFiles
.filter(
@ -187,8 +188,11 @@ export default function FormImage() {
return;
}
setFiles(validFiles);
setValue("files", validFiles);
setFiles((prev) => {
const next = [...prev, ...validFiles];
setValue("files", next, { shouldDirty: true });
return next;
});
},
});
@ -1167,12 +1171,13 @@ export default function FormImage() {
render={({ field: { onChange, value } }) =>
isLoadingData ? (
<div className="flex justify-center items-center h-40">
<p className="text-gray-500">
<p className="text-gray-500 dark:text-black">
Loading Proses Data...
</p>
</div>
) : (
<CustomEditor
className="dark:text-black"
onChange={(value: any) => {
onChange(value);
setEditorContent(value);
@ -1498,8 +1503,8 @@ export default function FormImage() {
}
}
field.onChange(updated);
setPublishedFor(updated);
field.onChange(updated);
setPublishedFor(updated);
};
return (

View File

@ -3,7 +3,6 @@
import { useEffect, useState } from "react";
import { useSearchParams, useParams } from "next/navigation";
import Image from "next/image";
import Link from "next/link"; // pastikan path-nya sesuai
import {
Carousel,
CarouselContent,
@ -12,7 +11,7 @@ import {
CarouselPrevious,
} from "@/components/ui/carousel";
import { getIndeksData, getIndeksDataFilter } from "@/service/landing/landing";
import { usePathname, useRouter } from "@/i18n/routing";
import { Link, usePathname, useRouter } from "@/i18n/routing";
import { loading } from "@/lib/swal";
import { getOnlyMonthAndYear } from "@/utils/globals";
@ -34,8 +33,8 @@ export default function IndeksCarouselComponent(props: {
const asPath = usePathname();
const params = useParams();
const searchParams = useSearchParams();
const [indeksData, setIndeksData] = useState<any[]>([]); // ✅ State untuk menyimpan konten data
const [newContent, setNewContent] = useState<any[]>([]); // Optional, bisa jadi redundant
const [indeksData, setIndeksData] = useState<any[]>([]);
const [newContent, setNewContent] = useState<any[]>([]);
const [totalData, setTotalData] = useState<number>(0);
const [totalPage, setTotalPage] = useState<number>(0);
const [totalContent, setTotalContent] = useState<number>(0);
@ -111,81 +110,53 @@ export default function IndeksCarouselComponent(props: {
]);
async function initFetch() {
if (asPath?.includes("/polda/") == true) {
if (asPath?.split("/")[2] !== "[polda_name]") {
const filter =
categoryFilter?.length > 0
? categoryFilter?.sort().join(",")
: categorie || "";
const filter =
categoryFilter?.length > 0
? categoryFilter?.sort().join(",")
: categorie || "";
const name = title == undefined ? "" : title;
const filterGroup = group == undefined ? asPath.split("/")[2] : group;
loading();
const response = await getIndeksDataFilter(
"4",
name,
filter,
12,
0,
sortByOpt,
"",
"",
filterGroup,
startDateString,
endDateString,
monthYearFilter
? getOnlyMonthAndYear(monthYearFilter)
?.split("/")[0]
?.replace("", "")
: "",
monthYearFilter
? getOnlyMonthAndYear(monthYearFilter)?.split("/")[1]
: ""
);
close();
const data = response?.data?.data;
const contentData = data?.content;
setNewContent(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
setTotalContent(response?.data?.data?.totalElements);
}
} else {
const filter =
categoryFilter?.length > 0
? categoryFilter?.sort().join(",")
: categorie || "";
const name = title ?? "";
const month = monthYearFilter
? getOnlyMonthAndYear(monthYearFilter)?.split("/")[0]?.replace("", "")
: "";
const year = monthYearFilter
? getOnlyMonthAndYear(monthYearFilter)?.split("/")[1]
: "";
const name = title == undefined ? "" : title;
// Gunakan group hanya jika asPath mengandung /polda/ atau /satker/, selain itu kosongkan
let filterGroup = "";
if (asPath.includes("/polda/") || asPath.includes("/satker/")) {
filterGroup = group ?? asPath.split("/")[2];
}
try {
loading();
const response = await getIndeksDataFilter(
"4",
name,
filter,
12,
0,
sortByOpt,
"",
"",
"4", // type
name, // title
filter, // kategori
12, // size
0, // page
sortByOpt, // sortBy
"",
"", // provinceId, cityId
filterGroup, // group
startDateString,
endDateString,
monthYearFilter
? getOnlyMonthAndYear(monthYearFilter)?.split("/")[0]?.replace("", "")
: "",
monthYearFilter
? getOnlyMonthAndYear(monthYearFilter)?.split("/")[1]
: ""
month,
year
);
close();
const data = response?.data?.data;
const contentData = data?.content;
setNewContent(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
setTotalContent(response?.data?.data?.totalElements);
setNewContent(contentData || []);
setTotalData(data?.totalElements || 0);
setTotalPage(data?.totalPages || 0);
setTotalContent(data?.totalElements || 0);
} catch (error) {
close();
console.error("Error fetching indeks data:", error);
}
}
@ -230,7 +201,7 @@ export default function IndeksCarouselComponent(props: {
</Carousel>
<div className="flex justify-center mt-1 mb-6">
<Link
href={`${prefixPath}/image`}
href={`${prefixPath}/indeks`}
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

View File

@ -726,17 +726,16 @@ const Navbar = () => {
{/* Inbox */}
<Popover>
<PopoverTrigger asChild>
<a className="cursor-pointer" onClick={() => test()}>
<a
className="cursor-pointer text-black dark:text-white"
onClick={() => test()}
>
{" "}
<Icon
icon="basil:envelope-outline"
color="black"
width="30"
/>
<Icon icon="basil:envelope-outline" width="30" />
</a>
</PopoverTrigger>
<PopoverContent
className=" p-0 h-32 flex flex-col mt-2"
className="overflow-y-scroll p-0 h-full flex flex-col mt-2"
align="end"
>
<Tabs
@ -1214,6 +1213,15 @@ const Navbar = () => {
</a>
</div>
{/* Languange */}
<div
className={`${
isHidden ? "hidden" : "custom-lg-button:flex"
} relative text-left`}
>
<LocalSwitcher />
</div>
<div className="relative inline-block mx-3 text-left">
<ThemeSwitcher />

View File

@ -155,7 +155,7 @@ const NewContent = (props: { group: string; type: string }) => {
{[
{ label: t("image", { defaultValue: "Image" }), value: "image" },
{ label: t("video", { defaultValue: "Video" }), value: "video" },
{ label: t("text", { defaultValue: "Text" }), value: "text" },
{ label: t("text", { defaultValue: "Text" }), value: "document" },
{ label: t("audio", { defaultValue: "Audio" }), value: "audio" },
].map((tab) => (
<TabsTrigger
@ -591,11 +591,11 @@ const NewContent = (props: { group: string; type: string }) => {
</div>
)}
</div>
{/* <div className="flex items-center flex-row justify-center">
<div onClick={() => router.push(prefixPath + `/${selectedTab}/filter?sortBy=${props.type}`)} className="cursor-pointer border text-[#bb3523] rounded-lg text-sm lg:text-md px-4 py-1 border-[#bb3523]">
<div className="flex items-center flex-row justify-center mt-3">
<div onClick={() => router.push(prefixPath + `/${selectedTab}/filter?sortBy=${props.type}`)} className="cursor-pointer border text-[#bb3523] rounded-lg text-sm lg:text-md px-4 py-1 border-[#bb3523] hover:text-white hover:bg-[#bb3523]">
{t("seeAll", { defaultValue: "See All" })}
</div>
</div> */}
</div>
</Reveal>
</div>
);

View File

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