demo ready

This commit is contained in:
Abin Toppo
2025-10-14 10:42:29 +05:30
13 changed files with 192 additions and 128 deletions
+4 -2
View File
@@ -46,12 +46,14 @@ export type RootStackParamList = {
TransactionList: undefined TransactionList: undefined
RandomSelectUserScreen: { groupId: string | number, cycleNumber: number }; RandomSelectUserScreen: { groupId: string | number, cycleNumber: number };
Notification: undefined; Notification: undefined;
NotificationRedirection:{ data: any }; NotificationRedirection: { data: any };
Management: Management:
| { actionTab: "My Groups" } | { actionTab: "My Groups" }
| { actionTab1: "Joined Groups" } | { actionTab1: "Joined Groups" }
| { actionTab2: "Requests" } | { actionTab2: "Requests" }
| { actionTab3: "Your Requests" }; | { actionTab3: "Your Requests" }
| { groupId: string | number; }
}; };
const Stack = createNativeStackNavigator<RootStackParamList>(); const Stack = createNativeStackNavigator<RootStackParamList>();
+1
View File
@@ -32,6 +32,7 @@ export type RootStackParamList = {
ManageJoinedGroup: { groupId: string | number }; ManageJoinedGroup: { groupId: string | number };
Invite: { groupId: string | number; code: string | number }; Invite: { groupId: string | number; code: string | number };
ManagementTabs:any ManagementTabs:any
NotificationRedirection: { data: any };
}; };
+3 -2
View File
@@ -9,6 +9,7 @@ import {
TouchableOpacity, TouchableOpacity,
Alert, Alert,
Image, Image,
ToastAndroid,
} from "react-native"; } from "react-native";
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import { CustomInput } from "../components/common/Custom"; import { CustomInput } from "../components/common/Custom";
@@ -75,8 +76,8 @@ export default function GroupCreationForm() {
console.log("Reviewing Payload:", payload); console.log("Reviewing Payload:", payload);
navigation.navigate("GroupReview", { form: payload }); navigation.navigate("GroupReview", { form: payload });
} else { } else {
Alert.alert("Incomplete Form", "Please fill out all required fields correctly."); ToastAndroid.show('Please fill out all required fields correctly.', ToastAndroid.SHORT);
setErrors('') setErrors('');
} }
}; };
+3 -3
View File
@@ -12,6 +12,7 @@ import {
ScrollView, ScrollView,
Alert, Alert,
RefreshControl, RefreshControl,
ToastAndroid,
} from "react-native"; } from "react-native";
import { FAB } from "react-native-paper"; import { FAB } from "react-native-paper";
import { Ionicons } from "@react-native-vector-icons/ionicons"; import { Ionicons } from "@react-native-vector-icons/ionicons";
@@ -176,13 +177,12 @@ export default function GroupScreen() {
console.log("JOIN_GROUP_URL response:", res); console.log("JOIN_GROUP_URL response:", res);
if (res.statusCode === 200) { if (res.statusCode === 200) {
Alert.alert("Success", "You requested to join the group."); ToastAndroid.show('You requested to join the group.', ToastAndroid.SHORT);
} else { } else {
// Alert.alert("Error", res.message || "Failed to join group."); ToastAndroid.show(res.message || "Failed to join group.", ToastAndroid.SHORT);
} }
} catch (error) { } catch (error) {
console.error("Join Group Error:", error); console.error("Join Group Error:", error);
// Alert.alert("Error", "An unexpected error occurred.");
} }
}; };
+1 -5
View File
@@ -18,14 +18,11 @@ const NotificationRedirection: React.FC = () => {
// This effect runs once when the component mounts // This effect runs once when the component mounts
if (data) { if (data) {
console.log('🔄 Processing notification data:', data); console.log('🔄 Processing notification data:', data);
// --- Your Redirection Logic Goes Here --- // --- Your Redirection Logic Goes Here ---
// Use the 'data' object to decide where to go. // Use the 'data' object to decide where to go.
// For this example, we'll navigate based on 'msgType'. // For this example, we'll navigate based on 'msgType'.
let destination: keyof RootStackParamList = 'Home'; // Default destination let destination: keyof RootStackParamList = 'Home'; // Default destination
let params: object | undefined = undefined; let params: object | undefined = undefined;
switch (data.msgType) { switch (data.msgType) {
case 'JOIN_REQUEST': case 'JOIN_REQUEST':
destination = 'Home'; destination = 'Home';
@@ -62,10 +59,9 @@ const NotificationRedirection: React.FC = () => {
// Keep the default destination as 'Home' // Keep the default destination as 'Home'
break; break;
} }
console.log(`➡ Redirecting to ${destination} with params:`, params);
// Use replace to prevent the user from navigating back to this loading screen // Use replace to prevent the user from navigating back to this loading screen
navigation.replace(destination, params); navigation.replace(destination, params);
} else { } else {
// If no data is passed for some reason, just go to the home screen // If no data is passed for some reason, just go to the home screen
console.warn('⚠ No data found in notification, redirecting to Home.'); console.warn('⚠ No data found in notification, redirecting to Home.');
+2
View File
@@ -59,6 +59,7 @@ const userActions: ActionItem[] = [
{ id: "1", title: "Joined Groups", subtitle: "See your groups", action: "NAVIGATE_MANAGEMENT", tab: "Joined Groups", iconName: "person-outline", backOne: '#D7E9F7', backTwo: '#82AAE3' }, { id: "1", title: "Joined Groups", subtitle: "See your groups", action: "NAVIGATE_MANAGEMENT", tab: "Joined Groups", iconName: "person-outline", backOne: '#D7E9F7', backTwo: '#82AAE3' },
{ id: "2", title: "Your Requests", subtitle: "Track your requests", action: "NAVIGATE_MANAGEMENT", tab: "Your Requests", iconName: "mail-open-outline", backOne: '#FFF4D2', backTwo: '#FFB344' }, { id: "2", title: "Your Requests", subtitle: "Track your requests", action: "NAVIGATE_MANAGEMENT", tab: "Your Requests", iconName: "mail-open-outline", backOne: '#FFF4D2', backTwo: '#FFB344' },
{ id: "3", title: "Transactions", subtitle: "View your history", action: "TRANSACTION", iconName: "receipt-outline", backOne: '#decbfcff', backTwo: '#B799FF' }, { id: "3", title: "Transactions", subtitle: "View your history", action: "TRANSACTION", iconName: "receipt-outline", backOne: '#decbfcff', backTwo: '#B799FF' },
{ id: "4", title: "Create Group", subtitle: "Create a new group", action: "NAVIGATE_CREATE_GROUP", tab: "Requests", iconName: "people-outline", backOne: '#DFF6DD', backTwo: '#88D18A' },
]; ];
const Home: React.FC = () => { const Home: React.FC = () => {
@@ -95,6 +96,7 @@ const Home: React.FC = () => {
} else if (item.action === "TRANSACTION") { } else if (item.action === "TRANSACTION") {
navigation.navigate("TransactionList" as never); navigation.navigate("TransactionList" as never);
} else if (item.action === "NAVIGATE_CREATE_GROUP") { } else if (item.action === "NAVIGATE_CREATE_GROUP") {
navigation.navigate("GroupCreation" as never); navigation.navigate("GroupCreation" as never);
} else { } else {
Alert.alert("Unknown action", item.title); Alert.alert("Unknown action", item.title);
+88 -23
View File
@@ -12,16 +12,19 @@ import {
import { useRoute } from "@react-navigation/native"; import { useRoute } from "@react-navigation/native";
import AppView from "../../../components/AppView"; import AppView from "../../../components/AppView";
import colors from "../../../components/colors"; import colors from "../../../components/colors";
import { Ionicons } from "@react-native-vector-icons/ionicons"; import Ionicons from '@react-native-vector-icons/ionicons';
import Header from "../../../components/common/Header"; import Header from "../../../components/common/Header";
import { apiCall } from "../../../utils/ApiHelper"; import { apiCall } from "../../../utils/ApiHelper";
import { BASE_URL, CONTRIBUTE, GROUP_ALL_MEMBER } from "../../../utils/ApiUrls"; import { BASE_URL, CONTRIBUTE, GROUP_ALL_MEMBER } from "../../../utils/ApiUrls";
import ContributionScreen from "../../ContributionScreen"; import ContributionScreen from "../../ContributionScreen";
import CycleDashboard from "./CycleDashboard"; import CycleDashboard from "./CycleDashboard";
const CustomDropdown = ({ items, selectedValue, onValueChange, placeholder = "Select an item" }:any) => {
const CustomDropdown = ({ items, selectedValue, onValueChange, placeholder = "Select an item" }: any) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const selectedLabel = items.find((item:any) => item.value === selectedValue)?.label || placeholder; const selectedLabel = items.find((item: any) => item.value === selectedValue)?.label || placeholder;
return ( return (
<View style={styles.dropdownWrapper}> <View style={styles.dropdownWrapper}>
@@ -30,6 +33,7 @@ const CustomDropdown = ({ items, selectedValue, onValueChange, placeholder = "Se
<Ionicons name='chevron-down' size={22} color={colors.black} /> <Ionicons name='chevron-down' size={22} color={colors.black} />
</TouchableOpacity> </TouchableOpacity>
<Modal <Modal
transparent transparent
animationType="fade" animationType="fade"
@@ -39,7 +43,7 @@ const CustomDropdown = ({ items, selectedValue, onValueChange, placeholder = "Se
<TouchableOpacity style={styles.modalOverlay} onPress={() => setOpen(false)}> <TouchableOpacity style={styles.modalOverlay} onPress={() => setOpen(false)}>
<View style={styles.dropdownListContainer}> <View style={styles.dropdownListContainer}>
<ScrollView> <ScrollView>
{items.map(item => ( {items.map((item: any) => (
<TouchableOpacity <TouchableOpacity
key={item.value} key={item.value}
onPress={() => { onPress={() => {
@@ -62,8 +66,12 @@ const CustomDropdown = ({ items, selectedValue, onValueChange, placeholder = "Se
); );
}; };
const GroupDetails = () => { const GroupDetails = () => {
const route = useRoute<any>(); const route = useRoute<any>();
console.log(" route id : ", route)
const [memberData, setMemberData] = useState([]); const [memberData, setMemberData] = useState([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [openModal, setOpenModal] = useState(false); const [openModal, setOpenModal] = useState(false);
@@ -72,6 +80,8 @@ const GroupDetails = () => {
const [cycleDashboardData, setCycleDashboardData] = useState<any>(); const [cycleDashboardData, setCycleDashboardData] = useState<any>();
const [selectedCycleNumber, setSelectedCycleNumber] = useState(null); const [selectedCycleNumber, setSelectedCycleNumber] = useState(null);
const [cycleItems, setCycleItems] = useState([]); const [cycleItems, setCycleItems] = useState([]);
const [selectedUser, setSelectedUser] = useState() as any
const group = { const group = {
id: route.params.item?.id, id: route.params.item?.id,
@@ -83,15 +93,26 @@ const GroupDetails = () => {
members: memberData, members: memberData,
}; };
const getPaymentStatus = async () => {
const response = await apiCall(`${BASE_URL}payments/group/${group.id || route?.params?.groupId}/payment/paid`, 'GET') as { status: string; data?: { currentCycle: number, allPaid: boolean, selectedUser: any }; message?: string };
console.log("paymentStatus", response.data?.selectedUser)
if (response.status === 'success') {
setSelectedUser(response.data?.selectedUser);
}
}
const getCycleDashboard = async () => { const getCycleDashboard = async () => {
try { try {
const response = await apiCall(`${BASE_URL}payments/groups/${group.id}/cycle-dashboard`, "GET") as any; const response = await apiCall(`${BASE_URL}payments/groups/${group.id || route?.params?.groupId}/cycle-dashboard`, "GET") as any;
console.log("Cycle Dashboard Response: ", response);
const responseData = response.data; const responseData = response.data;
setCycleDashboardData(responseData); setCycleDashboardData(responseData);
console.log("cycledata", responseData)
if (responseData?.cycles) { if (responseData?.cycles) {
const items = responseData.cycles.map(cycle => ({ const items = responseData.cycles.map((cycle: any) => ({
label: `Cycle ${cycle.cycleNumber}`, label: `Cycle ${cycle.cycleNumber}`,
value: cycle.cycleNumber value: cycle.cycleNumber
})); }));
@@ -105,9 +126,10 @@ const GroupDetails = () => {
} }
}; };
const fetchGroupDetails = async () => { const fetchGroupDetails = async () => {
try { try {
const res = await apiCall(`${GROUP_ALL_MEMBER}?groupId=${group.id}`, "GET") as any; const res = await apiCall(`${GROUP_ALL_MEMBER}?groupId=${group.id || route?.params?.groupId}`, "GET") as any;
console.log("Group Members Response: ", res); console.log("Group Members Response: ", res);
setMemberData(res.data); setMemberData(res.data);
} catch (error: any) { } catch (error: any) {
@@ -115,16 +137,17 @@ const GroupDetails = () => {
} }
}; };
const handleContribution = async () => { const handleContribution = async () => {
try { try {
const res = await apiCall(`${CONTRIBUTE}${group.id}/calculate-contribution`, 'GET') as any; const res = await apiCall(`${CONTRIBUTE}${group.id || route?.params?.groupId}/calculate-contribution`, 'GET') as any;
console.log("Contribution Calculation Response: ", res);
setPayable(res.data); setPayable(res.data);
} catch (error) { } catch (error) {
console.log("Error in handleContribution: ", error); console.log("Error in handleContribution: ", error);
} }
}; };
const fetchAllData = useCallback(async () => { const fetchAllData = useCallback(async () => {
setLoading(true); setLoading(true);
await Promise.all([ await Promise.all([
@@ -133,24 +156,30 @@ const GroupDetails = () => {
getCycleDashboard() getCycleDashboard()
]); ]);
setLoading(false); setLoading(false);
}, [group.id]); }, [group.id || route?.params?.groupId]);
useEffect(() => { useEffect(() => {
if (group.id) { if (group.id || route?.params?.groupId) {
fetchAllData(); fetchAllData();
getPaymentStatus();
} }
}, [group.id, fetchAllData]); }, [group.id || route?.params?.groupId, fetchAllData]);
const onRefresh = useCallback(async () => { const onRefresh = useCallback(async () => {
setRefreshing(true); setRefreshing(true);
await fetchAllData(); await fetchAllData();
await getPaymentStatus();
setRefreshing(false); setRefreshing(false);
}, [fetchAllData]); }, [fetchAllData]);
const confirmPayment = async () => { const confirmPayment = async () => {
try { try {
const res = await apiCall(`${BASE_URL}payments/contribute/${group?.id}?amount=${payable?.totalPayable}`, 'POST') as any; const res = await apiCall(`${BASE_URL}payments/contribute/${group?.id}?amount=${payable?.totalPayable}`, 'POST') as any;
if (res.status === 200 || res.status === 201) { console.log('payment res ', res)
if (res.status === 200 || res.status === 201 || res.statusCode === 200) {
ToastAndroid.show('Payment done!', ToastAndroid.SHORT); ToastAndroid.show('Payment done!', ToastAndroid.SHORT);
onRefresh(); onRefresh();
} else { } else {
@@ -161,18 +190,28 @@ const GroupDetails = () => {
} }
}; };
const selectedCycleData = cycleDashboardData?.cycles.find(c => c.cycleNumber === selectedCycleNumber);
const selectedCycleData = cycleDashboardData?.cycles.find((c: any) => c.cycleNumber === selectedCycleNumber);
return ( return (
<AppView paddingHorizontal={0} style={{ flex: 1 }}> <AppView paddingHorizontal={0} style={{ flex: 1 }}>
{selectedUser?.firstName && (
<View style={styles.floatingWinnerContainer}>
<Text style={styles.floatingWinnerText}>
Winner: {`${selectedUser.firstName} ${selectedUser.lastName || ''}`}
</Text>
</View>
)}
<ScrollView <ScrollView
refreshControl={ refreshControl={
<RefreshControl refreshing={refreshing || loading} onRefresh={onRefresh} colors={[colors.black]} /> <RefreshControl refreshing={refreshing || loading} onRefresh={onRefresh} colors={[colors.black]} />
} }
contentContainerStyle={styles.scrollContent} contentContainerStyle={styles.scrollContent}
> >
<Header title={cycleDashboardData?.groupName || group?.name} /> <Header title={group.name || route.name} />
<Text style={styles.description}>{group.description}</Text> <Text style={styles.description}>{group.description || route.name}</Text>
<View style={styles.statsRow}> <View style={styles.statsRow}>
<View style={styles.statBox}> <View style={styles.statBox}>
@@ -180,15 +219,16 @@ const GroupDetails = () => {
<Text style={styles.statLabel}>Members</Text> <Text style={styles.statLabel}>Members</Text>
</View> </View>
<View style={styles.statBox}> <View style={styles.statBox}>
<Text style={styles.statValue}>₹{cycleDashboardData?.contributionAmount|| group.collected}</Text> <Text style={styles.statValue}>₹{cycleDashboardData?.contributionAmount || group.collected}</Text>
<Text style={styles.statLabel}>Contribution</Text> <Text style={styles.statLabel}>Contribution</Text>
</View> </View>
<View style={styles.statBox}> <View style={styles.statBox}>
<Text style={styles.statValue}>₹{cycleDashboardData?.contributionAmount*memberData.length|| group.goal}</Text> <Text style={styles.statValue}>₹{cycleDashboardData?.contributionAmount * memberData.length || group.goal}</Text>
<Text style={styles.statLabel}>Total Amount</Text> <Text style={styles.statLabel}>Total Amount</Text>
</View> </View>
</View> </View>
{cycleItems.length > 0 && ( {cycleItems.length > 0 && (
<CustomDropdown <CustomDropdown
items={cycleItems} items={cycleItems}
@@ -202,6 +242,7 @@ const GroupDetails = () => {
<CycleDashboard data={{ ...cycleDashboardData, cycles: [selectedCycleData] }} /> <CycleDashboard data={{ ...cycleDashboardData, cycles: [selectedCycleData] }} />
)} )}
<View style={styles.membersHeader}> <View style={styles.membersHeader}>
<Text style={styles.sectionTitle}>Members</Text> <Text style={styles.sectionTitle}>Members</Text>
<View style={styles.statusBadge}> <View style={styles.statusBadge}>
@@ -209,7 +250,8 @@ const GroupDetails = () => {
</View> </View>
</View> </View>
{memberData.map((member:any) => (
{memberData.map((member: any) => (
<View key={member.userId} style={styles.memberCard}> <View key={member.userId} style={styles.memberCard}>
<Ionicons name="person" size={40} color={colors.black} /> <Ionicons name="person" size={40} color={colors.black} />
<View style={styles.memberInfo}> <View style={styles.memberInfo}>
@@ -220,7 +262,7 @@ const GroupDetails = () => {
</View> </View>
))} ))}
{/* Button at the bottom inside scroll (no absolute positioning) */}
{cycleDashboardData?.status === 'ACTIVE' && !payable?.hasPaid && ( {cycleDashboardData?.status === 'ACTIVE' && !payable?.hasPaid && (
<TouchableOpacity onPress={() => setOpenModal(true)} style={styles.button}> <TouchableOpacity onPress={() => setOpenModal(true)} style={styles.button}>
<Text style={styles.buttonText}>Contribute</Text> <Text style={styles.buttonText}>Contribute</Text>
@@ -228,6 +270,7 @@ const GroupDetails = () => {
)} )}
</ScrollView> </ScrollView>
{openModal && ( {openModal && (
<ContributionScreen <ContributionScreen
data={payable} data={payable}
@@ -243,8 +286,10 @@ const GroupDetails = () => {
); );
}; };
export default GroupDetails; export default GroupDetails;
const styles = StyleSheet.create({ const styles = StyleSheet.create({
dropdownWrapper: { dropdownWrapper: {
marginHorizontal: 15, marginHorizontal: 15,
@@ -260,6 +305,10 @@ const styles = StyleSheet.create({
borderRadius: 8, borderRadius: 8,
backgroundColor: '#fff', backgroundColor: '#fff',
}, },
headerText: {
fontSize: 15,
color: colors.black,
},
modalOverlay: { modalOverlay: {
flex: 1, flex: 1,
justifyContent: 'center', justifyContent: 'center',
@@ -334,7 +383,7 @@ const styles = StyleSheet.create({
statusText: { statusText: {
fontSize: 14, fontSize: 14,
fontWeight: '600', fontWeight: '600',
color: colors.Home, color: colors.black,
}, },
memberCard: { memberCard: {
flexDirection: "row", flexDirection: "row",
@@ -372,4 +421,20 @@ const styles = StyleSheet.create({
scrollContent: { scrollContent: {
paddingBottom: 50, paddingBottom: 50,
}, },
floatingWinnerContainer: {
position: 'absolute',
bottom: 80,
alignSelf: 'center',
backgroundColor: colors.pastelBlue,
paddingHorizontal: 15,
paddingVertical: 8,
borderRadius: 20,
elevation: 5,
zIndex: 10,
},
floatingWinnerText: {
color: colors.black,
fontWeight: 'bold',
fontSize: 16,
},
}); });
@@ -216,6 +216,7 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
try { try {
const res = await apiCall(`${BASE_URL}fund/groups/${groupDetails.id}/edit`, 'PUT', editableData); const res = await apiCall(`${BASE_URL}fund/groups/${groupDetails.id}/edit`, 'PUT', editableData);
console.log("Edit Group Response: ", res,editableData) console.log("Edit Group Response: ", res,editableData)
Alert.alert('Success', 'Group has been updated.'); Alert.alert('Success', 'Group has been updated.');
setEditingCard(null); setEditingCard(null);
await fetchGroupDetails(); await fetchGroupDetails();
+4 -4
View File
@@ -63,7 +63,7 @@ const Payments: React.FC = () => {
// These are regular functions and do not call hooks inside them, which is correct. // These are regular functions and do not call hooks inside them, which is correct.
const getCycleData = async () => { const getCycleData = async () => {
try { try {
const response = await apiCall(`${API_BASE_URL}/groups/${groupId}/cycle-dashboard`, 'GET') as ApiResponse<any>; const response = await apiCall(`${BASE_URL}/payments/groups/${groupId}/cycle-dashboard`, 'GET') as ApiResponse<any>;
if (response && response.statusCode === 200) { if (response && response.statusCode === 200) {
setCycleData(response.data); setCycleData(response.data);
} }
@@ -131,7 +131,7 @@ const Payments: React.FC = () => {
} }
try { try {
const url = `${BASE_URL}groups/${groupId}/cycles/${paymentDetails.currentCycle}/waive/${currentParticipant.userId}?amountToWaive=${amountToWaive}`; const url = `https://api.godemo.in/FundCollect/api/payments/groups/${groupId}/cycles/${paymentDetails.currentCycle}/waive/${currentParticipant.userId}?amountToWaive=${amountToWaive}`;
const response = await apiCall(url, 'PUT', {}) as any; const response = await apiCall(url, 'PUT', {}) as any;
if (response && response.statusCode === 200) { if (response && response.statusCode === 200) {
@@ -247,8 +247,8 @@ const Payments: React.FC = () => {
<Text style={styles.summaryValue}>₹{paymentDetails.contributionAmount}</Text> <Text style={styles.summaryValue}>₹{paymentDetails.contributionAmount}</Text>
</View> </View>
<View style={styles.summaryBox}> <View style={styles.summaryBox}>
<Text style={styles.summaryLabel}>Total Due</Text> <Text style={styles.summaryLabel}>Total Amount</Text>
<Text style={[styles.summaryValue, { color: colors.danger }]}>₹{paymentDetails.totalDueWithLateFee}</Text> <Text style={[styles.summaryValue, { color: colors.black }]}>₹{paymentDetails.totalDueWithLateFee}</Text>
</View> </View>
</View> </View>
<Text style={styles.sectionTitle}>Participants</Text> <Text style={styles.sectionTitle}>Participants</Text>
+2
View File
@@ -4,6 +4,7 @@ import { Ionicons } from '@react-native-vector-icons/ionicons'
import CustomModal from '../../components/common/CustomModal' import CustomModal from '../../components/common/CustomModal'
import { apiCall } from '../../utils/ApiHelper' import { apiCall } from '../../utils/ApiHelper'
import { BASE_URL } from '../../utils/ApiUrls' import { BASE_URL } from '../../utils/ApiUrls'
import colors from '../../components/colors'
interface WinnerUserProps { interface WinnerUserProps {
data: { data: {
@@ -111,6 +112,7 @@ const WinnerUser: React.FC<WinnerUserProps> = ({ data, visible, onClose, groupId
onClose={onClose} onClose={onClose}
confirmText={canProceedToWithdrawal ? 'Proceed to Withdraw' : 'Close'} confirmText={canProceedToWithdrawal ? 'Proceed to Withdraw' : 'Close'}
onConfirm={canProceedToWithdrawal ? onConfirm : onClose} onConfirm={canProceedToWithdrawal ? onConfirm : onClose}
confirmButton={colors.pastelOrange}
> >
<View style={styles.container}> <View style={styles.container}>
<Animated.View style={{ transform: [{ scale: scaleAnim }] }}> <Animated.View style={{ transform: [{ scale: scaleAnim }] }}>
+11 -10
View File
@@ -44,22 +44,20 @@ const Notification = () => {
dispatch(clearAllNotifications()); dispatch(clearAllNotifications());
}; };
const handleMarkAsRead = (messageId: string, screen: string) => { const handleMarkAsRead = (messageId: string, screen: string, groupId: string, cycleNumber: string, contributionId: string) => {
console.log("screen type : ", screen); console.log("screen type : ", screen);
handleMarkAsReadAndNavigate( handleMarkAsReadAndNavigate(
messageId, messageId,
screen, screen,
{ {
// Pass additional parameters based on notification type groupId: groupId,
groupId: 'ebc27862-acde-4129-b12c-fd4c2966e858', cycleNumber,
cycleNumber: '1', contributionId,
contributionId: '12345', actionTab3: 'Your Requests',
actionTab3: 'Your Requests' ,
actionTab1: 'Joined Groups', actionTab1: 'Joined Groups',
GroupDetails: { GroupDetails: {
item: {} item: {}
}, },
// etc.
} }
); );
}; };
@@ -240,9 +238,11 @@ const Notification = () => {
keyExtractor={(item) => item.messageId} keyExtractor={(item) => item.messageId}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
contentContainerStyle={styles.listContainer} contentContainerStyle={styles.listContainer}
renderItem={({ item }) => ( renderItem={({ item }) => {
console.log("noti items : ", item)
return (
<TouchableOpacity <TouchableOpacity
onPress={() => handleMarkAsRead(item.messageId, item?.data?.msgType)} onPress={() => handleMarkAsRead(item.messageId, item?.data?.msgType, item?.data?.groupId, item?.data?.cycleNumber, item?.data?.contributionId)}
activeOpacity={0.7} activeOpacity={0.7}
> >
<LinearGradient <LinearGradient
@@ -307,7 +307,8 @@ const Notification = () => {
</View> </View>
</LinearGradient> </LinearGradient>
</TouchableOpacity> </TouchableOpacity>
)} )
}}
ListEmptyComponent={ ListEmptyComponent={
<View style={styles.emptyContainer}> <View style={styles.emptyContainer}>
<Ionicons name="notifications-off-outline" size={64} color="#ccc" /> <Ionicons name="notifications-off-outline" size={64} color="#ccc" />
+8 -13
View File
@@ -161,13 +161,13 @@ const Profile = () => {
// Alert.alert("Success", "Profile updated successfully"); // Alert.alert("Success", "Profile updated successfully");
// setEditing(false); // setEditing(false);
// fetchUserProfile(); // fetchUserProfile();
// if (result.status === "success") { if (result.status === "success") {
// Alert.alert("Success", "Profile updated successfully"); Alert.alert("Success", "Profile updated successfully");
// setEditing(false); setEditing(false);
// fetchUserProfile(); // reload updated data fetchUserProfile(); // reload updated data
// } else { } else {
// Alert.alert("Error", "Failed to update profile"); Alert.alert("Error", "Failed to update profile");
// } }
} catch (error) { } catch (error) {
console.error("❌ Error updating profile:", error); console.error("❌ Error updating profile:", error);
// Alert.alert("Error", "Could not update profile"); // Alert.alert("Error", "Could not update profile");
@@ -309,7 +309,7 @@ const Profile = () => {
return; return;
} }
await deleteFcmToken(); await deleteFcmToken(user?.userId?.toString());
// Clear stored credentials // Clear stored credentials
await Keychain.resetGenericPassword(); await Keychain.resetGenericPassword();
@@ -463,11 +463,6 @@ const Profile = () => {
<View> <View>
<Text style={styles.sectionTitle}>Personal Information</Text> <Text style={styles.sectionTitle}>Personal Information</Text>
<Text style={{ color: "#64748b", marginBottom: 16 }}>Become Organizer</Text> <Text style={{ color: "#64748b", marginBottom: 16 }}>Become Organizer</Text>
{/* <View style={{ marginBottom: 16 }}>
</View> */}
</View> </View>
<View> <View>
<TouchableOpacity onPress={() => navigation.navigate('Transaction')}> <TouchableOpacity onPress={() => navigation.navigate('Transaction')}>
+2 -4
View File
@@ -176,10 +176,7 @@ export const getFcmToken = async (userId: string) => {
console.log('FCM Token:', token); console.log('FCM Token:', token);
// Send token to backend with user ID // Send token to backend with user ID
await apiCall(STORE_FCM_TOKEN, 'POST', { await apiCall(`${STORE_FCM_TOKEN}${token}`, 'POST');
token,
userId
});
console.log('FCM Token sent to backend', token); console.log('FCM Token sent to backend', token);
return token; return token;
@@ -239,6 +236,7 @@ const processAndAddNotification = (remoteMessage: any) => {
title: title, title: title,
additionalProp1: data?.additionalProp1 || '', additionalProp1: data?.additionalProp1 || '',
additionalProp2: data?.additionalProp2 || '', additionalProp2: data?.additionalProp2 || '',
groupId: data?.groupId || '',
...data // Spread any additional data ...data // Spread any additional data
}, },
from: from || 'unknown', from: from || 'unknown',