import BorderBottomItem from "@/components/borderBottomItem"; import ButtonTab from "@/components/buttonTab"; import InputSearch from "@/components/inputSearch"; import LabelStatus from "@/components/labelStatus"; import PaperGridContent from "@/components/paperGridContent"; import ProgressBar from "@/components/progressBar"; import Skeleton from "@/components/skeleton"; import SkeletonTwoItem from "@/components/skeletonTwoItem"; import Text from "@/components/Text"; import WrapTab from "@/components/wrapTab"; import { ColorsStatus } from "@/constants/ColorsStatus"; import Styles from "@/constants/Styles"; import { apiGetProject } from "@/lib/api"; import { useAuthSession } from "@/providers/AuthProvider"; import { useTheme } from "@/providers/ThemeProvider"; import { AntDesign, Ionicons, MaterialCommunityIcons, } from "@expo/vector-icons"; import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query"; import { router, useLocalSearchParams } from "expo-router"; import { useEffect, useMemo, useState } from "react"; import { Pressable, RefreshControl, ScrollView, View, VirtualizedList } from "react-native"; import { useSelector } from "react-redux"; type Props = { id: string; title: string; desc: string; status: number; member: number; progress: number; createdAt: string; }; export default function ListProject() { const { status, group, cat, year } = useLocalSearchParams<{ status?: string; group?: string; cat?: string; year?: string; }>(); const [statusFix, setStatusFix] = useState<'0' | '1' | '2' | '3'>( (status == '1' || status == '2' || status == '3') ? status : '0' ) const { token, decryptToken } = useAuthSession(); const { colors } = useTheme(); const entityUser = useSelector((state: any) => state.user) const [search, setSearch] = useState("") const [isList, setList] = useState(false) const update = useSelector((state: any) => state.projectUpdate) const queryClient = useQueryClient() const [refreshing, setRefreshing] = useState(false) // TanStack Query for Projects with Infinite Scroll const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, refetch } = useInfiniteQuery({ queryKey: ['projects', { statusFix, search, group, cat, year }], queryFn: async ({ pageParam = 1 }) => { const hasil = await decryptToken(String(token?.current)); const response = await apiGetProject({ user: hasil, status: statusFix, search: search, group: String(group), kategori: String(cat), page: pageParam, year: String(year) }); return response; }, initialPageParam: 1, getNextPageParam: (lastPage, allPages) => { return lastPage.data.length > 0 ? allPages.length + 1 : undefined; }, enabled: !!token?.current, staleTime: 0, }) // Refetch when manual update state changes useEffect(() => { refetch() }, [update.data, refetch]) // Flatten pages into a single data array const flatData = useMemo(() => { return data?.pages.flatMap(page => page.data) || []; }, [data]) // Get metadata from the first available page const nameGroup = useMemo(() => data?.pages[0]?.filter?.name || "", [data]) const isYear = useMemo(() => data?.pages[0]?.tahun || "", [data]) const handleRefresh = async () => { setRefreshing(true) await queryClient.invalidateQueries({ queryKey: ['projects'] }) setRefreshing(false) }; const loadMoreData = () => { if (hasNextPage && !isFetchingNextPage) { fetchNextPage() } }; const arrSkeleton = [0, 1, 2] const getItem = (_data: unknown, index: number): Props => ({ id: flatData[index]?.id, title: flatData[index]?.title, desc: flatData[index]?.desc, status: flatData[index]?.status, member: flatData[index]?.member, progress: flatData[index]?.progress, createdAt: flatData[index]?.createdAt, }) return ( { setStatusFix("0") }} label="Segera" icon={ } n={4} /> { setStatusFix("1") }} label="Dikerjakan" icon={ } n={4} /> { setStatusFix("2") }} label="Selesai" icon={ } n={4} /> { setStatusFix("3") }} label="Batal" icon={ } n={4} /> { setList(!isList); }} > { Filter : { (entityUser.role == "supadmin" || entityUser.role == "developer") && } { (entityUser.role == 'user' || entityUser.role == 'coadmin') ? (cat == 'null' || cat == 'undefined' || cat == undefined || cat == '' || cat == 'data-saya') ? : : '' } } { isLoading ? isList ? arrSkeleton.map((item, index) => ( )) : arrSkeleton.map((item, index) => ( )) : flatData.length > 0 ? isList ? ( flatData.length} getItem={getItem} renderItem={({ item, index }: { item: Props, index: number }) => { return ( { router.push(`/project/${item.id}`); }} borderType="bottom" bgColor="transparent" icon={ } title={item.title} /> ); }} keyExtractor={(item, index) => index.toString()} onEndReached={loadMoreData} onEndReachedThreshold={0.5} showsVerticalScrollIndicator={false} refreshControl={ } /> ) : ( flatData.length} getItem={getItem} renderItem={({ item, index }: { item: Props, index: number }) => { return ( { router.push(`/project/${item.id}`); }} content="page" title={item.title} headerColor="primary" titleTail={2} > {item.createdAt} ); }} keyExtractor={(item, index) => index.toString()} onEndReached={loadMoreData} onEndReachedThreshold={0.5} showsVerticalScrollIndicator={false} refreshControl={ } /> ) : Tidak ada kegiatan } ); }