"use client"; /** * TASK-0103 — live upload progress, by file id. * * An in-flight `uploadFile` writes its progress + cancel handle here; the * `FileBlock` reads it reactively to render the on-block progress bar * (fraction, speed, cancel button) while the bytes transfer. After the upload * settles (or on a page reload, where no live handle exists) the block falls * back to polling `GET /files/:id`. Keeping the progress OUT of the block * (which re-renders on every keystroke of its caption) means the transfer UI * is driven by one place. */ import { create } from "zustand"; import type { UploadProgress } from "./upload"; interface UploadStore { /** fileId → live progress (only while a transfer is in flight). */ active: Record; cancelFns: Record void>; set: (fileId: string, progress: UploadProgress) => void; registerCancel: (fileId: string, fn: () => void) => void; clear: (fileId: string) => void; } export const useUploadStore = create()((set) => ({ active: {}, cancelFns: {}, set: (fileId, progress) => set((s) => ({ active: { ...s.active, [fileId]: progress } })), registerCancel: (fileId, fn) => set((s) => ({ cancelFns: { ...s.cancelFns, [fileId]: fn } })), clear: (fileId) => set((s) => { const active = { ...s.active }; const cancelFns = { ...s.cancelFns }; delete active[fileId]; delete cancelFns[fileId]; return { active, cancelFns }; }), }));