This commit is contained in:
Sabda Yagra 2025-08-20 22:43:10 +07:00
parent 24a5e2a5c1
commit 7a4e7cbefe
3 changed files with 280 additions and 37 deletions

View File

@ -2,7 +2,7 @@ import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import { cn, getCookiesDecrypt } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
@ -17,9 +17,10 @@ import withReactContent from "sweetalert2-react-content";
import Swal from "sweetalert2";
import { error } from "@/lib/swal";
import { deleteCalendar } from "@/service/schedule/schedule";
import { loading, success } from "@/config/swal";
const useTableColumns = () => {
const t = useTranslations("Table"); // Panggil di dalam hook
const t = useTranslations("Table");
const columns: ColumnDef<any>[] = [
{
@ -100,15 +101,13 @@ const useTableColumns = () => {
enableHiding: false,
cell: ({ row }) => {
const MySwal = withReactContent(Swal);
const levelNumber = Number(getCookiesDecrypt("ulne")); // 1 = Mabes, 2 = Polda
const calendarOwnerLevel = Number(row.original.assignedToLevel); // dari API
const calendarOwner = row.original.assignedTo; // ID unit Polda/Mabes dari API
const myUnit = getCookiesDecrypt("unitId"); // misal ID unit Polda login
async function doDelete(id: any) {
// loading();
const data = {
id,
};
const response = await deleteCalendar(id);
if (response?.error) {
error(response.message);
return false;
@ -144,6 +143,29 @@ const useTableColumns = () => {
}
});
};
// === RULE AKSI ===
let canEdit = false;
let canDelete = false;
const canView = true;
if (levelNumber === 1) {
// Mabes -> bebas
canEdit = true;
canDelete = true;
} else if (levelNumber === 2) {
// Polda
if (calendarOwnerLevel === 1) {
// kalender Mabes -> hanya view
canEdit = false;
canDelete = false;
} else if (calendarOwnerLevel === 2 && calendarOwner === myUnit) {
// kalender polda sendiri -> bisa edit/delete
canEdit = true;
canDelete = true;
}
}
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
@ -156,34 +178,134 @@ const useTableColumns = () => {
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<Link
href={`/contributor/schedule/calendar-polri/detail/${row.original.id}`}
>
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
<Eye className="w-4 h-4 me-1.5" />
Detail
{canView && (
<Link
href={`/contributor/schedule/calendar-polri/detail/${row.original.id}`}
>
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
<Eye className="w-4 h-4 me-1.5" />
Detail
</DropdownMenuItem>
</Link>
)}
{canEdit && (
<Link
href={`/contributor/schedule/calendar-polri/update/${row.original.id}`}
>
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
<SquarePen className="w-4 h-4 me-1.5" />
Edit
</DropdownMenuItem>
</Link>
)}
{canDelete && (
<DropdownMenuItem
onClick={() => handleDeleteCalendars(row.original.id)}
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
>
<Trash2 className="w-4 h-4 me-1.5" />
Delete
</DropdownMenuItem>
</Link>
<Link
href={`/contributor/schedule/calendar-polri/update/${row.original.id}`}
>
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
<SquarePen className="w-4 h-4 me-1.5" />
Edit
</DropdownMenuItem>
</Link>
<DropdownMenuItem
onClick={() => handleDeleteCalendars(row.original.id)}
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
>
<Trash2 className="w-4 h-4 me-1.5" />
Delete
</DropdownMenuItem>
)}
</DropdownMenuContent>
</DropdownMenu>
);
},
},
// {
// id: "actions",
// accessorKey: "action",
// header: t("action", { defaultValue: "Action" }),
// enableHiding: false,
// cell: ({ row }) => {
// const MySwal = withReactContent(Swal);
// async function doDelete(id: any) {
// // loading();
// const data = {
// id,
// };
// const response = await deleteCalendar(id);
// if (response?.error) {
// error(response.message);
// return false;
// }
// success();
// }
// function success() {
// MySwal.fire({
// title: "Sukses",
// icon: "success",
// confirmButtonColor: "#3085d6",
// confirmButtonText: "OK",
// }).then((result) => {
// if (result.isConfirmed) {
// window.location.reload();
// }
// });
// }
// const handleDeleteCalendars = (id: any) => {
// MySwal.fire({
// title: "Hapus Data",
// text: "",
// icon: "warning",
// showCancelButton: true,
// cancelButtonColor: "#3085d6",
// confirmButtonColor: "#d33",
// confirmButtonText: "Hapus",
// }).then((result) => {
// if (result.isConfirmed) {
// doDelete(id);
// }
// });
// };
// return (
// <DropdownMenu>
// <DropdownMenuTrigger asChild>
// <Button
// size="icon"
// className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
// >
// <span className="sr-only">Open menu</span>
// <MoreVertical className="h-4 w-4 text-default-800" />
// </Button>
// </DropdownMenuTrigger>
// <DropdownMenuContent className="p-0" align="end">
// <Link
// href={`/contributor/schedule/calendar-polri/detail/${row.original.id}`}
// >
// <DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
// <Eye className="w-4 h-4 me-1.5" />
// Detail
// </DropdownMenuItem>
// </Link>
// <Link
// href={`/contributor/schedule/calendar-polri/update/${row.original.id}`}
// >
// <DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
// <SquarePen className="w-4 h-4 me-1.5" />
// Edit
// </DropdownMenuItem>
// </Link>
// <DropdownMenuItem
// onClick={() => handleDeleteCalendars(row.original.id)}
// className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
// >
// <Trash2 className="w-4 h-4 me-1.5" />
// Delete
// </DropdownMenuItem>
// </DropdownMenuContent>
// </DropdownMenu>
// );
// },
// },
];
return columns;

View File

@ -41,7 +41,7 @@ import {
} from "@/components/ui/popover";
import { Calendar } from "@/components/ui/calendar";
import { format } from "date-fns";
import { cn } from "@/lib/utils";
import { cn, getCookiesDecrypt } from "@/lib/utils";
import { getUserLevelForAssignments } from "@/service/task";
import { Card } from "@/components/ui/card";
import { useDropzone } from "react-dropzone";
@ -84,6 +84,8 @@ export function CalendarPolriAdd() {
>([]);
const [imageFiles, setImageFiles] = React.useState<FileWithPreview[]>([]);
const [date, setDate] = React.useState<DateRange | undefined>();
const levelNumber = Number(getCookiesDecrypt("ulne")) || 0;
const roleId = Number(getCookiesDecrypt("urie")) || 0;
const [unitSelection, setUnitSelection] = React.useState({
semua: false,
@ -143,7 +145,7 @@ export function CalendarPolriAdd() {
};
const handlePoldaPolresChange = () => {
return Array.from(checkedLevels).join(","); // Mengonversi Set ke string
return Array.from(checkedLevels).join(",");
};
const handleUnitChange = (
@ -233,7 +235,6 @@ export function CalendarPolriAdd() {
const resCsrf = await getCsrfToken();
const csrfToken = resCsrf?.data?.token;
console.log("CSRF TOKEN : ", csrfToken);
const headers = {
"X-XSRF-TOKEN": csrfToken,
};
@ -387,7 +388,7 @@ export function CalendarPolriAdd() {
<div>
<p className="font-medium">Publish Area</p>
<div className="flex flex-row">
<div className="flex flex-wrap gap-3 lg:ml-3 ">
{/* <div className="flex flex-wrap gap-3 lg:ml-3 ">
{Object.keys(unitSelection).map((key) => (
<div className="flex items-center gap-2" key={key}>
<Checkbox
@ -407,8 +408,128 @@ export function CalendarPolriAdd() {
</Label>
</div>
))}
</div> */}
<div className="flex flex-wrap gap-3 lg:ml-3 ">
{Object.keys(unitSelection)
.filter((key) => {
// Jika login sebagai polda (2), hanya tampilkan polda
if (levelNumber === 2) return key === "polda";
// Jika login sebagai satker (4), hanya tampilkan satker
if (levelNumber === 4) return key === "satker";
// Selain itu tampilkan semua
return true;
})
.map((key) => (
<div className="flex items-center gap-2" key={key}>
<Checkbox
id={key}
checked={
unitSelection[key as keyof typeof unitSelection]
}
onCheckedChange={(value) =>
handleUnitChange(
key as keyof typeof unitSelection,
value as boolean
)
}
/>
<Label htmlFor={key}>
{key.charAt(0).toUpperCase() + key.slice(1)}
</Label>
</div>
))}
</div>
<div className=" lg:pl-3">
{levelNumber !== 2 && levelNumber !== 4 && (
<div className="lg:pl-3">
<Dialog>
<DialogTrigger asChild>
<Button variant="soft" size="sm" color="primary">
[{t("custom", { defaultValue: "Custom" })}]
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px] md:max-w-[500px] lg:max-w-[1500px]">
<DialogHeader>
<DialogTitle>
Daftar Wilayah Polda dan Polres
</DialogTitle>
</DialogHeader>
<div className="grid grid-cols-2 gap-2 max-h-[400px] overflow-y-auto">
{listDest.map((polda: any) => (
<div key={polda.id} className="border p-2">
<Label className="flex items-center">
<Checkbox
checked={checkedLevels.has(polda.id)}
onCheckedChange={() =>
handleCheckboxChange(polda.id)
}
className="mr-3"
/>
{polda.name}
<button
onClick={() => toggleExpand(polda.id)}
className="ml-2 focus:outline-none"
>
{expandedPolda[polda.id] ? (
<ChevronUp size={16} />
) : (
<ChevronDown size={16} />
)}
</button>
</Label>
{expandedPolda[polda.id] && (
<div className="ml-6 mt-2">
<Label className="block">
<Checkbox
checked={polda?.subDestination?.every(
(polres: any) =>
checkedLevels.has(polres.id)
)}
onCheckedChange={(isChecked) => {
const updatedLevels = new Set(
checkedLevels
);
polda?.subDestination?.forEach(
(polres: any) => {
if (isChecked) {
updatedLevels.add(polres.id);
} else {
updatedLevels.delete(polres.id);
}
}
);
setCheckedLevels(updatedLevels);
}}
className="mr-2"
/>
Pilih Semua Polres
</Label>
{polda?.subDestination?.map((polres: any) => (
<Label
key={polres.id}
className="block mt-1"
>
<Checkbox
checked={checkedLevels.has(polres.id)}
onCheckedChange={() =>
handleCheckboxChange(polres.id)
}
className="mr-2"
/>
{polres.name}
</Label>
))}
</div>
)}
</div>
))}
</div>
</DialogContent>
</Dialog>
</div>
)}
{/* <div className=" lg:pl-3">
<Dialog>
<DialogTrigger asChild>
<Button variant="soft" size="sm" color="primary">
@ -490,7 +611,7 @@ export function CalendarPolriAdd() {
</div>
</DialogContent>
</Dialog>
</div>
</div> */}
</div>
</div>

View File

@ -536,7 +536,7 @@ const HeroNew = (props: { group?: string }) => {
<Swiper
modules={[Autoplay, Navigation]}
autoplay={{
delay: 3000,
delay: 10000,
disableOnInteraction: false,
}}
loop={true}