From c66577b386ae31fd260394985b48ceff8801abc1 Mon Sep 17 00:00:00 2001 From: daboudii Date: Fri, 14 Mar 2025 09:40:01 +0200 Subject: [PATCH 1/5] feat: add setInitial for --- libs/ngrx-toolkit/src/lib/with-call-state.spec.ts | 14 +++++++++++++- libs/ngrx-toolkit/src/lib/with-call-state.ts | 15 ++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/libs/ngrx-toolkit/src/lib/with-call-state.spec.ts b/libs/ngrx-toolkit/src/lib/with-call-state.spec.ts index 8c86e547..05cfee59 100644 --- a/libs/ngrx-toolkit/src/lib/with-call-state.spec.ts +++ b/libs/ngrx-toolkit/src/lib/with-call-state.spec.ts @@ -1,5 +1,5 @@ import { patchState, signalStore } from '@ngrx/signals'; -import { setLoaded, setLoading, withCallState } from './with-call-state'; +import { setLoaded, setLoading, setInitial, withCallState } from './with-call-state'; describe('withCallState', () => { it('should use and update a callState', () => { @@ -12,6 +12,18 @@ describe('withCallState', () => { expect(dataStore.loading()).toBe(true); }); + it('should reinitialize a callState', () => { + const DataStore = signalStore({ protectedState: false }, withCallState()); + const dataStore = new DataStore(); + + patchState(dataStore, setLoading()); + + patchState(dataStore, setInitial()); + + expect(dataStore.callState()).toBe('init'); + expect(dataStore.initial()).toBe(true); + }); + it('should use the callState for a collection', () => { const DataStore = signalStore( { protectedState: false }, diff --git a/libs/ngrx-toolkit/src/lib/with-call-state.ts b/libs/ngrx-toolkit/src/lib/with-call-state.ts index d1961342..400f2115 100644 --- a/libs/ngrx-toolkit/src/lib/with-call-state.ts +++ b/libs/ngrx-toolkit/src/lib/with-call-state.ts @@ -18,6 +18,7 @@ export type NamedCallStateSlice = { }; export type CallStateSignals = { + initial: Signal; loading: Signal; loaded: Signal; error: Signal; @@ -35,6 +36,7 @@ export function getCallStateKeys(config?: { collection?: string }) { const prop = config?.collection; return { callStateKey: prop ? `${config.collection}CallState` : 'callState', + initialKey: prop ? `${config.collection}Initial` : 'init', loadingKey: prop ? `${config.collection}Loading` : 'loading', loadedKey: prop ? `${config.collection}Loaded` : 'loaded', errorKey: prop ? `${config.collection}Error` : 'error', @@ -60,7 +62,7 @@ export function withCallState(): SignalStoreFeature< export function withCallState(config?: { collection: Collection; }): SignalStoreFeature { - const { callStateKey, errorKey, loadedKey, loadingKey } = + const { callStateKey, errorKey, loadedKey, loadingKey, initialKey } = getCallStateKeys(config); return signalStoreFeature( @@ -69,6 +71,7 @@ export function withCallState(config?: { const callState = state[callStateKey] as Signal; return { + [initialKey]: computed(() => callState() === 'init'), [loadingKey]: computed(() => callState() === 'loading'), [loadedKey]: computed(() => callState() === 'loaded'), [errorKey]: computed(() => { @@ -80,6 +83,16 @@ export function withCallState(config?: { ); } +export function setInitial( + prop?: Prop +): SetCallState { + if (prop) { + return { [`${prop}CallState`]: 'init' } as SetCallState; + } + + return { callState: 'init' } as SetCallState; +} + export function setLoading( prop?: Prop ): SetCallState { From 0d946f33bfa6c036b5c92089d59c1e0e692dd551 Mon Sep 17 00:00:00 2001 From: daboudii Date: Fri, 14 Mar 2025 09:43:13 +0200 Subject: [PATCH 2/5] fix: typo --- libs/ngrx-toolkit/src/lib/with-call-state.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ngrx-toolkit/src/lib/with-call-state.ts b/libs/ngrx-toolkit/src/lib/with-call-state.ts index 400f2115..ead21bd8 100644 --- a/libs/ngrx-toolkit/src/lib/with-call-state.ts +++ b/libs/ngrx-toolkit/src/lib/with-call-state.ts @@ -18,7 +18,7 @@ export type NamedCallStateSlice = { }; export type CallStateSignals = { - initial: Signal; + init: Signal; loading: Signal; loaded: Signal; error: Signal; From 81dbe1d8782dde740090b1c4c31e5b6e7729f7e6 Mon Sep 17 00:00:00 2001 From: daboudii Date: Fri, 14 Mar 2025 09:47:11 +0200 Subject: [PATCH 3/5] fix: test --- libs/ngrx-toolkit/src/lib/with-call-state.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ngrx-toolkit/src/lib/with-call-state.spec.ts b/libs/ngrx-toolkit/src/lib/with-call-state.spec.ts index 05cfee59..c09b82aa 100644 --- a/libs/ngrx-toolkit/src/lib/with-call-state.spec.ts +++ b/libs/ngrx-toolkit/src/lib/with-call-state.spec.ts @@ -21,7 +21,7 @@ describe('withCallState', () => { patchState(dataStore, setInitial()); expect(dataStore.callState()).toBe('init'); - expect(dataStore.initial()).toBe(true); + expect(dataStore.init()).toBe(true); }); it('should use the callState for a collection', () => { From e6ab8036cb317ac1d0f123e7139d9fbb90ea7c6a Mon Sep 17 00:00:00 2001 From: daboudii Date: Fri, 14 Mar 2025 22:17:48 +0200 Subject: [PATCH 4/5] Revert 'feat: add setInitial for withCallState' --- libs/ngrx-toolkit/src/lib/with-call-state.spec.ts | 14 +------------- libs/ngrx-toolkit/src/lib/with-call-state.ts | 15 +-------------- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/libs/ngrx-toolkit/src/lib/with-call-state.spec.ts b/libs/ngrx-toolkit/src/lib/with-call-state.spec.ts index c09b82aa..8c86e547 100644 --- a/libs/ngrx-toolkit/src/lib/with-call-state.spec.ts +++ b/libs/ngrx-toolkit/src/lib/with-call-state.spec.ts @@ -1,5 +1,5 @@ import { patchState, signalStore } from '@ngrx/signals'; -import { setLoaded, setLoading, setInitial, withCallState } from './with-call-state'; +import { setLoaded, setLoading, withCallState } from './with-call-state'; describe('withCallState', () => { it('should use and update a callState', () => { @@ -12,18 +12,6 @@ describe('withCallState', () => { expect(dataStore.loading()).toBe(true); }); - it('should reinitialize a callState', () => { - const DataStore = signalStore({ protectedState: false }, withCallState()); - const dataStore = new DataStore(); - - patchState(dataStore, setLoading()); - - patchState(dataStore, setInitial()); - - expect(dataStore.callState()).toBe('init'); - expect(dataStore.init()).toBe(true); - }); - it('should use the callState for a collection', () => { const DataStore = signalStore( { protectedState: false }, diff --git a/libs/ngrx-toolkit/src/lib/with-call-state.ts b/libs/ngrx-toolkit/src/lib/with-call-state.ts index ead21bd8..d1961342 100644 --- a/libs/ngrx-toolkit/src/lib/with-call-state.ts +++ b/libs/ngrx-toolkit/src/lib/with-call-state.ts @@ -18,7 +18,6 @@ export type NamedCallStateSlice = { }; export type CallStateSignals = { - init: Signal; loading: Signal; loaded: Signal; error: Signal; @@ -36,7 +35,6 @@ export function getCallStateKeys(config?: { collection?: string }) { const prop = config?.collection; return { callStateKey: prop ? `${config.collection}CallState` : 'callState', - initialKey: prop ? `${config.collection}Initial` : 'init', loadingKey: prop ? `${config.collection}Loading` : 'loading', loadedKey: prop ? `${config.collection}Loaded` : 'loaded', errorKey: prop ? `${config.collection}Error` : 'error', @@ -62,7 +60,7 @@ export function withCallState(): SignalStoreFeature< export function withCallState(config?: { collection: Collection; }): SignalStoreFeature { - const { callStateKey, errorKey, loadedKey, loadingKey, initialKey } = + const { callStateKey, errorKey, loadedKey, loadingKey } = getCallStateKeys(config); return signalStoreFeature( @@ -71,7 +69,6 @@ export function withCallState(config?: { const callState = state[callStateKey] as Signal; return { - [initialKey]: computed(() => callState() === 'init'), [loadingKey]: computed(() => callState() === 'loading'), [loadedKey]: computed(() => callState() === 'loaded'), [errorKey]: computed(() => { @@ -83,16 +80,6 @@ export function withCallState(config?: { ); } -export function setInitial( - prop?: Prop -): SetCallState { - if (prop) { - return { [`${prop}CallState`]: 'init' } as SetCallState; - } - - return { callState: 'init' } as SetCallState; -} - export function setLoading( prop?: Prop ): SetCallState { From 9ffabead00beb87dc4d3ccdb2f8c05311c66008e Mon Sep 17 00:00:00 2001 From: daboudii Date: Fri, 14 Mar 2025 22:22:29 +0200 Subject: [PATCH 5/5] feat:(withReset) reset only subset of the state --- libs/ngrx-toolkit/src/lib/with-reset.spec.ts | 29 ++++++++++++++++++++ libs/ngrx-toolkit/src/lib/with-reset.ts | 14 +++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/libs/ngrx-toolkit/src/lib/with-reset.spec.ts b/libs/ngrx-toolkit/src/lib/with-reset.spec.ts index fa31fd5b..f1c25dd3 100644 --- a/libs/ngrx-toolkit/src/lib/with-reset.spec.ts +++ b/libs/ngrx-toolkit/src/lib/with-reset.spec.ts @@ -109,4 +109,33 @@ describe('withReset', () => { 'Cannot set reset state, since store is not configured with withReset()' ); }); + + it('should reset one slice of state to initial', () => { + const { store } = setup(); + + store.changeUser(2, 'John'); + store.changeAddress('Vilnus', 'LT-00104'); + expect(getState(store)).toEqual({ + user: { id: 2, name: 'John' }, + address: { city: 'Vilnus', zip: 'LT-00104' }, + }); + store.resetSlice('address'); + expect(getState(store)).toEqual({ + user: { id: 2, name: 'John' }, + address: { city: 'Vienna', zip: '1010' }, + }); + }); + + it('should reset both slice of state to initial', () => { + const { store, initialState } = setup(); + + store.changeUser(2, 'John'); + store.changeAddress('Vilnus', 'LT-00104'); + expect(getState(store)).toEqual({ + user: { id: 2, name: 'John' }, + address: { city: 'Vilnus', zip: 'LT-00104' }, + }); + store.resetSlice(['address', 'user']); + expect(getState(store)).toStrictEqual(initialState); + }); }); diff --git a/libs/ngrx-toolkit/src/lib/with-reset.ts b/libs/ngrx-toolkit/src/lib/with-reset.ts index 1bb05941..e0331882 100644 --- a/libs/ngrx-toolkit/src/lib/with-reset.ts +++ b/libs/ngrx-toolkit/src/lib/with-reset.ts @@ -10,6 +10,7 @@ import { export type PublicMethods = { resetState(): void; + resetSlice(slice: string | string[]): void; }; /** @@ -20,13 +21,24 @@ export type PublicMethods = { */ export function withReset() { return signalStoreFeature( - withProps(() => ({ _resetState: { value: {} } })), + withProps(() => ({ _resetState: { value: {} as Record } })), withMethods((store): PublicMethods => { // workaround to TS excessive property check const methods = { resetState() { patchState(store, store._resetState.value); }, + resetSlice(slice: string | string[]) { + patchState(store, (state) => ({ + ...state, + ...(typeof slice === 'string' + ? { [slice]: store._resetState.value[slice] } + : slice.reduce((acc, key) => { + acc[key] = store._resetState.value[key]; + return acc; + }, {} as Record)), + })); + }, __setResetState__(state: object) { store._resetState.value = state; },