From 5758d1926728847990a933d3c40c06d5b6c3998c Mon Sep 17 00:00:00 2001 From: amel Date: Mon, 4 Nov 2024 13:48:30 +0800 Subject: [PATCH 1/2] fix: tugas divisi Deskripsi; - klo lagi loading, total = 0 - pencarian - ga bisa semua di klik saat tampilan list - pencarian saat tambah anggota tambah tugas - loading skeleton saat pencarian anggota - menghapus fitur pilih semua pada pilih anggota - mengganti label error pada edit judul tugas - memberikan loading pada saat upload file No Issues --- src/module/task/ui/add_file_detail_task.tsx | 12 +- src/module/task/ui/add_member_detail_task.tsx | 12 +- src/module/task/ui/create_task.tsx | 1 - src/module/task/ui/create_users_project.tsx | 118 ++++++++---------- src/module/task/ui/edit_task.tsx | 2 +- src/module/task/ui/list_division_task.tsx | 24 ++-- src/module/task/ui/tabs_division_task.tsx | 77 ++++++------ 7 files changed, 119 insertions(+), 127 deletions(-) diff --git a/src/module/task/ui/add_file_detail_task.tsx b/src/module/task/ui/add_file_detail_task.tsx index cce9d78..7bc6884 100644 --- a/src/module/task/ui/add_file_detail_task.tsx +++ b/src/module/task/ui/add_file_detail_task.tsx @@ -2,7 +2,7 @@ import { keyWibu, LayoutDrawer, LayoutNavbarNew, TEMA } from "@/module/_global"; import LayoutModal from "@/module/_global/layout/layout_modal"; import { useHookstate } from "@hookstate/core"; -import { Box, Button, Flex, Group, rem, SimpleGrid, Stack, Text, } from "@mantine/core"; +import { Box, Button, Flex, Group, Loader, rem, SimpleGrid, Stack, Text, } from "@mantine/core"; import { Dropzone } from "@mantine/dropzone"; import _ from "lodash"; import { useParams, useRouter } from "next/navigation"; @@ -27,6 +27,7 @@ export default function AddFileDetailTask() { const [openDrawerFile, setOpenDrawerFile] = useState(false) const tema = useHookstate(TEMA) const openRef = useRef<() => void>(null) + const [loadingUpload, setLoadingUpload] = useState(false) const [dataRealTime, setDataRealtime] = useWibuRealtime({ WIBU_REALTIME_TOKEN: keyWibu, project: "sdm" @@ -41,6 +42,7 @@ export default function AddFileDetailTask() { async function cekFileName(data: any) { try { + setLoadingUpload(true) const fd = new FormData(); fd.append(`file`, data); const res = await funCekNamFileUploadTask(param.detail, fd) @@ -53,6 +55,8 @@ export default function AddFileDetailTask() { } catch (error) { console.error(error) toast.error("Gagal menambahkan file, coba lagi nanti") + } finally { + setLoadingUpload(false) } } @@ -146,6 +150,12 @@ export default function AddFileDetailTask() { } + { + loadingUpload && + + + + } ([]) const openRef = useRef<() => void>(null) const [fileForm, setFileForm] = useState([]) - const [imgForm, setImgForm] = useState() const [listFile, setListFile] = useState([]) const [indexDelFile, setIndexDelFile] = useState(0) const [indexDelTask, setIndexDelTask] = useState(0) diff --git a/src/module/task/ui/create_users_project.tsx b/src/module/task/ui/create_users_project.tsx index ab44a50..93eb957 100644 --- a/src/module/task/ui/create_users_project.tsx +++ b/src/module/task/ui/create_users_project.tsx @@ -1,38 +1,20 @@ "use client" -import { LayoutNavbarNew, SkeletonList, SkeletonSingle, TEMA } from "@/module/_global"; -import { funGetDivisionById, funGetSearchMemberDivision, IDataMemberDivision } from "@/module/division_new"; +import { LayoutNavbarNew, SkeletonList, TEMA } from "@/module/_global"; +import { funGetSearchMemberDivision, IDataMemberDivision } from "@/module/division_new"; import { useHookstate } from "@hookstate/core"; -import { - ActionIcon, - Avatar, - Box, - Button, - Center, - Divider, - Flex, - Grid, - Group, - Indicator, - rem, - Skeleton, - Stack, - Text, - TextInput, -} from "@mantine/core"; +import { Carousel } from "@mantine/carousel"; +import { ActionIcon, Avatar, Box, Button, Center, Divider, Flex, Grid, Group, Indicator, rem, Skeleton, Stack, Text, TextInput } from "@mantine/core"; import { useMediaQuery, useShallowEffect } from "@mantine/hooks"; import { useParams, useRouter } from "next/navigation"; -import React, { useState } from "react"; +import { useState } from "react"; import toast from "react-hot-toast"; -import { globalMemberTask } from "../lib/val_task"; -import { FaCheck } from "react-icons/fa6"; -import { RiListCheck } from "react-icons/ri"; import { BsListCheck } from "react-icons/bs"; +import { FaCheck } from "react-icons/fa6"; import { HiChevronLeft, HiMagnifyingGlass } from "react-icons/hi2"; import { IoArrowBackOutline, IoClose } from "react-icons/io5"; -import { Carousel } from "@mantine/carousel"; +import { globalMemberTask } from "../lib/val_task"; export default function CreateUsersProject({ onClose }: { onClose: (val: any) => void }) { - const router = useRouter() const param = useParams<{ id: string }>() const [selectedFiles, setSelectedFiles] = useState([]) const [isData, setData] = useState([]) @@ -57,7 +39,6 @@ export default function CreateUsersProject({ onClose }: { onClose: (val: any) => } else { toast.error(response.message) } - setLoading(false) } catch (error) { console.error(error) toast.error("Gagal mendapatkan anggota, coba lagi nanti"); @@ -122,6 +103,7 @@ export default function CreateUsersProject({ onClose }: { onClose: (val: any) => async function fetchGetMember(val: string) { setSearchQuery(val) try { + setLoading(true) const res = await funGetSearchMemberDivision('?search=' + val, param.id); if (res.success) { setData(res.data) @@ -130,6 +112,8 @@ export default function CreateUsersProject({ onClose }: { onClose: (val: any) => } } catch (error) { console.error(error); + } finally { + setLoading(false) } } @@ -228,7 +212,7 @@ export default function CreateUsersProject({ onClose }: { onClose: (val: any) => - {loading ? + {/* {loading ? : @@ -237,7 +221,7 @@ export default function CreateUsersProject({ onClose }: { onClose: (val: any) => - } + } */} {loading ? Array(8) @@ -249,47 +233,47 @@ export default function CreateUsersProject({ onClose }: { onClose: (val: any) => )) : (isData.length === 0) ? - - Tidak ada anggota - - : - isData.map((v, i) => { - const isSelected = selectedFiles.some((i: any) => i?.idUser == v.idUser); - return ( - handleFileClick(i)}> - - - - - - - - {v.name} + + Tidak ada anggota + + : + isData.map((v, i) => { + const isSelected = selectedFiles.some((i: any) => i?.idUser == v.idUser); + return ( + handleFileClick(i)} mt={i===0 ? 100 : 0}> + + + + + + + + {v.name} + + {isSelected ? : null} - {isSelected ? : null} - - - - - + + + + + - - ); - }) + ); + }) } diff --git a/src/module/task/ui/edit_task.tsx b/src/module/task/ui/edit_task.tsx index 957f508..4b0e320 100644 --- a/src/module/task/ui/edit_task.tsx +++ b/src/module/task/ui/edit_task.tsx @@ -114,7 +114,7 @@ export default function EditTask() { onChange={(e) => { onValidation('title', e.target.value) }} error={ touched.title && ( - title == "" ? "Error! harus memasukkan judul tugas" : null + title == "" ? "Judul Tugas Tidak Boleh Kosong" : null ) } /> diff --git a/src/module/task/ui/list_division_task.tsx b/src/module/task/ui/list_division_task.tsx index 1ec13f5..2c2ba17 100644 --- a/src/module/task/ui/list_division_task.tsx +++ b/src/module/task/ui/list_division_task.tsx @@ -1,15 +1,15 @@ import { currentScroll, globalNotifPage, ReloadButtonTop, SkeletonList, TEMA } from "@/module/_global"; +import { useHookstate } from "@hookstate/core"; import { ActionIcon, Avatar, Box, Card, Center, Divider, Flex, Grid, Group, Progress, Skeleton, Text, TextInput, Title } from "@mantine/core"; -import { useParams, useRouter, useSearchParams } from "next/navigation"; -import { useEffect, useState } from "react"; -import { HiMagnifyingGlass, HiMiniPresentationChartBar, HiOutlineListBullet, HiSquares2X2 } from "react-icons/hi2"; -import { MdAccountCircle } from "react-icons/md"; -import { IDataTask } from "../lib/type_task"; -import { funGetAllTask } from "../lib/api_task"; -import toast from "react-hot-toast"; import { useMediaQuery, useShallowEffect } from "@mantine/hooks"; import _ from "lodash"; -import { useHookstate } from "@hookstate/core"; +import { useParams, useRouter, useSearchParams } from "next/navigation"; +import { useEffect, useState } from "react"; +import toast from "react-hot-toast"; +import { HiMagnifyingGlass, HiMiniPresentationChartBar, HiOutlineListBullet, HiSquares2X2 } from "react-icons/hi2"; +import { MdAccountCircle } from "react-icons/md"; +import { funGetAllTask } from "../lib/api_task"; +import { IDataTask } from "../lib/type_task"; export default function ListDivisionTask() { const [isList, setIsList] = useState(false) @@ -46,8 +46,6 @@ export default function ListDivisionTask() { } else { toast.error(response.message); } - - setLoading(false); } catch (error) { toast.error("Gagal mendapatkan tugas divisi, coba lagi nanti"); console.error(error); @@ -149,7 +147,7 @@ export default function ListDivisionTask() { Total Tugas - {totalData} + {loading ? 0 : totalData} {isList ? ( @@ -173,7 +171,7 @@ export default function ListDivisionTask() { isData.map((v, i) => { return ( - + router.push(`task/${v.id}`)}> - router.push(`task/${v.id}`)}> +
- - {dataStatus.map((item, index) => ( - - ))} - - + style={{ + display: "flex", + gap: "20px", + position: "relative", + overflowX: "scroll", + scrollbarWidth: "none", + maxWidth: "550px" + }} + > + + {dataStatus.map((item, index) => ( + + ))} + + ) From 9f8cf53dd8de3ed9e0de382b809647c4fa9b3b0f Mon Sep 17 00:00:00 2001 From: amel Date: Mon, 4 Nov 2024 16:02:45 +0800 Subject: [PATCH 2/2] fix: diskusi deskripsi: -pencarian - loading pada update status dan hapus diskusi No Issues --- .../discussion/ui/detail_discussion.tsx | 3 +- .../ui/drawer_detail_discussion.tsx | 17 ++++--- .../discussion/ui/form_create_discussion.tsx | 27 ++++++----- src/module/discussion/ui/list_discussion.tsx | 48 +++++++++++++++---- 4 files changed, 62 insertions(+), 33 deletions(-) diff --git a/src/module/discussion/ui/detail_discussion.tsx b/src/module/discussion/ui/detail_discussion.tsx index 78e11a4..69b6ff9 100644 --- a/src/module/discussion/ui/detail_discussion.tsx +++ b/src/module/discussion/ui/detail_discussion.tsx @@ -6,7 +6,7 @@ import { ActionIcon, Avatar, Badge, Box, Center, Divider, Flex, Grid, Group, rem import { useMediaQuery, useShallowEffect } from "@mantine/hooks"; import moment from "moment"; import "moment/locale/id"; -import { useParams, useRouter } from "next/navigation"; +import { useParams } from "next/navigation"; import { useState } from "react"; import toast from "react-hot-toast"; import { GrChatOption } from "react-icons/gr"; @@ -23,7 +23,6 @@ export default function DetailDiscussion({ id, idDivision }: { id: string, idDiv const [isComent, setIsComent] = useState("") const param = useParams<{ id: string, detail: string }>() const [isLoad, setIsLoad] = useState(true) - const router = useRouter() const refresh = useHookstate(globalRefreshDiscussion) const roleLogin = useHookstate(globalRole) const [isCreator, setCreator] = useState(false) diff --git a/src/module/discussion/ui/drawer_detail_discussion.tsx b/src/module/discussion/ui/drawer_detail_discussion.tsx index 90859c6..ecaa105 100644 --- a/src/module/discussion/ui/drawer_detail_discussion.tsx +++ b/src/module/discussion/ui/drawer_detail_discussion.tsx @@ -23,13 +23,15 @@ export default function DrawerDetailDiscussion({ onSuccess, id, status, idDivisi WIBU_REALTIME_TOKEN: keyWibu, project: "sdm" }) + const [loadingUpdate, setLoadingUpdate] = useState(false) + const [loadingDelete, setLoadingDelete] = useState(false) async function fetchStatusDiscussion(val: boolean) { try { + setLoadingUpdate(true) if (val) { const response = await funEditStatusDiscussion(id, { status: status }) - if (response.success) { toast.success(response.message) refresh.set(!refresh.get()) @@ -38,40 +40,37 @@ export default function DrawerDetailDiscussion({ onSuccess, id, status, idDivisi id: id, }]) onSuccess(false) - setValModalStatus(false) } else { toast.error(response.message) } } - setValModalStatus(false) } catch (error) { console.error(error); - setValModalStatus(false) toast.error("Gagal menambahkan diskusi, coba lagi nanti"); } finally { + setLoadingUpdate(false) setValModalStatus(false) } } async function fetchDeleteDiscussion(val: boolean) { try { + setLoadingDelete(true) if (val) { const response = await funDeleteDiscussion(id) if (response.success) { toast.success(response.message) - setValModal(false) onSuccess(false) router.push(`/division/${param.id}/discussion`) } else { toast.error(response.message) } } - setValModal(false) } catch (error) { console.error(error); - setValModal(false) toast.error("Gagal hapus diskusi, coba lagi nanti"); } finally { + setLoadingDelete(false) setValModal(false) } } @@ -130,12 +129,12 @@ export default function DrawerDetailDiscussion({ onSuccess, id, status, idDivisi - setValModal(false)} + setValModal(false)} description="Apakah Anda yakin ingin menghapus diskusi ini?" onYes={(val) => { fetchDeleteDiscussion(val) }} /> - setValModalStatus(false)} + setValModalStatus(false)} description="Apakah Anda yakin ingin mengubah status diskusi ini?" onYes={(val) => { fetchStatusDiscussion(val) }} /> diff --git a/src/module/discussion/ui/form_create_discussion.tsx b/src/module/discussion/ui/form_create_discussion.tsx index e53f844..dfce046 100644 --- a/src/module/discussion/ui/form_create_discussion.tsx +++ b/src/module/discussion/ui/form_create_discussion.tsx @@ -15,7 +15,6 @@ export default function FormCreateDiscussion({ id }: { id: string }) { const [isValModal, setValModal] = useState(false) const [loadingModal, setLoadingModal] = useState(false) const router = useRouter() - const [isImg, setImg] = useState("") const param = useParams<{ id: string, detail: string }>() const [loading, setLoading] = useState(true) const [img, setIMG] = useState() @@ -51,25 +50,27 @@ export default function FormCreateDiscussion({ id }: { id: string }) { async function createDiscussion(val: boolean) { try { - setLoadingModal(true) - const response = await funCreateDiscussion({ - desc: isData.desc, - idDivision: id - }) + if (val) { + setLoadingModal(true) + const response = await funCreateDiscussion({ + desc: isData.desc, + idDivision: id + }) - if (response.success) { - setDataRealtime(response.notif) - toast.success(response.message) - router.push(`/division/${param.id}/discussion/`) - } else { - toast.error(response.message) + if (response.success) { + setDataRealtime(response.notif) + toast.success(response.message) + router.push(`/division/${param.id}/discussion/`) + } else { + toast.error(response.message) + } } } catch (error) { console.error(error); toast.error("Gagal menambahkan diskusi, coba lagi nanti"); } finally { - setValModal(false) setLoadingModal(false) + setValModal(false) } } diff --git a/src/module/discussion/ui/list_discussion.tsx b/src/module/discussion/ui/list_discussion.tsx index 43b9c47..500420d 100644 --- a/src/module/discussion/ui/list_discussion.tsx +++ b/src/module/discussion/ui/list_discussion.tsx @@ -1,16 +1,17 @@ 'use client' -import { currentScroll, TEMA } from "@/module/_global"; +import { currentScroll, globalNotifPage, ReloadButtonTop, TEMA } from "@/module/_global"; +import { useHookstate } from "@hookstate/core"; import { Avatar, Badge, Box, Divider, Flex, Grid, Group, Skeleton, Spoiler, Text, TextInput } from "@mantine/core"; -import { useParams, useRouter, useSearchParams } from "next/navigation"; +import { useShallowEffect } from "@mantine/hooks"; +import _ from "lodash"; +import { useParams, useRouter } from "next/navigation"; import { useEffect, useState } from "react"; +import toast from "react-hot-toast"; import { GrChatOption } from "react-icons/gr"; import { HiMagnifyingGlass } from "react-icons/hi2"; import { funGetAllDiscussion } from "../lib/api_discussion"; -import { useShallowEffect } from "@mantine/hooks"; import { IDataDiscussion } from "../lib/type_discussion"; -import toast from "react-hot-toast"; -import _ from "lodash"; -import { useHookstate } from "@hookstate/core"; + export default function ListDiscussion({ id }: { id: string }) { const [isData, setData] = useState([]) @@ -21,11 +22,12 @@ export default function ListDiscussion({ id }: { id: string }) { const router = useRouter() const { value: containerRef } = useHookstate(currentScroll); const [isPage, setPage] = useState(1) + const notifLoadPage = useHookstate(globalNotifPage) + const [isRefresh, setRefresh] = useState(false) const getData = async (loading: boolean) => { try { - if (loading) - setLoading(true) + setLoading(loading) const response = await funGetAllDiscussion('?division=' + id + '&search=' + searchQuery + '&page=' + isPage) if (response.success) { if (isPage == 1) { @@ -36,7 +38,6 @@ export default function ListDiscussion({ id }: { id: string }) { } else { toast.error(response.message) } - setLoading(false) } catch (error) { console.error(error) } finally { @@ -75,8 +76,37 @@ export default function ListDiscussion({ id }: { id: string }) { }, [containerRef, isPage]); + + useShallowEffect(() => { + console.log(notifLoadPage.get()) + if (notifLoadPage.get().category == 'division/' + param.id + '/discussion' && notifLoadPage.get().load == true) { + setRefresh(true) + } + }, [notifLoadPage.get().load]) + + function onRefresh() { + notifLoadPage.set({ + category: '', + load: false + }) + setRefresh(false) + setPage(1) + setTimeout(() => { + getData(false) + }, 500) + } + + return ( + { + isRefresh && + { onRefresh() }} + title='UPDATE' + /> + + }