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,
},
});