import { createReduxStore, dispatch, register, useSelect, select } from '@wordpress/data'; const storeName = 'filter-ai/generate-params-store'; /** * Generation params stored per block. Named GenerationParams (not StreamArgs) * to avoid confusion with the StreamArgs type in streamIntoBlock.ts, which */ export type GenerationParams = { prompt: string; keywords: string[]; length: string; service?: string; blockName: string; /** * All clientIds produced by the last generation (first + any siblings from a * multi-block result). Stored so that Regenerate can replace the entire * previous generation — not just the first block — via replaceBlocks(). */ generatedClientIds: string[]; }; type State = Record; // clientId → params type Action = | { type: 'STORE_PARAMS'; clientId: string; params: GenerationParams } | { type: 'CLEAR_PARAMS'; clientId: string }; const store = createReduxStore(storeName, { reducer: (state: State = {}, action: Action): State => { switch (action.type) { case 'STORE_PARAMS': return { ...state, [action.clientId]: action.params }; case 'CLEAR_PARAMS': { const next = { ...state }; delete next[action.clientId]; return next; } default: return state; } }, actions: { storeParams: (clientId: string, params: GenerationParams): Action => ({ type: 'STORE_PARAMS', clientId, params, }), clearParams: (clientId: string): Action => ({ type: 'CLEAR_PARAMS', clientId, }), }, selectors: { getParams: (state: State, clientId: string): GenerationParams | undefined => state[clientId], }, }); // Guard against double-registration in HMR / multi-import scenarios. // `select(storeName)` returns undefined when the store hasn't been registered yet. if (!select(storeName)) { register(store); } /** Store generation params for a block after a successful generation. */ export const storeGenerationParams = (clientId: string, params: GenerationParams): void => { dispatch(store).storeParams(clientId, params); }; /** Remove stored params for a block (e.g. when the original block is replaced). */ export const clearGenerationParams = (clientId: string): void => { dispatch(store).clearParams(clientId); }; // Narrow selector type derived from the selectors object — avoids repeated inline casts. type ParamsSelectors = { getParams: (clientId: string) => GenerationParams | undefined }; /** Read params for a block directly (non-reactive, for use in async functions). */ export const getGenerationParams = (clientId: string): GenerationParams | undefined => (select(store) as unknown as ParamsSelectors).getParams(clientId); /** * React hook — returns params for the given clientId, or undefined if none stored. * Re-renders the component whenever the stored params for this clientId change. */ export const useGenerationParams = (clientId: string | undefined): GenerationParams | undefined => useSelect( (selectFn) => { if (!clientId) return undefined; return (selectFn(store) as unknown as ParamsSelectors).getParams(clientId); }, [clientId] );