implement dashboard api

This commit is contained in:
Jaanu423
2025-10-23 17:23:23 +05:30
parent da09a5598f
commit 313fe3f9e3
2 changed files with 247 additions and 541 deletions
+244 -539
View File
@@ -1,322 +1,4 @@
// import React, { useCallback, useEffect, useState } from "react"; import React, { use, useCallback, useEffect, useMemo, useRef, 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<UserProfileStatusProps> = ({ profileImage }) => {
// const navigation = useNavigation();
// const [loading, setLoading] = useState(true);
// const [statusData, setStatusData] = useState<ApiResponse["data"] | null>(null);
// const [showModal, setShowModal] = useState(false);
// const [intervalId, setIntervalId] = useState<null | number>(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 (
// <Animated.View style={[styles.container, { opacity: fadeAnim }]}>
// <LinearGradient
// colors={[colors.primary, colors.pastelPink]}
// start={{ x: 0, y: 0 }}
// end={{ x: 1, y: 1 }}
// style={styles.card}
// >
// {/* LEFT SECTION */}
// <View style={styles.leftSection}>
// <Text style={styles.header}>Profile Overview</Text>
// <View style={styles.infoRow}>
// <View>
// {[
// "Role",
// "Total Active Groups",
// "Total Joined Groups",
// "Total Created Groups",
// "Total Due Payment",
// "Total Completed Groups",
// ].map((label, i) => (
// <TouchableOpacity
// key={i}
// style={styles.infoLabelBox}
// onPress={() => handlePress(label)}
// >
// <Text style={styles.infoLabel}>{label}</Text>
// </TouchableOpacity>
// ))}
// </View>
// <View>
// {[
// statusData?.role || "-",
// "5",
// "3",
// "2",
// "₹1500",
// "4",
// ].map((value, i) => (
// <TouchableOpacity
// key={i}
// style={styles.infoValueBox}
// onPress={() => handlePress(value)}
// >
// <Text style={styles.infoValue}>{value}</Text>
// </TouchableOpacity>
// ))}
// </View>
// </View>
// <View style={styles.statusBox}>
// <Text style={styles.statusText}>
// Organizer: {statusData?.organizerStatus || "-"}
// </Text>
// <Text style={styles.statusText}>
// Profile Completed:{" "}
// {statusData?.profileStatus ? "Yes ✅" : "No ❌"}
// </Text>
// </View>
// </View>
// {/* RIGHT SECTION - IMAGE */}
// {/* <TouchableOpacity
// onPress={() => navigation.navigate("Profile" as never)}
// activeOpacity={0.8}
// >
// {profileImage ? (
// <Image source={{ uri: profileImage.uri }} style={styles.avatar} />
// ) : (
// <Ionicons name="person-circle-outline" size={80} color="#fff" />
// )}
// </TouchableOpacity> */}
// </LinearGradient>
// {/* Modal */}
// {showModal && (
// <Modal visible transparent animationType="fade">
// <View style={styles.modalOverlay}>
// <View style={styles.modalBox}>
// <Ionicons name="alert-circle" size={50} color={colors.primary} />
// <Text style={styles.modalTitle}>Complete Your Profile</Text>
// <Text style={styles.modalText}>
// Your profile is incomplete. Please update your details to continue.
// </Text>
// <TouchableOpacity style={styles.button} onPress={handleGoToProfile}>
// <Text style={styles.buttonText}>Go to Profile</Text>
// </TouchableOpacity>
// <TouchableOpacity
// style={[styles.button, styles.secondaryButton]}
// onPress={() => setShowModal(false)}
// >
// <Text style={[styles.buttonText, styles.secondaryText]}>Later</Text>
// </TouchableOpacity>
// </View>
// </View>
// </Modal>
// )}
// </Animated.View>
// );
// };
// 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 { import {
StyleSheet, StyleSheet,
Text, Text,
@@ -329,10 +11,11 @@ import {
} from "react-native"; } from "react-native";
import * as Keychain from "react-native-keychain"; import * as Keychain from "react-native-keychain";
import { useFocusEffect, useNavigation } from "@react-navigation/native"; 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 colors from "../../components/colors";
import LinearGradient from "react-native-linear-gradient"; import LinearGradient from "react-native-linear-gradient";
import { Ionicons } from "@react-native-vector-icons/ionicons"; import { Ionicons } from "@react-native-vector-icons/ionicons";
import { apiCall } from "../../utils/ApiHelper";
export type ApiResponse = { export type ApiResponse = {
message: string; 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 = { type UserProfileStatusProps = {
profileImage?: { uri: string }; profileImage?: { uri: string };
}; };
@@ -354,21 +80,31 @@ const UserProfileStatus: React.FC<UserProfileStatusProps> = ({ profileImage }) =
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [statusData, setStatusData] = useState<ApiResponse["data"] | null>(null); const [statusData, setStatusData] = useState<ApiResponse["data"] | null>(null);
const [showModal, setShowModal] = useState(false); const [showModal, setShowModal] = useState(false);
const [intervalId, setIntervalId] = useState<null | number>(null); const [moreItem, setMoreItem] = useState(false);
const [moreItem, setMoreItem] = useState(false) const [userDashboard, setUserDashboard] = useState<DashboardResponse["data"] | null>(null);
const fadeAnim = useState(new Animated.Value(0))[0];
const scaleAnim = useState(new Animated.Value(0.9))[0];
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 { try {
const credentials = await Keychain.getGenericPassword(); const credentials = await Keychain.getGenericPassword();
if (!credentials) { if (!credentials) {
ToastAndroid.show("You are not logged in", ToastAndroid.SHORT); ToastAndroid.show("You are not logged in", ToastAndroid.SHORT);
return; return;
} }
const token = credentials.password;
setLoading(true); setLoading(true);
const token = credentials.password;
const response = await fetch(PUT_USER_STATUS, { const response = await fetch(PUT_USER_STATUS, {
method: "GET", method: "GET",
headers: { headers: {
@@ -378,11 +114,10 @@ const UserProfileStatus: React.FC<UserProfileStatusProps> = ({ profileImage }) =
}); });
const json: ApiResponse = await response.json(); const json: ApiResponse = await response.json();
if (json.status === "success") { if (json.status === "success") {
setStatusData(json.data); setStatusData(json.data);
if (json.data.profileStatus === false) { if (!json.data.profileStatus) setShowModal(true);
setShowModal(true);
}
} else { } else {
ToastAndroid.show("Failed to fetch status", ToastAndroid.SHORT); ToastAndroid.show("Failed to fetch status", ToastAndroid.SHORT);
} }
@@ -391,62 +126,118 @@ const UserProfileStatus: React.FC<UserProfileStatusProps> = ({ profileImage }) =
} finally { } finally {
setLoading(false); setLoading(false);
} }
}; }, []);
useFocusEffect( useFocusEffect(
useCallback(() => { useCallback(() => {
userStatus(); userStatus();
}, []) }, [userStatus])
); );
// Animation start
useEffect(() => { useEffect(() => {
Animated.parallel([ Animated.parallel([
Animated.timing(fadeAnim, { Animated.timing(fadeAnim, { toValue: 1, duration: 600, useNativeDriver: true }),
toValue: 1, Animated.timing(scaleAnim, { toValue: 1, duration: 600, useNativeDriver: true }),
duration: 600,
useNativeDriver: true,
}),
Animated.timing(scaleAnim, {
toValue: 1,
duration: 600,
useNativeDriver: true,
}),
]).start(); ]).start();
}, []); }, [fadeAnim, scaleAnim]);
const handleGoToProfile = () => { const handleGoToProfile = useCallback(() => {
if (intervalId) {
clearInterval(intervalId);
setIntervalId(null);
}
setShowModal(false); setShowModal(false);
navigation.navigate("Profile" as never); navigation.navigate("Profile" as never);
}; }, [navigation]);
const handlePress = (label: string) => { const handlePress = useCallback((label: string) => {
ToastAndroid.show(`${label} clicked`, ToastAndroid.SHORT); 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) => { const getValueColor = (value: string) => {
if (value.includes("₹")) return "#4CAF50"; // Green for money if (value.includes("₹") || value === "Active" || value === "Yes ✅") return "#4CAF50";
if (value === "Active" || value === "Yes ✅") return "#4CAF50";
if (value === "Inactive" || value === "No ❌") return "#FF6B6B"; if (value === "Inactive" || value === "No ❌") return "#FF6B6B";
return "#fff"; 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 ( return (
<Animated.View style={[styles.container, { opacity: fadeAnim, transform: [{ scale: scaleAnim }] }]}> <Animated.View style={[styles.container, { opacity: fadeAnim, transform: [{ scale: scaleAnim }] }]}>
{/* Background Decorative Elements */} {/* Decorative Background */}
<View style={styles.backgroundGraphics}> <View style={styles.backgroundGraphics}>
<View style={[styles.floatingCircle, styles.circle1]} /> {["circle1", "circle2", "circle3"].map((c, i) => (
<View style={[styles.floatingCircle, styles.circle2]} /> <View key={i} style={[styles.floatingCircle, styles[c as keyof typeof styles]]} />
<View style={[styles.floatingCircle, styles.circle3]} /> ))}
</View> </View>
<LinearGradient <LinearGradient
@@ -455,11 +246,11 @@ const UserProfileStatus: React.FC<UserProfileStatusProps> = ({ profileImage }) =
end={{ x: 1, y: 1 }} end={{ x: 1, y: 1 }}
style={styles.card} style={styles.card}
> >
{/* Header with Graphics */} {/* Header */}
<View style={styles.headerSection}> <View style={styles.headerSection}>
<View style={styles.headerContent}> <View style={styles.headerContent}>
<View style={styles.titleWithIcon}> <View style={styles.titleWithIcon}>
<Ionicons name="stats-chart" size={24} color="#fff" style={styles.headerIcon} /> <Ionicons name="stats-chart" size={22} color="#fff" style={styles.headerIcon} />
<Text style={styles.header}>Profile Overview</Text> <Text style={styles.header}>Profile Overview</Text>
</View> </View>
<View style={styles.statusBadge}> <View style={styles.statusBadge}>
@@ -471,31 +262,20 @@ const UserProfileStatus: React.FC<UserProfileStatusProps> = ({ profileImage }) =
</View> </View>
</View> </View>
{/* Main Content */} {/* Content Section */}
<View style={styles.contentSection}> <View style={styles.contentSection}>
{/* LEFT SECTION - Stats */} {/* LEFT SIDE */}
<View style={styles.leftSection}> <View style={styles.leftSection}>
<View style={styles.infoGrid}> <View style={styles.infoGrid}>
{[ {infoItems.map((item, index) => (
{ 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) => (
<TouchableOpacity <TouchableOpacity
key={index} key={item.label}
style={styles.infoCard} style={styles.infoCard}
onPress={() => handlePress(item.label)} onPress={() => handlePress(item.label)}
> >
<View style={styles.infoCardHeader}> <View style={styles.infoCardHeader}>
<View style={styles.iconContainer}> <View style={styles.iconContainer}>
<Ionicons <Ionicons name={icons[index]} size={16} color={colors.primary} />
name={getStatusIcon(index)}
size={16}
color={colors.primary}
/>
</View> </View>
<Text style={styles.infoLabel}>{item.label}</Text> <Text style={styles.infoLabel}>{item.label}</Text>
</View> </View>
@@ -504,133 +284,100 @@ const UserProfileStatus: React.FC<UserProfileStatusProps> = ({ profileImage }) =
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
))} ))}
<TouchableOpacity onPress={()=>setMoreItem(!moreItem)}> </View>
<Ionicons name={"arrow-down"} color="#ffff" size={22}/> </View>
</TouchableOpacity> {/* RIGHT SIDE */}
<View style={styles.profileSection}>
<TouchableOpacity onPress={() => navigation.navigate("Profile" as never)} activeOpacity={0.8}>
<LinearGradient
colors={["rgba(255,255,255,0.2)", "rgba(255,255,255,0.1)"]}
style={styles.profileContainer}
>
{profileImage ? (
<Image source={{ uri: profileImage.uri }} style={styles.avatar} />
) : (
<View style={styles.avatarPlaceholder}>
<Ionicons name="person" size={40} color="#fff" />
</View>
)}
<View style={styles.profileBadge}>
<Ionicons name="camera" size={16} color={colors.primary} />
</View>
<Text style={styles.viewProfileText}>View Profile</Text>
</LinearGradient>
</TouchableOpacity>
<TouchableOpacity style={[styles.profileContainer, {marginVertical:15}]} onPress={() => setMoreItem(!moreItem)}>
<Ionicons name={moreItem ? "arrow-up" : "arrow-down"} color="#fff" size={22} />
</TouchableOpacity>
</View>
</View>
{moreItem && (
<>
<View style={styles.statusOverview}>
<View style={styles.statusHeader}>
<Ionicons name="information-circle" size={20} color="#fff" />
<Text style={styles.statusOverviewTitle}>Status Overview</Text>
</View>
<View style={styles.statusItems}>
<Text style={styles.statusItemText}>
Organizer: {statusData?.organizerStatus || "-"}
</Text>
<Text style={styles.statusItemText}>
Profile: {statusData?.profileStatus ? "Complete ✅" : "Incomplete ❌"}
</Text>
<Text style={styles.statusItemText}>
Pending Requests: {getPendingRequestsCount()}
</Text>
<Text style={styles.statusItemText}>
Total Due: {formatCurrency(getTotalDueAmount())}
</Text>
{userDashboard?.dueGroupDetails?.map((due, index) => (
<Text key={index} style={[styles.statusItemText, { fontSize: 12, opacity: 0.8 }]}>
• {due.groupName}: {formatCurrency(due.totalDue)} (Due: {due.dueDate})
</Text>
))}
</View>
</View> </View>
{/* Status Overview Card */} <View style={styles.progressSection}>
{ <View style={styles.progressHeader}>
moreItem && ( <Text style={styles.progressText}>Profile Completion</Text>
<View style={styles.statusOverview}> <Text style={styles.progressPercent}>
<View style={styles.statusHeader}> {statusData?.profileStatus ? "100%" : "60%"}
<Ionicons name="information-circle" size={20} color="#fff" /> </Text>
<Text style={styles.statusOverviewTitle}>Status Overview</Text>
</View>
<View style={styles.statusItems}>
<View style={styles.statusItem}>
<View style={styles.statusIndicator}>
<Ionicons
name={statusData?.organizerStatus === "Active" ? "checkmark-circle" : "time"}
size={16}
color={statusData?.organizerStatus === "Active" ? "#4CAF50" : "#FFA500"}
/>
</View>
<Text style={styles.statusItemText}>
Organizer: {statusData?.organizerStatus || "-"}
</Text>
</View>
<View style={styles.statusItem}>
<View style={styles.statusIndicator}>
<Ionicons
name={statusData?.profileStatus ? "checkmark-circle" : "close-circle"}
size={16}
color={statusData?.profileStatus ? "#4CAF50" : "#FF6B6B"}
/>
</View>
<Text style={styles.statusItemText}>
Profile: {statusData?.profileStatus ? "Complete" : "Incomplete"}
</Text>
</View>
</View>
</View>
)}
</View>
{/* RIGHT SECTION - Profile Graphic */}
<TouchableOpacity
onPress={() => navigation.navigate("Profile" as never)}
activeOpacity={0.8}
style={styles.profileSection}
>
<LinearGradient
colors={['rgba(255,255,255,0.2)', 'rgba(255,255,255,0.1)']}
style={styles.profileContainer}
>
{profileImage ? (
<Image source={{ uri: profileImage.uri }} style={styles.avatar} />
) : (
<View style={styles.avatarPlaceholder}>
<Ionicons name="person" size={40} color="#fff" />
</View>
)}
<View style={styles.profileBadge}>
<Ionicons name="camera" size={16} color={colors.primary} />
</View> </View>
<Text style={styles.viewProfileText}>View Profile</Text> <View style={styles.progressBar}>
</LinearGradient> <Animated.View
</TouchableOpacity> style={[
</View> styles.progressFill,
{
{/* Progress Bar for Profile Completion */} width: statusData?.profileStatus ? "100%" : "60%",
<View style={styles.progressSection}> backgroundColor: statusData?.profileStatus ? "#4CAF50" : "#FFA500",
<View style={styles.progressHeader}> },
<Text style={styles.progressText}>Profile Completion</Text> ]}
<Text style={styles.progressPercent}> />
{statusData?.profileStatus ? "100%" : "60%"} </View>
</Text> </View>
</View> </>
<View style={styles.progressBar}> )}
<Animated.View
style={[
styles.progressFill,
{
width: statusData?.profileStatus ? '100%' : '60%',
backgroundColor: statusData?.profileStatus ? '#4CAF50' : '#FFA500'
}
]}
/>
</View>
</View>
</LinearGradient> </LinearGradient>
{/* Enhanced Modal */} {/* Modal */}
{showModal && ( {showModal && (
<Modal visible transparent animationType="fade"> <Modal visible transparent animationType="fade">
<View style={styles.modalOverlay}> <View style={styles.modalOverlay}>
<Animated.View <Animated.View style={[styles.modalBox, { opacity: fadeAnim, transform: [{ scale: scaleAnim }] }]}>
style={[ <Ionicons name="alert-circle" size={60} color={colors.primary} />
styles.modalBox,
{
opacity: fadeAnim,
transform: [{ scale: scaleAnim }]
}
]}
>
<View style={styles.modalGraphic}>
<Ionicons name="alert-circle" size={60} color={colors.primary} />
<View style={styles.modalPulse} />
</View>
<Text style={styles.modalTitle}>Complete Your Profile</Text> <Text style={styles.modalTitle}>Complete Your Profile</Text>
<Text style={styles.modalText}> <Text style={styles.modalText}>
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.
</Text> </Text>
<View style={styles.modalProgress}>
<Text style={styles.modalProgressText}>Current Progress: 60%</Text>
<View style={styles.modalProgressBar}>
<View style={[styles.modalProgressFill, { width: '60%' }]} />
</View>
</View>
<View style={styles.modalButtons}> <View style={styles.modalButtons}>
<TouchableOpacity <TouchableOpacity style={[styles.button, styles.primaryButton]} onPress={handleGoToProfile}>
style={[styles.button, styles.primaryButton]}
onPress={handleGoToProfile}
>
<Ionicons name="person" size={18} color="#fff" /> <Ionicons name="person" size={18} color="#fff" />
<Text style={styles.buttonText}>Complete Profile</Text> <Text style={styles.buttonText}>Complete Profile</Text>
</TouchableOpacity> </TouchableOpacity>
@@ -655,7 +402,7 @@ export default UserProfileStatus;
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
margin: 16, // margin: 16,
}, },
backgroundGraphics: { backgroundGraphics: {
position: 'absolute', position: 'absolute',
@@ -742,13 +489,12 @@ const styles = StyleSheet.create({
flexDirection: 'row', flexDirection: 'row',
flexWrap: 'wrap', flexWrap: 'wrap',
justifyContent: 'space-between', justifyContent: 'space-between',
marginBottom: 16,
}, },
infoCard: { infoCard: {
width: '48%', width: '48%',
backgroundColor: 'rgba(255,255,255,0.15)', backgroundColor: 'rgba(255,255,255,0.15)',
borderRadius: 12, borderRadius: 12,
padding: 12, padding: 5,
marginBottom: 8, marginBottom: 8,
borderWidth: 1, borderWidth: 1,
borderColor: 'rgba(255,255,255,0.2)', borderColor: 'rgba(255,255,255,0.2)',
@@ -782,6 +528,7 @@ const styles = StyleSheet.create({
borderRadius: 12, borderRadius: 12,
borderWidth: 1, borderWidth: 1,
borderColor: 'rgba(255,255,255,0.2)', borderColor: 'rgba(255,255,255,0.2)',
marginTop: 16,
}, },
statusHeader: { statusHeader: {
flexDirection: 'row', flexDirection: 'row',
@@ -797,13 +544,6 @@ const styles = StyleSheet.create({
statusItems: { statusItems: {
gap: 8, gap: 8,
}, },
statusItem: {
flexDirection: 'row',
alignItems: 'center',
},
statusIndicator: {
marginRight: 8,
},
statusItemText: { statusItemText: {
color: "#fff", color: "#fff",
fontSize: 14, fontSize: 14,
@@ -902,19 +642,6 @@ const styles = StyleSheet.create({
shadowRadius: 15, shadowRadius: 15,
shadowOffset: { width: 0, height: 6 }, 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: { modalTitle: {
fontSize: 22, fontSize: 22,
fontWeight: "700", fontWeight: "700",
@@ -929,28 +656,6 @@ const styles = StyleSheet.create({
lineHeight: 20, lineHeight: 20,
marginBottom: 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: { modalButtons: {
width: '100%', width: '100%',
gap: 8, gap: 8,
+3 -2
View File
@@ -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 BASE_URL = "http://192.168.1.5:9060/api/"
export const LOGIN_URL = `${BASE_URL}user/generate/otp?mobiles=` export const LOGIN_URL = `${BASE_URL}user/generate/otp?mobiles=`
export const VARIFY_OTP_URL = `${BASE_URL}user/otp/verify` 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 TRANSACTION = `${BASE_URL}payments/my-transactions`;
export const UPLOAD_GROUP_IMAGE = `${BASE_URL}fund/groups/`; export const UPLOAD_GROUP_IMAGE = `${BASE_URL}fund/groups/`;
export const STORE_FCM_TOKEN = `${BASE_URL}token/store?fcmToken=` export const STORE_FCM_TOKEN = `${BASE_URL}token/store?fcmToken=`
export const REMOVE_FCM_TOKEN = `${BASE_URL}token/remove?fcmToken=` export const REMOVE_FCM_TOKEN = `${BASE_URL}token/remove?fcmToken=`
export const DASHBOARD_URL = `${BASE_URL}fund/dashboard`