import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Clock, Calendar, ChevronRight, Loader2, CircleCheck } from 'lucide-react'; import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { api } from '../api/client'; import { useAuth } from '../contexts/AuthContext'; import { useToast } from '../contexts/ToastContext'; import { formatRelativeTime } from '../utils/date'; import { filterCompatibleQueueItems } from '../utils/printer'; interface PrinterQueueWidgetProps { printerId: number; printerModel?: string | null; printerState?: string | null; plateCleared?: boolean; requirePlateClear?: boolean; loadedFilamentTypes?: Set; loadedFilaments?: Set; // "TYPE:rrggbb" pairs for filament override color matching } export function PrinterQueueWidget({ printerId, printerModel, printerState, plateCleared, requirePlateClear = true, loadedFilamentTypes, loadedFilaments }: PrinterQueueWidgetProps) { const { t } = useTranslation(); const queryClient = useQueryClient(); const { showToast } = useToast(); const { hasPermission } = useAuth(); const { data: queue } = useQuery({ queryKey: ['queue', printerId, 'pending', printerModel], queryFn: () => api.getQueue(printerId, 'pending', printerModel || undefined), refetchInterval: 30000, }); const clearPlateMutation = useMutation({ mutationFn: () => api.clearPlate(printerId), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['queue', printerId] }); queryClient.invalidateQueries({ queryKey: ['printerStatus', printerId] }); showToast(t('queue.clearPlateSuccess'), 'success'); }, onError: (err: Error) => { showToast(err.message, 'error'); }, }); // Filter queue to items this printer can actually print (filament type + color check) const compatibleQueue = queue ? filterCompatibleQueueItems(queue, loadedFilamentTypes, loadedFilaments) : undefined; // Split into auto-dispatchable vs staged (manual_start) items const autoDispatchQueue = compatibleQueue?.filter(item => !item.manual_start) ?? []; const totalPending = compatibleQueue?.length || 0; if (totalPending === 0) { return null; } const nextAutoItem = autoDispatchQueue[0]; const nextItem = compatibleQueue?.[0]; // Only prompt "Clear Plate & Start Next" when there are auto-dispatchable items const needsClearPlate = requirePlateClear && (printerState === 'FINISH' || printerState === 'FAILED') && !plateCleared && autoDispatchQueue.length > 0; if (needsClearPlate) { const displayItem = nextAutoItem || nextItem; return (

{t('queue.nextInQueue')}

{displayItem?.archive_name || displayItem?.library_file_name || `File #${displayItem?.archive_id || displayItem?.library_file_id}`}

{totalPending > 1 && ( +{totalPending - 1} )}
{clearPlateMutation.isSuccess ? (
{t('queue.plateReady')}
) : ( )}
); } return (

{t('queue.nextInQueue')}

{nextItem?.archive_name || nextItem?.library_file_name || `File #${nextItem?.archive_id || nextItem?.library_file_id}`}

{nextItem?.scheduled_time ? formatRelativeTime(nextItem.scheduled_time, 'system', t) : t('time.waiting')} {totalPending > 1 && ( +{totalPending - 1} )}
); }