feat:agenda setting,content,Spit,task

This commit is contained in:
Anang Yusman 2025-02-05 17:02:13 +08:00
parent 5a85eaa232
commit e21fff8309
7 changed files with 184 additions and 28 deletions

View File

@ -34,6 +34,9 @@ const FormSchema = z.object({
email: z.string({ email: z.string({
required_error: "Required", required_error: "Required",
}), }),
position: z.string({
required_error: "Required",
}),
region: z.string({ region: z.string({
required_error: "Required", required_error: "Required",
}), }),
@ -147,7 +150,28 @@ export default function AddExpertForm() {
</FormItem> </FormItem>
)} )}
/> />
<FormField
control={form.control}
name="position"
render={({ field }) => (
<FormItem>
<FormLabel>Posisi</FormLabel>
<Select onValueChange={field.onChange} value={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Pilih Region" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="koor-kurator">Koor Kurator</SelectItem>
<SelectItem value="kurator">Kurator</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField <FormField
control={form.control} control={form.control}
name="region" name="region"

View File

@ -10,7 +10,15 @@ import { Label } from "@/components/ui/label";
import ExternalDraggingevent from "./dragging-events"; import ExternalDraggingevent from "./dragging-events";
import { Calendar } from "@/components/ui/calendar"; import { Calendar } from "@/components/ui/calendar";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Book, CheckSquare2, CheckSquare2Icon, Plus } from "lucide-react"; import {
Book,
CheckCheck,
CheckSquare2,
CheckSquare2Icon,
Plus,
Timer,
TimerIcon,
} from "lucide-react";
import { Checkbox } from "@/components/ui/checkbox"; import { Checkbox } from "@/components/ui/checkbox";
import { EventContentArg } from "@fullcalendar/core"; import { EventContentArg } from "@fullcalendar/core";
import EventModal from "./event-modal"; import EventModal from "./event-modal";
@ -46,6 +54,7 @@ export type CalendarEvent = {
end: Date; end: Date;
createBy: string; createBy: string;
createdByName: string; createdByName: string;
isPublish: boolean | null;
allDay: boolean; allDay: boolean;
extendedProps: { extendedProps: {
calendar: string; calendar: string;
@ -94,6 +103,7 @@ interface ListItemProps {
item: any; item: any;
text: string; text: string;
createdBy: string; createdBy: string;
isPublish: boolean | null;
bgColor: string; bgColor: string;
} }
@ -175,12 +185,15 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
end: new Date(event.endDate), end: new Date(event.endDate),
allDay: true, allDay: true,
extendedProps: { extendedProps: {
isPublish: event.isPublish,
calendar: event.agendaType, calendar: event.agendaType,
description: event.description, description: event.description,
createdByName: event.createdByName, createdByName: event.createdByName,
}, },
})); }));
console.log("Dataaa event : ", events);
setCalendarEvents(events); setCalendarEvents(events);
} }
}; };
@ -238,6 +251,7 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
title: item.title, title: item.title,
createBy: "Mabes Polri - Approver", createBy: "Mabes Polri - Approver",
createdByName: item.createdByName, createdByName: item.createdByName,
isPublish: item.isPublish,
start: new Date(item.startDate), start: new Date(item.startDate),
end: new Date(item.endDate), end: new Date(item.endDate),
allDay: true, // Sesuaikan jika memang ada event sepanjang hari allDay: true, // Sesuaikan jika memang ada event sepanjang hari
@ -334,14 +348,13 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
const renderEventContent = (eventInfo: any) => { const renderEventContent = (eventInfo: any) => {
const { title } = eventInfo.event; const { title } = eventInfo.event;
const { isPublish } = eventInfo.event.extendedProps; const { createdByName, isPublish } = eventInfo.event.extendedProps;
const { createdByName } = eventInfo.event.extendedProps;
return ( return (
<> <>
<div className="flex flex-row"> <div className="flex flex-row">
{" "} {" "}
{isPublish && <CheckSquare2 />} {isPublish === true ? <CheckCheck size={15} /> : <Timer size={15} />}
<p className="ml-1">{title}</p> <p className="ml-1">{title}</p>
</div> </div>
@ -415,6 +428,7 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
end: new Date(item.endDate), end: new Date(item.endDate),
createBy: "Mabes Polri - Approver", // Sesuaikan dengan data yang sebenarnya jika ada createBy: "Mabes Polri - Approver", // Sesuaikan dengan data yang sebenarnya jika ada
createdByName: item.createdByName, createdByName: item.createdByName,
isPublish: item.isPublish,
allDay: true, allDay: true,
extendedProps: { extendedProps: {
calendar: item.agendaType, calendar: item.agendaType,
@ -437,6 +451,7 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
item, item,
text, text,
createdBy, createdBy,
isPublish,
bgColor, bgColor,
}) => ( }) => (
<div <div
@ -444,7 +459,7 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
onClick={() => handleClickListItem(item)} onClick={() => handleClickListItem(item)}
> >
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
<CheckSquare2Icon /> {isPublish ? <CheckCheck size={15} /> : <Timer size={15} />}
<p className="ml-1">{text}</p> <p className="ml-1">{text}</p>
</div> </div>
<p className="ml-1 text-xs text-start mt-2">Created By: {createdBy}</p> <p className="ml-1 text-xs text-start mt-2">Created By: {createdBy}</p>
@ -475,6 +490,7 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
item={event} item={event}
text={event.title} text={event.title}
createdBy={event.createdByName} createdBy={event.createdByName}
isPublish={event.isPublish}
bgColor={getEventColor(event.agendaType)} bgColor={getEventColor(event.agendaType)}
/> />
))} ))}
@ -504,6 +520,7 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
item={event} item={event}
text={event.title} text={event.title}
createdBy={event.createdByName} createdBy={event.createdByName}
isPublish={event.isPublish}
bgColor={getEventColor(event.agendaType)} bgColor={getEventColor(event.agendaType)}
/> />
))} ))}

View File

@ -26,6 +26,7 @@ import {
} from "@/components/ui/table"; } from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { import {
ChevronDown,
ChevronLeft, ChevronLeft,
ChevronRight, ChevronRight,
Eye, Eye,
@ -52,6 +53,8 @@ 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 } from "@/service/task";
import { Label } from "@/components/ui/label";
import { format } from "date-fns";
const TaskTable = () => { const TaskTable = () => {
const router = useRouter(); const router = useRouter();
@ -70,6 +73,10 @@ const TaskTable = () => {
pageIndex: 0, pageIndex: 0,
pageSize: 10, pageSize: 10,
}); });
const [statusFilter, setStatusFilter] = React.useState<any[]>([]);
const [dateFilter, setDateFilter] = React.useState("");
const [endDate, setEndDate] = React.useState("");
const [filterByCode, setFilterByCode] = React.useState<string>("");
const [page, setPage] = React.useState(1); const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1); const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10); const [limit, setLimit] = React.useState(10);
@ -106,14 +113,19 @@ const TaskTable = () => {
React.useEffect(() => { React.useEffect(() => {
fetchData(); fetchData();
}, [page, limit, isSpecificAttention, search]); }, [page, limit, isSpecificAttention, search, dateFilter, filterByCode]);
async function fetchData() { async function fetchData() {
const formattedStartDate = dateFilter
? format(new Date(dateFilter), "yyyy-MM-dd")
: "";
try { try {
const res = await listTask( const res = await listTask(
search,
page - 1, page - 1,
search,
limit, limit,
filterByCode,
formattedStartDate,
isSpecificAttention ? "atensi-khusus" : "tugas-harian" isSpecificAttention ? "atensi-khusus" : "tugas-harian"
); );
const data = res?.data?.data; const data = res?.data?.data;
@ -137,6 +149,21 @@ const TaskTable = () => {
table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel
}; };
function handleStatusCheckboxChange(value: any) {
setStatusFilter((prev: any) =>
prev.includes(value)
? prev.filter((status: any) => status !== value)
: [...prev, value]
);
}
const handleSearchFilterByCode = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
console.log("code :", value);
setFilterByCode(value);
fetchData();
};
return ( return (
<div className="w-full overflow-x-auto"> <div className="w-full overflow-x-auto">
<div className="mx-5 mb-3"> <div className="mx-5 mb-3">
@ -191,6 +218,69 @@ const TaskTable = () => {
/> />
</InputGroup> </InputGroup>
</div> </div>
<div className="flex flex-row items-center gap-2">
<div className="flex flex-row items-center gap-3">
<div className="flex items-center py-4">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" className="ml-auto" size="md">
Filter <ChevronDown />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
className="w-64 h-[200px] overflow-y-auto"
>
<div className="flex flex-row justify-between my-1 mx-1">
<p>Filter</p>
</div>
<div className="mx-2 my-1">
<Label>Tanggal Awal</Label>
<Input
type="date"
value={dateFilter}
onChange={(e) => setDateFilter(e.target.value)}
className="max-w-sm"
/>
</div>
<div className="mx-2 my-1">
<Label>Code</Label>
<Input
placeholder="Filter Status..."
value={filterByCode}
onChange={handleSearchFilterByCode}
className="max-w-sm"
/>
</div>
<Label className="ml-2 mt-2">Status</Label>
<div className="flex items-center px-4 py-1">
<input
type="checkbox"
id="status-2"
className="mr-2"
checked={statusFilter.includes(1)}
onChange={() => handleStatusCheckboxChange(1)}
/>
<label htmlFor="status-2" className="text-sm">
Selesai
</label>
</div>
<div className="flex items-center px-4 py-1">
<input
type="checkbox"
id="status-2"
className="mr-2"
checked={statusFilter.includes(2)}
onChange={() => handleStatusCheckboxChange(2)}
/>
<label htmlFor="status-2" className="text-sm">
Aktif
</label>
</div>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
<div className="flex-none"> <div className="flex-none">
<Input <Input
placeholder="Filter Status..." placeholder="Filter Status..."
@ -204,6 +294,7 @@ const TaskTable = () => {
/> />
</div> </div>
</div> </div>
</div>
<Table className="overflow-hidden mt-3"> <Table className="overflow-hidden mt-3">
<TableHeader> <TableHeader>
{table.getHeaderGroups().map((headerGroup) => ( {table.getHeaderGroups().map((headerGroup) => (

View File

@ -930,7 +930,7 @@ export default function FormImage() {
}`} }`}
onClick={() => handleArticleIdClick(id)} onClick={() => handleArticleIdClick(id)}
> >
{id} {"Narasi " + (index + 1)}
</p> </p>
))} ))}
</div> </div>

View File

@ -653,7 +653,7 @@ export default function FormConvertSPIT() {
}`} }`}
onClick={() => handleArticleIdClick(id)} onClick={() => handleArticleIdClick(id)}
> >
{id} {"Narasi " + (index + 1)}
</button> </button>
))} ))}
</div> </div>
@ -737,6 +737,9 @@ export default function FormConvertSPIT() {
</div> </div>
</div> </div>
</div> </div>
<div className="mt-3">
<Label className="text-xl">Penempatan file</Label>
</div>
{files?.map((file, index) => ( {files?.map((file, index) => (
<div <div
key={file.contentId} key={file.contentId}

View File

@ -172,6 +172,7 @@ interface UploadResult {
title: string; title: string;
description: string; description: string;
createdAt: string; createdAt: string;
creatorGroupLevelName: string;
category: { name: string }; category: { name: string };
fileType: { name: string }; fileType: { name: string };
uploadStatus: { name: string }; uploadStatus: { name: string };
@ -327,13 +328,24 @@ export default function FormTaskDetail() {
fetchPoldaPolres(); fetchPoldaPolres();
}, []); }, []);
const fetchAllData = async () => {
try {
const response = await getMediaUpload(id, userLevelId);
setUploadResults(response?.data?.data || []);
} catch (error) {
console.error("Error fetching all data:", error);
}
};
const fetchFilteredData = async (selectedLevels: any[]) => { const fetchFilteredData = async (selectedLevels: any[]) => {
try { try {
const levels = if (selectedLevels.length === 0) {
selectedLevels.length === 0 ? userLevelId : selectedLevels.join(","); fetchAllData(); // Jika tidak ada filter, panggil semua data
return;
}
const levels = selectedLevels.join(",");
const response = await getMediaUpload(id, levels); const response = await getMediaUpload(id, levels);
setUploadResults(response?.data?.data || []); setUploadResults(response?.data?.data || []);
} catch (error) { } catch (error) {
console.error("Error fetching filtered data:", error); console.error("Error fetching filtered data:", error);
@ -462,7 +474,6 @@ export default function FormTaskDetail() {
console.log("Checked Levels:", Array.from(updatedLevels)); console.log("Checked Levels:", Array.from(updatedLevels));
// Fetch data dengan filter userLevelId
fetchFilteredData(Array.from(updatedLevels)); fetchFilteredData(Array.from(updatedLevels));
return updatedLevels; return updatedLevels;
@ -1413,7 +1424,10 @@ export default function FormTaskDetail() {
type="button" type="button"
color="primary" color="primary"
variant={"default"} variant={"default"}
onClick={() => setIsTableResult(!isTableResult)} onClick={() => {
setIsTableResult(!isTableResult);
if (!isTableResult) fetchAllData(); // Panggil API saat tombol diklik
}}
> >
Hasil Upload {Number(userId)} Hasil Upload {Number(userId)}
</Button> </Button>
@ -1525,6 +1539,7 @@ export default function FormTaskDetail() {
<th className="px-4 py-2 text-left">Judul</th> <th className="px-4 py-2 text-left">Judul</th>
<th className="px-4 py-2 text-left">Konten</th> <th className="px-4 py-2 text-left">Konten</th>
<th className="px-4 py-2 text-left">Kategory</th> <th className="px-4 py-2 text-left">Kategory</th>
<th className="px-4 py-2 text-left">Kreator</th>
<th className="px-4 py-2 text-left">Diupload Oleh</th> <th className="px-4 py-2 text-left">Diupload Oleh</th>
</tr> </tr>
</thead> </thead>
@ -1536,6 +1551,9 @@ export default function FormTaskDetail() {
</td> </td>
<td className="px-4 py-2">{item.fileType.name}</td> <td className="px-4 py-2">{item.fileType.name}</td>
<td className="px-4 py-2">{item.category.name}</td> <td className="px-4 py-2">{item.category.name}</td>
<td className="px-4 py-2">
{item.creatorGroupLevelName}
</td>
<td className="px-4 py-2">{item.creatorName}</td> <td className="px-4 py-2">{item.creatorName}</td>
</tr> </tr>
))} ))}

View File

@ -12,13 +12,16 @@ import {
// } // }
export async function listTask( export async function listTask(
title: string = "",
page: any, page: any,
title: string = "",
size: any, size: any,
code: any,
createdAt: any,
taskType: string taskType: string
) { ) {
const url = `assignment/list?enablePage=1&size=${size}&page=${page}&title=${title}&taskType=${taskType}`; return httpGetInterceptor(
return httpGetInterceptor(url); `assignment/list?enablePage=1&size=${size}&page=${page}&title=${title}&taskType=${taskType}&uniqueCode=${code}&createdAt=${createdAt}`
);
} }
// export async function createTask(data: any) { // export async function createTask(data: any) {