handle notification type and navigate using deeplinking
This commit is contained in:
@@ -8,86 +8,314 @@ import {
|
||||
} from 'react-native';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import {
|
||||
addNotification,
|
||||
removeNotification,
|
||||
clearAllNotifications,
|
||||
markAsRead,
|
||||
markAllAsRead,
|
||||
} from '../../redux/notificationSlice';
|
||||
import LinearGradient from 'react-native-linear-gradient';
|
||||
import { Ionicons } from '@react-native-vector-icons/ionicons';
|
||||
import AppView from '../../components/AppView';
|
||||
import Header from '../../components/common/Header';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { useNotificationHandler } from '../hook/useNotificationHandler';
|
||||
|
||||
type FilterType = 'all' | 'JOIN_REQUEST' | 'CONTRIBUTION' | 'CONTRIBUTION_ACK' |
|
||||
'CYCLE_COMPLETED' | 'WITHDRAWAL' | 'WITHDRAWAL_NOTIFY' |
|
||||
'CYCLE_WAIVER' | 'WAIVER_RECEIVED' | 'USER_SELECTED' |
|
||||
'GROUP_STARTED' | 'JOIN_APPROVED' | 'JOIN_VIA_INVITE';
|
||||
|
||||
const Notification = () => {
|
||||
const dispatch = useDispatch();
|
||||
const navigation = useNavigation();
|
||||
const { handleMarkAsReadAndNavigate } = useNotificationHandler();
|
||||
const notifications = useSelector(
|
||||
(state: any) => state.notifications.notifications
|
||||
);
|
||||
|
||||
const handleAdd = () => {
|
||||
const newNotification = {
|
||||
id: Date.now().toString(),
|
||||
title: 'New Message',
|
||||
message: 'You have a new message in your inbox.',
|
||||
time: new Date().toLocaleString(),
|
||||
read: false,
|
||||
};
|
||||
dispatch(addNotification(newNotification));
|
||||
};
|
||||
|
||||
const handleDelete = (id: string) => {
|
||||
dispatch(removeNotification(id));
|
||||
console.log("notifications ==>", notifications);
|
||||
|
||||
const handleDelete = (messageId: string) => {
|
||||
dispatch(removeNotification(messageId));
|
||||
};
|
||||
|
||||
const handleClearAll = () => {
|
||||
dispatch(clearAllNotifications());
|
||||
};
|
||||
|
||||
const handleMarkAsRead = (messageId: string, screen: string) => {
|
||||
console.log("screen type : ", screen);
|
||||
handleMarkAsReadAndNavigate(
|
||||
messageId,
|
||||
screen,
|
||||
{
|
||||
// Pass additional parameters based on notification type
|
||||
groupId: 'ebc27862-acde-4129-b12c-fd4c2966e858',
|
||||
cycleNumber: '1',
|
||||
contributionId: '12345',
|
||||
actionTab3: 'Your Requests' ,
|
||||
actionTab1: 'Joined Groups',
|
||||
GroupDetails: {
|
||||
item: {}
|
||||
},
|
||||
// etc.
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const handleMarkAllAsRead = () => {
|
||||
dispatch(markAllAsRead());
|
||||
};
|
||||
|
||||
const formatTime = (timestamp: number) => {
|
||||
const date = new Date(timestamp);
|
||||
const now = new Date();
|
||||
const diffInHours = (now.getTime() - date.getTime()) / (1000 * 60 * 60);
|
||||
|
||||
if (diffInHours < 1) {
|
||||
return 'Just now';
|
||||
} else if (diffInHours < 24) {
|
||||
return `${Math.floor(diffInHours)}h ago`;
|
||||
} else {
|
||||
return date.toLocaleDateString();
|
||||
}
|
||||
};
|
||||
|
||||
const getNotificationIcon = (msgType: string) => {
|
||||
switch (msgType) {
|
||||
case 'JOIN_REQUEST':
|
||||
return 'person-add-outline';
|
||||
case 'CONTRIBUTION':
|
||||
return 'cash-outline';
|
||||
case 'CONTRIBUTION_ACK':
|
||||
return 'checkmark-done-outline';
|
||||
case 'CYCLE_COMPLETED':
|
||||
return 'trophy-outline';
|
||||
case 'WITHDRAWAL':
|
||||
return 'card-outline';
|
||||
case 'WITHDRAWAL_NOTIFY':
|
||||
return 'notifications-outline';
|
||||
case 'CYCLE_WAIVER':
|
||||
return 'document-text-outline';
|
||||
case 'WAIVER_RECEIVED':
|
||||
return 'download-outline';
|
||||
case 'USER_SELECTED':
|
||||
return 'people-outline';
|
||||
case 'GROUP_STARTED':
|
||||
return 'rocket-outline';
|
||||
case 'JOIN_APPROVED':
|
||||
return 'checkmark-circle-outline';
|
||||
case 'JOIN_VIA_INVITE':
|
||||
return 'gift-outline';
|
||||
default:
|
||||
return 'notifications-outline';
|
||||
}
|
||||
};
|
||||
|
||||
const getNotificationTypeNavigateScreen = (msgType: string) => {
|
||||
switch (msgType) {
|
||||
case 'JOIN_REQUEST':
|
||||
return 'Home'; // Screen for managing join requests
|
||||
case 'CONTRIBUTION':
|
||||
return 'ContributionDetails'; // Screen for contribution details
|
||||
case 'CONTRIBUTION_ACK':
|
||||
return 'ContributionHistory'; // Screen for contribution history
|
||||
case 'CYCLE_COMPLETED':
|
||||
return 'CycleCompleted'; // Screen showing cycle completion details
|
||||
case 'WITHDRAWAL':
|
||||
return 'WithdrawalHistory'; // Screen for withdrawal history
|
||||
case 'WITHDRAWAL_NOTIFY':
|
||||
return 'WithdrawalDetails'; // Screen for withdrawal notification details
|
||||
case 'CYCLE_WAIVER':
|
||||
return 'WaiverRequests'; // Screen for waiver requests
|
||||
case 'WAIVER_RECEIVED':
|
||||
return 'WaiverDetails'; // Screen for waiver details
|
||||
case 'USER_SELECTED':
|
||||
return 'UserSelection'; // Screen for user selection details
|
||||
case 'GROUP_STARTED':
|
||||
return 'GroupDetails'; // Screen for group details
|
||||
case 'JOIN_APPROVED':
|
||||
return 'JoinApproved'; // Screen for approved join requests
|
||||
case 'JOIN_VIA_INVITE':
|
||||
return 'InviteDetails'; // Screen for invite details
|
||||
default:
|
||||
return 'Home'; // Default fallback screen
|
||||
}
|
||||
};
|
||||
|
||||
const getNotificationColor = (msgType: string) => {
|
||||
switch (msgType) {
|
||||
case 'JOIN_REQUEST':
|
||||
return '#FF6B35'; // Orange
|
||||
case 'CONTRIBUTION':
|
||||
return '#4CAF50'; // Green
|
||||
case 'CONTRIBUTION_ACK':
|
||||
return '#2196F3'; // Blue
|
||||
case 'CYCLE_COMPLETED':
|
||||
return '#9C27B0'; // Purple
|
||||
case 'WITHDRAWAL':
|
||||
return '#FF9800'; // Amber
|
||||
case 'WITHDRAWAL_NOTIFY':
|
||||
return '#F44336'; // Red
|
||||
case 'CYCLE_WAIVER':
|
||||
return '#607D8B'; // Blue Grey
|
||||
case 'WAIVER_RECEIVED':
|
||||
return '#009688'; // Teal
|
||||
case 'USER_SELECTED':
|
||||
return '#673AB7'; // Deep Purple
|
||||
case 'GROUP_STARTED':
|
||||
return '#00BCD4'; // Cyan
|
||||
case 'JOIN_APPROVED':
|
||||
return '#4CAF50'; // Green
|
||||
case 'JOIN_VIA_INVITE':
|
||||
return '#FFC107'; // Yellow
|
||||
default:
|
||||
return '#757575'; // Grey
|
||||
}
|
||||
};
|
||||
|
||||
const getFilterDisplayName = (filter: FilterType) => {
|
||||
switch (filter) {
|
||||
case 'JOIN_REQUEST':
|
||||
return 'Requests';
|
||||
case 'CONTRIBUTION':
|
||||
return 'Contributions';
|
||||
case 'CONTRIBUTION_ACK':
|
||||
return 'Contributions Ack';
|
||||
case 'CYCLE_COMPLETED':
|
||||
return 'Cycle Completed';
|
||||
case 'WITHDRAWAL':
|
||||
return 'Withdrawals';
|
||||
case 'WITHDRAWAL_NOTIFY':
|
||||
return 'Withdrawal Notify';
|
||||
case 'CYCLE_WAIVER':
|
||||
return 'Waivers';
|
||||
case 'WAIVER_RECEIVED':
|
||||
return 'Waiver Received';
|
||||
case 'USER_SELECTED':
|
||||
return 'User Selected';
|
||||
case 'GROUP_STARTED':
|
||||
return 'Group Started';
|
||||
case 'JOIN_APPROVED':
|
||||
return 'Join Approved';
|
||||
case 'JOIN_VIA_INVITE':
|
||||
return 'Invites';
|
||||
default:
|
||||
return 'All';
|
||||
}
|
||||
};
|
||||
|
||||
const unreadCount = notifications.filter((item: any) => !item.read).length;
|
||||
|
||||
return (
|
||||
<AppView>
|
||||
{/* Header with Add and Clear All */}
|
||||
<Header title='Notifications' rightAction={<LinearGradient
|
||||
colors={['#FF6B6B', '#FF8E53']}
|
||||
style={styles.clearButtonGradient}>
|
||||
<TouchableOpacity onPress={handleClearAll}>
|
||||
<Text style={styles.clearButtonText}>Delete All</Text>
|
||||
</TouchableOpacity>
|
||||
</LinearGradient>}
|
||||
/>
|
||||
|
||||
|
||||
{/* Add Notification Button */}
|
||||
{/* <LinearGradient
|
||||
colors={['#4facfe', '#00f2fe']}
|
||||
style={styles.addButtonGradient}>
|
||||
<TouchableOpacity onPress={handleAdd}>
|
||||
<Text style={styles.addButtonText}>Add Notification</Text>
|
||||
</TouchableOpacity>
|
||||
</LinearGradient> */}
|
||||
{/* Header with actions */}
|
||||
<Header
|
||||
title={`Notifications ${unreadCount > 0 ? `(${unreadCount})` : ''}`} />
|
||||
<View style={styles.headerActions}>
|
||||
{unreadCount > 0 && (
|
||||
<LinearGradient
|
||||
colors={['#4CAF50', '#45a049']}
|
||||
style={[styles.headerButton, styles.markReadButton]}>
|
||||
<TouchableOpacity onPress={handleMarkAllAsRead}>
|
||||
<Text style={styles.headerButtonText}>Mark All Read</Text>
|
||||
</TouchableOpacity>
|
||||
</LinearGradient>
|
||||
)}
|
||||
{notifications.length > 0 && (
|
||||
<LinearGradient
|
||||
colors={['#FF6B6B', '#FF8E53']}
|
||||
style={styles.headerButton}>
|
||||
<TouchableOpacity onPress={handleClearAll}>
|
||||
<Text style={styles.headerButtonText}>Clear All</Text>
|
||||
</TouchableOpacity>
|
||||
</LinearGradient>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Notification List */}
|
||||
<FlatList
|
||||
data={notifications}
|
||||
keyExtractor={(item) => item.id}
|
||||
keyExtractor={(item) => item.messageId}
|
||||
showsVerticalScrollIndicator={false}
|
||||
contentContainerStyle={styles.listContainer}
|
||||
renderItem={({ item }) => (
|
||||
<LinearGradient
|
||||
colors={['#f5f7fa', '#c3cfe2']}
|
||||
style={styles.notificationCard}>
|
||||
<View style={styles.notificationContent}>
|
||||
<View style={{ flex: 1 }}>
|
||||
<Text style={styles.title}>{item.title}</Text>
|
||||
<Text style={styles.message}>{item.message}</Text>
|
||||
<Text style={styles.time}>{item.time}</Text>
|
||||
<TouchableOpacity
|
||||
onPress={() => handleMarkAsRead(item.messageId, item?.data?.msgType)}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={item.read ? ['#f8f9fa', '#e9ecef'] : ['#ffffff', '#f8f9fa']}
|
||||
style={[
|
||||
styles.notificationCard,
|
||||
!item.read && styles.unreadNotification, { borderLeftColor: getNotificationColor(item.data.msgType) }
|
||||
]}>
|
||||
<View style={styles.notificationContent}>
|
||||
{/* Icon */}
|
||||
<View style={styles.iconContainer}>
|
||||
<Ionicons
|
||||
name={getNotificationIcon(item.data.msgType)}
|
||||
size={24}
|
||||
color={getNotificationColor(item.data.msgType)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* Content */}
|
||||
<View style={styles.textContent}>
|
||||
<View style={styles.headerRow}>
|
||||
<Text style={[
|
||||
styles.title,
|
||||
!item.read && styles.unreadTitle
|
||||
]}>
|
||||
{item.data.title}
|
||||
</Text>
|
||||
<Text style={styles.time}>
|
||||
{formatTime(item.sentTime)}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<Text style={styles.message}>
|
||||
{item.data.body}
|
||||
</Text>
|
||||
|
||||
{item.data.msgType && (
|
||||
<View style={styles.tagContainer}>
|
||||
<Text style={[
|
||||
styles.tag,
|
||||
{ backgroundColor: getNotificationColor(item.data.msgType) }
|
||||
]}>
|
||||
{/* {item.data.msgType} */}
|
||||
{getFilterDisplayName(item.data.msgType as FilterType)}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Actions */}
|
||||
<View style={styles.actionsContainer}>
|
||||
{!item.read && (
|
||||
<View style={styles.unreadIndicator} />
|
||||
)}
|
||||
<TouchableOpacity
|
||||
onPress={() => handleDelete(item.messageId)}
|
||||
style={styles.deleteButton}
|
||||
>
|
||||
<Ionicons name="trash-outline" size={20} color="#e63946" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
<TouchableOpacity onPress={() => handleDelete(item.id)}>
|
||||
<Ionicons name="trash-outline" size={22} color="#e63946" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
ListEmptyComponent={
|
||||
<Text style={styles.emptyText}>No notifications found.</Text>
|
||||
<View style={styles.emptyContainer}>
|
||||
<Ionicons name="notifications-off-outline" size={64} color="#ccc" />
|
||||
<Text style={styles.emptyText}>No notifications yet</Text>
|
||||
<Text style={styles.emptySubtext}>
|
||||
When you get notifications, they'll appear here
|
||||
</Text>
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</AppView>
|
||||
@@ -97,74 +325,130 @@ const Notification = () => {
|
||||
export default Notification;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
headerContainer: {
|
||||
headerActions: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
justifyContent: 'flex-end',
|
||||
paddingHorizontal: 16,
|
||||
paddingTop: 12,
|
||||
paddingVertical: 10,
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: '700',
|
||||
color: '#222',
|
||||
},
|
||||
clearButtonGradient: {
|
||||
headerButton: {
|
||||
borderRadius: 8,
|
||||
paddingVertical: 6,
|
||||
paddingHorizontal: 14,
|
||||
},
|
||||
clearButtonText: {
|
||||
color: '#fff',
|
||||
fontWeight: '600',
|
||||
},
|
||||
addButtonGradient: {
|
||||
margin: 16,
|
||||
borderRadius: 8,
|
||||
paddingVertical: 10,
|
||||
paddingHorizontal: 12,
|
||||
minWidth: 80,
|
||||
alignItems: 'center',
|
||||
},
|
||||
addButtonText: {
|
||||
markReadButton: {
|
||||
minWidth: 100,
|
||||
},
|
||||
headerButtonText: {
|
||||
color: '#fff',
|
||||
fontWeight: '600',
|
||||
fontSize: 16,
|
||||
fontSize: 12,
|
||||
},
|
||||
listContainer: {
|
||||
paddingHorizontal: 12,
|
||||
paddingBottom: 30,
|
||||
paddingTop: 8,
|
||||
},
|
||||
notificationCard: {
|
||||
borderRadius: 10,
|
||||
padding: 12,
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
marginBottom: 10,
|
||||
shadowColor: '#000',
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 5,
|
||||
elevation: 2,
|
||||
elevation: 3,
|
||||
borderLeftWidth: 4,
|
||||
borderLeftColor: 'transparent',
|
||||
},
|
||||
unreadNotification: {
|
||||
// borderLeftColor: colors.primary,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
notificationContent: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
alignItems: 'flex-start',
|
||||
gap: 12,
|
||||
},
|
||||
iconContainer: {
|
||||
paddingTop: 2,
|
||||
},
|
||||
textContent: {
|
||||
flex: 1,
|
||||
gap: 4,
|
||||
},
|
||||
headerRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'flex-start',
|
||||
marginBottom: 4,
|
||||
},
|
||||
title: {
|
||||
fontWeight: '700',
|
||||
fontWeight: '600',
|
||||
fontSize: 16,
|
||||
color: '#333',
|
||||
flex: 1,
|
||||
marginRight: 8,
|
||||
},
|
||||
unreadTitle: {
|
||||
fontWeight: '700',
|
||||
color: '#000',
|
||||
},
|
||||
message: {
|
||||
fontSize: 14,
|
||||
color: '#555',
|
||||
marginTop: 2,
|
||||
color: '#666',
|
||||
lineHeight: 20,
|
||||
},
|
||||
time: {
|
||||
fontSize: 12,
|
||||
color: '#888',
|
||||
marginTop: 4,
|
||||
color: '#999',
|
||||
fontWeight: '500',
|
||||
},
|
||||
tagContainer: {
|
||||
marginTop: 6,
|
||||
},
|
||||
tag: {
|
||||
fontSize: 10,
|
||||
color: '#fff',
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 2,
|
||||
borderRadius: 4,
|
||||
overflow: 'hidden',
|
||||
alignSelf: 'flex-start',
|
||||
fontWeight: '600',
|
||||
},
|
||||
actionsContainer: {
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
},
|
||||
unreadIndicator: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
backgroundColor: '#2196F3',
|
||||
},
|
||||
deleteButton: {
|
||||
padding: 4,
|
||||
},
|
||||
emptyContainer: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: 100,
|
||||
paddingHorizontal: 40,
|
||||
},
|
||||
emptyText: {
|
||||
textAlign: 'center',
|
||||
marginTop: 60,
|
||||
fontSize: 16,
|
||||
color: '#999',
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
color: '#666',
|
||||
marginTop: 16,
|
||||
marginBottom: 8,
|
||||
},
|
||||
});
|
||||
emptySubtext: {
|
||||
fontSize: 14,
|
||||
color: '#999',
|
||||
textAlign: 'center',
|
||||
lineHeight: 20,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user