'use client'; import { createClient } from '@/utils/supabase'; import { useState, useEffect, useCallback, useRef } from 'react'; import { useAuth, useTVMode } from '@/components/context'; import { getRecentUsersWithStatuses, updateStatuses, updateUserStatus, type UserWithStatus, } from '@/lib/hooks/status'; import { Drawer, DrawerTrigger, Loading } from '@/components/ui'; import { toast } from 'sonner'; import { HistoryDrawer } from '@/components/status'; import type { Profile } from '@/utils/supabase'; import type { RealtimeChannel } from '@supabase/supabase-js'; type TechTableProps = { initialStatuses: UserWithStatus[]; className?: string; }; export const TechTable = ({ initialStatuses = [], className = 'w-full max-w-7xl mx-auto px-4', }: TechTableProps) => { const { isAuthenticated } = useAuth(); const { tvMode } = useTVMode(); const [loading, setLoading] = useState(true); const [selectedIds, setSelectedIds] = useState([]); const [selectAll, setSelectAll] = useState(false); const [statusInput, setStatusInput] = useState(''); const [usersWithStatuses, setUsersWithStatuses] = useState(initialStatuses); const [selectedHistoryUser, setSelectedHistoryUser] = useState(null); const channelRef = useRef(null); const fetchRecentUsersWithStatuses = useCallback(async () => { try { const response = await getRecentUsersWithStatuses(); if (!response.success) throw new Error(response.error); return response.data; } catch (error) { toast.error(`Error fetching technicians: ${error as Error}`); return []; } }, []); // Initial load useEffect(() => { const loadData = async () => { const data = await fetchRecentUsersWithStatuses(); setUsersWithStatuses(data); setLoading(false); }; loadData().catch((error) => { console.error('Error loading data:', error); }); }, [fetchRecentUsersWithStatuses, isAuthenticated]); const updateStatus = useCallback(async () => { if (!isAuthenticated) { toast.error('You must be signed in to update statuses.'); return; } if (!statusInput.trim()) { toast.error('Please enter a valid status.'); return; } try { if (selectedIds.length === 0) { const result = await updateUserStatus(statusInput); if (!result.success) throw new Error(result.error); toast.success(`Status updated for signed in user.`); } else { const result = await updateStatuses(selectedIds, statusInput); if (!result.success) throw new Error(result.error); toast.success( `Status updated for ${selectedIds.length} selected users.`, ); } setSelectedIds([]); setStatusInput(''); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); toast.error(`Failed to update status: ${errorMessage}`); } }, [isAuthenticated, statusInput, selectedIds]); const handleCheckboxChange = (id: string) => { setSelectedIds((prev) => prev.includes(id) ? prev.filter((prevId) => prevId !== id) : [...prev, id], ); }; const handleSelectAllChange = () => { if (selectAll) { setSelectedIds([]); } else { setSelectedIds(usersWithStatuses.map((tech) => tech.user.id)); } setSelectAll(!selectAll); }; useEffect(() => { setSelectAll( selectedIds.length === usersWithStatuses.length && usersWithStatuses.length > 0, ); }, [selectedIds.length, usersWithStatuses.length]); useEffect(() => { if (!isAuthenticated) return; const supabase = createClient(); const channel = supabase .channel('status_updates', { config: { broadcast: { self: true }} }) .on('broadcast', { event: 'status_updated' }, (payload) => { const { user_status } = payload.payload as { user_status: UserWithStatus; timestamp: string; }; console.log('Received status update:', user_status); setUsersWithStatuses((prevUsers) => { const existingUserIndex = prevUsers.findIndex((u) => u.user.id === user_status.user.id, ); if (existingUserIndex !== -1) { const updatedUsers = [...prevUsers]; updatedUsers[existingUserIndex] = { user: user_status.user, // Use the user from the broadcast status: user_status.status, created_at: user_status.created_at, updated_by: user_status.updated_by, }; return updatedUsers; } else { // Add new user to list! return [user_status, ...prevUsers]; } }); }) .subscribe((status) => { // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison if (status === 'SUBSCRIBED') { console.log('Successfully subscribed to status updates!'); // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison } else if (status === 'CHANNEL_ERROR') { console.error('Error subscribing to status updates.') } }); channelRef.current = channel; return () => { if (channelRef.current) { supabase.removeChannel(channelRef.current).catch((error) => { console.error(`Error unsubscribing from status updates: ${error}`); }); channelRef.current = null; } }; }, [isAuthenticated]); const formatTime = (timestamp: string) => { const date = new Date(timestamp); const time = date.toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric', }); const day = date.getDate(); const month = date.toLocaleString('default', { month: 'long' }); return `${time} - ${month} ${day}`; }; if (loading) { return (
); } return (
{!tvMode && ( )} {usersWithStatuses.map((userWithStatus, index) => ( {!tvMode && ( )} ))}
Name Status Updated At
handleCheckboxChange(userWithStatus.user.id) } /> {userWithStatus.user.full_name ?? 'Unknown User'} setSelectedHistoryUser(userWithStatus.user)} > {userWithStatus.status} {selectedHistoryUser === userWithStatus.user && ( )} {formatTime(userWithStatus.created_at)}
{!tvMode && (
setStatusInput(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { updateStatus().catch((error) => { toast.error(`Failed to update status: ${error as Error}`); }); } }} />
)}
); };