upd: caching data

Deskripsi:
- update caching pada fitur utama -yg fitur divisi belom
This commit is contained in:
2026-04-20 14:23:14 +08:00
parent 772551a917
commit ccf8ee1caf
27 changed files with 767 additions and 766 deletions

View File

@@ -1,4 +1,3 @@
import BorderBottomItem from "@/components/borderBottomItem";
import BorderBottomItemVertical from "@/components/borderBottomItemVertical";
import SkeletonTwoItem from "@/components/skeletonTwoItem";
import Text from "@/components/Text";
@@ -10,7 +9,8 @@ import { pushToPage } from "@/lib/pushToPage";
import { useAuthSession } from "@/providers/AuthProvider";
import { useTheme } from "@/providers/ThemeProvider";
import { Feather } from "@expo/vector-icons";
import { useEffect, useState } from "react";
import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query";
import { useEffect, useMemo, useState } from "react";
import { RefreshControl, SafeAreaView, View, VirtualizedList } from "react-native";
import { useDispatch, useSelector } from "react-redux";
@@ -27,64 +27,61 @@ type Props = {
export default function Notification() {
const { token, decryptToken } = useAuthSession()
const { colors } = useTheme();
const [loading, setLoading] = useState(false)
const [data, setData] = useState<Props[]>([])
const [page, setPage] = useState(1)
const [waiting, setWaiting] = useState(false)
const arrSkeleton = Array.from({ length: 5 }, (_, index) => index)
const queryClient = useQueryClient()
const dispatch = useDispatch()
const updateNotification = useSelector((state: any) => state.notificationUpdate)
const [refreshing, setRefreshing] = useState(false)
async function handleLoad(loading: boolean, thisPage: number) {
try {
setLoading(loading)
setPage(thisPage)
setWaiting(true)
// TanStack Query for Notifications with Infinite Scroll
const {
data,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
isLoading,
refetch
} = useInfiniteQuery({
queryKey: ['notifications'],
queryFn: async ({ pageParam = 1 }) => {
const hasil = await decryptToken(String(token?.current))
const response = await apiGetNotification({ user: hasil, page: thisPage })
if (thisPage == 1) {
setData(response.data)
} else if (thisPage > 1 && response.data.length > 0) {
setData([...data, ...response.data])
} else {
return;
}
} catch (error) {
console.error(error)
} finally {
setLoading(false)
setWaiting(false)
}
}
const response = await apiGetNotification({ user: hasil, page: pageParam })
return response;
},
initialPageParam: 1,
getNextPageParam: (lastPage, allPages) => {
return lastPage.data.length > 0 ? allPages.length + 1 : undefined;
},
enabled: !!token?.current,
staleTime: 0,
})
// Flatten pages into a single data array
const flatData = useMemo(() => {
return data?.pages.flatMap(page => page.data) || [];
}, [data])
const loadMoreData = () => {
if (waiting) return
setTimeout(() => {
handleLoad(false, page + 1)
}, 1000);
// Refetch when manual update state changes
useEffect(() => {
refetch()
}, [updateNotification, refetch])
const handleRefresh = async () => {
setRefreshing(true)
await queryClient.invalidateQueries({ queryKey: ['notifications'] })
setRefreshing(false)
};
useEffect(() => {
handleLoad(true, 1)
}, [])
const getItem = (_data: unknown, index: number): Props => ({
id: data[index].id,
title: data[index].title,
desc: data[index].desc,
category: data[index].category,
idContent: data[index].idContent,
isRead: data[index].isRead,
createdAt: data[index].createdAt,
});
const loadMoreData = () => {
if (hasNextPage && !isFetchingNextPage) {
fetchNextPage()
}
};
async function handleReadNotification(id: string, category: string, idContent: string) {
try {
const hasil = await decryptToken(String(token?.current))
const response = await apiReadOneNotification({ user: hasil, id: id })
await queryClient.invalidateQueries({ queryKey: ['notifications'] })
pushToPage(category, idContent)
dispatch(setUpdateNotification(!updateNotification))
} catch (error) {
@@ -92,28 +89,33 @@ export default function Notification() {
}
}
const handleRefresh = async () => {
setRefreshing(true)
handleLoad(false, 1)
await new Promise(resolve => setTimeout(resolve, 2000));
setRefreshing(false)
};
const arrSkeleton = [0, 1, 2, 3, 4]
const getItem = (_data: unknown, index: number): Props => ({
id: flatData[index]?.id,
title: flatData[index]?.title,
desc: flatData[index]?.desc,
category: flatData[index]?.category,
idContent: flatData[index]?.idContent,
isRead: flatData[index]?.isRead,
createdAt: flatData[index]?.createdAt,
});
return (
<SafeAreaView style={[Styles.flex1, { backgroundColor: colors.background }]}>
<View style={[Styles.p15]}>
{
loading ?
isLoading ?
arrSkeleton.map((item, index) => {
return (
<SkeletonTwoItem key={index} />
)
})
:
data.length > 0 ?
flatData.length > 0 ?
<VirtualizedList
data={data}
getItemCount={() => data.length}
data={flatData}
getItemCount={() => flatData.length}
getItem={getItem}
renderItem={({ item, index }: { item: Props, index: number }) => {
return (