Initial ecommerce standalone package

This commit is contained in:
2026-06-10 14:06:16 +08:00
commit 3d98933e24
241 changed files with 135283 additions and 0 deletions
+121
View File
@@ -0,0 +1,121 @@
import { create } from "zustand";
import type { WebGenerationPreviewTask } from "../types";
export type QueueItemStatus = "pending" | "running" | "completed" | "failed" | "cancelled";
export interface GenerationQueueItem {
id: string;
taskId?: string;
title: string;
type: "image" | "video" | "agent" | "digital-human" | "character-mix" | "ecommerce-video";
status: QueueItemStatus;
progress: number;
prompt: string;
createdAt: number;
sourceView: string; // which page created this: "ecommerce", "workbench", "canvas", "agent"
resultUrl?: string | null;
error?: string | null;
params?: Record<string, unknown>;
}
interface PersistedQueueSnapshot {
version: 1;
items: GenerationQueueItem[];
savedAt: number;
}
const STORAGE_KEY = "omniai:generation-queue";
const MAX_ITEMS = 80;
const STALE_MS = 2 * 60 * 60 * 1000; // 2 hours
function loadPersistedQueue(): GenerationQueueItem[] {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return [];
const snapshot = JSON.parse(raw) as PersistedQueueSnapshot;
if (Date.now() - (snapshot.savedAt || 0) > STALE_MS) {
localStorage.removeItem(STORAGE_KEY);
return [];
}
return snapshot.items.filter(
(item) => item.status === "pending" || item.status === "running",
);
} catch {
return [];
}
}
function persistQueue(items: GenerationQueueItem[]): void {
try {
const snapshot: PersistedQueueSnapshot = { version: 1, items, savedAt: Date.now() };
localStorage.setItem(STORAGE_KEY, JSON.stringify(snapshot));
} catch { /* quota exceeded */ }
}
interface GenerationStoreState {
queue: GenerationQueueItem[];
addTask: (item: GenerationQueueItem) => void;
updateTask: (id: string, patch: Partial<GenerationQueueItem>) => void;
removeTask: (id: string) => void;
getRunningTasks: () => GenerationQueueItem[];
getPendingTasks: () => GenerationQueueItem[];
getTasksByView: (sourceView: string) => GenerationQueueItem[];
clearTerminal: () => void;
}
function hashUserId(): string {
try {
const raw = localStorage.getItem("omniai-web-session");
if (!raw) return "anon";
const parsed = JSON.parse(raw) as { user?: { id?: number | string } };
return String(parsed?.user?.id || "anon");
} catch {
return "anon";
}
}
const initialQueue = loadPersistedQueue();
export const useGenerationStore = create<GenerationStoreState>((set, get) => ({
queue: initialQueue,
addTask: (item) => {
set((state) => {
const next = [item, ...state.queue].slice(0, MAX_ITEMS);
persistQueue(next.filter((i) => i.status === "pending" || i.status === "running"));
return { queue: next };
});
},
updateTask: (id, patch) => {
set((state) => {
const next = state.queue.map((item) =>
item.id === id ? { ...item, ...patch } : item,
);
persistQueue(next.filter((i) => i.status === "pending" || i.status === "running"));
return { queue: next };
});
},
removeTask: (id) => {
set((state) => {
const next = state.queue.filter((item) => item.id !== id);
persistQueue(next.filter((i) => i.status === "pending" || i.status === "running"));
return { queue: next };
});
},
getRunningTasks: () => get().queue.filter((i) => i.status === "running" || i.status === "pending"),
getPendingTasks: () => get().queue.filter((i) => i.status === "pending"),
getTasksByView: (sourceView) => get().queue.filter((i) => i.sourceView === sourceView),
clearTerminal: () => {
set((state) => {
const next = state.queue.filter(
(i) => i.status === "pending" || i.status === "running",
);
persistQueue(next);
return { queue: next };
});
},
}));