diff --git a/src/screens/home/UserProfileStatus.tsx b/src/screens/home/UserProfileStatus.tsx index d7b9f73..2eafcc2 100644 --- a/src/screens/home/UserProfileStatus.tsx +++ b/src/screens/home/UserProfileStatus.tsx @@ -1,322 +1,4 @@ -// import React, { useCallback, useEffect, useState } from "react"; -// import { -// StyleSheet, -// Text, -// View, -// TouchableOpacity, -// Modal, -// ToastAndroid, -// Image, -// Animated, -// } from "react-native"; -// import * as Keychain from "react-native-keychain"; -// import { useFocusEffect, useNavigation } from "@react-navigation/native"; -// import { PUT_USER_STATUS } from "../../utils/ApiUrls"; -// import colors from "../../components/colors"; -// import LinearGradient from "react-native-linear-gradient"; -// import {Ionicons} from "@react-native-vector-icons/ionicons"; - -// export type ApiResponse = { -// message: string; -// status: string; -// statusCode: number; -// data: { -// role: string; -// organizerStatus: string; -// profileStatus: boolean; -// }; -// }; - -// type UserProfileStatusProps = { -// profileImage?: { uri: string }; -// }; - -// const UserProfileStatus: React.FC = ({ profileImage }) => { -// const navigation = useNavigation(); -// const [loading, setLoading] = useState(true); -// const [statusData, setStatusData] = useState(null); -// const [showModal, setShowModal] = useState(false); -// const [intervalId, setIntervalId] = useState(null); -// const fadeAnim = useState(new Animated.Value(0))[0]; - -// const userStatus = async () => { -// try { -// const credentials = await Keychain.getGenericPassword(); -// if (!credentials) { -// ToastAndroid.show("You are not logged in", ToastAndroid.SHORT); -// return; -// } -// const token = credentials.password; - -// setLoading(true); -// const response = await fetch(PUT_USER_STATUS, { -// method: "GET", -// headers: { -// Accept: "*/*", -// Authorization: `Bearer ${token}`, -// }, -// }); - -// const json: ApiResponse = await response.json(); -// if (json.status === "success") { -// setStatusData(json.data); -// if (json.data.profileStatus === false) { -// setShowModal(true); -// } -// } else { -// ToastAndroid.show("Failed to fetch status", ToastAndroid.SHORT); -// } -// } catch { -// ToastAndroid.show("Something went wrong", ToastAndroid.SHORT); -// } finally { -// setLoading(false); -// } -// }; - -// useFocusEffect( -// useCallback(() => { -// userStatus(); -// }, []) -// ); - -// useEffect(() => { -// Animated.timing(fadeAnim, { -// toValue: 1, -// duration: 600, -// useNativeDriver: true, -// }).start(); -// }, []); - -// const handleGoToProfile = () => { -// if (intervalId) { -// clearInterval(intervalId); -// setIntervalId(null); -// } -// setShowModal(false); -// navigation.navigate("Profile" as never); -// }; - -// const handlePress = (label: string) => { -// ToastAndroid.show(`${label} clicked`, ToastAndroid.SHORT); -// }; - -// return ( -// -// -// {/* LEFT SECTION */} -// -// Profile Overview - -// -// -// {[ -// "Role", -// "Total Active Groups", -// "Total Joined Groups", -// "Total Created Groups", -// "Total Due Payment", -// "Total Completed Groups", -// ].map((label, i) => ( -// handlePress(label)} -// > -// {label} -// -// ))} -// - -// -// {[ -// statusData?.role || "-", -// "5", -// "3", -// "2", -// "₹1500", -// "4", -// ].map((value, i) => ( -// handlePress(value)} -// > -// {value} -// -// ))} -// -// - -// -// -// Organizer: {statusData?.organizerStatus || "-"} -// -// -// Profile Completed:{" "} -// {statusData?.profileStatus ? "Yes ✅" : "No ❌"} -// -// -// - -// {/* RIGHT SECTION - IMAGE */} -// {/* navigation.navigate("Profile" as never)} -// activeOpacity={0.8} -// > -// {profileImage ? ( -// -// ) : ( -// -// )} -// */} -// - -// {/* Modal */} -// {showModal && ( -// -// -// -// -// Complete Your Profile -// -// Your profile is incomplete. Please update your details to continue. -// - -// -// Go to Profile -// - -// setShowModal(false)} -// > -// Later -// -// -// -// -// )} -// -// ); -// }; - -// export default UserProfileStatus; - -// const styles = StyleSheet.create({ -// container: { -// margin: 12, -// }, -// card: { -// flexDirection: "row", -// justifyContent: "space-between", -// alignItems: "center", -// borderRadius: 16, -// padding: 18, -// elevation: 5, -// shadowColor: "#000", -// shadowOpacity: 0.2, -// shadowRadius: 6, -// }, -// header: { -// fontSize: 20, -// fontWeight: "700", -// color: "#fff", -// marginBottom: 10, -// }, -// leftSection: { -// flex: 1, -// }, -// infoRow: { -// flexDirection: "row", -// justifyContent: "space-between", -// marginBottom: 10, -// }, -// infoLabelBox: { -// marginBottom: 6, -// }, -// infoLabel: { -// color: "rgba(255,255,255,0.8)", -// fontSize: 13, -// }, -// infoValueBox: { -// marginBottom: 6, -// alignItems: "flex-end", -// }, -// infoValue: { -// color: "#fff", -// fontWeight: "600", -// fontSize: 13, -// }, -// statusBox: { -// backgroundColor: "rgba(255,255,255,0.15)", -// padding: 10, -// borderRadius: 8, -// }, -// statusText: { -// color: "#fff", -// fontSize: 13, -// }, -// avatar: { -// width: 80, -// height: 80, -// borderRadius: 40, -// borderWidth: 2, -// borderColor: "#fff", -// }, -// modalOverlay: { -// flex: 1, -// backgroundColor: "rgba(0,0,0,0.5)", -// justifyContent: "center", -// alignItems: "center", -// }, -// modalBox: { -// width: "85%", -// backgroundColor: "#fff", -// borderRadius: 18, -// padding: 20, -// alignItems: "center", -// elevation: 6, -// }, -// modalTitle: { -// fontSize: 20, -// fontWeight: "700", -// color: colors.primary, -// marginVertical: 8, -// }, -// modalText: { -// textAlign: "center", -// color: "#444", -// fontSize: 14, -// marginBottom: 18, -// }, -// button: { -// backgroundColor: colors.primary, -// paddingVertical: 10, -// paddingHorizontal: 30, -// borderRadius: 8, -// marginTop: 8, -// }, -// buttonText: { -// color: "#fff", -// fontWeight: "600", -// }, -// secondaryButton: { -// backgroundColor: "#eee", -// }, -// secondaryText: { -// color: "#333", -// }, -// }); - - - - -import React, { useCallback, useEffect, useState } from "react"; +import React, { use, useCallback, useEffect, useMemo, useRef, useState } from "react"; import { StyleSheet, Text, @@ -329,10 +11,11 @@ import { } from "react-native"; import * as Keychain from "react-native-keychain"; import { useFocusEffect, useNavigation } from "@react-navigation/native"; -import { PUT_USER_STATUS } from "../../utils/ApiUrls"; +import { DASHBOARD_URL, PUT_USER_STATUS } from "../../utils/ApiUrls"; import colors from "../../components/colors"; import LinearGradient from "react-native-linear-gradient"; import { Ionicons } from "@react-native-vector-icons/ionicons"; +import { apiCall } from "../../utils/ApiHelper"; export type ApiResponse = { message: string; @@ -345,6 +28,49 @@ export type ApiResponse = { }; }; +type DashboardResponse = { + message: string; + status: string; + statusCode: number; + data: { + totalPaidAmountMonth: number; + multiplePayAmount: number; + completeStatusMyGroupCount: number; + activeStatusMyGroupCount: number; + myCreatedGroups: any[]; + myJoinedGroups: Array<{ + groupId: string; + groupName: string; + contributionAmount: number; + currentCycle: number; + createdDate: string; + status: string; + }>; + requestList: any[]; + myRequests: Array<{ + requestId: string; + groupName: string; + type: string; + status: string; + requestDate: string; + }>; + dueGroupDetails: Array<{ + groupId: string; + groupName: string; + baseAmount: number; + lateFee: number; + waivedAmount: number; + totalDue: number; + dueDate: string; + isLate: boolean; + currentCycle: number; + lateFeeMode: string; + lateFeeValue: number; + hasPaid: boolean; + }>; + }; +}; + type UserProfileStatusProps = { profileImage?: { uri: string }; }; @@ -354,21 +80,31 @@ const UserProfileStatus: React.FC = ({ profileImage }) = const [loading, setLoading] = useState(true); const [statusData, setStatusData] = useState(null); const [showModal, setShowModal] = useState(false); - const [intervalId, setIntervalId] = useState(null); - const [moreItem, setMoreItem] = useState(false) - const fadeAnim = useState(new Animated.Value(0))[0]; - const scaleAnim = useState(new Animated.Value(0.9))[0]; + const [moreItem, setMoreItem] = useState(false); + const [userDashboard, setUserDashboard] = useState(null); - const userStatus = async () => { + // Animation refs to prevent re-creation on re-render + const fadeAnim = useRef(new Animated.Value(0)).current; + const scaleAnim = useRef(new Animated.Value(0.9)).current; + + // Memoized icons list + const icons = useMemo( + () => ["person", "people", "person-add", "create", "card", "checkmark-done"], + [] + ); + + // Fetch user status + const userStatus = useCallback(async () => { try { const credentials = await Keychain.getGenericPassword(); if (!credentials) { ToastAndroid.show("You are not logged in", ToastAndroid.SHORT); return; } - const token = credentials.password; setLoading(true); + const token = credentials.password; + const response = await fetch(PUT_USER_STATUS, { method: "GET", headers: { @@ -378,11 +114,10 @@ const UserProfileStatus: React.FC = ({ profileImage }) = }); const json: ApiResponse = await response.json(); + if (json.status === "success") { setStatusData(json.data); - if (json.data.profileStatus === false) { - setShowModal(true); - } + if (!json.data.profileStatus) setShowModal(true); } else { ToastAndroid.show("Failed to fetch status", ToastAndroid.SHORT); } @@ -391,62 +126,118 @@ const UserProfileStatus: React.FC = ({ profileImage }) = } finally { setLoading(false); } - }; + }, []); useFocusEffect( useCallback(() => { userStatus(); - }, []) + }, [userStatus]) ); + // Animation start useEffect(() => { Animated.parallel([ - Animated.timing(fadeAnim, { - toValue: 1, - duration: 600, - useNativeDriver: true, - }), - Animated.timing(scaleAnim, { - toValue: 1, - duration: 600, - useNativeDriver: true, - }), + Animated.timing(fadeAnim, { toValue: 1, duration: 600, useNativeDriver: true }), + Animated.timing(scaleAnim, { toValue: 1, duration: 600, useNativeDriver: true }), ]).start(); - }, []); + }, [fadeAnim, scaleAnim]); - const handleGoToProfile = () => { - if (intervalId) { - clearInterval(intervalId); - setIntervalId(null); - } + const handleGoToProfile = useCallback(() => { setShowModal(false); navigation.navigate("Profile" as never); - }; + }, [navigation]); - const handlePress = (label: string) => { + const handlePress = useCallback((label: string) => { ToastAndroid.show(`${label} clicked`, ToastAndroid.SHORT); - }; - - // Graphics and icons for different status items - const getStatusIcon = (index: number) => { - const icons = ["person", "people", "person-add", "create", "card", "checkmark-done"]; - return icons[index]; - }; + }, []); const getValueColor = (value: string) => { - if (value.includes("₹")) return "#4CAF50"; // Green for money - if (value === "Active" || value === "Yes ✅") return "#4CAF50"; + if (value.includes("₹") || value === "Active" || value === "Yes ✅") return "#4CAF50"; if (value === "Inactive" || value === "No ❌") return "#FF6B6B"; return "#fff"; }; + // Dynamic info items based on dashboard data + const infoItems = useMemo(() => { + if (!userDashboard) { + return [ + { label: "Role", value: statusData?.role || "-" }, + { label: "Active", value: "0" }, + { label: "Joined", value: "0" }, + { label: "Created", value: "0" }, + { label: "Due Pay", value: "₹0" }, + { label: "Completed", value: "0" }, + ]; + } + + return [ + { + label: "Role", + value: statusData?.role || "-" + }, + { + label: "Active", + value: userDashboard.activeStatusMyGroupCount.toString() + }, + { + label: "Joined", + value: userDashboard.myJoinedGroups.length.toString() + }, + { + label: "Created", + value: userDashboard.myCreatedGroups.length.toString() + }, + { + label: "Due Pay", + value: `₹${userDashboard.multiplePayAmount}` + }, + { + label: "Completed", + value: userDashboard.completeStatusMyGroupCount.toString() + }, + ]; + }, [userDashboard, statusData]); + + // Calculate total due amount + const getTotalDueAmount = useCallback(() => { + if (!userDashboard?.dueGroupDetails) return 0; + return userDashboard.dueGroupDetails.reduce((total, due) => total + due.totalDue, 0); + }, [userDashboard]); + + // Calculate pending requests count + const getPendingRequestsCount = useCallback(() => { + if (!userDashboard?.myRequests) return 0; + return userDashboard.myRequests.filter(request => request.status === "PENDING").length; + }, [userDashboard]); + + const getDashboardData = async () => { + try { + const result = (await apiCall(DASHBOARD_URL, "GET")) as DashboardResponse; + console.log("DASHBOARD_URL-------", result) + if (result.status === "success") { + setUserDashboard(result.data); + } + } catch (error) { + console.error("❌ Error fetching dashboard data:", error); + } + }; + + useEffect(() => { + getDashboardData(); + }, []); + + // Format currency + const formatCurrency = (amount: number) => { + return `₹${amount.toLocaleString('en-IN')}`; + }; + return ( - {/* Background Decorative Elements */} + {/* Decorative Background */} - - - + {["circle1", "circle2", "circle3"].map((c, i) => ( + + ))} = ({ profileImage }) = end={{ x: 1, y: 1 }} style={styles.card} > - {/* Header with Graphics */} + {/* Header */} - + Profile Overview @@ -471,31 +262,20 @@ const UserProfileStatus: React.FC = ({ profileImage }) = - {/* Main Content */} + {/* Content Section */} - {/* LEFT SECTION - Stats */} + {/* LEFT SIDE */} - {[ - { label: "Role", value: statusData?.role || "-" }, - { label: "Active Groups", value: "5" }, - { label: "Joined Groups", value: "3" }, - { label: "Created Groups", value: "2" }, - { label: "Due Payment", value: "₹1500" }, - { label: "Completed Groups", value: "4" }, - ].map((item, index) => ( + {infoItems.map((item, index) => ( handlePress(item.label)} > - + {item.label} @@ -504,133 +284,100 @@ const UserProfileStatus: React.FC = ({ profileImage }) = ))} - setMoreItem(!moreItem)}> - - + + + {/* RIGHT SIDE */} + + navigation.navigate("Profile" as never)} activeOpacity={0.8}> + + {profileImage ? ( + + ) : ( + + + + )} + + + + View Profile + + + + setMoreItem(!moreItem)}> + + + + + + {moreItem && ( + <> + + + + Status Overview + + + + + Organizer: {statusData?.organizerStatus || "-"} + + + Profile: {statusData?.profileStatus ? "Complete ✅" : "Incomplete ❌"} + + + Pending Requests: {getPendingRequestsCount()} + + + Total Due: {formatCurrency(getTotalDueAmount())} + + {userDashboard?.dueGroupDetails?.map((due, index) => ( + + • {due.groupName}: {formatCurrency(due.totalDue)} (Due: {due.dueDate}) + + ))} + - {/* Status Overview Card */} - { - moreItem && ( - - - - Status Overview - - - - - - - - - Organizer: {statusData?.organizerStatus || "-"} - - - - - - - - - Profile: {statusData?.profileStatus ? "Complete" : "Incomplete"} - - - - - )} - - - {/* RIGHT SECTION - Profile Graphic */} - navigation.navigate("Profile" as never)} - activeOpacity={0.8} - style={styles.profileSection} - > - - {profileImage ? ( - - ) : ( - - - - )} - - + + + Profile Completion + + {statusData?.profileStatus ? "100%" : "60%"} + - View Profile - - - - - {/* Progress Bar for Profile Completion */} - - - Profile Completion - - {statusData?.profileStatus ? "100%" : "60%"} - - - - - - + + + + + + )} - {/* Enhanced Modal */} + {/* Modal */} {showModal && ( - - - - - - + + Complete Your Profile - Your profile is incomplete. Please update your details to unlock all features and improve your experience. + Your profile is incomplete. Update your details to unlock all features. - - Current Progress: 60% - - - - - - + Complete Profile @@ -655,7 +402,7 @@ export default UserProfileStatus; const styles = StyleSheet.create({ container: { - margin: 16, + // margin: 16, }, backgroundGraphics: { position: 'absolute', @@ -742,13 +489,12 @@ const styles = StyleSheet.create({ flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', - marginBottom: 16, }, infoCard: { width: '48%', backgroundColor: 'rgba(255,255,255,0.15)', borderRadius: 12, - padding: 12, + padding: 5, marginBottom: 8, borderWidth: 1, borderColor: 'rgba(255,255,255,0.2)', @@ -782,6 +528,7 @@ const styles = StyleSheet.create({ borderRadius: 12, borderWidth: 1, borderColor: 'rgba(255,255,255,0.2)', + marginTop: 16, }, statusHeader: { flexDirection: 'row', @@ -797,13 +544,6 @@ const styles = StyleSheet.create({ statusItems: { gap: 8, }, - statusItem: { - flexDirection: 'row', - alignItems: 'center', - }, - statusIndicator: { - marginRight: 8, - }, statusItemText: { color: "#fff", fontSize: 14, @@ -902,19 +642,6 @@ const styles = StyleSheet.create({ shadowRadius: 15, shadowOffset: { width: 0, height: 6 }, }, - modalGraphic: { - position: 'relative', - marginBottom: 16, - }, - modalPulse: { - position: 'absolute', - top: -10, - left: -10, - right: -10, - bottom: -10, - borderRadius: 40, - backgroundColor: 'rgba(76, 175, 80, 0.2)', - }, modalTitle: { fontSize: 22, fontWeight: "700", @@ -929,28 +656,6 @@ const styles = StyleSheet.create({ lineHeight: 20, marginBottom: 20, }, - modalProgress: { - width: '100%', - marginBottom: 20, - }, - modalProgressText: { - textAlign: 'center', - color: "#333", - fontSize: 12, - fontWeight: '600', - marginBottom: 6, - }, - modalProgressBar: { - height: 4, - backgroundColor: '#f0f0f0', - borderRadius: 2, - overflow: 'hidden', - }, - modalProgressFill: { - height: '100%', - backgroundColor: colors.primary, - borderRadius: 2, - }, modalButtons: { width: '100%', gap: 8, diff --git a/src/utils/ApiUrls.tsx b/src/utils/ApiUrls.tsx index bf4553b..3026c5a 100644 --- a/src/utils/ApiUrls.tsx +++ b/src/utils/ApiUrls.tsx @@ -1,5 +1,5 @@ -export const BASE_URL = "https://api.godemo.in/FundCollect/api/" +export const BASE_URL = "http://192.168.1.18:9060/api/" // export const BASE_URL = "http://192.168.1.5:9060/api/" export const LOGIN_URL = `${BASE_URL}user/generate/otp?mobiles=` export const VARIFY_OTP_URL = `${BASE_URL}user/otp/verify` @@ -23,4 +23,5 @@ export const CONTRIBUTE = `${BASE_URL}payments/groups/`; export const TRANSACTION = `${BASE_URL}payments/my-transactions`; export const UPLOAD_GROUP_IMAGE = `${BASE_URL}fund/groups/`; export const STORE_FCM_TOKEN = `${BASE_URL}token/store?fcmToken=` -export const REMOVE_FCM_TOKEN = `${BASE_URL}token/remove?fcmToken=` \ No newline at end of file +export const REMOVE_FCM_TOKEN = `${BASE_URL}token/remove?fcmToken=` +export const DASHBOARD_URL = `${BASE_URL}fund/dashboard` \ No newline at end of file