demo ready
This commit is contained in:
@@ -59,6 +59,7 @@ const userActions: ActionItem[] = [
|
||||
{ id: "1", title: "Joined Groups", subtitle: "See your groups", action: "NAVIGATE_MANAGEMENT", tab: "Joined Groups", iconName: "person-outline", backOne: '#D7E9F7', backTwo: '#82AAE3' },
|
||||
{ id: "2", title: "Your Requests", subtitle: "Track your requests", action: "NAVIGATE_MANAGEMENT", tab: "Your Requests", iconName: "mail-open-outline", backOne: '#FFF4D2', backTwo: '#FFB344' },
|
||||
{ id: "3", title: "Transactions", subtitle: "View your history", action: "TRANSACTION", iconName: "receipt-outline", backOne: '#decbfcff', backTwo: '#B799FF' },
|
||||
{ id: "4", title: "Create Group", subtitle: "Create a new group", action: "NAVIGATE_CREATE_GROUP", tab: "Requests", iconName: "people-outline", backOne: '#DFF6DD', backTwo: '#88D18A' },
|
||||
];
|
||||
|
||||
const Home: React.FC = () => {
|
||||
@@ -95,6 +96,7 @@ const Home: React.FC = () => {
|
||||
} else if (item.action === "TRANSACTION") {
|
||||
navigation.navigate("TransactionList" as never);
|
||||
} else if (item.action === "NAVIGATE_CREATE_GROUP") {
|
||||
|
||||
navigation.navigate("GroupCreation" as never);
|
||||
} else {
|
||||
Alert.alert("Unknown action", item.title);
|
||||
|
||||
@@ -12,16 +12,19 @@ import {
|
||||
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 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 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;
|
||||
const selectedLabel = items.find((item: any) => item.value === selectedValue)?.label || placeholder;
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<View style={styles.dropdownWrapper}>
|
||||
@@ -30,6 +33,7 @@ const CustomDropdown = ({ items, selectedValue, onValueChange, placeholder = "Se
|
||||
<Ionicons name='chevron-down' size={22} color={colors.black} />
|
||||
</TouchableOpacity>
|
||||
|
||||
|
||||
<Modal
|
||||
transparent
|
||||
animationType="fade"
|
||||
@@ -39,7 +43,7 @@ const CustomDropdown = ({ items, selectedValue, onValueChange, placeholder = "Se
|
||||
<TouchableOpacity style={styles.modalOverlay} onPress={() => setOpen(false)}>
|
||||
<View style={styles.dropdownListContainer}>
|
||||
<ScrollView>
|
||||
{items.map(item => (
|
||||
{items.map((item: any) => (
|
||||
<TouchableOpacity
|
||||
key={item.value}
|
||||
onPress={() => {
|
||||
@@ -62,8 +66,12 @@ const CustomDropdown = ({ items, selectedValue, onValueChange, placeholder = "Se
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const GroupDetails = () => {
|
||||
const route = useRoute<any>();
|
||||
|
||||
|
||||
console.log(" route id : ", route)
|
||||
const [memberData, setMemberData] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [openModal, setOpenModal] = useState(false);
|
||||
@@ -72,6 +80,8 @@ const GroupDetails = () => {
|
||||
const [cycleDashboardData, setCycleDashboardData] = useState<any>();
|
||||
const [selectedCycleNumber, setSelectedCycleNumber] = useState(null);
|
||||
const [cycleItems, setCycleItems] = useState([]);
|
||||
const [selectedUser, setSelectedUser] = useState() as any
|
||||
|
||||
|
||||
const group = {
|
||||
id: route.params.item?.id,
|
||||
@@ -83,15 +93,26 @@ const GroupDetails = () => {
|
||||
members: memberData,
|
||||
};
|
||||
|
||||
|
||||
|
||||
const getPaymentStatus = async () => {
|
||||
const response = await apiCall(`${BASE_URL}payments/group/${group.id || route?.params?.groupId}/payment/paid`, 'GET') as { status: string; data?: { currentCycle: number, allPaid: boolean, selectedUser: any }; message?: string };
|
||||
console.log("paymentStatus", response.data?.selectedUser)
|
||||
if (response.status === 'success') {
|
||||
setSelectedUser(response.data?.selectedUser);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const getCycleDashboard = async () => {
|
||||
try {
|
||||
const response = await apiCall(`${BASE_URL}payments/groups/${group.id}/cycle-dashboard`, "GET") as any;
|
||||
console.log("Cycle Dashboard Response: ", response);
|
||||
const response = await apiCall(`${BASE_URL}payments/groups/${group.id || route?.params?.groupId}/cycle-dashboard`, "GET") as any;
|
||||
const responseData = response.data;
|
||||
setCycleDashboardData(responseData);
|
||||
|
||||
console.log("cycledata", responseData)
|
||||
if (responseData?.cycles) {
|
||||
const items = responseData.cycles.map(cycle => ({
|
||||
const items = responseData.cycles.map((cycle: any) => ({
|
||||
label: `Cycle ${cycle.cycleNumber}`,
|
||||
value: cycle.cycleNumber
|
||||
}));
|
||||
@@ -105,9 +126,10 @@ const GroupDetails = () => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const fetchGroupDetails = async () => {
|
||||
try {
|
||||
const res = await apiCall(`${GROUP_ALL_MEMBER}?groupId=${group.id}`, "GET") as any;
|
||||
const res = await apiCall(`${GROUP_ALL_MEMBER}?groupId=${group.id || route?.params?.groupId}`, "GET") as any;
|
||||
console.log("Group Members Response: ", res);
|
||||
setMemberData(res.data);
|
||||
} catch (error: any) {
|
||||
@@ -115,16 +137,17 @@ const GroupDetails = () => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleContribution = async () => {
|
||||
try {
|
||||
const res = await apiCall(`${CONTRIBUTE}${group.id}/calculate-contribution`, 'GET') as any;
|
||||
console.log("Contribution Calculation Response: ", res);
|
||||
const res = await apiCall(`${CONTRIBUTE}${group.id || route?.params?.groupId}/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([
|
||||
@@ -133,24 +156,30 @@ const GroupDetails = () => {
|
||||
getCycleDashboard()
|
||||
]);
|
||||
setLoading(false);
|
||||
}, [group.id]);
|
||||
}, [group.id || route?.params?.groupId]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (group.id) {
|
||||
if (group.id || route?.params?.groupId) {
|
||||
fetchAllData();
|
||||
getPaymentStatus();
|
||||
}
|
||||
}, [group.id, fetchAllData]);
|
||||
}, [group.id || route?.params?.groupId, fetchAllData]);
|
||||
|
||||
|
||||
const onRefresh = useCallback(async () => {
|
||||
setRefreshing(true);
|
||||
await fetchAllData();
|
||||
await getPaymentStatus();
|
||||
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) {
|
||||
console.log('payment res ', res)
|
||||
if (res.status === 200 || res.status === 201 || res.statusCode === 200) {
|
||||
ToastAndroid.show('Payment done!', ToastAndroid.SHORT);
|
||||
onRefresh();
|
||||
} else {
|
||||
@@ -161,18 +190,28 @@ const GroupDetails = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const selectedCycleData = cycleDashboardData?.cycles.find(c => c.cycleNumber === selectedCycleNumber);
|
||||
|
||||
const selectedCycleData = cycleDashboardData?.cycles.find((c: any) => c.cycleNumber === selectedCycleNumber);
|
||||
|
||||
|
||||
return (
|
||||
<AppView paddingHorizontal={0} style={{ flex: 1 }}>
|
||||
{selectedUser?.firstName && (
|
||||
<View style={styles.floatingWinnerContainer}>
|
||||
<Text style={styles.floatingWinnerText}>
|
||||
Winner: {`${selectedUser.firstName} ${selectedUser.lastName || ''}`}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
<ScrollView
|
||||
refreshControl={
|
||||
<RefreshControl refreshing={refreshing || loading} onRefresh={onRefresh} colors={[colors.black]} />
|
||||
}
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
>
|
||||
<Header title={cycleDashboardData?.groupName || group?.name} />
|
||||
<Text style={styles.description}>{group.description}</Text>
|
||||
<Header title={group.name || route.name} />
|
||||
<Text style={styles.description}>{group.description || route.name}</Text>
|
||||
|
||||
|
||||
<View style={styles.statsRow}>
|
||||
<View style={styles.statBox}>
|
||||
@@ -180,15 +219,16 @@ const GroupDetails = () => {
|
||||
<Text style={styles.statLabel}>Members</Text>
|
||||
</View>
|
||||
<View style={styles.statBox}>
|
||||
<Text style={styles.statValue}>₹{cycleDashboardData?.contributionAmount|| group.collected}</Text>
|
||||
<Text style={styles.statValue}>₹{cycleDashboardData?.contributionAmount || group.collected}</Text>
|
||||
<Text style={styles.statLabel}>Contribution</Text>
|
||||
</View>
|
||||
<View style={styles.statBox}>
|
||||
<Text style={styles.statValue}>₹{cycleDashboardData?.contributionAmount*memberData.length|| group.goal}</Text>
|
||||
<Text style={styles.statValue}>₹{cycleDashboardData?.contributionAmount * memberData.length || group.goal}</Text>
|
||||
<Text style={styles.statLabel}>Total Amount</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
|
||||
{cycleItems.length > 0 && (
|
||||
<CustomDropdown
|
||||
items={cycleItems}
|
||||
@@ -197,11 +237,12 @@ const GroupDetails = () => {
|
||||
placeholder="Select a Cycle"
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
{selectedCycleData && cycleDashboardData && (
|
||||
<CycleDashboard data={{ ...cycleDashboardData, cycles: [selectedCycleData] }} />
|
||||
)}
|
||||
|
||||
|
||||
<View style={styles.membersHeader}>
|
||||
<Text style={styles.sectionTitle}>Members</Text>
|
||||
<View style={styles.statusBadge}>
|
||||
@@ -209,7 +250,8 @@ const GroupDetails = () => {
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{memberData.map((member:any) => (
|
||||
|
||||
{memberData.map((member: any) => (
|
||||
<View key={member.userId} style={styles.memberCard}>
|
||||
<Ionicons name="person" size={40} color={colors.black} />
|
||||
<View style={styles.memberInfo}>
|
||||
@@ -220,7 +262,7 @@ const GroupDetails = () => {
|
||||
</View>
|
||||
))}
|
||||
|
||||
{/* Button at the bottom inside scroll (no absolute positioning) */}
|
||||
|
||||
{cycleDashboardData?.status === 'ACTIVE' && !payable?.hasPaid && (
|
||||
<TouchableOpacity onPress={() => setOpenModal(true)} style={styles.button}>
|
||||
<Text style={styles.buttonText}>Contribute</Text>
|
||||
@@ -228,6 +270,7 @@ const GroupDetails = () => {
|
||||
)}
|
||||
</ScrollView>
|
||||
|
||||
|
||||
{openModal && (
|
||||
<ContributionScreen
|
||||
data={payable}
|
||||
@@ -243,8 +286,10 @@ const GroupDetails = () => {
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default GroupDetails;
|
||||
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
dropdownWrapper: {
|
||||
marginHorizontal: 15,
|
||||
@@ -260,6 +305,10 @@ const styles = StyleSheet.create({
|
||||
borderRadius: 8,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
headerText: {
|
||||
fontSize: 15,
|
||||
color: colors.black,
|
||||
},
|
||||
modalOverlay: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
@@ -334,7 +383,7 @@ const styles = StyleSheet.create({
|
||||
statusText: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: colors.Home,
|
||||
color: colors.black,
|
||||
},
|
||||
memberCard: {
|
||||
flexDirection: "row",
|
||||
@@ -372,4 +421,20 @@ const styles = StyleSheet.create({
|
||||
scrollContent: {
|
||||
paddingBottom: 50,
|
||||
},
|
||||
floatingWinnerContainer: {
|
||||
position: 'absolute',
|
||||
bottom: 80,
|
||||
alignSelf: 'center',
|
||||
backgroundColor: colors.pastelBlue,
|
||||
paddingHorizontal: 15,
|
||||
paddingVertical: 8,
|
||||
borderRadius: 20,
|
||||
elevation: 5,
|
||||
zIndex: 10,
|
||||
},
|
||||
floatingWinnerText: {
|
||||
color: colors.black,
|
||||
fontWeight: 'bold',
|
||||
fontSize: 16,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user