import { useTheme } from '@/components/ThemeContext'; import { useInfiniteQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { router } from 'expo-router'; import { ArrowLeft } from 'lucide-react-native'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ActivityIndicator, Animated, FlatList, Pressable, StyleSheet, Text, TouchableOpacity, View, } from 'react-native'; import { user_api } from '../lib/api'; import { NotificationListDataRes } from '../lib/type'; const PAGE_SIZE = 10; export function NotificationTab() { const { isDark } = useTheme(); const { t } = useTranslation(); const { data, isLoading, isError, fetchNextPage, hasNextPage, isFetchingNextPage, refetch } = useInfiniteQuery({ queryKey: ['notifications-list'], queryFn: async ({ pageParam = 1 }) => { const response = await user_api.notification_list({ page: pageParam, page_size: PAGE_SIZE, }); return response.data.data; }, getNextPageParam: (lastPage) => lastPage.current_page < lastPage.total_pages ? lastPage.current_page + 1 : undefined, initialPageParam: 1, }); const notifications = data?.pages.flatMap((p) => p.results) ?? []; const queryClient = useQueryClient(); const { mutate: markAllAsRead, isPending: isMarkingAllRead } = useMutation({ mutationFn: () => user_api.mark_all_as_read(), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['notifications-list'] }); queryClient.invalidateQueries({ queryKey: ['notification-list'] }); }, }); if (isLoading) { return ( ); } if (isError) { return ( {t('Xatolik yuz berdi')} {t("Bildirishnomalarni yuklashda muammo bo'ldi")} refetch()}> {t('Qayta urinish')} ); } return ( router.push('/profile')}> {t('Bildirishnomalar')} {notifications.some((n) => !n.is_read) && ( markAllAsRead()} disabled={isMarkingAllRead} > {isMarkingAllRead ? ( ) : ( {t("Barchasi o'qildi")} )} )} item.id.toString()} contentContainerStyle={styles.listContent} showsVerticalScrollIndicator={false} renderItem={({ item, index }) => } onEndReached={() => { if (hasNextPage && !isFetchingNextPage) { fetchNextPage(); } }} onEndReachedThreshold={0.5} ListFooterComponent={ isFetchingNextPage ? ( ) : null } refreshing={isLoading} onRefresh={refetch} /> ); } /* ---------------- CARD ---------------- */ function NotificationCard({ item }: { item: NotificationListDataRes }) { const queryClient = useQueryClient(); const { isDark } = useTheme(); const { t } = useTranslation(); const [scaleAnim] = useState(new Animated.Value(1)); const { mutate } = useMutation({ mutationFn: (id: number) => user_api.is_ready_id(id), onSuccess: () => { queryClient.refetchQueries({ queryKey: ['notification-list'] }); queryClient.refetchQueries({ queryKey: ['notifications-list'] }); }, }); const handlePressIn = () => { Animated.spring(scaleAnim, { toValue: 0.96, useNativeDriver: true, }).start(); }; const handlePressOut = () => { Animated.spring(scaleAnim, { toValue: 1, friction: 4, tension: 50, useNativeDriver: true, }).start(); }; const handlePress = (id: number) => { if (!item.is_read) { mutate(id); } }; return ( handlePress(item.id)} style={[ styles.card, !item.is_read && styles.unreadCard, { backgroundColor: isDark ? '#283046' : '#e0f2fe', borderColor: isDark ? '#3b82f6' : '#3b82f6', }, ]} > {item.title} {!item.is_read && ( )} {item.description} {formatDate(item.created_at, t)} ); } /* ---------------- HELPERS ---------------- */ function formatDate(date: string, t: any) { const now = new Date(); const notifDate = new Date(date); const diffMs = now.getTime() - notifDate.getTime(); const diffMins = Math.floor(diffMs / 60000); const diffHours = Math.floor(diffMs / 3600000); const diffDays = Math.floor(diffMs / 86400000); if (diffMins < 1) return 'Hozir'; if (diffMins < 60) return `${diffMins} ${t('daqiqa oldin')}`; if (diffHours < 24) return `${diffHours} ${t('soat oldin')}`; if (diffDays < 7) return `${diffDays} ${t('kun oldin')}`; return notifDate.toLocaleDateString('uz-UZ', { day: 'numeric', month: 'short', }); } const styles = StyleSheet.create({ container: { flex: 1, }, listContent: { padding: 16, paddingBottom: 32, }, /* Card Styles */ card: { flexDirection: 'row', padding: 16, borderRadius: 24, borderWidth: 1, shadowColor: '#000', shadowOffset: { width: 0, height: 8 }, shadowOpacity: 0.25, shadowRadius: 12, elevation: 8, overflow: 'hidden', }, unreadCard: { shadowColor: '#3b82f6', shadowOpacity: 0.3, shadowRadius: 16, elevation: 10, }, cardContent: { flex: 1, justifyContent: 'center', }, cardHeader: { flexDirection: 'row', alignItems: 'center', marginBottom: 6, }, cardTitle: { flex: 1, fontSize: 16.5, fontWeight: '600', letterSpacing: -0.1, }, unreadTitle: { fontWeight: '700', // unread title rang }, unreadIndicator: { width: 10, height: 10, borderRadius: 5, marginLeft: 8, shadowColor: '#3b82f6', shadowOffset: { width: 0, height: 0 }, shadowOpacity: 0.7, shadowRadius: 6, }, cardMessage: { fontSize: 14.5, lineHeight: 21, marginBottom: 8, }, cardTime: { fontSize: 12.5, fontWeight: '500', opacity: 0.9, }, /* Loading State */ loadingContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', }, loadingContent: { alignItems: 'center', padding: 32, }, /* Error State */ errorContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', padding: 24, }, errorContent: { alignItems: 'center', padding: 32, borderRadius: 24, maxWidth: 320, }, errorTitle: { color: '#ef4444', fontSize: 20, fontWeight: '700', marginBottom: 8, }, errorMessage: { fontSize: 14, textAlign: 'center', marginBottom: 24, lineHeight: 20, }, retryButton: { backgroundColor: '#3b82f6', paddingHorizontal: 32, paddingVertical: 14, borderRadius: 12, shadowColor: '#3b82f6', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.3, shadowRadius: 8, elevation: 5, }, retryButtonText: { color: '#ffffff', fontSize: 15, fontWeight: '700', }, /* Header */ header: { padding: 16, flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start', gap: 10, elevation: 3, }, headerTitle: { fontSize: 18, fontWeight: '700', lineHeight: 24, flex: 1, }, markAllButton: { paddingHorizontal: 12, paddingVertical: 8, borderRadius: 8, borderWidth: 1, minWidth: 80, alignItems: 'center', justifyContent: 'center', }, markAllText: { fontSize: 13, fontWeight: '600', }, });