diff --git a/packages/core/config/src/lib/constants/store.ts b/packages/core/config/src/lib/constants/store.ts index 88b44ad1..af2d832e 100755 --- a/packages/core/config/src/lib/constants/store.ts +++ b/packages/core/config/src/lib/constants/store.ts @@ -9,6 +9,7 @@ export const STORE: Readonly = { authnState: 'authnStateV1', localeState: 'localeStateV1', routerState: 'routerStateV1', + timezoneState: 'timezoneStateV1', }, config: { app: { diff --git a/packages/core/state/src/lib/+state/timezone/index.ts b/packages/core/state/src/lib/+state/timezone/index.ts new file mode 100644 index 00000000..05d33417 --- /dev/null +++ b/packages/core/state/src/lib/+state/timezone/index.ts @@ -0,0 +1,3 @@ +export { TimezoneEffects } from './timezone.effects'; +export { TimezoneFacade } from './timezone.facade'; +export { timezoneReducer } from './timezone.reducer'; diff --git a/packages/core/state/src/lib/+state/timezone/timezone.actions.ts b/packages/core/state/src/lib/+state/timezone/timezone.actions.ts new file mode 100644 index 00000000..f6fa1ce7 --- /dev/null +++ b/packages/core/state/src/lib/+state/timezone/timezone.actions.ts @@ -0,0 +1,21 @@ +import { createAction, props } from '@ngrx/store'; + +import { + IIoRestorecommerceResourcebaseReadRequest, + IoRestorecommerceTimezoneTimezone, +} from '@console-core/graphql'; + +export const timezoneReadRequest = createAction( + '[TIMEZONE] Read request', + props<{ payload: IIoRestorecommerceResourcebaseReadRequest }>() +); + +export const timezoneReadRequestSuccess = createAction( + '[TIMEZONE] Read request success', + props<{ payload: IoRestorecommerceTimezoneTimezone[] }>() +); + +export const timezoneReadRequestFail = createAction( + '[TIMEZONE] Read request fail', + props<{ error: string }>() +); diff --git a/packages/core/state/src/lib/+state/timezone/timezone.effects.ts b/packages/core/state/src/lib/+state/timezone/timezone.effects.ts new file mode 100644 index 00000000..d8c19cf7 --- /dev/null +++ b/packages/core/state/src/lib/+state/timezone/timezone.effects.ts @@ -0,0 +1,65 @@ +import { Injectable } from '@angular/core'; +import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { catchError, map, of, switchMap, tap } from 'rxjs'; + +import { IoRestorecommerceTimezoneTimezone } from '@console-core/graphql'; +import { ENotificationTypes } from '@console-core/types'; + +import { TimezoneService } from '../../services'; +import { AppFacade } from '../app'; + +import * as timezoneActions from './timezone.actions'; + +@Injectable() +export class TimezoneEffects { + timezoneReadRequest$ = createEffect(() => { + return this.actions$.pipe( + ofType(timezoneActions.timezoneReadRequest), + switchMap(({ payload }) => + this.timezoneService.read(payload).pipe( + map((result) => { + const data = result?.data?.master_data?.timezone?.Read?.details; + + if (data?.operationStatus?.code !== 200 || !data?.items?.length) { + return timezoneActions.timezoneReadRequestFail({ + error: 'unknown error', + }); + } + + return timezoneActions.timezoneReadRequestSuccess({ + payload: data?.items.map( + (item) => item.payload as IoRestorecommerceTimezoneTimezone + ), + }); + }), + catchError((error: Error) => + of( + timezoneActions.timezoneReadRequestFail({ error: error.message }) + ) + ) + ) + ) + ); + }); + + handleNotificationErrors$ = createEffect( + () => { + return this.actions$.pipe( + ofType(timezoneActions.timezoneReadRequestFail), + tap(({ error }) => { + this.appFacade.addNotification({ + content: error ?? 'unknown error', + type: ENotificationTypes.ERROR, + }); + }) + ); + }, + { dispatch: false } + ); + + constructor( + private readonly actions$: Actions, + private readonly appFacade: AppFacade, + private readonly timezoneService: TimezoneService + ) {} +} diff --git a/packages/core/state/src/lib/+state/timezone/timezone.facade.ts b/packages/core/state/src/lib/+state/timezone/timezone.facade.ts new file mode 100644 index 00000000..a502b364 --- /dev/null +++ b/packages/core/state/src/lib/+state/timezone/timezone.facade.ts @@ -0,0 +1,35 @@ +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; + +import { IIoRestorecommerceResourcebaseReadRequest } from '@console-core/graphql'; + +import * as timezoneActions from './timezone.actions'; +import * as timezoneSelectors from './timezone.selectors'; + +@Injectable() +export class TimezoneFacade { + // Selectors + readonly timezoneIds$ = this.store.select( + timezoneSelectors.selectTimezoneIds + ); + readonly timezoneEntities$ = this.store.select( + timezoneSelectors.selectTimezoneEntities + ); + readonly allTimezones$ = this.store.select( + timezoneSelectors.selectAllTimezones + ); + readonly timezoneTotal$ = this.store.select( + timezoneSelectors.selectTimezoneTotal + ); + readonly actionStatus$ = this.store.select( + timezoneSelectors.selectActionStatus + ); + readonly error$ = this.store.select(timezoneSelectors.selectError); + + // Actions + readonly timezoneReadRequest = ( + payload: IIoRestorecommerceResourcebaseReadRequest + ) => this.store.dispatch(timezoneActions.timezoneReadRequest({ payload })); + + constructor(private readonly store: Store) {} +} diff --git a/packages/core/state/src/lib/+state/timezone/timezone.reducer.ts b/packages/core/state/src/lib/+state/timezone/timezone.reducer.ts new file mode 100644 index 00000000..66211b7c --- /dev/null +++ b/packages/core/state/src/lib/+state/timezone/timezone.reducer.ts @@ -0,0 +1,48 @@ +import { EntityAdapter, createEntityAdapter } from '@ngrx/entity'; +import { Action, createReducer, on } from '@ngrx/store'; + +import { IIoRestorecommerceTimezoneTimezone } from '@console-core/graphql'; +import { EActionStatus, ITimezoneState } from '@console-core/types'; + +import * as timezoneActions from './timezone.actions'; + +export const adapter: EntityAdapter = + createEntityAdapter(); + +export const initialState: ITimezoneState = adapter.getInitialState({ + selectedId: null, + actionStatus: EActionStatus.INIT, + error: null, +}); + +const reducer = createReducer( + initialState, + on( + timezoneActions.timezoneReadRequest, + (state): ITimezoneState => ({ + ...state, + actionStatus: EActionStatus.CREATED, + }) + ), + on( + timezoneActions.timezoneReadRequestSuccess, + (state, { payload }): ITimezoneState => + adapter.setAll(payload, { + ...state, + actionStatus: EActionStatus.SUCCEEDED, + }) + ), + on( + timezoneActions.timezoneReadRequestFail, + (state, { error }): ITimezoneState => ({ + ...state, + actionStatus: EActionStatus.FAILED, + error, + }) + ) +); + +export const timezoneReducer = ( + state: ITimezoneState | undefined, + action: Action +) => reducer(state, action); diff --git a/packages/core/state/src/lib/+state/timezone/timezone.selectors.ts b/packages/core/state/src/lib/+state/timezone/timezone.selectors.ts new file mode 100644 index 00000000..5aea3228 --- /dev/null +++ b/packages/core/state/src/lib/+state/timezone/timezone.selectors.ts @@ -0,0 +1,34 @@ +import { createFeatureSelector, createSelector } from '@ngrx/store'; + +import { STORE } from '@console-core/config'; +import { ITimezoneState } from '@console-core/types'; + +import { adapter } from './timezone.reducer'; + +export const selectTimezone = createFeatureSelector( + STORE.states.timezoneState +); + +const { selectIds, selectEntities, selectAll, selectTotal } = + adapter.getSelectors(); + +export const selectTimezoneIds = createSelector(selectTimezone, selectIds); + +export const selectTimezoneEntities = createSelector( + selectTimezone, + selectEntities +); + +export const selectAllTimezones = createSelector(selectTimezone, selectAll); + +export const selectTimezoneTotal = createSelector(selectTimezone, selectTotal); + +export const selectError = createSelector( + selectTimezone, + (state: ITimezoneState) => state.error +); + +export const selectActionStatus = createSelector( + selectTimezone, + (state: ITimezoneState) => state.actionStatus +); diff --git a/packages/core/state/src/lib/core-state.module.ts b/packages/core/state/src/lib/core-state.module.ts index b116abeb..49a8b8cd 100644 --- a/packages/core/state/src/lib/core-state.module.ts +++ b/packages/core/state/src/lib/core-state.module.ts @@ -19,8 +19,10 @@ import { LocaleFacade, localeReducer, RouterFacade, + TimezoneEffects, + TimezoneFacade, + timezoneReducer, } from './+state'; -import { AccountService, ApiService } from './services'; const facades = [ AccountFacade, @@ -28,8 +30,8 @@ const facades = [ AuthnFacade, LocaleFacade, RouterFacade, + TimezoneFacade, ]; -const services = [ApiService, AccountService]; @NgModule({ imports: [ @@ -41,8 +43,10 @@ const services = [ApiService, AccountService]; EffectsModule.forFeature([AuthnEffects]), StoreModule.forFeature(STORE.states.localeState, localeReducer), EffectsModule.forFeature([LocaleEffects]), + StoreModule.forFeature(STORE.states.timezoneState, timezoneReducer), + EffectsModule.forFeature([TimezoneEffects]), StoreModule.forFeature(STORE.states.routerState, fromRouter.routerReducer), ], - providers: [...facades, ...services], + providers: [...facades], }) export class CoreStateModule {} diff --git a/packages/core/state/src/lib/services/master-data/timezone.service.ts b/packages/core/state/src/lib/services/master-data/timezone.service.ts index 50f5a7b6..def990df 100644 --- a/packages/core/state/src/lib/services/master-data/timezone.service.ts +++ b/packages/core/state/src/lib/services/master-data/timezone.service.ts @@ -16,7 +16,7 @@ export class TimezoneService { private readonly masterDataTimezoneReadGQL: MasterDataTimezoneReadGQL ) {} - timezoneRead( + read( payload: IIoRestorecommerceResourcebaseReadRequest ): Observable> { return this.masterDataTimezoneReadGQL.fetch({ diff --git a/packages/core/types/src/lib/interfaces/state/index.ts b/packages/core/types/src/lib/interfaces/state/index.ts index 6ab614ab..129b8375 100644 --- a/packages/core/types/src/lib/interfaces/state/index.ts +++ b/packages/core/types/src/lib/interfaces/state/index.ts @@ -4,3 +4,4 @@ export * from './authn.state'; export * from './locale.state'; export * from './router.state'; export * from './store.state'; +export * from './timezone.state'; diff --git a/packages/core/types/src/lib/interfaces/state/timezone.state.ts b/packages/core/types/src/lib/interfaces/state/timezone.state.ts new file mode 100644 index 00000000..3f7de711 --- /dev/null +++ b/packages/core/types/src/lib/interfaces/state/timezone.state.ts @@ -0,0 +1,11 @@ +import { EntityState } from '@ngrx/entity'; + +import { IIoRestorecommerceTimezoneTimezone } from '@console-core/graphql'; + +import { IBaseStore } from './store.state'; + +export interface ITimezoneState + extends EntityState, + IBaseStore { + selectedId: string | null; +} diff --git a/packages/core/types/src/lib/interfaces/store.ts b/packages/core/types/src/lib/interfaces/store.ts index 0028f55a..b0a1dc73 100644 --- a/packages/core/types/src/lib/interfaces/store.ts +++ b/packages/core/types/src/lib/interfaces/store.ts @@ -5,6 +5,7 @@ export interface IStoreConstant { readonly authnState: 'authnStateV1'; readonly localeState: 'localeStateV1'; readonly routerState: 'routerStateV1'; + readonly timezoneState: 'timezoneStateV1'; }; readonly config: { readonly app: { diff --git a/packages/core/types/src/lib/types/new-notification.ts b/packages/core/types/src/lib/types/new-notification.ts index 330d96e5..7ea587cf 100644 --- a/packages/core/types/src/lib/types/new-notification.ts +++ b/packages/core/types/src/lib/types/new-notification.ts @@ -1,3 +1,3 @@ import { INotification } from '../interfaces'; -export type TNewNotification = Omit; +export type TNewNotification = Pick;