diff --git a/src/stores/storeEvents.ts b/src/stores/storeEvents.ts new file mode 100644 index 0000000..862fb53 --- /dev/null +++ b/src/stores/storeEvents.ts @@ -0,0 +1,52 @@ +/** + * Store Events + * + * Zustand-based event store for cross-store communication without tight coupling. + * Uses Zustand's built-in subscription system to emit and react to events. + */ + +import { create } from "zustand"; + +interface EventState { + // Event counters - incrementing these triggers subscriptions + patternDeletedCount: number; + + // Actions to emit events + emitPatternDeleted: () => void; +} + +/** + * Event store using Zustand for cross-store communication. + * Stores can emit events by calling actions, and subscribe to events using Zustand's subscribe. + */ +export const useEventStore = create((set) => ({ + patternDeletedCount: 0, + + emitPatternDeleted: () => { + set((state) => ({ patternDeletedCount: state.patternDeletedCount + 1 })); + }, +})); + +/** + * Subscribe to the pattern deleted event. + * + * The subscription remains active until the returned unsubscribe function is called. + * If the unsubscribe function is not called, the listener will persist for the + * lifetime of the event store (typically the lifetime of the application). + * + * Call the returned unsubscribe function when the listener is no longer needed, + * especially for short-lived components or non-module-level subscriptions. + * + * @param callback - Function to call when the event is emitted. + * @returns Unsubscribe function that removes the listener when invoked. + */ +export const onPatternDeleted = (callback: () => void): (() => void) => { + let prevCount = useEventStore.getState().patternDeletedCount; + + return useEventStore.subscribe((state) => { + if (state.patternDeletedCount !== prevCount) { + prevCount = state.patternDeletedCount; + callback(); + } + }); +}; diff --git a/src/stores/useMachineCacheStore.ts b/src/stores/useMachineCacheStore.ts index f13899d..b18d3ed 100644 --- a/src/stores/useMachineCacheStore.ts +++ b/src/stores/useMachineCacheStore.ts @@ -1,6 +1,7 @@ import { create } from "zustand"; import type { PesPatternData } from "../formats/import/pesImporter"; import { uuidToString } from "../services/PatternCacheService"; +import { onPatternDeleted } from "./storeEvents"; /** * Machine Cache Store @@ -192,3 +193,18 @@ export const useMachineCacheStore = create((set, get) => ({ }); }, })); + +// Subscribe to pattern deleted event. +// This subscription is intended to persist for the lifetime of the application, +// so the unsubscribe function returned by `onPatternDeleted` is intentionally +// not stored or called. +onPatternDeleted(() => { + try { + useMachineCacheStore.getState().clearResumeState(); + } catch (error) { + console.error( + "[MachineCacheStore] Failed to clear resume state on pattern deleted event:", + error, + ); + } +}); diff --git a/src/stores/useMachineStore.ts b/src/stores/useMachineStore.ts index 7ee6c57..b0c35db 100644 --- a/src/stores/useMachineStore.ts +++ b/src/stores/useMachineStore.ts @@ -13,7 +13,7 @@ import { SewingMachineError } from "../utils/errorCodeHelpers"; import { uuidToString } from "../services/PatternCacheService"; import { createStorageService } from "../platform"; import type { IStorageService } from "../platform/interfaces/IStorageService"; -import { usePatternStore } from "./usePatternStore"; +import { useEventStore } from "./storeEvents"; interface MachineState { // Service instances @@ -291,16 +291,8 @@ export const useMachineStore = create((set, get) => ({ sewingProgress: null, }); - // Clear uploaded pattern data in pattern store - usePatternStore.getState().clearUploadedPattern(); - - // Clear upload state in upload store - const { useMachineUploadStore } = await import("./useMachineUploadStore"); - useMachineUploadStore.getState().reset(); - - // Clear resume state in cache store - const { useMachineCacheStore } = await import("./useMachineCacheStore"); - useMachineCacheStore.getState().clearResumeState(); + // Emit pattern deleted event for other stores to react + useEventStore.getState().emitPatternDeleted(); await refreshStatus(); } catch (err) { diff --git a/src/stores/useMachineUploadStore.ts b/src/stores/useMachineUploadStore.ts index ce4ac3a..14c711f 100644 --- a/src/stores/useMachineUploadStore.ts +++ b/src/stores/useMachineUploadStore.ts @@ -1,6 +1,7 @@ import { create } from "zustand"; import type { PesPatternData } from "../formats/import/pesImporter"; import { uuidToString } from "../services/PatternCacheService"; +import { onPatternDeleted } from "./storeEvents"; /** * Machine Upload Store @@ -126,3 +127,18 @@ export const useMachineUploadStore = create((set) => ({ set({ uploadProgress: 0, isUploading: false }); }, })); + +// Subscribe to pattern deleted event. +// This subscription is intended to persist for the lifetime of the application, +// so the unsubscribe function returned by `onPatternDeleted` is intentionally +// not stored or called. +onPatternDeleted(() => { + try { + useMachineUploadStore.getState().reset(); + } catch (error) { + console.error( + "[MachineUploadStore] Failed to reset on pattern deleted event:", + error, + ); + } +}); diff --git a/src/stores/usePatternStore.ts b/src/stores/usePatternStore.ts index 94f568b..610fe34 100644 --- a/src/stores/usePatternStore.ts +++ b/src/stores/usePatternStore.ts @@ -1,5 +1,6 @@ import { create } from "zustand"; import type { PesPatternData } from "../formats/import/pesImporter"; +import { onPatternDeleted } from "./storeEvents"; interface PatternState { // Original pattern (pre-upload) @@ -121,3 +122,18 @@ export const useUploadedPatternOffset = () => usePatternStore((state) => state.uploadedPatternOffset); export const usePatternRotation = () => usePatternStore((state) => state.patternRotation); + +// Subscribe to pattern deleted event. +// This subscription is intended to persist for the lifetime of the application, +// so the unsubscribe function returned by `onPatternDeleted` is intentionally +// not stored or called. +onPatternDeleted(() => { + try { + usePatternStore.getState().clearUploadedPattern(); + } catch (error) { + console.error( + "[PatternStore] Failed to clear uploaded pattern on pattern deleted event:", + error, + ); + } +});