Files
jenna-mcp/src/components/DesaSetting.tsx
2025-12-01 15:21:59 +08:00

241 lines
6.6 KiB
TypeScript

import apiFetch from "@/lib/apiFetch";
import {
ActionIcon,
Anchor,
Button,
Divider,
FileInput,
Flex,
Group,
Input,
Modal,
Stack,
Table,
Title,
Tooltip
} from "@mantine/core";
import { useDisclosure, useShallowEffect } from "@mantine/hooks";
import { IconEdit } from "@tabler/icons-react";
import type { JsonValue } from "generated/prisma/runtime/library";
import _ from "lodash";
import { useState } from "react";
import useSWR from "swr";
import ModalFile from "./ModalFile";
import notification from "./notificationGlobal";
export default function DesaSetting({ permissions }: { permissions: JsonValue[] }) {
const [btnDisable, setBtnDisable] = useState(false);
const [btnLoading, setBtnLoading] = useState(false);
const [opened, { open, close }] = useDisclosure(false);
const [img, setImg] = useState<any>()
const [openedPreview, setOpenedPreview] = useState(false);
const [viewImg, setViewImg] = useState("");
const { data, mutate, isLoading } = useSWR("/", () =>
apiFetch.api["configuration-desa"].list.get(),
);
const list = data?.data || [];
const [dataEdit, setDataEdit] = useState({
id: "",
value: "",
name: "",
});
useShallowEffect(() => {
mutate();
}, []);
async function handleEdit() {
try {
setBtnLoading(true);
let finalData = { ...dataEdit }; // ← buffer data terbaru
if (dataEdit.name === "TTD") {
const oldImg = await apiFetch.api.pengaduan["delete-image"].post({ file: dataEdit.value, folder: "lainnya" });
const resImg = await apiFetch.api.pengaduan.upload.post({ file: img, folder: "lainnya" });
if (resImg.status === 200) {
finalData = {
...finalData,
value: resImg.data?.filename || ""
};
setDataEdit(finalData); // update state
} else {
return notification({
title: "Error",
message: "Failed to upload image",
type: "error",
});
}
}
const res = await apiFetch.api["configuration-desa"].edit.post(finalData);
if (res.status === 200) {
mutate();
close();
notification({
title: "Success",
message: "Your settings have been saved",
type: "success",
});
} else {
notification({
title: "Error",
message: "Failed to edit configuration",
type: "error",
});
}
} catch (error) {
console.error(error);
notification({
title: "Error",
message: "Failed to edit configuration",
type: "error",
});
} finally {
setBtnLoading(false);
}
}
function chooseEdit({ data }: { data: { id: string; value: string; name: string }; }) {
setDataEdit(data);
open();
}
function onValidation({ kat, value }: { kat: "value"; value: string }) {
if (value.length < 1) {
setBtnDisable(true);
} else {
setBtnDisable(false);
}
if (kat === "value") {
setDataEdit({ ...dataEdit, value: value });
}
}
useShallowEffect(() => {
if (dataEdit.value.length > 0) {
setBtnDisable(false);
}
}, [dataEdit.id]);
return (
<>
<Modal
opened={opened}
onClose={close}
title={"Edit"}
overlayProps={{ backgroundOpacity: 0.55, blur: 3 }}
>
<Stack gap="ld">
{
dataEdit.name == "TTD"
?
(
<Input.Wrapper label={dataEdit.name}>
<FileInput
clearable
placeholder="Upload TTD"
accept="image/*"
onChange={(e) => { setImg(e) }}
/>
</Input.Wrapper>
)
:
(
<Input.Wrapper label={dataEdit.name}>
<Input
value={dataEdit.value}
onChange={(e) =>
onValidation({ kat: "value", value: e.target.value })
}
/>
</Input.Wrapper>
)
}
<Group justify="center" grow>
<Button variant="light" onClick={close}>
Batal
</Button>
<Button
variant="filled"
onClick={handleEdit}
disabled={btnDisable || (dataEdit.name == "TTD" && !img)}
loading={btnLoading}
>
Simpan
</Button>
</Group>
</Stack>
</Modal>
<ModalFile
open={openedPreview && !_.isEmpty(viewImg)}
onClose={() => setOpenedPreview(false)}
folder="lainnya"
fileName={viewImg}
/>
<Stack gap={"md"}>
<Flex align="center" justify="space-between">
<Title order={4} c="gray.2">
Pengaturan Desa
</Title>
</Flex>
<Divider my={0} />
<Stack gap={"md"}>
<Table highlightOnHover>
<Table.Thead>
<Table.Tr>
<Table.Th>Nama</Table.Th>
<Table.Th>Value</Table.Th>
<Table.Th>Aksi</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{list?.map((v: any) => (
<Table.Tr key={v.id}>
<Table.Td>{v.name}</Table.Td>
<Table.Td>
{
v.name == "TTD"
?
v.value ?
<Anchor href="#" onClick={() => { setViewImg(v.value); setOpenedPreview(true); }} underline="always">
Lihat
</Anchor>
:
"-"
:
v.value
}
</Table.Td>
<Table.Td>
<Tooltip label={permissions.includes("setting.desa.edit") ? "Edit Setting" : "Edit Setting - Anda tidak memiliki akses"}>
<ActionIcon
variant="light"
size="sm"
style={{ boxShadow: "0 0 8px rgba(0,255,200,0.2)" }}
onClick={() => chooseEdit({ data: v })}
disabled={!permissions.includes("setting.desa.edit")}
>
<IconEdit size={20} />
</ActionIcon>
</Tooltip>
</Table.Td>
</Table.Tr>
))}
</Table.Tbody>
</Table>
</Stack>
</Stack>
</>
);
}