Skip to content

Commit

Permalink
feat: update refuge logic
Browse files Browse the repository at this point in the history
  • Loading branch information
oriolagobat committed Oct 25, 2023
1 parent 04c7ef7 commit 4e9e8f8
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 1 deletion.
92 changes: 92 additions & 0 deletions app/src/app/pages/refuges/refuge-update/refuge-udpate.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import {
} from '../../../schemas/image/post-image-schema';
import { ImageService } from '../../../services/image/image.service';
import { NgForm } from '@angular/forms';
import { UpdateRefugeResponse } from '../../../schemas/refuge/update/update-refuge-response';
import { UpdateRefugeError } from '../../../schemas/refuge/update/update-refuge-error';
import { ServerError } from '../../../schemas/refuge/create/create-refuge-error';

@Component({
selector: 'app-refuge-update',
Expand All @@ -29,6 +32,7 @@ import { NgForm } from '@angular/forms';
export class RefugeUdpatePage implements OnInit {
refuge?: Refuge;
form: UpdateRefuge = {
id: '',
name: '',
region: '',
image: 'no-photo.png',
Expand Down Expand Up @@ -82,6 +86,7 @@ export class RefugeUdpatePage implements OnInit {
.with({ status: 'correct' }, (response) => {
this.refuge = response.data;
this.form = {
id: this.refuge.id,
name: this.refuge.name,
region: this.refuge.region,
image: this.refuge.image,
Expand Down Expand Up @@ -265,10 +270,97 @@ export class RefugeUdpatePage implements OnInit {
await this.showError(() => (this.errorMessage = message));
}

async updateRefugeLoading(): Promise<void> {
const loading = await this.loadingController.create({
message: 'Actualitzant refugi...',
translucent: true,
});
return await loading.present();
}

onUpdate(form: NgForm) {
if (form.invalid) return;
const request = this.form;
this.updateRefuge(request);
}

private updateRefuge(request: UpdateRefuge) {
this.updateRefugeLoading().then(() => {
this.refugeService.updateRefuge(request).subscribe({
next: (response: UpdateRefugeResponse) =>
this.handleUpdateRefugeResponse(response),
error: () => this.handleClientError().then(),
});
});
}

private handleUpdateRefugeResponse(response: UpdateRefugeResponse) {
match(response)
.with({ status: 'updated' }, (response) => {
this.handleCorrectCreateRefugeResponse(response.data);
})
.with({ status: 'error' }, async (response) => {
this.handleError(response.error);
})
.exhaustive();
}

private handleCorrectCreateRefugeResponse(refuge: Refuge) {
this.loadingController.dismiss().then(() => {
this.router.navigate(['refuges', refuge.id]).then();
});
}

private handleError(error: UpdateRefugeError) {
match(error)
.with(ServerError.UNAUTHORIZED, () => {
this.handleUnauthorizedError().then();
})
.with(ServerError.FORBIDDEN, () => {
this.handleForbiddenError().then();
})
.with(ServerError.NOT_FOUND, () => {
this.handleNotFoundRefuge();
})
.with(ServerError.CONFLICT, () => {
this.handleConflictError().then();
})
.with(ServerError.INCORRECT_DATA, () => {
this.handleBadProgrammerData().then();
})
.with(ServerError.UNKNOWN_ERROR, () => {
this.handleUnknownError().then();
})
.with({ type: 'INVALID_USER_DATA' }, (error) => {
this.showErrorMessage(error.message).then();
})
.exhaustive();
}

private async handleUnauthorizedError() {
await this.showError(async () => {
await this.showErrorMessage(
'Trapella! La teva sessió no està iniciada!',
).then();
});
}

private async handleForbiddenError() {
await this.showError(async () => {
await this.router
.navigate(['/forbidden'], {
skipLocationChange: true,
})
.then();
});
}
private async handleConflictError() {
await this.showError(async () => {
await this.showErrorMessage(
'Ja existeix un refugi amb aquest nom',
).then();
});
}
getImageUrl(): string | undefined {
if (this.refuge == undefined) return undefined;
return this.refugeService.getImageUrlFor(this.refuge);
Expand Down
2 changes: 1 addition & 1 deletion app/src/app/schemas/refuge/refuge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export type Refuge = {
};

export type CreateRefuge = Omit<Refuge, 'id'>;
export type UpdateRefuge = Omit<Refuge, 'id'>;
export type UpdateRefuge = Refuge;
export const RefugePattern: P.Pattern<Refuge> = {};

export function isValidId(id: string): boolean {
Expand Down
58 changes: 58 additions & 0 deletions app/src/app/schemas/refuge/update/update-refuge-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
import { isMatching, match, P } from 'ts-pattern';

export type UpdateRefugeError = ServerError | ClientError;

export enum ServerError {
UNAUTHORIZED = 'UNAUTHORIZED',
FORBIDDEN = 'FORBIDDEN',
NOT_FOUND = 'NOT_FOUND',
CONFLICT = 'CONFLICT',
UNKNOWN_ERROR = 'UNKNOWN_ERROR',
INCORRECT_DATA = 'INCORRECT_DATA',
}

export type ClientError = {
type: 'INVALID_USER_DATA';
message: string;
};

export namespace UpdateRefugeError {
export function fromHttp(err: HttpErrorResponse): UpdateRefugeError | never {
return match(err.status)
.returnType<UpdateRefugeError>()
.with(0, () => {
throw new Error('You are offline or the server is down.');
})
.with(HttpStatusCode.Unauthorized, () => ServerError.UNAUTHORIZED)
.with(HttpStatusCode.Forbidden, () => ServerError.FORBIDDEN)
.with(HttpStatusCode.NotFound, () => ServerError.NOT_FOUND)
.with(HttpStatusCode.Conflict, () => ServerError.CONFLICT)
.with(HttpStatusCode.UnprocessableEntity, () =>
getErrorFromUnprocessableEntity(err),
)
.otherwise(() => ServerError.UNKNOWN_ERROR);
}
}

type UnprocessableEntityRefugeDetail = {
loc: [string, number];
msg: string;
type: string;
};

type UnprocessableEntityRefuge = {
detail: UnprocessableEntityRefugeDetail[];
};

const UnprocessableEntityRefugePattern: P.Pattern<UnprocessableEntityRefuge> =
{};

function getErrorFromUnprocessableEntity(
err: HttpErrorResponse,
): UpdateRefugeError {
const errorResponse: UnprocessableEntityRefuge = err.error;
if (isMatching(UnprocessableEntityRefugePattern, errorResponse))
return { type: 'INVALID_USER_DATA', message: errorResponse.detail[0].msg };
return ServerError.INCORRECT_DATA;
}
34 changes: 34 additions & 0 deletions app/src/app/schemas/refuge/update/update-refuge-response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Refuge, RefugePattern } from '../refuge';
import { isMatching } from 'ts-pattern';
import { ServerError, UpdateRefugeError } from './update-refuge-error';
import { HttpErrorResponse } from '@angular/common/http';

export type UpdateRefugeResponse =
| {
status: 'updated';
data: Refuge;
}
| {
status: 'error';
error: UpdateRefugeError;
};

export function updateRefugeResponseFromResponse(
response: any,
): UpdateRefugeResponse {
if (isMatching(RefugePattern, response))
return { status: 'updated', data: response };
return {
status: 'error',
error: ServerError.INCORRECT_DATA,
};
}

export function updateRefugeResponseFromError(
err: HttpErrorResponse,
): UpdateRefugeResponse {
return {
status: 'error',
error: UpdateRefugeError.fromHttp(err),
};
}
27 changes: 27 additions & 0 deletions app/src/app/services/refuge/refuge.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
isValidId,
Refuge,
RefugePattern,
UpdateRefuge,
} from '../../schemas/refuge/refuge';
import { isMatching } from 'ts-pattern';
import {
Expand All @@ -37,6 +38,11 @@ import {
fromError,
fromResponse,
} from '../../schemas/refuge/create/create-refuge-response';
import {
UpdateRefugeResponse,
updateRefugeResponseFromError,
updateRefugeResponseFromResponse,
} from '../../schemas/refuge/update/update-refuge-response';

@Injectable({
providedIn: 'root',
Expand Down Expand Up @@ -178,4 +184,25 @@ export class RefugeService {
private createRefugeEndpoint(): string {
return `${environment.API}/refuges/`;
}

updateRefuge(refuge: UpdateRefuge): Observable<UpdateRefugeResponse> {
return this.updateRefugeFromApi(refuge);
}

private updateRefugeFromApi(
refuge: UpdateRefuge,
): Observable<UpdateRefugeResponse> {
const endpoint = this.updateRefugeEndpoint(refuge.id);
return this.http.post<Refuge>(endpoint, refuge).pipe(
map((response: Refuge) => updateRefugeResponseFromResponse(response)),
catchError((err: HttpErrorResponse) =>
of(updateRefugeResponseFromError(err)),
),
retry(3),
);
}

private updateRefugeEndpoint(id: string): string {
return `${environment.API}/refuges/${id}/`;
}
}

0 comments on commit 4e9e8f8

Please sign in to comment.