import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { api } from "./client.ts"; import type { BoardSnapshot, HubSettings, IssueDetail, IssueRow, Note, NoteFields } from "./types.ts"; export const ISSUE_FILTER_NAMES = ["sprint", "assignee", "work_kind", "fact_status", "status", "label", "epic", "neighbor", "q"] as const; export type IssueFilters = Partial>; export const ISSUE_PAGE = 50; export const qk = { settings: ["settings"] as const, board: ["board"] as const, issues: (f: IssueFilters) => ["issues", f] as const, issue: (key: string) => ["issue", key] as const, }; export const useSettings = () => useQuery({ queryKey: qk.settings, queryFn: () => api.get("/settings"), staleTime: Infinity }); export const useBoard = () => useQuery({ queryKey: qk.board, queryFn: () => api.get("/board") }); export const useIssue = (key: string) => useQuery({ queryKey: qk.issue(key), queryFn: () => api.get(`/issues/${encodeURIComponent(key)}`) }); // список порциями по ISSUE_PAGE: следующая порция есть, пока последняя полная export const useIssues = (filters: IssueFilters) => useInfiniteQuery({ queryKey: qk.issues(filters), initialPageParam: 0, queryFn: ({ pageParam }) => api.get<{ issues: IssueRow[] }>("/issues", { ...filters, limit: ISSUE_PAGE, offset: pageParam }).then((r) => r.issues), getNextPageParam: (last, all) => (last.length < ISSUE_PAGE ? undefined : all.length * ISSUE_PAGE), }); // сохранение заметки: key фиксируется при создании мутации — ответ пишется в карточку той задачи, для которой отправлен export function useSaveNote(key: string) { const qc = useQueryClient(); return useMutation({ mutationFn: (fields: NoteFields) => api.put(`/issues/${encodeURIComponent(key)}/note`, { ...fields, updated_by: "web" }), onSuccess: (note) => { qc.setQueryData(qk.issue(key), (d) => (d ? { ...d, note } : d)); void qc.invalidateQueries({ queryKey: ["issues"] }); void qc.invalidateQueries({ queryKey: qk.board }); }, }); }