feat: add establishment settings

This commit is contained in:
2026-02-17 19:47:25 -03:00
parent 816252308c
commit eef3dbc2fb
32 changed files with 811 additions and 4 deletions

View File

@@ -28,10 +28,13 @@
"edit_chain": "edit chain"
},
"establishment": {
"establishments":"establishments"
"establishments":"establishments",
"new_establishment": "new establishment",
"edit_establishment": "edit establishment"
}
},
"common": {
"address":"address",
"name":"name",
"save": "save",
"update": "update",

View File

@@ -28,10 +28,13 @@
"edit_chain": "editar cadena"
},
"establishment": {
"establishments":"establecimientos"
"establishments":"establecimientos",
"new_establishment": "nuevo establecimiento",
"edit_establishment": "editar establecimiento"
}
},
"common": {
"address":"dirección",
"name":"nombre",
"no_file_yet": "Sin carga",
"save": "guardar",

View File

@@ -28,10 +28,13 @@
"edit_chain": "edit chain"
},
"establishment": {
"establishments":"establishments"
"establishments":"establishments",
"new_establishment": "new establishment",
"edit_establishment": "edit establishment"
}
},
"common": {
"address":"address",
"name":"name",
"save": "save",
"update": "update",

View File

@@ -0,0 +1,52 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { EstablishmentAdd } from './establishment-add';
import { provideTranslateService } from '@ngx-translate/core';
import { Chain } from '../../models/Chain';
import { Establishment } from '../../models/Establishment';
import { EstablishmentSettings } from '../../services/establishment-settings';
import { EstablishmentForm } from '../../pages/settings/establishments/establishment-form/establishment-form';
describe('EstablishmentAdd', () => {
let component: EstablishmentAdd;
let fixture: ComponentFixture<EstablishmentAdd>;
let establishmentSettings: Partial<EstablishmentSettings>;
beforeEach(async () => {
establishmentSettings = {
save: vi.fn(),
};
TestBed.overrideComponent(EstablishmentForm, {
set: { template: `` },
});
await TestBed.configureTestingModule({
imports: [EstablishmentAdd],
providers: [
provideTranslateService(),
{ provide: EstablishmentSettings, useValue: establishmentSettings },
],
}).compileComponents();
fixture = TestBed.createComponent(EstablishmentAdd);
component = fixture.componentInstance;
await fixture.whenStable();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should save on valid form', async () => {
const SELECTED_CHAIN_MOCK = new Chain('Mock', 'mock_logo.png', 1);
const ADDRESS_MOCK = 'Mock street';
await component.submit();
//form is invalid so it doesnt call establishmenDAO save method
expect(establishmentSettings.save).not.toHaveBeenCalled();
//User chooses chain, form is valid
component['form'].patchValue({ chain: SELECTED_CHAIN_MOCK, address: ADDRESS_MOCK });
await component.submit();
const establishment = new Establishment(SELECTED_CHAIN_MOCK, ADDRESS_MOCK);
expect(establishmentSettings.save).toHaveBeenCalledExactlyOnceWith(establishment);
});
});

View File

@@ -0,0 +1,36 @@
import { Component, inject } from '@angular/core';
import { EstablishmentSettings } from '../../services/establishment-settings';
import { Establishment } from '../../models/Establishment';
import { ActionBtn } from '../action-btn/action-btn';
import { TranslatePipe } from '@ngx-translate/core';
import { UpperfirstPipe } from '../../pipes/upperfirst-pipe';
import { EstablishmentFormGroup } from '../../pages/settings/establishments/establishment-formgroup';
import { SettingsBaseAddEdit } from '../settings-base-add-edit/settings-base-add-edit';
@Component({
selector: 'app-establishment-add',
imports: [
ActionBtn,
TranslatePipe,
UpperfirstPipe,
],
templateUrl: './../settings-base-add-edit/settings-base-add-edit.html',
styleUrl: './../settings-base-add-edit/settings-base-add-edit.scss',
})
export class EstablishmentAdd extends SettingsBaseAddEdit {
private readonly establishmentSettings = inject(EstablishmentSettings);
readonly form = new EstablishmentFormGroup();
btnText = 'common.save';
title = 'settings.establishment.new_establishment';
async submit() {
const chain = this.form.controls.chain.value;
const address = this.form.controls.address.value;
if (chain?.id) {
const establishment = new Establishment(chain, address);
this.establishmentSettings.save(establishment);
}
}
}

View File

@@ -0,0 +1,62 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { EstablishmentEdit } from './establishment-edit';
import { ActivatedRoute } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
import { Establishment } from '../../models/Establishment';
import { Chain } from '../../models/Chain';
import { EstablishmentSettings } from '../../services/establishment-settings';
import { provideTranslateService } from '@ngx-translate/core';
import { EstablishmentForm } from '../../pages/settings/establishments/establishment-form/establishment-form';
import { By } from '@angular/platform-browser';
describe('EstablishmentEdit', () => {
let component: EstablishmentEdit;
let fixture: ComponentFixture<EstablishmentEdit>;
let activatedRoute: Partial<ActivatedRoute>;
let establishmentSettings: Partial<EstablishmentSettings>;
const data = new BehaviorSubject({
establishment: new Establishment(new Chain('mock', 'logo_mock.jpg', 1), 'mock street', 1),
});
beforeEach(async () => {
activatedRoute = {
data,
};
establishmentSettings = {
update: vi.fn(),
};
TestBed.overrideComponent(EstablishmentForm, {
set: { template: `` },
});
await TestBed.configureTestingModule({
imports: [EstablishmentEdit],
providers: [
{ provide: ActivatedRoute, useValue: activatedRoute },
{ provide: EstablishmentSettings, useValue: establishmentSettings },
provideTranslateService(),
],
}).compileComponents();
fixture = TestBed.createComponent(EstablishmentEdit);
component = fixture.componentInstance;
await fixture.whenStable();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should call establishmentSettings update', async () => {
const CHAIN_MOCK = new Chain('mock', 'logo_mock.png', 2);
const ADDRESS_MOCK = 'mock street';
//User selects chain
component['form'].patchValue({chain: CHAIN_MOCK, address: ADDRESS_MOCK});
const submitBtn = fixture.debugElement.query(By.css('app-action-btn'));
submitBtn.triggerEventHandler('click');
await fixture.whenStable()
expect(establishmentSettings.update).toHaveBeenCalledExactlyOnceWith(new Establishment(CHAIN_MOCK, ADDRESS_MOCK, component['establishment']!.id));
});
});

View File

@@ -0,0 +1,53 @@
import { Component, inject, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { UpperfirstPipe } from '../../pipes/upperfirst-pipe';
import { TranslatePipe } from '@ngx-translate/core';
import { Establishment } from '../../models/Establishment';
import { Observable, take, tap } from 'rxjs';
import { EstablishmentFormGroup } from '../../pages/settings/establishments/establishment-formgroup';
import { ActionBtn } from '../action-btn/action-btn';
import { EstablishmentSettings } from '../../services/establishment-settings';
import { SettingsBaseAddEdit } from '../settings-base-add-edit/settings-base-add-edit';
@Component({
selector: 'app-establishment-edit',
imports: [UpperfirstPipe, TranslatePipe, ActionBtn],
templateUrl: './../settings-base-add-edit/settings-base-add-edit.html',
styleUrl: './../settings-base-add-edit/settings-base-add-edit.scss',
})
export class EstablishmentEdit extends SettingsBaseAddEdit implements OnInit {
private readonly activatedRoute = inject(ActivatedRoute);
private readonly establishmentSettings = inject(EstablishmentSettings);
private establishment?: Establishment;
readonly form = new EstablishmentFormGroup();
btnText = 'common.update';
title = 'settings.establishment.edit_establishment'
ngOnInit() {
(<Observable<{ establishment: Establishment }>>this.activatedRoute.data)
.pipe(
take(1),
tap((data) => (this.establishment = data.establishment)),
tap((data) => this.patchForm(data.establishment)),
)
.subscribe();
}
patchForm(establishment: Establishment) {
this.form.patchValue({
chain: establishment.chain,
address: establishment.address,
});
}
async submit() {
const chain = this.form.controls.chain.value;
if (chain && this.establishment?.id) {
const address = this.form.controls.address.value;
const establishment = new Establishment(chain, address, this.establishment.id);
await this.establishmentSettings.update(establishment);
}
}
}

View File

@@ -0,0 +1,3 @@
<app-establishment-add #e>
<app-establishment-form [form]="e.form"></app-establishment-form>
</app-establishment-add>

View File

@@ -0,0 +1,5 @@
:host {
display: flex;
flex-direction: column;
height: 100%;
}

View File

@@ -0,0 +1,35 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { EstablishmentAddPage } from './establishment-add-page';
import { EstablishmentSettings } from '../../../../services/establishment-settings';
import { provideTranslateService } from '@ngx-translate/core';
import { ChainDAO } from '../../../../dao/ChainDAO';
describe('EstablishmentAddPage', () => {
let component: EstablishmentAddPage;
let fixture: ComponentFixture<EstablishmentAddPage>;
let chainDAO: Partial<ChainDAO>;
beforeEach(async () => {
chainDAO = {
findAll: vi.fn(),
};
await TestBed.configureTestingModule({
imports: [EstablishmentAddPage],
providers: [
{ provide: ChainDAO, useValue: chainDAO },
{ provide: EstablishmentSettings, useValue: {} },
provideTranslateService(),
],
}).compileComponents();
fixture = TestBed.createComponent(EstablishmentAddPage);
component = fixture.componentInstance;
await fixture.whenStable();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,13 @@
import { Component } from '@angular/core';
import { EstablishmentAdd } from "../../../../components/establishment-add/establishment-add";
import { EstablishmentForm } from "../establishment-form/establishment-form";
@Component({
selector: 'app-establishment-add-page',
imports: [EstablishmentAdd, EstablishmentForm],
templateUrl: './establishment-add-page.html',
styleUrl: './establishment-add-page.scss',
})
export class EstablishmentAddPage {
}

View File

@@ -0,0 +1,3 @@
<app-establishment-edit #e>
<app-establishment-form [form]="e.form"></app-establishment-form>
</app-establishment-edit>

View File

@@ -0,0 +1,9 @@
:host {
display: flex;
flex-direction: column;
height: 100%;
}
h3 {
margin-top: 0;
}

View File

@@ -0,0 +1,45 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { EstablishmentEditPage } from './establishment-edit-page';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { Establishment } from '../../../../models/Establishment';
import { Chain } from '../../../../models/Chain';
import { EstablishmentSettings } from '../../../../services/establishment-settings';
import { provideTranslateService } from '@ngx-translate/core';
import { ChainDAO } from '../../../../dao/ChainDAO';
describe('EstablishmentEditPage', () => {
let component: EstablishmentEditPage;
let fixture: ComponentFixture<EstablishmentEditPage>;
let activatedRoute: Partial<ActivatedRoute>;
let chainDAO: Partial<ChainDAO>;
beforeEach(async () => {
activatedRoute = {
data: of({establishment: new Establishment(new Chain('mock', 'logo_mock.jpg', 1), 'mock street', 1)}),
};
chainDAO = {
findAll: vi.fn().mockResolvedValue([]),
};
await TestBed.configureTestingModule({
imports: [EstablishmentEditPage],
providers: [
{ provide: ActivatedRoute, useValue: activatedRoute },
{ provide: ChainDAO, useValue: chainDAO },
{ provide: EstablishmentSettings, useValue: {} },
provideTranslateService(),
],
}).compileComponents();
fixture = TestBed.createComponent(EstablishmentEditPage);
component = fixture.componentInstance;
await fixture.whenStable();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,13 @@
import { Component } from '@angular/core';
import { EstablishmentEdit } from "../../../../components/establishment-edit/establishment-edit";
import { EstablishmentForm } from "../establishment-form/establishment-form";
@Component({
selector: 'app-establishment-edit-page',
imports: [EstablishmentEdit, EstablishmentForm],
templateUrl: './establishment-edit-page.html',
styleUrl: './establishment-edit-page.scss',
})
export class EstablishmentEditPage {
}

View File

@@ -0,0 +1,7 @@
<form [formGroup]="form()">
<app-chain-select formControlName="chain"></app-chain-select>
<mat-form-field appearance="outline" class="full-width">
<mat-label>{{'common.address'|translate|upperfirst}}</mat-label>
<input matInput formControlName="address"/>
</mat-form-field>
</form>

View File

@@ -0,0 +1,31 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { EstablishmentForm } from './establishment-form';
import { ChainDAO } from '../../../../dao/ChainDAO';
import { provideTranslateService } from '@ngx-translate/core';
describe('EstablishmentForm', () => {
let component: EstablishmentForm;
let fixture: ComponentFixture<EstablishmentForm>;
let chainDAO: Partial<ChainDAO>;
beforeEach(async () => {
chainDAO = {
findAll: vi.fn().mockResolvedValue([]),
};
await TestBed.configureTestingModule({
imports: [EstablishmentForm],
providers: [{ provide: ChainDAO, useValue: chainDAO }, provideTranslateService()],
}).compileComponents();
fixture = TestBed.createComponent(EstablishmentForm);
component = fixture.componentInstance;
await fixture.whenStable();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,18 @@
import { Component, input } from '@angular/core';
import { EstablishmentFormGroup } from '../establishment-formgroup';
import { ChainSelect } from '../../../../components/chain-select/chain-select';
import { ReactiveFormsModule } from '@angular/forms';
import { MatFormField, MatLabel } from '@angular/material/form-field';
import { MatInput } from '@angular/material/input';
import { TranslatePipe } from '@ngx-translate/core';
import { UpperfirstPipe } from "../../../../pipes/upperfirst-pipe";
@Component({
selector: 'app-establishment-form',
imports: [ChainSelect, ReactiveFormsModule, MatFormField, MatInput, MatLabel, TranslatePipe, UpperfirstPipe],
templateUrl: './establishment-form.html',
styles: '',
})
export class EstablishmentForm {
form = input(new EstablishmentFormGroup());
}

View File

@@ -0,0 +1,16 @@
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { Chain } from '../../../models/Chain';
export class EstablishmentFormGroup extends FormGroup<{
chain: FormControl<Chain | null>;
address: FormControl<string>;
}> {
constructor(
form = {
chain: new FormControl<Chain | null>(null, [Validators.required]),
address: new FormControl('', { nonNullable: true }),
},
) {
super(form);
}
}

View File

@@ -0,0 +1,49 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { EstablishmentList } from './establishment-list';
import { ActivatedRoute, Router } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
import { Establishment } from '../../../../models/Establishment';
import { Chain } from '../../../../models/Chain';
import { By } from '@angular/platform-browser';
const ADD_PATH = ['settings', 'establishments', 'add'];
describe('EstablishmentList', () => {
let component: EstablishmentList;
let fixture: ComponentFixture<EstablishmentList>;
let activatedRoute: Partial<ActivatedRoute>;
let router: Partial<Router>;
const activatedRouteData = new BehaviorSubject({
establishments: [new Establishment(new Chain('Mock', 'logo_mock.png', 1), 'Mock street', 1)],
});
beforeEach(async () => {
activatedRoute = { data: activatedRouteData.asObservable() };
router = {
navigate: vi.fn(),
};
await TestBed.configureTestingModule({
imports: [EstablishmentList],
providers: [
{ provide: ActivatedRoute, useValue: activatedRoute },
{ provide: Router, useValue: router },
],
}).compileComponents();
fixture = TestBed.createComponent(EstablishmentList);
component = fixture.componentInstance;
await fixture.whenStable();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should navigate to add on add btn click', () => {
const addBtn = fixture.debugElement.query(By.css('app-floating-big-btn'));
addBtn.triggerEventHandler('bigClick');
expect(router.navigate).toHaveBeenCalledExactlyOnceWith(ADD_PATH);
});
});

View File

@@ -0,0 +1,40 @@
import { Component, inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { SimpleListWActions } from '../../../../components/simple-list-w-actions/simple-list-w-actions';
import { FloatingBigBtn } from '../../../../components/floating-big-btn/floating-big-btn';
import { AsyncPipe } from '@angular/common';
import { map } from 'rxjs';
import { SimpleListItem } from '../../../../components/simple-list-w-actions/SimpleListItem';
import { SimpleListItemAction } from '../../../../components/simple-list-w-actions/SimpleListItemAction';
import { Establishment } from '../../../../models/Establishment';
import { SettingsBaseList } from '../../../../components/settings-base-list/settings-base-list';
@Component({
selector: 'app-establishment-list',
imports: [SimpleListWActions, FloatingBigBtn, AsyncPipe],
templateUrl: './../../../../components/settings-base-list/settings-base-list.html',
styleUrl: './../../../../components/settings-base-list/settings-base-list.scss'
})
export class EstablishmentList extends SettingsBaseList{
activatedRoute = inject(ActivatedRoute);
router = inject(Router);
data$ = this.activatedRoute.data.pipe(
map((data) =>
(<Establishment[]>data['establishments']).map((e) => {
const itemName = e.chain.name + (e.address ? ` - ${e.address}` : '');
return new SimpleListItem(String(e.id), itemName ?? '', [
new SimpleListItemAction('edit', 'edit'),
]);
}),
),
);
edit(action: { action: string; subject: string }) {
this.router.navigate(['settings', 'establishments', 'edit', action.subject]);
}
add() {
this.router.navigate(['settings', 'establishments', 'add']);
}
}

View File

@@ -0,0 +1,3 @@
<app-simple-layout title="settings.establishment.establishments" [withBackBtn]="true" >
<router-outlet></router-outlet>
</app-simple-layout>

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Establishments } from './establishments';
import { provideTranslateService } from '@ngx-translate/core';
describe('Establishments', () => {
let component: Establishments;
let fixture: ComponentFixture<Establishments>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [Establishments],
providers: [provideTranslateService()]
})
.compileComponents();
fixture = TestBed.createComponent(Establishments);
component = fixture.componentInstance;
await fixture.whenStable();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,13 @@
import { Component } from '@angular/core';
import { SimpleLayout } from "../../../components/simple-layout/simple-layout";
import { RouterOutlet } from "@angular/router";
@Component({
selector: 'app-establishments',
imports: [SimpleLayout, RouterOutlet],
templateUrl: './establishments.html',
styles: '',
})
export class Establishments {
}

View File

@@ -2,6 +2,9 @@ import { Route } from '@angular/router';
import { chainsResolver } from '../../resolvers/chains-resolver';
import { ChainList } from './chains/chain-list/chain-list';
import { chainResolver } from '../../resolvers/chain-resolver';
import { EstablishmentList } from './establishments/establishment-list/establishment-list';
import { establishmentsResolver } from '../../resolvers/establishments-resolver';
import { establishmentResolver } from '../../resolvers/establishment-resolver';
export const routes: Route[] = [
{
@@ -32,4 +35,24 @@ export const routes: Route[] = [
}
]
},
{
path: 'establishments',
loadComponent: () => import('./establishments/establishments').then( c => c.Establishments ),
children: [
{
path: '',
component: EstablishmentList,
resolve: {establishments: establishmentsResolver},
},
{
path: 'add',
loadComponent: () => import('./establishments/establishment-add-page/establishment-add-page').then(c => c.EstablishmentAddPage)
},
{
path: 'edit/:id',
loadComponent: () => import('./establishments/establishment-edit-page/establishment-edit-page').then(c => c.EstablishmentEditPage),
resolve: {establishment: establishmentResolver}
}
]
},
];

View File

@@ -13,7 +13,7 @@ export class Settings {
readonly menuItems = [
new IconNavListItem('translate', 'settings.nav.language', ['languages']),
new IconNavListItem('warehouse', 'settings.nav.manage_chains', ['chains']),
new IconNavListItem('store', 'settings.nav.manage_establishments', ['/']),
new IconNavListItem('store', 'settings.nav.manage_establishments', ['establishments']),
new IconNavListItem('shopping_bag', 'settings.nav.manage_products', ['/']),
];
}

View File

@@ -0,0 +1,68 @@
import { TestBed } from '@angular/core/testing';
import { provideRouter, RedirectCommand, ResolveFn, Router } from '@angular/router';
import { establishmentResolver } from './establishment-resolver';
import { Establishment } from '../models/Establishment';
import { Component } from '@angular/core';
import { EstablishmentDAO } from '../dao/EstablishmentDAO';
import { Chain } from '../models/Chain';
const PATH_MOCK = 'mock/:id';
@Component({
selector: 'app-mock',
template: ``,
styles: [],
})
class MockComponent {}
const ESTABLISHMENT_SETTINGS_PATH = 'settings/establishments';
describe('establishmentResolver', () => {
let establishmentDAO: Partial<EstablishmentDAO>;
let router: Router;
let ESTABLISHMENT_MOCK: Establishment;
const executeResolver: ResolveFn<Establishment | RedirectCommand> = (...resolverParameters) =>
TestBed.runInInjectionContext(() => establishmentResolver(...resolverParameters));
beforeEach(() => {
ESTABLISHMENT_MOCK = new Establishment(new Chain('mock', 'logo_mock.png', 1), 'mock street');
establishmentDAO = {
findBy: vi.fn().mockResolvedValue([ESTABLISHMENT_MOCK]),
};
TestBed.configureTestingModule({
imports: [MockComponent],
providers: [
provideRouter([
{
path: 'mock/:id',
component: MockComponent,
resolve: { establishment: establishmentResolver },
},
{
path: ESTABLISHMENT_SETTINGS_PATH,
component: MockComponent
}
]),
{ provide: EstablishmentDAO, useValue: establishmentDAO },
],
});
router = TestBed.inject(Router);
});
it('should be created', () => {
expect(executeResolver).toBeTruthy();
});
it('should fetch establishment by id', async () => {
const ESTABLISHMENT_ID_MOCK = 1;
await router.navigate(['mock', ESTABLISHMENT_ID_MOCK]);
expect(establishmentDAO.findBy).toHaveBeenCalledExactlyOnceWith({id: ESTABLISHMENT_ID_MOCK})
});
it('should navigate back to settings if establishment is not found', async () => {
establishmentDAO.findBy = vi.fn().mockResolvedValue([]);
await router.navigate(['mock', 1]);
expect(router.url).toEqual('/'+ESTABLISHMENT_SETTINGS_PATH);
});
});

View File

@@ -0,0 +1,27 @@
import { inject } from '@angular/core';
import { RedirectCommand, ResolveFn, Router } from '@angular/router';
import { EstablishmentDAO } from '../dao/EstablishmentDAO';
import { Establishment } from '../models/Establishment';
export const establishmentResolver: ResolveFn<Establishment | RedirectCommand> = async (
route,
_,
) => {
const establishmentDAO = inject(EstablishmentDAO);
const router = inject(Router);
const establishmentID = (<{ id: string }>route.params).id;
let establishment: Establishment;
try {
const results = await establishmentDAO.findBy({ id: Number(establishmentID) });
if (!results[0]) {
throw new Error('The search for establishment on edit did not find any match');
}
establishment = results[0];
} catch (e) {
console.error(e);
return new RedirectCommand(router.parseUrl('settings/establishments'), {
skipLocationChange: true,
});
}
return establishment;
};

View File

@@ -0,0 +1,52 @@
import { TestBed } from '@angular/core/testing';
import { provideRouter, ResolveFn, Router } from '@angular/router';
import { establishmentsResolver } from './establishments-resolver';
import { Establishment } from '../models/Establishment';
import { EstablishmentDAO } from '../dao/EstablishmentDAO';
import { Component } from '@angular/core';
@Component({
selector: 'app-mock',
template: ``,
styles: ``,
})
class MockComponent {}
const PATH_MOCK = 'establishments';
describe('establishmentsResolver', () => {
let establishmentDAO: Partial<EstablishmentDAO>;
let router: Router;
const executeResolver: ResolveFn<Establishment[]> = (...resolverParameters) =>
TestBed.runInInjectionContext(() => establishmentsResolver(...resolverParameters));
beforeEach(() => {
establishmentDAO = {
findAll: vi.fn().mockResolvedValue([]),
};
TestBed.configureTestingModule({
providers: [
{ provide: EstablishmentDAO, useValue: establishmentDAO },
provideRouter([
{
path: PATH_MOCK,
component: MockComponent,
resolve: { establishments: establishmentsResolver },
},
]),
],
});
router = TestBed.inject(Router);
});
it('should be created', () => {
expect(executeResolver).toBeTruthy();
});
it('should call establishmentDAO findAll method', async () => {
await router.navigate([PATH_MOCK]);
expect(establishmentDAO.findAll).toHaveBeenCalled();
});
});

View File

@@ -0,0 +1,16 @@
import { inject } from '@angular/core';
import { ResolveFn } from '@angular/router';
import { EstablishmentDAO } from '../dao/EstablishmentDAO';
import { Establishment } from '../models/Establishment';
export const establishmentsResolver: ResolveFn<Establishment[]> = async (route, state) => {
const establishmentDAO = inject(EstablishmentDAO);
let establishments: Establishment[] = [];
try {
establishments = await establishmentDAO.findAll()
} catch(e) {
console.error(e);
//TODO: report error
}
return establishments;
};

View File

@@ -0,0 +1,44 @@
import { TestBed } from '@angular/core/testing';
import { EstablishmentSettings } from './establishment-settings';
import { EstablishmentDAO } from '../dao/EstablishmentDAO';
import { Router } from '@angular/router';
import { Chain } from '../models/Chain';
import { Establishment } from '../models/Establishment';
describe('EstablishmentSettings', () => {
let service: EstablishmentSettings;
let establishmentDAO: Partial<EstablishmentDAO>;
let router: Partial<Router>;
beforeEach(() => {
establishmentDAO = {
insert: vi.fn().mockResolvedValue({ rows: [] }),
};
router = {
navigate: vi.fn(),
};
TestBed.configureTestingModule({
providers: [
{ provide: EstablishmentDAO, useValue: establishmentDAO },
{ provide: Router, useValue: router },
],
});
service = TestBed.inject(EstablishmentSettings);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should insert new establishment', async () => {
const CHAIN_MOCK = new Chain('Chain mock', 'logo_mock.png', 1);
const ADDRESS_MOCK = 'Mock street';
const ESTABLISHMENT_MOCK = new Establishment(CHAIN_MOCK, ADDRESS_MOCK);
await service.save(ESTABLISHMENT_MOCK);
expect(establishmentDAO.insert).toHaveBeenCalledExactlyOnceWith(ESTABLISHMENT_MOCK);
expect(router.navigate).toHaveBeenCalledExactlyOnceWith(['settings', 'establishments']);
});
});

View File

@@ -0,0 +1,37 @@
import { inject, Injectable } from '@angular/core';
import { Location } from '@angular/common';
import { Router } from '@angular/router';
import { EstablishmentDAO } from '../dao/EstablishmentDAO';
import { Establishment } from '../models/Establishment';
@Injectable({
providedIn: 'root',
})
export class EstablishmentSettings {
private readonly establishmentDAO = inject(EstablishmentDAO);
private readonly router = inject(Router);
private readonly location = inject(Location);
async save(establishment: Establishment) {
try {
await this.establishmentDAO.insert(establishment);
} catch(e) {
console.error(e)
//TODO: handle error
}
this.router.navigate(['settings', 'establishments']);
this.location.replaceState('settings');
}
async update(establishment: Establishment) {
try {
await this.establishmentDAO.update(establishment, {id: establishment.id});
}catch(e) {
console.error(e)
//TODO: handle error
}
this.router.navigate(['settings', 'establishments']);
this.location.replaceState('settings');
}
}