"use client" import React, { useState, useEffect, useRef } from "react"; import { useRouter } from "next/navigation"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { formatDistanceToNow } from "date-fns"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Plus, MessageCircle, Loader2, RefreshCw } from "lucide-react"; import axios from "axios"; import { toast } from "sonner"; import { getCookie } from "@/lib/client-utils"; interface Chat { _id: string; buyerId: string; vendorId: string; storeId: string; lastUpdated: string; orderId?: string; } interface UnreadCounts { totalUnread: number; chatCounts: Record; } export default function ChatList() { const router = useRouter(); const [chats, setChats] = useState([]); const [loading, setLoading] = useState(true); const [unreadCounts, setUnreadCounts] = useState({ totalUnread: 0, chatCounts: {} }); const [previousTotalUnread, setPreviousTotalUnread] = useState(0); const [selectedStore, setSelectedStore] = useState(""); const [vendorStores, setVendorStores] = useState<{ _id: string, name: string }[]>([]); const audioRef = useRef(null); // Initialize audio element useEffect(() => { // Create audio element for notification sound audioRef.current = new Audio('/notification.mp3'); // Fallback if notification.mp3 doesn't exist - use browser API for a simple beep 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; audioRef.current.play().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); } }); } else { // Fallback to simple beep if audio element is not available 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); } } }; // Fetch vendor ID and stores useEffect(() => { const fetchVendorData = async () => { try { // Get auth token from cookies const authToken = getCookie("Authorization"); if (!authToken) { toast.error("You need to be logged in to view chats"); router.push("/auth/login"); return; } // Set up axios with the auth token const authAxios = axios.create({ baseURL: process.env.NEXT_PUBLIC_API_URL, headers: { Authorization: `Bearer ${authToken}` } }); // First, get vendor info using the /auth/me endpoint const vendorResponse = await authAxios.get('/auth/me'); console.log("Vendor auth response:", vendorResponse.data); // Access correct property - the vendor ID is in vendor._id const vendorId = vendorResponse.data.vendor?._id; if (!vendorId) { console.error("Vendor ID not found in profile response:", vendorResponse.data); toast.error("Could not retrieve vendor information"); return; } // Fetch vendor's store using storefront endpoint const storeResponse = await authAxios.get(`/storefront`); console.log("Store response:", storeResponse.data); // Handle both array and single object responses if (Array.isArray(storeResponse.data)) { // If it's an array, use it as is setVendorStores(storeResponse.data); if (storeResponse.data.length > 0) { setSelectedStore(storeResponse.data[0]._id); } } else if (storeResponse.data && typeof storeResponse.data === 'object' && storeResponse.data._id) { // If it's a single store object, convert it to an array with one element const singleStore = [storeResponse.data]; setVendorStores(singleStore); setSelectedStore(storeResponse.data._id); } else { console.error("Expected store data but received:", storeResponse.data); setVendorStores([]); toast.error("Failed to load store data in expected format"); } } catch (error) { console.error("Error fetching vendor data:", error); toast.error("Failed to load vendor data"); setVendorStores([]); } }; fetchVendorData(); }, [router]); // Fetch chats and unread counts when store is selected const fetchChats = async () => { if (!selectedStore && vendorStores.length > 0) { setSelectedStore("all"); // Set default "all" if we have stores but none selected } setLoading(true); try { const endpoint = selectedStore && selectedStore !== "all" ? `/chats?storeId=${selectedStore}` : "/chats"; const response = await axios.get(`${process.env.NEXT_PUBLIC_API_URL}/api${endpoint}`, { headers: { Authorization: getCookie("Authorization") || "", "Content-Type": "application/json", }, }); setChats(response.data || []); // Fetch unread counts after loading chats await fetchUnreadCounts(); } catch (error) { console.error("Failed to fetch chats:", error); toast.error("Failed to load chat conversations"); setChats([]); } finally { setLoading(false); } }; // Add polling effect useEffect(() => { if (selectedStore) { fetchChats(); // Poll for updates every 10 seconds const intervalId = setInterval(fetchChats, 10000); return () => clearInterval(intervalId); } }, [selectedStore]); // Handle chat selection const handleChatClick = (chatId: string) => { router.push(`/dashboard/chats/${chatId}`); }; // Handle store change const handleStoreChange = (e: React.ChangeEvent) => { setSelectedStore(e.target.value); }; // Create a new chat const handleCreateChat = () => { router.push("/dashboard/chats/new"); }; if (loading) { return ( Loading chats...
{[1, 2, 3].map((n) => (
))}
); } return (
Customer Last Activity Status Actions {loading ? ( ) : chats.length === 0 ? (

No chats found

) : ( chats.map((chat) => ( handleChatClick(chat._id)} >
{chat.buyerId?.slice(0, 2).toUpperCase() || 'CU'}
Customer {chat.buyerId.slice(0, 4)}
{chat.orderId && (
Order #{chat.orderId}
)}
{formatDistanceToNow(new Date(chat.lastUpdated), { addSuffix: true })} {unreadCounts.chatCounts[chat._id] > 0 ? ( {unreadCounts.chatCounts[chat._id]} new ) : ( Read )}
)) )}
); }