import React, { useEffect, useState, useCallback } from "react"; import { StyleSheet, Text, View, TouchableOpacity, ToastAndroid, RefreshControl, ScrollView, Modal, } from "react-native"; import { useRoute } from "@react-navigation/native"; import AppView from "../../../components/AppView"; import colors from "../../../components/colors"; import { Ionicons } from "@react-native-vector-icons/ionicons"; import Header from "../../../components/common/Header"; import { apiCall } from "../../../utils/ApiHelper"; import { BASE_URL, CONTRIBUTE, GROUP_ALL_MEMBER } from "../../../utils/ApiUrls"; import ContributionScreen from "../../ContributionScreen"; import CycleDashboard from "./CycleDashboard"; const CustomDropdown = ({ items, selectedValue, onValueChange, placeholder = "Select an item" }:any) => { const [open, setOpen] = useState(false); const selectedLabel = items.find((item:any) => item.value === selectedValue)?.label || placeholder; return ( setOpen(true)} style={styles.dropdownHeader}> {selectedLabel} setOpen(false)} > setOpen(false)}> {items.map(item => ( { onValueChange(item.value); setOpen(false); }} style={[ styles.dropdownItem, item.value === selectedValue && styles.selectedItem ]} > {item.label} ))} ); }; const GroupDetails = () => { const route = useRoute(); const [memberData, setMemberData] = useState([]); const [loading, setLoading] = useState(false); const [openModal, setOpenModal] = useState(false); const [payable, setPayable] = useState(); const [refreshing, setRefreshing] = useState(false); const [cycleDashboardData, setCycleDashboardData] = useState(); const [selectedCycleNumber, setSelectedCycleNumber] = useState(null); const [cycleItems, setCycleItems] = useState([]); const group = { id: route.params.item?.id, name: route.params.item?.groupName, collected: route.params.item?.contributionAmount, goal: route.params.item?.contributionAmount * route.params.item?.currentParticipants, description: route.params.item?.description, status: route.params.item?.status, members: memberData, }; const getCycleDashboard = async () => { try { const response = await apiCall(`${BASE_URL}payments/groups/${group.id}/cycle-dashboard`, "GET") as any; const responseData = response.data; setCycleDashboardData(responseData); if (responseData?.cycles) { const items = responseData.cycles.map(cycle => ({ label: `Cycle ${cycle.cycleNumber}`, value: cycle.cycleNumber })); setCycleItems(items); if (responseData.currentCycle) { setSelectedCycleNumber(responseData.currentCycle); } } } catch (error) { ToastAndroid.show("Failed to fetch cycle data", ToastAndroid.SHORT); } }; const fetchGroupDetails = async () => { try { const res = await apiCall(`${GROUP_ALL_MEMBER}?groupId=${group.id}`, "GET") as any; console.log("Group Members Response: ", res); setMemberData(res.data); } catch (error: any) { ToastAndroid.show(error?.message || "Failed to fetch group details", ToastAndroid.SHORT); } }; const handleContribution = async () => { try { const res = await apiCall(`${CONTRIBUTE}${group.id}/calculate-contribution`, 'GET') as any; setPayable(res.data); } catch (error) { console.log("Error in handleContribution: ", error); } }; const fetchAllData = useCallback(async () => { setLoading(true); await Promise.all([ fetchGroupDetails(), handleContribution(), getCycleDashboard() ]); setLoading(false); }, [group.id]); useEffect(() => { if (group.id) { fetchAllData(); } }, [group.id, fetchAllData]); const onRefresh = useCallback(async () => { setRefreshing(true); await fetchAllData(); setRefreshing(false); }, [fetchAllData]); const confirmPayment = async () => { try { const res = await apiCall(`${BASE_URL}payments/contribute/${group?.id}?amount=${payable?.totalPayable}`, 'POST') as any; if (res.status === 200 || res.status === 201) { ToastAndroid.show('Payment done!', ToastAndroid.SHORT); onRefresh(); } else { ToastAndroid.show(res?.data?.message || 'Payment failed!', ToastAndroid.SHORT); } } catch (error) { ToastAndroid.show("An error occurred during payment.", ToastAndroid.SHORT); } }; const selectedCycleData = cycleDashboardData?.cycles.find(c => c.cycleNumber === selectedCycleNumber); return ( } contentContainerStyle={styles.scrollContent} >
{group.description} {group.members.length ?? 0} Members ₹{group.collected} Contribution ₹{group.goal} Total Amount {cycleItems.length > 0 && ( )} {selectedCycleData && cycleDashboardData && ( )} Members {group.status} {memberData.map((member:any) => ( {member.firstName} {member.role === "Organizer" ? "(Organizer)" : ""} ))} {/* Button at the bottom inside scroll (no absolute positioning) */} {group.status === 'ACTIVE' && !payable?.hasPaid && ( setOpenModal(true)} style={styles.button}> Contribute )} {openModal && ( setOpenModal(false)} onConfirm={() => { confirmPayment(); setOpenModal(false); }} /> )} ); }; export default GroupDetails; const styles = StyleSheet.create({ dropdownWrapper: { marginHorizontal: 15, marginBottom: 20, }, dropdownHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: 12, borderWidth: 1, borderColor: '#ddd', borderRadius: 8, backgroundColor: '#fff', }, modalOverlay: { flex: 1, justifyContent: 'center', backgroundColor: 'rgba(0,0,0,0.4)', padding: 20, }, dropdownListContainer: { backgroundColor: '#fff', borderRadius: 8, padding: 10, maxHeight: 300, }, dropdownItem: { paddingVertical: 12, paddingHorizontal: 10, }, selectedItem: { backgroundColor: colors.pastelOrange, borderRadius: 6, }, itemText: { fontSize: 15, color: colors.black, }, description: { fontSize: 14, color: "#475569", marginBottom: 20, lineHeight: 20, paddingHorizontal: 15, }, statsRow: { flexDirection: "row", justifyContent: "space-around", marginBottom: 20, paddingHorizontal: 15, }, statBox: { alignItems: 'center', flex: 1, }, statValue: { fontSize: 18, fontWeight: '700', color: '#1e293b', }, statLabel: { fontSize: 12, color: '#64748b', marginTop: 4, }, membersHeader: { flexDirection: "row", justifyContent: "space-between", alignItems: 'center', paddingHorizontal: 15, marginTop: 20, marginBottom: 10, }, sectionTitle: { fontSize: 18, fontWeight: "600", color: "#0f172a", }, statusBadge: { backgroundColor: colors.pastelOrange, borderRadius: 20, paddingHorizontal: 12, paddingVertical: 6, elevation: 2, }, statusText: { fontSize: 14, fontWeight: '600', color: colors.Home, }, memberCard: { flexDirection: "row", alignItems: 'center', backgroundColor: '#fff', padding: 12, borderRadius: 12, marginBottom: 10, elevation: 2, marginHorizontal: 15, }, memberInfo: { marginLeft: 10, }, memberName: { fontSize: 15, fontWeight: "600", color: "#1e293b", }, button: { backgroundColor: colors.pastelOrange, marginHorizontal: 15, marginTop: 20, marginBottom: 30, elevation: 5, paddingVertical: 14, borderRadius: 10, alignItems: "center", }, buttonText: { fontSize: 16, fontWeight: "600", color: "#000", }, scrollContent: { paddingBottom: 50, }, });