From 2a44a6fbcf290f41b49446f368da0046c7b65738 Mon Sep 17 00:00:00 2001 From: amel Date: Mon, 14 Oct 2024 11:48:08 +0800 Subject: [PATCH 1/3] upd: jabatan Deskripsi: - update realtime create jabatan - update realtime edit jabatan - update realtime edit status jabatan No Issues --- src/app/api/position/[id]/route.ts | 1 - src/app/api/position/route.ts | 1 + src/module/_global/components/wrap_layout.tsx | 9 ------ .../position/ui/drawer_detail_position.tsx | 15 ++++++++- .../position/ui/drawer_list_position.tsx | 14 ++++++-- .../position/ui/list_position_active.tsx | 32 ++++++++++++------- 6 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/app/api/position/[id]/route.ts b/src/app/api/position/[id]/route.ts index 5d0d165..f469d63 100644 --- a/src/app/api/position/[id]/route.ts +++ b/src/app/api/position/[id]/route.ts @@ -120,7 +120,6 @@ export async function PUT(request: Request, context: { params: { id: string } }) }, data: { name: data.name, - // idGroup: data.idGroup, }, }); diff --git a/src/app/api/position/route.ts b/src/app/api/position/route.ts index 9112a5f..be5acd7 100644 --- a/src/app/api/position/route.ts +++ b/src/app/api/position/route.ts @@ -113,6 +113,7 @@ export async function POST(request: Request) { select: { id: true, name: true, + idGroup: true }, }); diff --git a/src/module/_global/components/wrap_layout.tsx b/src/module/_global/components/wrap_layout.tsx index efead1c..6d7869b 100644 --- a/src/module/_global/components/wrap_layout.tsx +++ b/src/module/_global/components/wrap_layout.tsx @@ -53,15 +53,6 @@ export default function WrapLayout({ children, role, theme, user }: { children: onClose={() => { '' }} /> } - - {/* { - '' - } - } - title='UPDATE' - /> */} {children} ); diff --git a/src/module/position/ui/drawer_detail_position.tsx b/src/module/position/ui/drawer_detail_position.tsx index 7ed430e..d81ad4e 100644 --- a/src/module/position/ui/drawer_detail_position.tsx +++ b/src/module/position/ui/drawer_detail_position.tsx @@ -1,4 +1,4 @@ -import { LayoutDrawer, TEMA, WARNA } from "@/module/_global" +import { keyWibu, LayoutDrawer, TEMA, WARNA } from "@/module/_global" import LayoutModal from "@/module/_global/layout/layout_modal" import { funGetAllGroup, IDataGroup } from "@/module/group" import { Box, Stack, SimpleGrid, Flex, Text, Select, TextInput, Button, Skeleton } from "@mantine/core" @@ -10,6 +10,7 @@ import { funEditPosition, funEditStatusPosition, funGetOnePosition } from "../li import { IDataPosition } from "../lib/type_position" import { useHookstate } from "@hookstate/core" import { globalRefreshPosition } from "../lib/val_posisition" +import { useWibuRealtime } from "wibu-realtime" export default function DrawerDetailPosition({ onUpdated, id, isActive }: { onUpdated: (val: boolean) => void, id: string, isActive: boolean; @@ -29,6 +30,10 @@ export default function DrawerDetailPosition({ onUpdated, id, isActive }: { const [touched, setTouched] = useState({ name: false, }); + const [dataRealTime, setDataRealtime] = useWibuRealtime({ + WIBU_REALTIME_TOKEN: keyWibu, + project: "sdm" + }) function onCLose() { onUpdated(true) @@ -78,6 +83,10 @@ export default function DrawerDetailPosition({ onUpdated, id, isActive }: { if (res.success) { toast.success(res.message); + setDataRealtime([{ + category: "data-position", + group: data.idGroup, + }]) refresh.set(!refresh.get()) onUpdated(true); onCLose(); @@ -122,6 +131,10 @@ export default function DrawerDetailPosition({ onUpdated, id, isActive }: { const res = await funEditStatusPosition(id, { isActive: isActive }) if (res.success) { toast.success(res.message); + setDataRealtime([{ + category: "data-position", + group: data.idGroup, + }]) refresh.set(!refresh.get()) onUpdated(true); } else { diff --git a/src/module/position/ui/drawer_list_position.tsx b/src/module/position/ui/drawer_list_position.tsx index 83d8ed2..78a647b 100644 --- a/src/module/position/ui/drawer_list_position.tsx +++ b/src/module/position/ui/drawer_list_position.tsx @@ -1,4 +1,4 @@ -import { WARNA, LayoutDrawer, globalRole, TEMA } from "@/module/_global"; +import { WARNA, LayoutDrawer, globalRole, TEMA, keyWibu } from "@/module/_global"; import { funGetAllGroup, IDataGroup } from "@/module/group"; import { Box, Stack, SimpleGrid, Flex, TextInput, Button, Text, Select } from "@mantine/core"; import { useShallowEffect } from "@mantine/hooks"; @@ -10,6 +10,7 @@ import { RiFilter2Line } from "react-icons/ri"; import { funCreatePosition } from "../lib/api_position"; import { useHookstate } from "@hookstate/core"; import { globalRefreshPosition } from "../lib/val_posisition"; +import { useWibuRealtime } from "wibu-realtime"; export default function DrawerListPosition({ onCreated }: { onCreated: (val: boolean) => void }) { @@ -26,11 +27,14 @@ export default function DrawerListPosition({ onCreated }: { onCreated: (val: boo name: false, idGroup: false }); - const [listData, setListData] = useState({ name: "", idGroup: "", }) + const [dataRealTime, setDataRealtime] = useWibuRealtime({ + WIBU_REALTIME_TOKEN: keyWibu, + project: "sdm" + }) async function getAllGroup() { try { @@ -60,10 +64,14 @@ export default function DrawerListPosition({ onCreated }: { onCreated: (val: boo }) if (res.success) { - setOpenDrawerGroup(false) toast.success(res.message) + setDataRealtime([{ + category: "data-position", + group: res.positions.idGroup, + }]) refresh.set(!refresh.get()) onCreated(true) + setOpenDrawerGroup(false) } else { toast.error(res.message) setOpenDrawerGroup(false) diff --git a/src/module/position/ui/list_position_active.tsx b/src/module/position/ui/list_position_active.tsx index ef7bd3e..c1c049a 100644 --- a/src/module/position/ui/list_position_active.tsx +++ b/src/module/position/ui/list_position_active.tsx @@ -1,17 +1,17 @@ -import { globalRole, LayoutDrawer, SkeletonSingle, TEMA, WARNA } from "@/module/_global"; +import { globalRole, keyWibu, LayoutDrawer, TEMA } from "@/module/_global"; +import { useHookstate } from "@hookstate/core"; import { ActionIcon, Box, Flex, Grid, Group, Skeleton, Text, TextInput } from "@mantine/core"; -import React, { useState } from "react"; -import { FaUserTie } from "react-icons/fa6"; -import { HiMagnifyingGlass } from "react-icons/hi2"; -import DrawerDetailPosition from "./drawer_detail_position"; -import toast from "react-hot-toast"; -import _ from "lodash"; import { useShallowEffect } from "@mantine/hooks"; import { useSearchParams } from "next/navigation"; +import { useState } from "react"; +import toast from "react-hot-toast"; +import { FaUserTie } from "react-icons/fa6"; +import { HiMagnifyingGlass } from "react-icons/hi2"; +import { useWibuRealtime } from "wibu-realtime"; import { funGetAllPosition } from "../lib/api_position"; import { IDataPosition } from "../lib/type_position"; -import { useHookstate } from "@hookstate/core"; import { globalRefreshPosition } from "../lib/val_posisition"; +import DrawerDetailPosition from "./drawer_detail_position"; export default function ListPositionActive() { @@ -29,10 +29,14 @@ export default function ListPositionActive() { const roleLogin = useHookstate(globalRole) const [nameGroup, setNameGroup] = useState('') const tema = useHookstate(TEMA) + const [dataRealTime, setDataRealtime] = useWibuRealtime({ + WIBU_REALTIME_TOKEN: keyWibu, + project: "sdm" + }) - async function getAllPosition() { + async function getAllPosition(loading: boolean) { try { - setLoading(true) + setLoading(loading) const res = await funGetAllPosition('?active=' + status + '&group=' + group + '&search=' + searchQuery) setDataPosition(res.data); setNameGroup(res.filter.name) @@ -46,9 +50,15 @@ export default function ListPositionActive() { } useShallowEffect(() => { - getAllPosition(); + getAllPosition(true); }, [status, group, searchQuery, refresh.get()]) + useShallowEffect(() => { + if (dataRealTime && dataRealTime.some((i: any) => i.category == 'data-position' && i.group == group)) { + getAllPosition(false) + } + }, [dataRealTime]) + return ( From 4bc043a8e147275e02b0b5254a3c64d390b34623 Mon Sep 17 00:00:00 2001 From: amel Date: Mon, 14 Oct 2024 15:30:42 +0800 Subject: [PATCH 2/3] upd: member Deskripsi: - realtime pada create member - realtime pada edit status member No Issues --- src/app/api/user/[id]/route.ts | 6 ++- src/app/api/user/route.ts | 5 ++- .../_global/components/reload_button_top.tsx | 2 +- src/module/user/member/ui/create_member.tsx | 11 ++++- .../user/member/ui/drawer_detail_member.tsx | 25 +++++------ src/module/user/member/ui/tab_list_member.tsx | 45 +++++++++++++++---- 6 files changed, 68 insertions(+), 26 deletions(-) diff --git a/src/app/api/user/[id]/route.ts b/src/app/api/user/[id]/route.ts index 7936848..f1d96c0 100644 --- a/src/app/api/user/[id]/route.ts +++ b/src/app/api/user/[id]/route.ts @@ -111,6 +111,10 @@ export async function DELETE(request: Request, context: { params: { id: string } data: { isActive: !isActive, }, + select: { + id: true, + idGroup: true, + }, }); // create log user @@ -120,7 +124,7 @@ export async function DELETE(request: Request, context: { params: { id: string } { success: true, message: "Berhasil mengupdate status anggota", - result, + data: result, }, { status: 200 } ); diff --git a/src/app/api/user/route.ts b/src/app/api/user/route.ts index 80ea26a..493ef89 100644 --- a/src/app/api/user/route.ts +++ b/src/app/api/user/route.ts @@ -186,7 +186,8 @@ export async function POST(request: Request) { idUserRole: data.idUserRole, }, select: { - id: true + id: true, + idGroup: true, }, }); @@ -211,7 +212,7 @@ export async function POST(request: Request) { // create log user const log = await createLogUser({ act: 'CREATE', desc: 'User membuat data user baru', table: 'user', data: users.id }) - return Response.json({ success: true, message: 'Sukses membuat user' }, { status: 200 }); + return Response.json({ success: true, message: 'Sukses membuat user', data: users}, { status: 200 }); } else { return Response.json({ success: false, message: "User sudah ada" }, { status: 400 }); } diff --git a/src/module/_global/components/reload_button_top.tsx b/src/module/_global/components/reload_button_top.tsx index cf2dd68..ca94071 100644 --- a/src/module/_global/components/reload_button_top.tsx +++ b/src/module/_global/components/reload_button_top.tsx @@ -13,7 +13,7 @@ export default function ReloadButtonTop({ onReload, title }: { onReload: () => v useShallowEffect(() => { const timer = setTimeout(() => { setOpened(true); - }, 2000); + }, 500); return () => clearTimeout(timer); }, []); diff --git a/src/module/user/member/ui/create_member.tsx b/src/module/user/member/ui/create_member.tsx index 060b197..326b801 100644 --- a/src/module/user/member/ui/create_member.tsx +++ b/src/module/user/member/ui/create_member.tsx @@ -1,5 +1,5 @@ "use client"; -import { globalRole, TEMA } from "@/module/_global"; +import { globalRole, keyWibu, TEMA } from "@/module/_global"; import LayoutModal from "@/module/_global/layout/layout_modal"; import { funGetUserByCookies } from "@/module/auth"; import { funGetAllGroup, IDataGroup } from "@/module/group"; @@ -16,6 +16,7 @@ import { FaCamera } from "react-icons/fa6"; import { valueRoleUser } from "../../lib/val_user"; import { funCreateMember } from "../lib/api_member"; import { IDataPositionMember, IDataROleMember } from "../lib/type_member"; +import { useWibuRealtime } from "wibu-realtime"; export default function CreateMember() { const router = useRouter(); @@ -29,6 +30,10 @@ export default function CreateMember() { const [imgForm, setImgForm] = useState() const openRef = useRef<() => void>(null) const tema = useHookstate(TEMA) + const [dataRealTime, setDataRealtime] = useWibuRealtime({ + WIBU_REALTIME_TOKEN: keyWibu, + project: "sdm" + }) const [touched, setTouched] = useState({ nik: false, name: false, @@ -118,6 +123,10 @@ export default function CreateMember() { )) const res = await funCreateMember(fd); if (res.success) { + setDataRealtime([{ + category: "data-member", + group: res.data.idGroup, + }]) toast.success(res.message); router.push("/member?active=true"); } else { diff --git a/src/module/user/member/ui/drawer_detail_member.tsx b/src/module/user/member/ui/drawer_detail_member.tsx index b8b4988..bb537fd 100644 --- a/src/module/user/member/ui/drawer_detail_member.tsx +++ b/src/module/user/member/ui/drawer_detail_member.tsx @@ -1,28 +1,23 @@ "use client"; -import { TEMA, WARNA } from "@/module/_global"; +import { keyWibu, TEMA } from "@/module/_global"; import LayoutModal from "@/module/_global/layout/layout_modal"; +import { useHookstate } from "@hookstate/core"; import { Box, Flex, SimpleGrid, Stack, Text } from "@mantine/core"; -import { useShallowEffect } from "@mantine/hooks"; import { useRouter } from "next/navigation"; import { useState } from "react"; import toast from "react-hot-toast"; import { FaPencil, FaToggleOff } from "react-icons/fa6"; -import { ImUserCheck } from "react-icons/im"; +import { useWibuRealtime } from "wibu-realtime"; import { funEditStatusMember } from "../lib/api_member"; -import { useHookstate } from "@hookstate/core"; -export default function DrawerDetailMember({ - onDeleted, - id, - status, -}: { - onDeleted: (val: boolean) => void; - id: string; - status: boolean; -}) { +export default function DrawerDetailMember({ onDeleted, id, status, }: { onDeleted: (val: boolean) => void; id: string; status: boolean; }) { const router = useRouter(); const [isModal, setModal] = useState(false); const tema = useHookstate(TEMA) + const [dataRealTime, setDataRealtime] = useWibuRealtime({ + WIBU_REALTIME_TOKEN: keyWibu, + project: "sdm" + }) async function nonActive(val: boolean) { try { @@ -31,6 +26,10 @@ export default function DrawerDetailMember({ isActive: status ? true : false, }); if (res.success) { + setDataRealtime([{ + category: "data-member", + group: res.data.idGroup, + }]) toast.success(res.message); router.push("/member?active=true"); onDeleted(true); diff --git a/src/module/user/member/ui/tab_list_member.tsx b/src/module/user/member/ui/tab_list_member.tsx index e370035..a6b0c47 100644 --- a/src/module/user/member/ui/tab_list_member.tsx +++ b/src/module/user/member/ui/tab_list_member.tsx @@ -1,14 +1,15 @@ -import { currentScroll, globalRole, SkeletonSingle, SkeletonUser, TEMA } from "@/module/_global" -import { Box, Text, TextInput, Divider, Avatar, Grid, Group, ActionIcon, Skeleton } from "@mantine/core" +import { currentScroll, globalRole, keyWibu, ReloadButtonTop, SkeletonUser, TEMA } from "@/module/_global" +import { useHookstate } from "@hookstate/core" +import { Avatar, Box, Divider, Grid, Text, TextInput } from "@mantine/core" import { useMediaQuery, useShallowEffect } from "@mantine/hooks" +import _ from "lodash" import { useRouter, useSearchParams } from "next/navigation" import { useEffect, useState } from "react" -import { HiMagnifyingGlass } from "react-icons/hi2" -import { IListMember } from "../lib/type_member" -import { funGetAllmember } from "../lib/api_member" import toast from "react-hot-toast" -import _ from "lodash" -import { useHookstate } from "@hookstate/core" +import { HiMagnifyingGlass } from "react-icons/hi2" +import { useWibuRealtime } from "wibu-realtime" +import { funGetAllmember } from "../lib/api_member" +import { IListMember } from "../lib/type_member" export default function TabListMember() { @@ -21,10 +22,16 @@ export default function TabListMember() { const status = searchParams.get('active') const roleLogin = useHookstate(globalRole) const [nameGroup, setNameGroup] = useState('') + const [idGroup, setIdGroup] = useState('') const tema = useHookstate(TEMA) const { value: containerRef } = useHookstate(currentScroll); const [isPage, setPage] = useState(1) const isMobile2 = useMediaQuery("(max-width: 438px)"); + const [dataRealTime, setDataRealtime] = useWibuRealtime({ + WIBU_REALTIME_TOKEN: keyWibu, + project: "sdm" + }) + const [isRefresh, setRefresh] = useState(false) async function getAllUser(loading: boolean) { @@ -34,10 +41,11 @@ export default function TabListMember() { const res = await funGetAllmember('?active=' + status + '&group=' + group + '&search=' + searchQuery + '&page=' + isPage) if (res.success) { setNameGroup(res.filter.name) + setIdGroup(res.filter.id) if (isPage == 1) { setDataMember(res.data) } else { - setDataMember([...dataMember, ...res.data]) + setDataMember((dataMember) => [...dataMember, ...res.data]) } } else { @@ -81,9 +89,30 @@ export default function TabListMember() { }; }, [containerRef, isPage]); + + useShallowEffect(() => { + if (dataRealTime && dataRealTime.some((i: any) => i.category == 'data-member' && i.group == idGroup)) { + setRefresh(true) + } + }, [dataRealTime]) + + function onRefresh() { + setRefresh(false) + setPage(1) + getAllUser(true) + } + return ( <> + { + isRefresh && + { onRefresh() }} + title='UPDATE' + /> + + } Date: Mon, 14 Oct 2024 17:53:20 +0800 Subject: [PATCH 3/3] upd: pengumuman Deskripsi: - update realtime tambah pengumuman pake yg refresh page No Issues --- src/module/_global/components/wrap_layout.tsx | 21 +++-- .../announcement/ui/list_announcement.tsx | 76 ++++++++++++++----- 2 files changed, 72 insertions(+), 25 deletions(-) diff --git a/src/module/_global/components/wrap_layout.tsx b/src/module/_global/components/wrap_layout.tsx index 6d7869b..1902a2a 100644 --- a/src/module/_global/components/wrap_layout.tsx +++ b/src/module/_global/components/wrap_layout.tsx @@ -5,7 +5,7 @@ import { useShallowEffect } from "@mantine/hooks"; import { useEffect, useState } from "react"; import { useWibuRealtime } from "wibu-realtime"; import NotificationCustome from "./notification_custome"; -import { useRouter } from "next/navigation"; +import { usePathname, useRouter } from "next/navigation"; import { globalParamJumlahNotif } from "@/module/home"; import ReloadButtonTop from "./reload_button_top"; @@ -20,6 +20,8 @@ export default function WrapLayout({ children, role, theme, user }: { children: WIBU_REALTIME_TOKEN: keyWibu, project: "sdm" }) + const path = usePathname() + useEffect(() => { roleLogin.set(role) @@ -29,11 +31,18 @@ export default function WrapLayout({ children, role, theme, user }: { children: useShallowEffect(() => { if (data && data.some((i: any) => i.idUserTo == user)) { - setTampilNotif(true) - paramNotif.set(!paramNotif.get()) - setTimeout(() => { - setTampilNotif(false); - }, 4000); + if (data.some((i: any) => i.category == path.substring(1))) { + notifLoadPage.set({ + category: path.substring(1), + load: true + }) + } else { + setTampilNotif(true) + paramNotif.set(!paramNotif.get()) + setTimeout(() => { + setTampilNotif(false); + }, 4000); + } } }, [data]) diff --git a/src/module/announcement/ui/list_announcement.tsx b/src/module/announcement/ui/list_announcement.tsx index 93f3f89..5a0c2c6 100644 --- a/src/module/announcement/ui/list_announcement.tsx +++ b/src/module/announcement/ui/list_announcement.tsx @@ -1,28 +1,29 @@ 'use client' -import { currentScroll, globalNotifPage, SkeletonSingle, SkeletonUser, TEMA, WARNA } from '@/module/_global'; -import { ActionIcon, Box, Center, Divider, Grid, Group, Spoiler, Stack, Text, TextInput } from '@mantine/core'; -import React, { useEffect, useState } from 'react'; -import { TfiAnnouncement } from "react-icons/tfi"; -import { HiMagnifyingGlass } from 'react-icons/hi2'; -import { useRouter, useSearchParams } from 'next/navigation'; -import { useShallowEffect } from '@mantine/hooks'; -import { IListDataAnnouncement } from '../lib/type_announcement'; -import { funGetAllAnnouncement } from '../lib/api_announcement'; -import toast from 'react-hot-toast'; +import { currentScroll, globalNotifPage, ReloadButtonTop, SkeletonUser, TEMA } from '@/module/_global'; +import { funGetUserByCookies } from '@/module/auth'; import { useHookstate } from '@hookstate/core'; +import { ActionIcon, Box, Center, Divider, Grid, Spoiler, Stack, Text, TextInput } from '@mantine/core'; +import { useShallowEffect } from '@mantine/hooks'; +import { useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import toast from 'react-hot-toast'; +import { HiMagnifyingGlass } from 'react-icons/hi2'; +import { TfiAnnouncement } from "react-icons/tfi"; +import { funGetAllAnnouncement } from '../lib/api_announcement'; +import { IListDataAnnouncement } from '../lib/type_announcement'; export default function ListAnnouncement() { const [isData, setIsData] = useState([]) + const [user, setUser] = useState('') const [searchQuery, setSearchQuery] = useState('') const router = useRouter() const [loading, setLoading] = useState(true); const tema = useHookstate(TEMA) - const load = useHookstate(globalNotifPage) - - // ini + const notifLoadPage = useHookstate(globalNotifPage) const { value: containerRef } = useHookstate(currentScroll); const [isPage, setPage] = useState(1) + const [isRefresh, setRefresh] = useState(false) const fetchData = async (loading: boolean) => { @@ -31,11 +32,11 @@ export default function ListAnnouncement() { setLoading(true) const response = await funGetAllAnnouncement('?search=' + searchQuery + '&page=' + isPage) if (response.success) { - if (isPage == 1) { - setIsData(response?.data) - } else { - setIsData([...isData, ...response?.data]) - } + if (isPage == 1) { + setIsData(response?.data) + } else { + setIsData([...isData, ...response?.data]) + } } else { toast.error(response.message); } @@ -48,7 +49,12 @@ export default function ListAnnouncement() { } } - function onSearch(val:string){ + async function onUser() { + const user = await funGetUserByCookies() + setUser(String(user.id)) + } + + function onSearch(val: string) { setSearchQuery(val) setPage(1) } @@ -63,6 +69,11 @@ export default function ListAnnouncement() { }, [isPage]) + useShallowEffect(() => { + onUser() + }, []) + + useEffect(() => { const handleScroll = async () => { @@ -84,8 +95,35 @@ export default function ListAnnouncement() { }; }, [containerRef, isPage]); + + useShallowEffect(() => { + if (notifLoadPage.get().category == 'announcement' && notifLoadPage.get().load == true) { + setRefresh(true) + } + }, [notifLoadPage.get().load]) + + function onRefresh() { + notifLoadPage.set({ + category: '', + load: false + }) + setRefresh(false) + setPage(1) + setTimeout(() => { + fetchData(true) + }, 500) + } + return ( + { + isRefresh && + { onRefresh() }} + title='UPDATE' + /> + + }