dashboard marged
This commit is contained in:
@@ -18,8 +18,8 @@ const Header: React.FC<HeaderProps> = ({
|
||||
showBack = true,
|
||||
onBackPress,
|
||||
rightAction,
|
||||
titleColor = colors.primary,
|
||||
arrowColor = colors.primary
|
||||
titleColor = '#000',
|
||||
arrowColor = '#000'
|
||||
}) => {
|
||||
const navigation = useNavigation();
|
||||
|
||||
@@ -33,12 +33,12 @@ const Header: React.FC<HeaderProps> = ({
|
||||
|
||||
return (
|
||||
<View style={styles.header}>
|
||||
{/* {showBack && (
|
||||
{showBack && (
|
||||
<TouchableOpacity onPress={handleBack} style={{padding:6}}>
|
||||
<Ionicons name="arrow-back" size={24} color={arrowColor} />
|
||||
</TouchableOpacity>
|
||||
)} */}
|
||||
<Text style={[styles.headerTitle, {color:colors.black}]}>{title}</Text>
|
||||
)}
|
||||
<Text style={[styles.headerTitle, {color:titleColor}]}>{title}</Text>
|
||||
<View>{rightAction}</View>
|
||||
</View>
|
||||
);
|
||||
@@ -57,6 +57,6 @@ const styles = StyleSheet.create({
|
||||
headerTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: "600",
|
||||
textTransform:'uppercase'
|
||||
textTransform: "capitalize",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -190,7 +190,8 @@ export default function GroupScreen() {
|
||||
try {
|
||||
const credentials = await Keychain.getGenericPassword();
|
||||
if (!credentials) {
|
||||
Alert.alert("Error", "You are not logged in");
|
||||
ToastAndroid.show('You are not logged in', ToastAndroid.SHORT);
|
||||
|
||||
return;
|
||||
}
|
||||
const token = credentials.password;
|
||||
@@ -233,7 +234,7 @@ export default function GroupScreen() {
|
||||
|
||||
const handleViewGroup = (group: Group) => {
|
||||
// navigation.navigate('GroupDetails', { group });
|
||||
Alert.alert("View Group", `Viewing details for ${group.groupName}`);
|
||||
ToastAndroid.show(`Viewing details for ${group.groupName}`, ToastAndroid.SHORT);
|
||||
};
|
||||
|
||||
const onRefresh = () => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
TouchableOpacity,
|
||||
Alert,
|
||||
ActivityIndicator,
|
||||
ToastAndroid,
|
||||
} from 'react-native';
|
||||
import { RootStackParamList } from '../navigation/AppNavigator'; // Adjust path
|
||||
import { apiCall } from '../utils/ApiHelper'; // Adjust path
|
||||
@@ -78,9 +79,10 @@ const InviteScreen: FC<InviteScreenProps> = ({ route }) => {
|
||||
// Replace with your actual API call to join the group
|
||||
// For now, it just shows an alert.
|
||||
await apiCall(`http://192.168.1.5:9060/api/fund/groups/join/invite/${code}`, 'POST');
|
||||
Alert.alert('Success!', `You have requested to join "${groupDetails.groupName}".`);
|
||||
ToastAndroid.show(`You have requested to join "${groupDetails.groupName}".`, ToastAndroid.SHORT);
|
||||
fetchGroupDetails(); // Refresh details after joining
|
||||
} catch (e: any) {
|
||||
Alert.alert('Join Error', e.message || 'An unexpected error occurred.');
|
||||
ToastAndroid.show(e.message || 'An unexpected error occurred.', ToastAndroid.SHORT);
|
||||
} finally {
|
||||
setJoining(false);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
ScrollView,
|
||||
ToastAndroid,
|
||||
} from "react-native";
|
||||
import axios from "axios";
|
||||
import { ORGRAGISTRATION } from "../utils/ApiUrls";
|
||||
@@ -30,7 +31,7 @@ export default function OrganizerRegisterScreen() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const handleSubmit = async () => {
|
||||
if (!bankAccountNumber || !bankName || !branchCode) {
|
||||
Alert.alert("Error", "All fields are required.");
|
||||
ToastAndroid.show('All fields are required.', ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -42,7 +43,7 @@ const handleSubmit = async () => {
|
||||
const token = creds ? creds.password : null;
|
||||
|
||||
if (!token) {
|
||||
Alert.alert("Error", "No token found. Please log in again.");
|
||||
ToastAndroid.show('No token found. Please log in again.', ToastAndroid.SHORT);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
@@ -65,10 +66,13 @@ const handleSubmit = async () => {
|
||||
);
|
||||
|
||||
console.log("✅ Organizer Registered:", res.data);
|
||||
Alert.alert("Success", "Organizer registered successfully!");
|
||||
ToastAndroid.show('Organizer registered successfully!', ToastAndroid.SHORT);
|
||||
// Optionally, reset form fields
|
||||
setBankAccountNumber("");
|
||||
setBankName("");
|
||||
setBranchCode("");
|
||||
} catch (err: any) {
|
||||
console.error("❌ Register Error:", err?.response?.data || err.message);
|
||||
// Alert.alert("Error", "Failed to register. Please try again.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ const GroupList = () => {
|
||||
const fetchGroups = async () => {
|
||||
const credentials = await keychain.getGenericPassword();
|
||||
if (!credentials) {
|
||||
Alert.alert("Error", "You are not logged in");
|
||||
ToastAndroid.show('You are not logged in', ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
const token = credentials.password;
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Alert,
|
||||
FlatList,
|
||||
ListRenderItem,
|
||||
ToastAndroid,
|
||||
} from "react-native";
|
||||
import AppView from "../../components/AppView";
|
||||
import colors from "../../components/colors";
|
||||
@@ -188,13 +189,12 @@ const Home: React.FC = () => {
|
||||
<Text style={styles.userName}>{user.firstName || apiUser?.firstName || 'User'}</Text>
|
||||
</View>
|
||||
<TouchableOpacity onPress={() => navigation.navigate("Notification" as never)}>
|
||||
{/* <Image source={getProfileImageUri()} style={styles.profileImage} /> */}
|
||||
<Text style={{ position: 'absolute', right: -6, top: -4, backgroundColor: colors.danger, color: colors.white, borderRadius: 8, width: 16, height: 16, textAlign: 'center', fontSize: 10, fontWeight: 'bold', lineHeight: 16, zIndex: 1 }}>{unreadCount > 0 ? unreadCount : ''}</Text>
|
||||
<Ionicons name="notifications-outline" size={30} color={colors.textDark} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<UserProfileStatus />
|
||||
<UserProfileStatus profileImage={getProfileImageUri()} />
|
||||
|
||||
<Text style={styles.sectionTitle}>Quick Actions</Text>
|
||||
|
||||
@@ -240,13 +240,6 @@ const styles = StyleSheet.create({
|
||||
fontWeight: 'bold',
|
||||
color: colors.textDark,
|
||||
},
|
||||
profileImage: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: 25,
|
||||
borderColor: colors.pastelPink, // Using pastelPink for border
|
||||
borderWidth: 2,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: '600',
|
||||
|
||||
@@ -8,7 +8,8 @@ import {
|
||||
RefreshControl,
|
||||
Alert,
|
||||
ActivityIndicator,
|
||||
TextInput
|
||||
TextInput,
|
||||
ToastAndroid
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@react-native-vector-icons/ionicons';
|
||||
import colors from '../../components/colors';
|
||||
@@ -50,7 +51,7 @@ const RequestList: React.FC = () => {
|
||||
|
||||
const credentials = await keychain.getGenericPassword();
|
||||
if (!credentials) {
|
||||
Alert.alert("Error", "You are not logged in");
|
||||
ToastAndroid.show('You are not logged in', ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
const token = credentials.password;
|
||||
@@ -146,14 +147,13 @@ const RequestList: React.FC = () => {
|
||||
// Remove the accepted request from the list
|
||||
const updatedRequests = requests.filter(req => req.requestId !== requestId);
|
||||
setRequests(updatedRequests);
|
||||
Alert.alert("Success", data.message || "Request accepted successfully");
|
||||
ToastAndroid.show(data.message || "Request accepted successfully", ToastAndroid.SHORT);
|
||||
fetchRequests();
|
||||
} else {
|
||||
throw new Error(data.message || "Failed to accept request");
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
|
||||
// Alert.alert("Error", `Failed to accept request: ${errorMessage}`);
|
||||
console.error("Accept Error:", error);
|
||||
} finally {
|
||||
setProcessingRequest(null);
|
||||
@@ -192,14 +192,15 @@ const RequestList: React.FC = () => {
|
||||
// Remove the declined request from the list
|
||||
const updatedRequests = requests.filter(req => req.requestId !== selectedRequestId);
|
||||
setRequests(updatedRequests);
|
||||
Alert.alert("Success", data.message || "Request declined successfully");
|
||||
ToastAndroid.show(data.message || "Request declined successfully", ToastAndroid.SHORT);
|
||||
|
||||
fetchRequests();
|
||||
} else {
|
||||
throw new Error(data.message || "Failed to decline request");
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
|
||||
// Alert.alert("Error", `Failed to decline request: ${errorMessage}`);
|
||||
|
||||
console.error("Decline Error:", error);
|
||||
} finally {
|
||||
setProcessingRequest(null);
|
||||
|
||||
@@ -1,249 +1,314 @@
|
||||
import React, { use, useCallback, useEffect, useState } from "react";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
ActivityIndicator,
|
||||
TouchableOpacity,
|
||||
Modal,
|
||||
Alert,
|
||||
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";
|
||||
import {Ionicons} from "@react-native-vector-icons/ionicons";
|
||||
|
||||
export type ApiResponse = {
|
||||
message: string;
|
||||
status: string;
|
||||
statusCode: number;
|
||||
data: {
|
||||
role: string;
|
||||
organizerStatus: string;
|
||||
profileStatus: boolean;
|
||||
};
|
||||
message: string;
|
||||
status: string;
|
||||
statusCode: number;
|
||||
data: {
|
||||
role: string;
|
||||
organizerStatus: string;
|
||||
profileStatus: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
type UserProfileStatusProps = {
|
||||
profileImage?: { uri: string };
|
||||
};
|
||||
|
||||
const UserProfileStatus: React.FC = () => {
|
||||
const navigation = useNavigation();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [statusData, setStatusData] = useState<ApiResponse["data"] | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [intervalId, setIntervalId] = useState<null | number>(null);
|
||||
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) {
|
||||
Alert.alert("Error", "You are not logged in");
|
||||
return;
|
||||
}
|
||||
const token = credentials.password;
|
||||
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);
|
||||
setError(null);
|
||||
const response = await fetch(PUT_USER_STATUS, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Accept: "*/*",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
setLoading(true);
|
||||
const response = await fetch(PUT_USER_STATUS, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Accept: "*/*",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const json: ApiResponse = await response.json();
|
||||
|
||||
console.log("Profile Status :", json);
|
||||
if (json.status === "success") {
|
||||
setStatusData(json.data);
|
||||
|
||||
if (json.data.profileStatus === false) {
|
||||
setShowModal(true);
|
||||
}
|
||||
} else {
|
||||
setError(json.message || "Failed to fetch status");
|
||||
}
|
||||
} catch (err) {
|
||||
setError("Something went wrong. Please try again.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
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();
|
||||
}, [])
|
||||
);
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
userStatus();
|
||||
}, [])
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (statusData && statusData.profileStatus === false) {
|
||||
const id = setInterval(() => {
|
||||
setShowModal(true);
|
||||
}, 5000);
|
||||
setIntervalId(id);
|
||||
return () => clearInterval(id);
|
||||
}
|
||||
}, [statusData]);
|
||||
useEffect(() => {
|
||||
Animated.timing(fadeAnim, {
|
||||
toValue: 1,
|
||||
duration: 600,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
}, []);
|
||||
|
||||
const handleGoToProfile = () => {
|
||||
// Stop modal repetition
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
setIntervalId(null);
|
||||
}
|
||||
const handleGoToProfile = () => {
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
setIntervalId(null);
|
||||
}
|
||||
setShowModal(false);
|
||||
navigation.navigate("Profile" as never);
|
||||
};
|
||||
|
||||
setShowModal(false);
|
||||
const handlePress = (label: string) => {
|
||||
ToastAndroid.show(`${label} clicked`, ToastAndroid.SHORT);
|
||||
};
|
||||
|
||||
// Option 1: Mark profile as completed temporarily (so condition stops)
|
||||
setStatusData(prev => (prev ? { ...prev, profileStatus: true } : prev));
|
||||
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>
|
||||
|
||||
// Navigate to Profile screen
|
||||
navigation.navigate("Profile" as never);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{/* <Text style={styles.title}>Welcome Back 👋</Text> */}
|
||||
|
||||
<LinearGradient
|
||||
colors={[colors.pastelPink, colors.pastelPink
|
||||
]}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
style={styles.card}
|
||||
>
|
||||
<View>
|
||||
<Text style={styles.cardTitle}>Profile Status</Text>
|
||||
<Text style={{ color: '#fff' }}>Role: {statusData?.role}</Text>
|
||||
<Text style={{ color: '#fff' }}>Organizer: {statusData?.organizerStatus}</Text>
|
||||
<Text style={{ color: '#fff' }}>
|
||||
Profile Completed: {statusData?.profileStatus ? "Yes ✅" : "No ❌"}
|
||||
</Text>
|
||||
</View>
|
||||
<Ionicons name="person-circle" color={'#fff'} size={100}/>
|
||||
</LinearGradient>
|
||||
|
||||
|
||||
{/* Custom Modal */}
|
||||
{showModal && (
|
||||
<Modal
|
||||
visible={showModal}
|
||||
animationType="slide"
|
||||
transparent
|
||||
onRequestClose={() => setShowModal(false)}
|
||||
<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)}
|
||||
>
|
||||
<View style={styles.modalOverlay}>
|
||||
<View style={styles.modalBox}>
|
||||
<Text style={styles.modalTitle}>Complete Your Profile</Text>
|
||||
<Text style={styles.modalText}>
|
||||
Your profile is incomplete. Please update your details to continue.
|
||||
</Text>
|
||||
<Text style={styles.infoLabel}>{label}</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
|
||||
<TouchableOpacity style={styles.button} onPress={handleGoToProfile}>
|
||||
<Text style={styles.buttonText}>Go to Profile</Text>
|
||||
</TouchableOpacity>
|
||||
<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>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[styles.button, { backgroundColor: "#ccc", marginTop: 8 }]}
|
||||
onPress={() => {
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
setIntervalId(null);
|
||||
}
|
||||
|
||||
setShowModal(false);
|
||||
}}
|
||||
>
|
||||
<Text style={[styles.buttonText, { color: "#333" }]}>Close</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
)}
|
||||
<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: {
|
||||
// flex: 1,
|
||||
// padding: 16,
|
||||
// backgroundColor: "#f5f7fb",
|
||||
},
|
||||
centered: {
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
title: {
|
||||
fontSize: 22,
|
||||
fontWeight: "700",
|
||||
marginBottom: 20,
|
||||
},
|
||||
card: {
|
||||
backgroundColor: "#fff",
|
||||
padding: 16,
|
||||
borderRadius: 12,
|
||||
elevation: 3,
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 6,
|
||||
marginBottom: 10,
|
||||
justifyContent:'space-between',
|
||||
flexDirection:'row'
|
||||
},
|
||||
cardTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: "600",
|
||||
marginBottom: 10,
|
||||
color: '#fff'
|
||||
},
|
||||
button: {
|
||||
backgroundColor: "#007AFF",
|
||||
paddingVertical: 10,
|
||||
paddingHorizontal: 20,
|
||||
borderRadius: 8,
|
||||
alignItems: "center",
|
||||
},
|
||||
buttonText: {
|
||||
color: "#fff",
|
||||
fontWeight: "600",
|
||||
},
|
||||
errorText: {
|
||||
color: "red",
|
||||
fontSize: 16,
|
||||
marginBottom: 12,
|
||||
},
|
||||
modalOverlay: {
|
||||
flex: 1,
|
||||
backgroundColor: "rgba(0,0,0,0.4)",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
modalBox: {
|
||||
width: "85%",
|
||||
backgroundColor: "#fff",
|
||||
borderRadius: 16,
|
||||
padding: 20,
|
||||
alignItems: "center",
|
||||
elevation: 5,
|
||||
},
|
||||
modalTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: "700",
|
||||
marginBottom: 10,
|
||||
color: colors.primary,
|
||||
},
|
||||
modalText: {
|
||||
fontSize: 14,
|
||||
color: "#444",
|
||||
textAlign: "center",
|
||||
marginBottom: 20,
|
||||
},
|
||||
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",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,249 +1,267 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
FlatList,
|
||||
TouchableOpacity,
|
||||
Alert,
|
||||
RefreshControl,
|
||||
ScrollView,
|
||||
Button,
|
||||
} from "react-native";
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
import type { NativeStackNavigationProp } from "@react-navigation/native-stack";
|
||||
import type { RootStackParamList } from "../../../navigation/AppNavigator";
|
||||
import colors from "../../../components/colors";
|
||||
import { Ionicons } from "@react-native-vector-icons/ionicons";
|
||||
import { GET_JOINED_GROUP_URL } from "../../../utils/ApiUrls";
|
||||
import * as Keychain from "react-native-keychain";
|
||||
import AnimatedCard from "../../../components/common/AnimatedCard";
|
||||
// import React, { useEffect, useState } from "react";
|
||||
// import {
|
||||
// StyleSheet,
|
||||
// Text,
|
||||
// View,
|
||||
// FlatList,
|
||||
// TouchableOpacity,
|
||||
// Alert,
|
||||
// RefreshControl,
|
||||
// ScrollView,
|
||||
// Button,
|
||||
// ToastAndroid,
|
||||
// } from "react-native";
|
||||
// import { useNavigation } from "@react-navigation/native";
|
||||
// import type { NativeStackNavigationProp } from "@react-navigation/native-stack";
|
||||
// import type { RootStackParamList } from "../../../navigation/AppNavigator";
|
||||
// import colors from "../../../components/colors";
|
||||
// import { Ionicons } from "@react-native-vector-icons/ionicons";
|
||||
// import { GET_JOINED_GROUP_URL } from "../../../utils/ApiUrls";
|
||||
// import * as Keychain from "react-native-keychain";
|
||||
// import AnimatedCard from "../../../components/common/AnimatedCard";
|
||||
|
||||
type NavigationProp = NativeStackNavigationProp<
|
||||
RootStackParamList,
|
||||
"GroupDetails"
|
||||
>;
|
||||
// type NavigationProp = NativeStackNavigationProp<
|
||||
// RootStackParamList,
|
||||
// "GroupDetails"
|
||||
// >;
|
||||
|
||||
type Group = {
|
||||
id: string;
|
||||
groupName: string;
|
||||
description: string;
|
||||
currentParticipants: number;
|
||||
maxParticipants: number;
|
||||
contributionAmount: number;
|
||||
status: string;
|
||||
};
|
||||
// type Group = {
|
||||
// id: string;
|
||||
// groupName: string;
|
||||
// description: string;
|
||||
// currentParticipants: number;
|
||||
// maxParticipants: number;
|
||||
// contributionAmount: number;
|
||||
// status: string;
|
||||
// };
|
||||
|
||||
// const UserHome = () => {
|
||||
// const navigation = useNavigation<NavigationProp>();
|
||||
// const [groups, setGroups] = useState<Group[]>([]);
|
||||
// const [loading, setLoading] = useState<boolean>(false)
|
||||
// const [refreshing, setRefreshing] = useState<boolean>(false)
|
||||
|
||||
|
||||
// const activeGroups = groups.filter((g) => g.status === "ACTIVE");
|
||||
|
||||
// const totalGroups = activeGroups.length;
|
||||
|
||||
// const totalContribution = activeGroups.reduce(
|
||||
// (sum, g) => sum + g.contributionAmount,
|
||||
// 0
|
||||
// );
|
||||
|
||||
// const onRefresh = async () => {
|
||||
// setRefreshing(true)
|
||||
// await handleGroup()
|
||||
// setRefreshing(false)
|
||||
// }
|
||||
|
||||
// const handleGroup = async () => {
|
||||
// try {
|
||||
// setLoading(true)
|
||||
// const credentials = await Keychain.getGenericPassword();
|
||||
// if (!credentials) {
|
||||
// ToastAndroid.show('You are not logged in', ToastAndroid.SHORT);
|
||||
// return;
|
||||
// }
|
||||
// const token = credentials.password;
|
||||
|
||||
// const response = await fetch(GET_JOINED_GROUP_URL, {
|
||||
// method: "GET",
|
||||
// headers: {
|
||||
// Accept: "*/*",
|
||||
// Authorization: `Bearer ${token}`,
|
||||
// },
|
||||
// });
|
||||
|
||||
// const result = await response.json();
|
||||
// if (result.status === "success") {
|
||||
// console.log("GET_JOINED_GROUP_URL res : ", result);
|
||||
// setGroups(result.data); // save API data
|
||||
// setLoading(false)
|
||||
// } else {
|
||||
// ToastAndroid.show("Failed to fetch groups", ToastAndroid.SHORT);
|
||||
// setLoading(false)
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error("❌ Error fetching groups:", error);
|
||||
// } finally {
|
||||
// setLoading(false)
|
||||
// }
|
||||
// };
|
||||
|
||||
// useEffect(() => {
|
||||
// handleGroup();
|
||||
// }, []);
|
||||
|
||||
// const renderItem = ({ item }: { item: Group }) => {
|
||||
// return (
|
||||
// <TouchableOpacity
|
||||
// style={styles.card}
|
||||
// onPress={() => navigation.navigate("GroupDetails", { item })}
|
||||
// >
|
||||
// <Text style={styles.groupName}>{item.groupName}</Text>
|
||||
// <Text style={styles.description} numberOfLines={1}>{item.description}</Text>
|
||||
// <View style={styles.statsRow}>
|
||||
// <Ionicons
|
||||
// name="person-circle-outline"
|
||||
// size={20}
|
||||
// color={colors.primary}
|
||||
// />
|
||||
// <Text style={styles.detail}>
|
||||
// {item.currentParticipants}/{item.maxParticipants} members
|
||||
// </Text>
|
||||
// </View>
|
||||
|
||||
// <Text style={styles.amount}>
|
||||
// Contribution: ₹{item.contributionAmount}
|
||||
// </Text>
|
||||
// <Text style={styles.status}>Status: {item.status}</Text>
|
||||
// </TouchableOpacity>
|
||||
// );
|
||||
// };
|
||||
|
||||
// return (
|
||||
// <ScrollView>
|
||||
// {/* Stats */}
|
||||
|
||||
// {/* <Button title="Transaction List" onPress={()=>navigation.navigate('TransactionList')}/> */}
|
||||
// <AnimatedCard
|
||||
// onPress={() => navigation.navigate("TransactionList")}
|
||||
// title={"transaction list"} iconName="calculator-outline"
|
||||
// subtitle="View your transaction history"
|
||||
// backOne={colors.Home}
|
||||
// backTwo={colors.pastelPink}
|
||||
// />
|
||||
// <AnimatedCard
|
||||
// onPress={() => navigation.navigate("Management" as never)}
|
||||
// title={"Group Management"}
|
||||
// iconName="person-outline"
|
||||
// subtitle="Manage your joined & requested groups"
|
||||
// backOne={colors.Settings}
|
||||
// backTwo={colors.pastelOrange}
|
||||
// />
|
||||
|
||||
// <View style={[styles.statsRow, { marginTop: 12 }]}>
|
||||
// <View style={styles.statBox}>
|
||||
// <Text style={styles.statValue}>{totalGroups}</Text>
|
||||
// <Text style={styles.statLabel}>Groups Joined</Text>
|
||||
// </View>
|
||||
// <View style={styles.statBox}>
|
||||
// <Text style={styles.statValue}>₹{totalContribution}</Text>
|
||||
// <Text style={styles.statLabel}>Cycle Contribution</Text>
|
||||
// </View>
|
||||
// </View>
|
||||
|
||||
|
||||
// {/* Groups List */}
|
||||
// <Text style={styles.sectionTitle}>Your Groups</Text>
|
||||
// <FlatList
|
||||
// data={groups.filter((status) => status.status === "ACTIVE")}
|
||||
// keyExtractor={(item) => item.id}
|
||||
// renderItem={renderItem}
|
||||
// contentContainerStyle={{ paddingBottom: 20 }}
|
||||
// onRefresh={onRefresh}
|
||||
// refreshing={refreshing}
|
||||
// />
|
||||
// </ScrollView>
|
||||
// );
|
||||
// };
|
||||
|
||||
// export default UserHome;
|
||||
|
||||
// const styles = StyleSheet.create({
|
||||
// statsRow: {
|
||||
// flexDirection: "row",
|
||||
// gap: 10,
|
||||
// },
|
||||
// statBox: {
|
||||
// flex: 1,
|
||||
// backgroundColor: "#fff",
|
||||
// padding: 16,
|
||||
// borderRadius: 12,
|
||||
// alignItems: "center",
|
||||
// shadowColor: "#000",
|
||||
// shadowOpacity: 0.05,
|
||||
// shadowOffset: { width: 0, height: 2 },
|
||||
// shadowRadius: 6,
|
||||
// elevation: 2,
|
||||
// borderWidth:1,
|
||||
// borderColor:colors.Home
|
||||
// },
|
||||
// statValue: {
|
||||
// fontSize: 18,
|
||||
// fontWeight: "700",
|
||||
// color: colors.Home,
|
||||
// },
|
||||
// statLabel: {
|
||||
// fontSize: 12,
|
||||
// color: "#64748b",
|
||||
// marginTop: 4,
|
||||
// },
|
||||
// sectionTitle: {
|
||||
// fontSize: 18,
|
||||
// fontWeight: "600",
|
||||
// color: colors.Home,
|
||||
// marginBottom: 12,
|
||||
// marginTop:15
|
||||
// },
|
||||
// card: {
|
||||
// backgroundColor: "#ffffff",
|
||||
// padding: 16,
|
||||
// marginBottom: 12,
|
||||
// borderRadius: 12,
|
||||
// shadowColor: "#000",
|
||||
// shadowOpacity: 0.05,
|
||||
// shadowOffset: { width: 0, height: 2 },
|
||||
// shadowRadius: 6,
|
||||
// elevation: 2,
|
||||
// borderLeftWidth: 5,
|
||||
// borderColor: colors.Home
|
||||
// },
|
||||
// groupName: {
|
||||
// fontSize: 16,
|
||||
// fontWeight: "600",
|
||||
// color: colors.Home,
|
||||
// marginBottom: 4,
|
||||
// },
|
||||
// description: {
|
||||
// fontSize: 13,
|
||||
// color: "#475569",
|
||||
// marginBottom: 8,
|
||||
// },
|
||||
// detail: {
|
||||
// fontSize: 13,
|
||||
// color: "#475569",
|
||||
// marginBottom: 8,
|
||||
// },
|
||||
// amount: {
|
||||
// fontSize: 13,
|
||||
// color: "#64748b",
|
||||
// marginTop: 4,
|
||||
// },
|
||||
// status: {
|
||||
// fontSize: 12,
|
||||
// fontWeight: "500",
|
||||
// color: colors.primary,
|
||||
// marginTop: 2,
|
||||
// },
|
||||
// });
|
||||
|
||||
|
||||
|
||||
import { StyleSheet, Text, View } from 'react-native'
|
||||
import React from 'react'
|
||||
|
||||
const UserHome = () => {
|
||||
const navigation = useNavigation<NavigationProp>();
|
||||
const [groups, setGroups] = useState<Group[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
const [refreshing, setRefreshing] = useState<boolean>(false)
|
||||
return (
|
||||
<View>
|
||||
<Text>UserHome</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default UserHome
|
||||
|
||||
const activeGroups = groups.filter((g) => g.status === "ACTIVE");
|
||||
|
||||
const totalGroups = activeGroups.length;
|
||||
|
||||
const totalContribution = activeGroups.reduce(
|
||||
(sum, g) => sum + g.contributionAmount,
|
||||
0
|
||||
);
|
||||
|
||||
const onRefresh = async () => {
|
||||
setRefreshing(true)
|
||||
await handleGroup()
|
||||
setRefreshing(false)
|
||||
}
|
||||
|
||||
const handleGroup = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
const credentials = await Keychain.getGenericPassword();
|
||||
if (!credentials) {
|
||||
Alert.alert("Error", "You are not logged in");
|
||||
return;
|
||||
}
|
||||
const token = credentials.password;
|
||||
|
||||
const response = await fetch(GET_JOINED_GROUP_URL, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Accept: "*/*",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
if (result.status === "success") {
|
||||
console.log("GET_JOINED_GROUP_URL res : ", result);
|
||||
setGroups(result.data); // save API data
|
||||
setLoading(false)
|
||||
} else {
|
||||
Alert.alert("Error", "Failed to fetch groups");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("❌ Error fetching groups:", error);
|
||||
// Alert.alert("Error", "Could not connect to server");
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
handleGroup();
|
||||
}, []);
|
||||
|
||||
const renderItem = ({ item }: { item: Group }) => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={styles.card}
|
||||
onPress={() => navigation.navigate("GroupDetails", { item })}
|
||||
>
|
||||
<Text style={styles.groupName}>{item.groupName}</Text>
|
||||
<Text style={styles.description} numberOfLines={1}>{item.description}</Text>
|
||||
<View style={styles.statsRow}>
|
||||
<Ionicons
|
||||
name="person-circle-outline"
|
||||
size={20}
|
||||
color={colors.primary}
|
||||
/>
|
||||
<Text style={styles.detail}>
|
||||
{item.currentParticipants}/{item.maxParticipants} members
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<Text style={styles.amount}>
|
||||
Contribution: ₹{item.contributionAmount}
|
||||
</Text>
|
||||
<Text style={styles.status}>Status: {item.status}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<ScrollView>
|
||||
{/* Stats */}
|
||||
|
||||
{/* <Button title="Transaction List" onPress={()=>navigation.navigate('TransactionList')}/> */}
|
||||
<AnimatedCard
|
||||
onPress={() => navigation.navigate("TransactionList")}
|
||||
title={"transaction list"} iconName="calculator-outline"
|
||||
subtitle="View your transaction history"
|
||||
backOne={colors.Home}
|
||||
backTwo={colors.pastelPink}
|
||||
/>
|
||||
<AnimatedCard
|
||||
onPress={() => navigation.navigate("Management" as never)}
|
||||
title={"Group Management"}
|
||||
iconName="person-outline"
|
||||
subtitle="Manage your joined & requested groups"
|
||||
backOne={colors.Settings}
|
||||
backTwo={colors.pastelOrange}
|
||||
/>
|
||||
|
||||
<View style={[styles.statsRow, { marginTop: 12 }]}>
|
||||
<View style={styles.statBox}>
|
||||
<Text style={styles.statValue}>{totalGroups}</Text>
|
||||
<Text style={styles.statLabel}>Groups Joined</Text>
|
||||
</View>
|
||||
<View style={styles.statBox}>
|
||||
<Text style={styles.statValue}>₹{totalContribution}</Text>
|
||||
<Text style={styles.statLabel}>Cycle Contribution</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
|
||||
{/* Groups List */}
|
||||
<Text style={styles.sectionTitle}>Your Groups</Text>
|
||||
<FlatList
|
||||
data={groups.filter((status) => status.status === "ACTIVE")}
|
||||
keyExtractor={(item) => item.id}
|
||||
renderItem={renderItem}
|
||||
contentContainerStyle={{ paddingBottom: 20 }}
|
||||
onRefresh={onRefresh}
|
||||
refreshing={refreshing}
|
||||
/>
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserHome;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
statsRow: {
|
||||
flexDirection: "row",
|
||||
gap: 10,
|
||||
},
|
||||
statBox: {
|
||||
flex: 1,
|
||||
backgroundColor: "#fff",
|
||||
padding: 16,
|
||||
borderRadius: 12,
|
||||
alignItems: "center",
|
||||
shadowColor: "#000",
|
||||
shadowOpacity: 0.05,
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowRadius: 6,
|
||||
elevation: 2,
|
||||
borderWidth:1,
|
||||
borderColor:colors.Home
|
||||
},
|
||||
statValue: {
|
||||
fontSize: 18,
|
||||
fontWeight: "700",
|
||||
color: colors.Home,
|
||||
},
|
||||
statLabel: {
|
||||
fontSize: 12,
|
||||
color: "#64748b",
|
||||
marginTop: 4,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: "600",
|
||||
color: colors.Home,
|
||||
marginBottom: 12,
|
||||
marginTop:15
|
||||
},
|
||||
card: {
|
||||
backgroundColor: "#ffffff",
|
||||
padding: 16,
|
||||
marginBottom: 12,
|
||||
borderRadius: 12,
|
||||
shadowColor: "#000",
|
||||
shadowOpacity: 0.05,
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowRadius: 6,
|
||||
elevation: 2,
|
||||
borderLeftWidth: 5,
|
||||
borderColor: colors.Home
|
||||
},
|
||||
groupName: {
|
||||
fontSize: 16,
|
||||
fontWeight: "600",
|
||||
color: colors.Home,
|
||||
marginBottom: 4,
|
||||
},
|
||||
description: {
|
||||
fontSize: 13,
|
||||
color: "#475569",
|
||||
marginBottom: 8,
|
||||
},
|
||||
detail: {
|
||||
fontSize: 13,
|
||||
color: "#475569",
|
||||
marginBottom: 8,
|
||||
},
|
||||
amount: {
|
||||
fontSize: 13,
|
||||
color: "#64748b",
|
||||
marginTop: 4,
|
||||
},
|
||||
status: {
|
||||
fontSize: 12,
|
||||
fontWeight: "500",
|
||||
color: colors.primary,
|
||||
marginTop: 2,
|
||||
},
|
||||
});
|
||||
const styles = StyleSheet.create({})
|
||||
@@ -65,7 +65,7 @@ export interface GroupDetails {
|
||||
organizerId: string;
|
||||
totalParticipants: number;
|
||||
participants: Participant[];
|
||||
imageBlob: string
|
||||
imageBlob: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
|
||||
if (!groupDetails) return;
|
||||
|
||||
if (editableData.maxParticipants < groupDetails.totalParticipants) {
|
||||
Alert.alert('Invalid Input', `Max participants cannot be less than the current count (${groupDetails.totalParticipants}).`);
|
||||
ToastAndroid.show(`Max participants cannot be less than the current count (${groupDetails.totalParticipants}).`, ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
|
||||
setEditingCard(null);
|
||||
await fetchGroupDetails();
|
||||
} catch (e: any) {
|
||||
Alert.alert('Save Error', e.message || 'An unexpected error occurred.');
|
||||
ToastAndroid.show(e.message || 'An unexpected error occurred.', ToastAndroid.SHORT);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
@@ -252,11 +252,11 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
|
||||
setStarting(true);
|
||||
try {
|
||||
await apiCall(`${BASE_URL}fund/group/start?groupId=${groupDetails.id}`, 'GET');
|
||||
Alert.alert('Success', 'Group has been started successfully.');
|
||||
ToastAndroid.show('Group has been started successfully.', ToastAndroid.SHORT);
|
||||
await fetchGroupDetails();
|
||||
navigation.goBack()
|
||||
} catch (e: any) {
|
||||
Alert.alert('Start Error', e.message || 'An unexpected error occurred.');
|
||||
ToastAndroid.show(e.message || 'An unexpected error occurred.', ToastAndroid.SHORT);
|
||||
} finally {
|
||||
setStarting(false);
|
||||
}
|
||||
@@ -278,7 +278,7 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
|
||||
|
||||
if (inviteLink) {
|
||||
Clipboard.setString(inviteLink);
|
||||
Alert.alert('Copied!', 'Invitation link copied to clipboard.');
|
||||
ToastAndroid.show('Invitation link copied to clipboard.', ToastAndroid.SHORT);
|
||||
await Share.share({
|
||||
message: `Join my group on CircleCollect! ${inviteLink}`,
|
||||
url: inviteLink,
|
||||
@@ -288,7 +288,7 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
|
||||
throw new Error('Could not generate invitation link.');
|
||||
}
|
||||
} catch (error: any) {
|
||||
Alert.alert('Error', error.message || 'Failed to generate invitation.');
|
||||
ToastAndroid.show(error.message || 'Failed to generate invitation.', ToastAndroid.SHORT);
|
||||
} finally {
|
||||
setInviting(false);
|
||||
}
|
||||
@@ -399,18 +399,18 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
|
||||
|
||||
|
||||
console.log(" myu status : ", groupDetails.status)
|
||||
|
||||
|
||||
const pickImage = () => {
|
||||
launchImageLibrary({ mediaType: "photo", quality: 0.5 }, (response) => {
|
||||
if (response.didCancel) return;
|
||||
|
||||
if (response.errorCode) {
|
||||
Alert.alert("Error", response.errorMessage || "Something went wrong");
|
||||
ToastAndroid.show(response.errorMessage || "Something went wrong", ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.assets || response.assets.length === 0) {
|
||||
Alert.alert("Error", "No image selected");
|
||||
ToastAndroid.show("No image selected", ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -428,7 +428,7 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
|
||||
}
|
||||
|
||||
if (!selectedImage.uri) {
|
||||
Alert.alert("Error", "Invalid image file");
|
||||
ToastAndroid.show("Invalid image file", ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
setSelectedImage(selectedImage.uri);
|
||||
@@ -440,14 +440,14 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
|
||||
try {
|
||||
const credentials = await Keychain.getGenericPassword();
|
||||
if (!credentials) {
|
||||
Alert.alert("Error", "You are not logged in");
|
||||
ToastAndroid.show('You are not logged in', ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
const token = credentials.password;
|
||||
|
||||
|
||||
if (!selectedImage) {
|
||||
Alert.alert("Error", "Please select an image first");
|
||||
ToastAndroid.show("Please select an image first", ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
TouchableOpacity,
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
ToastAndroid,
|
||||
} from "react-native";
|
||||
import { useNavigation, useFocusEffect, useRoute, RouteProp } from "@react-navigation/native";
|
||||
import { StackNavigationProp } from "@react-navigation/stack";
|
||||
@@ -103,13 +104,14 @@ const ManagementScreen: FC = () => {
|
||||
// No need to set loading here if the whole screen is already loading
|
||||
const res = await apiCall(url, "PUT", {}) as ApiResponse<null> | null;
|
||||
if (res && res.statusCode === 200) {
|
||||
Alert.alert("Success", res.message || successMessage);
|
||||
ToastAndroid.show("Success", ToastAndroid.SHORT);
|
||||
fetchData(); // Refresh data after action
|
||||
} else {
|
||||
throw new Error(res?.message || failureMessage);
|
||||
}
|
||||
} catch (err: any) {
|
||||
// Alert.alert("Error", err.message || "An unexpected error occurred.");
|
||||
console.error("Action Error:", err);
|
||||
ToastAndroid.show(err.message || failureMessage, ToastAndroid.SHORT);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { View, Text, StyleSheet, ActivityIndicator, ScrollView, RefreshControl, Alert, TouchableOpacity, Modal, TextInput } from 'react-native';
|
||||
import { View, Text, StyleSheet, ActivityIndicator, ScrollView, RefreshControl, Alert, TouchableOpacity, Modal, TextInput, ToastAndroid } from 'react-native';
|
||||
import { useRoute, RouteProp } from '@react-navigation/native';
|
||||
import { Ionicons } from "@react-native-vector-icons/ionicons";
|
||||
import colors from '../../components/colors';
|
||||
@@ -121,12 +121,12 @@ const Payments: React.FC = () => {
|
||||
const amountToWaive = parseFloat(waiverAmount);
|
||||
|
||||
if (isNaN(amountToWaive) || amountToWaive < 0) {
|
||||
Alert.alert("Invalid Input", "Please enter a valid waiver amount.");
|
||||
ToastAndroid.show("Please enter a valid waiver amount.", ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (amountToWaive > currentParticipant.lateFee) {
|
||||
Alert.alert("Invalid Amount", `Waiver cannot exceed the current late fee of ₹${currentParticipant.lateFee}.`);
|
||||
ToastAndroid.show(`Waiver cannot exceed the current late fee of ₹${currentParticipant.lateFee}.`, ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -135,14 +135,15 @@ const Payments: React.FC = () => {
|
||||
const response = await apiCall(url, 'PUT', {}) as any;
|
||||
|
||||
if (response && response.statusCode === 200) {
|
||||
Alert.alert("Success", `₹${amountToWaive} has been waived successfully.`);
|
||||
ToastAndroid.show(`₹${amountToWaive} has been waived successfully.`, ToastAndroid.SHORT);
|
||||
setModalVisible(false);
|
||||
onRefresh();
|
||||
} else {
|
||||
throw new Error(response?.message || "Failed to apply waiver.");
|
||||
}
|
||||
} catch (error: any) {
|
||||
Alert.alert("API Error", error.message);
|
||||
ToastAndroid.show(error.message || "Failed to apply waiver.", ToastAndroid.SHORT);
|
||||
console.error("Waive Fee Error:", error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { View, Text, StyleSheet, TouchableOpacity, FlatList, Dimensions, Alert, ActivityIndicator, Animated, Button } from 'react-native';
|
||||
import { View, Text, StyleSheet, TouchableOpacity, FlatList, Dimensions, Alert, ActivityIndicator, Animated, Button, ToastAndroid } from 'react-native';
|
||||
import { apiCall } from '../../utils/ApiHelper';
|
||||
import { Ionicons } from "@react-native-vector-icons/ionicons";
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
@@ -44,10 +44,10 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
|
||||
|
||||
setUsers(formattedUsers);
|
||||
} else {
|
||||
Alert.alert('Error', 'Failed to fetch participants.');
|
||||
ToastAndroid.show('Failed to fetch participants.', ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error) {
|
||||
Alert.alert('Error', 'Could not connect to the server to fetch participants.');
|
||||
ToastAndroid.show('Could not connect to the server to fetch participants.', ToastAndroid.SHORT);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
@@ -94,7 +94,7 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
|
||||
const availableUsers = users.filter(u => !u.selected);
|
||||
|
||||
if (availableUsers.length === 0 || isAnimating) {
|
||||
Alert.alert('Info', 'All users are already selected.');
|
||||
ToastAndroid.show('All users are already selected.', ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -134,14 +134,14 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
|
||||
setWinner(winnerData);
|
||||
setHighlightedIndex(winnerIndex);
|
||||
} else {
|
||||
Alert.alert('Error', 'Winner not found among participants.');
|
||||
ToastAndroid.show('Winner not found among participants.', ToastAndroid.SHORT);
|
||||
}
|
||||
} else {
|
||||
Alert.alert('Error', 'Failed to determine a winner from the API.');
|
||||
ToastAndroid.show('Failed to determine a winner from the API.', ToastAndroid.SHORT);
|
||||
}
|
||||
navigation.replace('EditGroup', { groupId })
|
||||
} catch (error) {
|
||||
// Alert.alert('Error', 'Could not connect to the server to fetch the winner.');
|
||||
ToastAndroid.show('Could not connect to the server to fetch the winner.', ToastAndroid.SHORT);
|
||||
} finally {
|
||||
setIsAnimating(false);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
NativeModules,
|
||||
Linking,
|
||||
Alert,
|
||||
ToastAndroid,
|
||||
} from "react-native";
|
||||
import AppView from "../../components/AppView";
|
||||
import colors from "../../components/colors";
|
||||
@@ -83,7 +84,7 @@ const YourContacts = () => {
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Error sending to WhatsApp:", err);
|
||||
Alert.alert("Error", "Something went wrong while trying to open WhatsApp");
|
||||
ToastAndroid.show("Something went wrong while trying to open WhatsApp", ToastAndroid.SHORT);
|
||||
}
|
||||
|
||||
setModalVisible(false);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
// import React from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
@@ -19,6 +19,7 @@ import AppView from '../../components/AppView';
|
||||
import Header from '../../components/common/Header';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { useNotificationHandler } from '../hook/useNotificationHandler';
|
||||
import colors from '../../components/colors';
|
||||
|
||||
type FilterType = 'all' | 'JOIN_REQUEST' | 'CONTRIBUTION' | 'CONTRIBUTION_ACK' |
|
||||
'CYCLE_COMPLETED' | 'WITHDRAWAL' | 'WITHDRAWAL_NOTIFY' |
|
||||
@@ -145,31 +146,31 @@ const Notification = () => {
|
||||
const getNotificationColor = (msgType: string) => {
|
||||
switch (msgType) {
|
||||
case 'JOIN_REQUEST':
|
||||
return '#FF6B35'; // Orange
|
||||
return '#FFB6C1'; // Pastel Pink
|
||||
case 'CONTRIBUTION':
|
||||
return '#4CAF50'; // Green
|
||||
return '#98FB98'; // Pastel Green
|
||||
case 'CONTRIBUTION_ACK':
|
||||
return '#2196F3'; // Blue
|
||||
return '#ADD8E6'; // Pastel Blue
|
||||
case 'CYCLE_COMPLETED':
|
||||
return '#9C27B0'; // Purple
|
||||
return '#D8BFD8'; // Pastel Purple
|
||||
case 'WITHDRAWAL':
|
||||
return '#FF9800'; // Amber
|
||||
return '#FFD700'; // Pastel Yellow
|
||||
case 'WITHDRAWAL_NOTIFY':
|
||||
return '#F44336'; // Red
|
||||
return '#FFA07A'; // Pastel Orange
|
||||
case 'CYCLE_WAIVER':
|
||||
return '#607D8B'; // Blue Grey
|
||||
return '#B0C4DE'; // Pastel Steel Blue
|
||||
case 'WAIVER_RECEIVED':
|
||||
return '#009688'; // Teal
|
||||
return '#AFEEEE'; // Pastel Turquoise
|
||||
case 'USER_SELECTED':
|
||||
return '#673AB7'; // Deep Purple
|
||||
return '#DDA0DD'; // Pastel Plum
|
||||
case 'GROUP_STARTED':
|
||||
return '#00BCD4'; // Cyan
|
||||
return '#87CEFA'; // Pastel Sky Blue
|
||||
case 'JOIN_APPROVED':
|
||||
return '#4CAF50'; // Green
|
||||
return '#98FB98'; // Pastel Green
|
||||
case 'JOIN_VIA_INVITE':
|
||||
return '#FFC107'; // Yellow
|
||||
return '#FFFACD'; // Pastel Lemon
|
||||
default:
|
||||
return '#757575'; // Grey
|
||||
return '#D3D3D3'; // Pastel Gray
|
||||
}
|
||||
};
|
||||
|
||||
@@ -210,11 +211,11 @@ const Notification = () => {
|
||||
<AppView>
|
||||
{/* Header with actions */}
|
||||
<Header
|
||||
title={`Notifications ${unreadCount > 0 ? `(${unreadCount})` : ''}`} />
|
||||
title={`Notifications ${unreadCount > 0 ? `(${unreadCount})` : ''}`} arrowColor='#000' titleColor='#000'/>
|
||||
<View style={styles.headerActions}>
|
||||
{unreadCount > 0 && (
|
||||
<LinearGradient
|
||||
colors={['#4CAF50', '#45a049']}
|
||||
colors={[colors.primary, colors.pastelPink]} // Pastel Green gradient
|
||||
style={[styles.headerButton, styles.markReadButton]}>
|
||||
<TouchableOpacity onPress={handleMarkAllAsRead}>
|
||||
<Text style={styles.headerButtonText}>Mark All Read</Text>
|
||||
@@ -223,7 +224,7 @@ const Notification = () => {
|
||||
)}
|
||||
{notifications.length > 0 && (
|
||||
<LinearGradient
|
||||
colors={['#FF6B6B', '#FF8E53']}
|
||||
colors={[colors.pastelPink, colors.pastelBlue]} // Pastel Pink to Pastel Orange gradient
|
||||
style={styles.headerButton}>
|
||||
<TouchableOpacity onPress={handleClearAll}>
|
||||
<Text style={styles.headerButtonText}>Clear All</Text>
|
||||
@@ -246,10 +247,11 @@ const Notification = () => {
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={item.read ? ['#f8f9fa', '#e9ecef'] : ['#ffffff', '#f8f9fa']}
|
||||
colors={item.read ? ['#F5F5F5', '#E8E8E8'] : ['#FFFFFF', '#F8F8FF']} // Pastel grays and whites
|
||||
style={[
|
||||
styles.notificationCard,
|
||||
!item.read && styles.unreadNotification, { borderLeftColor: getNotificationColor(item.data.msgType) }
|
||||
!item.read && styles.unreadNotification,
|
||||
{ borderLeftColor: getNotificationColor(item.data.msgType) }
|
||||
]}>
|
||||
<View style={styles.notificationContent}>
|
||||
{/* Icon */}
|
||||
@@ -285,7 +287,6 @@ const Notification = () => {
|
||||
styles.tag,
|
||||
{ backgroundColor: getNotificationColor(item.data.msgType) }
|
||||
]}>
|
||||
{/* {item.data.msgType} */}
|
||||
{getFilterDisplayName(item.data.msgType as FilterType)}
|
||||
</Text>
|
||||
</View>
|
||||
@@ -301,7 +302,7 @@ const Notification = () => {
|
||||
onPress={() => handleDelete(item.messageId)}
|
||||
style={styles.deleteButton}
|
||||
>
|
||||
<Ionicons name="trash-outline" size={20} color="#e63946" />
|
||||
<Ionicons name="trash-outline" size={20} color={colors.pastelPink} /> {/* Pastel Pink */}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
@@ -311,7 +312,7 @@ const Notification = () => {
|
||||
}}
|
||||
ListEmptyComponent={
|
||||
<View style={styles.emptyContainer}>
|
||||
<Ionicons name="notifications-off-outline" size={64} color="#ccc" />
|
||||
<Ionicons name="notifications-off-outline" size={64} color="#D3D3D3" /> {/* Pastel Gray */}
|
||||
<Text style={styles.emptyText}>No notifications yet</Text>
|
||||
<Text style={styles.emptySubtext}>
|
||||
When you get notifications, they'll appear here
|
||||
@@ -344,7 +345,7 @@ const styles = StyleSheet.create({
|
||||
minWidth: 100,
|
||||
},
|
||||
headerButtonText: {
|
||||
color: '#fff',
|
||||
color: '#FFFFFF', // White text for better contrast on pastel backgrounds
|
||||
fontWeight: '600',
|
||||
fontSize: 12,
|
||||
},
|
||||
@@ -358,15 +359,14 @@ const styles = StyleSheet.create({
|
||||
padding: 16,
|
||||
marginBottom: 10,
|
||||
shadowColor: '#000',
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 5,
|
||||
elevation: 3,
|
||||
shadowOpacity: 0.05, // Reduced opacity for softer shadow
|
||||
shadowRadius: 4,
|
||||
elevation: 2,
|
||||
borderLeftWidth: 4,
|
||||
borderLeftColor: 'transparent',
|
||||
},
|
||||
unreadNotification: {
|
||||
// borderLeftColor: colors.primary,
|
||||
backgroundColor: '#fff',
|
||||
backgroundColor: '#F8F8FF', // Pastel Lavender
|
||||
},
|
||||
notificationContent: {
|
||||
flexDirection: 'row',
|
||||
@@ -389,22 +389,22 @@ const styles = StyleSheet.create({
|
||||
title: {
|
||||
fontWeight: '600',
|
||||
fontSize: 16,
|
||||
color: '#333',
|
||||
color: '#696969', // Dim Gray
|
||||
flex: 1,
|
||||
marginRight: 8,
|
||||
},
|
||||
unreadTitle: {
|
||||
fontWeight: '700',
|
||||
color: '#000',
|
||||
color: '#2F4F4F', // Dark Slate Gray
|
||||
},
|
||||
message: {
|
||||
fontSize: 14,
|
||||
color: '#666',
|
||||
color: '#808080', // Gray
|
||||
lineHeight: 20,
|
||||
},
|
||||
time: {
|
||||
fontSize: 12,
|
||||
color: '#999',
|
||||
color: '#A9A9A9', // Dark Gray
|
||||
fontWeight: '500',
|
||||
},
|
||||
tagContainer: {
|
||||
@@ -412,7 +412,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
tag: {
|
||||
fontSize: 10,
|
||||
color: '#fff',
|
||||
color: '#FFFFFF', // White text for better contrast
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 2,
|
||||
borderRadius: 4,
|
||||
@@ -428,7 +428,7 @@ const styles = StyleSheet.create({
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
backgroundColor: '#2196F3',
|
||||
backgroundColor: '#87CEEB', // Pastel Sky Blue
|
||||
},
|
||||
deleteButton: {
|
||||
padding: 4,
|
||||
@@ -442,13 +442,13 @@ const styles = StyleSheet.create({
|
||||
emptyText: {
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
color: '#666',
|
||||
color: '#A9A9A9', // Dark Gray
|
||||
marginTop: 16,
|
||||
marginBottom: 8,
|
||||
},
|
||||
emptySubtext: {
|
||||
fontSize: 14,
|
||||
color: '#999',
|
||||
color: '#C0C0C0', // Silver
|
||||
textAlign: 'center',
|
||||
lineHeight: 20,
|
||||
},
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
TouchableOpacity,
|
||||
ToastAndroid,
|
||||
} from "react-native";
|
||||
import * as Keychain from "react-native-keychain";
|
||||
import { CustomInput, CustomButton } from "../../components/common/Custom";
|
||||
@@ -27,7 +28,7 @@ const BecomeOrg = () => {
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!idName || !idNumber || !issueDate) {
|
||||
Alert.alert("Error", "Please fill all fields");
|
||||
ToastAndroid.show("Please fill all fields", ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -35,7 +36,7 @@ const BecomeOrg = () => {
|
||||
setLoading(true);
|
||||
const credentials = await Keychain.getGenericPassword();
|
||||
if (!credentials) {
|
||||
Alert.alert("Error", "You are not logged in. Please log in to continue.");
|
||||
ToastAndroid.show("You are not logged in. Please log in to continue.", ToastAndroid.SHORT);
|
||||
setLoading(false);
|
||||
// Optionally navigate to login screen
|
||||
// navigation.navigate("Login");
|
||||
@@ -62,17 +63,17 @@ const BecomeOrg = () => {
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result.status === "success") {
|
||||
Alert.alert("Success", "Organizer registration application submitted successfully!");
|
||||
ToastAndroid.show("Organizer registration application submitted successfully!", ToastAndroid.SHORT);
|
||||
setIdName("");
|
||||
setIdNumber("");
|
||||
setIssueDate("");
|
||||
navigation.navigate("Home" as never);
|
||||
} else {
|
||||
Alert.alert("Error", result.message || "Failed to submit application");
|
||||
ToastAndroid.show(result.message || "Failed to submit application", ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("❌ Registration error:", error);
|
||||
// Alert.alert("Error", "An unexpected error occurred. Please try again.");
|
||||
ToastAndroid.show("An unexpected error occurred. Please try again.", ToastAndroid.SHORT);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
Alert,
|
||||
ActivityIndicator,
|
||||
TouchableOpacity,
|
||||
ToastAndroid,
|
||||
} from "react-native";
|
||||
import { useNavigation, useRoute } from "@react-navigation/native";
|
||||
import { CustomButton, CustomInput } from "../../components/common/Custom";
|
||||
@@ -39,7 +40,7 @@ const EditBankDetails = () => {
|
||||
// The update function remains the same, using the local state
|
||||
const handleUpdateBankDetails = async () => {
|
||||
if (!bankName || !bankAccountNumber || !branchCode) {
|
||||
Alert.alert("Validation Error", "Please fill in all bank details.");
|
||||
ToastAndroid.show("Please fill in all bank details.", ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -52,14 +53,14 @@ const EditBankDetails = () => {
|
||||
}) as { status: string; message?: string };
|
||||
console.log("Update Bank Response:", response);
|
||||
if (response.status === "success") {
|
||||
Alert.alert("Success", response.message || "Bank details updated successfully!");
|
||||
ToastAndroid.show(response.message || "Bank details updated successfully!", ToastAndroid.SHORT);
|
||||
navigation.goBack();
|
||||
} else {
|
||||
Alert.alert("Update Failed", response.message || "Could not update bank details.");
|
||||
ToastAndroid.show(response.message || "Could not update bank details.", ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error("Error updating bank details:", error);
|
||||
// Alert.alert("Error", error.message || "An unexpected error occurred. Please try again.");
|
||||
ToastAndroid.show(error.message || "An unexpected error occurred. Please try again.", ToastAndroid.SHORT);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
RefreshControl,
|
||||
ToastAndroid,
|
||||
} from "react-native";
|
||||
import * as Keychain from "react-native-keychain";
|
||||
import { Ionicons } from "@react-native-vector-icons/ionicons";
|
||||
@@ -69,7 +70,7 @@ const Profile = () => {
|
||||
try {
|
||||
const credentials = await Keychain.getGenericPassword();
|
||||
if (!credentials) {
|
||||
Alert.alert("Error", "You are not logged in");
|
||||
ToastAndroid.show('You are not logged in', ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
const token = credentials.password;
|
||||
@@ -114,11 +115,10 @@ const Profile = () => {
|
||||
profileStatus: true, // set true once profile is fetched
|
||||
}));
|
||||
} else {
|
||||
Alert.alert("Error", "Failed to fetch user profile");
|
||||
ToastAndroid.show("Failed to fetch user profile", ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("❌ Error fetching profile:", error);
|
||||
// Alert.alert("Error", "Could not connect to server");
|
||||
} finally {
|
||||
setFetching(false);
|
||||
}
|
||||
@@ -129,7 +129,7 @@ const Profile = () => {
|
||||
try {
|
||||
const credentials = await Keychain.getGenericPassword();
|
||||
if (!credentials) {
|
||||
Alert.alert("Error", "You are not logged in");
|
||||
ToastAndroid.show('You are not logged in', ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
const token = credentials.password;
|
||||
@@ -157,20 +157,16 @@ const Profile = () => {
|
||||
|
||||
|
||||
const result = await response.json();
|
||||
console.log("result for profile update :", result);
|
||||
// Alert.alert("Success", "Profile updated successfully");
|
||||
// setEditing(false);
|
||||
// fetchUserProfile();
|
||||
if (result.status === "success") {
|
||||
Alert.alert("Success", "Profile updated successfully");
|
||||
ToastAndroid.show("Profile updated successfully", ToastAndroid.SHORT);
|
||||
setEditing(false);
|
||||
fetchUserProfile(); // reload updated data
|
||||
} else {
|
||||
Alert.alert("Error", "Failed to update profile");
|
||||
ToastAndroid.show("Failed to update profile", ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("❌ Error updating profile:", error);
|
||||
// Alert.alert("Error", "Could not update profile");
|
||||
ToastAndroid.show("Could not update profile", ToastAndroid.SHORT);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -179,7 +175,7 @@ const Profile = () => {
|
||||
launchImageLibrary({ mediaType: "photo", quality: 0.5 }, (response) => {
|
||||
if (response.didCancel) return;
|
||||
if (response.errorCode) {
|
||||
Alert.alert("Error", response.errorMessage || "Something went wrong");
|
||||
ToastAndroid.show(response.errorMessage || "Something went wrong", ToastAndroid.SHORT);
|
||||
} else if (response.assets && response.assets.length > 0) {
|
||||
const selectedImage = response.assets[0];
|
||||
setUser((prev: any) =>
|
||||
@@ -194,14 +190,14 @@ const Profile = () => {
|
||||
try {
|
||||
const credentials = await Keychain.getGenericPassword();
|
||||
if (!credentials) {
|
||||
Alert.alert("Error", "You are not logged in");
|
||||
ToastAndroid.show('You are not logged in', ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
const token = credentials.password;
|
||||
|
||||
|
||||
if (!user?.filePath) {
|
||||
Alert.alert("Error", "Please select an image first");
|
||||
ToastAndroid.show("Please select an image first", ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -232,8 +228,7 @@ const Profile = () => {
|
||||
|
||||
const result = await response.json();
|
||||
if (result.status === "success") {
|
||||
Alert.alert("Success", "Profile image updated successfully");
|
||||
|
||||
ToastAndroid.show("Profile image updated successfully", ToastAndroid.SHORT);
|
||||
|
||||
// If API returns updated image, set it
|
||||
if (result.data?.imageBlob) {
|
||||
@@ -247,11 +242,11 @@ const Profile = () => {
|
||||
// Refresh profile from API as well
|
||||
fetchUserProfile();
|
||||
} else {
|
||||
Alert.alert("Error", result.message || "Failed to update profile image");
|
||||
ToastAndroid.show(result.message || "Failed to update profile image", ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("❌ Error updating profile image:", error);
|
||||
// Alert.alert("Error", "Could not update profile image");
|
||||
ToastAndroid.show("Could not update profile image", ToastAndroid.SHORT);
|
||||
} finally {
|
||||
setImageUpdating(false);
|
||||
}
|
||||
@@ -262,7 +257,7 @@ const Profile = () => {
|
||||
try {
|
||||
const credentials = await Keychain.getGenericPassword();
|
||||
if (!credentials) {
|
||||
Alert.alert("Error", "You are not logged in");
|
||||
ToastAndroid.show('You are not logged in', ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
const token = credentials.password;
|
||||
@@ -305,7 +300,7 @@ const Profile = () => {
|
||||
|
||||
|
||||
if (!credentials) {
|
||||
Alert.alert("Info", "No user is currently logged in");
|
||||
ToastAndroid.show('No user is currently logged in', ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -314,11 +309,10 @@ const Profile = () => {
|
||||
// Clear stored credentials
|
||||
await Keychain.resetGenericPassword();
|
||||
dispatch(clearUser())
|
||||
Alert.alert("Success", "You have been logged out");
|
||||
ToastAndroid.show("You have been logged out", ToastAndroid.SHORT);
|
||||
navigation.replace("Login");
|
||||
} catch (error) {
|
||||
console.error("Logout error:", error);
|
||||
// Alert.alert("Error", "Failed to log out. Please try again.");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@ import { useDispatch } from "react-redux";
|
||||
import { BASE_URL } from "./ApiUrls";
|
||||
import * as Keychain from "react-native-keychain";
|
||||
import { setUserData } from "../redux/userSlice";
|
||||
import { Alert } from "react-native";
|
||||
import { Alert, ToastAndroid } from "react-native";
|
||||
|
||||
export const fetchUserProfile = async () => {
|
||||
const dispatch = useDispatch();
|
||||
try {
|
||||
const credentials = await Keychain.getGenericPassword();
|
||||
if (!credentials) {
|
||||
// Alert.alert("Error", "You are not logged in");
|
||||
// ToastAndroid.show('You are not logged in', ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
const token = credentials.password;
|
||||
@@ -52,11 +52,11 @@ export const fetchUserProfile = async () => {
|
||||
|
||||
console.log("splash user data:", result.data);
|
||||
} else {
|
||||
Alert.alert("Error", "Failed to fetch user profile");
|
||||
ToastAndroid.show(result.message || "Failed to fetch user profile", ToastAndroid.SHORT);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("❌ Error fetching profile:", error);
|
||||
// Alert.alert("Error", "Could not connect to server");
|
||||
ToastAndroid.show("Could not connect to server", ToastAndroid.SHORT);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user