import React, { useState, useEffect, useCallback } from 'react'; import { View, Text, StyleSheet, FlatList, TouchableOpacity, ScrollView, ToastAndroid, RefreshControl, } from 'react-native'; import { useNavigation, useRoute, RouteProp, useFocusEffect } from '@react-navigation/native'; import { useSelector } from 'react-redux'; import { responsiveFontSize } from 'react-native-responsive-dimensions'; import LucideIcon from '../../components/common/LucideIcon'; import { APPROVE_REQUEST_URL, DECLINE_REQUEST_URL, GET_JOINED_GROUP_URL, MY_GROUPS_URL, REQUESTS_URL, USER_REQUEST } from '../../utils/ApiUrls'; import AppView from '../../components/AppView'; import { useTheme } from '../../hooks/ui/useTheme'; import { useFetch } from '../../hooks/core/useFetch'; import { useUpdate } from '../../hooks/core/useUpdate'; import { MyGroup, JoinRequest } from '../../types'; import MyGroupCard from '../../components/MyGroupCard'; import { JoinedGroupCard } from '../../components/JoinedGroupCard'; import { RequestCard } from '../../components/RequestCard'; import { UserRequested } from '../../components/UserRequested'; import SkeletonLoader from '../../components/common/SkeletonLoader'; import FontsFamily from '../../constents/FontsFamily'; import { RootTabParamList } from '../../navigation/BottomTabs'; type ManagementRouteProp = RouteProp; type ActiveTab = 'My Groups' | 'Joined Groups' | 'Requests' | 'My Requests'; type RequestSubTab = 'Join Requests' | 'My Requests'; type GroupStatusFilter = 'ALL' | 'PENDING' | 'APPROVED' | 'ACTIVE' | 'DELAY' | 'COMPLETED' | 'REJECTED' | 'CANCELLED'; const GROUP_STATUS_FILTERS: GroupStatusFilter[] = [ 'ALL', 'PENDING', 'APPROVED', 'ACTIVE', 'DELAY', 'COMPLETED', 'REJECTED', 'CANCELLED', ]; const JOINED_GROUP_STATUS_FILTERS: GroupStatusFilter[] = [ 'ALL', 'ACTIVE', 'DELAY', 'COMPLETED', 'APPROVED' ]; const getListFromResponse = (response: any): T[] => { if (!response) return []; if (Array.isArray(response?.data?.content)) return response.data.content; if (Array.isArray(response?.data)) return response.data; return []; }; const ManagementScreen: React.FC = () => { const theme = useTheme(); const user = useSelector((state: any) => state.user); const navigation = useNavigation(); const route = useRoute(); const [activeTab, setActiveTab] = useState( user.role === 'ORGANIZER' ? 'My Groups' : 'Joined Groups' ); const [myGroupStatusFilter, setMyGroupStatusFilter] = useState('APPROVED'); const [joinedGroupStatusFilter, setJoinedGroupStatusFilter] = useState('ALL'); const [requestSubTab, setRequestSubTab] = useState('Join Requests'); useEffect(() => { if (!route.params?.actionTab) return; const routeTab = route.params.actionTab as ActiveTab; setActiveTab(routeTab); }, [route.params?.actionTab]); const myGroupsParams = { ...(myGroupStatusFilter && myGroupStatusFilter !== 'ALL' ? { status: myGroupStatusFilter } : {}), page: 0, size: 10, }; const joinedGroupsParams = { ...(joinedGroupStatusFilter && joinedGroupStatusFilter !== 'ALL' ? { status: joinedGroupStatusFilter } : {}), page: 0, size: 10, }; const requestsParams = { page: 0, size: 10 }; const myRequestsParams = { page: 0, size: 10 }; const alwaysFreshFetchOptions = { staleTime: 0, gcTime: 0, refetchOnMount: 'always' as const, refetchOnReconnect: true, }; // Data Fetching const { data: myGroupsRes, isLoading: myLoading, isFetching: myFetching, refetch: refetchMy, } = useFetch( MY_GROUPS_URL, myGroupsParams, { enabled: user.role === 'ORGANIZER' && activeTab === 'My Groups', ...alwaysFreshFetchOptions } ); const { data: joinedRes, isLoading: joinedLoading, isFetching: joinedFetching, refetch: refetchJoined, } = useFetch( GET_JOINED_GROUP_URL, joinedGroupsParams, { enabled: activeTab === 'Joined Groups', ...alwaysFreshFetchOptions } ); const { data: requestsRes, isLoading: requestsLoading, isFetching: requestsFetching, refetch: refetchRequests, } = useFetch( REQUESTS_URL, requestsParams, { enabled: user.role === 'ORGANIZER' && activeTab === 'Requests' && requestSubTab === 'Join Requests', ...alwaysFreshFetchOptions, } ); const { data: userReqRes, isLoading: userReqLoading, isFetching: userReqFetching, refetch: refetchUserReq, } = useFetch( USER_REQUEST, myRequestsParams, { enabled: activeTab === 'My Requests' || (user.role === 'ORGANIZER' && activeTab === 'Requests' && requestSubTab === 'My Requests'), ...alwaysFreshFetchOptions, } ); const { mutate: updateRequest } = useUpdate(''); const myGroups = getListFromResponse(myGroupsRes); const joinedGroups = getListFromResponse(joinedRes); const incomingRequests = getListFromResponse(requestsRes); const myRequests = getListFromResponse(userReqRes); const [refreshing, setRefreshing] = useState(false); const onRefresh = useCallback(async () => { setRefreshing(true); const refreshTasks = [refetchJoined(), refetchUserReq()]; if (user.role === 'ORGANIZER') { refreshTasks.push(refetchMy(), refetchRequests()); } await Promise.all(refreshTasks).finally(() => { setRefreshing(false); }); }, [refetchMy, refetchJoined, refetchRequests, refetchUserReq, user.role]); const refetchActiveTab = useCallback(async () => { if (activeTab === 'My Groups' && user.role === 'ORGANIZER') { await refetchMy(); return; } if (activeTab === 'Joined Groups') { await refetchJoined(); return; } if (activeTab === 'Requests' && user.role === 'ORGANIZER') { if (requestSubTab === 'Join Requests') { await refetchRequests(); } else { await refetchUserReq(); } return; } if (activeTab === 'My Requests') { await refetchUserReq(); } }, [activeTab, requestSubTab, refetchMy, refetchJoined, refetchRequests, refetchUserReq, user.role]); useFocusEffect( useCallback(() => { refetchActiveTab(); }, [refetchActiveTab]) ); const tabs: ActiveTab[] = user.role === 'ORGANIZER' ? ['My Groups', 'Joined Groups', 'Requests'] : ['Joined Groups', 'My Requests']; const handleApprove = (req: JoinRequest) => { updateRequest({ resource: `${APPROVE_REQUEST_URL}${req.requestId}/approve`, payload: {} } as any, { onSuccess: () => { ToastAndroid.show('Request approved successfully', ToastAndroid.SHORT); refetchRequests(); }, onError: (err) => ToastAndroid.show(err.message || 'Failed to approve', ToastAndroid.SHORT), }); }; const handleDecline = (req: JoinRequest) => { updateRequest({ resource: `${DECLINE_REQUEST_URL}${req.requestId}/reject?reason=no Reason`, payload: {} } as any, { onSuccess: () => { ToastAndroid.show('Request declined', ToastAndroid.SHORT); refetchRequests(); }, onError: (err) => ToastAndroid.show(err.message || 'Failed to decline', ToastAndroid.SHORT), }); }; const handleManageGroup = (group: MyGroup) => navigation.navigate('ManagementTabs', { groupId: group.id }); const renderSkeletons = () => ( {[1, 2, 3].map(i => ( ))} ); const getFilteredData = () => { switch (activeTab) { case 'My Groups': return myGroups; case 'Joined Groups': return joinedGroups; case 'Requests': return requestSubTab === 'Join Requests' ? incomingRequests : myRequests; case 'My Requests': return myRequests; default: return []; } }; const isMyGroupsLoading = myLoading || myFetching; const isJoinedGroupsLoading = joinedLoading || joinedFetching; const isRequestsLoading = requestsLoading || requestsFetching; const isUserRequestsLoading = userReqLoading || userReqFetching; const isActiveTabLoading = activeTab === 'My Groups' ? isMyGroupsLoading : activeTab === 'Joined Groups' ? isJoinedGroupsLoading : activeTab === 'Requests' ? requestSubTab === 'Join Requests' ? isRequestsLoading : isUserRequestsLoading : isUserRequestsLoading; const listData = refreshing || isActiveTabLoading ? [] : getFilteredData(); return ( Account Hub Manage your circles and requests {tabs.map((tab) => ( setActiveTab(tab)} style={[ styles.tab, activeTab === tab && { backgroundColor: theme.colors.card, borderRadius: 12, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 2 } ]} > {tab} ))} {user.role === 'ORGANIZER' && activeTab === 'My Groups' && ( {GROUP_STATUS_FILTERS.map((status, index) => { const isActive = myGroupStatusFilter === status; return ( setMyGroupStatusFilter(status)} style={[ styles.statusFilterChip, index !== GROUP_STATUS_FILTERS.length - 1 && styles.statusFilterChipSpaced, { borderColor: isActive ? theme.colors.primary : theme.colors.border, backgroundColor: isActive ? theme.colors.primarySoft : theme.colors.surface, }, ]} > {status} ); })} )} {activeTab === 'Joined Groups' && ( {JOINED_GROUP_STATUS_FILTERS.map((status, index) => { const isActive = joinedGroupStatusFilter === status; return ( setJoinedGroupStatusFilter(status)} style={[ styles.statusFilterChip, index !== JOINED_GROUP_STATUS_FILTERS.length - 1 && styles.statusFilterChipSpaced, { borderColor: isActive ? theme.colors.primary : theme.colors.border, backgroundColor: isActive ? theme.colors.primarySoft : theme.colors.surface, }, ]} > {status} ); })} )} {activeTab === 'Requests' && user.role === 'ORGANIZER' && ( {(['Join Requests', 'My Requests'] as RequestSubTab[]).map((tab, index) => { const isActive = requestSubTab === tab; return ( setRequestSubTab(tab)} style={[ styles.statusFilterChip, index !== (['Join Requests', 'My Requests'] as RequestSubTab[]).length - 1 && styles.statusFilterChipSpaced, { borderColor: isActive ? theme.colors.primary : theme.colors.border, backgroundColor: isActive ? theme.colors.primarySoft : theme.colors.surface, }, ]} > {tab} ); })} )} String(item.id || item.requestId || index)} renderItem={({ item }) => { if (activeTab === 'My Groups') return ; if (activeTab === 'Joined Groups') return ; if (activeTab === 'Requests') { if (requestSubTab === 'Join Requests') { return ; } else { return ; } } if (activeTab === 'My Requests') return ; return null; }} refreshControl={ } ListEmptyComponent={ !isActiveTabLoading && !refreshing ? ( Nothing to show here ) : renderSkeletons() } /> ); }; const styles = StyleSheet.create({ header: { paddingHorizontal: 14, paddingTop: 10, paddingBottom: 12, zIndex: 10, }, headerTitleRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, refreshBtn: { padding: 8, borderRadius: 12, alignItems: 'center', justifyContent: 'center', }, title: { fontSize: responsiveFontSize(3.2), fontFamily: FontsFamily.nunitoBold, }, subtitle: { fontSize: responsiveFontSize(1.6), fontFamily: FontsFamily.nunitoRegular, marginTop: 4, }, tabContainer: { flexDirection: 'row', marginHorizontal: 12, padding: 5, borderRadius: 16, marginBottom: 12, zIndex: 10, }, tab: { flex: 1, paddingVertical: 10, alignItems: 'center', justifyContent: 'center', }, tabText: { fontSize: responsiveFontSize(1.4), fontFamily: FontsFamily.nunitoMedium, }, statusFilterContainer: { minHeight: 46, maxHeight: 46, marginBottom: 10, }, statusFilterRow: { paddingHorizontal: 12, alignItems: 'center', }, statusFilterChip: { borderWidth: 1, borderRadius: 999, minHeight: 34, paddingHorizontal: 14, paddingVertical: 0, justifyContent: 'center', alignSelf: 'center', }, statusFilterChipSpaced: { marginRight: 8, }, statusFilterText: { fontSize: responsiveFontSize(1.25), fontFamily: FontsFamily.nunitoSemiBold, }, listContent: { paddingBottom: 86, }, skeletonContainer: { paddingHorizontal: 12, }, emptyState: { alignItems: 'center', marginTop: 64, }, emptyText: { marginTop: 16, fontSize: responsiveFontSize(1.6), fontFamily: FontsFamily.nunitoMedium, }, }); export default ManagementScreen;