Skip to content

Commit

Permalink
chore:🌻 correct pah to import in effect
Browse files Browse the repository at this point in the history
  • Loading branch information
NsdHSO committed Oct 9, 2023
1 parent 15c821c commit c454b8d
Show file tree
Hide file tree
Showing 14 changed files with 329 additions and 14 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ node_modules
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
documentation.json

# misc
/.sass-cache
Expand Down
5 changes: 4 additions & 1 deletion ftx-ftm/src/lib/ftx-ftm/ftx-ftm.component.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<form
*ngIf="generateFormTrigger | async"
*ngIf="{
gene: generateFormTrigger | async,
formChange: formValueChanges$ | async
}"
[formGroup]="formData"
(ngSubmit)="submit()"
class="p-3 flex flex-col gap-5 bg-slate-200 ngx-forms-form-wrapper rounded-br-lg rounded-bl-lg shadow-lg"
Expand Down
26 changes: 23 additions & 3 deletions ftx-ftm/src/lib/ftx-ftm/ftx-ftm.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ import { CommonModule } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
Input,
inject,
Input,
} from '@angular/core';
import {
FormArray,
FormControl,
FormGroup,
ReactiveFormsModule,
} from '@angular/forms';
import { Store } from '@ngrx/store';
import { ButtonComponent, GenerateFormBuilderService } from 'ngx-ftx-forms';
import {
DataFormBuilder,
Expand All @@ -26,7 +27,9 @@ import {
SharedInputComponent,
SivanInputComponent,
} from 'ngx-ftx-shared';
import { of, tap } from 'rxjs';
import { debounceTime, of, shareReplay, tap, using } from 'rxjs';
import { infoUserValueChange } from '../../../../src/app/+state/info-user/info-user.actions';
import { selectInfoUserEntities } from '../../../../src/app/+state/info-user/info-user.selectors';
import {
GetTypePipe,
GetValueToShowPipe,
Expand Down Expand Up @@ -95,8 +98,13 @@ import {
})
export class FtxFtmComponent {
@Input({ required: true }) dataSource!: DataFormBuilder;

generateFormBuilderService = inject(GenerateFormBuilderService);

generativeService = inject(GenerativeService);

private readonly _store = inject(Store);

formData: FormGroup | FormControl | FormArray | any; //eslint-disable-line
generateFormTrigger = of('t').pipe(
tap(
Expand All @@ -107,9 +115,21 @@ export class FtxFtmComponent {
)
);

formValueChanges$ = using(
() =>
this.formData.valueChanges
.pipe(
debounceTime(200),
tap((value: any) => {
this._store.dispatch(infoUserValueChange(value));
})
)
.subscribe(),
() => this._store.select(selectInfoUserEntities)
).pipe(shareReplay());

public submit() {
console.log(this.formData?.getRawValue());

this.formData;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div
class="cursor-pointer w-16 bg-slate-100 rounded-full shadow-sm border"
class="cursor-pointer w-16 bg-slate-100 rounded-full shadow-sm border dark:bg-gray-800"
[ngClass]="{
'border-green-300': control.value,
'border-red-500': !control.value && control.disabled,
Expand Down
19 changes: 19 additions & 0 deletions src/app/+state/info-user/info-user.actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { createAction, props } from '@ngrx/store';
import { InfoUserEntity } from './info-user.models';
const prefixForm = 'FormDync';
export const initInfoUser = createAction('[InfoUser Page] Init');

export const loadInfoUserSuccess = createAction(
`[${prefixForm}/API] Load InfoUser Success`,
props<{ infoUser: InfoUserEntity[] }>()
);

export const infoUserValueChange = createAction(
`[${prefixForm}] Info User Changed`,
props<any>()
);

export const loadInfoUserFailure = createAction(
`[${prefixForm}/API] Load InfoUser Failure`,
props<{ error: any }>()
);
38 changes: 38 additions & 0 deletions src/app/+state/info-user/info-user.effects.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { TestBed } from '@angular/core/testing';
import { provideMockActions } from '@ngrx/effects/testing';
import { Action } from '@ngrx/store';
import { provideMockStore } from '@ngrx/store/testing';
import { hot } from 'jasmine-marbles';
import { Observable } from 'rxjs';
import * as InfoUserActions from './info-user.actions';
import { InfoUserEffects } from './info-user.effects';

describe('InfoUserEffects', () => {
let actions: Observable<Action>;
let effects: InfoUserEffects;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [],
providers: [
InfoUserEffects,
provideMockActions(() => actions),
provideMockStore(),
],
});

effects = TestBed.inject(InfoUserEffects);
});

describe('init$', () => {
it('should work', () => {
actions = hot('-a-|', { a: InfoUserActions.initInfoUser() });

const expected = hot('-a-|', {
a: InfoUserActions.loadInfoUserSuccess({ infoUser: [] }),
});

expect(effects.init$).toBeObservable(expected);
});
});
});
22 changes: 22 additions & 0 deletions src/app/+state/info-user/info-user.effects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Injectable, inject } from '@angular/core';
import { createEffect, Actions, ofType } from '@ngrx/effects';
import { switchMap, catchError, of } from 'rxjs';
import * as InfoUserActions from './info-user.actions';

@Injectable()
export class InfoUserEffects {
private actions$ = inject(Actions);

init$ = createEffect(() =>
this.actions$.pipe(
ofType(InfoUserActions.initInfoUser),
switchMap(() =>
of(InfoUserActions.loadInfoUserSuccess({ infoUser: [] }))
),
catchError((error) => {
console.error('Error', error);
return of(InfoUserActions.loadInfoUserFailure({ error }));
})
)
);
}
7 changes: 7 additions & 0 deletions src/app/+state/info-user/info-user.models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Interface for the 'InfoUser' data
*/
export interface InfoUserEntity {
id: string | number; // Primary ID
name: string;
}
41 changes: 41 additions & 0 deletions src/app/+state/info-user/info-user.reducer.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Action } from '@ngrx/store';

import * as InfoUserActions from './info-user.actions';
import { InfoUserEntity } from './info-user.models';
import {
InfoUserState,
initialInfoUserState,
infoReducer,
} from './info.reducer';

describe('InfoUser Reducer', () => {
const createInfoUserEntity = (id: string, name = ''): InfoUserEntity => ({
id,
name: name || `name-${id}`,
});

describe('valid InfoUser actions', () => {
it('loadInfoUserSuccess should return the list of known InfoUser', () => {
const infoUser = [
createInfoUserEntity('PRODUCT-AAA'),
createInfoUserEntity('PRODUCT-zzz'),
];
const action = InfoUserActions.loadInfoUserSuccess({ infoUser });

const result: InfoUserState = infoReducer(initialInfoUserState, action);

expect(result.loaded).toBe(true);
expect(result.ids.length).toBe(2);
});
});

describe('unknown action', () => {
it('should return the previous state', () => {
const action = {} as Action;

const result = infoReducer(initialInfoUserState, action);

expect(result).toBe(initialInfoUserState);
});
});
});
66 changes: 66 additions & 0 deletions src/app/+state/info-user/info-user.selectors.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { InfoUserEntity } from './info-user.models';
import {
infoUserAdapter,
InfoUserPartialState,
initialInfoUserState,
} from './info.reducer';
import * as InfoUserSelectors from './info-user.selectors';

describe('InfoUser Selectors', () => {
const ERROR_MSG = 'No Error Available';
const getInfoUserId = (it: InfoUserEntity) => it.id;
const createInfoUserEntity = (id: string, name = '') =>
({
id,
name: name || `name-${id}`,
} as InfoUserEntity);

let state: InfoUserPartialState;

beforeEach(() => {
state = {
infoUser: infoUserAdapter.setAll(
[
createInfoUserEntity('PRODUCT-AAA'),
createInfoUserEntity('PRODUCT-BBB'),
createInfoUserEntity('PRODUCT-CCC'),
],
{
...initialInfoUserState,
selectedId: 'PRODUCT-BBB',
error: ERROR_MSG,
loaded: true,
}
),
};
});

describe('InfoUser Selectors', () => {
it('selectAllInfoUser() should return the list of InfoUser', () => {
const results = InfoUserSelectors.selectAllInfoUser(state);
const selId = getInfoUserId(results[1]);

expect(results.length).toBe(3);
expect(selId).toBe('PRODUCT-BBB');
});

it('selectEntity() should return the selected Entity', () => {
const result = InfoUserSelectors.selectEntity(state) as InfoUserEntity;
const selId = getInfoUserId(result);

expect(selId).toBe('PRODUCT-BBB');
});

it('selectInfoUserLoaded() should return the current "loaded" status', () => {
const result = InfoUserSelectors.selectInfoUserLoaded(state);

expect(result).toBe(true);
});

it('selectInfoUserError() should return the current "error" state', () => {
const result = InfoUserSelectors.selectInfoUserError(state);

expect(result).toBe(ERROR_MSG);
});
});
});
44 changes: 44 additions & 0 deletions src/app/+state/info-user/info-user.selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { createFeatureSelector, createSelector } from '@ngrx/store';
import {
INFO_USER_FEATURE_KEY,
InfoUserState,
infoUserAdapter,
} from './info.reducer';

// Lookup the 'InfoUser' feature state managed by NgRx
export const selectInfoUserState = createFeatureSelector<InfoUserState>(
INFO_USER_FEATURE_KEY
);

const { selectAll, selectEntities } = infoUserAdapter.getSelectors();

export const selectInfoUserLoaded = createSelector(
selectInfoUserState,
(state: InfoUserState) => state.loaded
);

export const selectInfoUserError = createSelector(
selectInfoUserState,
(state: InfoUserState) => state.error
);

export const selectAllInfoUser = createSelector(
selectInfoUserState,
(state: InfoUserState) => selectAll(state)
);

export const selectInfoUserEntities = createSelector(
selectInfoUserState,
(state: InfoUserState) => selectEntities(state)
);

export const selectSelectedId = createSelector(
selectInfoUserState,
(state: InfoUserState) => state.selectedId
);

export const selectEntity = createSelector(
selectInfoUserEntities,
selectSelectedId,
(entities, selectedId) => (selectedId ? entities[selectedId] : undefined)
);
50 changes: 50 additions & 0 deletions src/app/+state/info-user/info.reducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
import { createReducer, on, Action } from '@ngrx/store';

import * as InfoUserActions from './info-user.actions';
import { InfoUserEntity } from './info-user.models';

export const INFO_USER_FEATURE_KEY = 'infoUser';

export interface InfoUserState extends EntityState<InfoUserEntity> {
selectedId?: string | number; // which InfoUser record has been selected
loaded: boolean; // has the InfoUser list been loaded
error?: string | null; // last known error (if any)
}

export interface InfoUserPartialState {
readonly [INFO_USER_FEATURE_KEY]: InfoUserState;
}

export const infoUserAdapter: EntityAdapter<InfoUserEntity> =
createEntityAdapter<InfoUserEntity>();

export const initialInfoUserState: InfoUserState =
infoUserAdapter.getInitialState({
// set initial required properties
loaded: false,
});

const infoUserReducer = createReducer(
initialInfoUserState,
on(InfoUserActions.initInfoUser, (state) => ({
...state,
loaded: false,
error: null,
})),
on(InfoUserActions.loadInfoUserSuccess, (state, { infoUser }) =>
infoUserAdapter.setAll(infoUser, { ...state, loaded: true })
),
on(InfoUserActions.loadInfoUserFailure, (state, { error }) => ({
...state,
error,
})),
on(InfoUserActions.infoUserValueChange, (state, { type, ...payload }) => ({
...state,
entities: { ...state.entities, ...payload },
}))
);

export function infoReducer(state: InfoUserState | undefined, action: Action) {
return infoUserReducer(state, action);
}
Loading

0 comments on commit c454b8d

Please sign in to comment.