feat: add polda section

This commit is contained in:
sabdayagra 2024-12-31 15:31:18 +07:00
commit ef57c42210
23 changed files with 1454 additions and 406 deletions

View File

@ -18,6 +18,7 @@ import EventModal from "./event-modal";
import { useTranslations } from "next-intl";
import { getAgendaSettingsList } from "@/service/agenda-setting/agenda-setting";
import dayjs from "dayjs";
import { getCookiesDecrypt } from "@/lib/utils";
const wait = () => new Promise((resolve) => setTimeout(resolve, 1000));
interface CalendarViewProps {
events: CalendarEvent[];
@ -66,7 +67,7 @@ const CalendarView = ({ events, categories }: CalendarViewProps) => {
// const [selectedEvent, setSelectedEvent] = useState<CalendarEvent | null>(
// null
// );
const roleId = Number(getCookiesDecrypt("urie")) || 0;
const [apiEvents, setApiEvents] = useState<CalendarEvent[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [draggableInitialized, setDraggableInitialized] =
@ -246,15 +247,17 @@ const CalendarView = ({ events, categories }: CalendarViewProps) => {
<div className="grid grid-cols-12 gap-6 divide-x divide-border">
<Card className="col-span-12 lg:col-span-4 2xl:col-span-3 pb-5">
<CardContent className="p-0">
<CardHeader className="border-none mb-2 pt-5">
<Button
onClick={handleDateClick}
className="dark:bg-background dark:text-foreground"
>
<Plus className="w-4 h-4 me-1" />
{"Tambahkan Agenda baru"}
</Button>
</CardHeader>
{roleId === 11 && (
<CardHeader className="border-none mb-2 pt-5">
<Button
onClick={handleDateClick}
className="dark:bg-background dark:text-foreground"
>
<Plus className="w-4 h-4 me-1" />
{"Tambahkan Agenda baru"}
</Button>
</CardHeader>
)}
<div className="px-3">
<Calendar
mode="single"

View File

@ -110,6 +110,12 @@ export const calendarCategories = [
activeClass: "ring-danger-500 bg-danger-500",
className: " group-hover:border-red-500",
},
{
label: "Satker",
value: "satker",
activeClass: "ring-yellow-500 bg-yellow-500",
className: " group-hover:border-red-500",
},
{
label: "Internasional",
value: "international",
@ -138,6 +144,12 @@ export const categories = [
className:
"data-[state=checked]:bg-destructive data-[state=checked]:ring-destructive ",
},
{
label: "Satker",
value: "satker",
className:
"data-[state=checked]:bg-warning data-[state=checked]:ring-warning ",
},
{
label: "Internasional",
value: "international",

View File

@ -21,7 +21,7 @@ import {
import { Calendar } from "@/components/ui/calendar";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { Loader2, CalendarIcon } from "lucide-react";
import { Loader2, CalendarIcon, ChevronUp, ChevronDown } from "lucide-react";
import DeleteConfirmationDialog from "@/components/delete-confirmation-dialog";
import { CalendarCategory } from "./data";
import {
@ -29,6 +29,7 @@ import {
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Textarea } from "@/components/ui/textarea";
import { error, loading } from "@/lib/swal";
@ -38,6 +39,9 @@ import withReactContent from "sweetalert2-react-content";
import { useRouter } from "next/navigation";
import { postSchedule } from "@/service/schedule/schedule";
import { saveAgendaSettings } from "@/service/agenda-setting/agenda-setting";
import { Checkbox } from "@/components/ui/checkbox";
import { getUserLevelForAssignments } from "@/service/task";
import { AudioRecorder } from "react-audio-voice-recorder";
const schema = z.object({
title: z.string().min(3, { message: "Required" }),
@ -63,11 +67,17 @@ const EventModal = ({
const [calendarProps, setCalendarProps] = React.useState<any>(
categories[0].value
);
// delete modal state
const [listDest, setListDest] = useState([]);
const [deleteModalOpen, setDeleteModalOpen] = useState<boolean>(false);
const [eventIdToDelete, setEventIdToDelete] = useState<string | null>(null);
const MySwal = withReactContent(Swal);
const router = useRouter();
const [isLoading, setIsLoading] = useState(false);
const [checkedLevels, setCheckedLevels] = useState(new Set());
const [expandedPolda, setExpandedPolda] = useState([{}]);
const [audioFile, setAudioFile] = useState<File | null>(null);
const [isRecording, setIsRecording] = useState(false);
const [timer, setTimer] = useState<number>(120);
const {
register,
@ -81,8 +91,47 @@ const EventModal = ({
mode: "all",
});
useEffect(() => {
async function fetchPoldaPolres() {
setIsLoading(true);
try {
const response = await getUserLevelForAssignments();
setListDest(response.data.data.list);
const initialExpandedState = response.data.data.list.reduce(
(acc: any, polda: any) => {
acc[polda.id] = false;
return acc;
},
{}
);
setExpandedPolda(initialExpandedState);
console.log("polres", initialExpandedState);
} catch (error) {
console.error("Error fetching Polda/Polres data:", error);
} finally {
setIsLoading(false);
}
}
fetchPoldaPolres();
}, []);
const handleCheckboxChange = (levelId: number) => {
setCheckedLevels((prev) => {
const updatedLevels = new Set(prev);
if (updatedLevels.has(levelId)) {
updatedLevels.delete(levelId);
} else {
updatedLevels.add(levelId);
}
return updatedLevels;
});
};
const save = async (data: any) => {
// loading();
if (!audioFile) return;
const formData = new FormData();
formData.append("voiceNote", audioFile);
const reqData = {
title: data.title,
@ -90,6 +139,7 @@ const EventModal = ({
agendaType: calendarProps,
startDate: format(startDate, "yyyy-MM-dd"),
endDate: format(endDate, "yyyy-MM-dd"),
voiceNote: formData,
};
console.log("Submitted Data:", reqData);
@ -146,6 +196,58 @@ const EventModal = ({
onClose();
};
const toggleExpand = (poldaId: any) => {
setExpandedPolda((prev: any) => ({
...prev,
[poldaId]: !prev[poldaId],
}));
};
const onRecordingStart = () => {
setIsRecording(true);
// Start a timer that stops the recording after 2 minutes (120 seconds)
const countdown = setInterval(() => {
setTimer((prevTimer) => {
if (prevTimer <= 1) {
clearInterval(countdown); // Stop the timer when it reaches 0
return 0;
}
return prevTimer - 1;
});
}, 1000); // Update every second
// Automatically stop recording after 2 minutes
setTimeout(() => {
if (isRecording) {
handleStopRecording();
}
}, 120000); // Stop after 2 minutes (120,000 ms)
};
const handleStopRecording = () => {
setIsRecording(false);
setTimer(120); // Reset the timer to 2 minutes for the next recording
};
const addAudioElement = (blob: Blob) => {
const url = URL.createObjectURL(blob);
const audio = document.createElement("audio");
audio.src = url;
audio.controls = true;
document.body.appendChild(audio);
// Convert Blob to File
const file = new File([blob], "voiceNote.webm", { type: "audio/webm" });
setAudioFile(file);
};
const handleDeleteAudio = () => {
// Remove the audio file by setting state to null
setAudioFile(null);
const audioElements = document.querySelectorAll("audio");
audioElements.forEach((audio) => audio.remove());
};
return (
<>
<DeleteConfirmationDialog
@ -155,14 +257,17 @@ const EventModal = ({
defaultToast={false}
/>
<Dialog open={open} onOpenChange={onClose}>
<DialogContent onPointerDownOutside={onClose}>
<DialogContent
onPointerDownOutside={onClose}
className="sm:max-w-[425px] md:max-w-[500px] lg:max-w-[700px] max-h-[80vh] overflow-y-auto"
>
<DialogHeader>
<DialogTitle>
{event ? "Edit Agenda Setting" : "Create Agenda Setting"}{" "}
{event?.title}
</DialogTitle>
</DialogHeader>
<div className="mt-6 h-full">
<div className="mt-6 h-full ">
<form className="h-full" onSubmit={handleSubmit(onSubmit)}>
<div className="space-y-4 pb-5 ">
<div className="space-y-1.5">
@ -181,7 +286,6 @@ const EventModal = ({
</div>
)}
</div>
<div className="space-y-1.5">
<Label htmlFor="startDate">Start Date </Label>
<Popover>
@ -254,7 +358,6 @@ const EventModal = ({
</PopoverContent>
</Popover>
</div>
<div className="space-y-1.5">
<Label htmlFor="calendarProps">Jenis Agenda </Label>
<Controller
@ -282,6 +385,94 @@ const EventModal = ({
)}
/>
</div>
{calendarProps === "polda" && (
<div>
<Dialog>
<DialogTrigger asChild>
<Button variant="soft" size="sm" color="primary">
[Kustom]
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px] md:max-w-[500px] lg:max-w-[1500px]">
<DialogHeader>
<DialogTitle>
Daftar Wilayah Polda dan Polres
</DialogTitle>
</DialogHeader>
<div className="grid grid-cols-2 gap-2 max-h-[400px] overflow-y-auto">
{listDest.map((polda: any) => (
<div key={polda.id} className="border p-2">
<Label className="flex items-center">
<Checkbox
checked={checkedLevels.has(polda.id)}
onCheckedChange={() =>
handleCheckboxChange(polda.id)
}
className="mr-3"
/>
{polda.name}
<button
onClick={() => toggleExpand(polda.id)}
className="ml-2 focus:outline-none"
>
{expandedPolda[polda.id] ? (
<ChevronUp size={16} />
) : (
<ChevronDown size={16} />
)}
</button>
</Label>
{expandedPolda[polda.id] && (
<div className="ml-6 mt-2">
<Label className="block">
<Checkbox
checked={polda?.subDestination?.every(
(polres: any) =>
checkedLevels.has(polres.id)
)}
onCheckedChange={(isChecked) => {
const updatedLevels = new Set(
checkedLevels
);
polda?.subDestination?.forEach(
(polres: any) => {
if (isChecked) {
updatedLevels.add(polres.id);
} else {
updatedLevels.delete(polres.id);
}
}
);
setCheckedLevels(updatedLevels);
}}
className="mr-2"
/>
Pilih Semua Polres
</Label>
{polda?.subDestination?.map((polres: any) => (
<Label
key={polres.id}
className="block mt-1"
>
<Checkbox
checked={checkedLevels.has(polres.id)}
onCheckedChange={() =>
handleCheckboxChange(polres.id)
}
className="mr-2"
/>
{polres.name}
</Label>
))}
</div>
)}
</div>
))}
</div>
</DialogContent>
</Dialog>
</div>
)}
<div className="space-y-1.5">
<Label htmlFor="description">Isi Agenda Setting</Label>
<Textarea
@ -297,8 +488,68 @@ const EventModal = ({
</div>
)}
</div>
<div className="space-y-1.5">
<Label htmlFor="attachments">Lampiran</Label>
<div className="space-y-3">
<div>
<Label>Video</Label>
<Input
type="file"
accept="video/*"
multiple
{...register("attachments.video")}
/>
</div>
<div>
<Label>Foto</Label>
<Input
type="file"
accept="image/*"
multiple
{...register("attachments.photo")}
/>
</div>
<div>
<Label>Teks</Label>
<Input
type="file"
accept="text/plain"
multiple
{...register("attachments.text")}
/>
</div>
<div>
<Label>Voice Note</Label>
<AudioRecorder
onRecordingComplete={addAudioElement}
audioTrackConstraints={{
noiseSuppression: true,
echoCancellation: true,
}}
downloadOnSavePress={true}
downloadFileExtension="webm"
/>
</div>
{audioFile && (
<div className="flex flex-row justify-between items-center">
<p>Voice note ready to submit: {audioFile.name}</p>
<Button
type="button"
onClick={handleDeleteAudio}
size="sm"
color="destructive"
>
X
</Button>
</div>
)}
{isRecording && (
<p>Recording... {timer} seconds remaining</p>
)}{" "}
{/* Display remaining time */}
</div>
</div>
</div>
<div className="flex flex-wrap gap-2 mt-10">
<Button type="submit" disabled={isPending} className="flex-1">
{isPending ? (

View File

@ -0,0 +1,17 @@
import { Card, CardContent } from "@/components/ui/card";
import SiteBreadcrumb from "@/components/site-breadcrumb";
import FormTask from "@/components/form/task/task-form";
import FormContestDetail from "@/components/form/contest/contest-detail-form";
const ContestDetailPage = async () => {
return (
<div>
<SiteBreadcrumb />
<div className="space-y-4">
<FormContestDetail />
</div>
</div>
);
};
export default ContestDetailPage;

View File

@ -1,6 +1,9 @@
import SiteBreadcrumb from "@/components/site-breadcrumb";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import ContestTable from "./components/contest-table";
import { Link } from "@/components/navigation";
import { Button } from "@/components/ui/button";
import { UploadIcon } from "lucide-react";
const ContestPage = () => {
return (
@ -15,12 +18,12 @@ const ContestPage = () => {
Table Lomba
</div>
<div className="flex-none">
{/* <Link href={"/contributor/task/create"}>
<Link href={"/shared/contest/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Buat Penugasan
Buat Lomba
</Button>
</Link> */}
</Link>
</div>
</div>
</CardTitle>

View File

@ -0,0 +1,110 @@
"use client"
import { Button } from "@/components/ui/button"
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { CalendarIcon, Plus } from "lucide-react";
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { z } from "zod"
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { toast } from "@/components/ui/use-toast"
import { Textarea } from "@/components/ui/textarea";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import Image from "next/image";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Calendar } from "@/components/ui/calendar";
import { cn } from "@/lib/utils";
import { format } from "date-fns";
import { useState } from "react";
import { useTranslations } from "next-intl";
import { saveKnowledgeBaseCategory } from "@/service/master/knowledge-base";
const FormSchema = z.object({
name: z.string().min(2, {
message: "Name must be at least 2 characters.",
}),
})
const CreateCategory = ({ onSuccess } : { onSuccess?: () => void } ) => {
const t = useTranslations("TodoApp")
const [isDialogOpen, setIsDialogOpen] = useState<boolean>(false);
const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
defaultValues: {
name: "",
},
})
async function save(data: any) {
const reqData = {
name: data.name
}
const response = await saveKnowledgeBaseCategory(reqData);
if (response?.error) {
return false;
}
toast({
title: "Task created successfully.",
});
if (onSuccess) {
onSuccess();
}
}
function onSubmit(data: z.infer<typeof FormSchema>) {
save(data);
setIsDialogOpen(false);
}
return (
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<DialogTrigger asChild>
<Button fullWidth size="lg" className="dark:bg-background dark:text-foreground">
<Plus className="w-6 h-6 me-1.5" />
Add Category
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader className="mb-4">
<DialogTitle>Add Category</DialogTitle>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel className="text-default-700">Name</FormLabel>
<FormControl>
<Input placeholder="Enter Title" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex justify-end">
<Button type="submit">Submit</Button>
</div>
</form>
</Form>
</DialogContent>
</Dialog>
);
};
export default CreateCategory;

View File

@ -11,8 +11,9 @@ import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs";
import SiteBreadcrumb from "@/components/site-breadcrumb";
import {getKnowledgeBaseCategoryList, getKnowledgeBaseList} from "@/service/master/knowledge-base";
import React from "react";
import {Plus} from "lucide-react";
import {Plus, Trash2} from "lucide-react";
import {Button} from "@/components/ui/button";
import CreateCategory from "./create-category";
const KnowledgeBase = () => {
const [categories, setCategories] = React.useState<any>([]);
@ -47,25 +48,26 @@ const KnowledgeBase = () => {
<Card className="lg:col-span-3 md:col-span-5 col-span-12 h-max">
<CardContent className=" p-6">
<TabsList className="md:flex-col gap-2 flex-wrap md:items-start justify-start">
<Button
fullWidth
size="lg"
className="dark:bg-background dark:ring-background dark:text-foreground"
>
<Plus className="w-6 h-6 me-1.5"/>
Add Category
</Button>
<CreateCategory onSuccess={fetchCategoryList} />
{categories?.map((category: any, index: number) => (
<TabsTrigger
<div>
<TabsTrigger
key={index}
value={`category-${index}`}
onClick={() => {
fetchQuestions(category?.id);
}}
className="data-[state=active]:bg-secondary data-[state=active]:text-default rounded-md px-6 py-3 w-full justify-start"
>
{category?.name}
</TabsTrigger>
>
{category?.name}
<div
className="absolute right-2 top-2 hidden group-hover:inline-flex"
// onClick={() => deleteCategory(category?.id)}
>
<Trash2 className="w-3.5 h-3.5 me-1" />
</div>
</TabsTrigger>
</div>
))}
</TabsList>
</CardContent>

View File

@ -257,13 +257,7 @@ export default function FormImageAI() {
Cookies.set("nulisAIArticleIdTemp", JSON.stringify(articleIds));
};
// const handleArticleIdClick = (articleId: string) => {
// setEditingArticleId(articleId);
// setSelectedArticleId(articleId);
// };
const handleArticleIdClick = async (id: string) => {
// Fetch article details by ID
const res = await getDetailArticle(id);
const articleData = res?.data?.data;
@ -273,7 +267,6 @@ export default function FormImageAI() {
);
const articleImagesData = articleData?.imagesUrl?.split(",");
// Update state with new article data
setArticleBody(cleanArticleBody || "");
setDetailData(articleData);
setSelectedArticleId(id);
@ -283,7 +276,6 @@ export default function FormImageAI() {
const handleEditClick = () => {
if (editingArticleId) {
console.log("Editing article:", editingArticleId);
// Handle the edit action here
}
};
@ -319,8 +311,7 @@ export default function FormImageAI() {
);
if (findCategory) {
// setValue("categoryId", findCategory.id);
setSelectedCategory(findCategory.id); // Set the selected category
setSelectedCategory(findCategory.id);
const response = await getTagsBySubCategoryId(findCategory.id);
setTags(response?.data.data);
}
@ -665,7 +656,7 @@ export default function FormImageAI() {
render={({ field: { onChange, value } }) => (
<JoditEditor
ref={editor}
value={articleBody || value} // Ensure the JoditEditor receives the correct article body
value={articleBody || value}
onChange={onChange}
className="dark:text-black"
/>

View File

@ -225,161 +225,156 @@ export default function FormContestDetail() {
<Card>
<div className="px-6 py-6">
<p className="text-lg font-semibold mb-3">Form Contest</p>
{detail !== undefined ? (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="gap-5 mb-5">
<div className="space-y-2">
<Label>Kode Lomba</Label>
<Controller
control={control}
name="hastagCode"
render={({ field }) => (
<Input
size="md"
type="text"
value={detail?.hastagCode}
onChange={field.onChange}
placeholder="Enter hastagCode"
/>
)}
/>
{errors.hastagCode?.message && (
<p className="text-red-400 text-sm">
{errors.hastagCode.message}
</p>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="gap-5 mb-5">
<div className="space-y-2">
<Label>Kode Lomba</Label>
<Controller
control={control}
name="hastagCode"
render={({ field }) => (
<Input
size="md"
type="text"
value={field.value}
onChange={field.onChange}
placeholder="Enter hastagCode"
/>
)}
</div>
{/* Input Title */}
<div className="space-y-2 mt-5">
<Label>Judul Lomba</Label>
<Controller
control={control}
name="theme"
render={({ field }) => (
<Input
size="md"
type="text"
value={detail?.theme}
onChange={field.onChange}
placeholder="Enter theme"
/>
)}
/>
{errors.theme?.message && (
<p className="text-red-400 text-sm">{errors.theme.message}</p>
/>
{errors.hastagCode?.message && (
<p className="text-red-400 text-sm">
{errors.hastagCode.message}
</p>
)}
</div>
{/* Input Title */}
<div className="space-y-2 mt-5">
<Label>Judul Lomba</Label>
<Controller
control={control}
name="theme"
render={({ field }) => (
<Input
size="md"
type="text"
value={field.value}
onChange={field.onChange}
placeholder="Enter theme"
/>
)}
</div>
<div className="flex flex-col mt-5">
<Label className="mr-3 mb-1">Tanggal</Label>
<Popover>
<PopoverTrigger asChild>
<Button
value={detail?.createdAt}
id="date"
variant={"outline"}
className={cn(
"w-[280px] lg:w-[300px] justify-start text-left font-normal",
!date && "text-muted-foreground"
)}
>
<CalendarIcon />
{date?.from ? (
date.to ? (
<>
{format(date.from, "LLL dd, y")} -{" "}
{format(date.to, "LLL dd, y")}
</>
) : (
format(date.from, "LLL dd, y")
)
/>
{errors.theme?.message && (
<p className="text-red-400 text-sm">{errors.theme.message}</p>
)}
</div>
<div className="flex flex-col mt-5">
<Label className="mr-3 mb-1">Tanggal</Label>
<Popover>
<PopoverTrigger asChild>
<Button
value={detail?.createdAt}
id="date"
variant={"outline"}
className={cn(
"w-[280px] lg:w-[300px] justify-start text-left font-normal",
!date && "text-muted-foreground"
)}
>
<CalendarIcon />
{date?.from ? (
date.to ? (
<>
{format(date.from, "LLL dd, y")} -{" "}
{format(date.to, "LLL dd, y")}
</>
) : (
<span>Pick a date</span>
)}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
initialFocus
mode="range"
defaultMonth={date?.from}
selected={date}
onSelect={setDate}
numberOfMonths={1}
format(date.from, "LLL dd, y")
)
) : (
<span>Pick a date</span>
)}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
initialFocus
mode="range"
defaultMonth={date?.from}
selected={date}
onSelect={setDate}
numberOfMonths={1}
/>
</PopoverContent>
</Popover>
</div>
<div className="mt-5">
<Label>Output Lomba</Label>
<div className="flex flex-wrap gap-3 mt-2">
{Object.keys(taskOutput).map((key) => (
<div className="flex items-center gap-2" key={key}>
<Checkbox
id={key}
checked={taskOutput[key as keyof typeof taskOutput]}
onCheckedChange={(value) =>
setTaskOutput({ ...taskOutput, [key]: value })
}
/>
</PopoverContent>
</Popover>
</div>
<div className="mt-5">
<Label>Output Lomba</Label>
<div className="flex flex-wrap gap-3 mt-2">
{Object.keys(taskOutput).map((key) => (
<div className="flex items-center gap-2" key={key}>
<Checkbox
id={key}
checked={taskOutput[key as keyof typeof taskOutput]}
onCheckedChange={(value) =>
setTaskOutput({ ...taskOutput, [key]: value })
}
/>
<Label htmlFor={key}>
{key.charAt(0).toUpperCase() + key.slice(1)}
</Label>
</div>
))}
</div>
</div>
<div className="flex flex-col mt-7">
<Label>Pelaksana Tugas</Label>
<div className="flex flex-row mt-2 gap-3">
{Object.keys(unitSelection).map((key) => (
<div className="flex items-center gap-2" key={key}>
<Checkbox
id={key}
checked={
unitSelection[key as keyof typeof unitSelection]
}
onCheckedChange={(value) =>
setUnitSelection({ ...unitSelection, [key]: value })
}
/>
<Label htmlFor={key}>
{key.charAt(0).toUpperCase() + key.slice(1)}
</Label>
</div>
))}
</div>
</div>
<div className="mt-7">
<Label>Narasi Penugasan</Label>
<Controller
control={control}
name="description"
render={({ field: { onChange, value } }) => (
<JoditEditor
ref={editor}
value={detail?.description}
onChange={onChange}
className="dark:text-black"
/>
)}
/>
{errors.description?.message && (
<p className="text-red-400 text-sm">
{errors.description.message}
</p>
)}
<Label htmlFor={key}>
{key.charAt(0).toUpperCase() + key.slice(1)}
</Label>
</div>
))}
</div>
</div>
<div className="flex flex-col mt-7">
<Label>Pelaksana Tugas</Label>
<div className="flex flex-row mt-2 gap-3">
{Object.keys(unitSelection).map((key) => (
<div className="flex items-center gap-2" key={key}>
<Checkbox
id={key}
checked={unitSelection[key as keyof typeof unitSelection]}
onCheckedChange={(value) =>
setUnitSelection({ ...unitSelection, [key]: value })
}
/>
<Label htmlFor={key}>
{key.charAt(0).toUpperCase() + key.slice(1)}
</Label>
</div>
))}
</div>
</div>
<div className="mt-7">
<Label>Narasi Penugasan</Label>
<Controller
control={control}
name="description"
render={({ field: { onChange, value } }) => (
<JoditEditor
ref={editor}
value={value}
onChange={onChange}
className="dark:text-black"
/>
)}
/>
{errors.description?.message && (
<p className="text-red-400 text-sm">
{errors.description.message}
</p>
)}
</div>
</div>
{/* <div className="mt-4">
{/* <div className="mt-4">
<Button type="submit" color="primary">
Submit
</Button>
</div> */}
</form>
) : (
""
)}
</form>
</div>
</Card>
);

View File

@ -33,6 +33,7 @@ import {
DialogTrigger,
} from "@/components/ui/dialog";
import { ChevronDown, ChevronUp } from "lucide-react";
import { AudioRecorder } from "react-audio-voice-recorder";
const taskSchema = z.object({
title: z.string().min(1, { message: "Judul diperlukan" }),
@ -82,15 +83,18 @@ export default function FormTask() {
// const [assignmentCategory, setAssignmentCategory] = useState("publication");
const [mainType, setMainType] = useState<string>("1");
const [taskType, setTaskType] = useState<string>("atensi-khusus");
const [broadcastType, setBroadcastType] = useState<string>(""); // untuk Tipe Penugasan
const [broadcastType, setBroadcastType] = useState<string>("");
const [type, setType] = useState<string>("1");
const [selectedTarget, setSelectedTarget] = useState("3,4");
const [detail, setDetail] = useState<taskDetail>();
const [refresh] = useState(false);
const [listDest, setListDest] = useState([]); // Data Polda dan Polres
const [listDest, setListDest] = useState([]);
const [checkedLevels, setCheckedLevels] = useState(new Set());
const [expandedPolda, setExpandedPolda] = useState([{}]);
const [isLoading, setIsLoading] = useState(false);
const [audioFile, setAudioFile] = useState<File | null>(null);
const [isRecording, setIsRecording] = useState(false);
const [timer, setTimer] = useState<number>(120);
const [platformTypeVisible, setPlatformTypeVisible] = useState(false);
const [unitSelection, setUnitSelection] = useState({
@ -101,11 +105,14 @@ export default function FormTask() {
});
const {
register,
control,
setValue,
handleSubmit,
formState: { errors },
} = useForm<TaskSchema>({
resolver: zodResolver(taskSchema),
mode: "all",
});
// const handleRadioChange = (event: React.ChangeEvent<HTMLInputElement>) => {
@ -176,8 +183,8 @@ export default function FormTask() {
.join(",");
const selectedOutputs = Object.keys(taskOutput)
.filter((key) => taskOutput[key as keyof typeof taskOutput]) // Ambil hanya yang `true`
.map((key) => fileTypeMapping[key as keyof typeof fileTypeMapping]) // Konversi ke nilai string
.filter((key) => taskOutput[key as keyof typeof taskOutput])
.map((key) => fileTypeMapping[key as keyof typeof fileTypeMapping])
.join(",");
const requestData: {
@ -249,6 +256,51 @@ export default function FormTask() {
}));
};
const onRecordingStart = () => {
setIsRecording(true);
// Start a timer that stops the recording after 2 minutes (120 seconds)
const countdown = setInterval(() => {
setTimer((prevTimer) => {
if (prevTimer <= 1) {
clearInterval(countdown); // Stop the timer when it reaches 0
return 0;
}
return prevTimer - 1;
});
}, 1000); // Update every second
// Automatically stop recording after 2 minutes
setTimeout(() => {
if (isRecording) {
handleStopRecording();
}
}, 120000); // Stop after 2 minutes (120,000 ms)
};
const handleStopRecording = () => {
setIsRecording(false);
setTimer(120); // Reset the timer to 2 minutes for the next recording
};
const addAudioElement = (blob: Blob) => {
const url = URL.createObjectURL(blob);
const audio = document.createElement("audio");
audio.src = url;
audio.controls = true;
document.body.appendChild(audio);
// Convert Blob to File
const file = new File([blob], "voiceNote.webm", { type: "audio/webm" });
setAudioFile(file);
};
const handleDeleteAudio = () => {
// Remove the audio file by setting state to null
setAudioFile(null);
const audioElements = document.querySelectorAll("audio");
audioElements.forEach((audio) => audio.remove());
};
return (
<Card>
<div className="px-6 py-6">
@ -306,82 +358,87 @@ export default function FormTask() {
</div>
))}
</div>
<Dialog>
<DialogTrigger asChild>
<Button variant="soft" size="sm" color="primary">
[Kustom]
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px] md:max-w-[500px] lg:max-w-[1500px]">
<DialogHeader>
<DialogTitle>Daftar Wilayah Polda dan Polres</DialogTitle>
</DialogHeader>
<div className="grid grid-cols-2 gap-2 max-h-[400px] overflow-y-auto">
{listDest.map((polda: any) => (
<div key={polda.id} className="border p-2">
<Label className="flex items-center">
<Checkbox
checked={checkedLevels.has(polda.id)}
onCheckedChange={() =>
handleCheckboxChange(polda.id)
}
className="mr-3"
/>
{polda.name}
<button
onClick={() => toggleExpand(polda.id)}
className="ml-2 focus:outline-none"
>
{expandedPolda[polda.id] ? (
<ChevronUp size={16} />
) : (
<ChevronDown size={16} />
)}
</button>
</Label>
{expandedPolda[polda.id] && (
<div className="ml-6 mt-2">
<Label className="block">
<Checkbox
checked={polda?.subDestination?.every(
(polres: any) => checkedLevels.has(polres.id)
)}
onCheckedChange={(isChecked) => {
const updatedLevels = new Set(checkedLevels);
polda?.subDestination?.forEach(
(polres: any) => {
if (isChecked) {
updatedLevels.add(polres.id);
} else {
updatedLevels.delete(polres.id);
}
}
);
setCheckedLevels(updatedLevels);
}}
className="mr-2"
/>
Pilih Semua Polres
</Label>
{polda?.subDestination?.map((polres: any) => (
<Label key={polres.id} className="block mt-1">
<div className="mt-6 pt-5 pl-3">
<Dialog>
<DialogTrigger asChild>
<Button variant="soft" size="sm" color="primary">
[Kustom]
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px] md:max-w-[500px] lg:max-w-[1500px]">
<DialogHeader>
<DialogTitle>Daftar Wilayah Polda dan Polres</DialogTitle>
</DialogHeader>
<div className="grid grid-cols-2 gap-2 max-h-[400px] overflow-y-auto">
{listDest.map((polda: any) => (
<div key={polda.id} className="border p-2">
<Label className="flex items-center">
<Checkbox
checked={checkedLevels.has(polda.id)}
onCheckedChange={() =>
handleCheckboxChange(polda.id)
}
className="mr-3"
/>
{polda.name}
<button
onClick={() => toggleExpand(polda.id)}
className="ml-2 focus:outline-none"
>
{expandedPolda[polda.id] ? (
<ChevronUp size={16} />
) : (
<ChevronDown size={16} />
)}
</button>
</Label>
{expandedPolda[polda.id] && (
<div className="ml-6 mt-2">
<Label className="block">
<Checkbox
checked={checkedLevels.has(polres.id)}
onCheckedChange={() =>
handleCheckboxChange(polres.id)
}
checked={polda?.subDestination?.every(
(polres: any) =>
checkedLevels.has(polres.id)
)}
onCheckedChange={(isChecked) => {
const updatedLevels = new Set(
checkedLevels
);
polda?.subDestination?.forEach(
(polres: any) => {
if (isChecked) {
updatedLevels.add(polres.id);
} else {
updatedLevels.delete(polres.id);
}
}
);
setCheckedLevels(updatedLevels);
}}
className="mr-2"
/>
{polres.name}
Pilih Semua Polres
</Label>
))}
</div>
)}
</div>
))}
</div>
</DialogContent>
</Dialog>
{polda?.subDestination?.map((polres: any) => (
<Label key={polres.id} className="block mt-1">
<Checkbox
checked={checkedLevels.has(polres.id)}
onCheckedChange={() =>
handleCheckboxChange(polres.id)
}
className="mr-2"
/>
{polres.name}
</Label>
))}
</div>
)}
</div>
))}
</div>
</DialogContent>
</Dialog>
</div>
</div>
<div className="mt-5">
<Label>Tipe Penugasan</Label>
@ -452,7 +509,7 @@ export default function FormTask() {
))}
</div>
</div>
<div className="mt-5">
{/* <div className="mt-5">
<Label>Broadcast </Label>
<RadioGroup
value={broadcastType} // Nilai terpilih diambil dari state broadcastType
@ -472,7 +529,7 @@ export default function FormTask() {
<Label htmlFor="whatsapp">WhatsApp Blast</Label>
</div>
</RadioGroup>
</div>
</div> */}
<div className="mt-5">
<Label>Narasi Penugasan</Label>
<Controller
@ -493,6 +550,65 @@ export default function FormTask() {
</p>
)}
</div>
<div className="space-y-1.5">
<Label htmlFor="attachments">Lampiran</Label>
<div className="space-y-3">
<div>
<Label>Video</Label>
<Input
type="file"
accept="video/*"
multiple
// {...register("attachments.video")}
/>
</div>
<div>
<Label>Foto</Label>
<Input
type="file"
accept="image/*"
multiple
// {...register("attachments.photo")}
/>
</div>
<div>
<Label>Teks</Label>
<Input
type="file"
accept="text/plain"
multiple
// {...register("attachments.text")}
/>
</div>
<div>
<Label>Voice Note</Label>
<AudioRecorder
onRecordingComplete={addAudioElement}
audioTrackConstraints={{
noiseSuppression: true,
echoCancellation: true,
}}
downloadOnSavePress={true}
downloadFileExtension="webm"
/>
</div>
{audioFile && (
<div className="flex flex-row justify-between items-center">
<p>Voice note ready to submit: {audioFile.name}</p>
<Button
type="button"
onClick={handleDeleteAudio}
size="sm"
color="destructive"
>
X
</Button>
</div>
)}
{isRecording && <p>Recording... {timer} seconds remaining</p>}{" "}
{/* Display remaining time */}
</div>
</div>
</div>
{/* Submit Button */}

View File

@ -56,26 +56,19 @@ const Navbar = () => {
setLanguage(lang);
setIsOpen(false);
};
const [hasMounted, setHasMounted] = useState(false);
// Hooks
useEffect(() => {
setHasMounted(true);
async function initState() {
const response = await getInfoProfile();
const details = response.data?.data;
setDetail(details);
console.log("data", details);
}
initState();
}, []);
// Render;
// if (!hasMounted) return null;
// useEffect(() => {
// async function initState() {
// const response = await getInfoProfile();
// const details = response.data?.data;
// setDetail(details);
// console.log("data", details);
// }
// initState();
// }, []);
return (
<div className="bg-[#f7f7f7] dark:bg-black shadow-md sticky top-0 z-50">

View File

@ -4,15 +4,23 @@ import React from "react";
import { Loader2 } from "lucide-react";
import DashCodeLogo from "./dascode-logo";
import { useMounted } from "@/hooks/use-mounted";
import Image from "next/image";
const Loader = () => {
const mounted = useMounted()
return (
mounted ? null : <div className=" h-screen flex items-center justify-center flex-col space-y-2">
<div className="flex gap-2 items-center ">
<DashCodeLogo className=" text-default-900 h-8 w-8 [&>path:nth-child(3)]:text-background [&>path:nth-child(2)]:text-background" />
<h1 className="text-xl font-semibold text-default-900 ">
{/* <DashCodeLogo className=" text-default-900 h-8 w-8 [&>path:nth-child(3)]:text-background [&>path:nth-child(2)]:text-background" /> */}
<Image
src="/assets/mediahub-logo-min.png"
alt=""
width={80}
height={80}
className="mb-4 w-full h-full"
/>
{/* <h1 className="text-xl font-semibold text-default-900 ">
DashCode
</h1>
</h1> */}
</div>
<span className=" inline-flex gap-1 items-center">
<Loader2 className="mr-2 h-4 w-4 animate-spin" />

View File

@ -0,0 +1,170 @@
"use client";
import { Button } from "@/components/ui/button";
import { Collapsible, CollapsibleContent } from "@/components/ui/collapsible";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { close, loading } from "@/config/swal";
import { Link } from "@/i18n/routing";
import {
getPlanningDailyByTypeId,
getPlanningPagination,
} from "@/service/agenda-setting/agenda-setting";
import { htmlToString, textEllipsis } from "@/utils/globals";
import { MoreVertical } from "lucide-react";
import { useEffect, useState } from "react";
export default function ExpandedData(props: { datas: any }) {
const { datas } = props;
const [isOpen, setIsOpen] = useState("");
const [getData, setGetData] = useState<any>();
const handleIsOpen = (id: string) => {
setIsOpen(id);
};
useEffect(() => {
if (isOpen !== "") {
fetchData();
}
}, [isOpen]);
async function fetchData() {
loading();
const response = await getPlanningPagination(0, "", 10, 1, 1, isOpen);
close();
setupData(response.data?.data);
}
function setupData(rawData: any) {
if (rawData != undefined) {
const dataContent = rawData?.content;
const data = [];
for (const [i, element] of dataContent.entries()) {
element.no = i + 1;
data.push(element);
}
setGetData(data);
}
}
return (
<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">
<a onClick={() => handleIsOpen(data.id)}>{data.title}</a>
</th>
<th
className="font-normal text-sm"
onClick={() =>
`disinni igninn membuat state untuk mennyimpan data isOpen`
}
>
{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/mediahub/create-daily/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-daily/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>
</th>
</tr>
<Collapsible
open={isOpen === data.id}
onOpenChange={() => handleIsOpen(data.id)}
>
<CollapsibleContent className="space-y-2 w-full text-xs">
<tr className="space-x-2">
<th className="px-3">No</th>
<th className="text-left">Judul Perencanaan</th>
<th className="text-left px-3">Nama Pembuat</th>
<th className="text-left px-3">Batas Waktu</th>
<th className="text-left px-3">Status</th>
<th>Aksi</th>
</tr>
{getData?.map((row: any) => (
<tr key={row.id}>
<td className="px-3">{row.no}</td>
<td>{row.title}</td>
<td className="text-left px-3">{row.createdByName}</td>
<td className="text-left px-3">{row.date}</td>
<td className="text-left px-3">{row.status}</td>
<td 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/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>
</td>
</tr>
))}
</CollapsibleContent>
</Collapsible>
</>
))}
</table>
);
}

View File

@ -26,6 +26,8 @@ import {
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Collapsible, CollapsibleContent } from "@/components/ui/collapsible";
import ExpandedData from "./expand-list-view";
const columns: ColumnDef<any>[] = [
{
@ -33,11 +35,7 @@ const columns: ColumnDef<any>[] = [
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",
@ -52,54 +50,7 @@ const columns: ColumnDef<any>[] = [
<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/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>
</th>
</tr>
))}
</table>
<ExpandedData datas={datas} />
</DialogContent>
</Dialog>
);

View File

@ -26,6 +26,7 @@ import {
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import ExpandedData from "./expand-list-view";
const columns: ColumnDef<any>[] = [
{
@ -52,54 +53,7 @@ const columns: ColumnDef<any>[] = [
<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>
<ExpandedData datas={datas} />
</DialogContent>
</Dialog>
);

View File

@ -32,6 +32,7 @@ export type Group = {
export function getMenuList(pathname: string, t: any): Group[] {
const roleId = getCookiesDecrypt("urie");
console.log("roleId");
const levelNumber = getCookiesDecrypt("ulne");
const userLevelId = getCookiesDecrypt("ulie");
@ -1676,6 +1677,265 @@ export function getMenuList(pathname: string, t: any): Group[] {
],
},
];
} else if (Number(roleId) === 2) {
menusSelected = [
{
groupLabel: t("apps"),
id: "dashboard",
menus: [
{
id: "dashboard",
href: "/dashboard",
label: t("dashboard"),
active: pathname.includes("/dashboard"),
icon: "material-symbols:dashboard",
submenus: [
{
href: "/dashboard",
label: "Executive",
active: pathname === "/dashboard",
icon: "heroicons:arrow-trending-up",
children: [],
},
{
href: "/dashboard/breakdown",
label: "Breakdown",
active: pathname === "/dashboard/breakdown",
icon: "heroicons:arrow-trending-up",
children: [],
},
],
},
],
},
{
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: "management-user",
menus: [
{
id: "management-user-menu",
href: "/adminn/management-user",
label: "Management User",
active: pathname.includes("/management-user"),
icon: "clarity:users-solid",
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: "performance-polda",
menus: [
{
id: "performance-polda",
href: "/admin/performance-polda",
label: t("performance-polda"),
active: pathname.includes("/admin/performance-polda"),
icon: "ant-design:signal-filled",
submenus: [],
},
],
},
{
groupLabel: "",
id: "analysis",
menus: [
{
id: "analysis",
href: "/admin/analysis",
label: t("analysis"),
active: pathname.includes("/task-plan"),
icon: "mdi:chart-line",
submenus: [
{
href: "/admin/analysis/magement-content",
label: t("management-content"),
active: pathname === "/admin/analysis/magement-content",
icon: "",
children: [],
},
{
href: "/admin/analysis/schedule",
label: t("schedule"),
active: pathname === "/admin/analysis/schedule",
icon: "heroicons:shopping-cart",
children: [],
},
{
href: "/admin/analysis/feedback-center",
label: "Feedback Center",
active: pathname === "/admin/analysis/feedback-center",
icon: "heroicons:shopping-cart",
children: [],
},
{
href: "/admin/analysis/emergency-issue",
label: "Emergency Issue",
active: pathname === "/admin/analysis/emergency-issue",
icon: "heroicons:shopping-cart",
children: [],
},
],
},
],
},
{
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: [
{
href: "/admin/media-tracking/media-online",
label: "Media Onlinne",
active: pathname === "/media-tracking/media-online",
icon: "heroicons:arrow-trending-up",
children: [],
},
{
href: "/admin/media-tracking/news",
label: "Tracking Beritra Hari Ini",
active: pathname === "/media-tracking/news",
icon: "heroicons:arrow-trending-up",
children: [],
},
],
},
],
},
{
groupLabel: "",
id: "contest",
menus: [
{
id: "contest",
href: "/shared/contest",
label: t("contest"),
active: pathname.includes("/contest"),
icon: "ic:outline-emoji-events",
submenus: [],
},
],
},
{
groupLabel: "",
id: "communication",
menus: [
{
id: "communication",
href: "/shared/communication",
label: t("communication"),
active: pathname.includes("/communication"),
icon: "token:chat",
submenus: [],
},
],
},
{
groupLabel: "",
id: "feedback",
menus: [
{
id: "feedback",
href: "/curator/feedback",
label: t("feedback"),
active: pathname.includes("/feedback"),
icon: "mdi:feedback-outline",
submenus: [],
},
],
},
{
groupLabel: "",
id: "broadcast",
menus: [
{
id: "broadcast",
href: "/admin/broadcast",
label: "Broadcast",
active: pathname.includes("/broadcast"),
icon: "mdi:broadcast",
submenus: [],
},
],
},
{
groupLabel: "",
id: "experts",
menus: [
{
id: "experts",
href: "/admin/add-experts",
label: t("add-experts"),
active: pathname.includes("/add-experts"),
icon: "majesticons:user",
submenus: [],
},
],
},
{
groupLabel: "",
id: "settings",
menus: [
{
id: "settings",
href: "/admin/settings",
label: t("settings"),
active: pathname.includes("/settinng"),
icon: "material-symbols:settings",
submenus: [],
},
],
},
];
}
return menusSelected;

View File

@ -294,7 +294,11 @@
"purchaseList": "Purchase List",
"sellers": "Sellers",
"typography": "Typography",
"colors": "Colors"
"colors": "Colors",
"performance-polda": "Performance Polda",
"analysis": "Analysis",
"management-content": "Management Content",
"add-experts": "Add Experts"
},
"Changelog": {
"version": "Version's",

View File

@ -146,7 +146,7 @@
"forward": "Forward",
"collaboration": "Collaboration",
"account-report": "Account Report",
"settings": "Settings",
"settings": "Pengaturan",
"feedback": "Feedback",
"content-production": "Produksi Konten",
"pattern-relation": "Pola & Relasi",
@ -294,7 +294,11 @@
"purchaseList": "Purchase List",
"sellers": "Sellers",
"typography": "Typography",
"colors": "Colors"
"colors": "Colors",
"performance-polda": "Performa Polda",
"analysis": "Analisa",
"management-content": "Manajemen Konten",
"add-experts": "Tambah Tenaga Ahli"
},
"Changelog": {
"version": "Version's",

222
package-lock.json generated
View File

@ -99,6 +99,7 @@
"react": "^18",
"react-advanced-news-ticker": "^1.0.1",
"react-apexcharts": "^1.4.1",
"react-audio-voice-recorder": "^2.2.0",
"react-chartjs-2": "^5.2.0",
"react-cssfx-loading": "^2.1.0",
"react-datepicker": "^7.5.0",
@ -119,6 +120,7 @@
"react-slick": "^0.30.2",
"react-syntax-highlighter": "^15.5.0",
"react-time-picker": "^7.0.0",
"react-voice-recorder": "^2.1.2",
"recharts": "^2.12.7",
"rtl-detect": "^1.1.2",
"sharp": "^0.33.4",
@ -157,6 +159,7 @@
"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"
},
@ -581,6 +584,25 @@
"npm": ">=6.14.13"
}
},
"node_modules/@ffmpeg/ffmpeg": {
"version": "0.11.6",
"resolved": "https://registry.npmjs.org/@ffmpeg/ffmpeg/-/ffmpeg-0.11.6.tgz",
"integrity": "sha512-uN8J8KDjADEavPhNva6tYO9Fj0lWs9z82swF3YXnTxWMBoFLGq3LZ6FLlIldRKEzhOBKnkVfA8UnFJuvGvNxcA==",
"dependencies": {
"is-url": "^1.2.4",
"node-fetch": "^2.6.1",
"regenerator-runtime": "^0.13.7",
"resolve-url": "^0.2.1"
},
"engines": {
"node": ">=12.16.1"
}
},
"node_modules/@ffmpeg/ffmpeg/node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"node_modules/@floating-ui/core": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz",
@ -842,6 +864,7 @@
"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,6 +881,7 @@
"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"
},
@ -869,6 +893,7 @@
"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"
},
@ -1204,6 +1229,7 @@
"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"
@ -1216,6 +1242,7 @@
"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"
}
@ -1224,6 +1251,7 @@
"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"
@ -1245,6 +1273,7 @@
"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"
@ -3443,6 +3472,7 @@
"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"
}
@ -3456,6 +3486,7 @@
"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"
},
@ -3469,12 +3500,14 @@
"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=="
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
"dev": true
},
"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"
@ -3519,7 +3552,8 @@
"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=="
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
"dev": true
},
"node_modules/argparse": {
"version": "2.0.1",
@ -3810,12 +3844,14 @@
"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=="
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"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"
},
@ -3837,6 +3873,7 @@
"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"
},
@ -3896,6 +3933,7 @@
"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"
}
@ -3995,6 +4033,7 @@
"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",
@ -4018,6 +4057,7 @@
"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"
},
@ -4202,6 +4242,7 @@
"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",
@ -4225,6 +4266,7 @@
"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"
},
@ -4900,7 +4942,8 @@
"node_modules/didyoumean": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
"dev": true
},
"node_modules/diff": {
"version": "5.2.0",
@ -4925,7 +4968,8 @@
"node_modules/dlv": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
"dev": true
},
"node_modules/doctrine": {
"version": "3.0.0",
@ -5026,7 +5070,8 @@
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true
},
"node_modules/elkjs": {
"version": "0.9.3",
@ -5074,7 +5119,8 @@
"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=="
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true
},
"node_modules/enhanced-resolve": {
"version": "5.17.1",
@ -5914,6 +5960,7 @@
"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",
@ -5929,6 +5976,7 @@
"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"
},
@ -5952,6 +6000,7 @@
"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"
}
@ -5995,6 +6044,7 @@
"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"
},
@ -6085,6 +6135,7 @@
"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"
@ -6295,6 +6346,7 @@
"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",
@ -6316,6 +6368,7 @@
"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"
},
@ -6327,6 +6380,7 @@
"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"
}
@ -6335,6 +6389,7 @@
"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"
},
@ -7302,6 +7357,7 @@
"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"
},
@ -7433,6 +7489,7 @@
"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"
}
@ -7456,6 +7513,7 @@
"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"
}
@ -7479,6 +7537,7 @@
"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"
},
@ -7523,6 +7582,7 @@
"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"
}
@ -7700,6 +7760,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-url": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
"integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="
},
"node_modules/is-weakmap": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
@ -7771,6 +7836,7 @@
"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"
},
@ -7788,6 +7854,7 @@
"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"
}
@ -8043,6 +8110,7 @@
"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"
},
@ -8151,7 +8219,8 @@
"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=="
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
"dev": true
},
"node_modules/lucide-react": {
"version": "0.390.0",
@ -8865,6 +8934,7 @@
"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"
}
@ -9652,6 +9722,7 @@
"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"
@ -9712,6 +9783,7 @@
"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"
}
@ -9760,6 +9832,7 @@
"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",
@ -10027,6 +10100,25 @@
"react-dom": "*"
}
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/non-layered-tidy-tree-layout": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz",
@ -10036,6 +10128,7 @@
"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"
}
@ -10082,6 +10175,7 @@
"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"
}
@ -10380,6 +10474,7 @@
"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"
}
@ -10393,6 +10488,7 @@
"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"
@ -10431,6 +10527,7 @@
"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"
},
@ -10442,6 +10539,7 @@
"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"
}
@ -10450,6 +10548,7 @@
"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"
}
@ -10467,6 +10566,7 @@
"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",
@ -10494,6 +10594,7 @@
"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",
@ -10510,6 +10611,7 @@
"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"
},
@ -10528,6 +10630,7 @@
"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",
@ -10562,6 +10665,7 @@
"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"
},
@ -10573,6 +10677,7 @@
"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",
@ -10597,6 +10702,7 @@
"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"
@ -10608,7 +10714,8 @@
"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=="
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true
},
"node_modules/preact": {
"version": "10.12.1",
@ -10702,6 +10809,7 @@
"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",
@ -10807,6 +10915,28 @@
"react": ">=0.13"
}
},
"node_modules/react-audio-visualize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/react-audio-visualize/-/react-audio-visualize-1.2.0.tgz",
"integrity": "sha512-rfO5nmT0fp23gjU0y2WQT6+ZOq2ZsuPTMphchwX1PCz1Di4oaIr6x7JZII8MLrbHdG7UB0OHfGONTIsWdh67kQ==",
"peerDependencies": {
"react": ">=16.2.0",
"react-dom": ">=16.2.0"
}
},
"node_modules/react-audio-voice-recorder": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/react-audio-voice-recorder/-/react-audio-voice-recorder-2.2.0.tgz",
"integrity": "sha512-Hq+143Zs99vJojT/uFvtpxUuiIKoLbMhxhA7qgxe5v8hNXrh5/qTnvYP92hFaE5V+GyoCXlESONa0ufk7t5kHQ==",
"dependencies": {
"@ffmpeg/ffmpeg": "^0.11.6",
"react-audio-visualize": "^1.1.3"
},
"peerDependencies": {
"react": ">=16.2.0",
"react-dom": ">=16.2.0"
}
},
"node_modules/react-chartjs-2": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz",
@ -11256,10 +11386,22 @@
"react-dom": ">=16.6.0"
}
},
"node_modules/react-voice-recorder": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/react-voice-recorder/-/react-voice-recorder-2.1.2.tgz",
"integrity": "sha512-fjLN3fdVqsFrlISujAFAuVk85yCxhK4kcyyuahxa0fYo4LxyY36rGeQ4HCG8XRhfHrPxd5E632e//N5UqrnLKg==",
"engines": {
"node": ">=10"
},
"peerDependencies": {
"react": "^16.0.0"
}
},
"node_modules/read-cache": {
"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"
}
@ -11268,6 +11410,7 @@
"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"
},
@ -11686,10 +11829,17 @@
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
}
},
"node_modules/resolve-url": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
"integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==",
"deprecated": "https://github.com/lydell/resolve-url#deprecated"
},
"node_modules/reusify": {
"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"
@ -11762,6 +11912,7 @@
"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",
@ -11953,6 +12104,7 @@
"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"
},
@ -11964,6 +12116,7 @@
"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"
}
@ -12000,6 +12153,7 @@
"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"
},
@ -12129,6 +12283,7 @@
"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",
@ -12146,6 +12301,7 @@
"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",
@ -12158,12 +12314,14 @@
"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=="
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"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"
},
@ -12175,6 +12333,7 @@
"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"
},
@ -12310,6 +12469,7 @@
"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"
},
@ -12322,6 +12482,7 @@
"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"
},
@ -12426,6 +12587,7 @@
"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",
@ -12447,6 +12609,7 @@
"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"
}
@ -12620,6 +12783,7 @@
"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",
@ -12679,6 +12843,7 @@
"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"
}
@ -12687,6 +12852,7 @@
"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"
},
@ -12799,6 +12965,7 @@
"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"
},
@ -12820,6 +12987,11 @@
"node": ">=6"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/trim-lines": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
@ -12861,7 +13033,8 @@
"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=="
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
"dev": true
},
"node_modules/tsconfig-paths": {
"version": "3.15.0",
@ -13339,7 +13512,8 @@
"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=="
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
},
"node_modules/uuid": {
"version": "9.0.1",
@ -13538,6 +13712,11 @@
"resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.3.0.tgz",
"integrity": "sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA=="
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/webpack-bundle-analyzer": {
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz",
@ -13574,10 +13753,20 @@
"node": ">= 10"
}
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": {
"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"
},
@ -13684,6 +13873,7 @@
"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",
@ -13701,6 +13891,7 @@
"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",
@ -13716,12 +13907,14 @@
"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=="
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"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",
@ -13735,6 +13928,7 @@
"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"
},
@ -13746,6 +13940,7 @@
"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"
},
@ -13757,6 +13952,7 @@
"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"
},

View File

@ -100,6 +100,7 @@
"react": "^18",
"react-advanced-news-ticker": "^1.0.1",
"react-apexcharts": "^1.4.1",
"react-audio-voice-recorder": "^2.2.0",
"react-chartjs-2": "^5.2.0",
"react-cssfx-loading": "^2.1.0",
"react-datepicker": "^7.5.0",
@ -120,6 +121,7 @@
"react-slick": "^0.30.2",
"react-syntax-highlighter": "^15.5.0",
"react-time-picker": "^7.0.0",
"react-voice-recorder": "^2.1.2",
"recharts": "^2.12.7",
"rtl-detect": "^1.1.2",
"sharp": "^0.33.4",

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

View File

@ -22,7 +22,7 @@ export async function getPlanningDailyByTypeId(
date: string,
typeId: number
) {
const url = `planning/pagination/daily?enablePage=1&size=${size}&page=${page}&date=${date}&typeId=${typeId}${
const url = `planning/pagination/daily?enablePage=1&time=1&size=${size}&page=${page}&date=${date}&typeId=${typeId}${
parentId ? `&parentId=${parentId}` : ""
}`;
return getAPIInterceptor(url);

View File

@ -1,5 +1,6 @@
import {
httpGetInterceptor,
httpPostInterceptor,
} from "../http-config/http-interceptor-service";
export async function getKnowledgeBaseCategoryList() {
@ -11,3 +12,8 @@ export async function getKnowledgeBaseList(id: number) {
const url = `knowledge-base?categoryId=${id}`;
return httpGetInterceptor(url);
}
export async function saveKnowledgeBaseCategory(data: any) {
const url = 'knowledge-base/category';
return httpPostInterceptor(url, data);
}