feat(web): app shell, library, entry detail
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
70bc6c36d3
commit
439d138967
@@ -0,0 +1,46 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useEffect, useState } from "react";
|
||||
import { api, type ChangeEvent, type EntryPatch } from "./api.ts";
|
||||
|
||||
/** Pending Changes-inbox events (first 200; the badge shows "200+" beyond that). */
|
||||
export function usePendingChanges() {
|
||||
return useQuery({ queryKey: ["changes", "pending"], queryFn: api.changes, staleTime: 30_000 });
|
||||
}
|
||||
|
||||
export function useMe() {
|
||||
return useQuery({ queryKey: ["me"], queryFn: api.me, retry: false, staleTime: Infinity });
|
||||
}
|
||||
|
||||
export function useSources() {
|
||||
return useQuery({ queryKey: ["sources"], queryFn: api.sources, staleTime: 60_000 });
|
||||
}
|
||||
|
||||
/** Pending events that touch an entry or one of its reads/plays. */
|
||||
export function changesFor(items: ChangeEvent[] | undefined, entryId: string, engagementIds: Set<string>): ChangeEvent[] {
|
||||
return (items ?? []).filter(
|
||||
(c) => c.targetId !== null && ((c.targetEntity === "entry" && c.targetId === entryId) || (c.targetEntity === "engagement" && engagementIds.has(c.targetId))),
|
||||
);
|
||||
}
|
||||
|
||||
export function useDebounced<T>(value: T, ms = 220): T {
|
||||
const [v, setV] = useState(value);
|
||||
useEffect(() => {
|
||||
const t = setTimeout(() => setV(value), ms);
|
||||
return () => clearTimeout(t);
|
||||
}, [value, ms]);
|
||||
return v;
|
||||
}
|
||||
|
||||
/** Shared save path for every detail edit: PATCH, then refresh the entry and the list. */
|
||||
export function useEntryPatch(id: string) {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (patch: EntryPatch) => api.patchEntry(id, patch),
|
||||
onSuccess: (entry) => {
|
||||
qc.setQueryData(["entry", id], entry);
|
||||
void qc.invalidateQueries({ queryKey: ["entries"] });
|
||||
void qc.invalidateQueries({ queryKey: ["history", id] });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user