import React from "react"; import { View, Text, ScrollView, TouchableOpacity, FlatList, } from "react-native"; import { User, ChevronRight, ArrowUpRight, ArrowDownLeft, UploadCloud, DollarSign, Ticket, } from "lucide-react-native"; import BackButton from "~/components/ui/backButton"; import { useNotifications } from "~/lib/hooks/useNotifications"; import { useAuthWithProfile } from "~/lib/hooks/useAuthWithProfile"; import { NotificationService } from "~/lib/services/notificationService"; import { RequestService } from "~/lib/services/requestService"; import { router } from "expo-router"; import { ROUTES } from "~/lib/routes"; import ScreenWrapper from "~/components/ui/ScreenWrapper"; import ModalToast from "~/components/ui/toast"; import { useTranslation } from "react-i18next"; import PermissionAlertModal from "~/components/ui/permissionAlertModal"; // Notification Card Component const NotificationCard = ({ notification, onPress, onMoneyRequestAction, onMoneyRequestPrompt, }: { notification: any; onPress?: () => void; onMoneyRequestAction?: ( requestId: string, action: "accept" | "decline" ) => void; onMoneyRequestPrompt?: (notification: any) => void; }) => { console.log("Notification:", notification); const getNotificationIcon = () => { const rawType = (notification.type || "").toString().toLowerCase(); const title = (notification.title || "").toString().toLowerCase(); const message = (notification.message || "").toString().toLowerCase(); const transactionSubtype = ( notification.transactionType || notification.transaction_type || notification.subtype || "" ) .toString() .toLowerCase(); // Event notifications (tickets, event reminders, etc.) if ( rawType === "event" || rawType === "event_ticket_purchased" || rawType === "event_reminder" || notification.category === "event" ) { return ; } // Money request notifications if ( rawType === "request_received" || title.includes("request") || message.includes("request") ) { // Arrow going 45° down for money request return ; } // Cash out (money icon, red theme handled by color helper) if ( rawType === "cash_out" || title.includes("cash out") || message.includes("cash out") ) { return ; } // Money received (same money icon but green theme) if ( rawType === "money_received" || rawType === "receive" || title.includes("received") || message.includes("received") ) { return ; } // Money sent (arrow 45° up) if ( rawType === "money_sent" || rawType === "send" || title.includes("sent") || message.includes("sent") ) { return ; } // Fallback for generic transaction-related notifications if ( rawType === "transaction_completed" || rawType === "transaction" || title.includes("transaction") || message.includes("transaction") ) { return ; } // Everything else fall back to user icon return ; }; const getNotificationColor = () => { const rawType = (notification.type || "").toString().toLowerCase(); const title = (notification.title || "").toString().toLowerCase(); const message = (notification.message || "").toString().toLowerCase(); const transactionSubtype = ( notification.transactionType || notification.transaction_type || notification.subtype || "" ) .toString() .toLowerCase(); // --- Explicit transaction subtypes (preferred) --- if (transactionSubtype === "cash_out") { // Cash out → red return "bg-red-50"; } if (transactionSubtype === "receive") { // Money received → green return "bg-green-50"; } if (transactionSubtype === "send") { // Money sent → blue return "bg-blue-50"; } if (transactionSubtype === "add_cash") { // Add cash → blue return "bg-blue-50"; } // Event notifications if ( rawType === "event" || rawType === "event_ticket_purchased" || rawType === "event_reminder" || notification.category === "event" ) { return "bg-purple-50"; } // Money request if ( rawType === "request_received" || title.includes("request") || message.includes("request") ) { return "bg-yellow-50"; } // Cash out → red if ( rawType === "cash_out" || title.includes("cash out") || message.includes("cash out") ) { return "bg-red-50"; } // Money received → green if ( rawType === "money_received" || rawType === "receive" || title.includes("received") || message.includes("received") ) { return "bg-green-50"; } // Money sent → blue if ( rawType === "money_sent" || rawType === "send" || title.includes("sent") || message.includes("sent") ) { return "bg-blue-50"; } // Generic transaction if ( rawType === "transaction_completed" || rawType === "transaction" || title.includes("transaction") || message.includes("transaction") ) { return "bg-blue-50"; } // Default return "bg-gray-50"; }; const getIconBackgroundColor = () => { const rawType = (notification.type || "").toString().toLowerCase(); const title = (notification.title || "").toString().toLowerCase(); const message = (notification.message || "").toString().toLowerCase(); const transactionSubtype = ( notification.transactionType || notification.transaction_type || notification.subtype || "" ) .toString() .toLowerCase(); // --- Explicit transaction subtypes (preferred) --- if (transactionSubtype === "cash_out") { // Cash out → red return "bg-red-500"; } if (transactionSubtype === "receive") { // Money received → green return "bg-green-500"; } if (transactionSubtype === "send") { // Money sent → blue return "bg-blue-500"; } if (transactionSubtype === "add_cash") { // Add cash → blue return "bg-blue-500"; } // Event notifications if ( rawType === "event" || rawType === "event_ticket_purchased" || rawType === "event_reminder" || notification.category === "event" ) { return "bg-purple-500"; } // Money request → yellow if ( rawType === "request_received" || title.includes("request") || message.includes("request") ) { return "bg-yellow-500"; } // Cash out → red if ( rawType === "cash_out" || title.includes("cash out") || message.includes("cash out") ) { return "bg-red-500"; } // Money received → green if ( rawType === "money_received" || rawType === "receive" || title.includes("received") || message.includes("received") ) { return "bg-green-500"; } // Money sent → blue if ( rawType === "money_sent" || rawType === "send" || title.includes("sent") || message.includes("sent") ) { return "bg-blue-500"; } // Generic transaction → blue if ( rawType === "transaction_completed" || rawType === "transaction" || title.includes("transaction") || message.includes("transaction") ) { return "bg-blue-500"; } // Default return "bg-orange-200"; }; const handleMoneyRequestPress = () => { console.log("NOTIFICATION", notification); //@ts-ignore if (notification.type === "request_received" && notification.requestId) { onMoneyRequestPrompt?.(notification); } else { onPress?.(); } }; return ( {/* Icon Avatar */} {getNotificationIcon()} {/* Notification Content */} {notification.title} {notification.message} {/* Chevron for money requests */} {notification.type === "request_received" && ( )} ); }; export default function Notification() { const { user } = useAuthWithProfile(); const { t } = useTranslation(); const [toastVisible, setToastVisible] = React.useState(false); const [toastTitle, setToastTitle] = React.useState(""); const [toastDescription, setToastDescription] = React.useState< string | undefined >(undefined); const [toastVariant, setToastVariant] = React.useState< "success" | "error" | "warning" | "info" >("info"); const toastTimeoutRef = React.useRef | null>( null ); const [requestModalVisible, setRequestModalVisible] = React.useState(false); const [activeRequestNotification, setActiveRequestNotification] = React.useState(null); const showToast = ( title: string, description?: string, variant: "success" | "error" | "warning" | "info" = "info" ) => { if (toastTimeoutRef.current) { clearTimeout(toastTimeoutRef.current); } setToastTitle(title); setToastDescription(description); setToastVariant(variant); setToastVisible(true); toastTimeoutRef.current = setTimeout(() => { setToastVisible(false); toastTimeoutRef.current = null; }, 2500); }; const { notifications, loading, error, unreadCount, markAsRead, markAllAsRead, } = useNotifications(user?.uid || null); const handleMarkAsRead = async () => { await markAllAsRead(); }; const handleNotificationPress = async (notification: any) => { if (notification?.id) { await markAsRead(notification.id); } const transactionId = notification?.transactionId || notification?.transaction_id; const transactionSubtype = notification?.transactionType || notification?.transaction_type || notification?.subtype; if ( transactionId && (notification?.type === "transaction_completed" || notification?.type === "money_received" || notification?.type === "money_sent" || notification?.category === "transaction") ) { router.push({ pathname: ROUTES.TRANSACTION_DETAIL, params: { transactionId, type: transactionSubtype || "", amount: notification?.amount !== undefined && notification?.amount !== null ? String(notification.amount) : "", recipientName: notification?.recipientName || notification?.counterpartyName || "", date: (notification?.createdAt && typeof notification.createdAt === "string" && notification.createdAt) || (notification?.date && typeof notification.date === "string" ? notification.date : ""), status: notification?.status || "", note: notification?.note || "", }, }); return; } // For other notification types (e.g. money requests), we rely on their specific handlers }; const handleMoneyRequestAction = async ( requestId: string, action: "accept" | "decline" ) => { try { // Get the request details const requestResult = await RequestService.getRequestById(requestId); if (!requestResult.success || !requestResult.request) { console.error("Failed to get request:", requestResult.error); return; } const request = requestResult.request; if (request.status !== "pending") { console.error("Request is not pending"); showToast( t("notification.toastErrorTitle"), t("notification.toastRequestNotPending"), "error" ); return; } // Get requestor details (the person who made the request) const requestorResult = await RequestService.getUserByPhoneNumber( request.requestorPhoneNumber ); if (!requestorResult.success || !requestorResult.user) { console.error( "Failed to get requestor details:", requestorResult.error ); return; } // Get requestee details (the person receiving the request - current user) const requesteeResult = await RequestService.getUserByPhoneNumber( request.requesteePhoneNumber ); if (!requesteeResult.success || !requesteeResult.user) { console.error( "Failed to get requestee details:", requesteeResult.error ); return; } const result = await NotificationService.acceptDeclineMoneyRequest( requestId, requesteeResult.user.uid, // requesteeUid (current user) requestorResult.user.uid, // requestorUid (person who made the request) requestorResult.user.displayName, // requestorName requesteeResult.user.displayName, // requesteeName request.amount, // actual amount from request action ); if (result.success) { console.log(`Request ${action}ed successfully`); if (action === "accept") { // Navigate to success screen only for accepted requests router.replace({ pathname: ROUTES.MONEY_DONATED, params: { message: `Congratulations! Transaction completed on your end.`, amount: (request.amount / 100).toFixed(2), recipientName: requestorResult.user!.displayName, }, }); } else { // For declined requests, show a simple confirmation toast showToast( t("notification.toastInfoTitle", "Request Declined"), t( "notification.toastRequestDeclined", `You have declined the money request from ${ requestorResult.user!.displayName }.` ), "info" ); } } else { console.error(`Failed to ${action} request:`, result.error); showToast( t("notification.toastErrorTitle"), t("notification.toastRequestActionFailed", { action }), "error" ); } } catch (error) { console.error(`Error ${action}ing request:`, error); showToast( t("notification.toastErrorTitle"), t("notification.toastRequestActionFailed", { action }), "error" ); } }; const handleMoneyRequestPrompt = (notification: any) => { setActiveRequestNotification(notification); setRequestModalVisible(true); }; return ( {t("notification.title")} {/* Today Section */} {t("notification.sectionToday")} {loading ? ( {t("notification.loading")} ) : error ? ( {t("notification.errorWithMessage", { error })} ) : ( item.id} scrollEnabled={false} ItemSeparatorComponent={() => } renderItem={({ item }) => ( handleNotificationPress(item)} onMoneyRequestAction={handleMoneyRequestAction} onMoneyRequestPrompt={handleMoneyRequestPrompt} /> )} /> )} {/* Empty state if no notifications */} {!loading && !error && notifications.length === 0 && ( {t("notification.emptyTitle")} {t("notification.emptySubtitle")} )} { if (activeRequestNotification?.requestId) { handleMoneyRequestAction( activeRequestNotification.requestId, "accept" ); } setRequestModalVisible(false); setActiveRequestNotification(null); }} onSecondary={() => { if (activeRequestNotification?.requestId) { handleMoneyRequestAction( activeRequestNotification.requestId, "decline" ); } setRequestModalVisible(false); setActiveRequestNotification(null); }} /> ); }