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);
}}
/>
);
}