21202ef437
* fix(web): show skeleton in mobile task switcher sheet while snapshot loads
When the user opens the mobile task switcher inside a task page before the
workflow snapshot has hydrated kanban, the sheet rendered "No tasks yet."
instead of a loading state — and stayed that way if the fetch silently
failed.
useWorkflowSnapshot now drives kanban.isLoading, useTasks exposes it as
{ tasks, isLoading }, and the sheet wires that into TaskSwitcher's existing
skeleton. Fetch errors are surfaced via console.warn so an indefinite empty
list isn't silent anymore.
* fix(web): guard snapshot finally on cancel and drop redundant subscription
Skip the workflow-snapshot fetch's finally block when the effect was superseded by a newer workflowId — otherwise the old fetch's settle would clear the loading flag the new effect just set, briefly flashing the empty-state UI mid-switch.
Also drop the redundant kanbanIsLoading subscription in useSheetData (useTasks already encapsulates it) and make the setState mock in use-tasks.test.ts actually mutate state so useWorkflowSnapshot's side effects are exercised by the test.
* fix(web): scope snapshot finally clear to the effect that raised the flag
If kanban already matched the requested workflowId, the effect skipped raising isLoading=true — but its finally still cleared it on settle, collapsing a skeleton a concurrent caller (e.g. workspace switch) had set independently. Track whether this effect raised the flag and only clear in that case.
Also collapse the multi-line useTasks comment per CLAUDE.md style.
* fix(web): suppress superseded snapshot fetch warnings
Skip the catch-handler console.warn when the effect has been cancelled — a stale fetch shouldn't surface noise after a newer workflow has taken over.
* test(web): flush microtasks explicitly in race test
waitFor on a never-true assertion resolves immediately, hiding the intent. Use explicit Promise.resolve() flushes to land the superseded fetch's .then/.finally chain before asserting.
* style(web): collapse multi-line comments per CLAUDE.md
20 lines
861 B
TypeScript
20 lines
861 B
TypeScript
import { useMemo } from "react";
|
|
import { useWorkflowSnapshot } from "@/hooks/use-workflow-snapshot";
|
|
import { useAppStore } from "@/components/state-provider";
|
|
|
|
export function useTasks(workflowId: string | null) {
|
|
useWorkflowSnapshot(workflowId);
|
|
|
|
const kanbanWorkflowId = useAppStore((state) => state.kanban.workflowId);
|
|
const kanbanIsLoading = useAppStore((state) => state.kanban.isLoading ?? false);
|
|
const tasks = useAppStore((state) => state.kanban.tasks);
|
|
|
|
const matchesActive = !!workflowId && kanbanWorkflowId === workflowId;
|
|
const workflowTasks = useMemo(() => (matchesActive ? tasks : []), [matchesActive, tasks]);
|
|
|
|
// Loading only while a snapshot fetch is in-flight; settles to false on success/error to avoid an infinite skeleton.
|
|
const isLoading = !!workflowId && kanbanIsLoading;
|
|
|
|
return { tasks: workflowTasks, isLoading };
|
|
}
|