diff --git a/app/[locale]/(protected)/contributor/task/components/columns.tsx b/app/[locale]/(protected)/contributor/task/components/columns.tsx index b1c9e66c..c590cf2b 100644 --- a/app/[locale]/(protected)/contributor/task/components/columns.tsx +++ b/app/[locale]/(protected)/contributor/task/components/columns.tsx @@ -23,8 +23,23 @@ const columns: ColumnDef[] = [ { accessorKey: "title", header: "Title", - cell: ({ row }) => {row.getValue("title")}, + cell: ({ row }) => ( +
+ {row.getValue("title")} + {row.original.isForward && ( + + )} +
+ ), }, + { accessorKey: "uniqueCode", header: "Code", diff --git a/app/[locale]/(protected)/shared/curated-content/giat-routine/image/detail/[id]/page.tsx b/app/[locale]/(protected)/shared/curated-content/giat-routine/image/detail/[id]/page.tsx index 9f776610..90858da6 100644 --- a/app/[locale]/(protected)/shared/curated-content/giat-routine/image/detail/[id]/page.tsx +++ b/app/[locale]/(protected)/shared/curated-content/giat-routine/image/detail/[id]/page.tsx @@ -21,8 +21,19 @@ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import Cookies from "js-cookie"; import { postBlog } from "@/service/blog/blog"; import { Textarea } from "@/components/ui/textarea"; -import { DotSquare, InboxIcon, PaperclipIcon, SmileIcon } from "lucide-react"; -import { detailMedia } from "@/service/curated-content/curated-content"; +import { + DotSquare, + InboxIcon, + PaperclipIcon, + SmileIcon, + TrashIcon, +} from "lucide-react"; +import { + deleteMediaCurationMessage, + detailMedia, + getMediaCurationMessage, + saveMediaCurationMessage, +} from "@/service/curated-content/curated-content"; import { Swiper, SwiperSlide } from "swiper/react"; import "swiper/css"; import "swiper/css/free-mode"; @@ -34,6 +45,14 @@ import "swiper/css/navigation"; import { FreeMode, Navigation, Pagination, Thumbs } from "swiper/modules"; import { Avatar, AvatarImage } from "@/components/ui/avatar"; import { Badge } from "@/components/ui/badge"; +import { listData } from "@/service/landing/landing"; +import { + createAssignmentResponse, + deleteAssignmentResponse, + getAssignmentResponseList, +} from "@/service/task"; +import { getCookiesDecrypt } from "@/lib/utils"; +import { close, loading } from "@/lib/swal"; const detailSchema = z.object({ title: z.string().min(1, { message: "Judul diperlukan" }), @@ -50,6 +69,24 @@ type Category = { categoryName: string; }; +const formatDate = (dateString: string): string => { + const date = new Date(dateString); + + // Pastikan validitas tanggal + if (isNaN(date.getTime())) { + throw new Error("Invalid date format"); + } + + // Format tanggal + const day = date.getDate().toString().padStart(2, "0"); + const month = (date.getMonth() + 1).toString().padStart(2, "0"); + const year = date.getFullYear(); + // const hours = date.getHours().toString().padStart(2, "0"); + + // Gabungkan hasil format + return `${day}-${month}-${year} `; +}; + export type curationDetail = { id: number; title: string; @@ -108,22 +145,21 @@ export default function DetailImage() { console.log(id); const editor = useRef(null); type DetailSchema = z.infer; - + const userLevelNumber = getCookiesDecrypt("ulne"); + const userId = getCookiesDecrypt("uie"); const [selectedFiles, setSelectedFiles] = useState([]); const taskId = Cookies.get("taskId"); const scheduleId = Cookies.get("scheduleId"); const scheduleType = Cookies.get("scheduleType"); const [selectedTarget, setSelectedTarget] = useState(""); - // const [detail, setDetail] = useState({ - // title: null, - // tags: null, - // files: [], - // fileType: null, - // }); const [detail, setDetail] = useState(); const [refresh] = useState(false); const [detailThumb, setDetailThumb] = useState([]); const [thumbsSwiper, setThumbsSwiper] = useState(null); + const [showInput, setShowInput] = useState(false); + const [selectedFileId, setSelectedFileId] = useState(null); + const [listData, setListData] = useState([]); + const [message, setMessage] = useState(""); const { control, @@ -142,31 +178,93 @@ export default function DetailImage() { setReplyingTo(commentId); }; - const addReply = (commentId: number) => { - if (replyText.trim()) { - const newCommentData = commentsData.map((comment: any) => { - if (comment.id === commentId) { - return { - ...comment, - replies: [ - ...comment.replies, - { - text: replyText, - username: "You", - date: new Date().toLocaleString(), - }, - ], - }; - } - return comment; - }); + const handleInputChange = (e: React.ChangeEvent) => { + setMessage(e.target.value); + }; - setCommentsData(newCommentData); - setReplyText(""); + useEffect(() => { + async function initState() { + // loading(); + const response = await getMediaCurationMessage(selectedFileId); + console.log("data", response?.data?.data); + console.log("userLvl", userLevelNumber); + setListData(response?.data?.data); + close(); + } + + initState(); + }, [selectedFileId]); + + // const postData = () => { + // sendSuggestionParent(); + // }; + + const postData = async () => { + if (message?.length > 1 && selectedFileId) { + try { + const data = { + mediaUploadFileId: selectedFileId, + message, + parentId: null, + }; + + const response = await saveMediaCurationMessage(data); + console.log("Komentar terkirim:", response); + + const responseGet = await getMediaCurationMessage(selectedFileId); + setListData(responseGet?.data?.data); + + setMessage(""); + } catch (error) { + console.error("Error posting comment:", error); + } + } else { + console.log("Pesan atau file ID tidak valid."); + } + }; + + const sendReplyData = async (parentId: number) => { + const inputElement = document.querySelector( + `#input-comment-${parentId}` + ) as HTMLTextAreaElement; + + if (inputElement?.value?.length > 1 && selectedFileId) { + loading(); + const data = { + mediaUploadFileId: selectedFileId, + message: inputElement.value, + parentId, + }; + + console.log("Sending reply:", data); + const response = await saveMediaCurationMessage(data); + console.log(response); + + const responseGet = await getMediaCurationMessage(selectedFileId); + console.log("Updated comments:", responseGet?.data?.data); + setListData(responseGet?.data?.data); + + inputElement.value = ""; + close(); setReplyingTo(null); } }; + async function deleteDataSuggestion(dataId: any) { + loading(); + const response = await deleteMediaCurationMessage(dataId); + console.log(response); + const responseGet = await getMediaCurationMessage(selectedFileId); + console.log(responseGet?.data?.data); + setListData(responseGet?.data?.data); + close(); + } + + const deleteData = (dataId: any) => { + deleteDataSuggestion(dataId); + console.log(dataId); + }; + useEffect(() => { async function initState() { if (id) { @@ -174,16 +272,29 @@ export default function DetailImage() { const details = response?.data?.data; setDetail(details); + setSelectedFileId(details?.files[0]?.id); const filesData = details.files || []; - const fileUrls = filesData.map((file: { thumbnailFileUrl: string }) => - file.thumbnailFileUrl ? file.thumbnailFileUrl : "default-image.jpg" - ); + const fileUrls = filesData.map((file: any) => ({ + id: file.id, + thumbnailFileUrl: file.thumbnailFileUrl || "default-image.jpg", + })); setDetailThumb(fileUrls); } } initState(); }, [id, refresh]); + const handleFileClick = async (fileId: any) => { + setSelectedFileId(fileId); + try { + const response = await getMediaCurationMessage(fileId); + console.log("Data komentar:", response?.data?.data); + setListData(response?.data?.data); + } catch (error) { + console.error("Error fetching comments:", error); + } + }; + return (
{detail !== undefined ? ( @@ -336,11 +447,14 @@ export default function DetailImage() { className="w-full" > {detailThumb?.map((data: any) => ( - + handleFileClick(data.id)} + > {` ))} @@ -357,11 +471,14 @@ export default function DetailImage() { // className="mySwiper2" > {detailThumb?.map((data: any) => ( - + handleFileClick(data.id)} + > {` ))} @@ -432,112 +549,186 @@ export default function DetailImage() {
-
- -
- - - - - -
-
- - - -
-
-
- {commentsData.map((comment) => ( -
- - - -
- - {comment.username} - - - {comment.date} - -

{comment.text}

-
handleReply(comment.id)} - > - - Balas +
+ - -
- )}
diff --git a/app/[locale]/(protected)/shared/curated-content/giat-routine/image/image.tsx b/app/[locale]/(protected)/shared/curated-content/giat-routine/image/image.tsx index 937b95bf..96600dc7 100644 --- a/app/[locale]/(protected)/shared/curated-content/giat-routine/image/image.tsx +++ b/app/[locale]/(protected)/shared/curated-content/giat-routine/image/image.tsx @@ -8,7 +8,8 @@ import { CarouselNext, CarouselPrevious, } from "@/components/ui/carousel"; -import { getListContent } from "@/service/landing/landing"; +import { listCuratedContent } from "@/service/curated-content/curated-content"; + import { formatDateToIndonesian, generateLocalizedPath, @@ -35,10 +36,12 @@ const ImageSliderPage = () => { const [imageData, setImageData] = useState(); const [displayImage, setDisplayImage] = useState([]); const [page, setPage] = useState(1); + const [limit, setLimit] = React.useState(10); + const [search, setSearch] = React.useState(""); useEffect(() => { fetchData(); - }, [page]); + }, [page, limit, search]); useEffect(() => { if (imageData?.length > 0) { @@ -49,12 +52,7 @@ const ImageSliderPage = () => { }, [imageData]); const fetchData = async () => { - const response = await getListContent({ - page: page - 1, - size: 6, - sortBy: "createdAt", - contentTypeId: "1", - }); + const response = await listCuratedContent(search, limit, page - 1, 1, "1"); console.log(response); const data = response?.data?.data; diff --git a/app/[locale]/(protected)/shared/curated-content/giat-routine/video/audio-visual.tsx b/app/[locale]/(protected)/shared/curated-content/giat-routine/video/audio-visual.tsx index 523f860e..07070ec0 100644 --- a/app/[locale]/(protected)/shared/curated-content/giat-routine/video/audio-visual.tsx +++ b/app/[locale]/(protected)/shared/curated-content/giat-routine/video/audio-visual.tsx @@ -1,6 +1,7 @@ "use client"; import { Link } from "@/components/navigation"; import { Card, CardContent } from "@/components/ui/card"; +import { listCuratedContent } from "@/service/curated-content/curated-content"; import { getListContent } from "@/service/landing/landing"; import { formatDateToIndonesian } from "@/utils/globals"; import { Icon } from "@iconify/react/dist/iconify.js"; @@ -11,10 +12,12 @@ const VideoSliderPage = () => { const [allVideoData, setAllVideoData] = useState([]); const [displayVideos, setDisplayVideos] = useState([]); const [page, setPage] = useState(1); + const [limit, setLimit] = React.useState(10); + const [search, setSearch] = React.useState(""); useEffect(() => { - initFetch(); - }, []); + fetchData(); + }, [page, limit, search]); useEffect(() => { if (allVideoData?.length > 0) { @@ -24,14 +27,13 @@ const VideoSliderPage = () => { } }, [allVideoData]); - const initFetch = async () => { - const response = await getListContent({ - page: page - 1, - size: 12, - sortBy: "createdAt", - contentTypeId: "2", - }); - setAllVideoData(response?.data?.data?.content || []); + const fetchData = async () => { + const response = await listCuratedContent(search, limit, page - 1, 1, "2"); + console.log(response); + + const data = response?.data?.data; + const contentData = data?.content; + setAllVideoData(contentData); }; const shuffleAndSetVideos = () => { diff --git a/components/form/task/task-detail-form.tsx b/components/form/task/task-detail-form.tsx index caeb22d2..04b5a06f 100644 --- a/components/form/task/task-detail-form.tsx +++ b/components/form/task/task-detail-form.tsx @@ -23,6 +23,8 @@ import JoditEditor from "jodit-react"; import { createAssignmentResponse, createTask, + deleteAssignmentResponse, + getAcceptance, getAssignmentResponseList, getTask, getUserLevelForAssignments, @@ -34,12 +36,13 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; -import { ChevronDown, ChevronUp } from "lucide-react"; +import { ChevronDown, ChevronUp, DotSquare, TrashIcon } from "lucide-react"; import dynamic from "next/dynamic"; import { Link } from "@/components/navigation"; import { Textarea } from "@/components/ui/textarea"; -import { loading } from "@/lib/swal"; +import { close, loading } from "@/lib/swal"; import { getCookiesDecrypt } from "@/lib/utils"; +import { Avatar, AvatarImage } from "@/components/ui/avatar"; const taskSchema = z.object({ uniqueCode: z.string().min(1, { message: "Judul diperlukan" }), @@ -85,6 +88,24 @@ const ViewEditor = dynamic( { ssr: false } ); +const formatDate = (dateString: string): string => { + const date = new Date(dateString); + + // Pastikan validitas tanggal + if (isNaN(date.getTime())) { + throw new Error("Invalid date format"); + } + + // Format tanggal + const day = date.getDate().toString().padStart(2, "0"); + const month = (date.getMonth() + 1).toString().padStart(2, "0"); + const year = date.getFullYear(); + // const hours = date.getHours().toString().padStart(2, "0"); + + // Gabungkan hasil format + return `${day}-${month}-${year} `; +}; + export default function FormTaskDetail() { const MySwal = withReactContent(Swal); const router = useRouter(); @@ -123,6 +144,10 @@ export default function FormTaskDetail() { const [showInput, setShowInput] = useState(false); const [listData, setListData] = useState([]); const [message, setMessage] = useState(""); + const [sentAcceptance, setSentAcceptance] = useState([]); + const [acceptAcceptance, setAcceptAcceptance] = useState([]); + const [refreshAcceptance, setRefreshAcceptance] = useState(false); + const [replyingTo, setReplyingTo] = useState(null); const [platformTypeVisible, setPlatformTypeVisible] = useState(false); const [unitSelection, setUnitSelection] = useState({ @@ -307,10 +332,6 @@ export default function FormTaskDetail() { })); }; - // const handleToggleInput = () => { - // setShowInput((prev: any) => !prev); // Toggle visibility of input field - // }; - useEffect(() => { async function initState() { // loading(); @@ -324,11 +345,6 @@ export default function FormTaskDetail() { initState(); }, []); - // const handleSubmitResponse = () => { - // console.log("Response Submitted:", response); - // setShowInput(false); // Optionally hide the input after submission - // }; - const handleToggleInput = (): void => { setShowInput(!showInput); }; @@ -356,12 +372,39 @@ export default function FormTaskDetail() { sendSuggestionParent(); }; + const sendReplyData = async (parentId: number) => { + const inputElement = document.querySelector( + `#input-comment-${parentId}` + ) as HTMLTextAreaElement; + + if (inputElement?.value?.length > 1) { + loading(); + const data = { + assignmentId: id, + message: inputElement.value, + parentId, + }; + + console.log(data); + const response = await createAssignmentResponse(data); + console.log(response); + + const responseGet = await getAssignmentResponseList(id); + console.log(responseGet?.data?.data); + setListData(responseGet?.data?.data); + + inputElement.value = ""; + close(); + setReplyingTo(null); + } + }; + async function sendSuggestionParent() { if (message?.length > 1) { loading(); const data = { assignmentId: id, - message, // Gunakan response di sini + message, parentId: null, }; @@ -377,11 +420,93 @@ export default function FormTaskDetail() { } } + async function deleteDataSuggestion(dataId: any) { + loading(); + const response = await deleteAssignmentResponse(dataId); + console.log(response); + const responseGet = await getAssignmentResponseList(id); + console.log(responseGet?.data?.data); + setListData(responseGet?.data?.data); + close(); + } + + const deleteData = (dataId: any) => { + deleteDataSuggestion(dataId); + console.log(dataId); + }; + + // async function sendSuggestionChild(parentId: any) { + // const msg = document.querySelectorAll(`#input-comment-${parentId}`)[0] + // .value; + + // if (msg?.length > 1) { + // loading(); + // const data = { + // assignmentId: id, + // message: msg, + // parentId, + // }; + + // console.log(data); + // const response = await createAssignmentResponse(data); + // console.log(response); + // const responseGet = await getAssignmentResponseList(id); + // console.log(responseGet?.data?.data); + // setListData(responseGet?.data?.data); + // // $(":input").val(""); + // close(); + // } + // } + + async function getListAcceptance() { + const isAccept = true; + const resSent = await getAcceptance(id, !isAccept); + setSentAcceptance(resSent?.data?.data); + const resAccept = await getAcceptance(id, isAccept); + + const acceptanceSort = resAccept?.data?.data?.sort((a: any, b: any) => { + const dateA = new Date(a.acceptAt).getTime(); + const dateB = new Date(b.acceptAt).getTime(); + return dateA - dateB; + }); + + console.log("Data sort :", acceptanceSort); + setAcceptAcceptance(acceptanceSort); + } + + useEffect(() => { + async function initState() { + getListAcceptance(); + } + + initState(); + }, [refreshAcceptance]); + + const setFinishAcceptance = async (id: any, isFinish: any) => { + if (!isFinish) { + loading(); + + setRefreshAcceptance(!refreshAcceptance); + close(); + } + }; + + const handleReply = (id: any) => { + setReplyingTo(id); + }; + return ( -
-

Form Penugasan

- {detail !== undefined ? ( + {detail !== undefined ? ( +
+
+

Detail Penugasan

+
+ + +
+
+
@@ -546,7 +671,7 @@ export default function FormTaskDetail() {
setMainType(value)} // value={String(mainType)} // onValueChange={(value) => setMainType(Number(value))} @@ -575,8 +700,8 @@ export default function FormTaskDetail() {
setType(value)} // Mengubah nilai state ketika pilihan berubah + value={detail.assignmentType.id.toString()} + onValueChange={(value) => setType(value)} className="flex flex-wrap gap-3" >
@@ -690,27 +815,163 @@ export default function FormTaskDetail() {
)}
-

Tanggapan

+

Tanggapan

{listData?.map((item: any) => ( -
-
- {item.name} - - {item.timestamp} - -
-

{item.content}

-
- - +
+
+ + + +
+
+ + {item.suggestionFrom.username} + + + {formatDate(item.createdAt)} + +
+

{item.message}

+
+
handleReply(item.id)} + > + + Balas +
+
deleteData(item.id)} + > + + Delete +
+
+
+ {replyingTo === item.id && ( +
+