diff --git a/app/src/app/pages/refuges/refuge-create/refuge-create.page.ts b/app/src/app/pages/refuges/refuge-create/refuge-create.page.ts index ca5fc61..eccca67 100644 --- a/app/src/app/pages/refuges/refuge-create/refuge-create.page.ts +++ b/app/src/app/pages/refuges/refuge-create/refuge-create.page.ts @@ -70,7 +70,6 @@ export class RefugeCreatePage implements OnInit { } private uploadImage(form: CreateRefuge): CreateRefuge { - // TODO: Check image, parse and upload if necessary, return form or error return form; } diff --git a/app/src/app/pages/refuges/refuge-detail/refuges-detail.page.ts b/app/src/app/pages/refuges/refuge-detail/refuges-detail.page.ts index 641e1ab..8a3a92e 100644 --- a/app/src/app/pages/refuges/refuge-detail/refuges-detail.page.ts +++ b/app/src/app/pages/refuges/refuge-detail/refuges-detail.page.ts @@ -151,7 +151,8 @@ export class RefugesDetailPage implements OnInit { } editRefuge() { - console.log('edit refuge'); + if (this.refuge == undefined) return; + this.router.navigate(['refuges', 'update', this.refuge.id]).then(); } deleteRefuge() { diff --git a/app/src/app/pages/refuges/refuge-update/refuge-udpate.page.ts b/app/src/app/pages/refuges/refuge-update/refuge-udpate.page.ts index 5e703ba..5adb72a 100644 --- a/app/src/app/pages/refuges/refuge-update/refuge-udpate.page.ts +++ b/app/src/app/pages/refuges/refuge-update/refuge-udpate.page.ts @@ -1,4 +1,25 @@ import { Component, OnInit } from '@angular/core'; +import { Refuge, UpdateRefuge } from '../../../schemas/refuge/refuge'; +import { ActivatedRoute, Router } from '@angular/router'; +import { RefugeService } from '../../../services/refuge/refuge.service'; +import { AlertController, LoadingController } from '@ionic/angular'; +import { + GetRefugeFromIdErrors, + GetRefugeResponse, +} from '../../../schemas/refuge/get-refuge-schema'; +import { match } from 'ts-pattern'; +import { + Camera, + CameraResultType, + ImageOptions, + Photo, +} from '@capacitor/camera'; +import { + PostImageErrors, + PostImageResponse, +} from '../../../schemas/image/post-image-schema'; +import { ImageService } from '../../../services/image/image.service'; +import { NgForm } from '@angular/forms'; @Component({ selector: 'app-refuge-update', @@ -6,7 +27,250 @@ import { Component, OnInit } from '@angular/core'; styleUrls: ['./refuge-update.page.scss'], }) export class RefugeUdpatePage implements OnInit { - constructor() {} + refuge?: Refuge; + form: UpdateRefuge = { + name: '', + region: '', + image: 'no-photo.png', + altitude: 0, + coordinates: { + latitude: 0, + longitude: 0, + }, + capacity: { + winter: 0, + summer: 0, + }, + }; + + hasError: boolean = false; + errorMessage: string = ''; + + constructor( + private router: Router, + private route: ActivatedRoute, + private refugeService: RefugeService, + private alertController: AlertController, + private loadingController: LoadingController, + private imageService: ImageService, + ) { + const refugeId = this.getRefugeIdFromUrl(); + this.fetchRefuge(refugeId).then(); + } ngOnInit() {} + + private getRefugeIdFromUrl(): string | null { + return this.route.snapshot.paramMap.get('id'); + } + + private async fetchRefuge(refugeId: string | null): Promise { + if (refugeId != null) this.fetchRefugeFromId(refugeId); + else this.router.navigate(['login']).then(); + } + + private fetchRefugeFromId(refugeId: string) { + this.refugeService.getRefugeFrom(refugeId).subscribe({ + next: (response: GetRefugeResponse) => + this.handleGetRefugeResponse(response), + error: () => this.handleClientError().then(), + }); + } + + private handleGetRefugeResponse(response: GetRefugeResponse) { + match(response) + .with({ status: 'correct' }, (response) => { + this.refuge = response.data; + this.form = { + name: this.refuge.name, + region: this.refuge.region, + image: this.refuge.image, + altitude: this.refuge.altitude, + coordinates: { + latitude: this.refuge.coordinates.latitude, + longitude: this.refuge.coordinates.longitude, + }, + capacity: { + winter: this.refuge.capacity.winter, + summer: this.refuge.capacity.summer, + }, + }; + }) + .with({ status: 'error' }, (response) => { + this.handleGetError(response.error); + }) + .exhaustive(); + } + + private handleGetError(error: GetRefugeFromIdErrors) { + match(error) + .with(GetRefugeFromIdErrors.NOT_FOUND, () => this.handleNotFoundRefuge()) + .with(GetRefugeFromIdErrors.CLIENT_SEND_DATA_ERROR, () => + this.handleBadUserData(), + ) + .with(GetRefugeFromIdErrors.UNKNOWN_ERROR, () => + this.handleUnknownError(), + ) + .with( + GetRefugeFromIdErrors.SERVER_INCORRECT_DATA_FORMAT_ERROR, + GetRefugeFromIdErrors.PROGRAMMER_SEND_DATA_ERROR, + () => this.handleBadProgrammerData(), + ) + .exhaustive(); + } + + private handleNotFoundRefuge() { + this.finishLoadAnimAndExecute(() => + this.router + .navigate(['not-found'], { + skipLocationChange: true, + }) + .then(), + ).then(); + } + + private async handleBadProgrammerData() { + this.finishLoadAnimAndExecute(() => + this.router + .navigate(['programming-error'], { + skipLocationChange: true, + }) + .then(), + ).then(); + } + + private async handleBadUserData() { + this.finishLoadAnimAndExecute(() => + this.router + .navigate(['not-found-page'], { + skipLocationChange: true, + }) + .then(), + ).then(); + } + + private async handleUnknownError() { + this.finishLoadAnimAndExecute(() => + this.router + .navigate(['internal-error-page'], { + skipLocationChange: true, + }) + .then(), + ).then(); + } + + private async handleClientError() { + const alert = await this.alertController.create({ + header: 'Alert', + subHeader: 'The client is failing', + message: + 'Is your internet connection working? Maybe is our fault and our server is down.', + buttons: [ + { + text: 'OK', + handler: () => { + this.alertController.dismiss().then(); + this.fetchRefuge(this.getRefugeIdFromUrl()); + }, + }, + ], + }); + return await alert.present(); + } + + private async finishLoadAnimAndExecute( + func: (() => void) | (() => Promise), + ) { + await this.loadingController.dismiss().then(); + await func(); + } + + async postImageLoading(): Promise { + const loading = await this.loadingController.create({ + message: 'Pujant imatge...', + translucent: true, + }); + return await loading.present(); + } + + async pickImage() { + const options: ImageOptions = { + quality: 100, + allowEditing: true, + resultType: CameraResultType.Base64, + }; + await Camera.getPhoto(options).then((image: Photo) => { + this.postImageLoading().then(() => { + this.imageService.uploadImage(image).subscribe({ + next: (response: PostImageResponse) => { + this.handlePostImageResponse(response); + }, + error: () => { + this.handleClientError().then(); + }, + }); + }); + }); + } + + private handlePostImageResponse(response: PostImageResponse): void { + match(response) + .with({ status: 'correct' }, (response) => { + this.handleCorrectPostImageResponse(response.data); + }) + .with({ status: 'error' }, async (response) => { + this.handleImageError(response.error); + }) + .exhaustive(); + } + + private handleCorrectPostImageResponse(filePath: string) { + this.loadingController.dismiss().then(() => { + this.form.image = filePath; + }); + } + + private handleImageError(error: PostImageErrors) { + match(error) + .with(PostImageErrors.INVALID_REQUEST, () => { + this.handleInvalidRequestError().then(); + }) + .with(PostImageErrors.PROGRAMMER_SEND_DATA_ERROR, () => { + this.handleBadProgrammerData().then(); + }) + .with(PostImageErrors.UNKNOWN_ERROR, () => { + this.handleUnknownError().then(); + }) + .with(PostImageErrors.SERVER_INCORRECT_DATA_FORMAT_ERROR, () => { + this.handleUnknownError().then(); + }) + .exhaustive(); + } + + private async handleInvalidRequestError() { + await this.showError(async () => { + await this.showErrorMessage( + 'El format del fitxer ha de ser .png o .jpeg', + ).then(); + }); + } + + private async showError(func: (() => void) | (() => Promise)) { + await this.loadingController.dismiss(); + await func(); + } + + private async showErrorMessage(message: string) { + this.hasError = true; + await this.showError(() => (this.errorMessage = message)); + } + + onUpdate(form: NgForm) { + if (form.invalid) return; + } + + getImageUrl(): string | undefined { + if (this.refuge == undefined) return undefined; + return this.refugeService.getImageUrlFor(this.refuge); + } } diff --git a/app/src/app/pages/refuges/refuge-update/refuge-update.page.html b/app/src/app/pages/refuges/refuge-update/refuge-update.page.html index 0197adc..9b9ceaa 100644 --- a/app/src/app/pages/refuges/refuge-update/refuge-update.page.html +++ b/app/src/app/pages/refuges/refuge-update/refuge-update.page.html @@ -5,9 +5,118 @@ - - - Update refuge - - + +
+
+ + + + + + + + + + + + + + + {{errorMessage}} + + + Update refuge + + + +
+
diff --git a/app/src/app/pages/refuges/refuge-update/refuge-update.page.scss b/app/src/app/pages/refuges/refuge-update/refuge-update.page.scss index e69de29..81b1415 100644 --- a/app/src/app/pages/refuges/refuge-update/refuge-update.page.scss +++ b/app/src/app/pages/refuges/refuge-update/refuge-update.page.scss @@ -0,0 +1,22 @@ +.sign-up-logo { + min-height: 200px; + padding: 20px 0; + text-align: center; +} + +.sign-up-logo img { + max-width: 250px; +} + +.sign-up-logo img:hover { + cursor: pointer; + opacity: 0.5; +} + +.create-refuge-form { + padding: 16px; +} + +ion-input { + margin-bottom: 10px; +} diff --git a/app/src/app/schemas/refuge/refuge.ts b/app/src/app/schemas/refuge/refuge.ts index c57b883..bb75169 100644 --- a/app/src/app/schemas/refuge/refuge.ts +++ b/app/src/app/schemas/refuge/refuge.ts @@ -18,6 +18,7 @@ export type Refuge = { }; export type CreateRefuge = Omit; +export type UpdateRefuge = Omit; export const RefugePattern: P.Pattern = {}; export function isValidId(id: string): boolean {