// src/screens/ManagementScreen.tsx import React, { useState, useCallback, FC, useEffect } from "react"; import { View, Text, StyleSheet, FlatList, TouchableOpacity, ActivityIndicator, Alert, } from "react-native"; import { useNavigation, useFocusEffect, useRoute, RouteProp } from "@react-navigation/native"; import { StackNavigationProp } from "@react-navigation/stack"; import { APPROVE_REQUEST_URL, DECLINE_REQUEST_URL, GET_JOINED_GROUP_URL, MY_GROUPS_URL, REQUESTS_URL, USER_REQUEST } from "../../utils/ApiUrls"; import colors from "../../components/colors"; import AppView from "../../components/AppView"; import { apiCall } from "../../utils/ApiHelper"; import { MyGroup, JoinedGroup, JoinRequest, ApiResponse, UserJoinRequest } from '../../types'; // Adjust import path import { MyGroupCard } from "../../components/MyGroupCard"; import { JoinedGroupCard } from "../../components/JoinedGroupCard"; import { RequestCard } from "../../components/RequestCard"; import { useSelector } from "react-redux"; import { UserRequested } from "../../components/UserRequested"; import { RootTabParamList } from "../../navigation/BottomTabs"; // Adjust import path // --- TYPE DEFINITIONS --- type GroupManagementNavProp = StackNavigationProp; type ManagementRouteProp = RouteProp; type ActiveTab = "My Groups" | "Joined Groups" | "Requests" | "Your Requests"; const ManagementScreen: FC = () => { const user = useSelector((state: any) => state.user); const navigation = useNavigation(); const route = useRoute(); const [activeTab, setActiveTab] = useState(user.role === "USER" ? "Joined Groups" : "My Groups"); const [myGroups, setMyGroups] = useState([]); const [joinedGroups, setJoinedGroups] = useState([]); const [requests, setRequests] = useState([]); const [userRequest, setUserRequest] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); // --- HOOKS --- // Effect to set the initial tab from route params useEffect(() => { const passedTab = route.params?.actionTab; if (passedTab) { const availableTabs = user.role === 'ORGANIZER' ? ["My Groups", "Joined Groups", "Requests"] : ["Joined Groups", "Your Requests"]; if (availableTabs.includes(passedTab)) { setActiveTab(passedTab); } } }, [route.params?.actionTab, user.role]); // --- FIXED: fetchData dependency array is corrected --- const fetchData = useCallback(async () => { // Check for loading state at the start to prevent multiple simultaneous fetches if (loading) return; setLoading(true); setError(null); try { if (user.role === "ORGANIZER") { const [myGroupsRes, joinedGroupsRes, requestsRes] = await Promise.all([ apiCall(MY_GROUPS_URL, "GET") as Promise>, apiCall(GET_JOINED_GROUP_URL, "GET") as Promise>, apiCall(REQUESTS_URL, "GET") as Promise>, ]); setMyGroups(myGroupsRes.data || []); setJoinedGroups(joinedGroupsRes.data || []); setRequests(requestsRes.data || []); } else { const [joinedGroupsRes, userRequestRes] = await Promise.all([ apiCall(GET_JOINED_GROUP_URL, "GET") as Promise>, apiCall(USER_REQUEST, "GET") as Promise>, ]); setJoinedGroups(joinedGroupsRes.data || []); setUserRequest(userRequestRes.data || []); } } catch (e) { console.error("Fetch Data Error:", e); setError("Failed to fetch data. Please pull to refresh."); } finally { setLoading(false); } // The only external dependency that should trigger a re-fetch is the user's role. }, [user.role]); // **FIXED**: Removed `loading` from the dependency array // --- FIXED: useFocusEffect now has a stable dependency --- useFocusEffect( useCallback(() => { fetchData(); }, [fetchData]) // This will now only re-run if fetchData (and thus user.role) changes. ); // --- HANDLERS (No changes needed here) --- const handleViewGroup = (item: JoinedGroup) => { // Assuming you have an 'Invite' screen in your RootTabParamList or another navigator // navigation.navigate('Invite' as any, { groupId: item.id }); }; const handleAction = async (url: string, successMessage: string, failureMessage: string) => { try { // No need to set loading here if the whole screen is already loading const res = await apiCall(url, "PUT", {}) as ApiResponse | null; if (res && res.statusCode === 200) { Alert.alert("Success", res.message || successMessage); fetchData(); // Refresh data after action } else { throw new Error(res?.message || failureMessage); } } catch (err: any) { Alert.alert("Error", err.message || "An unexpected error occurred."); } }; const handleApprove = (req: JoinRequest) => handleAction(APPROVE_REQUEST_URL + req.requestId + "/approve", `${req.userName} has been added.`, "Failed to approve request."); const handleDecline = (req: JoinRequest) => handleAction(DECLINE_REQUEST_URL + req.requestId + "/reject?reason=/", `Request from ${req.userName} has been declined.`, "Failed to decline request."); const handleManageGroup = (group: MyGroup) => navigation.navigate('ManagementTabs', { groupId: group.id }); // --- RENDER LOGIC --- const renderContent = () => { if (error) return {error}; // Improved loading logic to avoid hiding existing data during a refresh if (loading && myGroups.length === 0 && joinedGroups.length === 0 && requests.length === 0) { return ; } switch (activeTab) { case "My Groups": return } keyExtractor={(item) => item.id} ListEmptyComponent={You haven't created any groups yet.} onRefresh={fetchData} refreshing={loading} contentContainerStyle={{ paddingBottom: 100 }} />; case "Joined Groups": return handleViewGroup(item)} />} keyExtractor={(item) => item.id} ListEmptyComponent={You haven't joined any groups yet.} onRefresh={fetchData} refreshing={loading} contentContainerStyle={{ paddingBottom: 100 }} />; case "Requests": return } keyExtractor={(item) => item.requestId} ListEmptyComponent={No pending join requests.} onRefresh={fetchData} refreshing={loading} contentContainerStyle={{ paddingBottom: 100 }} />; case "Your Requests": return } keyExtractor={(item) => item.requestId} ListEmptyComponent={You haven't sent any join requests.} onRefresh={fetchData} refreshing={loading} contentContainerStyle={{ paddingBottom: 100 }} />; default: return null; } }; const tabs: ActiveTab[] = user.role === 'ORGANIZER' ? ["My Groups", "Joined Groups", "Requests"] : ["Joined Groups", "Your Requests"]; return ( Group Management {tabs.map((tab) => ( setActiveTab(tab)}> {tab} ))} {renderContent()} ); }; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#f5f6fa' }, header: { paddingHorizontal: 20, paddingBottom: 15, paddingTop: 10 }, title: { fontSize: 22, fontWeight: "600", color: colors.Settings }, segmentedControl: { flexDirection: 'row', backgroundColor: '#e9ecef', borderRadius: 10, marginHorizontal: 20, marginBottom: 20, padding: 3 }, segmentButton: { flex: 1, paddingVertical: 12, alignItems: 'center', borderRadius: 8 }, segmentActive: { backgroundColor: colors.pastelOrange, elevation: 3, shadowColor: '#000', shadowOpacity: 0.1, shadowRadius: 5 }, segmentText: { fontSize: 14, fontWeight: '600', color: '#6c757d' }, segmentTextActive: { color: colors.textDark }, contentArea: { flex: 1, paddingHorizontal: 20 }, loader: { marginTop: 50 }, emptyText: { textAlign: 'center', marginTop: 60, fontSize: 16, color: '#6c757d' }, }); export default ManagementScreen;