feat:update
This commit is contained in:
commit
0f40db9365
|
|
@ -0,0 +1,90 @@
|
|||
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 {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuItem,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { htmlToString } from "@/utils/globals";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => <span>{row.getValue("title")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "date",
|
||||
header: "Tanggal Masuk",
|
||||
cell: ({ row }) => <span>{row.getValue("date")}</span>,
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "duration",
|
||||
header: "Durasi",
|
||||
cell: ({ row }) => <span>{row.getValue("duration")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "crawling",
|
||||
header: "Model Crawling",
|
||||
cell: ({ row }) => <span>{row.getValue("crawling")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => <span>{row.getValue("status")}</span>,
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Aksi",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
Detail
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default columns;
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
PaginationState,
|
||||
SortingState,
|
||||
VisibilityState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import {
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Eye,
|
||||
MoreVertical,
|
||||
Search,
|
||||
SquarePen,
|
||||
Trash2,
|
||||
TrendingDown,
|
||||
TrendingUp,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
|
||||
import { paginationBlog } from "@/service/blog/blog";
|
||||
import { ticketingPagination } from "@/service/ticketing/ticketing";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import TablePagination from "@/components/table/table-pagination";
|
||||
import columns from "./column";
|
||||
import { getPlanningPagination } from "@/service/agenda-setting/agenda-setting";
|
||||
import { getMediaTrackingMonitoring } from "@/service/media-tracking/media-tracking";
|
||||
|
||||
const MediaTrackingTable = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||
const [totalData, setTotalData] = React.useState<number>(1);
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[]
|
||||
);
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
const [pagination, setPagination] = React.useState<PaginationState>({
|
||||
pageIndex: 0,
|
||||
pageSize: 10,
|
||||
});
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
onSortingChange: setSorting,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
onRowSelectionChange: setRowSelection,
|
||||
onPaginationChange: setPagination,
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
columnVisibility,
|
||||
rowSelection,
|
||||
pagination,
|
||||
},
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
const pageFromUrl = searchParams?.get("page");
|
||||
if (pageFromUrl) {
|
||||
setPage(Number(pageFromUrl));
|
||||
}
|
||||
}, [searchParams]);
|
||||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const response = await getMediaTrackingMonitoring(page, 10);
|
||||
const data = response.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
item.no = (page - 1) * limit + index + 1;
|
||||
});
|
||||
|
||||
console.log("contentData : ", data);
|
||||
|
||||
setDataTable(contentData);
|
||||
setTotalData(data?.totalElements);
|
||||
setTotalPage(data?.totalPages);
|
||||
} catch (error) {
|
||||
console.error("Error fetching tasks:", error);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<Table className="overflow-hidden mt-3">
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id} className="bg-default-200">
|
||||
{headerGroup.headers.map((header) => (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
className="h-[75px]"
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination
|
||||
table={table}
|
||||
totalData={totalData}
|
||||
totalPage={totalPage}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MediaTrackingTable;
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import MediaTrackingTable from "./component/table";
|
||||
|
||||
export default function MediaTracking() {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<MediaTrackingTable />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -60,11 +60,21 @@ const columns: ColumnDef<any>[] = [
|
|||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Link
|
||||
href={`/curator/task-plan/mediahub/detail/${row.original.id}`}
|
||||
href={`/curator/task-plan/mediahub/create-daily/detail/${row.original.id}`}
|
||||
>
|
||||
Detail
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Link
|
||||
href={`/curator/task-plan/mediahub/create-daily/edit/${row.original.id}`}
|
||||
>
|
||||
Edit
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<a className="text-red-600">Delete</a>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,759 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { getUserLevelForAssignments } from "@/service/task";
|
||||
import { list } from "postcss";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import { close, error, loading } from "@/config/swal";
|
||||
import { id } from "date-fns/locale";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
getWeeklyPlanList,
|
||||
savePlanning,
|
||||
} from "@/service/agenda-setting/agenda-setting";
|
||||
import { getOnlyDate } from "@/utils/globals";
|
||||
import { useParams } from "next/navigation";
|
||||
import { getPlanningById } from "@/service/planning/planning";
|
||||
|
||||
const FormSchema = z.object({
|
||||
date: z.date({
|
||||
required_error: "Required",
|
||||
}),
|
||||
title: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
detail: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
output: z.array(z.string()).refine((value) => value.some((item) => item), {
|
||||
message: "Required",
|
||||
}),
|
||||
unit: z.array(z.string()).refine((value) => value.some((item) => item), {
|
||||
message: "Required",
|
||||
}),
|
||||
type: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
parentId: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
});
|
||||
|
||||
const items = [
|
||||
{
|
||||
id: "2",
|
||||
label: "Audio Visual",
|
||||
},
|
||||
{
|
||||
id: "1",
|
||||
label: "Foto",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
label: "Audio",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
label: "Text",
|
||||
},
|
||||
];
|
||||
|
||||
const units = [
|
||||
{
|
||||
id: "1",
|
||||
label: "Mabes Polri",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
label: "Polda",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
label: "Polres",
|
||||
},
|
||||
];
|
||||
export default function DetailDaily() {
|
||||
const id = useParams()?.id;
|
||||
const MySwal = withReactContent(Swal);
|
||||
const [listDest, setListDest] = useState<any>([]);
|
||||
const router = useRouter();
|
||||
const [weeklyList, setWeeklyList] = useState<any>();
|
||||
const [selected, setSelected] = useState<{ [key: string]: boolean }>({});
|
||||
const [selectAll, setSelectAll] = useState<{ [key: string]: boolean }>({});
|
||||
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
}, [id]);
|
||||
|
||||
async function initFetch() {
|
||||
if (id != undefined) {
|
||||
loading();
|
||||
const res = await getPlanningById(id);
|
||||
close();
|
||||
|
||||
if (res?.data?.data != undefined) {
|
||||
const data = res?.data?.data;
|
||||
console.log("data");
|
||||
console.log("Data :", data);
|
||||
form.setValue("title", data.title);
|
||||
form.setValue("detail", data.description);
|
||||
form.setValue("date", new Date(data.date));
|
||||
form.setValue(
|
||||
"output",
|
||||
data.fileTypeOutput.split(",")?.length > 1
|
||||
? data.fileTypeOutput.split(",")
|
||||
: [data.fileTypeOutput]
|
||||
);
|
||||
form.setValue(
|
||||
"unit",
|
||||
data.assignedToLevel.split(",")?.length > 1
|
||||
? data.assignedToLevel.split(",")
|
||||
: [data.assignedToLevel]
|
||||
);
|
||||
form.setValue("type", String(data?.assignmentTypeId));
|
||||
form.setValue("parentId", String(data?.parentId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getWeeklyPlanning();
|
||||
}, []);
|
||||
|
||||
async function getWeeklyPlanning() {
|
||||
const res = await getWeeklyPlanList(new Date().getDate(), 1);
|
||||
|
||||
if (res.data !== null) {
|
||||
const rawUser = res.data?.data;
|
||||
const optionArr = rawUser.map((option: any) => ({
|
||||
id: option.id,
|
||||
label: option.title,
|
||||
value: String(option.id),
|
||||
}));
|
||||
setWeeklyList(optionArr);
|
||||
}
|
||||
}
|
||||
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
unit: [],
|
||||
output: [],
|
||||
detail: "",
|
||||
},
|
||||
});
|
||||
const editor = useRef(null);
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
console.log("data", data);
|
||||
if (form.getValues("detail") == "") {
|
||||
form.setError("detail", {
|
||||
type: "manual",
|
||||
message: "Required",
|
||||
});
|
||||
} else {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
const getSelectedString = () => {
|
||||
return Object.keys(selected)
|
||||
.filter((key) => selected[key])
|
||||
.join(", ");
|
||||
};
|
||||
console.log("data", data, selected);
|
||||
loading();
|
||||
|
||||
const reqData = {
|
||||
planningTypeId: 1,
|
||||
time: "1",
|
||||
title: data.title,
|
||||
assignmentTypeId: data.type, //string
|
||||
description: data.detail,
|
||||
assignedToLevel: unit?.join(","), //string
|
||||
assignmentPurpose: getSelectedString(), //string
|
||||
fileTypeOutput: data.output?.join(","), //string
|
||||
status: "Open",
|
||||
date: getOnlyDate(data.date),
|
||||
// date:
|
||||
// isPublish || isUpdate
|
||||
// ? selectedDate?.length > 10
|
||||
// ? data.date?.toISOString().slice(0, 10)
|
||||
// : selectedDate
|
||||
// : data.date?.toISOString().slice(0, 10),
|
||||
parentId: Number(data.parentId), //number
|
||||
assignmentMainTypeId: 1,
|
||||
};
|
||||
|
||||
console.log("req =>", reqData);
|
||||
const response = await savePlanning(reqData);
|
||||
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
close();
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push("/curator/task-plan/mediahub");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const output = form.watch("output");
|
||||
|
||||
const isAllChecked = items.every((item) => output?.includes(item.id));
|
||||
|
||||
const unit = form.watch("unit");
|
||||
|
||||
const isAllUnitChecked = units.every((item) => unit?.includes(item.id));
|
||||
|
||||
const handleAllCheckedChange = (checked: boolean | string) => {
|
||||
if (checked) {
|
||||
form.setValue(
|
||||
"output",
|
||||
items.map((item) => item.id)
|
||||
);
|
||||
} else {
|
||||
form.setValue("output", []);
|
||||
}
|
||||
};
|
||||
|
||||
const handleItemCheckedChange = (id: string, checked: boolean | string) => {
|
||||
form.setValue(
|
||||
"output",
|
||||
checked ? [...output, id] : output.filter((value) => value !== id)
|
||||
);
|
||||
};
|
||||
|
||||
const handleAllUnitCheckedChange = (checked: boolean | string) => {
|
||||
if (checked) {
|
||||
form.setValue(
|
||||
"unit",
|
||||
units.map((item) => item.id)
|
||||
);
|
||||
} else {
|
||||
form.setValue("unit", []);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUnitCheckedChange = (id: string, checked: boolean | string) => {
|
||||
if (checked) {
|
||||
form.setValue("unit", [...unit, id]);
|
||||
} else {
|
||||
if (id == "2") {
|
||||
const temp = [];
|
||||
for (const element of unit) {
|
||||
if (element == "1") {
|
||||
temp.push("1");
|
||||
}
|
||||
}
|
||||
form.setValue("unit", temp);
|
||||
} else {
|
||||
form.setValue(
|
||||
"unit",
|
||||
unit.filter((value) => value !== id)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
const response = await getUserLevelForAssignments();
|
||||
setListDest(response.data.data.list);
|
||||
}
|
||||
|
||||
initState();
|
||||
}, []);
|
||||
|
||||
const handleParentChange = (listId: string) => {
|
||||
setSelected((prev) => ({
|
||||
...prev,
|
||||
[listId]: !prev[listId],
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSelectAllPolres = (listId: string, isChecked: boolean) => {
|
||||
setSelectAll((prev) => ({
|
||||
...prev,
|
||||
[listId]: isChecked,
|
||||
}));
|
||||
|
||||
setSelected((prev) => {
|
||||
const updatedState = { ...prev };
|
||||
listDest
|
||||
.find((list: any) => list.id === listId)
|
||||
?.subDestination.forEach((subDes: any) => {
|
||||
updatedState[`${listId}${subDes.id}`] = isChecked;
|
||||
});
|
||||
return updatedState;
|
||||
});
|
||||
};
|
||||
|
||||
const handleChildChange = (childId: string) => {
|
||||
setSelected((prev) => ({
|
||||
...prev,
|
||||
[childId]: !prev[childId],
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col bg-white gap-2 p-6">
|
||||
<p className="text-lg">Perencanaan MediaHub</p>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Judul Perencanaan</FormLabel>
|
||||
<Input
|
||||
value={field.value}
|
||||
placeholder="Masukkan Judul Perencanaan"
|
||||
onChange={field.onChange}
|
||||
readOnly
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="output"
|
||||
render={() => (
|
||||
<FormItem>
|
||||
<div className="mb-4">
|
||||
<FormLabel className="text-sm">Output Tugas</FormLabel>
|
||||
</div>
|
||||
<div className="flex flex-row gap-3 items-center ">
|
||||
<div className="flex items-center gap-3">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={isAllChecked}
|
||||
onCheckedChange={(checked) =>
|
||||
handleAllCheckedChange(checked)
|
||||
}
|
||||
disabled
|
||||
/>
|
||||
<label htmlFor="all" className="text-sm">
|
||||
Semua
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{items.map((item) => (
|
||||
<FormField
|
||||
key={item.id}
|
||||
control={form.control}
|
||||
name="output"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<FormItem
|
||||
key={item.id}
|
||||
className="flex flex-row items-start space-x-3 space-y-0"
|
||||
>
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={output?.includes(item.id)}
|
||||
onCheckedChange={(checked) =>
|
||||
handleItemCheckedChange(item.id, checked)
|
||||
}
|
||||
disabled
|
||||
/>
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
{item.label}
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="unit"
|
||||
render={() => (
|
||||
<FormItem>
|
||||
<div className="mb-4">
|
||||
<FormLabel className="text-sm">Pelaksana Tugas</FormLabel>
|
||||
</div>
|
||||
<div className="flex flex-row gap-3 items-center ">
|
||||
<div className="flex items-center gap-3">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={isAllUnitChecked}
|
||||
onCheckedChange={(checked) =>
|
||||
handleAllUnitCheckedChange(checked)
|
||||
}
|
||||
disabled
|
||||
/>
|
||||
<label htmlFor="all" className="text-sm">
|
||||
Semua
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{units.map((item) => (
|
||||
<FormField
|
||||
key={item.id}
|
||||
control={form.control}
|
||||
name="unit"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<FormItem
|
||||
key={item.id}
|
||||
className="flex flex-row items-start space-x-3 space-y-0"
|
||||
>
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={unit?.includes(item.id)}
|
||||
// disabled={
|
||||
// item.id === "3" && !unit.includes("2")
|
||||
// }
|
||||
onCheckedChange={(checked) =>
|
||||
handleUnitCheckedChange(item.id, checked)
|
||||
}
|
||||
disabled
|
||||
/>
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
{item.label}
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<Dialog>
|
||||
<DialogTrigger disabled>
|
||||
<a className="text-primary cursor-pointer text-sm">
|
||||
{`[Kustom]`}
|
||||
</a>
|
||||
</DialogTrigger>
|
||||
<DialogContent size="md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
Daftar Wilayah Polda dan Polres
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="grid grid-cols-2 gap-4 py-4 px-2 max-h-[600px] overflow-y-auto custom-scrollbar-table">
|
||||
{listDest?.map((list: any) => (
|
||||
<div key={list.id}>
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
className="h-fit border-none"
|
||||
>
|
||||
<AccordionItem
|
||||
value={list.name}
|
||||
className="border-none"
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id={list.id}
|
||||
name={`all${list.id}`}
|
||||
checked={
|
||||
unit.includes("2")
|
||||
? true
|
||||
: !!selected[list.id]
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleParentChange(list.id)
|
||||
}
|
||||
disabled={unit.includes("2")}
|
||||
/>
|
||||
<label
|
||||
htmlFor={list.name}
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
{list.name}
|
||||
</label>
|
||||
<AccordionTrigger className="w-fit bg-transparent"></AccordionTrigger>
|
||||
</div>
|
||||
<AccordionContent>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
unit.includes("3")
|
||||
? true
|
||||
: !!selectAll[list.id]
|
||||
}
|
||||
onCheckedChange={(e) =>
|
||||
handleSelectAllPolres(
|
||||
list.id,
|
||||
Boolean(e)
|
||||
)
|
||||
}
|
||||
disabled={unit.includes("3")}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all-polres"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Pilih Semua Polres
|
||||
</label>
|
||||
</div>
|
||||
{list.subDestination.map(
|
||||
(subDes: any) => (
|
||||
<div
|
||||
key={subDes.id}
|
||||
className="flex items-center space-x-2"
|
||||
>
|
||||
<Checkbox
|
||||
id={`${list.id}${subDes.id}`}
|
||||
checked={
|
||||
unit.includes("3")
|
||||
? true
|
||||
: !!selected[
|
||||
`${list.id}${subDes.id}`
|
||||
]
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleChildChange(
|
||||
`${list.id}${subDes.id}`
|
||||
)
|
||||
}
|
||||
disabled={unit.includes("3")}
|
||||
/>
|
||||
<label
|
||||
htmlFor={`${list.id}${subDes.id}`}
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
{subDes.name}
|
||||
</label>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="type"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Jenis Penugasan</FormLabel>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
onValueChange={field.onChange}
|
||||
value={field.value}
|
||||
className="flex flex-row gap-3"
|
||||
disabled
|
||||
>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="1" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
Publikasi
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="2" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
Amplifikasi
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="3" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">Kontra</FormLabel>
|
||||
</FormItem>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="date"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Pilih Tanggal</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
disabled
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{field.value ? (
|
||||
format(field.value, "PPP")
|
||||
) : (
|
||||
<span>Masukkan Tanggal</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="parentId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Perencanaan Mingguan</FormLabel>
|
||||
<Select
|
||||
value={field.value}
|
||||
onValueChange={field.onChange}
|
||||
disabled
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{weeklyList?.map((list: any) => (
|
||||
<SelectItem key={list.id} value={list.value}>
|
||||
{list.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Detail Perencanaan</FormLabel>
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={field.value}
|
||||
config={{ readonly: true }}
|
||||
className="dark:text-black"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 justify-end mt-4 pt-4">
|
||||
<Button
|
||||
onClick={() => router.back()}
|
||||
variant="outline"
|
||||
color="destructive"
|
||||
type="button"
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,764 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { getUserLevelForAssignments } from "@/service/task";
|
||||
import { list } from "postcss";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import { close, error, loading } from "@/config/swal";
|
||||
import { id, te } from "date-fns/locale";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
getWeeklyPlanList,
|
||||
savePlanning,
|
||||
} from "@/service/agenda-setting/agenda-setting";
|
||||
import { getOnlyDate } from "@/utils/globals";
|
||||
import { useParams } from "next/navigation";
|
||||
import { getPlanningById } from "@/service/planning/planning";
|
||||
|
||||
const FormSchema = z.object({
|
||||
date: z.date({
|
||||
required_error: "Required",
|
||||
}),
|
||||
title: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
detail: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
output: z.array(z.string()).refine((value) => value.some((item) => item), {
|
||||
message: "Required",
|
||||
}),
|
||||
unit: z.array(z.string()).refine((value) => value.some((item) => item), {
|
||||
message: "Required",
|
||||
}),
|
||||
type: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
parentId: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
});
|
||||
|
||||
const items = [
|
||||
{
|
||||
id: "2",
|
||||
label: "Audio Visual",
|
||||
},
|
||||
{
|
||||
id: "1",
|
||||
label: "Foto",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
label: "Audio",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
label: "Text",
|
||||
},
|
||||
];
|
||||
|
||||
const units = [
|
||||
{
|
||||
id: "1",
|
||||
label: "Mabes Polri",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
label: "Polda",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
label: "Polres",
|
||||
},
|
||||
];
|
||||
export default function EditDaily() {
|
||||
const id = useParams()?.id;
|
||||
const MySwal = withReactContent(Swal);
|
||||
const [listDest, setListDest] = useState<any>([]);
|
||||
const router = useRouter();
|
||||
const [weeklyList, setWeeklyList] = useState<any>();
|
||||
const [selected, setSelected] = useState<{ [key: string]: boolean }>({});
|
||||
const [selectAll, setSelectAll] = useState<{ [key: string]: boolean }>({});
|
||||
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
}, [id]);
|
||||
|
||||
async function initFetch() {
|
||||
if (id != undefined) {
|
||||
loading();
|
||||
const res = await getPlanningById(id);
|
||||
close();
|
||||
|
||||
if (res?.data?.data != undefined) {
|
||||
const data = res?.data?.data;
|
||||
console.log("data");
|
||||
console.log("Data :", data);
|
||||
form.setValue("title", data.title);
|
||||
form.setValue("detail", data.description);
|
||||
form.setValue("date", new Date(data.date));
|
||||
form.setValue(
|
||||
"output",
|
||||
data.fileTypeOutput.split(",")?.length > 1
|
||||
? data.fileTypeOutput.split(",")
|
||||
: [data.fileTypeOutput]
|
||||
);
|
||||
form.setValue("type", String(data?.assignmentTypeId));
|
||||
form.setValue("parentId", String(data?.parentId));
|
||||
mapTopDestination(data?.assignedToLevel);
|
||||
mapDestination(data?.assignedToTopLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mapTopDestination = (data: string) => {
|
||||
const temp: string[] = [];
|
||||
data.split(",").map((list) => {
|
||||
if (list.length < 2) {
|
||||
temp.push(list);
|
||||
}
|
||||
});
|
||||
form.setValue("unit", temp);
|
||||
};
|
||||
|
||||
const mapDestination = (data: string) => {
|
||||
const temp: { [key: number]: boolean } = {};
|
||||
data.split(",").forEach((list) => {
|
||||
temp[Number(list)] = true;
|
||||
});
|
||||
setSelected(temp);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getWeeklyPlanning();
|
||||
}, []);
|
||||
|
||||
async function getWeeklyPlanning() {
|
||||
const res = await getWeeklyPlanList(new Date().getDate(), 1);
|
||||
|
||||
if (res.data !== null) {
|
||||
const rawUser = res.data?.data;
|
||||
const optionArr = rawUser.map((option: any) => ({
|
||||
id: option.id,
|
||||
label: option.title,
|
||||
value: String(option.id),
|
||||
}));
|
||||
setWeeklyList(optionArr);
|
||||
}
|
||||
}
|
||||
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
unit: [],
|
||||
output: [],
|
||||
detail: "",
|
||||
},
|
||||
});
|
||||
const editor = useRef(null);
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
console.log("data", data);
|
||||
if (form.getValues("detail") == "") {
|
||||
form.setError("detail", {
|
||||
type: "manual",
|
||||
message: "Required",
|
||||
});
|
||||
} else {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
const getSelectedString = () => {
|
||||
return Object.keys(selected)
|
||||
.filter((key) => selected[key])
|
||||
.join(", ");
|
||||
};
|
||||
console.log("data", data, selected);
|
||||
loading();
|
||||
|
||||
const reqData = {
|
||||
id: id,
|
||||
planningTypeId: 1,
|
||||
time: "1",
|
||||
title: data.title,
|
||||
assignmentTypeId: data.type, //string
|
||||
description: data.detail,
|
||||
assignedToLevel: unit?.join(","), //string
|
||||
assignmentPurpose: getSelectedString(), //string
|
||||
fileTypeOutput: data.output?.join(","), //string
|
||||
status: "Open",
|
||||
date: getOnlyDate(data.date),
|
||||
// date:
|
||||
// isPublish || isUpdate
|
||||
// ? selectedDate?.length > 10
|
||||
// ? data.date?.toISOString().slice(0, 10)
|
||||
// : selectedDate
|
||||
// : data.date?.toISOString().slice(0, 10),
|
||||
parentId: Number(data.parentId), //number
|
||||
assignmentMainTypeId: 1,
|
||||
};
|
||||
|
||||
const response = await savePlanning(reqData);
|
||||
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
close();
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push("/curator/task-plan/mediahub");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const output = form.watch("output");
|
||||
|
||||
const isAllChecked = items.every((item) => output?.includes(item.id));
|
||||
|
||||
const unit = form.watch("unit");
|
||||
|
||||
const isAllUnitChecked = units.every((item) => unit?.includes(item.id));
|
||||
|
||||
const handleAllCheckedChange = (checked: boolean | string) => {
|
||||
if (checked) {
|
||||
form.setValue(
|
||||
"output",
|
||||
items.map((item) => item.id)
|
||||
);
|
||||
} else {
|
||||
form.setValue("output", []);
|
||||
}
|
||||
};
|
||||
|
||||
const handleItemCheckedChange = (id: string, checked: boolean | string) => {
|
||||
form.setValue(
|
||||
"output",
|
||||
checked ? [...output, id] : output.filter((value) => value !== id)
|
||||
);
|
||||
};
|
||||
|
||||
const handleAllUnitCheckedChange = (checked: boolean | string) => {
|
||||
if (checked) {
|
||||
form.setValue(
|
||||
"unit",
|
||||
units.map((item) => item.id)
|
||||
);
|
||||
} else {
|
||||
form.setValue("unit", []);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUnitCheckedChange = (id: string, checked: boolean | string) => {
|
||||
if (checked) {
|
||||
form.setValue("unit", [...unit, id]);
|
||||
} else {
|
||||
if (id == "2") {
|
||||
const temp = [];
|
||||
for (const element of unit) {
|
||||
if (element == "1") {
|
||||
temp.push("1");
|
||||
}
|
||||
}
|
||||
form.setValue("unit", temp);
|
||||
} else {
|
||||
form.setValue(
|
||||
"unit",
|
||||
unit.filter((value) => value !== id)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
const response = await getUserLevelForAssignments();
|
||||
setListDest(response.data.data.list);
|
||||
}
|
||||
|
||||
initState();
|
||||
}, []);
|
||||
|
||||
const handleParentChange = (listId: string) => {
|
||||
setSelected((prev) => ({
|
||||
...prev,
|
||||
[listId]: !prev[listId],
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSelectAllPolres = (listId: string, isChecked: boolean) => {
|
||||
setSelectAll((prev) => ({
|
||||
...prev,
|
||||
[listId]: isChecked,
|
||||
}));
|
||||
|
||||
setSelected((prev) => {
|
||||
const updatedState = { ...prev };
|
||||
listDest
|
||||
.find((list: any) => list.id === listId)
|
||||
?.subDestination.forEach((subDes: any) => {
|
||||
updatedState[`${listId}${subDes.id}`] = isChecked;
|
||||
});
|
||||
return updatedState;
|
||||
});
|
||||
};
|
||||
|
||||
const handleChildChange = (childId: string) => {
|
||||
setSelected((prev) => ({
|
||||
...prev,
|
||||
[childId]: !prev[childId],
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col bg-white gap-2 p-6">
|
||||
<p className="text-lg">Perencanaan MediaHub</p>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Judul Perencanaan</FormLabel>
|
||||
<Input
|
||||
value={field.value}
|
||||
placeholder="Masukkan Judul Perencanaan"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="output"
|
||||
render={() => (
|
||||
<FormItem>
|
||||
<div className="mb-4">
|
||||
<FormLabel className="text-sm">Output Tugas</FormLabel>
|
||||
</div>
|
||||
<div className="flex flex-row gap-3 items-center ">
|
||||
<div className="flex items-center gap-3">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={isAllChecked}
|
||||
onCheckedChange={(checked) =>
|
||||
handleAllCheckedChange(checked)
|
||||
}
|
||||
/>
|
||||
<label htmlFor="all" className="text-sm">
|
||||
Semua
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{items.map((item) => (
|
||||
<FormField
|
||||
key={item.id}
|
||||
control={form.control}
|
||||
name="output"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<FormItem
|
||||
key={item.id}
|
||||
className="flex flex-row items-start space-x-3 space-y-0"
|
||||
>
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={output?.includes(item.id)}
|
||||
onCheckedChange={(checked) =>
|
||||
handleItemCheckedChange(item.id, checked)
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
{item.label}
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="unit"
|
||||
render={() => (
|
||||
<FormItem>
|
||||
<div className="mb-4">
|
||||
<FormLabel className="text-sm">Pelaksana Tugas</FormLabel>
|
||||
</div>
|
||||
<div className="flex flex-row gap-3 items-center ">
|
||||
<div className="flex items-center gap-3">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={isAllUnitChecked}
|
||||
onCheckedChange={(checked) =>
|
||||
handleAllUnitCheckedChange(checked)
|
||||
}
|
||||
/>
|
||||
<label htmlFor="all" className="text-sm">
|
||||
Semua
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{units.map((item) => (
|
||||
<FormField
|
||||
key={item.id}
|
||||
control={form.control}
|
||||
name="unit"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<FormItem
|
||||
key={item.id}
|
||||
className="flex flex-row items-start space-x-3 space-y-0"
|
||||
>
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={unit?.includes(item.id)}
|
||||
disabled={
|
||||
item.id === "3" && !unit.includes("2")
|
||||
}
|
||||
onCheckedChange={(checked) =>
|
||||
handleUnitCheckedChange(item.id, checked)
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
{item.label}
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<Dialog>
|
||||
<DialogTrigger>
|
||||
<a className="text-primary cursor-pointer text-sm">
|
||||
{`[Kustom]`}
|
||||
</a>
|
||||
</DialogTrigger>
|
||||
<DialogContent size="md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
Daftar Wilayah Polda dan Polres
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="grid grid-cols-2 gap-4 py-4 px-2 max-h-[600px] overflow-y-auto custom-scrollbar-table">
|
||||
{listDest?.map((list: any) => (
|
||||
<div key={list.id}>
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
className="h-fit border-none"
|
||||
>
|
||||
<AccordionItem
|
||||
value={list.name}
|
||||
className="border-none"
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id={list.id}
|
||||
name={`all${list.id}`}
|
||||
checked={
|
||||
unit.includes("2")
|
||||
? true
|
||||
: !!selected[list.id]
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleParentChange(list.id)
|
||||
}
|
||||
disabled={unit.includes("2")}
|
||||
/>
|
||||
<label
|
||||
htmlFor={list.name}
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
{list.name}
|
||||
</label>
|
||||
<AccordionTrigger className="w-fit bg-transparent"></AccordionTrigger>
|
||||
</div>
|
||||
<AccordionContent>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
unit.includes("3")
|
||||
? true
|
||||
: !!selectAll[list.id]
|
||||
}
|
||||
onCheckedChange={(e) =>
|
||||
handleSelectAllPolres(
|
||||
list.id,
|
||||
Boolean(e)
|
||||
)
|
||||
}
|
||||
disabled={unit.includes("3")}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all-polres"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Pilih Semua Polres
|
||||
</label>
|
||||
</div>
|
||||
{list.subDestination.map(
|
||||
(subDes: any) => (
|
||||
<div
|
||||
key={subDes.id}
|
||||
className="flex items-center space-x-2"
|
||||
>
|
||||
<Checkbox
|
||||
id={`${list.id}${subDes.id}`}
|
||||
checked={
|
||||
unit.includes("3")
|
||||
? true
|
||||
: !!selected[
|
||||
`${list.id}${subDes.id}`
|
||||
]
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleChildChange(
|
||||
`${list.id}${subDes.id}`
|
||||
)
|
||||
}
|
||||
disabled={unit.includes("3")}
|
||||
/>
|
||||
<label
|
||||
htmlFor={`${list.id}${subDes.id}`}
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
{subDes.name}
|
||||
</label>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="type"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Jenis Penugasan</FormLabel>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
onValueChange={field.onChange}
|
||||
value={field.value}
|
||||
className="flex flex-row gap-3"
|
||||
>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="1" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
Publikasi
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="2" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
Amplifikasi
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="3" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">Kontra</FormLabel>
|
||||
</FormItem>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="date"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Pilih Tanggal</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{field.value ? (
|
||||
format(field.value, "PPP")
|
||||
) : (
|
||||
<span>Masukkan Tanggal</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="parentId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Perencanaan Mingguan</FormLabel>
|
||||
<Select value={field.value} onValueChange={field.onChange}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{weeklyList?.map((list: any) => (
|
||||
<SelectItem key={list.id} value={list.value}>
|
||||
{list.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Detail Perencanaan</FormLabel>
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={field.value}
|
||||
className="dark:text-black"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 justify-end mt-4 pt-4">
|
||||
<Button
|
||||
onClick={() => router.back()}
|
||||
variant="outline"
|
||||
color="destructive"
|
||||
type="button"
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -8,9 +8,9 @@ import {
|
|||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useRef, useState } from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
|
|
@ -30,6 +30,35 @@ import Swal from "sweetalert2";
|
|||
import withReactContent from "sweetalert2-react-content";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { getUserLevelForAssignments } from "@/service/task";
|
||||
import { list } from "postcss";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import { close, error, loading } from "@/config/swal";
|
||||
import { id } from "date-fns/locale";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
getWeeklyPlanList,
|
||||
savePlanning,
|
||||
} from "@/service/agenda-setting/agenda-setting";
|
||||
import { getOnlyDate } from "@/utils/globals";
|
||||
|
||||
const FormSchema = z.object({
|
||||
date: z.date({
|
||||
|
|
@ -47,46 +76,72 @@ const FormSchema = z.object({
|
|||
unit: z.array(z.string()).refine((value) => value.some((item) => item), {
|
||||
message: "Required",
|
||||
}),
|
||||
type: z.enum(["publication", "amplification", "contra"], {
|
||||
type: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
parentId: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
});
|
||||
|
||||
const items = [
|
||||
{
|
||||
id: "video",
|
||||
id: "2",
|
||||
label: "Audio Visual",
|
||||
},
|
||||
{
|
||||
id: "image",
|
||||
id: "1",
|
||||
label: "Foto",
|
||||
},
|
||||
{
|
||||
id: "audio",
|
||||
id: "4",
|
||||
label: "Audio",
|
||||
},
|
||||
{
|
||||
id: "text",
|
||||
id: "3",
|
||||
label: "Text",
|
||||
},
|
||||
];
|
||||
|
||||
const units = [
|
||||
{
|
||||
id: "mabes",
|
||||
id: "1",
|
||||
label: "Mabes Polri",
|
||||
},
|
||||
{
|
||||
id: "polda",
|
||||
id: "2",
|
||||
label: "Polda",
|
||||
},
|
||||
{
|
||||
id: "polres",
|
||||
id: "3",
|
||||
label: "Polres",
|
||||
},
|
||||
];
|
||||
export default function CreateMonthly() {
|
||||
export default function CreateDaily() {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const [listDest, setListDest] = useState<any>([]);
|
||||
const router = useRouter();
|
||||
const [weeklyList, setWeeklyList] = useState<any>();
|
||||
const [selected, setSelected] = useState<{ [key: string]: boolean }>({});
|
||||
const [selectAll, setSelectAll] = useState<{ [key: string]: boolean }>({});
|
||||
|
||||
useEffect(() => {
|
||||
getWeeklyPlanning();
|
||||
}, []);
|
||||
|
||||
async function getWeeklyPlanning() {
|
||||
const res = await getWeeklyPlanList(new Date().getDate(), 1);
|
||||
|
||||
if (res.data !== null) {
|
||||
const rawUser = res.data?.data;
|
||||
const optionArr = rawUser.map((option: any) => ({
|
||||
id: option.id,
|
||||
label: option.title,
|
||||
value: String(option.id),
|
||||
}));
|
||||
setWeeklyList(optionArr);
|
||||
}
|
||||
}
|
||||
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
|
|
@ -123,7 +178,54 @@ export default function CreateMonthly() {
|
|||
};
|
||||
|
||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
console.log("data", data);
|
||||
const getSelectedString = () => {
|
||||
return Object.keys(selected)
|
||||
.filter((key) => selected[key])
|
||||
.join(", ");
|
||||
};
|
||||
console.log("data", data, selected);
|
||||
loading();
|
||||
|
||||
const reqData = {
|
||||
planningTypeId: 1,
|
||||
time: "1",
|
||||
title: data.title,
|
||||
assignmentTypeId: data.type, //string
|
||||
description: data.detail,
|
||||
assignedToLevel: unit?.join(","), //string
|
||||
assignmentPurpose: getSelectedString(), //string
|
||||
fileTypeOutput: data.output?.join(","), //string
|
||||
status: "Open",
|
||||
date: getOnlyDate(data.date),
|
||||
// date:
|
||||
// isPublish || isUpdate
|
||||
// ? selectedDate?.length > 10
|
||||
// ? data.date?.toISOString().slice(0, 10)
|
||||
// : selectedDate
|
||||
// : data.date?.toISOString().slice(0, 10),
|
||||
parentId: Number(data.parentId), //number
|
||||
assignmentMainTypeId: 1,
|
||||
};
|
||||
|
||||
console.log("req =>", reqData);
|
||||
const response = await savePlanning(reqData);
|
||||
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
close();
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push("/curator/task-plan/mediahub");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const output = form.watch("output");
|
||||
|
|
@ -164,10 +266,64 @@ export default function CreateMonthly() {
|
|||
};
|
||||
|
||||
const handleUnitCheckedChange = (id: string, checked: boolean | string) => {
|
||||
form.setValue(
|
||||
"unit",
|
||||
checked ? [...unit, id] : unit.filter((value) => value !== id)
|
||||
);
|
||||
if (checked) {
|
||||
form.setValue("unit", [...unit, id]);
|
||||
} else {
|
||||
if (id == "2") {
|
||||
const temp = [];
|
||||
for (const element of unit) {
|
||||
if (element == "1") {
|
||||
temp.push("1");
|
||||
}
|
||||
}
|
||||
form.setValue("unit", temp);
|
||||
} else {
|
||||
form.setValue(
|
||||
"unit",
|
||||
unit.filter((value) => value !== id)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
const response = await getUserLevelForAssignments();
|
||||
setListDest(response.data.data.list);
|
||||
}
|
||||
|
||||
initState();
|
||||
}, []);
|
||||
|
||||
const handleParentChange = (listId: string) => {
|
||||
setSelected((prev) => ({
|
||||
...prev,
|
||||
[listId]: !prev[listId],
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSelectAllPolres = (listId: string, isChecked: boolean) => {
|
||||
setSelectAll((prev) => ({
|
||||
...prev,
|
||||
[listId]: isChecked,
|
||||
}));
|
||||
|
||||
setSelected((prev) => {
|
||||
const updatedState = { ...prev };
|
||||
listDest
|
||||
.find((list: any) => list.id === listId)
|
||||
?.subDestination.forEach((subDes: any) => {
|
||||
updatedState[`${listId}${subDes.id}`] = isChecked;
|
||||
});
|
||||
return updatedState;
|
||||
});
|
||||
};
|
||||
|
||||
const handleChildChange = (childId: string) => {
|
||||
setSelected((prev) => ({
|
||||
...prev,
|
||||
[childId]: !prev[childId],
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -226,7 +382,6 @@ export default function CreateMonthly() {
|
|||
<Checkbox
|
||||
id="all"
|
||||
checked={isAllChecked}
|
||||
// indeterminate={isSomeChecked && !isAllChecked}
|
||||
onCheckedChange={(checked) =>
|
||||
handleAllCheckedChange(checked)
|
||||
}
|
||||
|
|
@ -305,8 +460,7 @@ export default function CreateMonthly() {
|
|||
<Checkbox
|
||||
checked={unit?.includes(item.id)}
|
||||
disabled={
|
||||
item.id === "polres" &&
|
||||
!unit.includes("polda")
|
||||
item.id === "3" && !unit.includes("2")
|
||||
}
|
||||
onCheckedChange={(checked) =>
|
||||
handleUnitCheckedChange(item.id, checked)
|
||||
|
|
@ -321,6 +475,116 @@ export default function CreateMonthly() {
|
|||
}}
|
||||
/>
|
||||
))}
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<a className="text-primary cursor-pointer text-sm">
|
||||
{`[Kustom]`}
|
||||
</a>
|
||||
</DialogTrigger>
|
||||
<DialogContent size="md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
Daftar Wilayah Polda dan Polres
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="grid grid-cols-2 gap-4 py-4 px-2 max-h-[600px] overflow-y-auto custom-scrollbar-table">
|
||||
{listDest?.map((list: any) => (
|
||||
<div key={list.id}>
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
className="h-fit border-none"
|
||||
>
|
||||
<AccordionItem
|
||||
value={list.name}
|
||||
className="border-none"
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id={list.id}
|
||||
name={`all${list.id}`}
|
||||
checked={
|
||||
unit.includes("2")
|
||||
? true
|
||||
: !!selected[list.id]
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleParentChange(list.id)
|
||||
}
|
||||
disabled={unit.includes("2")}
|
||||
/>
|
||||
<label
|
||||
htmlFor={list.name}
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
{list.name}
|
||||
</label>
|
||||
<AccordionTrigger className="w-fit bg-transparent"></AccordionTrigger>
|
||||
</div>
|
||||
<AccordionContent>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
unit.includes("3")
|
||||
? true
|
||||
: !!selectAll[list.id]
|
||||
}
|
||||
onCheckedChange={(e) =>
|
||||
handleSelectAllPolres(
|
||||
list.id,
|
||||
Boolean(e)
|
||||
)
|
||||
}
|
||||
disabled={unit.includes("3")}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all-polres"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Pilih Semua Polres
|
||||
</label>
|
||||
</div>
|
||||
{list.subDestination.map(
|
||||
(subDes: any) => (
|
||||
<div
|
||||
key={subDes.id}
|
||||
className="flex items-center space-x-2"
|
||||
>
|
||||
<Checkbox
|
||||
id={`${list.id}${subDes.id}`}
|
||||
checked={
|
||||
unit.includes("3")
|
||||
? true
|
||||
: !!selected[
|
||||
`${list.id}${subDes.id}`
|
||||
]
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleChildChange(
|
||||
`${list.id}${subDes.id}`
|
||||
)
|
||||
}
|
||||
disabled={unit.includes("3")}
|
||||
/>
|
||||
<label
|
||||
htmlFor={`${list.id}${subDes.id}`}
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
{subDes.name}
|
||||
</label>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
|
@ -340,7 +604,7 @@ export default function CreateMonthly() {
|
|||
>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="publication" />
|
||||
<RadioGroupItem value="1" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
Publikasi
|
||||
|
|
@ -348,7 +612,7 @@ export default function CreateMonthly() {
|
|||
</FormItem>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="amplification" />
|
||||
<RadioGroupItem value="2" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
Amplifikasi
|
||||
|
|
@ -356,7 +620,7 @@ export default function CreateMonthly() {
|
|||
</FormItem>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="contra" />
|
||||
<RadioGroupItem value="3" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">Kontra</FormLabel>
|
||||
</FormItem>
|
||||
|
|
@ -402,6 +666,31 @@ export default function CreateMonthly() {
|
|||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="parentId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Perencanaan Mingguan</FormLabel>
|
||||
<Select value={field.value} onValueChange={field.onChange}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{weeklyList?.map((list: any) => (
|
||||
<SelectItem key={list.id} value={list.value}>
|
||||
{list.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,249 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { close, error, loading } from "@/config/swal";
|
||||
import { savePlanning } from "@/service/agenda-setting/agenda-setting";
|
||||
import { getPlanningById } from "@/service/planning/planning";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
const FormSchema = z.object({
|
||||
month: z.date({
|
||||
required_error: "Required",
|
||||
}),
|
||||
title: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
detail: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
});
|
||||
export default function DetailMonthly() {
|
||||
const id = useParams()?.id;
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
detail: "",
|
||||
},
|
||||
});
|
||||
const editor = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
async function getPlanning() {
|
||||
if (id != undefined) {
|
||||
const parseDate = (dateString: string): Date => {
|
||||
const [month, year] = dateString.split("/").map(Number);
|
||||
return new Date(year, month - 1);
|
||||
};
|
||||
loading();
|
||||
const res = await getPlanningById(id);
|
||||
close();
|
||||
if (res?.data?.data != undefined) {
|
||||
const data = res?.data?.data;
|
||||
console.log("Data :", data);
|
||||
form.setValue("title", data?.title);
|
||||
form.setValue("detail", data.description);
|
||||
const date = parseDate(data.date);
|
||||
console.log("date", date);
|
||||
form.setValue(
|
||||
"month",
|
||||
new Date(date.getFullYear(), date.getMonth(), 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getPlanning();
|
||||
}, [id]);
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
if (form.getValues("detail") == "") {
|
||||
form.setError("detail", {
|
||||
type: "manual",
|
||||
message: "Required",
|
||||
});
|
||||
} else {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
const reqData = {
|
||||
planningTypeId: 1,
|
||||
title: data.title,
|
||||
time: "3",
|
||||
description: data.detail,
|
||||
username: "",
|
||||
date: `${new Date(data.month).getMonth() + 1}/${new Date(
|
||||
data.month
|
||||
).getFullYear()}`,
|
||||
status: "Open",
|
||||
};
|
||||
console.log("req", reqData, data.month);
|
||||
const response = await savePlanning(reqData);
|
||||
close();
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push("/curator/task-plan/mediahub");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleMonthSelect = (selectedDate: Date | undefined) => {
|
||||
if (!selectedDate) return;
|
||||
const newDate = new Date(
|
||||
selectedDate.getFullYear(),
|
||||
selectedDate.getMonth(),
|
||||
1
|
||||
);
|
||||
console.log("newDate", newDate, selectedDate);
|
||||
form.setValue("month", newDate);
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col bg-white gap-2 p-6">
|
||||
<p className="text-lg">Perencanaan MediaHub Bulanan</p>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Judul Perencanaan</FormLabel>
|
||||
<Input
|
||||
value={field.value}
|
||||
placeholder="Masukkan Judul Perencanaan"
|
||||
onChange={field.onChange}
|
||||
readOnly
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="month"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Pilih Bulan</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
disabled
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{field.value ? (
|
||||
format(field.value, "MMMM yyyy")
|
||||
) : (
|
||||
<span>Masukkan Bulan</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={handleMonthSelect}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Detail Perencanaan</FormLabel>
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
config={{ readonly: true }}
|
||||
value={field.value}
|
||||
className="dark:text-black"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 justify-end mt-4 pt-4">
|
||||
<Button
|
||||
onClick={() => router.back()}
|
||||
variant="outline"
|
||||
color="destructive"
|
||||
type="button"
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,250 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { close, error, loading } from "@/config/swal";
|
||||
import { savePlanning } from "@/service/agenda-setting/agenda-setting";
|
||||
import { getPlanningById } from "@/service/planning/planning";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
const FormSchema = z.object({
|
||||
month: z.date({
|
||||
required_error: "Required",
|
||||
}),
|
||||
title: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
detail: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
});
|
||||
export default function EditMonthly() {
|
||||
const id = useParams()?.id;
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
detail: "",
|
||||
},
|
||||
});
|
||||
const editor = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
async function getPlanning() {
|
||||
if (id != undefined) {
|
||||
const parseDate = (dateString: string): Date => {
|
||||
const [month, year] = dateString.split("/").map(Number);
|
||||
return new Date(year, month - 1);
|
||||
};
|
||||
loading();
|
||||
const res = await getPlanningById(id);
|
||||
close();
|
||||
if (res?.data?.data != undefined) {
|
||||
const data = res?.data?.data;
|
||||
console.log("Data :", data);
|
||||
form.setValue("title", data?.title);
|
||||
form.setValue("detail", data.description);
|
||||
const date = parseDate(data.date);
|
||||
console.log("date", date);
|
||||
form.setValue(
|
||||
"month",
|
||||
new Date(date.getFullYear(), date.getMonth(), 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getPlanning();
|
||||
}, [id]);
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
if (form.getValues("detail") == "") {
|
||||
form.setError("detail", {
|
||||
type: "manual",
|
||||
message: "Required",
|
||||
});
|
||||
} else {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
const reqData = {
|
||||
id: id,
|
||||
planningTypeId: 1,
|
||||
title: data.title,
|
||||
time: "3",
|
||||
description: data.detail,
|
||||
username: "",
|
||||
date: `${new Date(data.month).getMonth() + 1}/${new Date(
|
||||
data.month
|
||||
).getFullYear()}`,
|
||||
status: "Open",
|
||||
};
|
||||
console.log("req", reqData, data.month);
|
||||
const response = await savePlanning(reqData);
|
||||
close();
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push("/curator/task-plan/mediahub");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleMonthSelect = (selectedDate: Date | undefined) => {
|
||||
if (!selectedDate) return;
|
||||
const newDate = new Date(
|
||||
selectedDate.getFullYear(),
|
||||
selectedDate.getMonth(),
|
||||
1
|
||||
);
|
||||
console.log("newDate", newDate, selectedDate);
|
||||
form.setValue("month", newDate);
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col bg-white gap-2 p-6">
|
||||
<p className="text-lg">Perencanaan MediaHub Bulanan</p>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Judul Perencanaan</FormLabel>
|
||||
<Input
|
||||
value={field.value}
|
||||
placeholder="Masukkan Judul Perencanaan"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="month"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Pilih Bulan</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{field.value ? (
|
||||
format(field.value, "MMMM yyyy")
|
||||
) : (
|
||||
<span>Masukkan Bulan</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={handleMonthSelect}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Detail Perencanaan</FormLabel>
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={field.value}
|
||||
className="dark:text-black"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 justify-end mt-4 pt-4">
|
||||
<Button
|
||||
onClick={() => router.back()}
|
||||
variant="outline"
|
||||
color="destructive"
|
||||
type="button"
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -83,7 +83,9 @@ export default function CreateMonthly() {
|
|||
time: "3",
|
||||
description: data.detail,
|
||||
username: "",
|
||||
date: new Date(data.month).getMonth() + 1,
|
||||
date: `${new Date(data.month).getMonth() + 1}/${new Date(
|
||||
data.month
|
||||
).getFullYear()}`,
|
||||
status: "Open",
|
||||
};
|
||||
console.log("req", reqData, data.month);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,261 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { close, error, loading } from "@/config/swal";
|
||||
import { getOnlyDate } from "@/utils/globals";
|
||||
import {
|
||||
getMonthlyPlanList,
|
||||
savePlanning,
|
||||
} from "@/service/agenda-setting/agenda-setting";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import dayjs from "dayjs";
|
||||
import { getPlanningById } from "@/service/planning/planning";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
const FormSchema = z.object({
|
||||
week: z.object({
|
||||
from: z.date({
|
||||
required_error: "Start date (from) is required",
|
||||
}),
|
||||
to: z.date({
|
||||
required_error: "End date (to) is required",
|
||||
}),
|
||||
}),
|
||||
title: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
detail: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
});
|
||||
export default function DetailMonthly() {
|
||||
const id = useParams()?.id;
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const [parentId, setParentId] = useState<number | undefined>();
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
detail: "",
|
||||
},
|
||||
});
|
||||
|
||||
const editor = useRef(null);
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
if (form.getValues("detail") == "") {
|
||||
form.setError("detail", {
|
||||
type: "manual",
|
||||
message: "Required",
|
||||
});
|
||||
} else {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
const reqData = {
|
||||
id: id,
|
||||
planningTypeId: 1,
|
||||
title: data.title,
|
||||
time: "2",
|
||||
description: data.detail,
|
||||
username: "",
|
||||
date: `${getOnlyDate(data.week.from)} - ${getOnlyDate(data.week.to)}`,
|
||||
status: "Open",
|
||||
parentId: parentId,
|
||||
};
|
||||
console.log("req", reqData);
|
||||
const response = await savePlanning(reqData);
|
||||
close();
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push("/curator/task-plan/mediahub");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function getPlanningData() {
|
||||
if (id != undefined) {
|
||||
loading();
|
||||
const res = await getPlanningById(id);
|
||||
close();
|
||||
if (res?.data?.data != undefined) {
|
||||
const data = res?.data?.data;
|
||||
console.log("Data :", data);
|
||||
form.setValue("title", data?.title);
|
||||
form.setValue("week", {
|
||||
from: new Date(data?.startDate),
|
||||
to: new Date(data?.endDate),
|
||||
});
|
||||
form.setValue("detail", data.description);
|
||||
setParentId(data?.parentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getPlanningData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col bg-white gap-2 p-6">
|
||||
<p className="text-lg">Perencanaan MediaHub Mingguan</p>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Judul Perencanaan</FormLabel>
|
||||
<Input
|
||||
value={field.value}
|
||||
placeholder="Masukkan Judul Perencanaan"
|
||||
onChange={field.onChange}
|
||||
readOnly
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="week"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Pilih Tanggal</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
disabled
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{field.value?.from ? (
|
||||
field.value.to ? (
|
||||
<>
|
||||
{format(field.value.from, "LLL dd, y")} -{" "}
|
||||
{format(field.value.to, "LLL dd, y")}
|
||||
</>
|
||||
) : (
|
||||
format(field.value.from, "LLL dd, y")
|
||||
)
|
||||
) : (
|
||||
<span>Masukkan Tanggal</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar
|
||||
mode="range"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Detail Perencanaan</FormLabel>
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={field.value}
|
||||
className="dark:text-black"
|
||||
onChange={field.onChange}
|
||||
config={{ readonly: true }}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 justify-end mt-4 pt-4">
|
||||
<Button
|
||||
onClick={() => router.back()}
|
||||
variant="outline"
|
||||
color="destructive"
|
||||
type="button"
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { close, error, loading } from "@/config/swal";
|
||||
import { getOnlyDate } from "@/utils/globals";
|
||||
import {
|
||||
getMonthlyPlanList,
|
||||
savePlanning,
|
||||
} from "@/service/agenda-setting/agenda-setting";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import dayjs from "dayjs";
|
||||
import { getPlanningById } from "@/service/planning/planning";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
const FormSchema = z.object({
|
||||
week: z.object({
|
||||
from: z.date({
|
||||
required_error: "Start date (from) is required",
|
||||
}),
|
||||
to: z.date({
|
||||
required_error: "End date (to) is required",
|
||||
}),
|
||||
}),
|
||||
title: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
detail: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
});
|
||||
export default function EditMonthly() {
|
||||
const id = useParams()?.id;
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const [parentId, setParentId] = useState<number | undefined>();
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
detail: "",
|
||||
},
|
||||
});
|
||||
|
||||
const editor = useRef(null);
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
if (form.getValues("detail") == "") {
|
||||
form.setError("detail", {
|
||||
type: "manual",
|
||||
message: "Required",
|
||||
});
|
||||
} else {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
const reqData = {
|
||||
id: id,
|
||||
planningTypeId: 1,
|
||||
title: data.title,
|
||||
time: "2",
|
||||
description: data.detail,
|
||||
username: "",
|
||||
date: `${getOnlyDate(data.week.from)} - ${getOnlyDate(data.week.to)}`,
|
||||
status: "Open",
|
||||
parentId: parentId,
|
||||
};
|
||||
console.log("req", reqData);
|
||||
const response = await savePlanning(reqData);
|
||||
close();
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push("/curator/task-plan/mediahub");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function getPlanningData() {
|
||||
if (id != undefined) {
|
||||
loading();
|
||||
const res = await getPlanningById(id);
|
||||
close();
|
||||
if (res?.data?.data != undefined) {
|
||||
const data = res?.data?.data;
|
||||
console.log("Data :", data);
|
||||
form.setValue("title", data?.title);
|
||||
form.setValue("week", {
|
||||
from: new Date(data?.startDate),
|
||||
to: new Date(data?.endDate),
|
||||
});
|
||||
form.setValue("detail", data.description);
|
||||
setParentId(data?.parentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getPlanningData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col bg-white gap-2 p-6">
|
||||
<p className="text-lg">Perencanaan MediaHub Mingguan</p>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Judul Perencanaan</FormLabel>
|
||||
<Input
|
||||
value={field.value}
|
||||
placeholder="Masukkan Judul Perencanaan"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="week"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Pilih Tanggal</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{field.value?.from ? (
|
||||
field.value.to ? (
|
||||
<>
|
||||
{format(field.value.from, "LLL dd, y")} -{" "}
|
||||
{format(field.value.to, "LLL dd, y")}
|
||||
</>
|
||||
) : (
|
||||
format(field.value.from, "LLL dd, y")
|
||||
)
|
||||
) : (
|
||||
<span>Masukkan Tanggal</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar
|
||||
mode="range"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Detail Perencanaan</FormLabel>
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={field.value}
|
||||
className="dark:text-black"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 justify-end mt-4 pt-4">
|
||||
<Button
|
||||
onClick={() => router.back()}
|
||||
variant="outline"
|
||||
color="destructive"
|
||||
type="button"
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ import {
|
|||
} from "@/components/ui/popover";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useRef, useState } from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
|
|
@ -30,7 +30,18 @@ import Swal from "sweetalert2";
|
|||
import withReactContent from "sweetalert2-react-content";
|
||||
import { error } from "@/config/swal";
|
||||
import { getOnlyDate } from "@/utils/globals";
|
||||
import { savePlanning } from "@/service/agenda-setting/agenda-setting";
|
||||
import {
|
||||
getMonthlyPlanList,
|
||||
savePlanning,
|
||||
} from "@/service/agenda-setting/agenda-setting";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const FormSchema = z.object({
|
||||
week: z.object({
|
||||
|
|
@ -47,6 +58,9 @@ const FormSchema = z.object({
|
|||
detail: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
parentId: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
});
|
||||
export default function CreateMonthly() {
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
|
@ -57,6 +71,8 @@ export default function CreateMonthly() {
|
|||
detail: "",
|
||||
},
|
||||
});
|
||||
const [monthlyList, setMonthlyList] = useState<any>();
|
||||
|
||||
const editor = useRef(null);
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
|
|
@ -91,6 +107,7 @@ export default function CreateMonthly() {
|
|||
username: "",
|
||||
date: `${getOnlyDate(data.week.from)} - ${getOnlyDate(data.week.to)}`,
|
||||
status: "Open",
|
||||
parentId: Number(data.parentId),
|
||||
};
|
||||
console.log("req", reqData);
|
||||
const response = await savePlanning(reqData);
|
||||
|
|
@ -112,6 +129,23 @@ export default function CreateMonthly() {
|
|||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getMonthlyPlanning();
|
||||
}, []);
|
||||
|
||||
async function getMonthlyPlanning() {
|
||||
const res = await getMonthlyPlanList(new Date().getDate(), 1);
|
||||
|
||||
if (res.data !== null) {
|
||||
const rawUser = res.data?.data;
|
||||
const optionArr = rawUser.map((option: any) => ({
|
||||
id: option.id,
|
||||
label: option.title,
|
||||
value: String(option.id),
|
||||
}));
|
||||
setMonthlyList(optionArr);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
|
|
@ -198,6 +232,31 @@ export default function CreateMonthly() {
|
|||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="parentId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Perencanaan Bulanan</FormLabel>
|
||||
<Select value={field.value} onValueChange={field.onChange}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{monthlyList?.map((list: any) => (
|
||||
<SelectItem key={list.id} value={list.value}>
|
||||
{list.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
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 {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuItem,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { htmlToString } from "@/utils/globals";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Judul Perencanaan",
|
||||
cell: ({ row }) => <span>{row.getValue("title")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "createdByName",
|
||||
header: "Nama Pembuat",
|
||||
cell: ({ row }) => <span>{row.getValue("createdByName")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "description",
|
||||
header: "Deskripsi",
|
||||
cell: ({ row }) => <span>{htmlToString(row.getValue("description"))}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => <span>{row.getValue("status")}</span>,
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Link
|
||||
href={`/curator/task-plan/mediahub/detail/${row.original.id}`}
|
||||
>
|
||||
Detail
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default columns;
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
PaginationState,
|
||||
SortingState,
|
||||
VisibilityState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import {
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Eye,
|
||||
MoreVertical,
|
||||
Search,
|
||||
SquarePen,
|
||||
Trash2,
|
||||
TrendingDown,
|
||||
TrendingUp,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
|
||||
import { paginationBlog } from "@/service/blog/blog";
|
||||
import { ticketingPagination } from "@/service/ticketing/ticketing";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import TablePagination from "@/components/table/table-pagination";
|
||||
import columns from "./columns";
|
||||
|
||||
const TaskPlanMediahubTable = (props: {
|
||||
data: any;
|
||||
totalPage: number;
|
||||
totalData: number;
|
||||
}) => {
|
||||
const { data, totalPage, totalData } = props;
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||
// const [totalData, setTotalData] = React.useState<number>(1);
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[]
|
||||
);
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
const [pagination, setPagination] = React.useState<PaginationState>({
|
||||
pageIndex: 0,
|
||||
pageSize: 10,
|
||||
});
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
onSortingChange: setSorting,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
onRowSelectionChange: setRowSelection,
|
||||
onPaginationChange: setPagination,
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
columnVisibility,
|
||||
rowSelection,
|
||||
pagination,
|
||||
},
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
const pageFromUrl = searchParams?.get("page");
|
||||
if (pageFromUrl) {
|
||||
setPage(Number(pageFromUrl));
|
||||
}
|
||||
}, [searchParams]);
|
||||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit, data]);
|
||||
|
||||
async function fetchData() {
|
||||
// try {
|
||||
// const res = await ticketingPagination("", limit, page - 1);
|
||||
// const data = res.data?.data;
|
||||
console.log("datgaa", data);
|
||||
const contentData = data;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
item.no = (page - 1) * limit + index + 1;
|
||||
});
|
||||
|
||||
console.log("contentData : ", contentData);
|
||||
|
||||
setDataTable(contentData);
|
||||
// setTotalData(data?.totalElements);
|
||||
// } catch (error) {
|
||||
// console.error("Error fetching tasks:", error);
|
||||
// }
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<Table className="overflow-hidden mt-3">
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id} className="bg-default-200">
|
||||
{headerGroup.headers.map((header) => (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
className="h-[75px]"
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination
|
||||
table={table}
|
||||
totalData={totalData}
|
||||
totalPage={totalPage}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TaskPlanMediahubTable;
|
||||
|
|
@ -0,0 +1,791 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
getWeeklyPlanList,
|
||||
savePlanning,
|
||||
} from "@/service/agenda-setting/agenda-setting";
|
||||
import { id } from "date-fns/locale";
|
||||
import { close, error, loading } from "@/config/swal";
|
||||
import { getOnlyDate } from "@/utils/globals";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { getUserLevelForAssignments } from "@/service/task";
|
||||
|
||||
const FormSchema = z.object({
|
||||
date: z.date({
|
||||
required_error: "Required",
|
||||
}),
|
||||
title: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
detail: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
output: z.array(z.string()).refine((value) => value.some((item) => item), {
|
||||
message: "Required",
|
||||
}),
|
||||
unit: z.array(z.string()).refine((value) => value.some((item) => item), {
|
||||
message: "Required",
|
||||
}),
|
||||
type: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
parentId: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
media: z.array(z.string()).refine((value) => value.some((item) => item), {
|
||||
message: "Required",
|
||||
}),
|
||||
});
|
||||
|
||||
const items = [
|
||||
{
|
||||
id: "2",
|
||||
label: "Audio Visual",
|
||||
},
|
||||
{
|
||||
id: "1",
|
||||
label: "Foto",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
label: "Audio",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
label: "Text",
|
||||
},
|
||||
];
|
||||
|
||||
const medias = [
|
||||
{
|
||||
id: "5",
|
||||
label: "X",
|
||||
},
|
||||
{
|
||||
id: "1",
|
||||
label: "Facebook",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
label: "Instagram",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
label: "Youtube",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
label: "Tiktok",
|
||||
},
|
||||
];
|
||||
|
||||
const units = [
|
||||
{
|
||||
id: "1",
|
||||
label: "Mabes Polri",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
label: "Polda",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
label: "Polres",
|
||||
},
|
||||
];
|
||||
export default function CreateMonthly() {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const [weeklyList, setWeeklyList] = useState<any>();
|
||||
const router = useRouter();
|
||||
const [selected, setSelected] = useState<{ [key: string]: boolean }>({});
|
||||
const [selectAll, setSelectAll] = useState<{ [key: string]: boolean }>({});
|
||||
const [listDest, setListDest] = useState<any>([]);
|
||||
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
unit: [],
|
||||
output: [],
|
||||
detail: "",
|
||||
media: [],
|
||||
},
|
||||
});
|
||||
const editor = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
getWeeklyPlanning();
|
||||
}, []);
|
||||
|
||||
async function getWeeklyPlanning() {
|
||||
const res = await getWeeklyPlanList(new Date().getDate(), 2);
|
||||
|
||||
if (res.data !== null) {
|
||||
const rawUser = res.data?.data;
|
||||
const optionArr = rawUser.map((option: any) => ({
|
||||
id: option.id,
|
||||
label: option.title,
|
||||
value: String(option.id),
|
||||
}));
|
||||
setWeeklyList(optionArr);
|
||||
}
|
||||
}
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
if (form.getValues("detail") == "") {
|
||||
form.setError("detail", {
|
||||
type: "manual",
|
||||
message: "Required",
|
||||
});
|
||||
} else {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
const getSelectedString = () => {
|
||||
return Object.keys(selected)
|
||||
.filter((key) => selected[key])
|
||||
.join(", ");
|
||||
};
|
||||
loading();
|
||||
|
||||
const reqData = {
|
||||
planningTypeId: 2,
|
||||
time: "1",
|
||||
title: data.title,
|
||||
assignmentTypeId: data.type, //string
|
||||
description: data.detail,
|
||||
assignedToLevel: unit?.join(","), //string
|
||||
assignmentPurpose: getSelectedString(), //string
|
||||
fileTypeOutput: data.output?.join(","), //string
|
||||
status: "Open",
|
||||
date: getOnlyDate(data.date),
|
||||
platformType: data.media?.join(","),
|
||||
parentId: Number(data.parentId), //number
|
||||
assignmentMainTypeId: 2,
|
||||
};
|
||||
|
||||
console.log("req =>", reqData);
|
||||
const response = await savePlanning(reqData);
|
||||
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
close();
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push("/curator/task-plan/medsos-mediahub");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const output = form.watch("output");
|
||||
const media = form.watch("media");
|
||||
const unit = form.watch("unit");
|
||||
|
||||
const isAllChecked = items.every((item) => output?.includes(item.id));
|
||||
const isAllMediaChecked = medias.every((item) => media?.includes(item.id));
|
||||
const isAllUnitChecked = units.every((item) => unit?.includes(item.id));
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
const response = await getUserLevelForAssignments();
|
||||
setListDest(response.data.data.list);
|
||||
}
|
||||
|
||||
initState();
|
||||
}, []);
|
||||
|
||||
const handleParentChange = (listId: string) => {
|
||||
setSelected((prev) => ({
|
||||
...prev,
|
||||
[listId]: !prev[listId],
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSelectAllPolres = (listId: string, isChecked: boolean) => {
|
||||
setSelectAll((prev) => ({
|
||||
...prev,
|
||||
[listId]: isChecked,
|
||||
}));
|
||||
|
||||
setSelected((prev) => {
|
||||
const updatedState = { ...prev };
|
||||
listDest
|
||||
.find((list: any) => list.id === listId)
|
||||
?.subDestination.forEach((subDes: any) => {
|
||||
updatedState[`${listId}${subDes.id}`] = isChecked;
|
||||
});
|
||||
return updatedState;
|
||||
});
|
||||
};
|
||||
|
||||
const handleChildChange = (childId: string) => {
|
||||
setSelected((prev) => ({
|
||||
...prev,
|
||||
[childId]: !prev[childId],
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-row justify-center gap-5 mt-10">
|
||||
<Link
|
||||
href="/curator/task-plan/medsos-mediahub/create-monthly"
|
||||
className="bg-slate-200 text-black rounded-full px-5 py-2 text-sm"
|
||||
>
|
||||
Bulanan
|
||||
</Link>
|
||||
<Link
|
||||
href="/curator/task-plan/medsos-mediahub/create-weekly"
|
||||
className="bg-slate-200 text-black rounded-full px-5 py-2 text-sm"
|
||||
>
|
||||
Mingguan
|
||||
</Link>
|
||||
|
||||
<div className="bg-primary rounded-full px-5 py-2 text-white text-sm">
|
||||
Harian
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col bg-white gap-2 p-6">
|
||||
<p className="text-lg">Perencanaan MediaHub</p>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Judul Perencanaan</FormLabel>
|
||||
<Input
|
||||
value={field.value}
|
||||
placeholder="Masukkan Judul Perencanaan"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="output"
|
||||
render={() => (
|
||||
<FormItem>
|
||||
<div className="mb-4">
|
||||
<FormLabel className="text-sm">Output Tugas</FormLabel>
|
||||
</div>
|
||||
<div className="flex flex-row gap-3 items-center ">
|
||||
<div className="flex items-center gap-3">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={isAllChecked}
|
||||
onCheckedChange={(checked) => {
|
||||
if (checked) {
|
||||
form.setValue(
|
||||
"output",
|
||||
items.map((item) => item.id)
|
||||
);
|
||||
} else {
|
||||
form.setValue("output", []);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="all" className="text-sm">
|
||||
Semua
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{items.map((item) => (
|
||||
<FormField
|
||||
key={item.id}
|
||||
control={form.control}
|
||||
name="output"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<FormItem
|
||||
key={item.id}
|
||||
className="flex flex-row items-start space-x-3 space-y-0"
|
||||
>
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={output?.includes(item.id)}
|
||||
onCheckedChange={(checked) => {
|
||||
form.setValue(
|
||||
"output",
|
||||
checked
|
||||
? [...output, item.id]
|
||||
: output.filter(
|
||||
(value) => value !== item.id
|
||||
)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
{item.label}
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="unit"
|
||||
render={() => (
|
||||
<FormItem>
|
||||
<div className="mb-4">
|
||||
<FormLabel className="text-sm">Pelaksana Tugas</FormLabel>
|
||||
</div>
|
||||
<div className="flex flex-row gap-3 items-center ">
|
||||
<div className="flex items-center gap-3">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={isAllUnitChecked}
|
||||
onCheckedChange={(checked) => {
|
||||
if (checked) {
|
||||
form.setValue(
|
||||
"unit",
|
||||
units.map((item) => item.id)
|
||||
);
|
||||
} else {
|
||||
form.setValue("unit", []);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="all" className="text-sm">
|
||||
Semua
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{units.map((item) => (
|
||||
<FormField
|
||||
key={item.id}
|
||||
control={form.control}
|
||||
name="unit"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<FormItem
|
||||
key={item.id}
|
||||
className="flex flex-row items-start space-x-3 space-y-0"
|
||||
>
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={unit?.includes(item.id)}
|
||||
disabled={
|
||||
item.id === "polres" &&
|
||||
!unit.includes("polda")
|
||||
}
|
||||
onCheckedChange={(checked) => {
|
||||
form.setValue(
|
||||
"unit",
|
||||
checked
|
||||
? [...unit, item.id]
|
||||
: unit.filter(
|
||||
(value) => value !== item.id
|
||||
)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
{item.label}
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<a className="text-primary cursor-pointer text-sm">
|
||||
{`[Kustom]`}
|
||||
</a>
|
||||
</DialogTrigger>
|
||||
<DialogContent size="md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
Daftar Wilayah Polda dan Polres
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="grid grid-cols-2 gap-4 py-4 px-2 max-h-[600px] overflow-y-auto custom-scrollbar-table">
|
||||
{listDest?.map((list: any) => (
|
||||
<div key={list.id}>
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
className="h-fit border-none"
|
||||
>
|
||||
<AccordionItem
|
||||
value={list.name}
|
||||
className="border-none"
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id={list.id}
|
||||
name={`all${list.id}`}
|
||||
checked={
|
||||
unit.includes("2")
|
||||
? true
|
||||
: !!selected[list.id]
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleParentChange(list.id)
|
||||
}
|
||||
disabled={unit.includes("2")}
|
||||
/>
|
||||
<label
|
||||
htmlFor={list.name}
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
{list.name}
|
||||
</label>
|
||||
<AccordionTrigger className="w-fit bg-transparent"></AccordionTrigger>
|
||||
</div>
|
||||
<AccordionContent>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
unit.includes("3")
|
||||
? true
|
||||
: !!selectAll[list.id]
|
||||
}
|
||||
onCheckedChange={(e) =>
|
||||
handleSelectAllPolres(
|
||||
list.id,
|
||||
Boolean(e)
|
||||
)
|
||||
}
|
||||
disabled={unit.includes("3")}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all-polres"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Pilih Semua Polres
|
||||
</label>
|
||||
</div>
|
||||
{list.subDestination.map(
|
||||
(subDes: any) => (
|
||||
<div
|
||||
key={subDes.id}
|
||||
className="flex items-center space-x-2"
|
||||
>
|
||||
<Checkbox
|
||||
id={`${list.id}${subDes.id}`}
|
||||
checked={
|
||||
unit.includes("3")
|
||||
? true
|
||||
: !!selected[
|
||||
`${list.id}${subDes.id}`
|
||||
]
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleChildChange(
|
||||
`${list.id}${subDes.id}`
|
||||
)
|
||||
}
|
||||
disabled={unit.includes("3")}
|
||||
/>
|
||||
<label
|
||||
htmlFor={`${list.id}${subDes.id}`}
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
{subDes.name}
|
||||
</label>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="media"
|
||||
render={() => (
|
||||
<FormItem>
|
||||
<div className="mb-4">
|
||||
<FormLabel className="text-sm">Jenis Platform</FormLabel>
|
||||
</div>
|
||||
<div className="flex flex-row gap-3 items-center ">
|
||||
<div className="flex items-center gap-3">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={isAllMediaChecked}
|
||||
onCheckedChange={(checked) => {
|
||||
if (checked) {
|
||||
form.setValue(
|
||||
"media",
|
||||
medias.map((item) => item.id)
|
||||
);
|
||||
} else {
|
||||
form.setValue("media", []);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="all" className="text-sm">
|
||||
Semua
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{medias.map((item) => (
|
||||
<FormField
|
||||
key={item.id}
|
||||
control={form.control}
|
||||
name="output"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<FormItem
|
||||
key={item.id}
|
||||
className="flex flex-row items-start space-x-3 space-y-0"
|
||||
>
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={media?.includes(item.id)}
|
||||
onCheckedChange={(checked) => {
|
||||
form.setValue(
|
||||
"media",
|
||||
checked
|
||||
? [...media, item.id]
|
||||
: media.filter(
|
||||
(value) => value !== item.id
|
||||
)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
{item.label}
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="type"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Jenis Penugasan</FormLabel>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
onValueChange={field.onChange}
|
||||
defaultValue={field.value}
|
||||
className="flex flex-row gap-3"
|
||||
>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="1" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
Publikasi
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="2" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
Amplifikasi
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="3" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">Kontra</FormLabel>
|
||||
</FormItem>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="parentId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Perencanaan Mingguan</FormLabel>
|
||||
<Select value={field.value} onValueChange={field.onChange}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{weeklyList?.map((list: any) => (
|
||||
<SelectItem key={list.id} value={list.value}>
|
||||
{list.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="date"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Pilih Tanggal</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{field.value ? (
|
||||
format(field.value, "PPP")
|
||||
) : (
|
||||
<span>Masukkan Tanggal</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Detail Perencanaan</FormLabel>
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={field.value}
|
||||
className="dark:text-black"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 justify-end mt-4 pt-4">
|
||||
<Button type="submit" variant="outline" color="destructive">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,249 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { close, error, loading } from "@/config/swal";
|
||||
import { savePlanning } from "@/service/agenda-setting/agenda-setting";
|
||||
import { getPlanningById } from "@/service/planning/planning";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
const FormSchema = z.object({
|
||||
month: z.date({
|
||||
required_error: "Required",
|
||||
}),
|
||||
title: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
detail: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
});
|
||||
export default function DetailMonthly() {
|
||||
const id = useParams()?.id;
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
detail: "",
|
||||
},
|
||||
});
|
||||
const editor = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
async function getPlanning() {
|
||||
if (id != undefined) {
|
||||
const parseDate = (dateString: string): Date => {
|
||||
const [month, year] = dateString.split("/").map(Number);
|
||||
return new Date(year, month - 1);
|
||||
};
|
||||
loading();
|
||||
const res = await getPlanningById(id);
|
||||
close();
|
||||
if (res?.data?.data != undefined) {
|
||||
const data = res?.data?.data;
|
||||
console.log("Data :", data);
|
||||
form.setValue("title", data?.title);
|
||||
form.setValue("detail", data.description);
|
||||
const date = parseDate(data.date);
|
||||
console.log("date", date);
|
||||
form.setValue(
|
||||
"month",
|
||||
new Date(date.getFullYear(), date.getMonth(), 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getPlanning();
|
||||
}, [id]);
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
if (form.getValues("detail") == "") {
|
||||
form.setError("detail", {
|
||||
type: "manual",
|
||||
message: "Required",
|
||||
});
|
||||
} else {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
const reqData = {
|
||||
planningTypeId: 1,
|
||||
title: data.title,
|
||||
time: "3",
|
||||
description: data.detail,
|
||||
username: "",
|
||||
date: `${new Date(data.month).getMonth() + 1}/${new Date(
|
||||
data.month
|
||||
).getFullYear()}`,
|
||||
status: "Open",
|
||||
};
|
||||
console.log("req", reqData, data.month);
|
||||
const response = await savePlanning(reqData);
|
||||
close();
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push("/curator/task-plan/mediahub");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleMonthSelect = (selectedDate: Date | undefined) => {
|
||||
if (!selectedDate) return;
|
||||
const newDate = new Date(
|
||||
selectedDate.getFullYear(),
|
||||
selectedDate.getMonth(),
|
||||
1
|
||||
);
|
||||
console.log("newDate", newDate, selectedDate);
|
||||
form.setValue("month", newDate);
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col bg-white gap-2 p-6">
|
||||
<p className="text-lg">Perencanaan MediaHub Bulanan</p>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Judul Perencanaan</FormLabel>
|
||||
<Input
|
||||
value={field.value}
|
||||
placeholder="Masukkan Judul Perencanaan"
|
||||
onChange={field.onChange}
|
||||
readOnly
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="month"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Pilih Bulan</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
disabled
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{field.value ? (
|
||||
format(field.value, "MMMM yyyy")
|
||||
) : (
|
||||
<span>Masukkan Bulan</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={handleMonthSelect}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Detail Perencanaan</FormLabel>
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
config={{ readonly: true }}
|
||||
value={field.value}
|
||||
className="dark:text-black"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 justify-end mt-4 pt-4">
|
||||
<Button
|
||||
onClick={() => router.back()}
|
||||
variant="outline"
|
||||
color="destructive"
|
||||
type="button"
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,250 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { close, error, loading } from "@/config/swal";
|
||||
import { savePlanning } from "@/service/agenda-setting/agenda-setting";
|
||||
import { getPlanningById } from "@/service/planning/planning";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
const FormSchema = z.object({
|
||||
month: z.date({
|
||||
required_error: "Required",
|
||||
}),
|
||||
title: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
detail: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
});
|
||||
export default function EditMonthly() {
|
||||
const id = useParams()?.id;
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
detail: "",
|
||||
},
|
||||
});
|
||||
const editor = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
async function getPlanning() {
|
||||
if (id != undefined) {
|
||||
const parseDate = (dateString: string): Date => {
|
||||
const [month, year] = dateString.split("/").map(Number);
|
||||
return new Date(year, month - 1);
|
||||
};
|
||||
loading();
|
||||
const res = await getPlanningById(id);
|
||||
close();
|
||||
if (res?.data?.data != undefined) {
|
||||
const data = res?.data?.data;
|
||||
console.log("Data :", data);
|
||||
form.setValue("title", data?.title);
|
||||
form.setValue("detail", data.description);
|
||||
const date = parseDate(data.date);
|
||||
console.log("date", date);
|
||||
form.setValue(
|
||||
"month",
|
||||
new Date(date.getFullYear(), date.getMonth(), 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getPlanning();
|
||||
}, [id]);
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
if (form.getValues("detail") == "") {
|
||||
form.setError("detail", {
|
||||
type: "manual",
|
||||
message: "Required",
|
||||
});
|
||||
} else {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
const reqData = {
|
||||
id: id,
|
||||
planningTypeId: 1,
|
||||
title: data.title,
|
||||
time: "3",
|
||||
description: data.detail,
|
||||
username: "",
|
||||
date: `${new Date(data.month).getMonth() + 1}/${new Date(
|
||||
data.month
|
||||
).getFullYear()}`,
|
||||
status: "Open",
|
||||
};
|
||||
console.log("req", reqData, data.month);
|
||||
const response = await savePlanning(reqData);
|
||||
close();
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push("/curator/task-plan/mediahub");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleMonthSelect = (selectedDate: Date | undefined) => {
|
||||
if (!selectedDate) return;
|
||||
const newDate = new Date(
|
||||
selectedDate.getFullYear(),
|
||||
selectedDate.getMonth(),
|
||||
1
|
||||
);
|
||||
console.log("newDate", newDate, selectedDate);
|
||||
form.setValue("month", newDate);
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col bg-white gap-2 p-6">
|
||||
<p className="text-lg">Perencanaan MediaHub Bulanan</p>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Judul Perencanaan</FormLabel>
|
||||
<Input
|
||||
value={field.value}
|
||||
placeholder="Masukkan Judul Perencanaan"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="month"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Pilih Bulan</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{field.value ? (
|
||||
format(field.value, "MMMM yyyy")
|
||||
) : (
|
||||
<span>Masukkan Bulan</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={handleMonthSelect}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Detail Perencanaan</FormLabel>
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={field.value}
|
||||
className="dark:text-black"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 justify-end mt-4 pt-4">
|
||||
<Button
|
||||
onClick={() => router.back()}
|
||||
variant="outline"
|
||||
color="destructive"
|
||||
type="button"
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { error } from "@/config/swal";
|
||||
import { savePlanning } from "@/service/agenda-setting/agenda-setting";
|
||||
|
||||
const FormSchema = z.object({
|
||||
month: z.date({
|
||||
required_error: "Required",
|
||||
}),
|
||||
title: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
detail: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
});
|
||||
export default function CreateMonthly() {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
detail: "",
|
||||
},
|
||||
});
|
||||
const editor = useRef(null);
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
if (form.getValues("detail") == "") {
|
||||
form.setError("detail", {
|
||||
type: "manual",
|
||||
message: "Required",
|
||||
});
|
||||
} else {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
const reqData = {
|
||||
planningTypeId: 2,
|
||||
title: data.title,
|
||||
time: "3",
|
||||
description: data.detail,
|
||||
username: "",
|
||||
date: `${new Date(data.month).getMonth() + 1}/${new Date(
|
||||
data.month
|
||||
).getFullYear()}`,
|
||||
status: "Open",
|
||||
};
|
||||
console.log("req", reqData, data.month);
|
||||
const response = await savePlanning(reqData);
|
||||
close();
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push("/curator/task-plan/medsos-mediahub");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleMonthSelect = (selectedDate: Date | undefined) => {
|
||||
if (!selectedDate) return;
|
||||
const newDate = new Date(
|
||||
selectedDate.getFullYear(),
|
||||
selectedDate.getMonth(),
|
||||
1
|
||||
);
|
||||
form.setValue("month", newDate);
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-row justify-center gap-5 mt-10">
|
||||
<div className="bg-primary rounded-full px-5 py-2 text-white text-sm">
|
||||
Bulanan
|
||||
</div>
|
||||
<Link
|
||||
href="/curator/task-plan/medsos-mediahub/create-weekly"
|
||||
className="bg-slate-200 text-black rounded-full px-5 py-2 text-sm"
|
||||
>
|
||||
Mingguan
|
||||
</Link>
|
||||
<Link
|
||||
href="/curator/task-plan/medsos-mediahub/create-daily"
|
||||
className="bg-slate-200 text-black rounded-full px-5 py-2 text-sm"
|
||||
>
|
||||
Harian
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex flex-col bg-white gap-2 p-6">
|
||||
<p className="text-lg">Perencanaan MediaHub Bulanan</p>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Judul Perencanaan</FormLabel>
|
||||
<Input
|
||||
value={field.value}
|
||||
placeholder="Masukkan Judul Perencanaan"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="month"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Pilih Bulan</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{field.value ? (
|
||||
format(field.value, "MMMM yyyy")
|
||||
) : (
|
||||
<span>Masukkan Bulan</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={handleMonthSelect}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Detail Perencanaan</FormLabel>
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={field.value}
|
||||
className="dark:text-black"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 justify-end mt-4 pt-4">
|
||||
<Button type="submit" variant="outline" color="destructive">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { close, error, loading } from "@/config/swal";
|
||||
import { getOnlyDate } from "@/utils/globals";
|
||||
import {
|
||||
getMonthlyPlanList,
|
||||
savePlanning,
|
||||
} from "@/service/agenda-setting/agenda-setting";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import dayjs from "dayjs";
|
||||
import { getPlanningById } from "@/service/planning/planning";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
const FormSchema = z.object({
|
||||
week: z.object({
|
||||
from: z.date({
|
||||
required_error: "Start date (from) is required",
|
||||
}),
|
||||
to: z.date({
|
||||
required_error: "End date (to) is required",
|
||||
}),
|
||||
}),
|
||||
title: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
detail: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
});
|
||||
export default function DetailMonthly() {
|
||||
const id = useParams()?.id;
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const [parentId, setParentId] = useState<number | undefined>();
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
detail: "",
|
||||
},
|
||||
});
|
||||
|
||||
const editor = useRef(null);
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
if (form.getValues("detail") == "") {
|
||||
form.setError("detail", {
|
||||
type: "manual",
|
||||
message: "Required",
|
||||
});
|
||||
} else {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
const reqData = {
|
||||
id: id,
|
||||
planningTypeId: 1,
|
||||
title: data.title,
|
||||
time: "2",
|
||||
description: data.detail,
|
||||
username: "",
|
||||
date: `${getOnlyDate(data.week.from)} - ${getOnlyDate(data.week.to)}`,
|
||||
status: "Open",
|
||||
parentId: parentId,
|
||||
};
|
||||
console.log("req", reqData);
|
||||
const response = await savePlanning(reqData);
|
||||
close();
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push("/curator/task-plan/mediahub");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function getPlanningData() {
|
||||
if (id != undefined) {
|
||||
loading();
|
||||
const res = await getPlanningById(id);
|
||||
close();
|
||||
if (res?.data?.data != undefined) {
|
||||
const data = res?.data?.data;
|
||||
console.log("Data :", data);
|
||||
form.setValue("title", data?.title);
|
||||
form.setValue("week", {
|
||||
from: new Date(data?.startDate),
|
||||
to: new Date(data?.endDate),
|
||||
});
|
||||
form.setValue("detail", data.description);
|
||||
setParentId(data?.parentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getPlanningData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col bg-white gap-2 p-6">
|
||||
<p className="text-lg">Perencanaan MediaHub Mingguan</p>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Judul Perencanaan</FormLabel>
|
||||
<Input
|
||||
value={field.value}
|
||||
placeholder="Masukkan Judul Perencanaan"
|
||||
onChange={field.onChange}
|
||||
readOnly
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="week"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Pilih Tanggal</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
disabled
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{field.value?.from ? (
|
||||
field.value.to ? (
|
||||
<>
|
||||
{format(field.value.from, "LLL dd, y")} -{" "}
|
||||
{format(field.value.to, "LLL dd, y")}
|
||||
</>
|
||||
) : (
|
||||
format(field.value.from, "LLL dd, y")
|
||||
)
|
||||
) : (
|
||||
<span>Masukkan Tanggal</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar
|
||||
mode="range"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Detail Perencanaan</FormLabel>
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={field.value}
|
||||
className="dark:text-black"
|
||||
onChange={field.onChange}
|
||||
config={{ readonly: true }}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 justify-end mt-4 pt-4">
|
||||
<Button
|
||||
onClick={() => router.back()}
|
||||
variant="outline"
|
||||
color="destructive"
|
||||
type="button"
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { close, error, loading } from "@/config/swal";
|
||||
import { getOnlyDate } from "@/utils/globals";
|
||||
import {
|
||||
getMonthlyPlanList,
|
||||
savePlanning,
|
||||
} from "@/service/agenda-setting/agenda-setting";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import dayjs from "dayjs";
|
||||
import { getPlanningById } from "@/service/planning/planning";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
const FormSchema = z.object({
|
||||
week: z.object({
|
||||
from: z.date({
|
||||
required_error: "Start date (from) is required",
|
||||
}),
|
||||
to: z.date({
|
||||
required_error: "End date (to) is required",
|
||||
}),
|
||||
}),
|
||||
title: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
detail: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
});
|
||||
export default function EditMonthly() {
|
||||
const id = useParams()?.id;
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const [parentId, setParentId] = useState<number | undefined>();
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
detail: "",
|
||||
},
|
||||
});
|
||||
|
||||
const editor = useRef(null);
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
if (form.getValues("detail") == "") {
|
||||
form.setError("detail", {
|
||||
type: "manual",
|
||||
message: "Required",
|
||||
});
|
||||
} else {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
const reqData = {
|
||||
id: id,
|
||||
planningTypeId: 1,
|
||||
title: data.title,
|
||||
time: "2",
|
||||
description: data.detail,
|
||||
username: "",
|
||||
date: `${getOnlyDate(data.week.from)} - ${getOnlyDate(data.week.to)}`,
|
||||
status: "Open",
|
||||
parentId: parentId,
|
||||
};
|
||||
console.log("req", reqData);
|
||||
const response = await savePlanning(reqData);
|
||||
close();
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push("/curator/task-plan/mediahub");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function getPlanningData() {
|
||||
if (id != undefined) {
|
||||
loading();
|
||||
const res = await getPlanningById(id);
|
||||
close();
|
||||
if (res?.data?.data != undefined) {
|
||||
const data = res?.data?.data;
|
||||
console.log("Data :", data);
|
||||
form.setValue("title", data?.title);
|
||||
form.setValue("week", {
|
||||
from: new Date(data?.startDate),
|
||||
to: new Date(data?.endDate),
|
||||
});
|
||||
form.setValue("detail", data.description);
|
||||
setParentId(data?.parentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getPlanningData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col bg-white gap-2 p-6">
|
||||
<p className="text-lg">Perencanaan MediaHub Mingguan</p>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Judul Perencanaan</FormLabel>
|
||||
<Input
|
||||
value={field.value}
|
||||
placeholder="Masukkan Judul Perencanaan"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="week"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Pilih Tanggal</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{field.value?.from ? (
|
||||
field.value.to ? (
|
||||
<>
|
||||
{format(field.value.from, "LLL dd, y")} -{" "}
|
||||
{format(field.value.to, "LLL dd, y")}
|
||||
</>
|
||||
) : (
|
||||
format(field.value.from, "LLL dd, y")
|
||||
)
|
||||
) : (
|
||||
<span>Masukkan Tanggal</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar
|
||||
mode="range"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Detail Perencanaan</FormLabel>
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={field.value}
|
||||
className="dark:text-black"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 justify-end mt-4 pt-4">
|
||||
<Button
|
||||
onClick={() => router.back()}
|
||||
variant="outline"
|
||||
color="destructive"
|
||||
type="button"
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,292 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { format } from "date-fns";
|
||||
import JoditEditor from "jodit-react";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { error } from "@/config/swal";
|
||||
import { getOnlyDate } from "@/utils/globals";
|
||||
import {
|
||||
getMonthlyPlanList,
|
||||
savePlanning,
|
||||
} from "@/service/agenda-setting/agenda-setting";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
|
||||
const FormSchema = z.object({
|
||||
week: z.object({
|
||||
from: z.date({
|
||||
required_error: "Start date (from) is required",
|
||||
}),
|
||||
to: z.date({
|
||||
required_error: "End date (to) is required",
|
||||
}),
|
||||
}),
|
||||
title: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
detail: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
parentId: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
});
|
||||
export default function CreateMonthly() {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
detail: "",
|
||||
},
|
||||
});
|
||||
const [monthlyList, setMonthlyList] = useState<any>();
|
||||
|
||||
const editor = useRef(null);
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
if (form.getValues("detail") == "") {
|
||||
form.setError("detail", {
|
||||
type: "manual",
|
||||
message: "Required",
|
||||
});
|
||||
} else {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
const reqData = {
|
||||
planningTypeId: 2,
|
||||
title: data.title,
|
||||
time: "2",
|
||||
description: data.detail,
|
||||
username: "",
|
||||
date: `${getOnlyDate(data.week.from)} - ${getOnlyDate(data.week.to)}`,
|
||||
status: "Open",
|
||||
parentId: Number(data.parentId),
|
||||
};
|
||||
console.log("req", reqData);
|
||||
const response = await savePlanning(reqData);
|
||||
close();
|
||||
if (response.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push("/curator/task-plan/medsos-mediahub");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getMonthlyPlanning();
|
||||
}, []);
|
||||
|
||||
async function getMonthlyPlanning() {
|
||||
const res = await getMonthlyPlanList(new Date().getDate(), 2);
|
||||
|
||||
if (res.data !== null) {
|
||||
const rawUser = res.data?.data;
|
||||
const optionArr = rawUser.map((option: any) => ({
|
||||
id: option.id,
|
||||
label: option.title,
|
||||
value: String(option.id),
|
||||
}));
|
||||
console.log("ssss", optionArr);
|
||||
setMonthlyList(optionArr);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-row justify-center gap-5 mt-10">
|
||||
<Link
|
||||
href="/curator/task-plan/medsos-mediahub/create-monthly"
|
||||
className="bg-slate-200 text-black rounded-full px-5 py-2 text-sm"
|
||||
>
|
||||
Bulanan
|
||||
</Link>
|
||||
<div className="bg-primary rounded-full px-5 py-2 text-white text-sm">
|
||||
Mingguan
|
||||
</div>
|
||||
|
||||
<Link
|
||||
href="/curator/task-plan/medsos-mediahub/create-daily"
|
||||
className="bg-slate-200 text-black rounded-full px-5 py-2 text-sm"
|
||||
>
|
||||
Harian
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex flex-col bg-white gap-2 p-6">
|
||||
<p className="text-lg">Perencanaan MediaHub Mingguan</p>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Judul Perencanaan</FormLabel>
|
||||
<Input
|
||||
value={field.value}
|
||||
placeholder="Masukkan Judul Perencanaan"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="week"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Pilih Tanggal</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{field.value?.from ? (
|
||||
field.value.to ? (
|
||||
<>
|
||||
{format(field.value.from, "LLL dd, y")} -{" "}
|
||||
{format(field.value.to, "LLL dd, y")}
|
||||
</>
|
||||
) : (
|
||||
format(field.value.from, "LLL dd, y")
|
||||
)
|
||||
) : (
|
||||
<span>Masukkan Tanggal</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar
|
||||
mode="range"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="parentId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Perencanaan Bulanan</FormLabel>
|
||||
<Select value={field.value} onValueChange={field.onChange}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{monthlyList?.map((list: any) => (
|
||||
<SelectItem key={list.id} value={list.value}>
|
||||
{list.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="detail"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Detail Perencanaan</FormLabel>
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={field.value}
|
||||
className="dark:text-black"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 justify-end mt-4 pt-4">
|
||||
<Button type="submit" variant="outline" color="destructive">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,270 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import { close, loading } from "@/config/swal";
|
||||
import { getWeeklyPlanList } from "@/service/agenda-setting/agenda-setting";
|
||||
import { getPlanningById } from "@/service/planning/planning";
|
||||
import { useParams } from "next/navigation";
|
||||
import dayjs from "dayjs";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import JoditEditor from "jodit-react";
|
||||
|
||||
export default function DetailTaskPlanMediahub() {
|
||||
const params = useParams();
|
||||
const id = params?.id;
|
||||
const editor = useRef(null);
|
||||
|
||||
const [planningData, setPlanningData] = useState<any>();
|
||||
|
||||
const [type, setType] = useState("");
|
||||
|
||||
const [weeklyList, setWeeklyList] = useState<any>([]);
|
||||
const [weeklySelected, setWeeklySelected] = useState();
|
||||
|
||||
const [taskOutput, setTaskOutput] = useState<any>([]);
|
||||
const [destination, setDestination] = useState<any>([]);
|
||||
const [listDest, setListDest] = useState([]);
|
||||
const [topDestination, setTopDestination] = useState<any>([]);
|
||||
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
}, [id]);
|
||||
|
||||
async function initFetch() {
|
||||
if (id != undefined) {
|
||||
loading();
|
||||
const res = await getPlanningById(id);
|
||||
close();
|
||||
|
||||
if (res?.data?.data != undefined) {
|
||||
const data = res?.data?.data;
|
||||
console.log("Data :", data);
|
||||
setPlanningData(data);
|
||||
setAssignedTopLevel(data?.assignedToTopLevel);
|
||||
setArrayDestination(data?.assignedToLevel);
|
||||
setArrayTaskOutput(data?.fileTypeOutput);
|
||||
setType(String(data?.assignmentTypeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setArrayDestination(assignedToLevel: any) {
|
||||
if (assignedToLevel?.length > 0) {
|
||||
const arrayDestination = [];
|
||||
const arrayDest = assignedToLevel.split(",");
|
||||
|
||||
for (const element of arrayDest) {
|
||||
arrayDestination.push(element);
|
||||
}
|
||||
|
||||
setDestination(arrayDestination);
|
||||
}
|
||||
}
|
||||
|
||||
function setAssignedTopLevel(assignedToTopLevel: any) {
|
||||
if (assignedToTopLevel?.length > 0) {
|
||||
const arrayTopLevel = [];
|
||||
const arrayTop = assignedToTopLevel.split(",");
|
||||
|
||||
for (const element of arrayTop) {
|
||||
arrayTopLevel.push(Number(element));
|
||||
}
|
||||
|
||||
setTopDestination(arrayTopLevel);
|
||||
}
|
||||
}
|
||||
|
||||
function setArrayTaskOutput(output: any) {
|
||||
if (output?.length > 0) {
|
||||
const arrayOutput = [];
|
||||
const arrOutput = output.split(",");
|
||||
|
||||
for (const element of arrOutput) {
|
||||
arrayOutput.push(Number(element));
|
||||
}
|
||||
|
||||
setTaskOutput(arrayOutput);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getWeeklyPlanning();
|
||||
}, [planningData]);
|
||||
|
||||
async function getWeeklyPlanning() {
|
||||
const TODAY = dayjs().format("YYYY-MM-DD");
|
||||
const res = await getWeeklyPlanList(planningData?.date || TODAY, 1);
|
||||
|
||||
if (res.data !== null) {
|
||||
const rawUser = res.data?.data;
|
||||
const optionArr = rawUser.map((option: any) => ({
|
||||
id: option.id,
|
||||
label: option.title,
|
||||
value: option.id,
|
||||
}));
|
||||
console.log("res", optionArr);
|
||||
|
||||
setWeeklyList(optionArr);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<SiteBreadcrumb />
|
||||
<div className="text-black flex flex-col gap-4">
|
||||
<p className="text-lg">Perencanaan Mediahub</p>
|
||||
<p className="text-sm">Judul Perencanaan</p>
|
||||
<Input value={planningData?.title} readOnly />
|
||||
<p className="text-sm">Output Tugas</p>
|
||||
<div className="flex flex-row gap-3">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={taskOutput ? taskOutput.length == 4 : false}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Semua
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={taskOutput ? taskOutput.includes(2) : false}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Audio Visual
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={taskOutput ? taskOutput.includes(4) : false}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Audio
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={taskOutput ? taskOutput.includes(1) : false}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Foto
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={taskOutput ? taskOutput.includes(3) : false}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Text
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-sm">Pelaksana Tugas</p>
|
||||
<div className="flex flex-row gap-3">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={topDestination ? topDestination.includes(0) : false}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Semua Unit
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={topDestination ? topDestination.includes(1) : false}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Mabes Polri
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={topDestination ? topDestination.includes(2) : false}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Polda
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="all"
|
||||
checked={topDestination ? topDestination.includes(3) : false}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Polres
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-sm">Jenis Penugasan</p>
|
||||
<RadioGroup className="flex flex-row" disabled>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="1" id="1" checked={type === "1"} />
|
||||
<Label htmlFor="1">Publikasi {type}</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="2" id="2" checked={type === "2"} />
|
||||
<Label htmlFor="2">Amplifikasi</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="3" id="3" checked={type === "3"} />
|
||||
<Label htmlFor="3">Kontra</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
<p className="text-sm">Tanggal</p>
|
||||
<Input value={planningData?.date} className="w-fit" readOnly />
|
||||
<p className="text-sm">Penugasan Mingguan</p>
|
||||
<Input value={weeklyList[0]?.label} readOnly />
|
||||
<JoditEditor
|
||||
ref={editor}
|
||||
value={planningData?.description}
|
||||
className="dark:text-black"
|
||||
config={{ readonly: true, toolbar: false }}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,9 +1,41 @@
|
|||
"use client";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import ListViewSocialMediaTable from "@/components/table/task-plan/list-view-social-media-table";
|
||||
import SingleViewSocialMediaTable from "@/components/table/task-plan/single-view-social-media-table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useRouter } from "@/i18n/routing";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function TaskPlanMedsosMediaHub() {
|
||||
export default function TaskPlanSocialMediaMediaHub() {
|
||||
const router = useRouter();
|
||||
const [view, setView] = useState("single");
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<SiteBreadcrumb />
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex justify-between">
|
||||
<Button
|
||||
onClick={() =>
|
||||
view === "single" ? setView("list") : setView("single")
|
||||
}
|
||||
>
|
||||
{view == "single" ? "List" : "Single"} View
|
||||
</Button>
|
||||
<Button
|
||||
color="primary"
|
||||
onClick={() =>
|
||||
router.push("/curator/task-plan/medsos-mediahub/create-monthly")
|
||||
}
|
||||
>
|
||||
Buat Perencaan
|
||||
</Button>
|
||||
</div>
|
||||
{view == "single" ? (
|
||||
<SingleViewSocialMediaTable />
|
||||
) : (
|
||||
<ListViewSocialMediaTable />
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,10 +49,25 @@ const DetailAudio = () => {
|
|||
<BarWave color="#ffc831" width="60px" height="25px" duration="2s" />
|
||||
<div className="absolute top-4 left-4"></div>
|
||||
</div>
|
||||
{/* Footer Informasi */}
|
||||
<div className="p-4 text-sm text-gray-500 flex justify-between items-center border-t mt-4">
|
||||
<p className="flex flex-row items-center">
|
||||
oleh <span className="font-semibold text-black">{detailDataAudio?.uploadedBy?.userLevel?.name}</span> | Diupdate pada {detailDataAudio?.updatedAt} WIB |
|
||||
<Icon icon="formkit:eye" width="15" height="15" />
|
||||
|
||||
{detailDataAudio?.clickCount}
|
||||
</p>
|
||||
<p>Kreator: {detailDataAudio?.creatorName}</p>
|
||||
</div>
|
||||
{/* Keterangan */}
|
||||
<div className="md:w-3/4">
|
||||
<h1 className="flex flex-row font-bold text-2xl mx-5 my-8">{detailDataAudio?.title}</h1>
|
||||
<div className="font-light text-justify" dangerouslySetInnerHTML={{ __html: detailDataAudio?.htmlDescription }} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bagian Kanan */}
|
||||
<div className="md:w-1/4 p-4 bg-gray-300 rounded-lg mx-4">
|
||||
<div className="md:w-1/4 p-4 h-fit bg-gray-300 rounded-lg mx-4">
|
||||
<div className="flex flex-col mb-3 items-center justify-center cursor-pointer">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="2.5em" height="2.5em" viewBox="0 0 24 24">
|
||||
<path fill="black" d="m17 18l-5-2.18L7 18V5h10m0-2H7a2 2 0 0 0-2 2v16l7-3l7 3V5a2 2 0 0 0-2-2" />
|
||||
|
|
@ -106,24 +121,8 @@ const DetailAudio = () => {
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer Informasi */}
|
||||
<div className="p-4 text-sm text-gray-500 flex justify-between items-center border-t mt-4">
|
||||
<p className="flex flex-row items-center">
|
||||
oleh <span className="font-semibold text-black">{detailDataAudio?.uploadedBy?.userLevel?.name}</span> | Diupdate pada {detailDataAudio?.updatedAt} WIB |
|
||||
<Icon icon="formkit:eye" width="15" height="15" />
|
||||
|
||||
{detailDataAudio?.clickCount}
|
||||
</p>
|
||||
<p>Kreator: {detailDataAudio?.creatorName}</p>
|
||||
</div>
|
||||
|
||||
{/* Keterangan */}
|
||||
<div className="md:w-3/4">
|
||||
<h1 className="flex flex-row font-bold text-2xl mx-5 my-8">{detailDataAudio?.title}</h1>
|
||||
<div dangerouslySetInnerHTML={{ __html: detailDataAudio?.htmlDescription }} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full mb-8">
|
||||
{/* Comment */}
|
||||
<div className="flex flex-col my-16 gap-5 p-10 bg-gray-300">
|
||||
|
|
|
|||
|
|
@ -4,11 +4,9 @@ import { useParams, usePathname, useRouter } from "next/navigation";
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { getDetail } from "@/service/landing/landing";
|
||||
import VideoPlayer from "@/utils/video-player";
|
||||
import NewContent from "@/components/landing-page/new-content";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { BarWave } from "react-cssfx-loading";
|
||||
|
||||
const DetailDocument = () => {
|
||||
const [selectedSize, setSelectedSize] = useState<string>("L");
|
||||
|
|
@ -49,19 +47,19 @@ const DetailDocument = () => {
|
|||
<div className="absolute top-4 left-4"></div>
|
||||
</div>
|
||||
{/* Footer Informasi */}
|
||||
<div className="p-4 text-sm text-gray-500 flex justify-between items-center border-t mt-4">
|
||||
<p className="flex flex-row items-center">
|
||||
<div className="text-sm text-gray-500 flex justify-between items-center border-t mt-4">
|
||||
<p className="flex flex-row items-center mt-3">
|
||||
oleh <span className="font-semibold text-black">{detailDataDocument?.uploadedBy?.userLevel?.name}</span> | Diupdate pada {detailDataDocument?.updatedAt} WIB |
|
||||
<Icon icon="formkit:eye" width="15" height="15" />
|
||||
|
||||
{detailDataDocument?.clickCount}
|
||||
</p>
|
||||
<p>Kreator: {detailDataDocument?.creatorName}</p>
|
||||
<p className="mt-3">Kreator: {detailDataDocument?.creatorName}</p>
|
||||
</div>
|
||||
|
||||
{/* Keterangan */}
|
||||
<div className="md:w-3/4">
|
||||
<h1 className="flex flex-row font-bold text-2xl mx-5 my-8">{detailDataDocument?.title}</h1>
|
||||
<h1 className="flex flex-row font-bold text-2xl my-8">{detailDataDocument?.title}</h1>
|
||||
<div dangerouslySetInnerHTML={{ __html: detailDataDocument?.htmlDescription }} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -123,15 +121,15 @@ const DetailDocument = () => {
|
|||
<div className="w-full mb-8">
|
||||
{/* Comment */}
|
||||
<div className="flex flex-col my-16 p-10 bg-[#f7f7f7]">
|
||||
<div className="gap-5 flex flex-col px-4 lg:px-20">
|
||||
<div className="gap-5 flex flex-col px-4 lg:px-16">
|
||||
<p className="flex items-start text-lg">Berikan Komentar</p>
|
||||
<Textarea placeholder="Type your comments here." className="flex w-full" />
|
||||
<button className="flex items-start bg-[#bb3523] rounded-lg w-fit px-4 py-1">Kirim</button>
|
||||
<button className="flex items-start bg-[#bb3523] rounded-lg text-white w-fit px-4 py-1">Kirim</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Konten Serupa */}
|
||||
<div className="px-4">
|
||||
<div className="">
|
||||
<NewContent type={"similar"} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
"use client";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from "@/components/ui/pagination";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { getListContent } from "@/service/landing/landing";
|
||||
import { formatDateToIndonesian } from "@/utils/globals";
|
||||
import { useParams, usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { ColumnDef, ColumnFiltersState, PaginationState, SortingState, VisibilityState, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
|
||||
import { formatDateToIndonesian, getOnlyDate, getOnlyMonthAndYear } from "@/utils/globals";
|
||||
import { useParams, usePathname, useSearchParams } from "next/navigation";
|
||||
import { getListContent, getUserLevelListByParent, listCategory, listData, listDataRegional } from "@/service/landing/landing";
|
||||
import { ColumnDef, ColumnFiltersState, PaginationState, SortingState, VisibilityState, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
|
||||
import LandingPagination from "@/components/landing-page/pagination";
|
||||
import { Reveal } from "@/components/landing-page/Reveal";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import ReactDatePicker from "react-datepicker";
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
import { close, loading } from "@/config/swal";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -19,35 +23,13 @@ const columns: ColumnDef<any>[] = [
|
|||
},
|
||||
];
|
||||
|
||||
const categories = [
|
||||
{ id: 1, title: "HUT HUMAS KE - 73" },
|
||||
{ id: 2, title: "OPERASI ZEBRA 2024" },
|
||||
{ id: 3, title: "PON XXI" },
|
||||
{ id: 4, title: "OPS LILIN NATARU 2024" },
|
||||
{ id: 5, title: "HUT HUMAS KE - 72" },
|
||||
{ id: 6, title: "OPS MANTAP PRAJA & PILKADA 2024" },
|
||||
{ id: 6, title: "OPS KETUPAT 2024" },
|
||||
{ id: 6, title: "OPS PATUH 2024" },
|
||||
{ id: 6, title: "HARI JUANG POLRI" },
|
||||
{ id: 6, title: "HUT RI KE-79" },
|
||||
{ id: 6, title: "HARI BHAYANGKARA KE-78" },
|
||||
];
|
||||
|
||||
const formatAudio = [
|
||||
{ id: 1, title: "DOC" },
|
||||
{ id: 2, title: "DOCX" },
|
||||
{ id: 3, title: "PDF" },
|
||||
{ id: 4, title: "PPT" },
|
||||
{ id: 5, title: "PPTX" },
|
||||
];
|
||||
|
||||
const DocumentPage = () => {
|
||||
const FilterPage = () => {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const asPath = usePathname();
|
||||
const params = useParams();
|
||||
const searchParams = useSearchParams();
|
||||
const locale = params?.locale;
|
||||
const [imageData, setImageData] = useState<any>();
|
||||
const [documentData, setDocumentData] = useState<any>();
|
||||
const [totalData, setTotalData] = React.useState<number>(1);
|
||||
const [totalPage, setTotalPage] = React.useState<number>(1);
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
|
|
@ -56,9 +38,36 @@ const DocumentPage = () => {
|
|||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
const [pagination, setPagination] = React.useState<PaginationState>({
|
||||
pageIndex: 0,
|
||||
pageSize: 6,
|
||||
pageSize: 10,
|
||||
});
|
||||
const [page, setPage] = useState(1);
|
||||
const [totalContent, setTotalContent] = useState();
|
||||
const [change, setChange] = useState(false);
|
||||
const sortBy = searchParams?.get("sortBy");
|
||||
const title = searchParams?.get("title");
|
||||
const categorie = searchParams?.get("category");
|
||||
const group = searchParams?.get("group");
|
||||
const [, setGetTotalPage] = useState();
|
||||
let typingTimer: any;
|
||||
const doneTypingInterval = 1500;
|
||||
const [contentDocument, setContentDocument] = useState([]);
|
||||
const [categoryFilter, setCategoryFilter] = useState<any>([]);
|
||||
const [monthYearFilter, setMonthYearFilter] = useState<any>();
|
||||
const [searchTitle, setSearchTitle] = useState<string>("");
|
||||
const [sortByOpt, setSortByOpt] = useState<any>(sortBy === "popular" ? "clickCount" : "createdAt");
|
||||
const isRegional = asPath?.includes("regional");
|
||||
const isSatker = asPath?.includes("satker");
|
||||
const [formatFilter, setFormatFilter] = useState<any>([]);
|
||||
const pages = page ? page - 1 : 0;
|
||||
const [startDateString, setStartDateString] = useState<any>();
|
||||
const [endDateString, setEndDateString] = useState<any>();
|
||||
const [dateRange, setDateRange] = useState<any>([null, null]);
|
||||
const [calenderState, setCalenderState] = useState(false);
|
||||
const [handleClose, setHandleClose] = useState(false);
|
||||
const [categories, setCategories] = useState([]);
|
||||
const [userLevels, setUserLevels] = useState([]);
|
||||
|
||||
// const [startDate, endDate] = dateRange;
|
||||
|
||||
React.useEffect(() => {
|
||||
const pageFromUrl = searchParams?.get("page");
|
||||
|
|
@ -67,8 +76,191 @@ const DocumentPage = () => {
|
|||
}
|
||||
}, [searchParams]);
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
getCategories();
|
||||
// getSelectedCategory();
|
||||
if (isSatker) {
|
||||
getUserLevels();
|
||||
}
|
||||
}
|
||||
|
||||
initState();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (categorie) {
|
||||
setCategoryFilter(categorie?.split("&")?.length > 1 ? categorie?.split("&") : [categorie]);
|
||||
console.log("Kategori", categorie, categorie?.split("&")?.length > 1 ? categorie?.split("&") : [categorie]);
|
||||
}
|
||||
}, [categorie]);
|
||||
|
||||
// useEffect(() => {
|
||||
// fetchData();
|
||||
// }, [page, sortBy, sortByOpt, title]);
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
if (isRegional) {
|
||||
getDataRegional();
|
||||
} else {
|
||||
getDataAll();
|
||||
}
|
||||
}
|
||||
console.log(monthYearFilter, "monthFilter");
|
||||
initState();
|
||||
}, [change, asPath, monthYearFilter, page, sortBy, sortByOpt, title, startDateString, endDateString, categorie, formatFilter]);
|
||||
|
||||
async function getCategories() {
|
||||
const category = await listCategory("3");
|
||||
const resCategory = category?.data?.data?.content;
|
||||
setCategories(resCategory);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
function initState() {
|
||||
if (dateRange[0] != null && dateRange[1] != null) {
|
||||
setStartDateString(getOnlyDate(dateRange[0]));
|
||||
setEndDateString(getOnlyDate(dateRange[1]));
|
||||
setHandleClose(true);
|
||||
console.log("date range", dateRange, getOnlyDate(dateRange[0]));
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [calenderState]);
|
||||
|
||||
async function getDataAll() {
|
||||
if (asPath?.includes("/polda/") == true) {
|
||||
if (asPath?.split("/")[2] !== "[polda_name]") {
|
||||
const filter = categoryFilter?.length > 0 ? categoryFilter?.sort().join(",") : categorie || "";
|
||||
|
||||
const name = title == undefined ? "" : title;
|
||||
const format = formatFilter == undefined ? "" : formatFilter?.join(",");
|
||||
const filterGroup = group == undefined ? asPath.split("/")[2] : group;
|
||||
loading();
|
||||
const response = await listData(
|
||||
"3",
|
||||
name,
|
||||
filter,
|
||||
12,
|
||||
pages,
|
||||
sortByOpt,
|
||||
format,
|
||||
"",
|
||||
filterGroup,
|
||||
startDateString,
|
||||
endDateString,
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[0]?.replace("", "") : "",
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[1] : ""
|
||||
);
|
||||
close();
|
||||
// setGetTotalPage(response.data?.data?.totalPages);
|
||||
// setContentImage(response.data?.data?.content);
|
||||
// setTotalContent(response.data?.data?.totalElements);
|
||||
const data = response.data?.data;
|
||||
const contentData = data?.content;
|
||||
setDocumentData(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 == undefined ? "" : title;
|
||||
const format = formatFilter == undefined ? "" : formatFilter?.join(",");
|
||||
loading();
|
||||
const response = await listData(
|
||||
"3",
|
||||
name,
|
||||
filter,
|
||||
12,
|
||||
pages,
|
||||
sortByOpt,
|
||||
format,
|
||||
"",
|
||||
"",
|
||||
startDateString,
|
||||
endDateString,
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[0]?.replace("", "") : "",
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[1] : ""
|
||||
);
|
||||
close();
|
||||
// setGetTotalPage(response.data?.data?.totalPages);
|
||||
// setContentImage(response.data?.data?.content);
|
||||
// setTotalContent(response.data?.data?.totalElements);
|
||||
const data = response.data?.data;
|
||||
const contentData = data?.content;
|
||||
setDocumentData(contentData);
|
||||
setTotalData(data?.totalElements);
|
||||
setTotalPage(data?.totalPages);
|
||||
setTotalContent(response.data?.data?.totalElements);
|
||||
}
|
||||
}
|
||||
|
||||
const handleCategoryFilter = (e: boolean, id: string) => {
|
||||
let filter = [...categoryFilter];
|
||||
|
||||
if (e) {
|
||||
filter = [...categoryFilter, String(id)];
|
||||
} else {
|
||||
filter.splice(categoryFilter.indexOf(id), 1);
|
||||
}
|
||||
console.log("checkbox filter", filter);
|
||||
setCategoryFilter(filter);
|
||||
router.push(`?category=${filter.join("&")}`);
|
||||
};
|
||||
|
||||
const handleFormatFilter = (e: boolean, id: string) => {
|
||||
let filter = [...formatFilter];
|
||||
|
||||
if (e) {
|
||||
filter = [...formatFilter, id];
|
||||
} else {
|
||||
filter.splice(formatFilter.indexOf(id), 1);
|
||||
}
|
||||
console.log("Format filter", filter);
|
||||
setFormatFilter(filter);
|
||||
};
|
||||
|
||||
const cleanCheckbox = () => {
|
||||
setCategoryFilter([]);
|
||||
setFormatFilter([]);
|
||||
router.push(`?category=&title=`);
|
||||
setDateRange([null, null]);
|
||||
setMonthYearFilter(null);
|
||||
setChange(!change);
|
||||
};
|
||||
|
||||
async function getDataRegional() {
|
||||
const filter = categoryFilter?.length > 0 ? categoryFilter?.sort().join(",") : categorie || "";
|
||||
|
||||
const name = title == undefined ? "" : title;
|
||||
const format = formatFilter == undefined ? "" : formatFilter?.join(",");
|
||||
loading();
|
||||
const response = await listDataRegional(
|
||||
"3",
|
||||
name,
|
||||
filter,
|
||||
format,
|
||||
"",
|
||||
startDateString,
|
||||
endDateString,
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[0]?.replace("", "") : "",
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[1] : "",
|
||||
12,
|
||||
pages,
|
||||
sortByOpt
|
||||
);
|
||||
close();
|
||||
|
||||
setGetTotalPage(response.data?.data?.totalPages);
|
||||
setContentDocument(response.data?.data?.content);
|
||||
setTotalContent(response.data?.data?.totalElements);
|
||||
}
|
||||
|
||||
const table = useReactTable({
|
||||
data: imageData,
|
||||
data: documentData,
|
||||
columns: columns,
|
||||
onSortingChange: setSorting,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
|
|
@ -88,10 +280,9 @@ const DocumentPage = () => {
|
|||
},
|
||||
});
|
||||
|
||||
const [documentData, setDocumentData] = useState<any>();
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
}, []);
|
||||
}, [page]);
|
||||
const initFetch = async () => {
|
||||
const response = await getListContent({ page: page - 1, size: 6, sortBy: "createdAt", contentTypeId: "3" });
|
||||
console.log(response);
|
||||
|
|
@ -102,81 +293,199 @@ const DocumentPage = () => {
|
|||
setTotalData(data?.totalElements);
|
||||
setTotalPage(data?.totalPages);
|
||||
};
|
||||
|
||||
function getSelectedCategory() {
|
||||
const filter = [];
|
||||
|
||||
if (categorie) {
|
||||
const categoryArr = categorie.split(",");
|
||||
|
||||
for (const element of categoryArr) {
|
||||
filter.push(Number(element));
|
||||
}
|
||||
|
||||
setCategoryFilter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeleteDate = () => {
|
||||
setDateRange([null, null]);
|
||||
setStartDateString("");
|
||||
setEndDateString("");
|
||||
setHandleClose(false);
|
||||
};
|
||||
|
||||
const handleSorting = (e: any) => {
|
||||
console.log(e.target.value);
|
||||
if (e.target.value == "terbaru") {
|
||||
setSortByOpt("createdAt");
|
||||
} else {
|
||||
setSortByOpt("clickCount");
|
||||
}
|
||||
|
||||
setChange(!change);
|
||||
};
|
||||
|
||||
async function getUserLevels() {
|
||||
const res = await getUserLevelListByParent(761);
|
||||
const userLevelList = res?.data?.data;
|
||||
|
||||
if (userLevelList !== null) {
|
||||
let optionArr: any = [];
|
||||
|
||||
userLevelList?.map((option: any) => {
|
||||
let optionData = {
|
||||
id: option.id,
|
||||
label: option.name,
|
||||
value: option.id,
|
||||
};
|
||||
|
||||
optionArr.push(optionData);
|
||||
});
|
||||
|
||||
setUserLevels(optionArr);
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyUp = () => {
|
||||
clearTimeout(typingTimer);
|
||||
typingTimer = setTimeout(doneTyping, doneTypingInterval);
|
||||
};
|
||||
|
||||
async function doneTyping() {
|
||||
if (searchTitle == "" || searchTitle == undefined) {
|
||||
router.push("?title=");
|
||||
} else {
|
||||
router.push(`?title=${searchTitle}`);
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyDown = () => {
|
||||
clearTimeout(typingTimer);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
{/* Header */}
|
||||
|
||||
<div className="flex flex-col md:flex-row items-start gap-5 p-10 bg-[#f7f7f7] dark:bg-black">
|
||||
<p>
|
||||
{" "}
|
||||
Teks {">"} <span className="font-bold">Semua Teks</span>
|
||||
</p>
|
||||
<p className="font-bold">|</p>
|
||||
<p>Terdapat 32499 artikel berisi Teks yang dapat diunduh </p>
|
||||
<p>{`Terdapat ${totalContent} artikel berisi Teks yang dapat diunduh`}</p>
|
||||
</div>
|
||||
|
||||
{/* Left */}
|
||||
<div className="flex flex-col lg:flex-row gap-6 p-4">
|
||||
{/* Sidebar Kiri */}
|
||||
<div className="lg:w-1/4 w-full bg-[#f7f7f7] dark:bg-black p-4 rounded-lg shadow-md">
|
||||
<h2 className="text-xl font-semibold mb-4 flex items-center gap-1">
|
||||
<div className="lg:w-[40%] w-full bg-[#f7f7f7] dark:bg-black p-4 rounded-lg shadow-md">
|
||||
<h2 className="text-lg font-semibold mb-4 flex items-center gap-1">
|
||||
<Icon icon="stash:filter-light" fontSize={30} />
|
||||
Filter
|
||||
</h2>
|
||||
<div className="border-t border-black dark:border-white my-4"></div>
|
||||
<div className="border-t border-black my-4 dark:border-white"></div>
|
||||
<div className="space-y-6">
|
||||
{/* Pencarian */}
|
||||
<div>
|
||||
<label htmlFor="search" className="block text-sm font-medium text-gray-700 dark:text-white">
|
||||
Pencarian
|
||||
</label>
|
||||
<input type="text" id="search" placeholder="Cari judul..." className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" />
|
||||
<Input
|
||||
value={searchTitle}
|
||||
onChange={(e) => setSearchTitle(e.target.value)}
|
||||
onKeyUp={handleKeyUp}
|
||||
onKeyDown={handleKeyDown}
|
||||
type="text"
|
||||
id="search"
|
||||
placeholder="Cari judul..."
|
||||
className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
|
||||
/>
|
||||
</div>
|
||||
{/* Tahun & Bulan */}
|
||||
|
||||
<div>
|
||||
<label htmlFor="month" className="block text-sm font-medium text-gray-700 dark:text-white">
|
||||
Pilih Tahun & Bulan
|
||||
</label>
|
||||
<input type="month" id="month" className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" />
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white">Tahun & Bulan</label>
|
||||
<ReactDatePicker
|
||||
selected={monthYearFilter}
|
||||
className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
|
||||
onChange={(date) => setMonthYearFilter(date)}
|
||||
dateFormat="MM | yyyy"
|
||||
placeholderText="Pilih Tahun dan Bulan"
|
||||
showMonthYearPicker
|
||||
/>
|
||||
</div>
|
||||
{/* Tanggal */}
|
||||
|
||||
<div>
|
||||
<label htmlFor="date" className="block text-sm font-medium text-gray-700 dark:text-white">
|
||||
Pilih Tanggal
|
||||
</label>
|
||||
<input type="date" id="date" className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" />
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white">Tanggal</label>
|
||||
<div className="flex flex-row justify justify-between gap-2">
|
||||
<ReactDatePicker
|
||||
selectsRange
|
||||
className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
|
||||
startDate={dateRange[0]}
|
||||
endDate={dateRange[1]}
|
||||
onChange={(update) => {
|
||||
setDateRange(update);
|
||||
}}
|
||||
placeholderText="Pilih Tanggal"
|
||||
onCalendarClose={() => setCalenderState(!calenderState)}
|
||||
/>
|
||||
<div className="flex items-center">{handleClose ? <Icon icon="carbon:close-filled" onClick={handleDeleteDate} width="20" inline color="#216ba5" /> : ""}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Kategori */}
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-700 dark:text-white">Kategori</h3>
|
||||
<ul className="mt-2 space-y-2">
|
||||
{categories.map((category) => (
|
||||
{categories.map((category: any) => (
|
||||
<li key={category?.id}>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="terms" />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">{category.title}</span>
|
||||
<label className="inline-flex items-center" htmlFor={`${category.id}`}>
|
||||
<Checkbox id={`${category.id}`} value={category.id} checked={categoryFilter.includes(String(category.id))} onCheckedChange={(e) => handleCategoryFilter(Boolean(e), category.id)} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">{category?.name}</span>
|
||||
</label>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
{/* Garis */}
|
||||
<div className="border-t border-black dark:border-white my-4"></div>
|
||||
<div className="border-t border-black my-4 dark:border-white"></div>
|
||||
{/* Garis */}
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-700 dark:text-white">Format Foto</h3>
|
||||
<h3 className="text-sm font-medium text-gray-700 dark:text-white">Format Teks</h3>
|
||||
<ul className="mt-2 space-y-2">
|
||||
{formatAudio.map((format) => (
|
||||
<li key={format?.id}>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="terms" />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">{format.title}</span>
|
||||
</label>
|
||||
</li>
|
||||
))}
|
||||
<li>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="doc" value="doc" checked={formatFilter.includes("doc")} onCheckedChange={(e) => handleFormatFilter(Boolean(e), "doc")} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">DOC</span>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="docx" value="docx" checked={formatFilter.includes("docx")} onCheckedChange={(e) => handleFormatFilter(Boolean(e), "docx")} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">DOCX</span>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="pdf" value="pdf" checked={formatFilter.includes("pdf")} onCheckedChange={(e) => handleFormatFilter(Boolean(e), "pdf")} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">PDF</span>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="ppt" value="ppt" checked={formatFilter.includes("ppt")} onCheckedChange={(e) => handleFormatFilter(Boolean(e), "ppt")} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">PPT</span>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="pptx" value="pptx" checked={formatFilter.includes("pptx")} onCheckedChange={(e) => handleFormatFilter(Boolean(e), "pptx")} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">PPTX</span>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="border-t border-black dark:border-white my-4"></div>
|
||||
<div className="text-center">
|
||||
<a href="#" className="text-[#bb3523]">
|
||||
<a onClick={cleanCheckbox} className="text-[#bb3523] cursor-pointer">
|
||||
<b>Reset Filter</b>
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -184,20 +493,16 @@ const DocumentPage = () => {
|
|||
</div>
|
||||
|
||||
{/* Konten Kanan */}
|
||||
|
||||
<div className="flex-1">
|
||||
<Reveal>
|
||||
<Reveal>
|
||||
<div className="flex-1">
|
||||
<div className="flex flex-col items-end mb-4">
|
||||
<h2 className="text-lg font-semibold tetx-red-300">Urutkan berdasarkan</h2>
|
||||
<select className="border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500">
|
||||
<h2 className="text-lg font-semibold">Urutkan berdasarkan</h2>
|
||||
<select defaultValue={sortBy == "popular" ? "terpopuler" : "terbaru"} onChange={(e) => handleSorting(e)} className="border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500">
|
||||
<option value="terbaru">Terbaru</option>
|
||||
<option value="terlama">Terpopuler</option>
|
||||
<option value="terpopuler">Terpopuler</option>
|
||||
</select>
|
||||
</div>
|
||||
</Reveal>
|
||||
|
||||
{/* Card */}
|
||||
<Reveal>
|
||||
<div className=" grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{documentData?.map((document: any) => (
|
||||
<Link href={`/document/detail/${document?.slug}`} key={document?.id} className="flex flex-col bg-yellow-500 sm:flex-row items-center dark:bg-gray-800 cursor-pointer shadow-md rounded-lg p-4 gap-4 w-full">
|
||||
|
|
@ -226,11 +531,11 @@ const DocumentPage = () => {
|
|||
))}
|
||||
</div>
|
||||
<LandingPagination table={table} totalData={totalData} totalPage={totalPage} />
|
||||
</Reveal>
|
||||
</div>
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocumentPage;
|
||||
export default FilterPage;
|
||||
|
|
|
|||
|
|
@ -49,17 +49,17 @@ const DetailInfo = () => {
|
|||
</div>
|
||||
|
||||
{/* Gambar bawah Kecil */}
|
||||
<div className="p-4 grid grid-cols-4 gap-2">
|
||||
<div className="py-4 flex flex-row gap-3">
|
||||
{detailDataImage?.files?.map((file: any, index: number) => (
|
||||
<a onClick={() => setSelectedImage(index)} key={file?.id}>
|
||||
<img src={file?.url} className="w-full h-fit object-cover rounded-md cursor-pointer hover:ring-2 hover:ring-red-600" />
|
||||
<img src={file?.url} className="w-[120px] h-[90px] object-cover rounded-md cursor-pointer hover:ring-2 hover:ring-red-600" />
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Footer Informasi */}
|
||||
<div className="p-4 text-sm text-gray-500 flex justify-between items-center border-t mt-4">
|
||||
<div className="flex flex-row items-center">
|
||||
<div className="text-sm text-gray-500 flex justify-between items-center border-t mt-4">
|
||||
<div className="flex flex-row items-center mt-3 justify-between">
|
||||
oleh <span className="font-semibold text-black">{detailDataImage?.uploadedBy?.userLevel?.name}</span> | Diupdate pada {detailDataImage?.updatedAt} WIB |
|
||||
<Icon icon="formkit:eye" width="15" height="15" />
|
||||
{detailDataImage?.clickCount}
|
||||
|
|
@ -69,8 +69,8 @@ const DetailInfo = () => {
|
|||
|
||||
{/* Keterangan */}
|
||||
<div className="w-full">
|
||||
<h1 className="flex flex-row font-bold text-2xl mx-5 my-8">{detailDataImage?.title}</h1>
|
||||
<div dangerouslySetInnerHTML={{ __html: detailDataImage?.htmlDescription }} />
|
||||
<h1 className="flex flex-row font-bold text-2xl my-8">{detailDataImage?.title}</h1>
|
||||
<div className="font-light text-justify" dangerouslySetInnerHTML={{ __html: detailDataImage?.htmlDescription }} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -134,15 +134,15 @@ const DetailInfo = () => {
|
|||
<div className="w-full mb-8">
|
||||
{/* Comment */}
|
||||
<div className="flex flex-col my-16 p-10 bg-[#f7f7f7]">
|
||||
<div className="gap-5 flex flex-col px-4 lg:px-16">
|
||||
<div className="gap-5 flex flex-col px-4 lg:px-14">
|
||||
<p className="flex items-start text-lg">Berikan Komentar</p>
|
||||
<Textarea placeholder="Type your comments here." className="flex w-full" />
|
||||
<button className="flex items-start bg-[#bb3523] rounded-lg w-fit px-4 py-1">Kirim</button>
|
||||
<button className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-4 py-1">Kirim</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Konten Serupa */}
|
||||
<div className="px-4">
|
||||
<div className="">
|
||||
<NewContent type={"similar"} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,14 +3,17 @@ import React, { useEffect, useState } from "react";
|
|||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { formatDateToIndonesian } from "@/utils/globals";
|
||||
import { useParams, usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { getListContent, listCategory } from "@/service/landing/landing";
|
||||
import { ColumnDef, ColumnFiltersState, PaginationState, SortingState, VisibilityState, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
|
||||
import { formatDateToIndonesian, getOnlyDate, getOnlyMonthAndYear } from "@/utils/globals";
|
||||
import { useParams, usePathname, useSearchParams } from "next/navigation";
|
||||
import { getUserLevelListByParent, listCategory, listData, listDataRegional } from "@/service/landing/landing";
|
||||
import { ColumnDef, ColumnFiltersState, PaginationState, SortingState, VisibilityState, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
|
||||
import LandingPagination from "@/components/landing-page/pagination";
|
||||
import { Reveal } from "@/components/landing-page/Reveal";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import ReactDatePicker from "react-datepicker";
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
import { close, loading } from "@/config/swal";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -20,25 +23,6 @@ const columns: ColumnDef<any>[] = [
|
|||
},
|
||||
];
|
||||
|
||||
const categories = [
|
||||
{ id: 1, title: "HUT HUMAS KE - 73" },
|
||||
{ id: 2, title: "OPERASI ZEBRA 2024" },
|
||||
{ id: 3, title: "PON XXI" },
|
||||
{ id: 4, title: "OPS LILIN NATARU 2024" },
|
||||
{ id: 5, title: "HUT HUMAS KE - 72" },
|
||||
{ id: 6, title: "OPS MANTAP PRAJA & PILKADA 2024" },
|
||||
{ id: 7, title: "OPS KETUPAT 2024" },
|
||||
{ id: 8, title: "OPS PATUH 2024" },
|
||||
{ id: 9, title: "HARI JUANG POLRI" },
|
||||
{ id: 10, title: "HUT RI KE-79" },
|
||||
{ id: 11, title: "HARI BHAYANGKARA KE-78" },
|
||||
];
|
||||
const formatPicture = [
|
||||
{ id: 1, title: "PNG" },
|
||||
{ id: 2, title: "JPEG" },
|
||||
{ id: 3, title: "JPG" },
|
||||
];
|
||||
|
||||
const FilterPage = () => {
|
||||
const router = useRouter();
|
||||
const asPath = usePathname();
|
||||
|
|
@ -58,12 +42,33 @@ const FilterPage = () => {
|
|||
});
|
||||
const [page, setPage] = useState(1);
|
||||
const [totalContent, setTotalContent] = useState();
|
||||
const [change, setChange] = useState(false);
|
||||
const sortBy = searchParams?.get("sortBy");
|
||||
const title = searchParams?.get("title");
|
||||
const categorie = searchParams?.get("category");
|
||||
const group = searchParams?.get("group");
|
||||
const [contentImage, setContentImage] = useState([]);
|
||||
const [, setGetTotalPage] = useState();
|
||||
const [categories, setCategories] = useState<any>([]);
|
||||
let typingTimer: any;
|
||||
const doneTypingInterval = 1500;
|
||||
const [search, setSearch] = useState();
|
||||
const [categoryFilter, setCategoryFilter] = useState<any>([]);
|
||||
const [monthYearFilter, setMonthYearFilter] = useState<any>();
|
||||
const [searchTitle, setSearchTitle] = useState<string>("");
|
||||
const [sortByOpt, setSortByOpt] = useState<any>(sortBy === "popular" ? "clickCount" : "createdAt");
|
||||
const isRegional = asPath?.includes("regional");
|
||||
const isSatker = asPath?.includes("satker");
|
||||
const [formatFilter, setFormatFilter] = useState<any>([]);
|
||||
const pages = page ? page - 1 : 0;
|
||||
const [startDateString, setStartDateString] = useState<any>();
|
||||
const [endDateString, setEndDateString] = useState<any>();
|
||||
const [dateRange, setDateRange] = useState<any>([null, null]);
|
||||
const [calenderState, setCalenderState] = useState(false);
|
||||
const [handleClose, setHandleClose] = useState(false);
|
||||
const [categories, setCategories] = useState([]);
|
||||
const [userLevels, setUserLevels] = useState([]);
|
||||
|
||||
// const [startDate, endDate] = dateRange;
|
||||
|
||||
React.useEffect(() => {
|
||||
const pageFromUrl = searchParams?.get("page");
|
||||
|
|
@ -73,20 +78,188 @@ const FilterPage = () => {
|
|||
}, [searchParams]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [page]);
|
||||
async function initState() {
|
||||
getCategories();
|
||||
// getSelectedCategory();
|
||||
if (isSatker) {
|
||||
getUserLevels();
|
||||
}
|
||||
}
|
||||
|
||||
const fetchData = async () => {
|
||||
const response = await getListContent({ page: page - 1, size: 6, sortBy: "createdAt", contentTypeId: "1" });
|
||||
console.log(response);
|
||||
initState();
|
||||
}, []);
|
||||
|
||||
const data = response.data?.data;
|
||||
const contentData = data?.content;
|
||||
setImageData(contentData);
|
||||
setTotalData(data?.totalElements);
|
||||
setTotalPage(data?.totalPages);
|
||||
useEffect(() => {
|
||||
if (categorie) {
|
||||
setCategoryFilter(categorie?.split("&")?.length > 1 ? categorie?.split("&") : [categorie]);
|
||||
console.log("Kategori", categorie, categorie?.split("&")?.length > 1 ? categorie?.split("&") : [categorie]);
|
||||
}
|
||||
}, [categorie]);
|
||||
|
||||
// useEffect(() => {
|
||||
// fetchData();
|
||||
// }, [page, sortBy, sortByOpt, title]);
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
if (isRegional) {
|
||||
getDataRegional();
|
||||
} else {
|
||||
getDataAll();
|
||||
}
|
||||
}
|
||||
console.log(monthYearFilter, "monthFilter");
|
||||
initState();
|
||||
}, [change, asPath, monthYearFilter, page, sortBy, sortByOpt, title, startDateString, endDateString, categorie, formatFilter]);
|
||||
|
||||
async function getCategories() {
|
||||
const category = await listCategory("1");
|
||||
const resCategory = category?.data?.data?.content;
|
||||
setCategories(resCategory);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
function initState() {
|
||||
if (dateRange[0] != null && dateRange[1] != null) {
|
||||
setStartDateString(getOnlyDate(dateRange[0]));
|
||||
setEndDateString(getOnlyDate(dateRange[1]));
|
||||
setHandleClose(true);
|
||||
console.log("date range", dateRange, getOnlyDate(dateRange[0]));
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [calenderState]);
|
||||
|
||||
async function getDataAll() {
|
||||
if (asPath?.includes("/polda/") == true) {
|
||||
if (asPath?.split("/")[2] !== "[polda_name]") {
|
||||
const filter = categoryFilter?.length > 0 ? categoryFilter?.sort().join(",") : categorie || "";
|
||||
|
||||
const name = title == undefined ? "" : title;
|
||||
const format = formatFilter == undefined ? "" : formatFilter?.join(",");
|
||||
const filterGroup = group == undefined ? asPath.split("/")[2] : group;
|
||||
loading();
|
||||
const response = await listData(
|
||||
"1",
|
||||
name,
|
||||
filter,
|
||||
12,
|
||||
pages,
|
||||
sortByOpt,
|
||||
format,
|
||||
"",
|
||||
filterGroup,
|
||||
startDateString,
|
||||
endDateString,
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[0]?.replace("", "") : "",
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[1] : ""
|
||||
);
|
||||
close();
|
||||
// setGetTotalPage(response.data?.data?.totalPages);
|
||||
// setContentImage(response.data?.data?.content);
|
||||
// setTotalContent(response.data?.data?.totalElements);
|
||||
const data = response.data?.data;
|
||||
const contentData = data?.content;
|
||||
setImageData(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 == undefined ? "" : title;
|
||||
const format = formatFilter == undefined ? "" : formatFilter?.join(",");
|
||||
loading();
|
||||
const response = await listData(
|
||||
"1",
|
||||
name,
|
||||
filter,
|
||||
12,
|
||||
pages,
|
||||
sortByOpt,
|
||||
format,
|
||||
"",
|
||||
"",
|
||||
startDateString,
|
||||
endDateString,
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[0]?.replace("", "") : "",
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[1] : ""
|
||||
);
|
||||
close();
|
||||
// setGetTotalPage(response.data?.data?.totalPages);
|
||||
// setContentImage(response.data?.data?.content);
|
||||
// setTotalContent(response.data?.data?.totalElements);
|
||||
const data = response.data?.data;
|
||||
const contentData = data?.content;
|
||||
setImageData(contentData);
|
||||
setTotalData(data?.totalElements);
|
||||
setTotalPage(data?.totalPages);
|
||||
setTotalContent(response.data?.data?.totalElements);
|
||||
}
|
||||
}
|
||||
|
||||
const handleCategoryFilter = (e: boolean, id: string) => {
|
||||
let filter = [...categoryFilter];
|
||||
|
||||
if (e) {
|
||||
filter = [...categoryFilter, String(id)];
|
||||
} else {
|
||||
filter.splice(categoryFilter.indexOf(id), 1);
|
||||
}
|
||||
console.log("checkbox filter", filter);
|
||||
setCategoryFilter(filter);
|
||||
router.push(`?category=${filter.join("&")}`);
|
||||
};
|
||||
|
||||
const handleFormatFilter = (e: boolean, id: string) => {
|
||||
let filter = [...formatFilter];
|
||||
|
||||
if (e) {
|
||||
filter = [...formatFilter, id];
|
||||
} else {
|
||||
filter.splice(formatFilter.indexOf(id), 1);
|
||||
}
|
||||
console.log("Format filter", filter);
|
||||
setFormatFilter(filter);
|
||||
};
|
||||
|
||||
const cleanCheckbox = () => {
|
||||
setCategoryFilter([]);
|
||||
setFormatFilter([]);
|
||||
router.push(`?category=&title=`);
|
||||
setDateRange([null, null]);
|
||||
setMonthYearFilter(null);
|
||||
setChange(!change);
|
||||
};
|
||||
|
||||
async function getDataRegional() {
|
||||
const filter = categoryFilter?.length > 0 ? categoryFilter?.sort().join(",") : categorie || "";
|
||||
|
||||
const name = title == undefined ? "" : title;
|
||||
const format = formatFilter == undefined ? "" : formatFilter?.join(",");
|
||||
loading();
|
||||
const response = await listDataRegional(
|
||||
"1",
|
||||
name,
|
||||
filter,
|
||||
format,
|
||||
"",
|
||||
startDateString,
|
||||
endDateString,
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[0]?.replace("", "") : "",
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[1] : "",
|
||||
12,
|
||||
pages,
|
||||
sortByOpt
|
||||
);
|
||||
close();
|
||||
|
||||
setGetTotalPage(response.data?.data?.totalPages);
|
||||
setContentImage(response.data?.data?.content);
|
||||
setTotalContent(response.data?.data?.totalElements);
|
||||
}
|
||||
|
||||
const table = useReactTable({
|
||||
data: imageData,
|
||||
columns: columns,
|
||||
|
|
@ -108,25 +281,58 @@ const FilterPage = () => {
|
|||
},
|
||||
});
|
||||
|
||||
// async function getCategories() {
|
||||
// const category = await listCategory("1");
|
||||
// const resCategory = category?.data?.data?.content;
|
||||
// setCategories(resCategory);
|
||||
// }
|
||||
function getSelectedCategory() {
|
||||
const filter = [];
|
||||
|
||||
// function getSelectedCategory() {
|
||||
// const filter = [];
|
||||
if (categorie) {
|
||||
const categoryArr = categorie.split(",");
|
||||
|
||||
// if (category) {
|
||||
// const categoryArr = category.split(",");
|
||||
for (const element of categoryArr) {
|
||||
filter.push(Number(element));
|
||||
}
|
||||
|
||||
// for (const element of categoryArr) {
|
||||
// filter.push(Number(element));
|
||||
// }
|
||||
setCategoryFilter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
// setCategoryFilter(filter);
|
||||
// }
|
||||
// }
|
||||
const handleDeleteDate = () => {
|
||||
setDateRange([null, null]);
|
||||
setStartDateString("");
|
||||
setEndDateString("");
|
||||
setHandleClose(false);
|
||||
};
|
||||
|
||||
const handleSorting = (e: any) => {
|
||||
console.log(e.target.value);
|
||||
if (e.target.value == "terbaru") {
|
||||
setSortByOpt("createdAt");
|
||||
} else {
|
||||
setSortByOpt("clickCount");
|
||||
}
|
||||
|
||||
setChange(!change);
|
||||
};
|
||||
|
||||
async function getUserLevels() {
|
||||
const res = await getUserLevelListByParent(761);
|
||||
const userLevelList = res?.data?.data;
|
||||
|
||||
if (userLevelList !== null) {
|
||||
let optionArr: any = [];
|
||||
|
||||
userLevelList?.map((option: any) => {
|
||||
let optionData = {
|
||||
id: option.id,
|
||||
label: option.name,
|
||||
value: option.id,
|
||||
};
|
||||
|
||||
optionArr.push(optionData);
|
||||
});
|
||||
|
||||
setUserLevels(optionArr);
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyUp = () => {
|
||||
clearTimeout(typingTimer);
|
||||
|
|
@ -134,10 +340,10 @@ const FilterPage = () => {
|
|||
};
|
||||
|
||||
async function doneTyping() {
|
||||
if (search == "" || search == undefined) {
|
||||
router.push("");
|
||||
if (searchTitle == "" || searchTitle == undefined) {
|
||||
router.push("?title=");
|
||||
} else {
|
||||
router.push(`?title=${search}`);
|
||||
router.push(`?title=${searchTitle}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -155,12 +361,12 @@ const FilterPage = () => {
|
|||
Foto {">"} <span className="font-bold">Semua Foto</span>
|
||||
</p>
|
||||
<p className="font-bold">|</p>
|
||||
<p>Terdapat 324911 artikel berisi Foto yang dapat diunduh </p>
|
||||
<p>{`Terdapat ${totalContent} artikel berisi Foto yang dapat diunduh`}</p>
|
||||
</div>
|
||||
|
||||
{/* Left */}
|
||||
<div className="flex flex-col lg:flex-row gap-6 p-4">
|
||||
<div className="lg:w-1/4 w-full bg-[#f7f7f7] dark:bg-black p-4 rounded-lg shadow-md">
|
||||
<div className="lg:w-[40%] w-full bg-[#f7f7f7] dark:bg-black p-4 rounded-lg shadow-md">
|
||||
<h2 className="text-lg font-semibold mb-4 flex items-center gap-1">
|
||||
<Icon icon="stash:filter-light" fontSize={30} />
|
||||
Filter
|
||||
|
|
@ -171,21 +377,46 @@ const FilterPage = () => {
|
|||
<label htmlFor="search" className="block text-sm font-medium text-gray-700 dark:text-white">
|
||||
Pencarian
|
||||
</label>
|
||||
<Input onKeyUp={handleKeyUp} onKeyDown={handleKeyDown} type="text" id="search" placeholder="Cari judul..." className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" />
|
||||
<Input
|
||||
value={searchTitle}
|
||||
onChange={(e) => setSearchTitle(e.target.value)}
|
||||
onKeyUp={handleKeyUp}
|
||||
onKeyDown={handleKeyDown}
|
||||
type="text"
|
||||
id="search"
|
||||
placeholder="Cari judul..."
|
||||
className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="month" className="block text-sm font-medium text-gray-700 dark:text-white">
|
||||
Tahun & Bulan
|
||||
</label>
|
||||
<input type="month" id="month" className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" />
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white">Tahun & Bulan</label>
|
||||
<ReactDatePicker
|
||||
selected={monthYearFilter}
|
||||
className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
|
||||
onChange={(date) => setMonthYearFilter(date)}
|
||||
dateFormat="MM | yyyy"
|
||||
placeholderText="Pilih Tahun dan Bulan"
|
||||
showMonthYearPicker
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="date" className="block text-sm font-medium text-gray-700 dark:text-white">
|
||||
Tanggal
|
||||
</label>
|
||||
<input type="date" id="date" className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" />
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white">Tanggal</label>
|
||||
<div className="flex flex-row justify justify-between gap-2">
|
||||
<ReactDatePicker
|
||||
selectsRange
|
||||
className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
|
||||
startDate={dateRange[0]}
|
||||
endDate={dateRange[1]}
|
||||
onChange={(update) => {
|
||||
setDateRange(update);
|
||||
}}
|
||||
placeholderText="Pilih Tanggal"
|
||||
onCalendarClose={() => setCalenderState(!calenderState)}
|
||||
/>
|
||||
<div className="flex items-center">{handleClose ? <Icon icon="carbon:close-filled" onClick={handleDeleteDate} width="20" inline color="#216ba5" /> : ""}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
@ -193,9 +424,9 @@ const FilterPage = () => {
|
|||
<ul className="mt-2 space-y-2">
|
||||
{categories.map((category: any) => (
|
||||
<li key={category?.id}>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="terms" />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">{category?.title}</span>
|
||||
<label className="inline-flex items-center" htmlFor={`${category.id}`}>
|
||||
<Checkbox id={`${category.id}`} value={category.id} checked={categoryFilter.includes(String(category.id))} onCheckedChange={(e) => handleCategoryFilter(Boolean(e), category.id)} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">{category?.name}</span>
|
||||
</label>
|
||||
</li>
|
||||
))}
|
||||
|
|
@ -207,19 +438,29 @@ const FilterPage = () => {
|
|||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-700 dark:text-white">Format Foto</h3>
|
||||
<ul className="mt-2 space-y-2">
|
||||
{formatPicture.map((format) => (
|
||||
<li key={format?.id}>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="terms" />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">{format.title}</span>
|
||||
</label>
|
||||
</li>
|
||||
))}
|
||||
<li>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="png" value="png" checked={formatFilter.includes("png")} onCheckedChange={(e) => handleFormatFilter(Boolean(e), "png")} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">PNG</span>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="jpeg" value="jpeg" checked={formatFilter.includes("jpeg")} onCheckedChange={(e) => handleFormatFilter(Boolean(e), "jpeg")} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">JPEG</span>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="jpg" value="jpg" checked={formatFilter.includes("jpg")} onCheckedChange={(e) => handleFormatFilter(Boolean(e), "jpg")} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">JPG</span>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="border-t border-black dark:border-white my-4"></div>
|
||||
<div className="text-center">
|
||||
<a href="#" className="text-[#bb3523]">
|
||||
<a onClick={cleanCheckbox} className="text-[#bb3523] cursor-pointer">
|
||||
<b>Reset Filter</b>
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -231,9 +472,9 @@ const FilterPage = () => {
|
|||
<div className="flex-1">
|
||||
<div className="flex flex-col items-end mb-4">
|
||||
<h2 className="text-lg font-semibold">Urutkan berdasarkan</h2>
|
||||
<select className="border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500">
|
||||
<select defaultValue={sortBy == "popular" ? "terpopuler" : "terbaru"} onChange={(e) => handleSorting(e)} className="border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500">
|
||||
<option value="terbaru">Terbaru</option>
|
||||
<option value="terlama">Terlama</option>
|
||||
<option value="terpopuler">Terpopuler</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,69 +2,91 @@
|
|||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { useParams, usePathname, useRouter } from "next/navigation";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import NewContent from "@/components/landing-page/new-content";
|
||||
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/components/ui/carousel";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { getDetailIndeks } from "@/service/landing/landing";
|
||||
import { getDetailIndeks, publicDetailBlog } from "@/service/landing/landing";
|
||||
import { formatDateToIndonesian } from "@/utils/globals";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
|
||||
const IndeksDetail = () => {
|
||||
const [indeksData, setIndeksData] = useState<any>();
|
||||
const params = useParams();
|
||||
const slug = params?.slug;
|
||||
const [relatedPost, setRelatedPost] = useState<any>();
|
||||
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
detailFetch();
|
||||
}, []);
|
||||
const initFetch = async () => {
|
||||
const response = await getDetailIndeks();
|
||||
console.log(response);
|
||||
setIndeksData(response?.data?.data?.content);
|
||||
setRelatedPost(response?.data?.data?.content);
|
||||
};
|
||||
const detailFetch = async () => {
|
||||
const response = await publicDetailBlog(slug);
|
||||
console.log(response);
|
||||
setIndeksData(response?.data?.data);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="p-4 lg:px-60 lg:p-12">
|
||||
{/* Judul */}
|
||||
<div className="flex justify-center mb-5">
|
||||
<div className="flex flex-col mb-5">
|
||||
<h1 className="text-lg mb-2">Indeks / Detail</h1>
|
||||
<h1 className="flex flex-row font-bold text-center text-2xl">{indeksData?.title}</h1>
|
||||
</div>
|
||||
{/* Gambar Utama */}
|
||||
<div className="flex items-center justify-center">
|
||||
<img src={indeksData?.thumbnailLink} alt="Main" className="h-[500px] w-full rounded-lg" />
|
||||
<img src={indeksData?.thumbnailLink} alt="Main" className="h-[550px] w-full rounded-lg" />
|
||||
</div>
|
||||
{/* Footer Informasi */}
|
||||
<div className="p-4 text-sm text-gray-500 flex justify-between items-center border-t mt-4">
|
||||
<p className="items-end">
|
||||
{formatDateToIndonesian(new Date(indeksData?.createdAt))} {indeksData?.timezone ? indeksData?.timezone : "WIB"}|{" "}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 24 24">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M11.5 18c4 0 7.46-2.22 9.24-5.5C18.96 9.22 15.5 7 11.5 7s-7.46 2.22-9.24 5.5C4.04 15.78 7.5 18 11.5 18m0-12c4.56 0 8.5 2.65 10.36 6.5C20 16.35 16.06 19 11.5 19S3 16.35 1.14 12.5C3 8.65 6.94 6 11.5 6m0 2C14 8 16 10 16 12.5S14 17 11.5 17S7 15 7 12.5S9 8 11.5 8m0 1A3.5 3.5 0 0 0 8 12.5a3.5 3.5 0 0 0 3.5 3.5a3.5 3.5 0 0 0 3.5-3.5A3.5 3.5 0 0 0 11.5 9"
|
||||
/>
|
||||
</svg>{" "}
|
||||
{indeksData?.clickCount}
|
||||
</p>
|
||||
<div className="text-sm text-gray-500 flex justify-between items-center border-t mt-4">
|
||||
<div className="flex flex-row items-center mt-3 justify-between">
|
||||
oleh <span className="font-semibold text-black">{indeksData?.uploaderName}</span> | Diupdate pada {indeksData?.createdAt} WIB
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Keterangan */}
|
||||
<div className="w-auto">
|
||||
<p dangerouslySetInnerHTML={{ __html: indeksData?.description }} />
|
||||
<p className="font-light text-justify" dangerouslySetInnerHTML={{ __html: indeksData?.description }} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Comment */}
|
||||
<div className="w-full">
|
||||
{/* Comment */}
|
||||
<div className="flex flex-col my-16 p-10 bg-[#f7f7f7]">
|
||||
<div className="flex flex-col py-5 p-10 bg-[#f7f7f7]">
|
||||
<div className="gap-5 flex flex-col px-4 lg:px-16">
|
||||
<p className="flex items-start text-lg">Berikan Komentar</p>
|
||||
<Textarea placeholder="Type your comments here." className="flex w-full" />
|
||||
<button className="flex items-start bg-[#bb3523] rounded-lg w-fit px-4 py-1">Kirim</button>
|
||||
<button className="flex items-start bg-[#bb3523] text-white rounded-lg w-fit px-4 py-1">Kirim</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Konten Serupa */}
|
||||
<div className="space-x-5 flex flex-col p-4">
|
||||
<NewContent type={"similar"} />
|
||||
<div className="space-x-5 flex flex-col px-4 lg:px-16 py-16 gap-5">
|
||||
<h1 className="font-bold text-base lg:text-xl px-4 lg:px-8">Post Terkait</h1>
|
||||
<Carousel>
|
||||
<CarouselContent className="w-full max-w-7xl">
|
||||
{relatedPost?.map((relate: any) => (
|
||||
<CarouselItem key={relate?.id} className="md:basis-1/2 lg:basis-1/3">
|
||||
<Link href={`/indeks/detail/${relate?.slug}`} className="relative group overflow-hidden shadow-md hover:shadow-lg">
|
||||
<img src={relate?.thumbnailLink} className="w-full rounded-lg h-40 lg:h-60 object-cover group-hover:scale-100 transition-transform duration-300" />
|
||||
<div className="absolute bottom-0 left-0 right-0 bg-gray-600 border-l-4 border-[#bb3523] rounded-lg backdrop-blur-sm text-white p-2">
|
||||
<span className="text-white bg-[#bb3523] rounded-md w-full h-full font-semibold uppercase text-sm px-4 py-1">{relate?.categoryName}</span>
|
||||
<h1 className="text-sm lg:text-lg mb-2 font-semibold h-5 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible">{relate?.title}</h1>
|
||||
<p className="flex flex-row items-center text-[10px] gap-2">
|
||||
{formatDateToIndonesian(new Date(relate?.createdAt))} {relate?.timezone ? relate?.timezone : "WIB"} | <Icon icon="formkit:eye" width="15" height="15" /> {relate.clickCount}{" "}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ import { format } from "date-fns";
|
|||
import { cn } from "@/lib/utils";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { listSchedule, listScheduleNextPublic, listSchedulePrevPublic, listScheduleTodayPublic } from "@/service/schedule/schedule";
|
||||
import { detailSchedule, listSchedule, listScheduleNextPublic, listSchedulePrevPublic, listScheduleTodayPublic } from "@/service/schedule/schedule";
|
||||
import { useRouter } from "@/i18n/routing";
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
|
||||
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog";
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
|
||||
import { close, loading } from "@/config/swal";
|
||||
|
||||
const timeList = [
|
||||
{
|
||||
|
|
@ -114,7 +114,7 @@ const timeList = [
|
|||
},
|
||||
];
|
||||
|
||||
const Schedule = () => {
|
||||
const Schedule = (props: any) => {
|
||||
const router = useRouter();
|
||||
const [startDate, setStartDate] = useState<Date | undefined>(new Date());
|
||||
const [dateAWeek, setDateAWeek] = useState<string[]>([]);
|
||||
|
|
@ -125,6 +125,19 @@ const Schedule = () => {
|
|||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
const [schedules, setSchedules] = useState([]);
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const [detail, setDetail] = useState<any>();
|
||||
const [content, setContent] = useState();
|
||||
const { id } = props;
|
||||
|
||||
useEffect(() => {
|
||||
async function getDataSchedule() {
|
||||
const response = await detailSchedule(id);
|
||||
setDetail(response.data?.data);
|
||||
setContent(response.data?.data?.files);
|
||||
}
|
||||
|
||||
getDataSchedule();
|
||||
}, [id]);
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
|
|
@ -256,7 +269,13 @@ const Schedule = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const getItem = (itemFound: any) => {
|
||||
const getItem = async (itemFound: any) => {
|
||||
loading();
|
||||
const response = await detailSchedule(itemFound?.id);
|
||||
setDetail(response.data?.data);
|
||||
setContent(response.data?.data?.files);
|
||||
console.log("item Found", itemFound);
|
||||
close();
|
||||
setOpenDialog(true);
|
||||
};
|
||||
|
||||
|
|
@ -687,29 +706,31 @@ const Schedule = () => {
|
|||
<AlertDialog open={openDialog} onOpenChange={setOpenDialog}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Test Event</AlertDialogTitle>
|
||||
<AlertDialogTitle>
|
||||
<h1 className="my-4 font-light">JADWAL / {detail?.isYoutube == true ? "LIVE STREAMING" : "DETAIL"}</h1>
|
||||
<p className="font-bold">{detail?.title}</p>
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
<p className="flex flex-row items-center gap-2">
|
||||
<Icon icon="iconamoon:clock-thin" />
|
||||
08.00 - 12.00 WIB
|
||||
{detail?.date} {detail?.startTime} - {detail?.endTime} {detail?.timezone ? detail.timezone : "WIB"}
|
||||
</p>
|
||||
</AlertDialogDescription>
|
||||
<AlertDialogDescription>
|
||||
<p className="flex flex-row items-start gap-2 ">
|
||||
<Icon icon="bxs:map" width={30} />
|
||||
Jl. Trunojoyo No.3 2, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia.
|
||||
{detail?.address}
|
||||
</p>
|
||||
</AlertDialogDescription>
|
||||
<AlertDialogDescription>
|
||||
<p className="flex flex-row items-center gap-2">
|
||||
<Icon icon="ic:round-person" />
|
||||
Hanif Salafi
|
||||
{detail?.speakerTitle || ""} {detail?.speakerName || ""}{" "}
|
||||
</p>
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction>Continue</AlertDialogAction>
|
||||
<AlertDialogAction>Close</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
|
|
|
|||
|
|
@ -49,20 +49,20 @@ const DetailVideo = () => {
|
|||
</div>
|
||||
|
||||
{/* Footer Informasi */}
|
||||
<div className="p-4 text-sm text-gray-500 flex justify-between items-center border-t mt-4">
|
||||
<p className="flex flex-row items-center">
|
||||
<div className="text-sm text-gray-500 flex justify-between items-center border-t mt-4">
|
||||
<p className="flex flex-row items-center mt-3">
|
||||
oleh <span className="font-semibold text-black">{detailDataVideo?.uploadedBy?.userLevel?.name}</span> | Diupdate pada {detailDataVideo?.updatedAt} WIB |
|
||||
<Icon icon="formkit:eye" width="15" height="15" />
|
||||
|
||||
{detailDataVideo?.clickCount}
|
||||
</p>
|
||||
<p>Kreator: {detailDataVideo?.creatorName}</p>
|
||||
<p className="mt-3">Kreator: {detailDataVideo?.creatorName}</p>
|
||||
</div>
|
||||
|
||||
{/* Keterangan */}
|
||||
<div className="w-full">
|
||||
<h1 className="flex flex-row font-bold text-2xl mx-5 my-8">{detailDataVideo?.title}</h1>
|
||||
<div dangerouslySetInnerHTML={{ __html: detailDataVideo?.htmlDescription }} />
|
||||
<h1 className="flex flex-row font-bold text-2xl my-8">{detailDataVideo?.title}</h1>
|
||||
<div className="font-light text-justify" dangerouslySetInnerHTML={{ __html: detailDataVideo?.htmlDescription }} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -125,15 +125,15 @@ const DetailVideo = () => {
|
|||
<div className="w-full mb-8">
|
||||
{/* Comment */}
|
||||
<div className="flex flex-col my-16 p-10 bg-[#f7f7f7]">
|
||||
<div className="gap-5 flex flex-col px-4 lg:px-16">
|
||||
<div className="gap-5 flex flex-col px-4 lg:px-14">
|
||||
<p className="flex items-start text-lg">Berikan Komentar</p>
|
||||
<Textarea placeholder="Type your comments here." className="flex w-full" />
|
||||
<button className="flex items-start bg-[#bb3523] rounded-lg w-fit px-4 py-1">Kirim</button>
|
||||
<button className="flex items-start bg-[#bb3523] text-white rounded-lg w-fit px-4 py-1">Kirim</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Konten Serupa */}
|
||||
<div className="px-4">
|
||||
<div className="">
|
||||
<NewContent type={"similar"} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,13 +3,17 @@ import React, { useEffect, useState } from "react";
|
|||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { getListContent } from "@/service/landing/landing";
|
||||
import { formatDateToIndonesian } from "@/utils/globals";
|
||||
import { useParams, usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { ColumnDef, ColumnFiltersState, PaginationState, SortingState, VisibilityState, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
|
||||
import { formatDateToIndonesian, getOnlyDate, getOnlyMonthAndYear } from "@/utils/globals";
|
||||
import { useParams, usePathname, useSearchParams } from "next/navigation";
|
||||
import { getListContent, getUserLevelListByParent, listCategory, listData, listDataRegional } from "@/service/landing/landing";
|
||||
import { ColumnDef, ColumnFiltersState, PaginationState, SortingState, VisibilityState, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
|
||||
import LandingPagination from "@/components/landing-page/pagination";
|
||||
import { Reveal } from "@/components/landing-page/Reveal";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import ReactDatePicker from "react-datepicker";
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
import { close, loading } from "@/config/swal";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
|
|
@ -19,34 +23,13 @@ const columns: ColumnDef<any>[] = [
|
|||
},
|
||||
];
|
||||
|
||||
const categories = [
|
||||
{ id: 1, title: "HUT HUMAS KE - 73" },
|
||||
{ id: 2, title: "OPERASI ZEBRA 2024" },
|
||||
{ id: 3, title: "PON XXI" },
|
||||
{ id: 4, title: "OPS LILIN NATARU 2024" },
|
||||
{ id: 5, title: "HUT HUMAS KE - 72" },
|
||||
{ id: 6, title: "OPS MANTAP PRAJA & PILKADA 2024" },
|
||||
{ id: 6, title: "OPS KETUPAT 2024" },
|
||||
{ id: 6, title: "OPS PATUH 2024" },
|
||||
{ id: 6, title: "HARI JUANG POLRI" },
|
||||
{ id: 6, title: "HUT RI KE-79" },
|
||||
{ id: 6, title: "HARI BHAYANGKARA KE-78" },
|
||||
];
|
||||
const formatPicture = [
|
||||
{ id: 1, title: "MK4" },
|
||||
{ id: 2, title: "MOV" },
|
||||
{ id: 3, title: "MP4" },
|
||||
{ id: 3, title: "AVI" },
|
||||
{ id: 3, title: "WMV" },
|
||||
];
|
||||
|
||||
const FilterPage = () => {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const asPath = usePathname();
|
||||
const params = useParams();
|
||||
const searchParams = useSearchParams();
|
||||
const locale = params?.locale;
|
||||
const [imageData, setImageData] = useState<any>();
|
||||
const [videoData, setVideoData] = useState<any>();
|
||||
const [totalData, setTotalData] = React.useState<number>(1);
|
||||
const [totalPage, setTotalPage] = React.useState<number>(1);
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
|
|
@ -55,9 +38,36 @@ const FilterPage = () => {
|
|||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
const [pagination, setPagination] = React.useState<PaginationState>({
|
||||
pageIndex: 0,
|
||||
pageSize: 6,
|
||||
pageSize: 10,
|
||||
});
|
||||
const [page, setPage] = useState(1);
|
||||
const [totalContent, setTotalContent] = useState();
|
||||
const [change, setChange] = useState(false);
|
||||
const sortBy = searchParams?.get("sortBy");
|
||||
const title = searchParams?.get("title");
|
||||
const categorie = searchParams?.get("category");
|
||||
const group = searchParams?.get("group");
|
||||
const [, setGetTotalPage] = useState();
|
||||
let typingTimer: any;
|
||||
const doneTypingInterval = 1500;
|
||||
const [contentVideo, setContentVideo] = useState([]);
|
||||
const [categoryFilter, setCategoryFilter] = useState<any>([]);
|
||||
const [monthYearFilter, setMonthYearFilter] = useState<any>();
|
||||
const [searchTitle, setSearchTitle] = useState<string>("");
|
||||
const [sortByOpt, setSortByOpt] = useState<any>(sortBy === "popular" ? "clickCount" : "createdAt");
|
||||
const isRegional = asPath?.includes("regional");
|
||||
const isSatker = asPath?.includes("satker");
|
||||
const [formatFilter, setFormatFilter] = useState<any>([]);
|
||||
const pages = page ? page - 1 : 0;
|
||||
const [startDateString, setStartDateString] = useState<any>();
|
||||
const [endDateString, setEndDateString] = useState<any>();
|
||||
const [dateRange, setDateRange] = useState<any>([null, null]);
|
||||
const [calenderState, setCalenderState] = useState(false);
|
||||
const [handleClose, setHandleClose] = useState(false);
|
||||
const [categories, setCategories] = useState([]);
|
||||
const [userLevels, setUserLevels] = useState([]);
|
||||
|
||||
// const [startDate, endDate] = dateRange;
|
||||
|
||||
React.useEffect(() => {
|
||||
const pageFromUrl = searchParams?.get("page");
|
||||
|
|
@ -66,8 +76,191 @@ const FilterPage = () => {
|
|||
}
|
||||
}, [searchParams]);
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
getCategories();
|
||||
// getSelectedCategory();
|
||||
if (isSatker) {
|
||||
getUserLevels();
|
||||
}
|
||||
}
|
||||
|
||||
initState();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (categorie) {
|
||||
setCategoryFilter(categorie?.split("&")?.length > 1 ? categorie?.split("&") : [categorie]);
|
||||
console.log("Kategori", categorie, categorie?.split("&")?.length > 1 ? categorie?.split("&") : [categorie]);
|
||||
}
|
||||
}, [categorie]);
|
||||
|
||||
// useEffect(() => {
|
||||
// fetchData();
|
||||
// }, [page, sortBy, sortByOpt, title]);
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
if (isRegional) {
|
||||
getDataRegional();
|
||||
} else {
|
||||
getDataAll();
|
||||
}
|
||||
}
|
||||
console.log(monthYearFilter, "monthFilter");
|
||||
initState();
|
||||
}, [change, asPath, monthYearFilter, page, sortBy, sortByOpt, title, startDateString, endDateString, categorie, formatFilter]);
|
||||
|
||||
async function getCategories() {
|
||||
const category = await listCategory("2");
|
||||
const resCategory = category?.data?.data?.content;
|
||||
setCategories(resCategory);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
function initState() {
|
||||
if (dateRange[0] != null && dateRange[1] != null) {
|
||||
setStartDateString(getOnlyDate(dateRange[0]));
|
||||
setEndDateString(getOnlyDate(dateRange[1]));
|
||||
setHandleClose(true);
|
||||
console.log("date range", dateRange, getOnlyDate(dateRange[0]));
|
||||
}
|
||||
}
|
||||
initState();
|
||||
}, [calenderState]);
|
||||
|
||||
async function getDataAll() {
|
||||
if (asPath?.includes("/polda/") == true) {
|
||||
if (asPath?.split("/")[2] !== "[polda_name]") {
|
||||
const filter = categoryFilter?.length > 0 ? categoryFilter?.sort().join(",") : categorie || "";
|
||||
|
||||
const name = title == undefined ? "" : title;
|
||||
const format = formatFilter == undefined ? "" : formatFilter?.join(",");
|
||||
const filterGroup = group == undefined ? asPath.split("/")[2] : group;
|
||||
loading();
|
||||
const response = await listData(
|
||||
"2",
|
||||
name,
|
||||
filter,
|
||||
12,
|
||||
pages,
|
||||
sortByOpt,
|
||||
format,
|
||||
"",
|
||||
filterGroup,
|
||||
startDateString,
|
||||
endDateString,
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[0]?.replace("", "") : "",
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[1] : ""
|
||||
);
|
||||
close();
|
||||
// setGetTotalPage(response.data?.data?.totalPages);
|
||||
// setContentImage(response.data?.data?.content);
|
||||
// setTotalContent(response.data?.data?.totalElements);
|
||||
const data = response.data?.data;
|
||||
const contentData = data?.content;
|
||||
setVideoData(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 == undefined ? "" : title;
|
||||
const format = formatFilter == undefined ? "" : formatFilter?.join(",");
|
||||
loading();
|
||||
const response = await listData(
|
||||
"2",
|
||||
name,
|
||||
filter,
|
||||
12,
|
||||
pages,
|
||||
sortByOpt,
|
||||
format,
|
||||
"",
|
||||
"",
|
||||
startDateString,
|
||||
endDateString,
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[0]?.replace("", "") : "",
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[1] : ""
|
||||
);
|
||||
close();
|
||||
// setGetTotalPage(response.data?.data?.totalPages);
|
||||
// setContentImage(response.data?.data?.content);
|
||||
// setTotalContent(response.data?.data?.totalElements);
|
||||
const data = response.data?.data;
|
||||
const contentData = data?.content;
|
||||
setVideoData(contentData);
|
||||
setTotalData(data?.totalElements);
|
||||
setTotalPage(data?.totalPages);
|
||||
setTotalContent(response.data?.data?.totalElements);
|
||||
}
|
||||
}
|
||||
|
||||
const handleCategoryFilter = (e: boolean, id: string) => {
|
||||
let filter = [...categoryFilter];
|
||||
|
||||
if (e) {
|
||||
filter = [...categoryFilter, String(id)];
|
||||
} else {
|
||||
filter.splice(categoryFilter.indexOf(id), 1);
|
||||
}
|
||||
console.log("checkbox filter", filter);
|
||||
setCategoryFilter(filter);
|
||||
router.push(`?category=${filter.join("&")}`);
|
||||
};
|
||||
|
||||
const handleFormatFilter = (e: boolean, id: string) => {
|
||||
let filter = [...formatFilter];
|
||||
|
||||
if (e) {
|
||||
filter = [...formatFilter, id];
|
||||
} else {
|
||||
filter.splice(formatFilter.indexOf(id), 1);
|
||||
}
|
||||
console.log("Format filter", filter);
|
||||
setFormatFilter(filter);
|
||||
};
|
||||
|
||||
const cleanCheckbox = () => {
|
||||
setCategoryFilter([]);
|
||||
setFormatFilter([]);
|
||||
router.push(`?category=&title=`);
|
||||
setDateRange([null, null]);
|
||||
setMonthYearFilter(null);
|
||||
setChange(!change);
|
||||
};
|
||||
|
||||
async function getDataRegional() {
|
||||
const filter = categoryFilter?.length > 0 ? categoryFilter?.sort().join(",") : categorie || "";
|
||||
|
||||
const name = title == undefined ? "" : title;
|
||||
const format = formatFilter == undefined ? "" : formatFilter?.join(",");
|
||||
loading();
|
||||
const response = await listDataRegional(
|
||||
"2",
|
||||
name,
|
||||
filter,
|
||||
format,
|
||||
"",
|
||||
startDateString,
|
||||
endDateString,
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[0]?.replace("", "") : "",
|
||||
monthYearFilter ? getOnlyMonthAndYear(monthYearFilter)?.split("/")[1] : "",
|
||||
12,
|
||||
pages,
|
||||
sortByOpt
|
||||
);
|
||||
close();
|
||||
|
||||
setGetTotalPage(response.data?.data?.totalPages);
|
||||
setContentVideo(response.data?.data?.content);
|
||||
setTotalContent(response.data?.data?.totalElements);
|
||||
}
|
||||
|
||||
const table = useReactTable({
|
||||
data: imageData,
|
||||
data: videoData,
|
||||
columns: columns,
|
||||
onSortingChange: setSorting,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
|
|
@ -87,7 +280,6 @@ const FilterPage = () => {
|
|||
},
|
||||
});
|
||||
|
||||
const [videoData, setVideoData] = useState<any>();
|
||||
useEffect(() => {
|
||||
initFetch();
|
||||
}, [page]);
|
||||
|
|
@ -102,97 +294,212 @@ const FilterPage = () => {
|
|||
setTotalPage(data?.totalPages);
|
||||
};
|
||||
|
||||
|
||||
function getSelectedCategory() {
|
||||
const filter = [];
|
||||
|
||||
if (categorie) {
|
||||
const categoryArr = categorie.split(",");
|
||||
|
||||
for (const element of categoryArr) {
|
||||
filter.push(Number(element));
|
||||
}
|
||||
|
||||
setCategoryFilter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeleteDate = () => {
|
||||
setDateRange([null, null]);
|
||||
setStartDateString("");
|
||||
setEndDateString("");
|
||||
setHandleClose(false);
|
||||
};
|
||||
|
||||
const handleSorting = (e: any) => {
|
||||
console.log(e.target.value);
|
||||
if (e.target.value == "terbaru") {
|
||||
setSortByOpt("createdAt");
|
||||
} else {
|
||||
setSortByOpt("clickCount");
|
||||
}
|
||||
|
||||
setChange(!change);
|
||||
};
|
||||
|
||||
async function getUserLevels() {
|
||||
const res = await getUserLevelListByParent(761);
|
||||
const userLevelList = res?.data?.data;
|
||||
|
||||
if (userLevelList !== null) {
|
||||
let optionArr: any = [];
|
||||
|
||||
userLevelList?.map((option: any) => {
|
||||
let optionData = {
|
||||
id: option.id,
|
||||
label: option.name,
|
||||
value: option.id,
|
||||
};
|
||||
|
||||
optionArr.push(optionData);
|
||||
});
|
||||
|
||||
setUserLevels(optionArr);
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyUp = () => {
|
||||
clearTimeout(typingTimer);
|
||||
typingTimer = setTimeout(doneTyping, doneTypingInterval);
|
||||
};
|
||||
|
||||
async function doneTyping() {
|
||||
if (searchTitle == "" || searchTitle == undefined) {
|
||||
router.push("?title=");
|
||||
} else {
|
||||
router.push(`?title=${searchTitle}`);
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyDown = () => {
|
||||
clearTimeout(typingTimer);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
{/* Header */}
|
||||
|
||||
<div className="flex flex-col md:flex-row items-start gap-5 p-10 bg-[#f7f7f7] dark:bg-black">
|
||||
<p>
|
||||
{" "}
|
||||
Audio Visual {">"} <span className="font-bold">Semua Audio Visual</span>
|
||||
</p>
|
||||
<p className="font-bold">|</p>
|
||||
<p>Terdapat 324911 artikel berisi Audio Visual yang dapat diunduh </p>
|
||||
<p>{`Terdapat ${totalContent} artikel berisi Audio Visual yang dapat diunduh`}</p>
|
||||
</div>
|
||||
|
||||
{/* Left */}
|
||||
<div className="flex flex-col lg:flex-row gap-6 p-4">
|
||||
<div className="lg:w-1/4 w-full bg-[#f7f7f7] dark:bg-black p-4 rounded-lg shadow-md">
|
||||
<Reveal>
|
||||
<h2 className="text-lg font-semibold mb-4 flex items-center gap-1">
|
||||
<Icon icon="stash:filter-light" fontSize={30} />
|
||||
Filter
|
||||
</h2>
|
||||
<div className="border-t border-black dark:border-white my-4"></div>
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<label htmlFor="search" className="block text-sm font-medium text-gray-700 dark:text-white">
|
||||
Pencarian
|
||||
</label>
|
||||
<input type="text" id="search" placeholder="Cari judul..." className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" />
|
||||
</div>
|
||||
<div className="lg:w-[40%] w-full bg-[#f7f7f7] dark:bg-black p-4 rounded-lg shadow-md">
|
||||
<h2 className="text-lg font-semibold mb-4 flex items-center gap-1">
|
||||
<Icon icon="stash:filter-light" fontSize={30} />
|
||||
Filter
|
||||
</h2>
|
||||
<div className="border-t border-black my-4 dark:border-white"></div>
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<label htmlFor="search" className="block text-sm font-medium text-gray-700 dark:text-white">
|
||||
Pencarian
|
||||
</label>
|
||||
<Input
|
||||
value={searchTitle}
|
||||
onChange={(e) => setSearchTitle(e.target.value)}
|
||||
onKeyUp={handleKeyUp}
|
||||
onKeyDown={handleKeyDown}
|
||||
type="text"
|
||||
id="search"
|
||||
placeholder="Cari judul..."
|
||||
className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="month" className="block text-sm font-medium text-gray-700 dark:text-white">
|
||||
Tahun & Bulan
|
||||
</label>
|
||||
<input type="month" id="month" className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white">Tahun & Bulan</label>
|
||||
<ReactDatePicker
|
||||
selected={monthYearFilter}
|
||||
className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
|
||||
onChange={(date) => setMonthYearFilter(date)}
|
||||
dateFormat="MM | yyyy"
|
||||
placeholderText="Pilih Tahun dan Bulan"
|
||||
showMonthYearPicker
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="date" className="block text-sm font-medium text-gray-700 dark:text-white">
|
||||
Tanggal
|
||||
</label>
|
||||
<input type="date" id="date" className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-700 dark:text-white">Kategori</h3>
|
||||
<ul className="mt-2 space-y-2">
|
||||
{categories.map((category) => (
|
||||
<li key={category?.id}>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="terms" />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">{category.title}</span>
|
||||
</label>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
{/* Garis */}
|
||||
<div className="border-t border-black dark:border-white my-4"></div>
|
||||
{/* Garis */}
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-700 dark:text-white">Format Foto</h3>
|
||||
<ul className="mt-2 space-y-2">
|
||||
{formatPicture.map((format) => (
|
||||
<li key={format?.id}>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="terms" />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">{format.title}</span>
|
||||
</label>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="border-t border-black dark:border-white my-4"></div>
|
||||
<div className="text-center">
|
||||
<a href="#" className="text-[#bb3523]">
|
||||
<b>Reset Filter</b>
|
||||
</a>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white">Tanggal</label>
|
||||
<div className="flex flex-row justify justify-between gap-2">
|
||||
<ReactDatePicker
|
||||
selectsRange
|
||||
className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
|
||||
startDate={dateRange[0]}
|
||||
endDate={dateRange[1]}
|
||||
onChange={(update) => {
|
||||
setDateRange(update);
|
||||
}}
|
||||
placeholderText="Pilih Tanggal"
|
||||
onCalendarClose={() => setCalenderState(!calenderState)}
|
||||
/>
|
||||
<div className="flex items-center">{handleClose ? <Icon icon="carbon:close-filled" onClick={handleDeleteDate} width="20" inline color="#216ba5" /> : ""}</div>
|
||||
</div>
|
||||
</div>
|
||||
</Reveal>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-700 dark:text-white">Kategori</h3>
|
||||
<ul className="mt-2 space-y-2">
|
||||
{categories.map((category: any) => (
|
||||
<li key={category?.id}>
|
||||
<label className="inline-flex items-center" htmlFor={`${category.id}`}>
|
||||
<Checkbox id={`${category.id}`} value={category.id} checked={categoryFilter.includes(String(category.id))} onCheckedChange={(e) => handleCategoryFilter(Boolean(e), category.id)} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">{category?.name}</span>
|
||||
</label>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
{/* Garis */}
|
||||
<div className="border-t border-black my-4 dark:border-white"></div>
|
||||
{/* Garis */}
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-700 dark:text-white">Format Foto</h3>
|
||||
<ul className="mt-2 space-y-2">
|
||||
<li>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="mk4" value="mk4" checked={formatFilter.includes("mk4")} onCheckedChange={(e) => handleFormatFilter(Boolean(e), "mk4")} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">MK4</span>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="mov" value="mov" checked={formatFilter.includes("mov")} onCheckedChange={(e) => handleFormatFilter(Boolean(e), "mov")} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">MOV</span>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="mp4" value="mp4" checked={formatFilter.includes("mp4")} onCheckedChange={(e) => handleFormatFilter(Boolean(e), "mp4")} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">MP4</span>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="avi" value="avi" checked={formatFilter.includes("avi")} onCheckedChange={(e) => handleFormatFilter(Boolean(e), "avi")} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">AVI</span>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label className="inline-flex items-center">
|
||||
<Checkbox id="wmv" value="wmv" checked={formatFilter.includes("wmv")} onCheckedChange={(e) => handleFormatFilter(Boolean(e), "wmv")} />
|
||||
<span className="ml-2 text-gray-700 dark:text-white">WMV</span>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="border-t border-black dark:border-white my-4"></div>
|
||||
<div className="text-center">
|
||||
<a onClick={cleanCheckbox} className="text-[#bb3523] cursor-pointer">
|
||||
<b>Reset Filter</b>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Konten Kanan */}
|
||||
<div className="flex-1">
|
||||
<Reveal>
|
||||
<Reveal>
|
||||
<div className="flex-1">
|
||||
<div className="flex flex-col items-end mb-4">
|
||||
<h2 className="text-lg font-semibold">Urutkan berdasarkan</h2>
|
||||
<select className="border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500">
|
||||
<select defaultValue={sortBy == "popular" ? "terpopuler" : "terbaru"} onChange={(e) => handleSorting(e)} className="border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500">
|
||||
<option value="terbaru">Terbaru</option>
|
||||
<option value="terlama">Terlama</option>
|
||||
<option value="terpopuler">Terpopuler</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
|
@ -201,7 +508,7 @@ const FilterPage = () => {
|
|||
<Card key={video?.id} className="hover:scale-110 transition-transform duration-300">
|
||||
<CardContent className="flex flex-col text-xs lg:text-sm w-full p-0">
|
||||
<Link href={`/video/detail/${video?.slug}`}>
|
||||
<img src={video?.thumbnailLink} className=" h-60 object-cover items-center w-full justify-center rounded-lg" />
|
||||
<img src={video?.thumbnailLink} className="h-60 object-cover items-center justify-center cursor-pointer rounded-lg place-self-center" />
|
||||
<div className="flex flex-row items-center gap-2 text-[10px] mx-2">
|
||||
{formatDateToIndonesian(new Date(video?.createdAt))} {video?.timezone ? video?.timezone : "WIB"}| <Icon icon="formkit:eye" width="15" height="15" />
|
||||
{video?.clickCount}{" "}
|
||||
|
|
@ -212,15 +519,15 @@ const FilterPage = () => {
|
|||
/>
|
||||
</svg>{" "}
|
||||
</div>
|
||||
<div className="font-semibold pr-3 pb-3 mx-2 hover:h-auto truncate text-base hover:whitespace-normal hover:overflow-visible w-full">{video?.title}</div>
|
||||
<div className="font-semibold pr-3 pb-3 mx-2 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible w-full">{video?.title}</div>
|
||||
</Link>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
<LandingPagination table={table} totalData={totalData} totalPage={totalPage} />
|
||||
</Reveal>
|
||||
</div>
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,130 @@
|
|||
import { SVGProps } from "react";
|
||||
|
||||
type IconSvgProps = SVGProps<SVGSVGElement> & {
|
||||
size?: number;
|
||||
};
|
||||
|
||||
export const FacebookIcon = ({
|
||||
size,
|
||||
height = 24,
|
||||
width = 24,
|
||||
fill = "currentColor",
|
||||
...props
|
||||
}: IconSvgProps) => (
|
||||
<svg
|
||||
height={size || height}
|
||||
width={size || width}
|
||||
viewBox="0 0 24 24"
|
||||
fill={fill}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<g fill="none">
|
||||
<g clip-path="url(#akarIconsFacebookFill0)">
|
||||
<path
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
d="M0 12.067C0 18.034 4.333 22.994 10 24v-8.667H7V12h3V9.333c0-3 1.933-4.666 4.667-4.666c.866 0 1.8.133 2.666.266V8H15.8c-1.467 0-1.8.733-1.8 1.667V12h3.2l-.533 3.333H14V24c5.667-1.006 10-5.966 10-11.933C24 5.43 18.6 0 12 0S0 5.43 0 12.067"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="akarIconsFacebookFill0">
|
||||
<path fill="#fff" d="M0 0h24v24H0z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
export const InstagramIcon = ({
|
||||
size,
|
||||
height = 24,
|
||||
width = 24,
|
||||
fill = "currentColor",
|
||||
...props
|
||||
}: IconSvgProps) => (
|
||||
<svg
|
||||
height={size || height}
|
||||
width={size || width}
|
||||
viewBox="0 0 24 24"
|
||||
fill={fill}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M7.8 2h8.4C19.4 2 22 4.6 22 7.8v8.4a5.8 5.8 0 0 1-5.8 5.8H7.8C4.6 22 2 19.4 2 16.2V7.8A5.8 5.8 0 0 1 7.8 2m-.2 2A3.6 3.6 0 0 0 4 7.6v8.8C4 18.39 5.61 20 7.6 20h8.8a3.6 3.6 0 0 0 3.6-3.6V7.6C20 5.61 18.39 4 16.4 4zm9.65 1.5a1.25 1.25 0 0 1 1.25 1.25A1.25 1.25 0 0 1 17.25 8A1.25 1.25 0 0 1 16 6.75a1.25 1.25 0 0 1 1.25-1.25M12 7a5 5 0 0 1 5 5a5 5 0 0 1-5 5a5 5 0 0 1-5-5a5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3a3 3 0 0 0 3 3a3 3 0 0 0 3-3a3 3 0 0 0-3-3"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export const YoutubeIcon = ({
|
||||
size,
|
||||
height = 24,
|
||||
width = 24,
|
||||
fill = "currentColor",
|
||||
...props
|
||||
}: IconSvgProps) => (
|
||||
<svg
|
||||
height={size || height}
|
||||
width={size || width}
|
||||
viewBox="0 0 24 24"
|
||||
fill={fill}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<g fill="none">
|
||||
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12 4c.855 0 1.732.022 2.582.058l1.004.048l.961.057l.9.061l.822.064a3.8 3.8 0 0 1 3.494 3.423l.04.425l.075.91c.07.943.122 1.971.122 2.954s-.052 2.011-.122 2.954l-.075.91l-.04.425a3.8 3.8 0 0 1-3.495 3.423l-.82.063l-.9.062l-.962.057l-1.004.048A62 62 0 0 1 12 20a62 62 0 0 1-2.582-.058l-1.004-.048l-.961-.057l-.9-.062l-.822-.063a3.8 3.8 0 0 1-3.494-3.423l-.04-.425l-.075-.91A41 41 0 0 1 2 12c0-.983.052-2.011.122-2.954l.075-.91l.04-.425A3.8 3.8 0 0 1 5.73 4.288l.821-.064l.9-.061l.962-.057l1.004-.048A62 62 0 0 1 12 4m0 2c-.825 0-1.674.022-2.5.056l-.978.047l-.939.055l-.882.06l-.808.063a1.8 1.8 0 0 0-1.666 1.623C4.11 9.113 4 10.618 4 12s.11 2.887.227 4.096c.085.872.777 1.55 1.666 1.623l.808.062l.882.06l.939.056l.978.047c.826.034 1.675.056 2.5.056s1.674-.022 2.5-.056l.978-.047l.939-.055l.882-.06l.808-.063a1.8 1.8 0 0 0 1.666-1.623C19.89 14.887 20 13.382 20 12s-.11-2.887-.227-4.096a1.8 1.8 0 0 0-1.666-1.623l-.808-.062l-.882-.06l-.939-.056l-.978-.047A61 61 0 0 0 12 6m-2 3.575a.6.6 0 0 1 .819-.559l.081.04l4.2 2.424a.6.6 0 0 1 .085.98l-.085.06l-4.2 2.425a.6.6 0 0 1-.894-.43l-.006-.09z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const TiktokIcon = ({
|
||||
size,
|
||||
height = 24,
|
||||
width = 24,
|
||||
fill = "currentColor",
|
||||
...props
|
||||
}: IconSvgProps) => (
|
||||
<svg
|
||||
height={size || height}
|
||||
width={size || width}
|
||||
viewBox="0 0 24 24"
|
||||
fill={fill}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M16.6 5.82s.51.5 0 0A4.28 4.28 0 0 1 15.54 3h-3.09v12.4a2.59 2.59 0 0 1-2.59 2.5c-1.42 0-2.6-1.16-2.6-2.6c0-1.72 1.66-3.01 3.37-2.48V9.66c-3.45-.46-6.47 2.22-6.47 5.64c0 3.33 2.76 5.7 5.69 5.7c3.14 0 5.69-2.55 5.69-5.7V9.01a7.35 7.35 0 0 0 4.3 1.38V7.3s-1.88.09-3.24-1.48"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export const XIcon = ({
|
||||
size,
|
||||
height = 24,
|
||||
width = 24,
|
||||
fill = "currentColor",
|
||||
...props
|
||||
}: IconSvgProps) => (
|
||||
<svg
|
||||
height={size || height}
|
||||
width={size || width}
|
||||
viewBox="0 0 24 24"
|
||||
fill={fill}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
d="m13.081 10.712l-4.786-6.71a.6.6 0 0 0-.489-.252H5.28a.6.6 0 0 0-.488.948l6.127 8.59m2.162-2.576l6.127 8.59a.6.6 0 0 1-.488.948h-2.526a.6.6 0 0 1-.489-.252l-4.786-6.71m2.162-2.576l5.842-6.962m-8.004 9.538L5.077 20.25"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
|
@ -534,7 +534,7 @@ const Navbar = () => {
|
|||
<NavigationMenuTrigger>
|
||||
<a className="dark:text-white text-black flex flex-row justify-center items-center cursor-pointer">
|
||||
<svg
|
||||
className="mx-2 dark:"
|
||||
className="mx-2"
|
||||
width="25"
|
||||
height="24"
|
||||
viewBox="0 0 25 24"
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
"use-client";
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/components/ui/carousel";
|
||||
import { useParams, usePathname, useRouter } from "next/navigation";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { formatDateToIndonesian, textEllipsis } from "@/utils/globals";
|
||||
import { generateLocalizedPath } from "@/utils/globals";
|
||||
import { formatDateToIndonesian } from "@/utils/globals";
|
||||
import { getListContent } from "@/service/landing/landing";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { Reveal } from "./Reveal";
|
||||
|
|
@ -33,11 +34,11 @@ const NewContent = (props: { type: string }) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="px-4 lg:px-16">
|
||||
<div className="px-4 lg:px-16 py-4">
|
||||
<Reveal>
|
||||
<div className="flex flex-col p-4">
|
||||
<div className="mx-auto w-full max-w-7xl justify-start flex px-5 flex-col lg:flex-row gap-5 mb-4">
|
||||
<h2 className="flex items-center text-sm lg:text-xl w-fit font-bold bg-[#bb3523] px-4 py-1 rounded-lg text-white">
|
||||
<h2 className="flex items-center text-xl lg:text-2xl w-fit font-bold bg-[#bb3523] px-4 py-1 rounded-lg text-white">
|
||||
<span className="text-black ">Konten </span>
|
||||
{props.type == "popular" ? "Populer" : props.type == "latest" ? "Terbaru" : "Serupa"}
|
||||
</h2>
|
||||
|
|
@ -73,7 +74,7 @@ const NewContent = (props: { type: string }) => {
|
|||
</TabsList>
|
||||
</Tabs>
|
||||
</div>
|
||||
<div className="px-10">
|
||||
<div className="px-0 lg:px-10">
|
||||
{selectedTab == "video" ? (
|
||||
newContent?.length > 0 ? (
|
||||
<Carousel className="w-full max-w-7xl mx-auto">
|
||||
|
|
@ -81,7 +82,7 @@ const NewContent = (props: { type: string }) => {
|
|||
{newContent?.map((video: any) => (
|
||||
<CarouselItem key={video?.id} className="md:basis-1/2 lg:basis-1/3">
|
||||
<Link href={`/video/detail/${video?.slug}`} className="relative group overflow-hidden shadow-md hover:shadow-lg">
|
||||
<img src={video?.thumbnailLink} className="w-full rounded-lg h-40 lg:h-60 object-cover group-hover:scale-100 transition-transform duration-300" />
|
||||
<img src={video?.thumbnailLink} className="w-full rounded-lg h-48 lg:h-60 object-cover group-hover:scale-100 transition-transform duration-300" />
|
||||
<div className="absolute bottom-0 left-0 right-0 bg-gray-600 border-l-4 border-[#bb3523] rounded-lg backdrop-blur-sm text-white p-2">
|
||||
<h1 className="text-sm lg:text-lg mb-2 font-semibold h-5 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible">{video?.title}</h1>
|
||||
<p className="flex flex-row items-center text-[10px] gap-2">
|
||||
|
|
@ -200,7 +201,7 @@ const NewContent = (props: { type: string }) => {
|
|||
</div>
|
||||
</div>
|
||||
<div className="flex items-center flex-row justify-center">
|
||||
<Link href="/video/filter" className="border text-[#bb3523] rounded-lg text-sm lg:text-md px-4 py-1 border-[#bb3523]">
|
||||
<Link href={`/${selectedTab}/filter?sortBy=${props.type}`} className="border text-[#bb3523] rounded-lg text-sm lg:text-md px-4 py-1 border-[#bb3523]">
|
||||
LIHAT SEMUA
|
||||
</Link>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const SearchSection = () => {
|
|||
<h1 className="text-2xl md:text-3xl font-bold text-gray-800 dark:text-white">
|
||||
<span className="text-[#bb3523] dark:text-white">Eksplorasi</span> dan <span className="text-[#bb3523] dark:text-white">Download</span> Liputan Resmi Kami
|
||||
</h1>
|
||||
<div className="w-auto h-1 bg-[#bb3523] mx-auto mt-2"></div>
|
||||
<div className="w-[80%] h-1 bg-[#bb3523] mx-auto mt-2"></div>
|
||||
<p className="text-sm md:text-base text-gray-500 dark:text-gray-100 mt-4">Liputan resmi yang bersumber dari kegiatan Polri di Mabes dan Polda seluruh Indonesia</p>
|
||||
|
||||
{/* Search Form */}
|
||||
|
|
@ -76,7 +76,7 @@ const SearchSection = () => {
|
|||
{/* Search Input */}
|
||||
|
||||
{/* Button */}
|
||||
<button className="px-6 lg:w-[20%] py-2 bg-[#bb3523] flex justify-center items-center gap-2 text-white rounded-lg hover:bg-red-700">
|
||||
<button className="flex justify-center items-center px-6 w-full lg:w-[20%] py-2 bg-[#bb3523] gap-2 text-white rounded-lg hover:bg-red-700">
|
||||
Cari Liputan <Icon icon="ri:arrow-right-s-line" fontSize={20} />
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -78,7 +78,21 @@ const columns: ColumnDef<any>[] = [
|
|||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
Detail
|
||||
<Link
|
||||
href={`/curator/task-plan/mediahub/create-weekly/detail/${data.id}`}
|
||||
>
|
||||
Detail
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Link
|
||||
href={`/curator/task-plan/mediahub/create-weekly/edit/${data.id}`}
|
||||
>
|
||||
Edit
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<a className="text-red-600">Delete</a>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
|
@ -121,7 +135,21 @@ const columns: ColumnDef<any>[] = [
|
|||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
Detail
|
||||
<Link
|
||||
href={`/curator/task-plan/mediahub/create-monthly/detail/${row.original.id}`}
|
||||
>
|
||||
Detail
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Link
|
||||
href={`/curator/task-plan/mediahub/create-monthly/edit/${row.original.id}`}
|
||||
>
|
||||
Edit
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<a className="text-red-600">Delete</a>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,161 @@
|
|||
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 {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuItem,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { htmlToString } from "@/utils/globals";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||
},
|
||||
// {
|
||||
// accessorKey: "title",
|
||||
// header: "Judul Perencanaan",
|
||||
// cell: ({ row }) => <span>{row.getValue("title")}</span>,
|
||||
// },
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Judul Perencanaan",
|
||||
cell: ({ row }) => {
|
||||
const datas = row.original.subPlanningList;
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<a className="cursor-pointer">{row.getValue("title")}</a>
|
||||
</DialogTrigger>
|
||||
<DialogContent size="md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Rencanaan Mingguan</DialogTitle>
|
||||
</DialogHeader>
|
||||
<table>
|
||||
<tr>
|
||||
<th className="text-left">Judul Perencanaan</th>
|
||||
<th>Batas Waktu</th>
|
||||
<th>Status</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
{datas?.map((data: any) => (
|
||||
<tr key={data.id}>
|
||||
<th className="text-left font-normal text-sm">
|
||||
{data.title}
|
||||
</th>
|
||||
<th className="font-normal text-sm">{data.date}</th>
|
||||
<th className="font-normal text-sm">{data.status}</th>
|
||||
<th className="flex justify-center text-sm">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Link
|
||||
href={`/curator/task-plan/medsos-mediahub/create-weekly/detail/${data.id}`}
|
||||
>
|
||||
Detail
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Link
|
||||
href={`/curator/task-plan/medsos-mediahub/create-weekly/edit/${data.id}`}
|
||||
>
|
||||
Edit
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<a className="text-red-600">Hapus</a>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</th>
|
||||
</tr>
|
||||
))}
|
||||
</table>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "date",
|
||||
header: "Batas Waktu",
|
||||
cell: ({ row }) => <span>{row.getValue("date")}</span>,
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => <span>{row.getValue("status")}</span>,
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Link
|
||||
href={`/curator/task-plan/medsos-mediahub/create-monthly/detail/${row.original.id}`}
|
||||
>
|
||||
Detail
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Link
|
||||
href={`/curator/task-plan/medsos-mediahub/create-monthly/edit/${row.original.id}`}
|
||||
>
|
||||
Edit
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<a className="text-red-600">Hapus</a>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default columns;
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
PaginationState,
|
||||
SortingState,
|
||||
VisibilityState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import {
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Eye,
|
||||
MoreVertical,
|
||||
Search,
|
||||
SquarePen,
|
||||
Trash2,
|
||||
TrendingDown,
|
||||
TrendingUp,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
|
||||
import { paginationBlog } from "@/service/blog/blog";
|
||||
import { ticketingPagination } from "@/service/ticketing/ticketing";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import TablePagination from "@/components/table/table-pagination";
|
||||
import columns from "./list-view-social-media-column";
|
||||
import { getPlanningPagination } from "@/service/agenda-setting/agenda-setting";
|
||||
|
||||
const ListViewSocialMediaTable = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||
const [totalData, setTotalData] = React.useState<number>(1);
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[]
|
||||
);
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
const [pagination, setPagination] = React.useState<PaginationState>({
|
||||
pageIndex: 0,
|
||||
pageSize: 10,
|
||||
});
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
onSortingChange: setSorting,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
onRowSelectionChange: setRowSelection,
|
||||
onPaginationChange: setPagination,
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
columnVisibility,
|
||||
rowSelection,
|
||||
pagination,
|
||||
},
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
const pageFromUrl = searchParams?.get("page");
|
||||
if (pageFromUrl) {
|
||||
setPage(Number(pageFromUrl));
|
||||
}
|
||||
}, [searchParams]);
|
||||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const res = await getPlanningPagination(page - 1, "", 10, 2, 3);
|
||||
const data = res.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
item.no = (page - 1) * limit + index + 1;
|
||||
});
|
||||
|
||||
console.log("contentData : ", data);
|
||||
|
||||
setDataTable(contentData);
|
||||
setTotalData(data?.totalElements);
|
||||
setTotalPage(data?.totalPages);
|
||||
} catch (error) {
|
||||
console.error("Error fetching tasks:", error);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<Table className="overflow-hidden mt-3">
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id} className="bg-default-200">
|
||||
{headerGroup.headers.map((header) => (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
className="h-[75px]"
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination
|
||||
table={table}
|
||||
totalData={totalData}
|
||||
totalPage={totalPage}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ListViewSocialMediaTable;
|
||||
|
|
@ -0,0 +1,470 @@
|
|||
"use client";
|
||||
import dayjs from "dayjs";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import { close, loading } from "@/config/swal";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { Swiper, SwiperSlide } from "swiper/react";
|
||||
import "swiper/css";
|
||||
import "swiper/css/free-mode";
|
||||
import "swiper/css/navigation";
|
||||
import "swiper/css/thumbs";
|
||||
|
||||
import Image from "next/image";
|
||||
import { FreeMode, Navigation, Thumbs } from "swiper/modules";
|
||||
import { Swiper as SwiperType } from "swiper/types";
|
||||
import {
|
||||
getMonthlyPlanList,
|
||||
getPlanningDailyByTypeId,
|
||||
getPlanningDailyMedsosByPlatform,
|
||||
getPlanningMonthlyPerSocmed,
|
||||
getWeeklyPlanList,
|
||||
getWeeklyPlanListByParentId,
|
||||
} from "@/service/agenda-setting/agenda-setting";
|
||||
import TaskPlanMediahubTable from "@/app/[locale]/(protected)/curator/task-plan/mediahub/components/table";
|
||||
import weekday from "dayjs/plugin/weekday";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import {
|
||||
FacebookIcon,
|
||||
InstagramIcon,
|
||||
TiktokIcon,
|
||||
XIcon,
|
||||
YoutubeIcon,
|
||||
} from "@/components/icon";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import TaskPlanningSocialMediaTable from "./social-media-modal/table";
|
||||
|
||||
const WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||
const TODAY = dayjs().format("YYYY-MM-DD");
|
||||
|
||||
export default function SingleViewSocialMediaTable() {
|
||||
const params = useSearchParams();
|
||||
const [selectedMonthItem, setSelectedMonthItem] = useState<
|
||||
string | undefined
|
||||
>(undefined);
|
||||
const [selectedWeekly, setSelectedWeekly] = useState<string | undefined>(
|
||||
undefined
|
||||
);
|
||||
const [selectedDate, setSelectedDate] = useState<number>(
|
||||
new Date(TODAY).getDate()
|
||||
);
|
||||
const [nowDate, setNowDate] = useState<string>(TODAY);
|
||||
|
||||
const INITIAL_YEAR = dayjs().format("YYYY");
|
||||
const INITIAL_MONTH = dayjs().format("M");
|
||||
const size = 20;
|
||||
|
||||
const page: string | undefined | null = params?.get("page");
|
||||
const id: string | undefined | null = params?.get("id");
|
||||
const pages = page ? Number(page) - 1 : 0;
|
||||
const no = (size || 10) * pages;
|
||||
|
||||
const [selectedMonth, setSelectedMonth] = useState<any>(
|
||||
dayjs(new Date(parseInt(INITIAL_YEAR), parseInt(INITIAL_MONTH) - 1, 1))
|
||||
);
|
||||
|
||||
const [selectedMonthTitle, setSelectedMonthTitle] = useState<string>("");
|
||||
const [days, setDays] = useState<any>([]);
|
||||
|
||||
const weekday = require("dayjs/plugin/weekday");
|
||||
const weekOfYear = require("dayjs/plugin/weekOfYear");
|
||||
|
||||
const [planningData, setPlanningData] = useState<any>([]);
|
||||
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(weekday);
|
||||
dayjs.extend(weekOfYear);
|
||||
|
||||
let currentMonthDays: any;
|
||||
let previousMonthDays: any;
|
||||
let nextMonthDays: any;
|
||||
|
||||
const [monthlyList, setMonthlyList] = useState([]);
|
||||
const [weeklyList, setWeeklyList] = useState([]);
|
||||
const [getData, setGetData] = useState<any>([]);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [selectedDateNow, setSelectedDateNow] = useState("");
|
||||
const [selectedPlatform, setSelectedPlatform] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
createCalendar("START");
|
||||
}, []);
|
||||
|
||||
function createDaysForCurrentMonth(
|
||||
year: string,
|
||||
month: string,
|
||||
daysInMonth: number
|
||||
) {
|
||||
const days: any = [];
|
||||
for (let day = 1; day <= daysInMonth; day++) {
|
||||
const date = dayjs(
|
||||
new Date(parseInt(year), parseInt(month) - 1, day)
|
||||
).format("YYYY-MM-DD");
|
||||
days.push({
|
||||
date,
|
||||
isCurrentMonth: true,
|
||||
isToday: date === TODAY,
|
||||
});
|
||||
}
|
||||
return days;
|
||||
}
|
||||
|
||||
async function getMonthlyPlanning(dates: number) {
|
||||
const res = await getMonthlyPlanList(dates, 2);
|
||||
setMonthlyList(res.data?.data);
|
||||
}
|
||||
|
||||
async function getWeeklyPlanning(
|
||||
id: string | undefined,
|
||||
date: number | undefined
|
||||
) {
|
||||
if (id) {
|
||||
const res = await getWeeklyPlanListByParentId(id, 2);
|
||||
setWeeklyList(res.data?.data);
|
||||
} else {
|
||||
const res = await getWeeklyPlanList(date, 2, true);
|
||||
setWeeklyList(res.data?.data);
|
||||
}
|
||||
}
|
||||
|
||||
function createCalendar(
|
||||
year: string = INITIAL_YEAR,
|
||||
month: string = INITIAL_MONTH
|
||||
) {
|
||||
year = year === "START" ? INITIAL_YEAR : year;
|
||||
|
||||
fetchData(month, year);
|
||||
|
||||
setSelectedMonthTitle(
|
||||
dayjs(new Date(parseInt(year), parseInt(month) - 1))
|
||||
.utc()
|
||||
.local()
|
||||
.format("MMMM YYYY")
|
||||
);
|
||||
|
||||
currentMonthDays = createDaysForCurrentMonth(
|
||||
year,
|
||||
month,
|
||||
dayjs(`${year}-${month}-01`).daysInMonth()
|
||||
);
|
||||
|
||||
getMonthlyPlanning(year ? currentMonthDays[0]?.date : TODAY);
|
||||
getWeeklyPlanning(undefined, year ? currentMonthDays[0]?.date : TODAY);
|
||||
|
||||
previousMonthDays = createDaysForPreviousMonth(year, month);
|
||||
nextMonthDays = createDaysForNextMonth(year, month);
|
||||
const listDay = [
|
||||
...previousMonthDays,
|
||||
...currentMonthDays,
|
||||
...nextMonthDays,
|
||||
];
|
||||
setDays(listDay);
|
||||
}
|
||||
|
||||
function getWeekday(date: string | undefined) {
|
||||
return dayjs(date).weekday();
|
||||
}
|
||||
|
||||
function createDaysForPreviousMonth(year: string, month: string) {
|
||||
const firstDayOfTheMonthWeekday = getWeekday(currentMonthDays[0]?.date);
|
||||
|
||||
const previousMonth = dayjs(`${year}-${month}-01`).subtract(1, "month");
|
||||
|
||||
// Cover first day of the month being sunday (firstDayOfTheMonthWeekday == 0)
|
||||
const visibleNumberOfDaysFromPreviousMonth = firstDayOfTheMonthWeekday
|
||||
? firstDayOfTheMonthWeekday - 1
|
||||
: 6;
|
||||
|
||||
const previousMonthLastMondayDayOfMonth = dayjs(currentMonthDays[0].date)
|
||||
.subtract(visibleNumberOfDaysFromPreviousMonth, "day")
|
||||
.date();
|
||||
|
||||
return [...new Array(visibleNumberOfDaysFromPreviousMonth)].map(
|
||||
(day, index) => ({
|
||||
date: dayjs(
|
||||
`${previousMonth.year()}-${previousMonth.month() + 1}-${
|
||||
previousMonthLastMondayDayOfMonth + index
|
||||
}`
|
||||
).format("YYYY-MM-DD"),
|
||||
dayOfMonth: previousMonthLastMondayDayOfMonth + index,
|
||||
isCurrentMonth: false,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function createDaysForNextMonth(year: string, month: string) {
|
||||
const lastDayOfTheMonthWeekday = getWeekday(
|
||||
`${year}-${month}-${currentMonthDays.length}`
|
||||
);
|
||||
|
||||
const nextMonth = dayjs(`${year}-${month}-01`).add(1, "month");
|
||||
|
||||
const visibleNumberOfDaysFromNextMonth = lastDayOfTheMonthWeekday
|
||||
? 7 - lastDayOfTheMonthWeekday
|
||||
: lastDayOfTheMonthWeekday;
|
||||
|
||||
return [...new Array(visibleNumberOfDaysFromNextMonth)].map(
|
||||
(day, index) => ({
|
||||
date: dayjs(
|
||||
`${nextMonth.year()}-${nextMonth.month() + 1}-${index + 1}`
|
||||
).format("YYYY-MM-DD"),
|
||||
dayOfMonth: index + 1,
|
||||
isCurrentMonth: false,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async function fetchData(
|
||||
month: string,
|
||||
year: string,
|
||||
|
||||
parentId?: string | undefined
|
||||
) {
|
||||
loading();
|
||||
const res = await getPlanningMonthlyPerSocmed(month, year, 2, parentId);
|
||||
close();
|
||||
setPlanningData(res.data?.data);
|
||||
}
|
||||
|
||||
function getPrevMonth() {
|
||||
const selectedMonthNew = dayjs(selectedMonth).subtract(1, "month");
|
||||
|
||||
createCalendar(
|
||||
selectedMonthNew.format("YYYY"),
|
||||
selectedMonthNew.format("M")
|
||||
);
|
||||
fetchData("", selectedMonthNew?.format("YYYY-MM-DD"));
|
||||
setSelectedMonth(selectedMonthNew);
|
||||
setSelectedDate(1);
|
||||
}
|
||||
|
||||
function getPresentMonth() {
|
||||
const selectedMonthNew = dayjs(
|
||||
new Date(parseInt(INITIAL_YEAR), parseInt(INITIAL_MONTH) - 1, 1)
|
||||
);
|
||||
|
||||
createCalendar(
|
||||
selectedMonthNew.format("YYYY"),
|
||||
selectedMonthNew.format("M")
|
||||
);
|
||||
fetchData("", TODAY);
|
||||
setSelectedDate(Number(dayjs().format("D")));
|
||||
setSelectedMonth(selectedMonthNew);
|
||||
}
|
||||
|
||||
function getNextMonth() {
|
||||
const selectedMonthNew = dayjs(selectedMonth).add(1, "month");
|
||||
|
||||
createCalendar(
|
||||
selectedMonthNew.format("YYYY"),
|
||||
selectedMonthNew.format("M")
|
||||
);
|
||||
fetchData("", selectedMonthNew?.format("YYYY-MM-DD"));
|
||||
setSelectedMonth(selectedMonthNew);
|
||||
setSelectedDate(1);
|
||||
}
|
||||
const onSelectedMonthItem = (id: string | undefined) => {
|
||||
// fetchData(date)
|
||||
setSelectedMonthItem(id);
|
||||
getWeeklyPlanning(id, undefined);
|
||||
};
|
||||
|
||||
const onSelectedWeekly = (id: string | undefined) => {
|
||||
setSelectedWeekly(id);
|
||||
fetchData("", String(id));
|
||||
};
|
||||
|
||||
const removeSelection = () => {
|
||||
setSelectedMonthItem(undefined);
|
||||
setSelectedWeekly(undefined);
|
||||
};
|
||||
|
||||
const onSelectedSocmed = async (date: string, platform: string) => {
|
||||
setSelectedDateNow(date);
|
||||
setSelectedPlatform(platform);
|
||||
setIsOpen(true);
|
||||
};
|
||||
|
||||
const getDataForThisDate = (day: number) => {
|
||||
const todayData = planningData?.find((a: any) => a?.day == day);
|
||||
|
||||
if (todayData) {
|
||||
return (
|
||||
<div className="flex flex-col gap-1">
|
||||
<a
|
||||
onClick={() =>
|
||||
onSelectedSocmed(todayData.planningList[0].date, "5")
|
||||
}
|
||||
className="flex flex-row gap-5 rounded-sm bg-[#0C0705] text-white px-3 py-1 justify-center cursor-pointer"
|
||||
>
|
||||
Total: {todayData.totalTwitter} <XIcon />
|
||||
</a>
|
||||
<a
|
||||
onClick={() =>
|
||||
onSelectedSocmed(todayData.planningList[0].date, "1")
|
||||
}
|
||||
className="flex flex-row gap-5 rounded-sm bg-[#1877F2] text-white px-3 py-1 justify-center cursor-pointer"
|
||||
>
|
||||
Total: {todayData.totalFacebook} <FacebookIcon />
|
||||
</a>
|
||||
<a
|
||||
onClick={() =>
|
||||
onSelectedSocmed(todayData.planningList[0].date, "2")
|
||||
}
|
||||
className="flex flex-row gap-5 rounded-sm bg-[#d62976] text-white px-3 py-1 justify-center cursor-pointer"
|
||||
>
|
||||
Total: {todayData.totalInstagram} <InstagramIcon />
|
||||
</a>
|
||||
<a
|
||||
onClick={() =>
|
||||
onSelectedSocmed(todayData.planningList[0].date, "3")
|
||||
}
|
||||
className="flex flex-row gap-5 rounded-sm bg-[#FF0000] text-white px-3 py-1 justify-center cursor-pointer"
|
||||
>
|
||||
Total: {todayData.totalYoutube} <YoutubeIcon />
|
||||
</a>
|
||||
<a
|
||||
onClick={() =>
|
||||
onSelectedSocmed(todayData.planningList[0].date, "4")
|
||||
}
|
||||
className="flex flex-row gap-5 rounded-sm bg-[#000000] text-white px-3 py-1 justify-center cursor-pointer"
|
||||
>
|
||||
Total: {todayData.totalTiktok} <TiktokIcon />
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="border-2 rounded-sm p-4 flex gap-3 flex-col">
|
||||
<div className="flex justify-between">
|
||||
<div className="flex flex-row gap-2">
|
||||
<a onClick={getPrevMonth} className="cursor-pointer">
|
||||
<ChevronLeft />
|
||||
</a>
|
||||
<a onClick={getPresentMonth} className="cursor-pointer">
|
||||
Today
|
||||
</a>
|
||||
<a onClick={getNextMonth} className="cursor-pointer">
|
||||
<ChevronRight />
|
||||
</a>
|
||||
</div>
|
||||
<p className="text-xl font-semibold">{selectedMonthTitle}</p>
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<a
|
||||
className="border-2 border-primary px-2 py-1 rounded-full text-[10px] text-primary cursor-pointer"
|
||||
onClick={() => removeSelection()}
|
||||
>
|
||||
Hapus Pilihan
|
||||
</a>
|
||||
</div>
|
||||
<div className="px-8 flex flex-col gap-2 text-sm">
|
||||
<p className="font-semibold">Rencana Bulanan</p>
|
||||
{monthlyList?.length > 0 ? (
|
||||
<div className="flex flex-nowrap gap-3 flex-row">
|
||||
{monthlyList?.map((item: any) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className={`rounded-full px-8 py-3 cursor-pointer ${
|
||||
selectedMonthItem === item.id
|
||||
? "bg-sky-600 text-white "
|
||||
: "bg-sky-300"
|
||||
}`}
|
||||
onClick={() => onSelectedMonthItem(item.id)}
|
||||
>
|
||||
<p>{item.title}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex justify-center bg-slate-200 rounded-full py-1">
|
||||
Rencana Bulanan Belum Tersedia
|
||||
</div>
|
||||
)}
|
||||
<p className="font-semibold">Rencana Mingguan</p>
|
||||
{weeklyList?.length > 0 ? (
|
||||
<div className="flex flex-nowrap gap-3 flex-row">
|
||||
{weeklyList?.map((item: any) => (
|
||||
<a
|
||||
key={item.id}
|
||||
className={`bg-sky-300 rounded-full px-8 py-3 cursor-pointer ${
|
||||
selectedWeekly === item.id
|
||||
? "bg-sky-600 text-white "
|
||||
: "bg-sky-300"
|
||||
}`}
|
||||
onClick={() => onSelectedWeekly(item.id)}
|
||||
>
|
||||
<p>{item.title}</p>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex justify-center bg-slate-200 rounded-full py-1">
|
||||
Rencana Mingguan Belum Tersedia
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<div className="w-full mb-2">
|
||||
<div className="overflow-auto">
|
||||
<ol
|
||||
id="days-of-week"
|
||||
className="grid grid-cols-7 gap-1 border-y-2 py-3"
|
||||
>
|
||||
{WEEKDAYS.map((weekday, index) => (
|
||||
<li
|
||||
key={`weekday-${index}`}
|
||||
className="mr-1 text-sm font-medium text-end"
|
||||
>
|
||||
{weekday}
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
<ol id="calendar-days" className="grid grid-cols-7 gap-1">
|
||||
{days?.map((day: any, index: number) => (
|
||||
<li
|
||||
key={`day-${index}`}
|
||||
className={`p-2 text-end min-h-[100px] ${
|
||||
day.isCurrentMonth ? "" : "bg-slate-200 text-slate-400"
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`block mb-1 ${
|
||||
day.date == TODAY ? "font-semibold text-xl" : ""
|
||||
}`}
|
||||
>
|
||||
{parseInt(day.date.split("-")[2])}
|
||||
</span>
|
||||
{day.isCurrentMonth &&
|
||||
getDataForThisDate(parseInt(day.date.split("-")[2]))}
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogContent size="lg" className="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Perencanaan Medsos Harian</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="flex items-center space-x-2">
|
||||
<TaskPlanningSocialMediaTable
|
||||
date={selectedDateNow}
|
||||
platform={selectedPlatform}
|
||||
/>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
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 {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuItem,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { htmlToString } from "@/utils/globals";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||
},
|
||||
// {
|
||||
// accessorKey: "title",
|
||||
// header: "Judul Perencanaan",
|
||||
// cell: ({ row }) => <span>{row.getValue("title")}</span>,
|
||||
// },
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Judul Perencanaan",
|
||||
cell: ({ row }) => <span>{row.getValue("title")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "createdByName",
|
||||
header: "Nama Pembuat",
|
||||
cell: ({ row }) => <span>{row.getValue("createdByName")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Dibuat",
|
||||
cell: ({ row }) => <span>{row.getValue("createdAt")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Dibuat",
|
||||
cell: ({ row }) => <span>{row.getValue("status")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "platformTypeId",
|
||||
header: "Jenis Platform",
|
||||
cell: ({ row }) => <span>{row.getValue("platformTypeId")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => <span>{row.getValue("status")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "description",
|
||||
header: "Deskripsi",
|
||||
cell: ({ row }) => <span>{htmlToString(row.getValue("status"))}</span>,
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Aksi",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
Detail
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default columns;
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
PaginationState,
|
||||
SortingState,
|
||||
VisibilityState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import {
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Eye,
|
||||
MoreVertical,
|
||||
Search,
|
||||
SquarePen,
|
||||
Trash2,
|
||||
TrendingDown,
|
||||
TrendingUp,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
|
||||
import { paginationBlog } from "@/service/blog/blog";
|
||||
import { ticketingPagination } from "@/service/ticketing/ticketing";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import TablePagination from "@/components/table/table-pagination";
|
||||
import columns from "./column";
|
||||
import {
|
||||
getPlanningDailyMedsosByPlatform,
|
||||
getPlanningPagination,
|
||||
} from "@/service/agenda-setting/agenda-setting";
|
||||
|
||||
const TaskPlanningSocialMediaTable = (props: {
|
||||
date: string;
|
||||
platform: string;
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||
const [totalData, setTotalData] = React.useState<number>(1);
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[]
|
||||
);
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
const [pagination, setPagination] = React.useState<PaginationState>({
|
||||
pageIndex: 0,
|
||||
pageSize: 10,
|
||||
});
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
onSortingChange: setSorting,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
onRowSelectionChange: setRowSelection,
|
||||
onPaginationChange: setPagination,
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
columnVisibility,
|
||||
rowSelection,
|
||||
pagination,
|
||||
},
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
const pageFromUrl = searchParams?.get("page");
|
||||
if (pageFromUrl) {
|
||||
setPage(Number(pageFromUrl));
|
||||
}
|
||||
}, [searchParams]);
|
||||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit, props]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
const response = await getPlanningDailyMedsosByPlatform(
|
||||
"0",
|
||||
20,
|
||||
props.date,
|
||||
props.platform
|
||||
);
|
||||
const data = response.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
item.no = (page - 1) * limit + index + 1;
|
||||
item.platformTypeId =
|
||||
props.platform === "1"
|
||||
? "Facebook"
|
||||
: props.platform === "2"
|
||||
? "Instagram"
|
||||
: props.platform === "3"
|
||||
? "Youtube"
|
||||
: props.platform === "4"
|
||||
? "Tiktok"
|
||||
: props.platform === "3"
|
||||
? "X"
|
||||
: "";
|
||||
});
|
||||
|
||||
setDataTable(contentData);
|
||||
setTotalData(data?.totalElements);
|
||||
setTotalPage(data?.totalPages);
|
||||
} catch (error) {
|
||||
console.error("Error fetching tasks:", error);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<Table className="overflow-hidden mt-3">
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id} className="bg-default-200">
|
||||
{headerGroup.headers.map((header) => (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
className="h-[75px]"
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination
|
||||
table={table}
|
||||
totalData={totalData}
|
||||
totalPage={totalPage}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TaskPlanningSocialMediaTable;
|
||||
585
lib/menus.ts
585
lib/menus.ts
|
|
@ -31,7 +31,6 @@ export type Group = {
|
|||
};
|
||||
|
||||
export function getMenuList(pathname: string, t: any): Group[] {
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
const levelNumber = getCookiesDecrypt("ulne");
|
||||
const userLevelId = getCookiesDecrypt("ulie");
|
||||
|
|
@ -1383,300 +1382,300 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
|
||||
if (Number(roleId) == 9) {
|
||||
menusSelected = [
|
||||
{
|
||||
groupLabel: t("apps"),
|
||||
id: "dashboard",
|
||||
menus: [
|
||||
{
|
||||
id: "dashboard",
|
||||
href: "/dashboard",
|
||||
label: t("dashboard"),
|
||||
active: pathname.includes("/dashboard"),
|
||||
icon: "material-symbols:dashboard",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "ticketing",
|
||||
menus: [
|
||||
{
|
||||
id: "ticketing",
|
||||
href: "/supervisor/ticketing",
|
||||
label: t("ticketing"),
|
||||
active: pathname.includes("/ticketing"),
|
||||
icon: "mdi:ticket-outline",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "knowledge-base",
|
||||
menus: [
|
||||
{
|
||||
id: "knowledge-base",
|
||||
href: "/supervisor/knowledge-base",
|
||||
label: t("knowledge-base"),
|
||||
active: pathname.includes("/knowledge-base"),
|
||||
icon: "hugeicons:knowledge-02",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "faq",
|
||||
menus: [
|
||||
{
|
||||
id: "faq",
|
||||
href: "/supervisor/faq",
|
||||
label: t("faq"),
|
||||
active: pathname.includes("/frequently-asked-question"),
|
||||
icon: "wpf:faq",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "communication",
|
||||
menus: [
|
||||
{
|
||||
id: "communication",
|
||||
href: "/supervisor/communications",
|
||||
label: t("communication"),
|
||||
active: pathname.includes("/communications"),
|
||||
icon: "icon-park-outline:communication",
|
||||
submenus: [
|
||||
{
|
||||
href: "/supervisor/communications/questions",
|
||||
label: t("questions"),
|
||||
active: pathname.includes("/communications/questions"),
|
||||
icon: "solar:inbox-line-outline",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/supervisor/communications/internal",
|
||||
label: t("internal"),
|
||||
active: pathname.includes("/communications/internal"),
|
||||
icon: "ri:chat-private-line",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/supervisor/communications/forward",
|
||||
label: t("forward"),
|
||||
active: pathname.includes("/communications/forward"),
|
||||
icon: "ri:share-forward-2-fill",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/supervisor/communications/collaboration",
|
||||
label: t("collaboration"),
|
||||
active: pathname.includes("/communications/collaboration"),
|
||||
icon: "clarity:employee-group-line",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/supervisor/communications/account-report",
|
||||
label: t("account-report"),
|
||||
active: pathname.includes("/communications/account-report"),
|
||||
icon: "uiw:user-delete",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "settings",
|
||||
menus: [
|
||||
{
|
||||
id: "settings",
|
||||
href: "/supervisor/settings",
|
||||
label: t("settings"),
|
||||
active: pathname.includes("/settings"),
|
||||
icon: "uil:setting",
|
||||
submenus: [
|
||||
{
|
||||
href: "/settings/feedback",
|
||||
label: t("feedback"),
|
||||
active: pathname.includes("/settings/feedback"),
|
||||
icon: "clarity:employee-group-line",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/settings/social-media",
|
||||
label: t("social-media"),
|
||||
active: pathname.includes("/settings/social-media"),
|
||||
icon: "clarity:employee-group-line",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
{
|
||||
groupLabel: t("apps"),
|
||||
id: "dashboard",
|
||||
menus: [
|
||||
{
|
||||
id: "dashboard",
|
||||
href: "/dashboard",
|
||||
label: t("dashboard"),
|
||||
active: pathname.includes("/dashboard"),
|
||||
icon: "material-symbols:dashboard",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "ticketing",
|
||||
menus: [
|
||||
{
|
||||
id: "ticketing",
|
||||
href: "/supervisor/ticketing",
|
||||
label: t("ticketing"),
|
||||
active: pathname.includes("/ticketing"),
|
||||
icon: "mdi:ticket-outline",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "knowledge-base",
|
||||
menus: [
|
||||
{
|
||||
id: "knowledge-base",
|
||||
href: "/supervisor/knowledge-base",
|
||||
label: t("knowledge-base"),
|
||||
active: pathname.includes("/knowledge-base"),
|
||||
icon: "hugeicons:knowledge-02",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "faq",
|
||||
menus: [
|
||||
{
|
||||
id: "faq",
|
||||
href: "/supervisor/faq",
|
||||
label: t("faq"),
|
||||
active: pathname.includes("/frequently-asked-question"),
|
||||
icon: "wpf:faq",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "communication",
|
||||
menus: [
|
||||
{
|
||||
id: "communication",
|
||||
href: "/supervisor/communications",
|
||||
label: t("communication"),
|
||||
active: pathname.includes("/communications"),
|
||||
icon: "icon-park-outline:communication",
|
||||
submenus: [
|
||||
{
|
||||
href: "/supervisor/communications/questions",
|
||||
label: t("questions"),
|
||||
active: pathname.includes("/communications/questions"),
|
||||
icon: "solar:inbox-line-outline",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/supervisor/communications/internal",
|
||||
label: t("internal"),
|
||||
active: pathname.includes("/communications/internal"),
|
||||
icon: "ri:chat-private-line",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/supervisor/communications/forward",
|
||||
label: t("forward"),
|
||||
active: pathname.includes("/communications/forward"),
|
||||
icon: "ri:share-forward-2-fill",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/supervisor/communications/collaboration",
|
||||
label: t("collaboration"),
|
||||
active: pathname.includes("/communications/collaboration"),
|
||||
icon: "clarity:employee-group-line",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/supervisor/communications/account-report",
|
||||
label: t("account-report"),
|
||||
active: pathname.includes("/communications/account-report"),
|
||||
icon: "uiw:user-delete",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "settings",
|
||||
menus: [
|
||||
{
|
||||
id: "settings",
|
||||
href: "/supervisor/settings",
|
||||
label: t("settings"),
|
||||
active: pathname.includes("/settings"),
|
||||
icon: "uil:setting",
|
||||
submenus: [
|
||||
{
|
||||
href: "/settings/feedback",
|
||||
label: t("feedback"),
|
||||
active: pathname.includes("/settings/feedback"),
|
||||
icon: "clarity:employee-group-line",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/settings/social-media",
|
||||
label: t("social-media"),
|
||||
active: pathname.includes("/settings/social-media"),
|
||||
icon: "clarity:employee-group-line",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
} else if (Number(roleId) == 11) {
|
||||
menusSelected = [
|
||||
{
|
||||
groupLabel: t("apps"),
|
||||
id: "dashboard",
|
||||
menus: [
|
||||
{
|
||||
id: "dashboard",
|
||||
href: "/dashboard",
|
||||
label: t("dashboard"),
|
||||
active: pathname.includes("/dashboard"),
|
||||
icon: "material-symbols:dashboard",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "content-production",
|
||||
menus: [
|
||||
{
|
||||
id: "content-production",
|
||||
href: "/curator/content-production",
|
||||
label: t("content-production"),
|
||||
active: pathname.includes("/content-production"),
|
||||
icon: "fluent:content-view-gallery-16-regular",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "pattern-relation",
|
||||
menus: [
|
||||
{
|
||||
id: "pattern-relation",
|
||||
href: "/curator/pattern-relation",
|
||||
label: t("pattern-relation"),
|
||||
active: pathname.includes("/pattern-relation"),
|
||||
icon: "oui:app-index-pattern",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "agenda-setting",
|
||||
menus: [
|
||||
{
|
||||
id: "agenda-setting",
|
||||
href: "/curator/agenda-setting",
|
||||
label: t("agenda-setting"),
|
||||
active: pathname.includes("/agenda-setting"),
|
||||
icon: "iconoir:journal-page",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "task-plan",
|
||||
menus: [
|
||||
{
|
||||
id: "task-plan",
|
||||
href: "/curator/task-plan",
|
||||
label: t("task-plan"),
|
||||
active: pathname.includes("/task-plan"),
|
||||
icon: "pajamas:planning",
|
||||
submenus: [
|
||||
{
|
||||
href: "/curator/task-plan/mediahub",
|
||||
label: "mediaHub",
|
||||
active: pathname === "/task-plan/mediahub",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/curator/task-plan/medsos-mediahub",
|
||||
label: "medsos mediahub",
|
||||
active: pathname === "/task-plan/medsos-mediahub",
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "curatedcontent",
|
||||
menus: [
|
||||
{
|
||||
id: "curatedcontent",
|
||||
href: "/shared/curated-content",
|
||||
label: t("curated-content"),
|
||||
active: pathname.includes("/curated-content"),
|
||||
icon: "pixelarticons:calendar-text",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "media-tracking",
|
||||
menus: [
|
||||
{
|
||||
id: "media-tracking",
|
||||
href: "/curator/media-tracking",
|
||||
label: t("media-tracking"),
|
||||
active: pathname.includes("/media-tracking"),
|
||||
icon: "material-symbols:map-search-outline",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "communication",
|
||||
menus: [
|
||||
{
|
||||
id: "communication",
|
||||
href: "/shared/communication",
|
||||
label: t("communication"),
|
||||
active: pathname.includes("/communication"),
|
||||
icon: "token:chat",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "contest",
|
||||
menus: [
|
||||
{
|
||||
id: "contest",
|
||||
href: "/shared/contest",
|
||||
label: t("contest"),
|
||||
active: pathname.includes("/contest"),
|
||||
icon: "ic:outline-emoji-events",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "feedback",
|
||||
menus: [
|
||||
{
|
||||
id: "feedback",
|
||||
href: "/curator/feedback",
|
||||
label: t("feedback"),
|
||||
active: pathname.includes("/feedback"),
|
||||
icon: "mdi:feedback-outline",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
{
|
||||
groupLabel: t("apps"),
|
||||
id: "dashboard",
|
||||
menus: [
|
||||
{
|
||||
id: "dashboard",
|
||||
href: "/dashboard",
|
||||
label: t("dashboard"),
|
||||
active: pathname.includes("/dashboard"),
|
||||
icon: "material-symbols:dashboard",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "content-production",
|
||||
menus: [
|
||||
{
|
||||
id: "content-production",
|
||||
href: "/curator/content-production",
|
||||
label: t("content-production"),
|
||||
active: pathname.includes("/content-production"),
|
||||
icon: "fluent:content-view-gallery-16-regular",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "pattern-relation",
|
||||
menus: [
|
||||
{
|
||||
id: "pattern-relation",
|
||||
href: "/curator/pattern-relation",
|
||||
label: t("pattern-relation"),
|
||||
active: pathname.includes("/pattern-relation"),
|
||||
icon: "oui:app-index-pattern",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "agenda-setting",
|
||||
menus: [
|
||||
{
|
||||
id: "agenda-setting",
|
||||
href: "/contributor/agenda-setting",
|
||||
label: t("agenda-setting"),
|
||||
active: pathname.includes("/agenda-setting"),
|
||||
icon: "iconoir:journal-page",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "task-plan",
|
||||
menus: [
|
||||
{
|
||||
id: "task-plan",
|
||||
href: "/curator/task-plan",
|
||||
label: t("task-plan"),
|
||||
active: pathname.includes("/task-plan"),
|
||||
icon: "pajamas:planning",
|
||||
submenus: [
|
||||
{
|
||||
href: "/curator/task-plan/mediahub",
|
||||
label: "mediaHub",
|
||||
active: pathname === "/task-plan/mediahub",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/curator/task-plan/medsos-mediahub",
|
||||
label: "medsos mediahub",
|
||||
active: pathname === "/task-plan/medsos-mediahub",
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "curatedcontent",
|
||||
menus: [
|
||||
{
|
||||
id: "curatedcontent",
|
||||
href: "/shared/curated-content",
|
||||
label: t("curated-content"),
|
||||
active: pathname.includes("/curated-content"),
|
||||
icon: "pixelarticons:calendar-text",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "media-tracking",
|
||||
menus: [
|
||||
{
|
||||
id: "media-tracking",
|
||||
href: "/curator/media-tracking",
|
||||
label: t("media-tracking"),
|
||||
active: pathname.includes("/media-tracking"),
|
||||
icon: "material-symbols:map-search-outline",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "communication",
|
||||
menus: [
|
||||
{
|
||||
id: "communication",
|
||||
href: "/shared/communication",
|
||||
label: t("communication"),
|
||||
active: pathname.includes("/communication"),
|
||||
icon: "token:chat",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "contest",
|
||||
menus: [
|
||||
{
|
||||
id: "contest",
|
||||
href: "/shared/contest",
|
||||
label: t("contest"),
|
||||
active: pathname.includes("/contest"),
|
||||
icon: "ic:outline-emoji-events",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "feedback",
|
||||
menus: [
|
||||
{
|
||||
id: "feedback",
|
||||
href: "/curator/feedback",
|
||||
label: t("feedback"),
|
||||
active: pathname.includes("/feedback"),
|
||||
icon: "mdi:feedback-outline",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return menusSelected;
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
"@types/cleave.js": "^1.4.12",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/next": "^9.0.0",
|
||||
"@types/qs": "^6.9.17",
|
||||
"@types/react-google-recaptcha": "^2.1.9",
|
||||
"@types/react-html-parser": "^2.0.6",
|
||||
|
|
@ -88,7 +89,7 @@
|
|||
"leaflet": "^1.9.4",
|
||||
"lucide-react": "^0.390.0",
|
||||
"moment": "^2.30.1",
|
||||
"next": "14.2.3",
|
||||
"next": "^14.2.3",
|
||||
"next-intl": "^3.19.1",
|
||||
"next-themes": "^0.3.0",
|
||||
"nextra": "^2.13.4",
|
||||
|
|
@ -155,7 +156,6 @@
|
|||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
|
|
@ -841,7 +841,6 @@
|
|||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"string-width": "^5.1.2",
|
||||
"string-width-cjs": "npm:string-width@^4.2.0",
|
||||
|
|
@ -858,7 +857,6 @@
|
|||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -870,7 +868,6 @@
|
|||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.0.1"
|
||||
},
|
||||
|
|
@ -1206,7 +1203,6 @@
|
|||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "2.0.5",
|
||||
"run-parallel": "^1.1.9"
|
||||
|
|
@ -1219,7 +1215,6 @@
|
|||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
|
||||
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
|
|
@ -1228,7 +1223,6 @@
|
|||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
|
||||
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nodelib/fs.scandir": "2.1.5",
|
||||
"fastq": "^1.6.0"
|
||||
|
|
@ -1250,7 +1244,6 @@
|
|||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
|
|
@ -3119,6 +3112,15 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz",
|
||||
"integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g=="
|
||||
},
|
||||
"node_modules/@types/next": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/next/-/next-9.0.0.tgz",
|
||||
"integrity": "sha512-gnBXM8rP1mnCgT1uE2z8SnpFTKRWReJlhbZLZkOLq/CH1ifvTNwjIVtXvsywTy1dwVklf+y/MB0Eh6FOa94yrg==",
|
||||
"deprecated": "This is a stub types definition. next provides its own type definitions, so you do not need this installed.",
|
||||
"dependencies": {
|
||||
"next": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.17.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.9.tgz",
|
||||
|
|
@ -3440,7 +3442,6 @@
|
|||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
|
|
@ -3454,7 +3455,6 @@
|
|||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
|
|
@ -3468,14 +3468,12 @@
|
|||
"node_modules/any-promise": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
||||
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
|
|
@ -3520,8 +3518,7 @@
|
|||
"node_modules/arg": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
||||
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
|
|
@ -3812,14 +3809,12 @@
|
|||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
|
|
@ -3841,7 +3836,6 @@
|
|||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fill-range": "^7.1.1"
|
||||
},
|
||||
|
|
@ -3901,7 +3895,6 @@
|
|||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
|
|
@ -4001,7 +3994,6 @@
|
|||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
|
|
@ -4025,7 +4017,6 @@
|
|||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
|
|
@ -4210,7 +4201,6 @@
|
|||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
|
|
@ -4234,7 +4224,6 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"cssesc": "bin/cssesc"
|
||||
},
|
||||
|
|
@ -4910,8 +4899,7 @@
|
|||
"node_modules/didyoumean": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "5.2.0",
|
||||
|
|
@ -4936,8 +4924,7 @@
|
|||
"node_modules/dlv": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
"version": "3.0.0",
|
||||
|
|
@ -5038,8 +5025,7 @@
|
|||
"node_modules/eastasianwidth": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
|
||||
},
|
||||
"node_modules/elkjs": {
|
||||
"version": "0.9.3",
|
||||
|
|
@ -5087,8 +5073,7 @@
|
|||
"node_modules/emoji-regex": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
|
||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.17.1",
|
||||
|
|
@ -5928,7 +5913,6 @@
|
|||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
||||
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
|
|
@ -5944,7 +5928,6 @@
|
|||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
|
|
@ -5968,7 +5951,6 @@
|
|||
"version": "1.17.1",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
|
||||
"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
|
|
@ -6012,7 +5994,6 @@
|
|||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
|
|
@ -6103,7 +6084,6 @@
|
|||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
|
||||
"integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.0",
|
||||
"signal-exit": "^4.0.1"
|
||||
|
|
@ -6314,7 +6294,6 @@
|
|||
"version": "10.3.10",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
|
||||
"integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.1.0",
|
||||
"jackspeak": "^2.3.5",
|
||||
|
|
@ -6336,7 +6315,6 @@
|
|||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.3"
|
||||
},
|
||||
|
|
@ -6348,7 +6326,6 @@
|
|||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
|
|
@ -6357,7 +6334,6 @@
|
|||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
|
|
@ -7325,7 +7301,6 @@
|
|||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
},
|
||||
|
|
@ -7457,7 +7432,6 @@
|
|||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -7481,7 +7455,6 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
|
|
@ -7505,7 +7478,6 @@
|
|||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
|
|
@ -7550,7 +7522,6 @@
|
|||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
|
|
@ -7799,7 +7770,6 @@
|
|||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
|
||||
"integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@isaacs/cliui": "^8.0.2"
|
||||
},
|
||||
|
|
@ -7817,7 +7787,6 @@
|
|||
"version": "1.21.6",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
|
||||
"integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"jiti": "bin/jiti.js"
|
||||
}
|
||||
|
|
@ -8073,7 +8042,6 @@
|
|||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
|
||||
"integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
|
|
@ -8182,8 +8150,7 @@
|
|||
"node_modules/lru-cache": {
|
||||
"version": "10.4.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
|
||||
},
|
||||
"node_modules/lucide-react": {
|
||||
"version": "0.390.0",
|
||||
|
|
@ -8897,7 +8864,6 @@
|
|||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
|
|
@ -9685,7 +9651,6 @@
|
|||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"braces": "^3.0.3",
|
||||
"picomatch": "^2.3.1"
|
||||
|
|
@ -9746,7 +9711,6 @@
|
|||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
|
|
@ -9795,7 +9759,6 @@
|
|||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"any-promise": "^1.0.0",
|
||||
"object-assign": "^4.0.1",
|
||||
|
|
@ -10072,7 +10035,6 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -10119,7 +10081,6 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
|
||||
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
|
|
@ -10418,7 +10379,6 @@
|
|||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
|
|
@ -10432,7 +10392,6 @@
|
|||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
|
||||
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^10.2.0",
|
||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
|
|
@ -10471,7 +10430,6 @@
|
|||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
|
|
@ -10483,7 +10441,6 @@
|
|||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -10492,7 +10449,6 @@
|
|||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
|
||||
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
|
|
@ -10510,7 +10466,6 @@
|
|||
"version": "8.4.49",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
|
||||
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
|
@ -10538,7 +10493,6 @@
|
|||
"version": "15.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
|
||||
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.0.0",
|
||||
"read-cache": "^1.0.0",
|
||||
|
|
@ -10555,7 +10509,6 @@
|
|||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
|
||||
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"camelcase-css": "^2.0.1"
|
||||
},
|
||||
|
|
@ -10574,7 +10527,6 @@
|
|||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
|
||||
"integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
|
@ -10609,7 +10561,6 @@
|
|||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz",
|
||||
"integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
|
|
@ -10621,7 +10572,6 @@
|
|||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
|
||||
"integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
|
@ -10646,7 +10596,6 @@
|
|||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
|
||||
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
|
|
@ -10658,8 +10607,7 @@
|
|||
"node_modules/postcss-value-parser": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
||||
},
|
||||
"node_modules/preact": {
|
||||
"version": "10.12.1",
|
||||
|
|
@ -10753,7 +10701,6 @@
|
|||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
|
|
@ -11304,7 +11251,6 @@
|
|||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"pify": "^2.3.0"
|
||||
}
|
||||
|
|
@ -11313,7 +11259,6 @@
|
|||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
|
|
@ -11736,7 +11681,6 @@
|
|||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"iojs": ">=1.0.0",
|
||||
"node": ">=0.10.0"
|
||||
|
|
@ -11809,7 +11753,6 @@
|
|||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
|
|
@ -12001,7 +11944,6 @@
|
|||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
},
|
||||
|
|
@ -12013,7 +11955,6 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
|
|
@ -12050,7 +11991,6 @@
|
|||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
|
|
@ -12180,7 +12120,6 @@
|
|||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
||||
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"eastasianwidth": "^0.2.0",
|
||||
"emoji-regex": "^9.2.2",
|
||||
|
|
@ -12198,7 +12137,6 @@
|
|||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
|
|
@ -12211,14 +12149,12 @@
|
|||
"node_modules/string-width-cjs/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"node_modules/string-width/node_modules/ansi-regex": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -12230,7 +12166,6 @@
|
|||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.0.1"
|
||||
},
|
||||
|
|
@ -12366,7 +12301,6 @@
|
|||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
|
|
@ -12379,7 +12313,6 @@
|
|||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
|
|
@ -12484,7 +12417,6 @@
|
|||
"version": "3.35.0",
|
||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
|
||||
"integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
"commander": "^4.0.0",
|
||||
|
|
@ -12506,7 +12438,6 @@
|
|||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
||||
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
|
|
@ -12680,7 +12611,6 @@
|
|||
"version": "3.4.16",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.16.tgz",
|
||||
"integrity": "sha512-TI4Cyx7gDiZ6r44ewaJmt0o6BrMCT5aK5e0rmJ/G9Xq3w7CX/5VXl/zIPEJZFUK5VEqwByyhqNPycPlvcK4ZNw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
"arg": "^5.0.2",
|
||||
|
|
@ -12740,7 +12670,6 @@
|
|||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
||||
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"any-promise": "^1.0.0"
|
||||
}
|
||||
|
|
@ -12749,7 +12678,6 @@
|
|||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
|
||||
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"thenify": ">= 3.1.0 < 4"
|
||||
},
|
||||
|
|
@ -12862,7 +12790,6 @@
|
|||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
|
|
@ -12925,8 +12852,7 @@
|
|||
"node_modules/ts-interface-checker": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
||||
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.15.0",
|
||||
|
|
@ -13404,8 +13330,7 @@
|
|||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "9.0.1",
|
||||
|
|
@ -13644,7 +13569,6 @@
|
|||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"isexe": "^2.0.0"
|
||||
},
|
||||
|
|
@ -13751,7 +13675,6 @@
|
|||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
||||
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.1.0",
|
||||
"string-width": "^5.0.1",
|
||||
|
|
@ -13769,7 +13692,6 @@
|
|||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
|
|
@ -13785,14 +13707,12 @@
|
|||
"node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
|
|
@ -13806,7 +13726,6 @@
|
|||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -13818,7 +13737,6 @@
|
|||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
|
||||
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -13830,7 +13748,6 @@
|
|||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.0.1"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@
|
|||
"@types/cleave.js": "^1.4.12",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/next": "^9.0.0",
|
||||
"@types/qs": "^6.9.17",
|
||||
"@types/react-google-recaptcha": "^2.1.9",
|
||||
"@types/react-html-parser": "^2.0.6",
|
||||
|
|
@ -89,7 +90,7 @@
|
|||
"leaflet": "^1.9.4",
|
||||
"lucide-react": "^0.390.0",
|
||||
"moment": "^2.30.1",
|
||||
"next": "14.2.3",
|
||||
"next": "^14.2.3",
|
||||
"next-intl": "^3.19.1",
|
||||
"next-themes": "^0.3.0",
|
||||
"nextra": "^2.13.4",
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export async function getPlanningDailyByTypeId(
|
|||
return getAPIInterceptor(url);
|
||||
}
|
||||
|
||||
export async function getMonthlyPlanList(dates: number, typeId: number) {
|
||||
export async function getMonthlyPlanList(dates: any, typeId: number) {
|
||||
const url = `planning/monthly/list?date=${dates}&typeId=${typeId}`;
|
||||
return getAPIInterceptor(url);
|
||||
}
|
||||
|
|
@ -63,3 +63,23 @@ export async function savePlanning(data: any) {
|
|||
const url = "planning";
|
||||
return postAPIInterceptor(url, data);
|
||||
}
|
||||
|
||||
export async function getPlanningMonthlyPerSocmed(
|
||||
month = "",
|
||||
year = "",
|
||||
typeId: number,
|
||||
parentId = ""
|
||||
) {
|
||||
const url = `planning/socmed/monthly?month=${month}&year=${year}&typeId=${typeId}&parentId=${parentId}`;
|
||||
return getAPIInterceptor(url);
|
||||
}
|
||||
|
||||
export async function getPlanningDailyMedsosByPlatform(
|
||||
page: string,
|
||||
size = 10,
|
||||
date: string,
|
||||
platformTypeId: string
|
||||
) {
|
||||
const url = `planning/pagination/daily?enablePage=1&size=${size}&page=${page}&date=${date}&typeId=2&platformTypeId=${platformTypeId}`;
|
||||
return getAPIInterceptor(url);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ export async function getCategoryData() {
|
|||
|
||||
export async function getListContent(props: any) {
|
||||
return await httpGetInterceptor(
|
||||
`media/public/list?enablePage=1&sort=desc&sortBy=${props.sortBy}&size=${props.size}&page=${props.page}&typeId=${props.contentTypeId}&title=&categoryId=&fileFormats=&tags=&group=&startDate=&endDate=&month=&year=`
|
||||
`media/public/list?enablePage=1&sort=desc&sortBy=${props.sortBy}&size=${props.size}&page=${props.page}&typeId=${props.contentTypeId}&title=${
|
||||
props.title ? props.title : ""
|
||||
}&categoryId=&fileFormats=&tags=&group=&startDate=&endDate=&month=&year=`
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -42,4 +44,22 @@ export async function listCategory(type = "") {
|
|||
return await httpGetInterceptor(`media/categories/list/enable?enablePage=1&sort=desc&sortBy=updatedAt&size=12&type=${type}`);
|
||||
}
|
||||
|
||||
export async function publicDetailBlog(slug: any) {
|
||||
return await httpGetInterceptor(`blog/public/read/${slug}`);
|
||||
}
|
||||
|
||||
export async function listData(type: string, search: string, category: string, size = 10, page = 0, sortBy = "createdAt", format = "", tag = "", group = "", startDate = "", endDate = "", month = "", year = "") {
|
||||
return await httpGetInterceptor(
|
||||
`media/public/list?enablePage=1&sort=desc&sortBy=${sortBy}&size=${size}&page=${page}&typeId=${type}&title=${search}&categoryId=${category}&fileFormats=${format}&tags=${tag}&group=${group}&startDate=${startDate}&endDate=${endDate}&month=${month}&year=${year}`
|
||||
);
|
||||
}
|
||||
|
||||
export async function listDataRegional(type: string, search: string, category: string, format = "", tag = "", startDate = "", endDate = "", month = "", year = "", size = 10, page = 0, sortBy = "createdAt") {
|
||||
return await httpGetInterceptor(
|
||||
`media/public/regional-list?enablePage=1&size=${size}&page=${page}&sort=desc&sortBy=${sortBy}&typeId=${type}&title=${search}&categoryId=${category}&fileFormats=${format}&tags=${tag}&startDate=${startDate}&endDate=${endDate}&month=${month}&year=${year}`
|
||||
);
|
||||
}
|
||||
|
||||
export async function getUserLevelListByParent(id: any) {
|
||||
return await httpGetInterceptor(`users/user-levels/list?userLevelId=${id}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
import { getAPIInterceptor } from "@/config/api";
|
||||
|
||||
export async function getMediaTrackingMonitoring(page: number, size: number) {
|
||||
const url = `cekmedsos/monitoring/pagination?page=${page}&size=${size}`;
|
||||
return getAPIInterceptor(url);
|
||||
}
|
||||
|
|
@ -63,3 +63,9 @@ export function getOnlyDate(date: Date) {
|
|||
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
export function getOnlyMonthAndYear(d: Date) {
|
||||
const pad = (n: any, s = 2) => `${new Array(s).fill(0)}${n}`.slice(-s);
|
||||
return `${pad(d.getMonth() + 1)}/${pad(d.getFullYear(), 4)}`;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue