diff --git a/src/app/(application)/layout.tsx b/src/app/(application)/layout.tsx index 8eb45f9..d2839d0 100644 --- a/src/app/(application)/layout.tsx +++ b/src/app/(application)/layout.tsx @@ -1,4 +1,4 @@ -import { WrapLayout } from "@/module/_global" +import { ScrollProvider, WrapLayout } from "@/module/_global" import { funDetectCookies, funGetUserByCookies } from "@/module/auth" import _ from "lodash" import { redirect } from "next/navigation" @@ -11,7 +11,9 @@ export default async function Layout({ children }: { children: React.ReactNode } return ( <> - {children} + + {children} + ); diff --git a/src/app/api/announcement/route.ts b/src/app/api/announcement/route.ts index 279f728..3bf8a44 100644 --- a/src/app/api/announcement/route.ts +++ b/src/app/api/announcement/route.ts @@ -24,6 +24,8 @@ export async function GET(request: Request) { const groupId = user.idGroup const { searchParams } = new URL(request.url); const name = searchParams.get('search'); + const page = searchParams.get('page'); + const dataSkip = Number(page) * 10 - 10; let kondisi: any = { idVillage: String(villageId), @@ -76,6 +78,8 @@ export async function GET(request: Request) { const announcements = await prisma.announcement.findMany({ + skip: dataSkip, + take: 10, where: kondisi, select: { id: true, @@ -128,7 +132,8 @@ export async function POST(request: Request) { let memberDivision = [] - for (var i = 0, l = groups.length; i < l; i++) {2 + for (var i = 0, l = groups.length; i < l; i++) { + 2 var obj = groups[i].Division; for (let index = 0; index < obj.length; index++) { const element = obj[index]; diff --git a/src/module/_global/bin/val_global.ts b/src/module/_global/bin/val_global.ts index 7813d32..4ec8875 100644 --- a/src/module/_global/bin/val_global.ts +++ b/src/module/_global/bin/val_global.ts @@ -1,5 +1,6 @@ import { hookstate } from "@hookstate/core" import { IGlobalTema } from './type_global'; +import { RefObject } from "react"; export const pwd_key_config = "fchgvjknlmdfnbvghhujlaknsdvjbhknlkmsdbdyu567t8y9u30r4587638y9uipkoeghjvuyi89ipkoefmnrjbhtiu4or9ipkoemnjfbhjiuoijdklnjhbviufojkejnshbiuojijknehgruyu" export const globalRole = hookstate('') @@ -24,4 +25,6 @@ export const TEMA = hookstate({ export const globalNotifPage = hookstate({ load: false, category: '' -}) \ No newline at end of file +}) + +export const currentScroll = hookstate | null>(null); \ No newline at end of file diff --git a/src/module/_global/components/scroll_provider.tsx b/src/module/_global/components/scroll_provider.tsx new file mode 100644 index 0000000..152019a --- /dev/null +++ b/src/module/_global/components/scroll_provider.tsx @@ -0,0 +1,38 @@ +"use client"; + +import { useHookstate } from "@hookstate/core"; +import { useEffect, useRef } from "react"; +import { Box } from "@mantine/core"; +import { currentScroll } from "../bin/val_global"; + +export function ScrollProvider({ children }: { children: React.ReactNode }) { + const containerRef = useRef(null); + const { set } = useHookstate(currentScroll); + + useEffect(() => { + if (window) { + const handleScroll = () => { + if (containerRef.current) { + set(containerRef); + } + }; + + const container = containerRef.current; + container?.addEventListener("scroll", handleScroll); + + return () => { + container?.removeEventListener("scroll", handleScroll); + }; + } + }, [containerRef, set]); + return ( + + {children} + + ); +} + diff --git a/src/module/_global/index.ts b/src/module/_global/index.ts index 0e47ef8..3f987f4 100644 --- a/src/module/_global/index.ts +++ b/src/module/_global/index.ts @@ -1,6 +1,6 @@ import MqttLoad from "./bin/mqtt_load"; import prisma from "./bin/prisma"; -import { DIR, globalNotifPage, globalRole, pwd_key_config, TEMA } from "./bin/val_global"; +import { currentScroll, DIR, globalNotifPage, globalRole, pwd_key_config, TEMA } from "./bin/val_global"; import SkeletonAvatar from "./components/skeleton_avatar"; import SkeletonDetailDiscussionComment from "./components/skeleton_detail_discussion_comment"; import SkeletonDetailDiscussionMember from "./components/skeleton_detail_discussion_member"; @@ -24,6 +24,7 @@ import ReloadButtonTop from "./components/reload_button_top"; import ViewFilter from "./view/view_filter"; import mtqq_client from "./bin/mqtt_client" import NotificationCustome from "./components/notification_custome"; +import { ScrollProvider } from "./components/scroll_provider"; export { WARNA }; export { LayoutLogin }; @@ -55,3 +56,5 @@ export { globalNotifPage } export { SkeletonAvatar } export { ReloadButtonTop } export { NotificationCustome } +export { ScrollProvider } +export { currentScroll } diff --git a/src/module/announcement/ui/list_announcement.tsx b/src/module/announcement/ui/list_announcement.tsx index dd7cb21..76e58fc 100644 --- a/src/module/announcement/ui/list_announcement.tsx +++ b/src/module/announcement/ui/list_announcement.tsx @@ -1,7 +1,7 @@ 'use client' -import { globalNotifPage, SkeletonSingle, TEMA, WARNA } from '@/module/_global'; +import { currentScroll, globalNotifPage, SkeletonSingle, TEMA, WARNA } from '@/module/_global'; import { ActionIcon, Box, Center, Divider, Grid, Group, Spoiler, Stack, Text, TextInput } from '@mantine/core'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { TfiAnnouncement } from "react-icons/tfi"; import { HiMagnifyingGlass } from 'react-icons/hi2'; import { useRouter, useSearchParams } from 'next/navigation'; @@ -9,7 +9,6 @@ import { useShallowEffect } from '@mantine/hooks'; import { IListDataAnnouncement } from '../lib/type_announcement'; import { funGetAllAnnouncement } from '../lib/api_announcement'; import toast from 'react-hot-toast'; -import { funGetAllGroup, IDataGroup } from '@/module/group'; import { useHookstate } from '@hookstate/core'; @@ -21,13 +20,24 @@ export default function ListAnnouncement() { const tema = useHookstate(TEMA) const load = useHookstate(globalNotifPage) - const fetchData = async () => { - try { - setLoading(true); - const response = await funGetAllAnnouncement('?search=' + searchQuery) + // ini + const { value: containerRef } = useHookstate(currentScroll); + const [isPage, setPage] = useState(1) + + const fetchData = async (loading: boolean) => { + try { + if (loading) + setLoading(true) + const response = await funGetAllAnnouncement('?search=' + searchQuery + '&page=' + isPage) if (response.success) { - setIsData(response?.data) + if (response.data.length > 0) { + if (isPage == 1) { + setIsData(response?.data) + } else { + setIsData([...isData, ...response?.data]) + } + } } else { toast.error(response.message); } @@ -40,16 +50,49 @@ export default function ListAnnouncement() { } } - useShallowEffect(() => { - fetchData() - }, [searchQuery, load.get().load]) + function onSearch(val:string){ + setSearchQuery(val) + setPage(1) + } useShallowEffect(() => { - if (load.get().category == "announcement") { - console.log('masuk sinii', load.get().load) - fetchData() - } - }, [load.get().load]) + fetchData(true) + }, [searchQuery]) + + + useShallowEffect(() => { + fetchData(false) + }, [isPage]) + + + // useShallowEffect(() => { + // if (load.get().category == "announcement") { + // console.log('masuk sinii', load.get().load) + // fetchData() + // } + // }, [load.get().load]) + + + useEffect(() => { + const handleScroll = async () => { + if (containerRef && containerRef.current) { + const scrollTop = containerRef.current.scrollTop; + const containerHeight = containerRef.current.clientHeight; + const scrollHeight = containerRef.current.scrollHeight; + + if (scrollTop + containerHeight >= scrollHeight) { + setPage(isPage + 1) + } + } + }; + + const container = containerRef?.current; + container?.addEventListener("scroll", handleScroll); + + return () => { + container?.removeEventListener("scroll", handleScroll); + }; + }, [containerRef, isPage]); return ( @@ -65,7 +108,7 @@ export default function ListAnnouncement() { radius={30} leftSection={} placeholder="Pencarian" - onChange={(e) => setSearchQuery(e.target.value)} + onChange={(e) => onSearch(e.target.value)} /> {loading ? Array(6)