Skip to content

Commit

Permalink
fix: save Address Doctor configuration to the state management so it …
Browse files Browse the repository at this point in the history
…works with SSR (#1622)

* save Address Doctor configuration in the ngrx store/address-doctor-store.module.ts
* so the configuration can be provided in the docker_compose or in a deployment yaml file and be transfered from SSR to client side in the browser
  • Loading branch information
SGrueber authored Apr 22, 2024
1 parent 8f6e86f commit 2cadc4b
Show file tree
Hide file tree
Showing 13 changed files with 356 additions and 94 deletions.
41 changes: 30 additions & 11 deletions docs/guides/address-doctor.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,40 @@ You will also have to provide the endpoint and additional verification data.
This can be done by defining it in [Angular CLI environment](../concepts/configuration.md#angular-cli-environments) files:

```typescript
export const environment: Environment = {
...ENVIRONMENT_DEFAULTS,

addressDoctor: {
url: '<addressDoctor-url>',
login: '<addressDoctor-login>',
password: '<addressDoctor-password>',
maxResultCount: 5,
},
features: [
'addressDoctor'
],
addressDoctor: {
url: '<addressDoctor-url>',
login: '<addressDoctor-login>',
password: '<addressDoctor-password>',
maxResultCount: 5,
},
```

This configuration can also be supplied via environment variable `ADDRESS_DOCTOR` as stringified JSON:
The Address Doctor configuration can also be supplied via environment variable `ADDRESS_DOCTOR` as stringified JSON:

```text
ADDRESS_DOCTOR='{ "addressDoctor": { "url": "<addressDoctor-url>", "login": "<addressDoctor-login>", "password": "<addressDoctor-password>", "maxResultCount": "5" } }';
ADDRESS_DOCTOR='{ "url": "<addressDoctor-url>", "login": "<addressDoctor-login>", "password": "<addressDoctor-password>", "maxResultCount": "5" }';
```

The Address Doctor configuration for `docker-compose` looks like this:

```yaml
pwa:
environment:
ADDRESS_DOCTOR: '{ "url": "<addressDoctor-url>", "login": "<addressDoctor-login>", "password": "<addressDoctor-password>", "maxResultCount": "5" }'
```
For the current PWA Helm Chart that is also used in the PWA Flux deployments, the Address Doctor configuration looks like this.:
```yaml
environment:
- name: ADDRESS_DOCTOR
value: |
{
"url": "<addressDoctor-url>", "login": "<addressDoctor-login>", "password": "<addressDoctor-password>", "maxResultCount": "5"
}
```
## Workflow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,23 @@ import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';

import { FeatureToggleModule } from 'ish-core/feature-toggle.module';
import { LAZY_FEATURE_MODULE } from 'ish-core/utils/module-loader/module-loader.service';

import { LazyAddressDoctorComponent } from './lazy-address-doctor/lazy-address-doctor.component';

@NgModule({
imports: [CommonModule, TranslateModule],
imports: [CommonModule, FeatureToggleModule, TranslateModule],
providers: [
{
provide: LAZY_FEATURE_MODULE,
useValue: {
feature: 'addressDoctor',
location: () => import('../store/address-doctor-store.module').then(m => m.AddressDoctorStoreModule),
},
multi: true,
},
],
declarations: [LazyAddressDoctorComponent],
exports: [LazyAddressDoctorComponent],
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { provideMockStore } from '@ngrx/store/testing';
import { pick } from 'lodash-es';
import { of } from 'rxjs';
import { instance, mock, when } from 'ts-mockito';

import { Address } from 'ish-core/models/address/address.model';
import { StatePropertiesService } from 'ish-core/utils/state-transfer/state-properties.service';

import { AddressDoctorConfig } from '../../models/address-doctor/address-doctor-config.model';
import { getAddressDoctorConfig } from '../../store/address-doctor';

import { AddressDoctorService } from './address-doctor.service';

Expand Down Expand Up @@ -121,28 +119,29 @@ const response = {
describe('Address Doctor Service', () => {
let addressDoctorService: AddressDoctorService;
let controller: HttpTestingController;
let statePropertiesService: StatePropertiesService;

beforeEach(() => {
statePropertiesService = mock(StatePropertiesService);
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [{ provide: StatePropertiesService, useFactory: () => instance(statePropertiesService) }],
providers: [
provideMockStore({
selectors: [
{
selector: getAddressDoctorConfig,
value: {
login: 'login',
password: 'password',
maxResultCount: 5,
url: 'http://address-doctor.com',
},
},
],
}),
],
});
addressDoctorService = TestBed.inject(AddressDoctorService);

controller = TestBed.inject(HttpTestingController);

when(
statePropertiesService.getStateOrEnvOrDefault<AddressDoctorConfig>('ADDRESS_DOCTOR', 'addressDoctor')
).thenReturn(
of({
login: 'login',
password: 'password',
maxResultCount: 5,
url: 'http://address-doctor.com',
})
);
});

afterEach(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { HttpClient } from '@angular/common/http';
import { Injectable, inject } from '@angular/core';
import { Observable, catchError, map, of, switchMap, throwError } from 'rxjs';
import { Store, select } from '@ngrx/store';
import { Observable, catchError, map, of, switchMap, take, throwError } from 'rxjs';

import { Address } from 'ish-core/models/address/address.model';
import { whenTruthy } from 'ish-core/utils/operators';
import { StatePropertiesService } from 'ish-core/utils/state-transfer/state-properties.service';

import { AddressDoctorConfig } from '../../models/address-doctor/address-doctor-config.model';
import { AddressDoctorVariants } from '../../models/address-doctor/address-doctor.interface';
import { AddressDoctorMapper } from '../../models/address-doctor/address-doctor.mapper';
import { getAddressDoctorConfig } from '../../store/address-doctor';

@Injectable({ providedIn: 'root' })
export class AddressDoctorService {
private http = inject(HttpClient);
private statePropertiesService = inject(StatePropertiesService);
private store = inject(Store);

postAddress(address: Address): Observable<Address[]> {
let addressLine = '';
Expand Down Expand Up @@ -45,74 +45,74 @@ export class AddressDoctorService {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
private mapToBody(address: Address, addressLine: string): Observable<{ url: string; body: any }> {
return this.statePropertiesService
.getStateOrEnvOrDefault<AddressDoctorConfig>('ADDRESS_DOCTOR', 'addressDoctor')
.pipe(
whenTruthy(),
map(config => ({
url: config.url,
body: {
Login: config.login,
Password: config.password,
UseTransactions: 'PRODUCTION',
Request: {
Parameters: {
Mode: 'QuickCapture',
return this.store.pipe(
select(getAddressDoctorConfig),
whenTruthy(),
take(1),
map(config => ({
url: config.url,
body: {
Login: config.login,
Password: config.password,
UseTransactions: 'PRODUCTION',
Request: {
Parameters: {
Mode: 'QuickCapture',

CountrySets: [
{
OutputDetail: {
PreformattedData: {
PostalFormattedAddressLines: true,
SingleAddressLine: true,
SingleAddressLineDelimiter: 'Semicolon',
},
SubItems: true,
CountrySets: [
{
OutputDetail: {
PreformattedData: {
PostalFormattedAddressLines: true,
SingleAddressLine: true,
SingleAddressLineDelimiter: 'Semicolon',
},
Result: {
MaxResultCount: config.maxResultCount,
NumericRangeExpansion: {
RangesToExpand: 'None',
RangeExpansionType: 'Flexible',
},
SubItems: true,
},
Result: {
MaxResultCount: config.maxResultCount,
NumericRangeExpansion: {
RangesToExpand: 'None',
RangeExpansionType: 'Flexible',
},
Standardizations: [
{
Default: {
PreferredScript: {
Script: 'Latin',
TransliterationType: 'Default',
LimitLatinCharacters: 'Latin1',
},
FormatWithCountry: false,
CountryNameType: 'NameEN',
CountryCodeType: 'ISO2',
MaxItemLength: 255,
Casing: 'PostalAdmin',
DescriptorLength: 'Database',
AliasHandling: 'PostalAdmin',
},
Standardizations: [
{
Default: {
PreferredScript: {
Script: 'Latin',
TransliterationType: 'Default',
LimitLatinCharacters: 'Latin1',
},
FormatWithCountry: false,
CountryNameType: 'NameEN',
CountryCodeType: 'ISO2',
MaxItemLength: 255,
Casing: 'PostalAdmin',
DescriptorLength: 'Database',
AliasHandling: 'PostalAdmin',
},
],
},
],
},

IO: {
Inputs: [
{
AddressElements: {
Country: address.countryCode,
},
PreformattedData: {
SingleAddressLine: addressLine,
},
],
},
],
},

IO: {
Inputs: [
{
AddressElements: {
Country: address.countryCode,
},
PreformattedData: {
SingleAddressLine: addressLine,
},
],
},
},
],
},
},
}))
);
},
}))
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { NgModule } from '@angular/core';
import { EffectsModule } from '@ngrx/effects';
import { ActionReducerMap, StoreModule } from '@ngrx/store';
import { pick } from 'lodash-es';

import { AddressDoctorState } from './address-doctor-store';
import { AddressDoctorEffects } from './address-doctor/address-doctor.effects';
import { addressDoctorReducer } from './address-doctor/address-doctor.reducer';

const addressDoctorReducers: ActionReducerMap<AddressDoctorState> = {
addressDoctorConfig: addressDoctorReducer,
};

const addressDoctorEffects = [AddressDoctorEffects];

@NgModule({
imports: [
EffectsModule.forFeature(addressDoctorEffects),
StoreModule.forFeature('addressDoctor', addressDoctorReducers),
],
})
export class AddressDoctorStoreModule {
static forTesting(...reducers: (keyof ActionReducerMap<AddressDoctorState>)[]) {
return StoreModule.forFeature('addressDoctor', pick(addressDoctorReducers, reducers));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createFeatureSelector } from '@ngrx/store';

import { AddressDoctorConfig } from '../models/address-doctor/address-doctor-config.model';

export interface AddressDoctorState {
addressDoctorConfig: AddressDoctorConfig;
}

export const getAddressDoctorState = createFeatureSelector<AddressDoctorState>('addressDoctor');
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { createActionGroup, emptyProps } from '@ngrx/store';

import { payload } from 'ish-core/utils/ngrx-creators';

import { AddressDoctorConfig } from '../../models/address-doctor/address-doctor-config.model';

export const addressDoctorInternalActions = createActionGroup({
source: 'Address Doctor Internal',
events: {
'Load Address Doctor Config': emptyProps(),
'Set Address Doctor Config': payload<{ config: AddressDoctorConfig }>(),
},
});
Loading

0 comments on commit 2cadc4b

Please sign in to comment.