Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 'use client' import { useQueryClient } from '@tanstack/react-query' import { useEffect, useRef, useState } from 'react' import type { Socket } from 'socket.io-client' import { PRINT_JOB_UPDATED_EVENT, type PrintJobUpdatedEvent } from '@/lib/abacus/print/ring-events' import { abacusPrintKeys } from '@/lib/queryKeys' import { createSocket } from '@/lib/socket' /** * Doorbell listener for Abacus Studio print jobs (Phase 2a, #8.4), modeled * on `useParentSocket`. * * Joins the viewer's `user:` room and, on each print-job-updated ring, * invalidates the print proxy query keys so React Query re-reads the real * state through the authenticated proxy. The ring payload itself is never * trusted as state — it's identifiers only. * * Mount once per surface that shows job state (the #9 print panel). The * slow safety-net poll on active-job queries backstops missed rings and * carries progress %, which never rings. * * @param userId - The viewer's user id (undefined = don't connect) */ export function usePrintJobRing(userId: string | undefined): { connected: boolean } { const [connected, setConnected] = useState(false) const socketRef = useRef<Socket | null>(null) const queryClient = useQueryClient() useEffect(() => { if (!userId) return const socket = createSocket({ reconnection: true, reconnectionDelay: 1000, reconnectionAttempts: 5, }) socketRef.current = socket socket.on('connect', () => { setConnected(true) socket.emit('join-user-channel', { userId }) }) socket.on('disconnect', () => { setConnected(false) }) socket.on(PRINT_JOB_UPDATED_EVENT, (data: PrintJobUpdatedEvent) => { // Job state changed → re-read the roster and the specific job. queryClient.invalidateQueries({ queryKey: abacusPrintKeys.jobs() }) if (data.jobId) { queryClient.invalidateQueries({ queryKey: abacusPrintKeys.job(data.jobId) }) } // A phase change can also mean AMS state moved (spool consumed/swapped); // refresh that printer's filament snapshot early rather than waiting // out the staleTime. if (data.printerId) { queryClient.invalidateQueries({ queryKey: abacusPrintKeys.filaments(data.printerId) }) } }) return () => { socket.disconnect() socketRef.current = null } }, [userId, queryClient]) return { connected } } |