- notes-store: wrap hydrate() and openNote() in try/catch to prevent isLoading stuck true - inbox-store: wrap hydrate() in try/catch to prevent isLoading stuck true on API failure - openNote falls back to cached list note when detail fetch fails
87 lines
2.2 KiB
TypeScript
87 lines
2.2 KiB
TypeScript
import { create } from 'zustand';
|
|
import {
|
|
listActivityFeed,
|
|
listApprovalQueue,
|
|
updateApprovalState,
|
|
type MobileActivityItem,
|
|
type MobileApprovalItem,
|
|
} from '../api/note-agent-actions';
|
|
|
|
export type ApprovalItem = {
|
|
id: string;
|
|
workspaceId: string;
|
|
noteId: string;
|
|
title: string;
|
|
summary: string;
|
|
status: 'pending' | 'approved' | 'rejected';
|
|
};
|
|
|
|
export type ActivityItem = {
|
|
id: string;
|
|
title: string;
|
|
summary: string;
|
|
kind: 'note' | 'task' | 'agent';
|
|
};
|
|
|
|
export type InboxState = {
|
|
approvals: ApprovalItem[];
|
|
activity: ActivityItem[];
|
|
isLoading: boolean;
|
|
hydrate: () => Promise<void>;
|
|
approve: (id: string, reviewNote?: string) => Promise<void>;
|
|
reject: (id: string, reviewNote?: string) => Promise<void>;
|
|
};
|
|
|
|
function toApprovalItem(item: MobileApprovalItem): ApprovalItem {
|
|
return item;
|
|
}
|
|
|
|
function toActivityItem(item: MobileActivityItem): ActivityItem {
|
|
return item;
|
|
}
|
|
|
|
export const useInboxStore = create<InboxState>((set, get) => ({
|
|
approvals: [],
|
|
activity: [],
|
|
isLoading: false,
|
|
async hydrate() {
|
|
set({ isLoading: true });
|
|
try {
|
|
const [approvals, activity] = await Promise.all([listApprovalQueue(), listActivityFeed()]);
|
|
set({
|
|
approvals: approvals.map(toApprovalItem),
|
|
activity: activity.map(toActivityItem),
|
|
isLoading: false,
|
|
});
|
|
} catch {
|
|
set({ isLoading: false });
|
|
}
|
|
},
|
|
async approve(id: string, reviewNote?: string) {
|
|
const current = get().approvals.find((item) => item.id === id);
|
|
if (!current) {
|
|
return;
|
|
}
|
|
|
|
const updated = await updateApprovalState(id, current.workspaceId, 'approved', reviewNote);
|
|
set((state) => ({
|
|
approvals: state.approvals.map((item) =>
|
|
item.id === id ? toApprovalItem(updated) : item,
|
|
),
|
|
}));
|
|
},
|
|
async reject(id: string, reviewNote?: string) {
|
|
const current = get().approvals.find((item) => item.id === id);
|
|
if (!current) {
|
|
return;
|
|
}
|
|
|
|
const updated = await updateApprovalState(id, current.workspaceId, 'rejected', reviewNote);
|
|
set((state) => ({
|
|
approvals: state.approvals.map((item) =>
|
|
item.id === id ? toApprovalItem(updated) : item,
|
|
),
|
|
}));
|
|
},
|
|
}));
|