feat:update create,edit,detail task ta, download report

This commit is contained in:
Anang Yusman 2025-04-22 13:22:08 +08:00
parent df90fc0906
commit 4e71b4525e
11 changed files with 528 additions and 158 deletions

View File

@ -25,8 +25,13 @@ import withReactContent from "sweetalert2-react-content";
import { deleteBlog } from "@/service/blog/blog"; import { deleteBlog } from "@/service/blog/blog";
import { error, loading } from "@/lib/swal"; import { error, loading } from "@/lib/swal";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import axios from "axios";
const useTableColumns = () => { const useTableColumns = ({
handlePreview,
}: {
handlePreview: (id: string) => void;
}) => {
const t = useTranslations("Table"); // Panggil di dalam hook const t = useTranslations("Table"); // Panggil di dalam hook
const columns: ColumnDef<any>[] = [ const columns: ColumnDef<any>[] = [
@ -112,6 +117,33 @@ const useTableColumns = () => {
} }
}); });
}; };
const handleDownload = async (id: string) => {
try {
const response = await axios.get(
`https://netidhub.com/api/media/report/download?id=${id}`,
{
responseType: "blob",
}
);
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", `report-${id}.pdf`);
document.body.appendChild(link);
link.click();
link.remove();
} catch (error) {
console.error("Download failed", error);
MySwal.fire({
title: "Gagal",
text: "Terjadi kesalahan saat mengunduh file.",
icon: "error",
});
}
};
return ( return (
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
@ -124,18 +156,22 @@ const useTableColumns = () => {
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end"> <DropdownMenuContent className="p-0" align="end">
<Link href={`/contributor/blog/detail/${row.original.id}`}> <DropdownMenuItem
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none"> onClick={() => handlePreview(row.original.id)}
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" /> <Eye className="w-4 h-4 me-1.5" />
Preview Preview
</DropdownMenuItem> </DropdownMenuItem>
</Link>
<Link href={`/contributor/blog/update/${row.original.id}`}> <DropdownMenuItem
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none"> onClick={() => handleDownload(row.original.id)}
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none"
>
<Upload className="w-4 h-4 me-1.5" /> <Upload className="w-4 h-4 me-1.5" />
Download Download
</DropdownMenuItem> </DropdownMenuItem>
</Link>
<DropdownMenuItem <DropdownMenuItem
onClick={() => handleDeleteBlog(row.original.id)} onClick={() => handleDeleteBlog(row.original.id)}
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none" className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"

View File

@ -43,14 +43,40 @@ import {
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import Swal from "sweetalert2";
import { listEnableCategory } from "@/service/content/content"; import { listEnableCategory } from "@/service/content/content";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { CardHeader, CardTitle } from "@/components/ui/card"; import { CardHeader, CardTitle } from "@/components/ui/card";
import { Link } from "@/i18n/routing"; import { Link } from "@/i18n/routing";
import useTableColumns from "./columns"; import useTableColumns from "./columns";
import {
getPreviewById,
paginationReport,
saveReport,
} from "@/service/report/report";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { format } from "date-fns";
import withReactContent from "sweetalert2-react-content";
type PreviewApiResponse = {
error: boolean;
message: string;
data: {
id: number;
title: string;
filePath: string;
version: number;
} | null;
};
const ReportTable = () => { const ReportTable = () => {
const router = useRouter(); const router = useRouter();
const MySwal = withReactContent(Swal);
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const t = useTranslations("Report"); const t = useTranslations("Report");
const [dataTable, setDataTable] = React.useState<any[]>([]); const [dataTable, setDataTable] = React.useState<any[]>([]);
@ -78,7 +104,16 @@ const ReportTable = () => {
const [categoryFilter, setCategoryFilter] = React.useState<string>(""); const [categoryFilter, setCategoryFilter] = React.useState<string>("");
const [dateFilter, setDateFilter] = React.useState(""); const [dateFilter, setDateFilter] = React.useState("");
const [statusFilter, setStatusFilter] = React.useState<any[]>([]); const [statusFilter, setStatusFilter] = React.useState<any[]>([]);
const columns = useTableColumns(); const [openPreview, setOpenPreview] = React.useState(false);
const [previewData, setPreviewData] = React.useState<any>(null);
const handlePreview = (id: string) => {
const url = `https://netidhub.com/api/media/report/view?id=${id}`;
setPreviewData({ url });
setOpenPreview(true);
};
const columns = useTableColumns({ handlePreview });
const table = useReactTable({ const table = useReactTable({
data: dataTable, data: dataTable,
columns, columns,
@ -114,7 +149,7 @@ const ReportTable = () => {
async function fetchData() { async function fetchData() {
try { try {
const res = await paginationBlog( const res = await paginationReport(
showData, showData,
page - 1, page - 1,
search, search,
@ -144,11 +179,10 @@ const ReportTable = () => {
} }
const handleCheckboxChange = (categoryId: number) => { const handleCheckboxChange = (categoryId: number) => {
setSelectedCategories( setSelectedCategories((prev: any) =>
(prev: any) =>
prev.includes(categoryId) prev.includes(categoryId)
? prev.filter((id: any) => id !== categoryId) // Hapus jika sudah dipilih ? prev.filter((id: any) => id !== categoryId)
: [...prev, categoryId] // Tambahkan jika belum dipilih : [...prev, categoryId]
); );
// Perbarui filter kategori // Perbarui filter kategori
@ -176,8 +210,61 @@ const ReportTable = () => {
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
}; };
const handleGenerateReport = async () => {
const today = new Date();
const formattedDate = format(today, "dd-MM-yyyy"); // Hasil: 22-04-2025
const title = `Report ${formattedDate}`;
const requestData = {
title,
};
try {
const response = await saveReport(requestData);
if (response?.error) {
MySwal.fire(
"Error",
response?.message || "Gagal menyimpan laporan",
"error"
);
return;
}
MySwal.fire({
title: "Sukses",
text: "Laporan berhasil dibuat.",
icon: "success",
confirmButtonColor: "#3085d6",
confirmButtonText: "OK",
}).then(() => {
fetchData(); // Refresh tabel setelah generate
});
} catch (error) {
console.error("Generate report error:", error);
MySwal.fire("Error", "Terjadi kesalahan saat membuat laporan", "error");
}
};
return ( return (
<div> <div>
<Dialog open={openPreview} onOpenChange={setOpenPreview}>
<DialogContent className="min-w-max h-[500px] p-0 overflow-hidden">
<DialogHeader className="p-4 border-b">
<DialogTitle>Preview Laporan</DialogTitle>
</DialogHeader>
<div className="h-full w-[1000px] overflow-auto">
{previewData ? (
<iframe
src={previewData.url}
className="w-full h-[calc(100vh-100px)]"
/>
) : (
<div className="p-4">Loading preview...</div>
)}
</div>
</DialogContent>
</Dialog>
<CardHeader className="border-b border-solid border-default-200 mb-6"> <CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle> <CardTitle>
<div className="flex items-center"> <div className="flex items-center">
@ -185,17 +272,14 @@ const ReportTable = () => {
{t("table")} {t("report")} {t("table")} {t("report")}
</div> </div>
<div className="flex-none"> <div className="flex-none">
<Link href={"#"}> <Button fullWidth color="primary" onClick={handleGenerateReport}>
<Button fullWidth color="primary">
<Plus size={18} className=" me-1.5" /> <Plus size={18} className=" me-1.5" />
{t("generate-report")} {t("generate-report")}
</Button> </Button>
</Link>
</div> </div>
</div> </div>
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<div className="w-full overflow-x-auto"> <div className="w-full overflow-x-auto">
<div className="flex flex-col md:flex-row lg:flex-row md:justify-between lg:justify-between items-center md:px-5 lg:px-5"> <div className="flex flex-col md:flex-row lg:flex-row md:justify-between lg:justify-between items-center md:px-5 lg:px-5">
<div className="w-full md:w-[200px] lg:w-[200px] px-2"> <div className="w-full md:w-[200px] lg:w-[200px] px-2">

View File

@ -158,13 +158,13 @@ const useTableColumns = () => {
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end"> <DropdownMenuContent className="p-0" align="end">
<Link href={`/contributor/task/detail/${row.original.id}`}> <Link href={`/contributor/task-ta/detail/${row.original.id}`}>
<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">
<Eye className="w-4 h-4 me-1.5" /> <Eye className="w-4 h-4 me-1.5" />
View View
</DropdownMenuItem> </DropdownMenuItem>
</Link> </Link>
<Link href={`/contributor/task/update/${row.original.id}`}> <Link href={`/contributor/task-ta/update/${row.original.id}`}>
<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">
<SquarePen className="w-4 h-4 me-1.5" /> <SquarePen className="w-4 h-4 me-1.5" />
Edit Edit

View File

@ -54,7 +54,7 @@ import { Badge } from "@/components/ui/badge";
import { useRouter, useSearchParams } from "next/navigation"; import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination"; import TablePagination from "@/components/table/table-pagination";
import columns from "./columns"; import columns from "./columns";
import { listTask } from "@/service/task"; import { listTask, listTaskTa } from "@/service/task";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { format } from "date-fns"; import { format } from "date-fns";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
@ -133,7 +133,7 @@ const TaskTaTable = () => {
? format(new Date(dateFilter), "yyyy-MM-dd") ? format(new Date(dateFilter), "yyyy-MM-dd")
: ""; : "";
try { try {
const res = await listTask( const res = await listTaskTa(
page - 1, page - 1,
search, search,
showData, showData,

View File

@ -2,13 +2,14 @@ import { Card, CardContent } from "@/components/ui/card";
import SiteBreadcrumb from "@/components/site-breadcrumb"; import SiteBreadcrumb from "@/components/site-breadcrumb";
import FormTask from "@/components/form/task/task-form"; import FormTask from "@/components/form/task/task-form";
import FormTaskDetail from "@/components/form/task/task-detail-form"; import FormTaskDetail from "@/components/form/task/task-detail-form";
import FormTaskTaDetail from "@/components/form/task-ta/task-ta-detail-form";
const TaskTaDetailPage = async () => { const TaskTaDetailPage = async () => {
return ( return (
<div> <div>
<SiteBreadcrumb /> <SiteBreadcrumb />
<div className="space-y-4"> <div className="space-y-4">
<FormTaskDetail /> <FormTaskTaDetail />
</div> </div>
</div> </div>
); );

View File

@ -3,13 +3,14 @@ import SiteBreadcrumb from "@/components/site-breadcrumb";
import FormTask from "@/components/form/task/task-form"; import FormTask from "@/components/form/task/task-form";
import FormTaskDetail from "@/components/form/task/task-detail-form"; import FormTaskDetail from "@/components/form/task/task-detail-form";
import FormTaskEdit from "@/components/form/task/task-edit-form"; import FormTaskEdit from "@/components/form/task/task-edit-form";
import FormTaskTaEdit from "@/components/form/task-ta/task-ta-edit-form";
const TaskTaDetailPage = async () => { const TaskTaDetailPage = async () => {
return ( return (
<div> <div>
<SiteBreadcrumb /> <SiteBreadcrumb />
<div className="space-y-4"> <div className="space-y-4">
<FormTaskEdit /> <FormTaskTaEdit />
</div> </div>
</div> </div>
); );

View File

@ -32,6 +32,7 @@ import {
getAssignmentResponseList, getAssignmentResponseList,
getMediaUpload, getMediaUpload,
getTask, getTask,
getTaskTa,
getUserLevelForAssignments, getUserLevelForAssignments,
} from "@/service/task"; } from "@/service/task";
import { import {
@ -82,11 +83,11 @@ export type taskDetail = {
title: string; title: string;
fileTypeOutput: string; fileTypeOutput: string;
assignedToRole: string; assignedToRole: string;
assignedToTopLevel: string; assignedToUsers: string;
assignmentType: { // assignmentType: {
id: number; // id: number;
name: string; // name: string;
}; // };
assignmentMainType: { assignmentMainType: {
id: number; id: number;
name: string; name: string;
@ -106,7 +107,8 @@ export type taskDetail = {
userGroupId: number; userGroupId: number;
}; };
}; };
taskType: string; assignmentType: string;
expertCompetencies: string;
broadcastType: string; broadcastType: string;
narration: string; narration: string;
is_active: string; is_active: string;
@ -198,6 +200,22 @@ export default function FormTaskTaDetail() {
const userId = getCookiesDecrypt("uie"); const userId = getCookiesDecrypt("uie");
const userLevelId = ""; const userLevelId = "";
const [expertise, setExpertiseOutput] = useState({
semua: false,
komunikasi: false,
hukum: false,
bahasa: false,
ekonomi: false,
politik: false,
sosiologi: false,
ilmuadministrasipemerintah: false,
ti: false,
});
const [expert, setExpertOutput] = useState({
semua: false,
});
// State for various form fields // State for various form fields
const [taskOutput, setTaskOutput] = useState({ const [taskOutput, setTaskOutput] = useState({
all: false, all: false,
@ -307,6 +325,62 @@ export default function FormTaskTaDetail() {
// setPlatformTypeVisible(selectedValue === 2); // setPlatformTypeVisible(selectedValue === 2);
// }; // };
const handleExpertiseOutputChange = (
key: keyof typeof expertise,
value: boolean
) => {
if (key === "semua") {
const newState = {
semua: value,
komunikasi: value,
hukum: value,
bahasa: value,
ekonomi: value,
politik: value,
sosiologi: value,
ilmuadministrasipemerintah: value,
ti: value,
};
setExpertiseOutput(newState);
} else {
const updated = {
...expertise,
[key]: value,
};
const allChecked = ["video", "audio", "image", "text"].every(
(k) => updated[k as keyof typeof expertise]
);
updated.semua = allChecked;
setExpertiseOutput(updated);
}
};
const handleExpertOutputChange = (
key: keyof typeof expert,
value: boolean
) => {
if (key === "semua") {
const newState = {
semua: value,
};
setExpertOutput(newState);
} else {
const updated = {
...expert,
[key]: value,
};
const allChecked = ["video", "audio", "image", "text"].every(
(k) => updated[k as keyof typeof expert]
);
updated.semua = allChecked;
setExpertOutput(updated);
}
};
useEffect(() => { useEffect(() => {
async function fetchPoldaPolres() { async function fetchPoldaPolres() {
setIsLoading(true); setIsLoading(true);
@ -358,7 +432,7 @@ export default function FormTaskTaDetail() {
useEffect(() => { useEffect(() => {
async function initState() { async function initState() {
if (id) { if (id) {
const response = await getTask(id); const response = await getTaskTa(id);
const details = response?.data?.data; const details = response?.data?.data;
setDetail(details); setDetail(details);
@ -427,19 +501,36 @@ export default function FormTaskTaDetail() {
}, [detail?.fileTypeOutput]); }, [detail?.fileTypeOutput]);
useEffect(() => { useEffect(() => {
if (detail?.assignedToTopLevel) { if (detail?.expertCompetencies) {
const outputSet = new Set( const outputSet = new Set(
detail.assignedToTopLevel.split(",").map(Number) detail.expertCompetencies.split(",").map(String)
); );
setUnitSelection({ setExpertiseOutput({
allUnit: outputSet.has(0), semua: outputSet.has("0"),
mabes: outputSet.has(1), komunikasi: outputSet.has("1"),
polda: outputSet.has(2), hukum: outputSet.has("2"),
polres: outputSet.has(3), bahasa: outputSet.has("3"),
satker: outputSet.has(4), ekonomi: outputSet.has("4"),
politik: outputSet.has("5"),
sosiologi: outputSet.has("6"),
ilmuadministrasipemerintah: outputSet.has("7"),
ti: outputSet.has("8"),
}); });
} }
}, [detail?.fileTypeOutput]); }, [detail?.expertCompetencies]);
useEffect(() => {
if (detail?.assignedToUsers) {
const outputSet = new Set(detail.assignedToUsers.split(",").map(String));
setUnitSelection({
allUnit: outputSet.has("0"),
mabes: outputSet.has("1"),
polda: outputSet.has("2"),
polres: outputSet.has("3"),
satker: outputSet.has("4"),
});
}
}, [detail?.assignedToUsers]);
const successConfirm = () => { const successConfirm = () => {
MySwal.fire({ MySwal.fire({
@ -1022,7 +1113,7 @@ export default function FormTaskTaDetail() {
</Dialog> </Dialog>
</div> </div>
</div> </div>
<div className="mt-6 space-y-2"> {/* <div className="mt-6 space-y-2">
<Label>{t("type-task")}</Label> <Label>{t("type-task")}</Label>
<RadioGroup <RadioGroup
value={detail.assignmentMainType.id.toString()} value={detail.assignmentMainType.id.toString()}
@ -1036,11 +1127,11 @@ export default function FormTaskTaDetail() {
<RadioGroupItem value="2" id="medsos-mediahub" /> <RadioGroupItem value="2" id="medsos-mediahub" />
<Label htmlFor="medsos-mediahub">Medsos Mediahub</Label> <Label htmlFor="medsos-mediahub">Medsos Mediahub</Label>
</RadioGroup> </RadioGroup>
</div> </div> */}
<div className="mt-6 space-y-2"> <div className="mt-6 space-y-2">
<Label>{t("assigment-type")} </Label> <Label>{t("assigment-type")} </Label>
<RadioGroup <RadioGroup
value={detail.taskType.toString()} value={detail?.assignmentType}
onValueChange={(value) => setTaskType(String(value))} onValueChange={(value) => setTaskType(String(value))}
className="flex flex-wrap gap-3" className="flex flex-wrap gap-3"
> >
@ -1050,40 +1141,21 @@ export default function FormTaskTaDetail() {
<Label htmlFor="tugas-harian">Tugas Harian</Label> <Label htmlFor="tugas-harian">Tugas Harian</Label>
</RadioGroup> </RadioGroup>
</div> </div>
{/* RadioGroup Assignment Category */} <div className="mt-5 space-y-2">
<div className="mt-6 space-y-2"> <Label>{t("areas-expertise")}</Label>
<Label>{t("type-of-task")}</Label> <div className="flex flex-wrap gap-4">
<RadioGroup {Object.keys(expertise).map((key) => (
value={detail.assignmentType.id.toString()}
onValueChange={(value) => setType(value)}
className="flex flex-wrap gap-3"
>
<div className="flex items-center gap-2">
<RadioGroupItem value="1" id="publication" />
<Label htmlFor="publication">Publikasi</Label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="2" id="amplification" />
<Label htmlFor="amplification">Amplifikasi</Label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="3" id="contra" />
<Label htmlFor="contra">Kontra</Label>
</div>
</RadioGroup>
</div>
<div className="mt-6 space-y-2">
<Label>{t("output-task")}</Label>
<div className="flex flex-wrap gap-3">
{Object.keys(taskOutput).map((key) => (
<div className="flex items-center gap-2" key={key}> <div className="flex items-center gap-2" key={key}>
<Checkbox <Checkbox
id={key} id={key}
disabled checked={expertise[key as keyof typeof expertise]}
checked={taskOutput[key as keyof typeof taskOutput]}
onCheckedChange={(value) => onCheckedChange={(value) =>
setTaskOutput({ ...taskOutput, [key]: value }) handleExpertiseOutputChange(
key as keyof typeof expertise,
value as boolean
)
} }
disabled
/> />
<Label htmlFor={key}> <Label htmlFor={key}>
{key.charAt(0).toUpperCase() + key.slice(1)} {key.charAt(0).toUpperCase() + key.slice(1)}
@ -1093,6 +1165,28 @@ export default function FormTaskTaDetail() {
</div> </div>
</div> </div>
<div className="mt-5 space-y-2">
<Label>{t("choose-expert")}</Label>
<div className="flex flex-wrap gap-4">
{Object.keys(expert).map((key) => (
<div className="flex items-center gap-2" key={key}>
<Checkbox
id={key}
checked={expert[key as keyof typeof expert]}
onCheckedChange={(value) =>
handleExpertOutputChange(
key as keyof typeof expert,
value as boolean
)
}
/>
<Label htmlFor={key}>
{key.charAt(0).toUpperCase() + key.slice(1)}
</Label>
</div>
))}
</div>
</div>
<div className="mt-6 space-y-2"> <div className="mt-6 space-y-2">
<Label>{t("description")}</Label> <Label>{t("description")}</Label>
<Controller <Controller

View File

@ -22,7 +22,9 @@ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import JoditEditor from "jodit-react"; import JoditEditor from "jodit-react";
import { import {
createTask, createTask,
createTaskTa,
getTask, getTask,
getTaskTa,
getUserLevelForAssignments, getUserLevelForAssignments,
} from "@/service/task"; } from "@/service/task";
import { import {
@ -65,16 +67,13 @@ export type taskDetail = {
title: string; title: string;
fileTypeOutput: string; fileTypeOutput: string;
assignedToRole: string; assignedToRole: string;
assignedToTopLevel: string; assignedToUsers: string;
assignmentType: {
id: number;
name: string;
};
assignmentMainType: { assignmentMainType: {
id: number; id: number;
name: string; name: string;
}; };
taskType: string; assignmentType: string;
expertCompetencies: string;
broadcastType: string; broadcastType: string;
narration: string; narration: string;
attachmentUrl: string; attachmentUrl: string;
@ -110,7 +109,22 @@ export default function FormTaskTaEdit() {
const { id } = useParams() as { id: string }; const { id } = useParams() as { id: string };
console.log(id); console.log(id);
// State for various form fields const [expertise, setExpertiseOutput] = useState({
semua: false,
komunikasi: false,
hukum: false,
bahasa: false,
ekonomi: false,
politik: false,
sosiologi: false,
ilmuadministrasipemerintah: false,
ti: false,
});
const [expert, setExpertOutput] = useState({
semua: false,
});
const [taskOutput, setTaskOutput] = useState({ const [taskOutput, setTaskOutput] = useState({
all: false, all: false,
video: false, video: false,
@ -177,12 +191,61 @@ export default function FormTaskTaEdit() {
resolver: zodResolver(taskSchema), resolver: zodResolver(taskSchema),
}); });
// const handleRadioChange = (event: React.ChangeEvent<HTMLInputElement>) => { const handleExpertiseOutputChange = (
// const selectedValue = Number(event.target.value); key: keyof typeof expertise,
// setMainType(selectedValue); value: boolean
) => {
if (key === "semua") {
const newState = {
semua: value,
komunikasi: value,
hukum: value,
bahasa: value,
ekonomi: value,
politik: value,
sosiologi: value,
ilmuadministrasipemerintah: value,
ti: value,
};
setExpertiseOutput(newState);
} else {
const updated = {
...expertise,
[key]: value,
};
// setPlatformTypeVisible(selectedValue === 2); const allChecked = ["video", "audio", "image", "text"].every(
// }; (k) => updated[k as keyof typeof expertise]
);
updated.semua = allChecked;
setExpertiseOutput(updated);
}
};
const handleExpertOutputChange = (
key: keyof typeof expert,
value: boolean
) => {
if (key === "semua") {
const newState = {
semua: value,
};
setExpertOutput(newState);
} else {
const updated = {
...expert,
[key]: value,
};
const allChecked = ["video", "audio", "image", "text"].every(
(k) => updated[k as keyof typeof expert]
);
updated.semua = allChecked;
setExpertOutput(updated);
}
};
useEffect(() => { useEffect(() => {
async function fetchPoldaPolres() { async function fetchPoldaPolres() {
@ -211,7 +274,7 @@ export default function FormTaskTaEdit() {
useEffect(() => { useEffect(() => {
async function initState() { async function initState() {
if (id) { if (id) {
const response = await getTask(id); const response = await getTaskTa(id);
const details = response?.data?.data; const details = response?.data?.data;
setDetail(details); setDetail(details);
@ -274,19 +337,49 @@ export default function FormTaskTaEdit() {
}, [detail?.fileTypeOutput]); }, [detail?.fileTypeOutput]);
useEffect(() => { useEffect(() => {
if (detail?.assignedToTopLevel) { if (detail?.expertCompetencies) {
const outputSet = new Set( const outputSet = new Set(
detail.assignedToTopLevel.split(",").map(Number) detail.expertCompetencies.split(",").map(String)
); );
setUnitSelection({ setExpertiseOutput({
allUnit: outputSet.has(0), semua: outputSet.has("0"),
mabes: outputSet.has(1), komunikasi: outputSet.has("1"),
polda: outputSet.has(2), hukum: outputSet.has("2"),
polres: outputSet.has(3), bahasa: outputSet.has("3"),
satker: outputSet.has(4), ekonomi: outputSet.has("4"),
politik: outputSet.has("5"),
sosiologi: outputSet.has("6"),
ilmuadministrasipemerintah: outputSet.has("7"),
ti: outputSet.has("8"),
}); });
} }
}, [detail?.fileTypeOutput]); }, [detail?.expertCompetencies]);
useEffect(() => {
if (detail?.assignedToUsers) {
const outputSet = new Set(detail.assignedToUsers.split(",").map(String));
setUnitSelection({
allUnit: outputSet.has("0"),
mabes: outputSet.has("1"),
polda: outputSet.has("2"),
polres: outputSet.has("3"),
satker: outputSet.has("4"),
});
}
}, [detail?.assignedToUsers]);
const successConfirm = () => {
MySwal.fire({
title: "Sukses",
icon: "success",
confirmButtonColor: "#3085d6",
confirmButtonText: "OK",
}).then((result) => {
if (result.isConfirmed) {
router.push("/en/contributor/task");
}
});
};
const handleCheckboxChange = (levelId: number) => { const handleCheckboxChange = (levelId: number) => {
setCheckedLevels((prev) => { setCheckedLevels((prev) => {
@ -391,15 +484,16 @@ export default function FormTaskTaEdit() {
id?: any; id?: any;
title: string; title: string;
assignedToLevel: any; assignedToLevel: any;
assignmentPurpose: any; assignedToUsers: any;
assignmentTypeId: string; assignmentTypeId: string;
fileTypeOutput: string; fileTypeOutput: string;
narration: string; narration: string;
platformType: string | null; platformType: string | null;
assignmentMainTypeId: any; assignmentMainTypeId: any;
taskType: string; assignmentType: string;
assignedToRole: string; assignedToRole: string;
broadcastType: string; broadcastType: string;
expertCompetencies: string;
attachmentUrl: string[]; attachmentUrl: string[];
} = { } = {
...data, ...data,
@ -407,20 +501,21 @@ export default function FormTaskTaEdit() {
// assignmentCategory, // assignmentCategory,
id: detail?.id || null, id: detail?.id || null,
assignedToLevel: handlePoldaPolresChange(), assignedToLevel: handlePoldaPolresChange(),
assignmentPurpose: assignmentPurposeString, assignedToUsers: assignmentPurposeString,
assignedToRole: selectedTarget, assignedToRole: selectedTarget,
taskType: taskType, assignmentType: taskType,
broadcastType: broadcastType, broadcastType: broadcastType,
assignmentMainTypeId: mainType, assignmentMainTypeId: mainType,
assignmentTypeId: type, assignmentTypeId: type,
fileTypeOutput: selectedOutputs, fileTypeOutput: selectedOutputs,
narration: data.naration, narration: data.naration,
platformType: "", platformType: "",
expertCompetencies: "1,2,3",
title: data.title, title: data.title,
attachmentUrl: links, attachmentUrl: links,
}; };
const response = await createTask(requestData); const response = await createTaskTa(requestData);
console.log("Form Data Submitted:", requestData); console.log("Form Data Submitted:", requestData);
console.log("response", response); console.log("response", response);
@ -832,25 +927,10 @@ export default function FormTaskTaEdit() {
</Dialog> </Dialog>
</div> </div>
</div> </div>
<div className="mt-5 space-y-2"> <div className="mt-6 space-y-2">
<Label>{t("type-task")}</Label>
<RadioGroup
defaultValue={detail.assignmentMainType.id.toString()} // State yang dipetakan ke value RadioGroup
onValueChange={(value) => setMainType(value)}
// value={String(mainType)}
// onValueChange={(value) => setMainType(Number(value))}
className="flex flex-wrap gap-3"
>
<RadioGroupItem value="1" id="mediahub" />
<Label htmlFor="mediahub">Mediahub</Label>
<RadioGroupItem value="2" id="medsos-mediahub" />
<Label htmlFor="medsos-mediahub">Medsos Mediahub</Label>
</RadioGroup>
</div>
<div className="mt-5 space-y-2">
<Label>{t("assigment-type")} </Label> <Label>{t("assigment-type")} </Label>
<RadioGroup <RadioGroup
defaultValue={detail.taskType.toString()} defaultValue={detail?.assignmentType}
onValueChange={(value) => setTaskType(String(value))} onValueChange={(value) => setTaskType(String(value))}
className="flex flex-wrap gap-3" className="flex flex-wrap gap-3"
> >
@ -860,39 +940,17 @@ export default function FormTaskTaEdit() {
<Label htmlFor="tugas-harian">Tugas Harian</Label> <Label htmlFor="tugas-harian">Tugas Harian</Label>
</RadioGroup> </RadioGroup>
</div> </div>
{/* RadioGroup Assignment Category */}
<div className="mt-5 space-y-2"> <div className="mt-5 space-y-2">
<Label>{t("type-of-task")}</Label> <Label>{t("areas-expertise")}</Label>
<RadioGroup
defaultValue={detail.assignmentType.id.toString()} // State yang dipetakan ke value RadioGroup
onValueChange={(value) => setType(value)} // Mengubah nilai state ketika pilihan berubah
className="flex flex-wrap gap-3"
>
<div className="flex items-center gap-2">
<RadioGroupItem value="1" id="publication" />
<Label htmlFor="publication">Publikasi</Label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="2" id="amplification" />
<Label htmlFor="amplification">Amplifikasi</Label>
</div>
<div className="flex items-center gap-2">
<RadioGroupItem value="3" id="contra" />
<Label htmlFor="contra">Kontra</Label>
</div>
</RadioGroup>
</div>
<div className="mt-5 space-y-2">
<Label>{t("output-task")}</Label>
<div className="flex flex-wrap gap-4"> <div className="flex flex-wrap gap-4">
{Object.keys(taskOutput).map((key) => ( {Object.keys(expertise).map((key) => (
<div className="flex items-center gap-2" key={key}> <div className="flex items-center gap-2" key={key}>
<Checkbox <Checkbox
id={key} id={key}
checked={taskOutput[key as keyof typeof taskOutput]} checked={expertise[key as keyof typeof expertise]}
onCheckedChange={(value) => onCheckedChange={(value) =>
handleTaskOutputChange( handleExpertiseOutputChange(
key as keyof typeof taskOutput, key as keyof typeof expertise,
value as boolean value as boolean
) )
} }
@ -904,6 +962,30 @@ export default function FormTaskTaEdit() {
))} ))}
</div> </div>
</div> </div>
<div className="mt-5 space-y-2">
<Label>{t("choose-expert")}</Label>
<div className="flex flex-wrap gap-4">
{Object.keys(expert).map((key) => (
<div className="flex items-center gap-2" key={key}>
<Checkbox
id={key}
checked={expert[key as keyof typeof expert]}
onCheckedChange={(value) =>
handleExpertOutputChange(
key as keyof typeof expert,
value as boolean
)
}
/>
<Label htmlFor={key}>
{key.charAt(0).toUpperCase() + key.slice(1)}
</Label>
</div>
))}
</div>
</div>
<div className="mt-5 space-y-2"> <div className="mt-5 space-y-2">
<Label>{t("description")}</Label> <Label>{t("description")}</Label>
<Controller <Controller

View File

@ -22,6 +22,7 @@ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import JoditEditor from "jodit-react"; import JoditEditor from "jodit-react";
import { import {
createTask, createTask,
createTaskTa,
getTask, getTask,
getUserLevelForAssignments, getUserLevelForAssignments,
} from "@/service/task"; } from "@/service/task";
@ -318,35 +319,37 @@ export default function FormTaskTa() {
id?: number; id?: number;
title: string; title: string;
assignedToLevel: any; assignedToLevel: any;
assignmentPurpose: any; assignedToUsers: any;
assignmentTypeId: string; assignmentTypeId: string;
fileTypeOutput: string; fileTypeOutput: string;
narration: string; narration: string;
platformType: string | null; platformType: string | null;
assignmentMainTypeId: any; assignmentMainTypeId: any;
taskType: string; assignmentType: string;
assignedToRole: string; assignedToRole: string;
broadcastType: string; broadcastType: string;
expertCompetencies: string;
attachmentUrl: string[]; attachmentUrl: string[];
} = { } = {
...data, ...data,
// assignmentType, // assignmentType,
// assignmentCategory, // assignmentCategory,
assignedToLevel: handlePoldaPolresChange(), assignedToLevel: handlePoldaPolresChange(),
assignmentPurpose: assignmentPurposeString, assignedToUsers: assignmentPurposeString,
assignedToRole: selectedTarget, assignedToRole: selectedTarget,
taskType: taskType, assignmentType: taskType,
broadcastType: broadcastType, broadcastType: broadcastType,
assignmentMainTypeId: mainType, assignmentMainTypeId: mainType,
assignmentTypeId: type, assignmentTypeId: type,
fileTypeOutput: selectedOutputs, fileTypeOutput: selectedOutputs,
narration: data.naration, narration: data.naration,
platformType: "", platformType: "",
expertCompetencies: "1,2,3",
title: data.title, title: data.title,
attachmentUrl: links, attachmentUrl: links,
}; };
const response = await createTask(requestData); const response = await createTaskTa(requestData);
console.log("Form Data Submitted:", requestData); console.log("Form Data Submitted:", requestData);
console.log("response", response); console.log("response", response);
@ -719,7 +722,19 @@ export default function FormTaskTa() {
</Dialog> </Dialog>
</div> </div>
</div> </div>
<div className="mt-5 space-y-2">
<Label>{t("assigment-type")} </Label>
<RadioGroup
value={taskType}
onValueChange={(value) => setTaskType(String(value))}
className="flex flex-wrap gap-3"
>
<RadioGroupItem value="atensi-khusus" id="khusus" />
<Label htmlFor="atensi-khusus">Atensi Khusus</Label>
<RadioGroupItem value="tugas-harian" id="harian" />
<Label htmlFor="tugas-harian">Tugas Harian</Label>
</RadioGroup>
</div>
<div className="mt-5 space-y-2"> <div className="mt-5 space-y-2">
<Label>{t("areas-expertise")}</Label> <Label>{t("areas-expertise")}</Label>
<div className="flex flex-wrap gap-4"> <div className="flex flex-wrap gap-4">

25
service/report/report.ts Normal file
View File

@ -0,0 +1,25 @@
import {
httpGetInterceptor,
httpPostInterceptor,
} from "../http-config/http-interceptor-service";
export async function paginationReport(
size: any,
page: number,
title: string = "",
categoryFilter: any,
statusFilter: any
) {
return await httpGetInterceptor(
`/media/report/list?enablePage=1&page=${page}&size=${size}&title=${title}&categoryId=${categoryFilter}&statusId=${statusFilter}`
);
}
export async function getPreviewById(id: any) {
return await httpGetInterceptor(`/media/report/view?id=${id}`);
}
export async function saveReport(data: any) {
const url = "/media/report";
return httpPostInterceptor(url, data);
}

View File

@ -112,3 +112,35 @@ export async function finishTask(id: any) {
const url = `assignment/finish?id=${id}`; const url = `assignment/finish?id=${id}`;
return httpPostInterceptor(url); return httpPostInterceptor(url);
} }
export async function listTaskTa(
page: any,
title: string = "",
size: any,
code: any,
createdAt: any,
taskType: string,
status: number[]
) {
let statusQuery = "";
if (status.includes(1)) {
statusQuery = "&isDone=true";
} else if (status.includes(2)) {
statusQuery = "&isDone=false";
}
return httpGetInterceptor(
`assignment-expert/pagination?enablePage=1&size=${size}&page=${page}&title=${title}&taskType=${taskType}&uniqueCode=${code}&createdAt=${createdAt}${statusQuery}`
);
}
export async function createTaskTa(data: any) {
const pathUrl = "assignment-expert";
return httpPostInterceptor(pathUrl, data);
}
export async function getTaskTa(id: any) {
const url = `/assignment-expert?id=${id}`;
return httpGetInterceptor(url);
}