Creation : add hours selection in step 4

This commit is contained in:
Tykayn 2021-11-22 15:30:23 +01:00 committed by tykayn
parent edcb1bdcf8
commit 135cc5e512
14 changed files with 194 additions and 35 deletions

View File

@ -18,7 +18,7 @@ export class PollConfiguration {
public hasMaxCountOfAnswers: boolean = false, public hasMaxCountOfAnswers: boolean = false,
public whoCanChangeAnswers: string = environment.poll.defaultConfig.whoCanChangeAnswers, // everybody, self, nobody (= just admin) public whoCanChangeAnswers: string = environment.poll.defaultConfig.whoCanChangeAnswers, // everybody, self, nobody (= just admin)
public visibility: string = environment.poll.defaultConfig.visibility, // visible to anyone with the link: public visibility: string = environment.poll.defaultConfig.visibility, // visible to anyone with the link:
public voteChoices: string = environment.poll.defaultConfig.voteChoices, // possible answers to a vote choice: only "yes", "yes, maybe, no": number = environment.poll.defaultConfig.maxCountOfAnswers, public voteChoices: string = environment.poll.defaultConfig.voteChoices, // possible answers to a vote timeSlice: only "yes", "yes, maybe, no": number = environment.poll.defaultConfig.maxCountOfAnswers,
public maxCountOfAnswers: number = environment.poll.defaultConfig.maxCountOfAnswers, public maxCountOfAnswers: number = environment.poll.defaultConfig.maxCountOfAnswers,
public expiresDaysDelay: number = environment.poll.defaultConfig.expiresDaysDelay, public expiresDaysDelay: number = environment.poll.defaultConfig.expiresDaysDelay,
public expiracyAfterLastModificationInDays: number = environment.poll.defaultConfig public expiracyAfterLastModificationInDays: number = environment.poll.defaultConfig

View File

@ -8,3 +8,13 @@ export interface DateChoice {
export interface TimeSlices { export interface TimeSlices {
literal: string; literal: string;
} }
export const timeSlicesProposals: TimeSlices[] = [
{ literal: 'matin' },
{ literal: 'midi' },
{ literal: 'après-midi' },
{ literal: 'soir' },
{ literal: 'aux aurores' },
{ literal: 'au petit dej' },
{ literal: 'au deuxième petit dej des hobbits' },
];

View File

@ -17,7 +17,7 @@ export class PollDTO {
myPolls; // list of retrieved polls from the backend api myPolls; // list of retrieved polls from the backend api
allowSeveralHours; allowSeveralHours;
visibility; // visible to one with the link: visibility; // visible to one with the link:
voteChoices = 'yes; maybe; no'; // possible answers to a vote choice: only "yes"; "yes; maybe; no" voteChoices = 'yes; maybe; no'; // possible answers to a vote timeSlice: only "yes"; "yes; maybe; no"
created_at; created_at;
expirationDate; // expiracy date expirationDate; // expiracy date
voteStackId; // id of the vote stack to update voteStackId; // id of the vote stack to update

View File

@ -77,7 +77,6 @@ export class PollService implements Resolve<Poll> {
} }
if (environment.autofill_creation) { if (environment.autofill_creation) {
this.setDemoValues(); this.setDemoValues();
this.toastService.display('auto fill de création fait');
} }
if (environment.autoSendNewPoll) { if (environment.autoSendNewPoll) {
this.createPoll(); this.createPoll();
@ -303,7 +302,11 @@ export class PollService implements Resolve<Poll> {
converted.push({ converted.push({
literal: element.literal, literal: element.literal,
date_object: element.date_object, date_object: element.date_object,
timeList: [], timeList: [
{
literal: 'matin',
},
],
}); });
}); });
this.dateChoiceList = [...new Set(converted)]; this.dateChoiceList = [...new Set(converted)];
@ -327,14 +330,14 @@ export class PollService implements Resolve<Poll> {
const lastChoice = this.choices.length - 1 === choice_number; const lastChoice = this.choices.length - 1 === choice_number;
// reset field with Ctrl + D // reset field with Ctrl + D
// add a field with Ctrl + N // add a field with Ctrl + N
// go to previous choice with arrow up // go to previous timeSlice with arrow up
// go to next choice with arrow down // go to next timeSlice with arrow down
if ($event.key == 'ArrowUp' && choice_number > 0) { if ($event.key == 'ArrowUp' && choice_number > 0) {
this.focusOnChoice(choice_number - 1); this.focusOnChoice(choice_number - 1);
} }
if ($event.key == 'ArrowDown') { if ($event.key == 'ArrowDown') {
// add a field if we are on the last choice // add a field if we are on the last timeSlice
if (lastChoice) { if (lastChoice) {
this.addChoice(); this.addChoice();
this.toastService.display('choix ajouté par raccourci "flèche bas"'); this.toastService.display('choix ajouté par raccourci "flèche bas"');
@ -374,7 +377,7 @@ export class PollService implements Resolve<Poll> {
} }
/** /**
* add a time period to a specific date choice, * add a time period to a specific date timeSlice,
* focus on the new input * focus on the new input
* @param config * @param config
* @param id * @param id

View File

@ -71,7 +71,7 @@ export class StorageService {
// console.log('autofill au hasard des votes à ce sondage'); // console.log('autofill au hasard des votes à ce sondage');
// this.toastService.display('autofill au hasard des votes à ce sondage'); // this.toastService.display('autofill au hasard des votes à ce sondage');
// const defaultvalue = Math.random() > 0.75 ? 'yes' : ''; // const defaultvalue = Math.random() > 0.75 ? 'yes' : '';
// this.vote_stack.votes.push(new Vote(choice.id, defaultvalue)); // this.vote_stack.votes.push(new Vote(timeSlice.id, defaultvalue));
// } else { // } else {
this.vote_stack.votes.push(new Vote(choice.id)); this.vote_stack.votes.push(new Vote(choice.id));
// } // }
@ -80,7 +80,7 @@ export class StorageService {
} }
/** /**
* look for a choice in the stored vote stack and change it answer * look for a timeSlice in the stored vote stack and change it answer
* @param choice_id * @param choice_id
* @param value * @param value
*/ */
@ -97,7 +97,7 @@ export class StorageService {
} }
/** /**
* check for the value of a choice in the stored vote stack * check for the value of a timeSlice in the stored vote stack
* @param choice_id * @param choice_id
* @param value * @param value
*/ */
@ -113,7 +113,7 @@ export class StorageService {
} }
/** /**
* set all time slices of a choice to the same answer at once * set all time slices of a timeSlice to the same answer at once
* @param groupe * @param groupe
* @param newAnswer * @param newAnswer
*/ */

View File

@ -24,8 +24,8 @@
> >
<!-- <span class="button is-default">--> <!-- <span class="button is-default">-->
<!-- <i class="icon fa fa-arrows-v"></i>--> <!-- <i class="icon fa fa-arrows-v"></i>-->
<!-- <span *ngIf="choice.date_object">--> <!-- <span *ngIf="timeSlice.date_object">-->
<!-- {{ choice.date_object | date: 'E':'Europe/Paris':'fr_FR' }}--> <!-- {{ timeSlice.date_object | date: 'E':'Europe/Paris':'fr_FR' }}-->
<!-- </span>--> <!-- </span>-->
<!-- </span>--> <!-- </span>-->
<div class="columns"> <div class="columns">

View File

@ -60,7 +60,7 @@ export class DayListComponent {
} }
/** /**
* add a time period to a specific date choice, * add a time period to a specific date timeSlice,
* focus on the new input * focus on the new input
* @param choice DateChoice * @param choice DateChoice
* @param id number * @param id number
@ -79,7 +79,7 @@ export class DayListComponent {
if (firstField) { if (firstField) {
firstField.focus(); firstField.focus();
} else { } else {
console.log('no last time choice found'); console.log('no last time timeSlice found');
} }
} }
@ -97,15 +97,15 @@ export class DayListComponent {
// TODO handle shortcuts // TODO handle shortcuts
// reset field with Ctrl + D // reset field with Ctrl + D
// add a field with Ctrl + N // add a field with Ctrl + N
// go to previous choice with arrow up // go to previous timeSlice with arrow up
// go to next choice with arrow down // go to next timeSlice with arrow down
console.log('$event', $event); console.log('$event', $event);
if ($event.ctrlKey && $event.key == 'ArrowUp' && choice_number > 0) { if ($event.ctrlKey && $event.key == 'ArrowUp' && choice_number > 0) {
this.focusOnChoice(choice_number - 1); this.focusOnChoice(choice_number - 1);
} }
if ($event.ctrlKey && ($event.key == 'ArrowDown' || $event.key == 'ArrowRight')) { if ($event.ctrlKey && ($event.key == 'ArrowDown' || $event.key == 'ArrowRight')) {
// add a field if we are on the last choice // add a field if we are on the last timeSlice
if (lastChoice) { if (lastChoice) {
this.addChoice(); this.addChoice();
this.toastService.display('choix ajouté par raccourci "flèche bas"'); this.toastService.display('choix ajouté par raccourci "flèche bas"');

View File

@ -60,7 +60,7 @@ export class TimeListComponent implements OnInit {
focusOnLastField() { focusOnLastField() {
this.cd.detectChanges(); this.cd.detectChanges();
if (!this.focusOnFieldNumber(this.timeSlices.length - 1)) { if (!this.focusOnFieldNumber(this.timeSlices.length - 1)) {
console.log('no last time choice found'); console.log('no last time timeSlice found');
this.createNewField(); this.createNewField();
this.focusOnLastField(); this.focusOnLastField();
} }

View File

@ -1,12 +1,81 @@
<div class="step"> <div class="step">
<div class="min-height"> <div class="min-height">
<form action="#" [formGroup]="pollService.form">
<app-stepper [step_current]="4" [step_max]="pollService.step_max"></app-stepper> <app-stepper [step_current]="4" [step_max]="pollService.step_max"></app-stepper>
<app-errors-list [form]="pollService.form"></app-errors-list> <app-errors-list [form]="pollService.form"></app-errors-list>
<h2 class="title is-2"> <h2 class="title is-2">
Choisissez les horaires Choisissez les horaires
</h2> </h2>
</form> <app-wip-todo></app-wip-todo>
<div
class="days-list-having-separated-time-slices rounded-block"
*ngFor="let dayChoice of pollService.dateChoiceList; index as day_id"
>
<div class="heading day-choice">
{{ dayChoice.date_object | date }}
</div>
<section class="time-slice-list-of-a-day">
<div *ngFor="let timeSlice of dayChoice.timeSlices; index as id" class="time-choice padded">
<label for="dateChoices_{{ id }}"> Horaire / option {{ id + 1 }} </label>
<input
class="input is-fullwidth"
type="text"
id="dateChoices_{{ id }}"
[(ngModel)]="timeSlice.literal"
/>
<button class="button input is-full" (click)="pollService.timeList.splice(id, 1)">
<i class="fa fa-trash"></i> supprimer
</button>
</div>
<div class="add-time-choice">
<button (click)="addChoiceForDay(dayChoice)">
<i class="fa fa-plus"></i>
Ajouter horaire / option
</button>
</div>
</section>
</div>
<section class="proposals">
<h3 class="title is-3">
Propositions de créneaux horaires
</h3>
<div class="time-slices-proposals rounded-block">
<div
class="button is-rounded"
*ngFor="let text of timeSlicesProposals"
(click)="addPreselect(text.literal)"
>
{{ text.literal }}
</div>
</div>
</section>
<section class="same-time-slices">
<button class="is-outlined is-primary" (click)="toggleHasSeveralHours()">
Appliquer le même horaire / option à toutes les dates
</button>
<section class="same-time-slices rounded-block" *ngIf="pollService.form.value.hasSeveralHours">
<h3 class="title is-3">
Choisissez les horaires ou options à appliquer à toutes les dates
</h3>
<div *ngFor="let timeSlice of pollService.timeList; index as id" class="time-choice padded">
<label for="timeList_{{ id }}"> Horaire / option {{ id + 1 }} </label>
<input
class="input is-fullwidth"
type="text"
id="timeList_{{ id }}"
[(ngModel)]="timeSlice.literal"
/>
<button class="button is-block" (click)="pollService.timeList.splice(id, 1)">
<i class="fa fa-trash"></i> supprimer
</button>
</div>
<button class="is-primary button" (click)="applyTimeSlicesToDateChoices()">
Appliquer ces créneaux
</button>
</section>
</section>
</div> </div>
<div class="columns"> <div class="columns">
<div class="column"> <div class="column">

View File

@ -1,7 +1,12 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, Inject, Input, OnInit } from '@angular/core';
import { PollService } from '../../../../../core/services/poll.service'; import { PollService } from '../../../../../core/services/poll.service';
import { environment } from '../../../../../../environments/environment'; import { environment } from '../../../../../../environments/environment';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { DateUtilitiesService } from '../../../../../core/services/date.utilities.service';
import { DOCUMENT } from '@angular/common';
import { StorageService } from '../../../../../core/services/storage.service';
import { DateChoice, TimeSlices, timeSlicesProposals } from '../../../../../core/models/dateChoice.model';
import { ToastService } from '../../../../../core/services/toast.service';
@Component({ @Component({
selector: 'app-step-four', selector: 'app-step-four',
@ -15,10 +20,78 @@ export class StepFourComponent implements OnInit {
step_max: any; step_max: any;
@Input() @Input()
form: any; form: any;
showSameTimeSlices: boolean = false;
timeSlicesProposals: TimeSlices[] = timeSlicesProposals;
constructor(private router: Router, public pollService: PollService) { constructor(
private dateUtilitiesService: DateUtilitiesService,
private router: Router,
private toastService: ToastService,
@Inject(DOCUMENT) private document: any,
private storageService: StorageService,
public pollService: PollService
) {
this.pollService.step_current = 4; this.pollService.step_current = 4;
} }
ngOnInit(): void {} ngOnInit(): void {}
/**
* toggle hasSeveralHours to show an other form section
* so that the user can choose between time slices applying equally to all days in her form,
* or have the ability to define different times lices for each day
*/
toggleHasSeveralHours() {
this.pollService.form.patchValue({
hasSeveralHours: !this.pollService.form.value.hasSeveralHours,
});
}
addChoiceForDay(dayChoice: DateChoice): void {
let lastDateChoice = this.pollService.dateChoiceList[this.pollService.dateChoiceList.length];
console.log('lastDateChoice', lastDateChoice);
let lastDateChoiceObject = this.dateUtilitiesService.addDaysToDate(
this.pollService.dateChoiceList.length,
new Date()
);
if (lastDateChoice && lastDateChoice.date_object) {
lastDateChoiceObject = lastDateChoice.date_object;
} else {
lastDateChoiceObject = new Date();
}
dayChoice.timeSlices.push({
literal: '',
});
dayChoice.timeSlices.sort((a: any, b: any) => {
return a.date_object - b.date_object;
});
this.focusOnChoice(this.storageService.dateChoices.length - 1);
}
focusOnChoice(index): void {
const selector = '#choice_label_' + index;
const elem = this.document.querySelector(selector);
if (elem) {
elem.focus();
}
}
addPreselect(literal: string) {
if (
!this.pollService.timeList.find((elem) => {
return elem.literal === literal;
})
) {
this.pollService.timeList.push({ literal });
}
}
applyTimeSlicesToDateChoices() {
let timeSlicesToApply = this.pollService.timeList;
this.pollService.dateChoiceList.forEach((elem) => {
return (elem.timeSlices = timeSlicesToApply);
});
this.toastService.display(`time slices appliquées avec succès`);
}
} }

View File

@ -24,7 +24,7 @@
</span> </span>
</div> </div>
<div class="column is-narrow"> <div class="column is-narrow">
<!-- <button class="button is-white" (click)="openModal(poll, choice)">--> <!-- <button class="button is-white" (click)="openModal(poll, timeSlice)">-->
<!-- <i class="fa fa-info-circle"></i>--> <!-- <i class="fa fa-info-circle"></i>-->
<!-- </button>--> <!-- </button>-->
</div> </div>

View File

@ -5,7 +5,7 @@
Choix Choix
</th> </th>
<th *ngFor="let choice of poll.choices"> <th *ngFor="let choice of poll.choices">
<!-- {{choice.id}}--> <!-- {{timeSlice.id}}-->
<span class="label" *ngIf="poll.kind == 'text'"> <span class="label" *ngIf="poll.kind == 'text'">
{{ choice.name }} {{ choice.name }}
</span> </span>

View File

@ -15,7 +15,7 @@ export const environment = {
advanced_options_display: false, advanced_options_display: false,
autofill_participation: false, autofill_participation: false,
showDemoWarning: false, showDemoWarning: false,
autoSendNewPoll: true, autoSendNewPoll: false,
showStepperShortcuts: true, showStepperShortcuts: true,
interval_days_default: 7, interval_days_default: 7,
expiresDaysDelay: 60, expiresDaysDelay: 60,

View File

@ -298,7 +298,7 @@ mat-checkbox {
} }
} }
.block-resume { .rounded-block {
border-radius: 0.25em; border-radius: 0.25em;
background: $bg-grey; background: $bg-grey;
padding: 1em; padding: 1em;
@ -308,8 +308,8 @@ mat-checkbox {
margin: 0.5em -1em; margin: 0.5em -1em;
background: $rules; background: $rules;
} }
.go-to-step,
.go-to-step { .custom-action {
@extend .clickable; @extend .clickable;
color: $secondary_color; color: $secondary_color;
padding: 1.5em; padding: 1.5em;
@ -321,3 +321,7 @@ mat-checkbox {
} }
} }
} }
.block-resume {
@extend .rounded-block;
}