| import { create } from "zustand"; |
| import { persist, createJSONStorage } from "zustand/middleware"; |
|
|
| type ViewMode = "grid" | "list"; |
|
|
| export type HistoryItem = { |
| filename: string; |
| previewUrl: string; |
| maskCount: number; |
| uploadedAt: number; |
| }; |
|
|
| |
| function getOrCreateUserId(): string { |
| const key = "hr-user-id"; |
| let id = localStorage.getItem(key); |
| if (!id) { |
| id = typeof crypto !== "undefined" && crypto.randomUUID |
| ? crypto.randomUUID() |
| : `u-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`; |
| localStorage.setItem(key, id); |
| } |
| return id; |
| } |
|
|
| |
| type HistoryStore = { |
| userId: string; |
| sessionHistory: HistoryItem[]; |
| addToHistory: (item: HistoryItem) => void; |
| setSessionHistory: (items: HistoryItem[]) => void; |
| removeFromHistory: (filename: string) => void; |
| }; |
|
|
| export const useHistoryStore = create<HistoryStore>()( |
| persist( |
| (set) => ({ |
| userId: getOrCreateUserId(), |
| sessionHistory: [], |
| addToHistory: (item) => |
| set((state) => { |
| const withoutDupe = state.sessionHistory.filter( |
| (h) => h.filename !== item.filename, |
| ); |
| const cutoff = Date.now() - 30 * 24 * 60 * 60 * 1000; |
| const fresh = withoutDupe.filter((h) => h.uploadedAt > cutoff); |
| return { sessionHistory: [item, ...fresh].slice(0, 10) }; |
| }), |
| setSessionHistory: (items) => set({ sessionHistory: items }), |
| removeFromHistory: (filename) => |
| set((state) => ({ |
| sessionHistory: state.sessionHistory.filter((h) => h.filename !== filename), |
| })), |
| }), |
| { |
| name: "hr-history", |
| storage: createJSONStorage(() => localStorage), |
| }, |
| ), |
| ); |
|
|
| |
| type AppStore = { |
| previewImage: string | null; |
| uploadMessage: string | null; |
| openProductId: string | number | null; |
| viewMode: ViewMode; |
| segmentFilename: string | null; |
| maskCount: number | null; |
| segmentProgress: number; |
| accumulatedFilename: string | null; |
| setPreviewImage: (previewImage: string | null) => void; |
| setUploadMessage: (uploadMessage: string | null) => void; |
| setOpenProductId: (openProductId: string | number | null) => void; |
| setViewMode: (viewMode: ViewMode) => void; |
| setSegmentResult: (filename: string, maskCount: number) => void; |
| setSegmentProgress: (progress: number) => void; |
| setAccumulatedFilename: (filename: string | null) => void; |
| reset: () => void; |
| }; |
|
|
| const useAppStore = create<AppStore>()( |
| persist( |
| (set) => ({ |
| previewImage: null, |
| uploadMessage: null, |
| openProductId: null, |
| viewMode: "list", |
| segmentFilename: null, |
| maskCount: null, |
| segmentProgress: 0, |
| accumulatedFilename: null, |
| setPreviewImage: (previewImage) => set({ previewImage }), |
| setUploadMessage: (uploadMessage) => set({ uploadMessage }), |
| setOpenProductId: (openProductId) => set({ openProductId }), |
| setViewMode: (viewMode) => set({ viewMode }), |
| setSegmentResult: (segmentFilename, maskCount) => |
| set({ segmentFilename, maskCount }), |
| setSegmentProgress: (segmentProgress) => set({ segmentProgress }), |
| setAccumulatedFilename: (accumulatedFilename) => set({ accumulatedFilename }), |
| reset: () => |
| set({ |
| previewImage: null, |
| uploadMessage: null, |
| openProductId: null, |
| viewMode: "list", |
| segmentFilename: null, |
| maskCount: null, |
| segmentProgress: 0, |
| accumulatedFilename: null, |
| }), |
| }), |
| { |
| name: "hr-session", |
| storage: createJSONStorage(() => sessionStorage), |
| partialize: (state) => ({ |
| previewImage: state.previewImage, |
| segmentFilename: state.segmentFilename, |
| maskCount: state.maskCount, |
| accumulatedFilename: state.accumulatedFilename, |
| }), |
| }, |
| ), |
| ); |
|
|
| export default useAppStore; |
|
|