mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-22 17:49:48 +02:00
Phase 1: Monorepo infrastructure - Add Turborepo with turbo.json pipeline (build, dev, typecheck, test) - Update pnpm-workspace.yaml to include packages/* - Create shared TypeScript config (packages/tsconfig) Phase 2: Extract packages/core (zero react-dom, all-platform reuse) - Move domain types, API client, logger, utils → packages/core/ - Move TanStack Query modules (issues, inbox, workspace, runtimes) - Move Zustand stores (auth, workspace, issues, navigation, modals) - Move realtime sync (WSProvider, hooks, ws-updaters) - Refactor auth/workspace stores to factory pattern for DI - Refactor ApiClient with onUnauthorized callback - Refactor useWorkspaceId to React Context (WorkspaceIdProvider) - Refactor WSProvider to accept wsUrl + store props - Create apps/web/platform/ bridge layer (api singleton, store instances) - Update 91 import paths across apps/web/ - Fix 3 test files for new import paths Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
114 lines
3.5 KiB
TypeScript
114 lines
3.5 KiB
TypeScript
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
import { api } from "../api";
|
|
import { inboxKeys } from "./queries";
|
|
import { useWorkspaceId } from "../hooks";
|
|
import type { InboxItem } from "../types";
|
|
|
|
export function useMarkInboxRead() {
|
|
const qc = useQueryClient();
|
|
const wsId = useWorkspaceId();
|
|
return useMutation({
|
|
mutationFn: (id: string) => api.markInboxRead(id),
|
|
onMutate: async (id) => {
|
|
await qc.cancelQueries({ queryKey: inboxKeys.list(wsId) });
|
|
const prev = qc.getQueryData<InboxItem[]>(inboxKeys.list(wsId));
|
|
qc.setQueryData<InboxItem[]>(inboxKeys.list(wsId), (old) =>
|
|
old?.map((item) => (item.id === id ? { ...item, read: true } : item)),
|
|
);
|
|
return { prev };
|
|
},
|
|
onError: (_err, _id, ctx) => {
|
|
if (ctx?.prev) qc.setQueryData(inboxKeys.list(wsId), ctx.prev);
|
|
},
|
|
onSettled: () => {
|
|
qc.invalidateQueries({ queryKey: inboxKeys.list(wsId) });
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useArchiveInbox() {
|
|
const qc = useQueryClient();
|
|
const wsId = useWorkspaceId();
|
|
return useMutation({
|
|
mutationFn: (id: string) => api.archiveInbox(id),
|
|
onMutate: async (id) => {
|
|
await qc.cancelQueries({ queryKey: inboxKeys.list(wsId) });
|
|
const prev = qc.getQueryData<InboxItem[]>(inboxKeys.list(wsId));
|
|
// Archive all items for the same issue (same behavior as store)
|
|
const target = prev?.find((i) => i.id === id);
|
|
const issueId = target?.issue_id;
|
|
qc.setQueryData<InboxItem[]>(inboxKeys.list(wsId), (old) =>
|
|
old?.map((item) =>
|
|
item.id === id || (issueId && item.issue_id === issueId)
|
|
? { ...item, archived: true }
|
|
: item,
|
|
),
|
|
);
|
|
return { prev };
|
|
},
|
|
onError: (_err, _id, ctx) => {
|
|
if (ctx?.prev) qc.setQueryData(inboxKeys.list(wsId), ctx.prev);
|
|
},
|
|
onSettled: () => {
|
|
qc.invalidateQueries({ queryKey: inboxKeys.list(wsId) });
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useMarkAllInboxRead() {
|
|
const qc = useQueryClient();
|
|
const wsId = useWorkspaceId();
|
|
return useMutation({
|
|
mutationFn: () => api.markAllInboxRead(),
|
|
onMutate: async () => {
|
|
await qc.cancelQueries({ queryKey: inboxKeys.list(wsId) });
|
|
const prev = qc.getQueryData<InboxItem[]>(inboxKeys.list(wsId));
|
|
qc.setQueryData<InboxItem[]>(inboxKeys.list(wsId), (old) =>
|
|
old?.map((item) =>
|
|
!item.archived ? { ...item, read: true } : item,
|
|
),
|
|
);
|
|
return { prev };
|
|
},
|
|
onError: (_err, _vars, ctx) => {
|
|
if (ctx?.prev) qc.setQueryData(inboxKeys.list(wsId), ctx.prev);
|
|
},
|
|
onSettled: () => {
|
|
qc.invalidateQueries({ queryKey: inboxKeys.list(wsId) });
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useArchiveAllInbox() {
|
|
const qc = useQueryClient();
|
|
const wsId = useWorkspaceId();
|
|
return useMutation({
|
|
mutationFn: () => api.archiveAllInbox(),
|
|
onSettled: () => {
|
|
qc.invalidateQueries({ queryKey: inboxKeys.list(wsId) });
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useArchiveAllReadInbox() {
|
|
const qc = useQueryClient();
|
|
const wsId = useWorkspaceId();
|
|
return useMutation({
|
|
mutationFn: () => api.archiveAllReadInbox(),
|
|
onSettled: () => {
|
|
qc.invalidateQueries({ queryKey: inboxKeys.list(wsId) });
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useArchiveCompletedInbox() {
|
|
const qc = useQueryClient();
|
|
const wsId = useWorkspaceId();
|
|
return useMutation({
|
|
mutationFn: () => api.archiveCompletedInbox(),
|
|
onSettled: () => {
|
|
qc.invalidateQueries({ queryKey: inboxKeys.list(wsId) });
|
|
},
|
|
});
|
|
}
|