72 lines
2.4 KiB
TypeScript
72 lines
2.4 KiB
TypeScript
import { create } from "zustand";
|
|
|
|
export type SyncProjectProgress = {
|
|
projectId: string;
|
|
total: number;
|
|
completed: number;
|
|
phase: "pending" | "uploading" | "saving" | "done" | "error" | "conflict";
|
|
message?: string;
|
|
draftCount?: number;
|
|
};
|
|
|
|
type SyncProgressStore = {
|
|
syncingProjects: Record<string, SyncProjectProgress>;
|
|
setProjectProgress: (projectId: string, patch: Partial<SyncProjectProgress> | null) => void;
|
|
incrementProjectCompleted: (projectId: string) => void;
|
|
clearAll: () => void;
|
|
isAnySyncing: () => boolean;
|
|
};
|
|
|
|
export const useSyncProgressStore = create<SyncProgressStore>((set, get) => ({
|
|
syncingProjects: {},
|
|
setProjectProgress: (projectId, patch) =>
|
|
set((state) => {
|
|
if (!patch) {
|
|
const next = { ...state.syncingProjects };
|
|
delete next[projectId];
|
|
return { syncingProjects: next };
|
|
}
|
|
const current = state.syncingProjects[projectId] || {
|
|
projectId,
|
|
total: 0,
|
|
completed: 0,
|
|
phase: "uploading",
|
|
};
|
|
return {
|
|
syncingProjects: {
|
|
...state.syncingProjects,
|
|
[projectId]: { ...current, ...patch },
|
|
},
|
|
};
|
|
}),
|
|
incrementProjectCompleted: (projectId) =>
|
|
set((state) => {
|
|
const current = state.syncingProjects[projectId];
|
|
if (!current) return state;
|
|
return {
|
|
syncingProjects: {
|
|
...state.syncingProjects,
|
|
[projectId]: {
|
|
...current,
|
|
completed: Math.min(current.total, current.completed + 1),
|
|
},
|
|
},
|
|
};
|
|
}),
|
|
clearAll: () => set({ syncingProjects: {} }),
|
|
isAnySyncing: () => {
|
|
const list = Object.values(get().syncingProjects);
|
|
return list.some((item) => item.phase !== "done");
|
|
},
|
|
}));
|
|
|
|
if (typeof window !== "undefined") {
|
|
window.addEventListener("beforeunload", (event) => {
|
|
if (useSyncProgressStore.getState().isAnySyncing()) {
|
|
event.preventDefault();
|
|
event.returnValue = "画布正在同步至云端,请勿关闭页面。";
|
|
return "画布正在同步至云端,请勿关闭页面。";
|
|
}
|
|
});
|
|
}
|