"use client"; import { useEffect, useState, useRef } from "react"; import { clientFetch } from "@/lib/api"; import { toast } from "sonner"; import { Package, Bell } from "lucide-react"; import { useRouter } from "next/navigation"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; interface Order { _id: string; orderId: string; status: string; totalPrice: number; orderDate: string; items?: Array<{ name: string; quantity: number }>; customerName?: string; } export default function OrderNotifications() { const router = useRouter(); const [newOrders, setNewOrders] = useState([]); const [loading, setLoading] = useState(true); const seenOrderIds = useRef>(new Set()); const isInitialFetch = useRef(true); const audioRef = useRef(null); useEffect(() => { audioRef.current = new Audio('/hohoho.mp3'); // Fallback if hohoho.mp3 doesn't exist audioRef.current.addEventListener('error', () => { audioRef.current = null; }); return () => { if (audioRef.current) { audioRef.current = null; } }; }, []); // Function to play notification sound const playNotificationSound = () => { if (audioRef.current) { audioRef.current.currentTime = 0; const playPromise = audioRef.current.play(); if (playPromise !== undefined) { playPromise.catch(err => { console.log('Error playing sound:', err); // Fallback to simple beep if audio file fails try { const context = new (window.AudioContext || (window as any).webkitAudioContext)(); const oscillator = context.createOscillator(); oscillator.type = 'sine'; oscillator.frequency.setValueAtTime(800, context.currentTime); oscillator.connect(context.destination); oscillator.start(); oscillator.stop(context.currentTime + 0.2); } catch (e) { console.error('Could not play fallback audio', e); } }); } } }; useEffect(() => { // Only run this on dashboard pages if (typeof window === 'undefined' || !window.location.pathname.includes("/dashboard")) return; const checkForNewOrders = async () => { try { // Get orders from the last 24 hours with a more efficient query const yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); const timestamp = yesterday.toISOString(); // Use orderDate parameter instead of 'after' to avoid backend casting errors // The error logs show that the 'after' parameter is being interpreted as 'orderId' incorrectly const orderData = await clientFetch(`/orders?status=paid&limit=10&orderDate[gte]=${timestamp}`); const orders: Order[] = orderData.orders || []; // If this is the first fetch, just store the orders without notifications if (isInitialFetch.current) { orders.forEach(order => seenOrderIds.current.add(order._id)); isInitialFetch.current = false; setLoading(false); return; } // Check for new paid orders that haven't been seen before const latestNewOrders = orders.filter(order => !seenOrderIds.current.has(order._id)); // Show notifications for new orders if (latestNewOrders.length > 0) { // Update the seen orders set latestNewOrders.forEach(order => seenOrderIds.current.add(order._id)); // Show a notification for each new order latestNewOrders.forEach(order => { toast.success(

New Paid Order!

Order #{order.orderId}

£{order.totalPrice.toFixed(2)}

, { duration: 8000, icon: , action: { label: "View", onClick: () => window.open(`/dashboard/orders/${order._id}`, "_blank") } } ); }); // Play notification sound playNotificationSound(); // Update the state with new orders for the dropdown setNewOrders(prev => [...latestNewOrders, ...prev].slice(0, 10)); } setLoading(false); } catch (error) { console.error("Error checking for new orders:", error); setLoading(false); } }; // Check immediately on component mount (with a small delay) const initialTimeout = setTimeout(() => { checkForNewOrders(); }, 2000); // Set up polling interval (every 60 seconds) const interval = setInterval(checkForNewOrders, 60000); // Clean up return () => { clearTimeout(initialTimeout); clearInterval(interval); }; }, []); const handleOrderClick = (orderId: string) => { router.push(`/dashboard/orders/${orderId}`); }; const clearNotifications = () => { setNewOrders([]); }; // Format the price as currency const formatPrice = (price: number) => { return `£${price.toFixed(2)}`; }; return (

New Paid Orders

{newOrders.length > 0 && ( )}
{newOrders.length === 0 ? (

No new paid orders

) : ( <>
{newOrders.map((order) => ( handleOrderClick(order._id)} >

Order #{order.orderId}

{formatPrice(order.totalPrice)}

Paid
))}
)}
); }