diff --git a/action/app-actions.ts b/action/app-actions.ts index 0fb80fd0..b8ab74ce 100644 --- a/action/app-actions.ts +++ b/action/app-actions.ts @@ -1,7 +1,6 @@ 'use server' import { redirect } from "next/navigation"; import { revalidatePath } from "next/cache"; -import { postMessage } from "@/app/[locale]/(protected)/app/chat/utils"; export const postMessageAction = async (id: string, message: string,) => { diff --git a/app/[locale]/(protected)/admin/survey/component/table.tsx b/app/[locale]/(protected)/admin/survey/component/table.tsx index 5e084b5a..ae1f97ff 100644 --- a/app/[locale]/(protected)/admin/survey/component/table.tsx +++ b/app/[locale]/(protected)/admin/survey/component/table.tsx @@ -54,22 +54,7 @@ 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 { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; -import { - getMediaBlastCampaignPage, - listDataMedia, -} from "@/service/broadcast/broadcast"; -import { listEnableCategory } from "@/service/content/content"; -import { Checkbox } from "@/components/ui/checkbox"; import { close, loading } from "@/config/swal"; -import { Link } from "@/i18n/routing"; -import { NewCampaignIcon } from "@/components/icon"; -import search from "../../../app/chat/components/search"; import { Select, SelectContent, @@ -79,7 +64,6 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { Card, CardContent } from "@/components/ui/card"; import { Bar, BarChart, diff --git a/app/[locale]/(protected)/contributor/planning/mediahub/components/mediahub-table.tsx b/app/[locale]/(protected)/contributor/planning/mediahub/components/mediahub-table.tsx index 2dadb124..96719606 100644 --- a/app/[locale]/(protected)/contributor/planning/mediahub/components/mediahub-table.tsx +++ b/app/[locale]/(protected)/contributor/planning/mediahub/components/mediahub-table.tsx @@ -54,7 +54,6 @@ import { useRouter, useSearchParams } from "next/navigation"; import TablePagination from "@/components/table/table-pagination"; import columns from "./columns"; import { getPlanningSentPagination } from "@/service/planning/planning"; -import search from "@/app/[locale]/(protected)/app/chat/components/search"; import { CardHeader, CardTitle } from "@/components/ui/card"; import { useTranslations } from "next-intl"; import useTableColumns from "./columns"; diff --git a/app/[locale]/(protected)/contributor/task/create/page.tsx b/app/[locale]/(protected)/contributor/task/create/page.tsx index 9ed4c0a4..2897575a 100644 --- a/app/[locale]/(protected)/contributor/task/create/page.tsx +++ b/app/[locale]/(protected)/contributor/task/create/page.tsx @@ -1,7 +1,6 @@ import { Card, CardContent } from "@/components/ui/card"; import SiteBreadcrumb from "@/components/site-breadcrumb"; import FormTask from "@/components/form/task/task-form"; -import FormTaskRefactored from "@/components/form/task/task-form-refactored"; const TaskCreatePage = () => { return ( diff --git a/app/[locale]/(protected)/dashboard/routine-task/components/recent-activity.tsx b/app/[locale]/(protected)/dashboard/routine-task/components/recent-activity.tsx index ad649f48..dfbfc559 100644 --- a/app/[locale]/(protected)/dashboard/routine-task/components/recent-activity.tsx +++ b/app/[locale]/(protected)/dashboard/routine-task/components/recent-activity.tsx @@ -11,7 +11,6 @@ import { import { DockIcon, ImageIcon, MicIcon, YoutubeIcon } from "lucide-react"; import { useRouter, useSearchParams } from "next/navigation"; import React from "react"; -import search from "../../../app/chat/components/search"; import { useTranslations } from "next-intl"; type StatusFilter = string[]; diff --git a/components/auth/identity-form.tsx b/components/auth/identity-form.tsx index 6adf6fef..a6493082 100644 --- a/components/auth/identity-form.tsx +++ b/components/auth/identity-form.tsx @@ -105,9 +105,7 @@ export const IdentityForm: React.FC = ({ {t("member", { defaultValue: "Member" })} * - {errors.association && ( + {/* {errors.association && (
{errors.association.message}
- )} + )} */}
diff --git a/components/auth/profile-form.tsx b/components/auth/profile-form.tsx index f4959adb..cf9c5d19 100644 --- a/components/auth/profile-form.tsx +++ b/components/auth/profile-form.tsx @@ -122,6 +122,7 @@ export const ProfileForm: React.FC = ({ } const instituteData: InstituteData = { + id: "0", name: customInstituteName, address: instituteAddress, }; diff --git a/components/form/content/task-ta/video-update-form.tsx b/components/form/content/task-ta/video-update-form.tsx index c1ebd894..93716f82 100644 --- a/components/form/content/task-ta/video-update-form.tsx +++ b/components/form/content/task-ta/video-update-form.tsx @@ -48,7 +48,6 @@ import "swiper/css/thumbs"; import "swiper/css"; import "swiper/css/navigation"; import { FreeMode, Navigation, Pagination, Thumbs } from "swiper/modules"; -import { files } from "@/app/[locale]/(protected)/app/projects/[id]/data"; import { useDropzone } from "react-dropzone"; import Image from "next/image"; import { Icon } from "@iconify/react/dist/iconify.js"; diff --git a/components/form/content/video-update-form.tsx b/components/form/content/video-update-form.tsx index 6c50ecf3..3810fbe7 100644 --- a/components/form/content/video-update-form.tsx +++ b/components/form/content/video-update-form.tsx @@ -48,7 +48,6 @@ import "swiper/css/thumbs"; import "swiper/css"; import "swiper/css/navigation"; import { FreeMode, Navigation, Pagination, Thumbs } from "swiper/modules"; -import { files } from "@/app/[locale]/(protected)/app/projects/[id]/data"; import { useDropzone } from "react-dropzone"; import Image from "next/image"; import { Icon } from "@iconify/react/dist/iconify.js"; diff --git a/components/form/task/task-form-refactored.tsx b/components/form/task/task-form-refactored.tsx deleted file mode 100644 index 2e72e695..00000000 --- a/components/form/task/task-form-refactored.tsx +++ /dev/null @@ -1,840 +0,0 @@ -"use client"; -import React, { useEffect, useRef, useState } from "react"; -import { useForm } from "react-hook-form"; -import { Button } from "@/components/ui/button"; -import { Card } from "@/components/ui/card"; -import { zodResolver } from "@hookform/resolvers/zod"; -import * as z from "zod"; -import Swal from "sweetalert2"; -import withReactContent from "sweetalert2-react-content"; -import { useParams, useRouter } from "next/navigation"; -import { Input } from "@/components/ui/input"; -import { Checkbox } from "@/components/ui/checkbox"; -import { Label } from "@/components/ui/label"; - -// Import new reusable form components -import { - FormField, - FormSelect, - FormCheckbox, - FormRadio, - FormSection, - FormGrid, - FormGridItem, - SelectOption, - CheckboxOption, - RadioOption, -} from "@/components/form/shared"; - -import { - createTask, - getTask, - getUserLevelForAssignments, -} from "@/service/task"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/components/ui/dialog"; -import { ChevronDown, ChevronUp, Trash2 } from "lucide-react"; -import { AudioRecorder } from "react-audio-voice-recorder"; -import FileUploader from "@/components/form/shared/file-uploader"; -import { Upload } from "tus-js-client"; -import { close, error } from "@/config/swal"; -import { getCsrfToken } from "@/service/auth"; -import { loading } from "@/lib/swal"; -import { useTranslations } from "next-intl"; -import dynamic from "next/dynamic"; - -// ============================================================================= -// SCHEMA -// ============================================================================= - -const taskSchema = z.object({ - title: z.string().min(1, { message: "Judul diperlukan" }), - naration: z.string().min(2, { - message: "Narasi Penugasan harus lebih dari 2 karakter.", - }), - assignmentSelection: z.string().min(1, { message: "Assignment selection is required" }), - mainType: z.string().min(1, { message: "Main type is required" }), - taskType: z.string().min(1, { message: "Task type is required" }), - type: z.string().min(1, { message: "Type is required" }), - taskOutput: z.array(z.string()).min(1, { message: "At least one output is required" }), -}); - -// ============================================================================= -// TYPES -// ============================================================================= - -interface FileWithPreview extends File { - preview: string; -} - -export type taskDetail = { - id: number; - title: string; - fileTypeOutput: string; - assignedToTopLevel: string; - assignedToLevel: string; - assignmentType: { - id: number; - name: string; - }; - assignmentMainType: { - id: number; - name: string; - }; - attachmentUrl: string; - taskType: string; - broadcastType: string; - narration: string; - is_active: string; -}; - -const CustomEditor = dynamic( - () => { - return import("@/components/editor/custom-editor"); - }, - { ssr: false } -); - -// ============================================================================= -// OPTIONS DATA -// ============================================================================= - -const assignmentSelectionOptions: SelectOption[] = [ - { value: "3,4", label: "Semua Pengguna" }, - { value: "4", label: "Kontributor" }, - { value: "3", label: "Approver" }, -]; - -const mainTypeOptions: RadioOption[] = [ - { value: "1", label: "Mediahub" }, - { value: "2", label: "Medsos Mediahub" }, -]; - -const taskTypeOptions: RadioOption[] = [ - { value: "atensi-khusus", label: "Atensi Khusus" }, - { value: "tugas-harian", label: "Tugas Harian" }, -]; - -const typeOptions: RadioOption[] = [ - { value: "1", label: "Publikasi" }, - { value: "2", label: "Amplifikasi" }, - { value: "3", label: "Kontra" }, -]; - -const taskOutputOptions: CheckboxOption[] = [ - { value: "all", label: "All" }, - { value: "video", label: "Video" }, - { value: "audio", label: "Audio" }, - { value: "image", label: "Image" }, - { value: "text", label: "Text" }, -]; - -const unitSelectionOptions: CheckboxOption[] = [ - { value: "allUnit", label: "All Unit" }, - { value: "mabes", label: "Mabes" }, - { value: "polda", label: "Polda" }, - { value: "polres", label: "Polres" }, - { value: "satker", label: "Satker" }, -]; - -// ============================================================================= -// COMPONENT -// ============================================================================= - -export default function FormTaskRefactored() { - const MySwal = withReactContent(Swal); - const router = useRouter(); - const editor = useRef(null); - type TaskSchema = z.infer; - const { id } = useParams() as { id: string }; - const t = useTranslations("Form"); - - // ============================================================================= - // STATE - // ============================================================================= - - const [detail, setDetail] = useState(); - const [listDest, setListDest] = useState([]); - const [checkedLevels, setCheckedLevels] = useState(new Set()); - const [expandedPolda, setExpandedPolda] = useState([{}]); - const [isLoading, setIsLoading] = useState(false); - const [audioFile, setAudioFile] = useState(null); - const [isRecording, setIsRecording] = useState(false); - const [timer, setTimer] = useState(120); - const [imageFiles, setImageFiles] = useState([]); - const [videoFiles, setVideoFiles] = useState([]); - const [textFiles, setTextFiles] = useState([]); - const [audioFiles, setAudioFiles] = useState([]); - const [isImageUploadFinish, setIsImageUploadFinish] = useState(false); - const [isVideoUploadFinish, setIsVideoUploadFinish] = useState(false); - const [isTextUploadFinish, setIsTextUploadFinish] = useState(false); - const [isAudioUploadFinish, setIsAudioUploadFinish] = useState(false); - const [voiceNoteLink, setVoiceNoteLink] = useState(""); - const [links, setLinks] = useState([""]); - - // ============================================================================= - // FORM SETUP - // ============================================================================= - - const form = useForm({ - resolver: zodResolver(taskSchema), - mode: "all", - defaultValues: { - title: detail?.title || "", - naration: detail?.narration || "", - assignmentSelection: "3,4", - mainType: "1", - taskType: "atensi-khusus", - type: "1", - taskOutput: [], - }, - }); - - // ============================================================================= - // EFFECTS - // ============================================================================= - - 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); - } catch (error) { - console.error("Error fetching Polda/Polres data:", error); - } finally { - setIsLoading(false); - } - } - fetchPoldaPolres(); - }, []); - - // ============================================================================= - // HANDLERS - // ============================================================================= - - 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 handlePoldaPolresChange = () => { - return Array.from(checkedLevels).join(","); - }; - - const toggleExpand = (poldaId: any) => { - setExpandedPolda((prev) => ({ - ...prev, - [poldaId]: !prev[poldaId], - })); - }; - - const onRecordingStart = () => { - setIsRecording(true); - setTimer(120); - const interval = setInterval(() => { - setTimer((prev) => { - if (prev <= 1) { - clearInterval(interval); - setIsRecording(false); - return 0; - } - return prev - 1; - }); - }, 1000); - }; - - const handleStopRecording = () => { - setIsRecording(false); - }; - - const addAudioElement = (blob: Blob) => { - const url = URL.createObjectURL(blob); - const audio = new Audio(url); - const file = new File([blob], "voice-note.webm", { type: "audio/webm" }); - setAudioFile(file); - setVoiceNoteLink(url); - }; - - const handleDeleteAudio = (index: number) => { - setAudioFiles((prev) => prev.filter((_, i) => i !== index)); - }; - - const handleLinkChange = (index: number, value: string) => { - const newLinks = [...links]; - newLinks[index] = value; - setLinks(newLinks); - }; - - const handleAddRow = () => { - setLinks([...links, ""]); - }; - - const handleRemoveRow = (index: number) => { - setLinks(links.filter((_, i) => i !== index)); - }; - - // ============================================================================= - // SUBMISSION - // ============================================================================= - - const save = async (data: TaskSchema) => { - try { - const csrfToken = await getCsrfToken(); - const formData = new FormData(); - - formData.append("title", data.title); - formData.append("narration", data.naration); - formData.append("assignmentSelection", data.assignmentSelection); - formData.append("mainType", data.mainType); - formData.append("taskType", data.taskType); - formData.append("type", data.type); - formData.append("taskOutput", data.taskOutput.join(",")); - formData.append("selectedTarget", handlePoldaPolresChange()); - - // Add file uploads - if (videoFiles.length > 0) { - videoFiles.forEach((file) => { - formData.append("videoFiles", file); - }); - } - - if (imageFiles.length > 0) { - imageFiles.forEach((file) => { - formData.append("imageFiles", file); - }); - } - - if (textFiles.length > 0) { - textFiles.forEach((file) => { - formData.append("textFiles", file); - }); - } - - if (audioFiles.length > 0) { - audioFiles.forEach((file) => { - formData.append("audioFiles", file); - }); - } - - if (audioFile) { - formData.append("audioFile", audioFile); - } - - // Add links - formData.append("links", JSON.stringify(links.filter(link => link.trim() !== ""))); - - const response = await createTask(formData, csrfToken); - - if (response?.data?.success) { - successSubmit("/task"); - } else { - error("Failed to create task"); - } - } catch (error) { - console.error("Error saving task:", error); - error("An error occurred while saving the task"); - } - }; - - const onSubmit = (data: TaskSchema) => { - 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 successSubmit = (redirect: string) => { - MySwal.fire({ - title: "Berhasil!", - text: "Data berhasil disimpan", - icon: "success", - timer: 2000, - showConfirmButton: false, - }).then(() => { - router.push(redirect); - }); - }; - - // ============================================================================= - // RENDER - // ============================================================================= - - return ( -
- -
- {/* Header */} -
-

- {t("form-task", { defaultValue: "Form Task" })} (Refactored) -

-

Create and manage task assignments with detailed configuration

-
- -
- {/* Basic Information */} -
-
-

Basic Information

-

Enter the basic details for your task

-
- -
-
- - - {form.formState.errors.title && ( -

{form.formState.errors.title.message}

- )} -
-
-
- - {/* Assignment Configuration */} -
-
-

Assignment Configuration

-

Configure assignment settings and target audience

-
- -
-
- - - {form.formState.errors.assignmentSelection && ( -

{form.formState.errors.assignmentSelection.message}

- )} -
- -
- -
- {unitSelectionOptions.map((option) => ( -
- - -
- ))} -
-
-
- - {/* Custom Assignment Dialog */} -
- - - - - - - Daftar Wilayah Polda dan Polres - -
- {listDest.map((polda: any) => ( -
- - {expandedPolda[polda.id] && ( -
- - {polda?.subDestination?.map((polres: any) => ( - - ))} -
- )} -
- ))} -
-
-
-
-
- - {/* Task Configuration */} -
-
-

Task Configuration

-

Configure task type and output settings

-
- -
-
- -
- {mainTypeOptions.map((option) => ( -
- - -
- ))} -
- {form.formState.errors.mainType && ( -

{form.formState.errors.mainType.message}

- )} -
- -
- -
- {taskTypeOptions.map((option) => ( -
- - -
- ))} -
- {form.formState.errors.taskType && ( -

{form.formState.errors.taskType.message}

- )} -
- -
- -
- {typeOptions.map((option) => ( -
- - -
- ))} -
- {form.formState.errors.type && ( -

{form.formState.errors.type.message}

- )} -
- -
- -
- {taskOutputOptions.map((option) => ( -
- - -
- ))} -
- {form.formState.errors.taskOutput && ( -

{form.formState.errors.taskOutput.message}

- )} -
-
-
- - {/* Task Description */} -
-
-

Task Description

-

Provide detailed description of the task

-
- -
- -
- -
- {form.formState.errors.naration && ( -

{form.formState.errors.naration.message}

- )} -
-
- - {/* Attachments */} -
-
-

Attachments

-

Upload files and add links for the task

-
- -
- {/* File Uploaders */} -
-
- - setVideoFiles(files)} - /> -
- -
- - setImageFiles(files)} - /> -
- -
- - setTextFiles(files)} - /> -
- -
- - - setAudioFiles((prev) => [...prev, ...files])} - /> -
-
- - {/* Audio Files List */} - {audioFiles?.length > 0 && ( -
- - {audioFiles.map((audio: any, idx: any) => ( -
- {t("voice-note", { defaultValue: "Voice Note" })} {idx + 1} - -
- ))} -
- )} - - {isRecording && ( -
-

Recording... {timer} seconds remaining

-
- )} - - {/* News Links */} -
- -
- {links.map((link, index) => ( -
- handleLinkChange(index, e.target.value)} - /> - {links.length > 1 && ( - - )} -
- ))} - -
-
-
-
- - {/* Submit Button */} -
- -
-
-
-
-
- ); -} \ No newline at end of file diff --git a/components/landing-page/scrollable-content-polda.tsx b/components/landing-page/scrollable-content-polda.tsx index 77641d84..ad6a314c 100644 --- a/components/landing-page/scrollable-content-polda.tsx +++ b/components/landing-page/scrollable-content-polda.tsx @@ -1,4 +1,3 @@ -import search from "@/app/[locale]/(protected)/app/chat/components/search"; import { useTranslations } from "next-intl"; import { useParams } from "next/navigation"; import router from "next/router"; diff --git a/components/landing-page/scrollable-content-satker.tsx b/components/landing-page/scrollable-content-satker.tsx index 6f86ca79..c1e963f9 100644 --- a/components/landing-page/scrollable-content-satker.tsx +++ b/components/landing-page/scrollable-content-satker.tsx @@ -1,4 +1,3 @@ -import search from "@/app/[locale]/(protected)/app/chat/components/search"; import { useTranslations } from "next-intl"; import { useParams } from "next/navigation"; import router from "next/router"; diff --git a/components/landing-page/search-section-new.tsx b/components/landing-page/search-section-new.tsx index a8cc5d15..aa17f0bc 100644 --- a/components/landing-page/search-section-new.tsx +++ b/components/landing-page/search-section-new.tsx @@ -1,4 +1,3 @@ -import search from "@/app/[locale]/(protected)/app/chat/components/search"; import { useTranslations } from "next-intl"; import { useParams } from "next/navigation"; import router from "next/router"; diff --git a/components/landing-page/search-section-polda.tsx b/components/landing-page/search-section-polda.tsx index c52fc977..a52b9c0a 100644 --- a/components/landing-page/search-section-polda.tsx +++ b/components/landing-page/search-section-polda.tsx @@ -1,4 +1,3 @@ -import search from "@/app/[locale]/(protected)/app/chat/components/search"; import { Select, SelectTrigger, SelectValue, SelectContent, SelectGroup, SelectItem } from "@radix-ui/react-select"; import { Icon } from "lucide-react"; import { useTranslations } from "next-intl"; diff --git a/components/landing-page/search-section-satker.tsx b/components/landing-page/search-section-satker.tsx index 7595741e..8b673b54 100644 --- a/components/landing-page/search-section-satker.tsx +++ b/components/landing-page/search-section-satker.tsx @@ -1,4 +1,3 @@ -import search from "@/app/[locale]/(protected)/app/chat/components/search"; import { Select, SelectTrigger, SelectValue, SelectContent, SelectGroup, SelectItem } from "@radix-ui/react-select"; import { Icon } from "lucide-react"; import { useTranslations } from "next-intl"; diff --git a/components/landing-page/search-section.tsx b/components/landing-page/search-section.tsx index 9af0b96a..acca5827 100644 --- a/components/landing-page/search-section.tsx +++ b/components/landing-page/search-section.tsx @@ -1,4 +1,3 @@ -import search from "@/app/[locale]/(protected)/app/chat/components/search"; import { Select, SelectTrigger, diff --git a/lib/registration-utils.ts b/lib/registration-utils.ts index dc8565c5..cda5a23b 100644 --- a/lib/registration-utils.ts +++ b/lib/registration-utils.ts @@ -154,6 +154,7 @@ export const sanitizeRegistrationData = (data: RegistrationFormData): Registrati export const sanitizeInstituteData = (data: InstituteData): InstituteData => { return { + id : data.id, name: data.name.trim(), address: data.address.trim(), }; diff --git a/lib/utils.ts b/lib/utils.ts index 2ed06ee6..eeb1f8c1 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -4,7 +4,6 @@ import Cookies from "js-cookie"; import CryptoJS from "crypto-js"; import Swal from "sweetalert2"; import withReactContent from "sweetalert2-react-content"; -import Loading from "@/app/[locale]/(protected)/app/projects/loading"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); diff --git a/types/registration.ts b/types/registration.ts index 61fa33f0..4474825c 100644 --- a/types/registration.ts +++ b/types/registration.ts @@ -85,6 +85,7 @@ export const generalRegistrationSchema = z.object({ }); export const instituteSchema = z.object({ + id: z.string(), name: z .string() .min(1, { message: "Institute name is required" })