import React, { useState, useEffect } from 'react'; import { View, Text, StyleSheet, ScrollView, TouchableOpacity, RefreshControl, Alert, ActivityIndicator, TextInput } from 'react-native'; import { Ionicons } from '@react-native-vector-icons/ionicons'; import colors from '../../components/colors'; import DeclineModal from './DeclineModal'; import * as keychain from 'react-native-keychain' // Define TypeScript interfaces interface GroupRequest { requestId: string; groupName: string; groupId: string; userId: number; userName: string; mobile: string; status: string; } interface ApiResponse { message: string; status: string; statusCode: number; data: GroupRequest[]; } const RequestList: React.FC = () => { const [requests, setRequests] = useState([]); const [filteredRequests, setFilteredRequests] = useState([]); const [refreshing, setRefreshing] = useState(false); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [searchQuery, setSearchQuery] = useState(''); const [processingRequest, setProcessingRequest] = useState(null); const [showDeclineModal, setShowDeclineModal] = useState<{ modal: boolean, requestId: string | null }>({ modal: false, requestId: null }); const [selectedRequestId, setSelectedRequestId] = useState(null); // Fetch data from API const fetchRequests = async (): Promise => { const credentials = await keychain.getGenericPassword(); if (!credentials) { Alert.alert("Error", "You are not logged in"); return; } const token = credentials.password; try { setRefreshing(true); setError(null); const response = await fetch( "https://api.godemo.in/FundCollect/api/fund/group/pending/request", { method: "GET", headers: { accept: "*/*", Authorization: `Bearer ${token}` } } ); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data: ApiResponse = await response.json(); if (data.status === "success") { setRequests(data.data); setFilteredRequests(data.data); } else { throw new Error("Failed to fetch requests"); } } catch (error) { const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; setError(errorMessage); console.error("API Error:", error); } finally { setLoading(false); setRefreshing(false); } }; useEffect(() => { fetchRequests(); }, []); // Filter requests based on search query useEffect(() => { if (searchQuery.trim() === '') { setFilteredRequests(requests); } else { const query = searchQuery.toLowerCase(); const filtered = requests.filter(request => request.groupName.toLowerCase().includes(query) || request.userName.toLowerCase().includes(query) || request.mobile.includes(query) || request.status.toLowerCase().includes(query) ); setFilteredRequests(filtered); } }, [searchQuery, requests]); const handleAccept = async (requestId: string): Promise => { Alert.alert( "Accept Request", "Are you sure you want to accept this request?", [ { text: "Cancel", style: "cancel" }, { text: "Accept", onPress: async () => { try { setProcessingRequest(requestId); // Make API call to approve the request const response = await fetch( `https://api.godemo.in/FundCollect/api/fund/requests/${requestId}/approve`, { method: "PUT", headers: { "accept": "*/*", "Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2MjY1MjI5MzcxIiwidXNlcklkIjoiMTAwMDAxIiwiaWF0IjoxNzU4MDkxMjEzLCJleHAiOjE3NTgxNzc2MTN9.T3BvU7nl8fnjwwVobIWRmSFFxQzOjtyIct1Ba0i9lIU" } } ); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } // Parse response const data = await response.json(); if (data.status === "success") { // Remove the accepted request from the list const updatedRequests = requests.filter(req => req.requestId !== requestId); setRequests(updatedRequests); Alert.alert("Success", data.message || "Request accepted successfully"); fetchRequests(); } else { throw new Error(data.message || "Failed to accept request"); } } catch (error) { const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; // Alert.alert("Error", `Failed to accept request: ${errorMessage}`); console.error("Accept Error:", error); } finally { setProcessingRequest(null); } } } ] ); }; const handleDeclineConfirm = async (requestedId: string | null, reason: string) => { setShowDeclineModal({ modal: false, requestId: null }); try { setProcessingRequest(requestedId); // Make API call to decline the request const response = await fetch( `https://api.godemo.in/FundCollect/api/fund/requests/${requestedId}/reject?reason=/${reason}`, { method: "PUT", headers: { "accept": "*/*", "Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2MjY1MjI5MzcxIiwidXNlcklkIjoiMTAwMDAxIiwiaWF0IjoxNzU4MDkxMjEzLCJleHAiOjE3NTgxNzc2MTN9.T3BvU7nl8fnjwwVobIWRmSFFxQzOjtyIct1Ba0i9lIU" } } ); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } // Parse response const data = await response.json(); if (data.status === "success") { // Remove the declined request from the list const updatedRequests = requests.filter(req => req.requestId !== selectedRequestId); setRequests(updatedRequests); Alert.alert("Success", data.message || "Request declined successfully"); fetchRequests(); } else { throw new Error(data.message || "Failed to decline request"); } } catch (error) { const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; // Alert.alert("Error", `Failed to decline request: ${errorMessage}`); console.error("Decline Error:", error); } finally { setProcessingRequest(null); }// call your API }; const onRefresh = (): void => { fetchRequests(); }; const getInitials = (name: string): string => { return name .split(' ') .map(word => word.charAt(0)) .join('') .toUpperCase() .substring(0, 2); }; const clearSearch = (): void => { setSearchQuery(''); }; if (loading) { return ( Loading requests... ); } if (error) { return ( Error loading requests {error} Try Again ); } return ( Pending Requests {filteredRequests.length} pending group request{filteredRequests.length !== 1 ? 's' : ''} {searchQuery ? ` matching "${searchQuery}"` : ''} {/* Search Bar */} {searchQuery ? ( ) : null} } contentContainerStyle={filteredRequests.length === 0 ? styles.emptyScrollView : undefined} > {filteredRequests.length === 0 ? ( {searchQuery ? ( <> No matching requests No requests found for "{searchQuery}" Clear Search ) : ( <> No pending requests You're all caught up! There are no pending group requests. )} ) : ( filteredRequests.map((request) => ( {getInitials(request.groupName)} {request.groupName} Group Join Request {request.status} {request.userName} {request.mobile} setShowDeclineModal({ modal: true, requestId: request.requestId })} disabled={processingRequest === request.requestId} > {processingRequest === request.requestId ? ( ) : ( Decline )} handleAccept(request.requestId)} disabled={processingRequest === request.requestId} > {processingRequest === request.requestId ? ( ) : ( Accept )} )) )} {showDeclineModal.modal && ( setShowDeclineModal({ modal: false, requestId: null })} onSubmit={(reason) => handleDeclineConfirm(showDeclineModal.requestId, reason)} /> )} ); }; const styles = StyleSheet.create({ container: { paddingBottom: '100%', }, centerContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#f5f7fb', padding: 20, }, loadingText: { fontSize: 16, color: '#666', marginTop: 12, }, errorText: { fontSize: 18, fontWeight: '600', color: '#e74c3c', marginTop: 16, marginBottom: 8, }, errorSubText: { fontSize: 14, color: '#7f8c8d', textAlign: 'center', marginBottom: 20, }, retryButton: { backgroundColor: colors.pastelPink, paddingHorizontal: 20, paddingVertical: 10, borderRadius: 8, }, retryButtonText: { color: '#fff', fontWeight: '600', }, header: { // backgroundColor: '#fff', // // padding: 20, // borderBottomWidth: 1, // borderBottomColor: '#eee', // shadowColor: '#000', // shadowOffset: { width: 0, height: 2 }, // shadowOpacity: 0.1, // shadowRadius: 3, // elevation: 3, }, headerTitle: { fontSize: 24, fontWeight: 'bold', color: '#2c3e50', marginBottom: 5, }, headerSubtitle: { fontSize: 14, color: '#7f8c8d', }, // Search styles searchContainer: { flexDirection: 'row', alignItems: 'center', backgroundColor: '#fff', marginVertical: 16, marginBottom: 8, borderRadius: 10, paddingHorizontal: 12, height: 50, shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.1, shadowRadius: 2, elevation: 2, }, searchIcon: { marginRight: 8, }, searchInput: { flex: 1, height: '100%', fontSize: 16, color: '#2c3e50', padding: 0, }, clearButton: { padding: 4, }, clearSearchButton: { marginTop: 16, paddingVertical: 8, paddingHorizontal: 16, backgroundColor: '#ecf0f1', borderRadius: 6, }, clearSearchText: { color: '#7f8c8d', fontWeight: '500', }, emptyScrollView: { flexGrow: 1, justifyContent: 'center', }, requestCard: { backgroundColor: '#fff', borderRadius: 12, marginBottom: 16, padding: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3, }, cardHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12, }, groupInfo: { flexDirection: 'row', alignItems: 'center', flex: 1, }, avatar: { width: 50, height: 50, borderRadius: 25, backgroundColor: colors.pastelPink, justifyContent: 'center', alignItems: 'center', marginRight: 12, }, avatarText: { color: '#fff', fontSize: 16, fontWeight: 'bold', }, groupName: { fontSize: 18, fontWeight: '600', color: '#2c3e50', }, requestText: { fontSize: 14, color: '#7f8c8d', marginTop: 2, }, statusBadge: { paddingHorizontal: 10, paddingVertical: 5, borderRadius: 12, }, pendingBadge: { backgroundColor: '#fff4e6', }, otherBadge: { backgroundColor: '#e8f5e9', }, statusText: { fontSize: 12, fontWeight: '600', }, divider: { height: 1, backgroundColor: '#ecf0f1', marginVertical: 12, }, userInfo: { flexDirection: 'row', alignItems: 'center', marginBottom: 8, }, userName: { fontSize: 16, color: '#2c3e50', marginLeft: 8, }, userDetail: { fontSize: 14, color: '#7f8c8d', marginLeft: 8, }, actions: { flexDirection: 'row', justifyContent: 'flex-end', marginTop: 16, }, button: { paddingVertical: 10, paddingHorizontal: 20, borderRadius: 8, marginLeft: 12, minWidth: 100, alignItems: 'center', }, acceptButton: { backgroundColor: '#2ecc71', }, declineButton: { backgroundColor: '#fff', borderWidth: 1, borderColor: '#e74c3c', }, acceptButtonText: { color: '#fff', fontWeight: '600', }, declineButtonText: { color: '#e74c3c', fontWeight: '600', }, emptyState: { alignItems: 'center', justifyContent: 'center', padding: 40, }, emptyStateText: { fontSize: 18, fontWeight: '600', color: '#7f8c8d', marginTop: 16, marginBottom: 8, }, emptyStateSubtext: { fontSize: 14, color: '#bdc3c7', textAlign: 'center', }, }); export default RequestList;