import { NativeStackScreenProps } from '@react-navigation/native-stack'; import React, { useState, useEffect, useCallback, FC } from 'react'; import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Alert, ActivityIndicator, } from 'react-native'; import { RootStackParamList } from '../navigation/AppNavigator'; // Adjust path import { apiCall } from '../utils/ApiHelper'; // Adjust path import AppView from '../components/AppView'; // Adjust path import colors from '../components/colors'; // Adjust path // --- Type Definitions --- interface Participant { id: string; firstName: string; lastName: string | null; mobile: string; role: 'ORGANIZER' | 'USER'; } interface GroupDetails { id: string; groupName: string; description: string; contributionAmount: number; maxParticipants: number; cycleType: 'QUARTERLY' | 'MONTHLY' | 'WEEKLY' | 'CUSTOM'; status: 'PENDING' | 'ACTIVE' | 'COMPLETED' | 'APPROVED'; organizerFirstName: string; organizerLastName: string | null; totalParticipants: number; participants: Participant[]; } type InviteScreenProps = NativeStackScreenProps; // Assuming 'Invite' is in your stack // --- Main Screen Component --- const InviteScreen: FC = ({ route }) => { const { groupId,code} = route.params; const [groupDetails, setGroupDetails] = useState(null); const [loading, setLoading] = useState(true); const [joining, setJoining] = useState(false); const [error, setError] = useState(null); const fetchGroupDetails = useCallback(async () => { setLoading(true); setError(null); try { const response = await apiCall(`https://exotic-humpback-mistakenly.ngrok-free.app/api/fund/group/details?groupId=${groupId}`, 'GET') as { status: string; data?: GroupDetails; message?: string }; if (response.status === 'success' && response.data) { setGroupDetails(response.data); } else { throw new Error(response.message || 'Failed to fetch group invitation details.'); } } catch (e: any) { setError(e.message); } finally { setLoading(false); } }, [groupId]); useEffect(() => { fetchGroupDetails(); }, [fetchGroupDetails]); const handleJoinGroup = async () => { if (!groupDetails) return; setJoining(true); try { // Replace with your actual API call to join the group // For now, it just shows an alert. await apiCall(`https://exotic-humpback-mistakenly.ngrok-free.app/api/fund/groups/join/invite/${code}`, 'POST'); Alert.alert('Success!', `You have requested to join "${groupDetails.groupName}".`); } catch (e: any) { Alert.alert('Join Error', e.message || 'An unexpected error occurred.'); } finally { setJoining(false); } }; if (loading) return ; if (error) return {error}; if (!groupDetails) return null; const organizerName = `${groupDetails.organizerFirstName} ${groupDetails.organizerLastName || ''}`.trim(); return ( You're Invited! Join the group {groupDetails.groupName} {/* Group Info Card */} Group Details {/* Participants Card */} Participants ({groupDetails.totalParticipants} / {groupDetails.maxParticipants}) {groupDetails.participants.length > 0 ? ( groupDetails.participants.map(p => ( {`${p.firstName} ${p.lastName || ''}`.trim()} {p.role === 'ORGANIZER' && Organizer} )) ) : ( Be the first to join! )} {/* Floating Join Button */} {joining ? ( ) : ( {groupDetails.status === 'PENDING' || groupDetails.status === 'APPROVED' ? 'Join Group' : `Group is ${groupDetails.status}`} )} ); }; // Helper component for displaying rows const InfoRow = ({ label, value }: { label: string; value: string | number }) => ( {label} {value} ); const styles = StyleSheet.create({ centered: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F3F4F6' }, errorText: { color: '#EF4444', fontSize: 16, textAlign: 'center', padding: 20 }, contentContainer: { padding: 16, paddingBottom: 100 }, // Add padding to avoid overlap with button headerTitle: { fontSize: 32, fontWeight: 'bold', color: '#111827', textAlign: 'center' }, headerSubtitle: { fontSize: 18, color: '#4B5563', textAlign: 'center', marginBottom: 24, marginTop: 4 }, card: { backgroundColor: '#FFFFFF', borderRadius: 16, padding: 20, marginBottom: 16, shadowColor: '#374151', shadowOpacity: 0.05, shadowRadius: 10 }, cardTitle: { fontSize: 18, fontWeight: 'bold', color: '#1F2937', marginBottom: 12, borderBottomWidth: 1, borderBottomColor: '#E5E7EB', paddingBottom: 10 }, infoRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 8 }, infoLabel: { fontSize: 16, color: '#6B7280' }, infoValue: { fontSize: 16, fontWeight: '600', color: '#111827', textTransform: 'capitalize' }, participantRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 10 }, participantName: { fontSize: 16, color: '#1F2937' }, organizerBadge: { backgroundColor: '#FEF3C7', paddingHorizontal: 8, paddingVertical: 3, borderRadius: 12 }, organizerBadgeText: { color: '#92400E', fontSize: 12, fontWeight: '500' }, noParticipantsText: { fontSize: 15, color: '#6B7280', textAlign: 'center', paddingVertical: 10 }, floatingButtonContainer: { position: 'absolute', bottom: 20, left: 20, right: 20, alignItems: 'center', }, joinButton: { backgroundColor: colors.primary, borderRadius: 14, paddingVertical: 16, paddingHorizontal: 32, elevation: 5, shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.3, shadowRadius: 4, width: '80%', alignItems: 'center', }, joinButtonText: { color: '#FFFFFF', fontSize: 18, fontWeight: 'bold', }, disabledButton: { backgroundColor: '#9CA3AF', // Gray color when disabled }, }); export default InviteScreen;