Added functions to send and see proof before valid participation from random challenge
This commit is contained in:
@@ -1,25 +1,69 @@
|
||||
<div class="bg-white m-4 rounded-2xl border border-amber-200 shadow-sm p-4 space-y-3">
|
||||
|
||||
<div class="grid grid-cols-5 items-center">
|
||||
|
||||
<h3 class="col-span-4 text-base font-semibold text-gray-900 m-0">
|
||||
Title
|
||||
{{ data().label }}
|
||||
</h3>
|
||||
|
||||
<span class="col-span-1 text-right text-xs font-extrabold text-yellow-900 bg-amber-50 px-2 py-1 rounded-lg">
|
||||
{{ tag() }}
|
||||
</span>
|
||||
</div>
|
||||
<p class="text-[11px] text-gray-500 leading-relaxed">Description</p>
|
||||
|
||||
<p class="text-[11px] text-gray-500 leading-relaxed">{{ data().libelle }}</p>
|
||||
|
||||
<div class="grid grid-cols-5 items-center">
|
||||
<span class="col-span-4 text-[11px] text-gray-500">
|
||||
Info supplémentaire
|
||||
</span>
|
||||
<span class="col-span-4 text-[11px] text-gray-500">
|
||||
Aucun malus pour ce défi
|
||||
</span>
|
||||
|
||||
<div class="col-span-1 flex justify-end">
|
||||
<ion-button
|
||||
fill="clear"
|
||||
class="m-0 p-0 min-h-0 text-[11px] font-black bg-black text-white rounded-3xl"
|
||||
style="--padding-top: 4px; --padding-bottom: 4px;">
|
||||
style="--padding-top: 4px; --padding-bottom: 4px;"
|
||||
(touchstart)="setOpen(true, data().id)">
|
||||
{{ action() }}
|
||||
</ion-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ion-modal [isOpen]="isModalOpen">
|
||||
<ng-template>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Défi Quotidien</ion-title>
|
||||
<ion-buttons slot="start" style="--ion-color-primary: #0054E9;">
|
||||
<ion-back-button default-href="" (touchstart)="setOpen(false, null)"></ion-back-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-padding m-1" style="--background: #f7f6f2;">
|
||||
|
||||
<div class="mt-4 bg-white rounded-2xl shadow-sm p-4 space-y-3">
|
||||
<div class="grid grid-cols-5 items-center">
|
||||
<h3 class="col-span-4 text-base font-semibold text-gray-900 m-0">
|
||||
{{ data().label }}
|
||||
</h3>
|
||||
<span class="col-span-1 text-right text-xs font-extrabold text-yellow-900 bg-amber-50 px-2 py-1 rounded-lg">
|
||||
{{ tag() }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p class="text-[11px] text-gray-500 leading-relaxed">{{ data().libelle }}</p>
|
||||
</div>
|
||||
|
||||
<app-tooltip title="Aucun malus si non réalisé"
|
||||
content="entièrement facultatif et solo. Points réduits comparé à un défi classique."></app-tooltip>
|
||||
|
||||
<div class="mb-6">
|
||||
<app-proof-form #proofForm></app-proof-form>
|
||||
</div>
|
||||
|
||||
<ion-button expand="block" (touchstart)="sendProof(data().id)">Soumettre ma preuve</ion-button>
|
||||
|
||||
</ion-content>
|
||||
</ng-template>
|
||||
</ion-modal>
|
||||
@@ -1,16 +1,74 @@
|
||||
import {Component, input} from '@angular/core';
|
||||
import {IonicModule} from "@ionic/angular";
|
||||
import {Component, inject, input, signal, viewChild} from '@angular/core';
|
||||
import {IonicModule, ToastController} from "@ionic/angular";
|
||||
import {GetRandomChallengeDto, RandomchallengesService} from "../../services/api";
|
||||
import {firstValueFrom} from "rxjs";
|
||||
import {TooltipComponent} from "../tooltip/tooltip.component";
|
||||
import {ProofFormComponent} from "../proof-form/proof-form.component";
|
||||
import {SignOnFormComponent} from "../sign-on-form/sign-on-form.component";
|
||||
|
||||
@Component({
|
||||
selector: 'app-challenge-card',
|
||||
templateUrl: './challenge-card.component.html',
|
||||
styleUrls: ['./challenge-card.component.scss'],
|
||||
imports: [
|
||||
IonicModule
|
||||
IonicModule,
|
||||
TooltipComponent,
|
||||
ProofFormComponent
|
||||
]
|
||||
})
|
||||
export class ChallengeCardComponent {
|
||||
private randomChallengesService = inject(RandomchallengesService);
|
||||
private toastCtrl = inject(ToastController);
|
||||
|
||||
action = input.required<string>();
|
||||
tag = input.required<string>();
|
||||
color = input.required<string>();
|
||||
data = input.required<GetRandomChallengeDto>();
|
||||
|
||||
selectedChallenge = signal<GetRandomChallengeDto>(null);
|
||||
|
||||
proof = viewChild<ProofFormComponent>('proofForm');
|
||||
|
||||
isModalOpen = false;
|
||||
|
||||
async setOpen(isOpen: boolean, randomChallengeId: number) {
|
||||
if (isOpen) {
|
||||
try {
|
||||
const userInfo = await firstValueFrom(this.randomChallengesService.getRandomChallengeEndpoint(randomChallengeId));
|
||||
this.selectedChallenge.set(userInfo);
|
||||
this.isModalOpen = isOpen;
|
||||
} catch {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Impossible de charger les données du défi',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async sendProof(randomChallengeId: number) {
|
||||
const file = this.proof().proofForm.value.proof;
|
||||
|
||||
try {
|
||||
await firstValueFrom(this.randomChallengesService.patchProofEndpoint(randomChallengeId, file));
|
||||
|
||||
this.isModalOpen = false;
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'La preuve de ta réussite a bien été déposée',
|
||||
duration: 2000,
|
||||
color: 'success'
|
||||
});
|
||||
await toast.present();
|
||||
} catch(err) {
|
||||
const toast = await this.toastCtrl.create({
|
||||
message: 'Impossible de déposer ta preuve',
|
||||
duration: 2000,
|
||||
color: 'danger'
|
||||
});
|
||||
await toast.present();
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<app-title-part textInfo="Ta preuve"></app-title-part>
|
||||
|
||||
<form [formGroup]="proofForm">
|
||||
<div [ngClass]="{ 'py-20': !previewUrl }" class="mt-2 rounded-lg p-1 bg-white border-2 border-dashed border-gray-300 flex items-center justify-center cursor-pointer overflow-hidden"
|
||||
(click)="fileInput.click()">
|
||||
|
||||
@if (previewUrl) {
|
||||
<ng-container>
|
||||
<img class="rounded-lg" [src]="previewUrl" alt=""/>
|
||||
</ng-container>
|
||||
} @else {
|
||||
<p class="text-xs text-gray-400 text-center"> Prendre une photo </p>
|
||||
}
|
||||
</div>
|
||||
|
||||
<input #fileInput type="file" hidden (change)="onFileChange(fileInput.files)">
|
||||
</form>
|
||||
@@ -0,0 +1,36 @@
|
||||
import {Component} from '@angular/core';
|
||||
import {FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators} from "@angular/forms";
|
||||
import {IonicModule} from "@ionic/angular";
|
||||
import {TitlePartComponent} from "../title-part/title-part.component";
|
||||
import {NgClass} from "@angular/common";
|
||||
|
||||
@Component({
|
||||
selector: 'app-proof-form',
|
||||
templateUrl: './proof-form.component.html',
|
||||
styleUrls: ['./proof-form.component.scss'],
|
||||
imports: [
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
ReactiveFormsModule,
|
||||
TitlePartComponent,
|
||||
NgClass
|
||||
]
|
||||
})
|
||||
export class ProofFormComponent {
|
||||
proofForm: FormGroup = new FormGroup({
|
||||
proof: new FormControl(null, [Validators.required]),
|
||||
})
|
||||
|
||||
previewUrl: string | null = null;
|
||||
|
||||
onFileChange(files?: FileList | null) {
|
||||
if (!files?.length) return;
|
||||
|
||||
const file = files[0];
|
||||
|
||||
this.previewUrl = URL.createObjectURL(file);
|
||||
this.proofForm.patchValue({
|
||||
proof: file
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<div [ngClass]="{
|
||||
'border-l-red-700': color() == 'red',
|
||||
'border-l-green-700': color() == 'green'}"
|
||||
class="ml-4 mr-5 pl-4 border border-gray-400 rounded-r-xl border-l-{{color()}}-700 border-l-4 bg-[#f7f6f2]">
|
||||
class="mt-4 mb-4 pl-4 border border-gray-400 rounded-r-xl border-l-{{color()}}-700 border-l-4 bg-[#f7f6f2]">
|
||||
<p class="text-[11px] text-gray-600">
|
||||
<strong class="text-gray-900">{{ title() }}</strong>
|
||||
— {{ content() }}
|
||||
|
||||
Reference in New Issue
Block a user