feat: add notification to contact response
This commit is contained in:
53
src/app/services/ResponseStateNotificatio.spec.ts
Normal file
53
src/app/services/ResponseStateNotificatio.spec.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { ResponseStateNotification } from './ResponseStateNotificatio';
|
||||||
|
import { Notifier } from './notifier';
|
||||||
|
import { catchError, EMPTY, of, throwError } from 'rxjs';
|
||||||
|
import { Notification } from '../models/Notification';
|
||||||
|
|
||||||
|
describe('ResponseStateNotificatio', () => {
|
||||||
|
let service: ResponseStateNotification;
|
||||||
|
let notifier: jasmine.SpyObj<Notifier>;
|
||||||
|
|
||||||
|
let NOTIFICATION_MOCK: Notification;
|
||||||
|
beforeEach(() => {
|
||||||
|
notifier = jasmine.createSpyObj(Notifier.name, ['notify']);
|
||||||
|
NOTIFICATION_MOCK = new Notification('mock', 'success');
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
providers: [{ provide: Notifier, useValue: notifier }],
|
||||||
|
});
|
||||||
|
service = TestBed.inject(ResponseStateNotification);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should notify success if observable has no errors', () => {
|
||||||
|
service
|
||||||
|
.handleResponse(
|
||||||
|
of({
|
||||||
|
data: null,
|
||||||
|
message: 'success',
|
||||||
|
success: true,
|
||||||
|
}),
|
||||||
|
NOTIFICATION_MOCK.message,
|
||||||
|
NOTIFICATION_MOCK.message
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
expect(notifier.notify).toHaveBeenCalledOnceWith(NOTIFICATION_MOCK);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should notify error if observable throws error', () => {
|
||||||
|
service
|
||||||
|
.handleResponse(
|
||||||
|
throwError(() => new Error('Stream errored!')),
|
||||||
|
NOTIFICATION_MOCK.message,
|
||||||
|
NOTIFICATION_MOCK.message
|
||||||
|
)
|
||||||
|
.pipe(catchError(() => of(EMPTY)))
|
||||||
|
.subscribe();
|
||||||
|
NOTIFICATION_MOCK.type = 'error';
|
||||||
|
expect(notifier.notify).toHaveBeenCalledOnceWith(NOTIFICATION_MOCK);
|
||||||
|
});
|
||||||
|
});
|
||||||
26
src/app/services/ResponseStateNotificatio.ts
Normal file
26
src/app/services/ResponseStateNotificatio.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { catchError, Observable, tap, throwError } from 'rxjs';
|
||||||
|
import { Response } from '../models/Response';
|
||||||
|
import { Notification } from '../models/Notification';
|
||||||
|
import { inject, Injectable } from '@angular/core';
|
||||||
|
import { Notifier } from './notifier';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class ResponseStateNotification {
|
||||||
|
private readonly notifier = inject(Notifier);
|
||||||
|
|
||||||
|
handleResponse<T>(
|
||||||
|
r: Observable<Response<T>>,
|
||||||
|
success: string,
|
||||||
|
error: string
|
||||||
|
): Observable<Response<T>> {
|
||||||
|
return r.pipe(
|
||||||
|
tap(() => this.notifier.notify(new Notification(success, 'success'))),
|
||||||
|
catchError((err) => {
|
||||||
|
this.notifier.notify(new Notification(error, 'error'));
|
||||||
|
return throwError(() => err);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,19 +4,29 @@ import { environment } from '../../environments/environment';
|
|||||||
import { ContactDTO } from '../models/ContactDTO';
|
import { ContactDTO } from '../models/ContactDTO';
|
||||||
import { Response } from '../models/Response';
|
import { Response } from '../models/Response';
|
||||||
import { BehaviorSubject, map, switchMap, tap } from 'rxjs';
|
import { BehaviorSubject, map, switchMap, tap } from 'rxjs';
|
||||||
|
import { ResponseStateNotification } from './ResponseStateNotificatio';
|
||||||
|
import { strings } from '../strings';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class ContactService {
|
export class ContactService {
|
||||||
private readonly httpClient = inject(HttpClient);
|
private readonly httpClient = inject(HttpClient);
|
||||||
|
private readonly responseStateNotification = inject(ResponseStateNotification);
|
||||||
private readonly contacts = new BehaviorSubject<ContactDTO[]>([]);
|
private readonly contacts = new BehaviorSubject<ContactDTO[]>([]);
|
||||||
|
|
||||||
readonly contacts$ = this.contacts.asObservable();
|
readonly contacts$ = this.contacts.asObservable();
|
||||||
|
|
||||||
delete(id: number) {
|
delete(id: number) {
|
||||||
return this.httpClient
|
return this.httpClient.delete<Response<string>>(`${environment.apiUrl}/contacts/${id}`).pipe(
|
||||||
.delete<Response<string>>(`${environment.apiUrl}/contacts/${id}`)
|
(r) =>
|
||||||
.pipe(switchMap(() => this.getAll()));
|
this.responseStateNotification.handleResponse(
|
||||||
|
r,
|
||||||
|
strings.deleteContactSuccessNotification,
|
||||||
|
strings.errorNotification
|
||||||
|
),
|
||||||
|
switchMap(() => this.getAll())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
findById(id: string) {
|
findById(id: string) {
|
||||||
@@ -33,15 +43,27 @@ export class ContactService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
save(contact: ContactDTO) {
|
save(contact: ContactDTO) {
|
||||||
return this.httpClient
|
return this.httpClient.post<any>(environment.apiUrl + '/contacts', contact).pipe(
|
||||||
.post<Response<ContactDTO[] | null>>(environment.apiUrl + '/contacts', contact)
|
(r) =>
|
||||||
.pipe(switchMap(() => this.getAll()));
|
this.responseStateNotification.handleResponse(
|
||||||
|
r,
|
||||||
|
strings.createContactSuccessNotification,
|
||||||
|
strings.errorNotification
|
||||||
|
),
|
||||||
|
|
||||||
|
switchMap(() => this.getAll())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(contact: ContactDTO) {
|
update(contact: ContactDTO) {
|
||||||
return this.httpClient.put<Response<ContactDTO[] | null>>(
|
return this.httpClient
|
||||||
`${environment.apiUrl}/contacts/${contact.id}`,
|
.put<Response<ContactDTO[] | null>>(`${environment.apiUrl}/contacts/${contact.id}`, contact)
|
||||||
contact
|
.pipe((r) =>
|
||||||
|
this.responseStateNotification.handleResponse(
|
||||||
|
r,
|
||||||
|
strings.editContactSuccessNotification,
|
||||||
|
strings.errorNotification
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,15 @@ export const strings = Object.freeze({
|
|||||||
contactsCompany: "Contact's company",
|
contactsCompany: "Contact's company",
|
||||||
contactsPhone: "Contact's phone",
|
contactsPhone: "Contact's phone",
|
||||||
contactList: 'contact list',
|
contactList: 'contact list',
|
||||||
|
createContactSuccessNotification: 'Contact created successfully',
|
||||||
|
deleteContactSuccessNotification: 'Contact deleted successfully',
|
||||||
editContact: 'edit contact',
|
editContact: 'edit contact',
|
||||||
|
editContactSuccessNotification: 'Contact edited successfully',
|
||||||
editTheContact: 'edit the contact',
|
editTheContact: 'edit the contact',
|
||||||
errorMessageMaxLength: (maxLen: number) => `Must be ${maxLen} characters or fewer.`,
|
errorMessageMaxLength: (maxLen: number) => `Must be ${maxLen} characters or fewer.`,
|
||||||
errorMessagePhonePattern: `Valid format: + (optional) plus 12 to 15 digits`,
|
errorMessagePhonePattern: `Valid format: + (optional) plus 12 to 15 digits`,
|
||||||
errorMessageRequired: 'This field is required.',
|
errorMessageRequired: 'This field is required.',
|
||||||
|
errorNotification: 'Oops, there was an error',
|
||||||
name: 'name',
|
name: 'name',
|
||||||
phone: 'phone',
|
phone: 'phone',
|
||||||
save: 'save',
|
save: 'save',
|
||||||
|
|||||||
Reference in New Issue
Block a user