add libs and steps components

This commit is contained in:
Tykayn 2021-11-07 14:52:49 +01:00 committed by tykayn
parent e73336c00e
commit 1a410f120b
30 changed files with 886 additions and 354 deletions

View File

@ -45,10 +45,12 @@
"@fullcalendar/core": "^4.4.0",
"@ngx-translate/core": "^12.1.2",
"@ngx-translate/http-loader": "^5.0.0",
"angular-date-value-accessor": "^1.0.2",
"axios": "^0.19.2",
"bulma": "^0.9.0",
"bulma-switch": "^2.0.0",
"chart.js": "^2.9.3",
"crypto": "^1.0.1",
"crypto-js": "^4.0.0",
"fork-awesome": "^1.1.7",
"ng-keyboard-shortcuts": "^10.1.17",
@ -57,6 +59,7 @@
"ngx-markdown": "^9.0.0",
"ngx-webstorage": "^5.0.0",
"node-forge": "^0.10.0",
"primeng": "^11.0.0",
"quill": "^1.3.7",
"rxjs": "^6.5.5",
"rxjs-compat": "^6.5.5",
@ -75,9 +78,9 @@
"@babel/preset-env": "^7.9.5",
"@babel/preset-typescript": "^7.9.0",
"@compodoc/compodoc": "^1.1.11",
"@types/crypto-js": "^4.0.0",
"@types/jest": "^26.0.0",
"@types/node": "^14.0.1",
"@types/crypto-js": "^4.0.0",
"@typescript-eslint/eslint-plugin": "^3.0.0",
"@typescript-eslint/parser": "^3.0.0",
"babel-jest": "^26.0.0",

View File

@ -17,6 +17,7 @@ import { Title } from '@angular/platform-browser';
import { DateUtilitiesService } from './date.utilities.service';
import { Stack } from '../models/stack.model';
import { Vote } from '../models/vote.model';
import { FormGroup } from '@angular/forms';
@Injectable({
providedIn: 'root',
@ -25,6 +26,16 @@ export class PollService implements Resolve<Poll> {
_poll: BehaviorSubject<Poll | undefined> = new BehaviorSubject<Poll | undefined>(undefined);
public readonly poll: Observable<Poll | undefined> = this._poll.asObservable();
public pass_hash: string;
public calendar: Date[] = [];
public form: FormGroup;
public startDateInterval: string;
public endDateInterval: string;
public intervalDays: any;
public intervalDaysDefault = 7;
public previousRouteName: string = '/administration';
public nextRouteName: string = '/administration/step/2';
public step_current: number = 1;
public step_max: number = 5;
constructor(
private http: HttpClient,
@ -262,7 +273,7 @@ export class PollService implements Resolve<Poll> {
if (this._poll && this._poll.getValue) {
const polltemp = this._poll.getValue();
if (polltemp) {
url = `${environment.frontDomain}#/poll/${polltemp.custom_url}/consultation`;
url = `${environment.api.baseHref}#/poll/${polltemp.custom_url}/consultation`;
}
}
// TODO handle pass access

View File

@ -2,11 +2,27 @@ import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AdministrationComponent } from './administration.component';
import { NamingComponent } from './naming/naming.component';
import { StepTwoComponent } from './form/steps/step-two/step-two.component';
import { StepThreeComponent } from './form/steps/step-three/step-three.component';
import { StepFourComponent } from './form/steps/step-four/step-four.component';
import { StepFiveComponent } from './form/steps/step-five/step-five.component';
import { StepOneComponent } from './form/steps/step-one/step-one.component';
const routes: Routes = [
{ path: '', component: AdministrationComponent, data: { animation: 'AdminPage' } },
{ path: 'naming', component: NamingComponent },
{
path: '',
component: AdministrationComponent,
},
{
path: 'step',
children: [
{ path: '1', component: StepOneComponent },
{ path: '2', component: StepTwoComponent },
{ path: '3', component: StepThreeComponent },
{ path: '4', component: StepFourComponent },
{ path: '5', component: StepFiveComponent },
],
},
];
@NgModule({

View File

@ -9,6 +9,12 @@ import { AdministrationComponent } from './administration.component';
import { StepperComponent } from './stepper/stepper.component';
import { NamingComponent } from './naming/naming.component';
import { FormComponent } from './form/form.component';
import { StepOneComponent } from './form/steps/step-one/step-one.component';
import { StepTwoComponent } from './form/steps/step-two/step-two.component';
import { StepThreeComponent } from './form/steps/step-three/step-three.component';
import { StepFourComponent } from './form/steps/step-four/step-four.component';
import { StepFiveComponent } from './form/steps/step-five/step-five.component';
import { CalendarModule } from 'primeng/calendar';
import { SuccessComponent } from './success/success.component';
import { DateSelectComponent } from './form/date-select/date-select.component';
import { TextSelectComponent } from './form/text-select/text-select.component';
@ -34,6 +40,12 @@ import { TimeListComponent } from './form/date/list/time/time-list.component';
KindSelectComponent,
BaseConfigComponent,
AdvancedConfigComponent,
StepOneComponent,
StepTwoComponent,
StepThreeComponent,
StepFourComponent,
StepFiveComponent,
SuccessComponent,
IntervalComponent,
DayListComponent,
PickerComponent,
@ -42,6 +54,7 @@ import { TimeListComponent } from './form/date/list/time/time-list.component';
imports: [
AdministrationRoutingModule,
CommonModule,
CalendarModule,
ReactiveFormsModule,
SharedModule,
FormsModule,

View File

@ -1,101 +1,14 @@
<div class="admin-form padded">
<div class="container is-max-widescreen">
<form [formGroup]="form">
<header class="columns">
<div class="column">
<h1 class="title is-2">
{{ 'creation.title' | translate }}
</h1>
</div>
</header>
<button class="btn is-success is-fixed-bottom" (click)="createPoll()" *ngIf="!environment.production">
<i class="fa fa-save"></i>
Enregistrer le sondage (sans vérifier)
</button>
<button class="btn btn--warning" (click)="askInitFormDefault()">
<i class="fa fa-refresh"></i>
Tout réinitialiser
</button>
<button class="btn is-default" (click)="automaticSlug()">
<i class="fa fa-refresh"></i>
Slug automatique
</button>
<main class="columns">
<div class="column">
<label class="label is-medium" for="kind">
{{ 'creation.want' | translate }}
</label>
<!-- <div class="step-choices" *ngIf="currentStep === 'base'">-->
<app-kind-select [form]="form"></app-kind-select>
<app-base-config [form]="form"></app-base-config>
<!-- </div>-->
<!-- <div class="step-choices" *ngIf="currentStep === 'choices'"> </div>-->
<app-date-select *ngIf="form.value && form.value.kind == 'date'" [form]="form"></app-date-select>
<app-text-select *ngIf="form.value && form.value.kind == 'text'" [form]="form"></app-text-select>
<div class="admin-form">
<header>
<h2 classs="title is-2">
{{ 'creation.title' | translate }}
</h2>
</header>
<section class="step-container min-height">
<router-outlet>
<app-step-one [form]="form"></app-step-one>
</router-outlet>
<button
class="btn"
[class]="{ 'is-primary': advancedDisplayEnabled, 'is-info': !advancedDisplayEnabled }"
(click)="advancedDisplayEnabled = !advancedDisplayEnabled"
>
<i class="fa fa-save"></i>
{{ 'creation.advanced' | translate }}
</button>
<app-advanced-config
[poll]="poll"
[form]="form"
*ngIf="advancedDisplayEnabled"
></app-advanced-config>
<!-- <div class="bar-nav-admin">-->
<!-- <div class="columns">-->
<!-- <div class="column">-->
<!-- <p class="control">-->
<!-- <a class="button is-light" (click)="goPreviousStep()">-->
<!-- Précédent-->
<!-- </a>-->
<!-- </p>-->
<!-- </div>-->
<!-- <div class="column">-->
<!-- <p class="control text-right">-->
<!-- <a class="button is-primary" (click)="goNextStep()">-->
<!-- Suivant-->
<!-- </a>-->
<!-- </p>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
</div>
</main>
<app-picker [form]="form" *ngIf="displayDatePicker"></app-picker>
<app-errors-list [form]="form"></app-errors-list>
<button
[disabled]="!form.valid && form.touched"
class="btn is-success is-fixed-bottom"
(click)="createPoll()"
>
<i class="fa fa-save"></i>
Enregistrer le sondage
</button>
<button class="btn is-success is-fixed-bottom" (click)="createPoll()" *ngIf="!environment.production">
<i class="fa fa-save"></i>
Enregistrer le sondage (sans vérifier)
</button>
<footer class="column" *ngIf="show_debug_data">
<h2>Debug data</h2>
<pre class="debug padded warning">
form values :
{{ form.value | json }}
</pre
>
<pre class="debug padded warning">
poll initial values :
{{ poll | json }}
</pre
>
</footer>
<hr />
</form>
</div>
<app-errors-list [form]="pollService.form"></app-errors-list>
</section>
</div>

View File

@ -0,0 +1,92 @@
<app-stepper [step_current]="5" [step_max]="5"></app-stepper>
<div class="content">
<h1 class="title is-1">
Félicitations, votre sondage "<strong>
{{ pollService.form.value.title }} </strong
>" est créé
</h1>
Un récapitulatif par email vous a été envoyé. Partagez-le au monde avec ce lien: Administrez-le avec cet autre lien:
<hr />
<h1 i18n>
{{ 'resume.title' | translate }}
</h1>
<section class="admin">
<h2 i18n>{{ 'resume.admins' | translate }}</h2>
<p>
Votre sondage «
<span class="poll-title">
{{ pollService.form.value.title }}
</span>
» a bien été créé !
</p>
<p>
Voici les liens daccès au sondage, conservez-les soigneusement ! (Si vous les perdez vous pourrez toujours
les recevoir par email)
</p>
<p>
Pour accéder au sondage et à tous ses paramètres :
<a href="{{ pollService.form.value.urlAdmin }}">{{ pollService.form.value.urlAdmin }} </a>
</p>
<app-copy-text [textToCopy]="pollService.form.value.urlAdmin"></app-copy-text>
<a href="{{ pollService.form.value.urlAdmin }}">
Voir le sondage coté administrateur·ice
</a>
<p class="note">
Note : Le sondage sera supprimé {{ pollService.form.value.deletionDateAfterLastModification }} jours après
la date de sa dernière modification.
</p>
</section>
<section class="public">
<h2 i18n>{{ 'resume.users' | translate }}</h2>
<p>
Pour accéder au sondage :
<a href="{{ pollService.form.value.urlPublic }}">{{ pollService.form.value.urlPublic }} </a>
</p>
<app-copy-text [textToCopy]="pollService.form.value.urlPublic"></app-copy-text>
<a href="{{ pollService.form.value.urlPublic }}">
Voir le sondage
</a>
</section>
<section class="mail">
<h2 i18n>{{ 'resume.links_mail' | translate }}</h2>
<a href="{{ pollService.form.value.urlPublic }}">
Voir le sondage
</a>
</section>
</div>
<div class="columns">
<div class="column"></div>
<div class="column">
<button class="btn is-primary" (click)="createPoll()" [disabled]="!form.valid || !form.valid">
<i class="fa fa-save"></i>
Enregistrer le sondage
</button>
</div>
</div>
<section class="supplement">
<img src="assets/img/undraw_Moving_twwf.svg" alt="image WIP" />
<button class="btn btn--warning" (click)="askInitFormDefault()">
<i class="fa fa-refresh"></i>
Tout réinitialiser
</button>
<button class="btn is-success" (click)="createPoll()">
<i class="fa fa-save"></i>
Enregistrer le sondage
</button>
<button class="btn is-default" (click)="pollService.automaticSlug()">
<i class="fa fa-save"></i>
Slug automatique
</button>
<div class="well">
{{ poll.custom_url }}
</div>
<div class="has-background-danger" *ngIf="!form.valid">
le formulaire est invalide
<pre> {{ form.errors | json }}</pre>
</div>
</section>

View File

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { StepFiveComponent } from './step-five.component';
describe('StepFiveComponent', () => {
let component: StepFiveComponent;
let fixture: ComponentFixture<StepFiveComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [StepFiveComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(StepFiveComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,22 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { PollService } from '../../../../../core/services/poll.service';
@Component({
selector: 'app-step-five',
templateUrl: './step-five.component.html',
styleUrls: ['./step-five.component.scss'],
})
export class StepFiveComponent implements OnInit {
@Input() step_max: any;
@Input() public form: FormGroup;
poll: any;
constructor(public pollService: PollService) {}
ngOnInit(): void {}
askInitFormDefault() {}
createPoll() {}
automaticSlug() {}
}

View File

@ -0,0 +1,127 @@
<div class="step">
<div class="min-height">
<form action="#" [formGroup]="pollService.form">
<app-stepper [step_current]="4" [step_max]="5"></app-stepper>
<div class="creator-infos">
<label class="" for="creatorEmail">
<span>
{{ 'creation.name' | translate }}
</span>
</label>
<input
#title
matInput
placeholder="pseudo"
formControlName="creatorPseudo"
id="creatorPseudo"
required
/>
<label class="hidden" for="creatorPseudo">
<span>
{{ 'creation.email' | translate }}
</span>
</label>
<input
#title
matInput
placeholder="mon-email@example.com"
formControlName="creatorEmail"
id="creatorEmail"
required
/>
</div>
<fieldset class="advanced-config">
<button class="btn is-info" (click)="advancedDisplayEnabled = !advancedDisplayEnabled">
<i class="fa fa-save"></i>
{{ 'creation.advanced' | translate }}
</button>
<fieldset class="complete well" *ngIf="advancedDisplayEnabled">
<h2>{{ 'creation.advanced' | translate }}</h2>
<br />
<label for="slug">Url pour les participants </label>
<br />
<span
>{{ urlPrefix }} <strong> {{ pollService.form.controls.custom_url.value }} </strong>
</span>
<app-copy-text
[textToCopy]="urlPrefix + pollService.form.controls.custom_url.value"
></app-copy-text>
<button
mat-button
*ngIf="form.controls.custom_url.value"
matSuffix
mat-icon-button
aria-label="Clear"
(click)="slug.value = ''"
></button>
<input #slug matInput id="slug" placeholder="Url" formControlName="slug" required />
<br />
<div appearance="outline" class="is-not-flex">
<mat-label>Nombre de jours avant expiration</mat-label>
<input
#expiracy
id="expiracy"
matInput
type="number"
placeholder="Nombre de jours avant expiration"
formControlName="expiracyNumberOfDays"
required
/>
<button
mat-button
*ngIf="expiracy.value"
matSuffix
mat-icon-button
aria-label="Clear"
(click)="expiracy.value = ''"
>
<i class="fa fa-close"></i>
</button>
</div>
<br />
<mat-checkbox class="is-not-flex" formControlName="areResultsPublic">
Les participants pourront consulter les résultats
</mat-checkbox>
<br />
<mat-checkbox class="is-not-flex" formControlName="isAboutDate">
Les choix possibles concerneront des dates
</mat-checkbox>
<br />
<mat-checkbox class="is-not-flex" formControlName="isProtectedByPassword">
Le sondage sera protégé par un mot de passe
</mat-checkbox>
<br />
<mat-checkbox class="is-not-flex" formControlName="isOwnerNotifiedByEmailOnNewVote">
Vous recevrez un mail à chaque nouvelle participation
</mat-checkbox>
<br />
<mat-checkbox class="is-not-flex" formControlName="isOwnerNotifiedByEmailOnNewComment">
Vous recevrez un mail à chaque nouveau commentaire
</mat-checkbox>
<br />
<mat-checkbox class="is-not-flex" formControlName="isMaybeAnswerAvailable">
La réponse « peut-être » sera disponible
</mat-checkbox>
</fieldset>
</fieldset>
</form>
</div>
<div class="columns">
<div class="column">
<button class="button is-secondary is-fullwidth" [routerLink]="['/administration/step/4']">
précédent
</button>
</div>
<div class="column">
<!-- [disabled]="form.invalid"-->
<button class="button is-primary is-fullwidth" [routerLink]="['/administration/step/5']">
suivant
</button>
</div>
</div>
</div>

View File

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { StepFourComponent } from './step-four.component';
describe('StepFourComponent', () => {
let component: StepFourComponent;
let fixture: ComponentFixture<StepFourComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [StepFourComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(StepFourComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,19 @@
import { Component, Input, OnInit } from '@angular/core';
import { PollService } from '../../../../../core/services/poll.service';
@Component({
selector: 'app-step-four',
templateUrl: './step-four.component.html',
styleUrls: ['./step-four.component.scss'],
})
export class StepFourComponent implements OnInit {
urlPrefix: any;
advancedDisplayEnabled: any;
@Input()
step_max: any;
@Input()
form: any;
constructor(public pollService: PollService) {}
ngOnInit(): void {}
}

View File

@ -0,0 +1,91 @@
<div class="step">
<form class="min-height" [formGroup]="pollService.form">
<app-stepper [step_current]="1" [step_max]="5"></app-stepper>
<section class="poll-title">
<h2 class="title is-2">
{{ 'creation.choose_title' | translate }}
</h2>
<div class="columns">
<div class="column">
<label class="hidden" for="title">Titre</label>
<input
class="input-lg"
#title
[placeholder]="'creation.choose_title_placeholder' | translate"
formControlName="title"
aria-placeholder="Quel resto ce soir ?"
placeholder="Quel resto ce soir ?"
id="title"
autofocus="autofocus"
required
/>
</div>
<!-- (keyup)="pollService.updateSlug()"-->
<!-- (blur)="pollService.updateSlug()"-->
<div class="column is-narrow">
<button
mat-button
*ngIf="title.value"
matSuffix
mat-icon-button
aria-label="Clear"
(click)="title.value = ''"
>
<i class="fa fa-close"></i>
</button>
</div>
</div>
</section>
<div class="poll-description">
<div class="columns">
<div class="column">
<label for="descr">Description (optionnel)</label>
<div class="rich-text-toggle">
<label for="richTextMode">mode de saisie avancée</label>
<mat-checkbox formControlName="richTextMode" id="richTextMode"></mat-checkbox>
</div>
<div class="rich-toolbar" *ngIf="pollService.form.value.richTextMode">
richTextMode activé
</div>
<textarea
class="ui-inputtextarea is-fullwidth is-block"
#description
matInput
id="descr"
class="is-large is-full"
placeholder="Description"
formControlName="description"
required
maxlength="300"
></textarea>
<div class="text-info">
300 caractères maximum
</div>
</div>
<div class="column is-narrow">
<button
mat-button
*ngIf="description.value"
matSuffix
mat-icon-button
aria-label="Clear"
(click)="description.value = ''"
>
<i class="fa fa-close"></i>
</button>
</div>
</div>
</div>
slug: {{ pollService.form.value.custom_url }}
</form>
<div class="columns">
<div class="column"></div>
<div class="column">
<!-- [disabled]="form.invalid"-->
<button class="button is-primary is-fullwidth" [routerLink]="['/administration/step/2']">
suivant
</button>
</div>
</div>
</div>

View File

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { StepOneComponent } from './step-one.component';
describe('StepOneComponent', () => {
let component: StepOneComponent;
let fixture: ComponentFixture<StepOneComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [StepOneComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(StepOneComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,19 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { PollService } from '../../../../../core/services/poll.service';
@Component({
selector: 'app-step-one',
templateUrl: './step-one.component.html',
styleUrls: ['./step-one.component.scss'],
})
export class StepOneComponent implements OnInit {
constructor(public pollService: PollService) {}
@Input()
step_max: any;
@Input()
form: FormGroup;
ngOnInit(): void {}
}

View File

@ -0,0 +1,98 @@
<div class="min-height">
<app-stepper [step_current]="3" [step_max]="5"></app-stepper>
<!-- choix spécialement pour les dates-->
<div class="dates-list">
<div class="title">
<span class="count-dates">
{{ pollService.timeList.length }}
</span>
<span class="count-dates-txt">
{{ 'dates.count_time' | translate }}
(pour chaque jour)
</span>
</div>
<div class="actions">
<button
(click)="pollService.addTime()"
*ngIf="'false' === pollService.allowSeveralHours"
class="btn btn--primary"
id="add_time_button"
>
<i class="fa fa-plus" aria-hidden="true"></i>
{{ 'dates.add_time' | translate }}
</button>
<button
(click)="pollService.removeAllTimes()"
*ngIf="'false' === pollService.allowSeveralHours"
class="btn btn--warning"
id="remove_time_button"
>
<i class="fa fa-trash" aria-hidden="true"></i>
Aucune plage horaire
</button>
<button
(click)="pollService.resetTimes()"
*ngIf="'false' === pollService.allowSeveralHours"
class="btn btn--warning"
id="reset_time_button"
>
<i class="fa fa-refresh" aria-hidden="true"></i>
réinitialiser
</button>
</div>
<div *ngIf="'false' === pollService.allowSeveralHours" class="identical-dates">
<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)">
<div *ngFor="let time of pollService.timeList; index as id" class="time-choice" cdkDrag>
<label for="timeChoices_{{ id }}">
<i class="fa fa-clock-o" aria-hidden="true"></i>
</label>
<input
[(ngModel)]="time.literal"
name="timeChoices_{{ id }}"
type="text"
id="timeChoices_{{ id }}"
/>
<button (click)="time.timeList.splice(id, 1)" class="btn btn-warning">
<i class="fa fa-times" aria-hidden="true"></i>
</button>
</div>
</div>
</div>
<hr />
<span class="count-dates title">
{{ pollService.calendar.length }}
</span>
<span>
{{ 'dates.count_dates' | translate }}
</span>
<div class="calendar">
<p-calendar
[(ngModel)]="pollService.calendar"
firstDayOfWeek="5"
selectionMode="multiple"
inputId="multiple"
showButtonBar="true"
[inline]="true"
[showWeek]="true"
></p-calendar>
</div>
<!-- <div class="debug">-->
<!-- <pre>{{pollService.calendar |json}}</pre>-->
<!-- </div>-->
</div>
</div>
<div class="columns">
<div class="column">
<button class="button is-secondary is-fullwidth" [routerLink]="['/administration/step/2']">
précédent
</button>
</div>
<div class="column">
<!-- [disabled]="form.invalid"-->
<button class="button is-primary is-fullwidth" [routerLink]="['/administration/step/4']">
suivant
</button>
</div>
</div>

View File

@ -0,0 +1,9 @@
@import '../../../../../../styles/variables';
.ui-datepicker table td.ui-datepicker-today > a.ui-state-active,
.ui-datepicker table td.ui-datepicker-today > span.ui-state-active {
background-color: $primary-color !important;
}
.calendar {
margin-top: 1em;
}

View File

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { StepThreeComponent } from './step-three.component';
describe('StepThreeComponent', () => {
let component: StepThreeComponent;
let fixture: ComponentFixture<StepThreeComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [StepThreeComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(StepThreeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,23 @@
import { Component, Input, OnInit } from '@angular/core';
import { PollService } from '../../../../../core/services/poll.service';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
@Component({
selector: 'app-step-three',
templateUrl: './step-three.component.html',
styleUrls: ['./step-three.component.scss'],
})
export class StepThreeComponent implements OnInit {
@Input()
step_max: any;
@Input()
form: any;
constructor(public pollService: PollService) {}
ngOnInit(): void {}
drop(event: CdkDragDrop<string[]>) {
// moveItemInArray(this.pollService.choices, event.previousIndex, event.currentIndex);
}
}

View File

@ -0,0 +1,43 @@
<div class="form-field poll-kind">
<div class="min-height">
<app-stepper [step_current]="2" [step_max]="5"></app-stepper>
<h2 class="title is-2">
{{ 'creation.want' | translate }}
</h2>
<div class="kind-of-poll columns">
<div class="column">
<button
class="button is-fullwidth"
[ngClass]="{ 'is-selected is-primary': pollService.form.controls.isAboutDate.value }"
(click)="pollService.form.controls.isAboutDate.setValue(true)"
>
<i class="fa fa-calendar"></i>
{{ 'creation.kind.date' | translate }}
</button>
</div>
<div class="column">
<button
class="button is-fullwidth"
[ngClass]="{ 'is-selected is-primary': !pollService.form.controls.isAboutDate.value }"
(click)="pollService.form.controls.isAboutDate.setValue(false)"
>
<i class="fa fa-list-ul"></i>
{{ 'creation.kind.classic' | translate }}
</button>
</div>
</div>
</div>
<div class="columns">
<div class="column">
<button class="button is-secondary is-fullwidth" [routerLink]="['/administration/step/1']">
précédent
</button>
</div>
<div class="column">
<!-- [disabled]="form.invalid"-->
<button class="button is-primary is-fullwidth" [routerLink]="['/administration/step/3']">
suivant
</button>
</div>
</div>
</div>

View File

@ -0,0 +1,3 @@
.fa {
margin-right: 1em;
}

View File

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { StepTwoComponent } from './step-two.component';
describe('StepTwoComponent', () => {
let component: StepTwoComponent;
let fixture: ComponentFixture<StepTwoComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [StepTwoComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(StepTwoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,61 @@
import { ChangeDetectorRef, Component, Inject, Input, OnInit } from '@angular/core';
import { FormArray, FormBuilder } from '@angular/forms';
import { DOCUMENT } from '@angular/common';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { Router } from '@angular/router';
import { UuidService } from '../../../../../core/services/uuid.service';
import { ToastService } from '../../../../../core/services/toast.service';
import { PollService } from '../../../../../core/services/poll.service';
import { DateUtilitiesService } from '../../../../../core/services/date.utilities.service';
import { ApiService } from '../../../../../core/services/api.service';
@Component({
selector: 'app-step-two',
templateUrl: './step-two.component.html',
styleUrls: ['./step-two.component.scss'],
})
export class StepTwoComponent implements OnInit {
ngOnInit(): void {}
@Input()
form: any;
@Input()
step_max: any;
timeList: any;
allowSeveralHours: string;
dateList: any;
showDateInterval: boolean;
intervalDays: any;
constructor(
private fb: FormBuilder,
private cd: ChangeDetectorRef,
private uuidService: UuidService,
private toastService: ToastService,
public pollService: PollService,
private router: Router,
public dateUtilities: DateUtilitiesService,
private apiService: ApiService,
@Inject(DOCUMENT) private document: any
) {
this.form = this.pollService.form;
}
addIntervalOfDates() {}
get choices(): FormArray {
return this.form.get('choices') as FormArray;
}
addTime() {}
removeAllTimes() {}
resetTimes() {}
addChoice() {}
addTimeToDate(choice: any, id: number) {}
countDays() {}
}

View File

@ -1,114 +1,11 @@
<mat-vertical-stepper #stepper linear>
<mat-step [stepControl]="pollFormGroup" class="is-expanded">
<form [formGroup]="pollFormGroup">
<ng-template matStepLabel>Informations du sondage</ng-template>
<mat-form-field appearance="outline">
<mat-label>Titre</mat-label>
<input #title matInput placeholder="Question posée, sujet" formControlName="title" required />
</mat-form-field>
<mat-form-field appearance="outline" class="is-flex">
<mat-label>Description</mat-label>
<textarea
#description
matInput
placeholder="Description"
formControlName="description"
required
></textarea>
<button
mat-button
*ngIf="description.value"
matSuffix
mat-icon-button
aria-label="Clear"
(click)="description.value = ''"
>
<i class="fa fa-close"></i>
</button>
</mat-form-field>
<mat-form-field appearance="outline" class="is-flex">
<mat-label>Url pour les participants</mat-label>
<span matPrefix>{{ urlPrefix }}</span>
<input #slug matInput placeholder="Url" formControlName="slug" required />
<button
mat-button
*ngIf="slug.value"
matSuffix
mat-icon-button
aria-label="Clear"
(click)="slug.value = ''"
>
<i class="fa fa-close"></i>
</button>
</mat-form-field>
<div>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step [stepControl]="configurationFormGroup">
<form [formGroup]="configurationFormGroup">
<ng-template matStepLabel>PollConfiguration du sondage</ng-template>
<mat-form-field appearance="outline" class="is-flex">
<mat-label>Nombre de jours avant expiration</mat-label>
<input
#expiracy
matInput
type="number"
placeholder="Nombre de jours avant expiration"
formControlName="expiracyNumberOfDays"
required
/>
<button
mat-button
*ngIf="expiracy.value"
matSuffix
mat-icon-button
aria-label="Clear"
(click)="expiracy.value = ''"
>
<i class="fa fa-close"></i>
</button>
</mat-form-field>
<mat-checkbox class="is-flex" formControlName="areResultsPublic">
Les participants pourront consulter les résultats
</mat-checkbox>
<mat-checkbox class="is-flex" formControlName="isAboutDate">
Les choix possibles concerneront des dates
</mat-checkbox>
<mat-checkbox class="is-flex" formControlName="isProtectedByPassword">
Le sondage sera protégé par un mot de passe
</mat-checkbox>
<mat-checkbox class="is-flex" formControlName="isOwnerNotifiedByEmailOnNewVote">
Vous recevrez un mail à chaque nouvelle participation
</mat-checkbox>
<mat-checkbox class="is-flex" formControlName="isOwnerNotifiedByEmailOnNewComment">
Vous recevrez un mail à chaque nouveau commentaire
</mat-checkbox>
<mat-checkbox class="is-flex" formControlName="isMaybeAnswerAvailable">
La réponse « peut-être » sera disponible
</mat-checkbox>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step>
<ng-template matStepLabel>Done</ng-template>
<p>You are now done.</p>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button (click)="stepper.reset()">Reset</button>
</div>
<div>
<button mat-button (click)="savePoll()" [disabled]="!pollFormGroup.valid || !configurationFormGroup.valid">
Enregistrer le sondage
</button>
</div>
</mat-step>
</mat-vertical-stepper>
<section class="creation-stepper">
<div class="step-info">
<h2 class="title is-2">
Étape {{ step_current }} /
{{ step_max }}
</h2>
</div>
<div class="step-bar-container" style="width: 100%;">
<div class="step-bar-progress" [ngStyle]="{ width: (step_current / step_max) * 100 + '%' }"></div>
</div>
</section>

View File

@ -0,0 +1,19 @@
@import '../../../../styles/variables';
.step-bar-container {
margin: 1em 0;
height: 0.5em;
display: inline-block;
min-width: 1px;
background: $border-color !important;
width: 100%;
}
.step-bar-progress {
position: relative;
top: -0.6em;
left: 0;
height: 0.5em;
display: inline-block;
min-width: 1px;
background: $primary_color;
}

View File

@ -1,55 +1,13 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Poll } from '../../../core/models/poll.model';
import { UuidService } from '../../../core/services/uuid.service';
import { DateService } from '../../../core/services/date.service';
@Component({
selector: 'app-stepper',
templateUrl: './stepper.component.html',
styleUrls: ['./stepper.component.scss'],
})
export class StepperComponent implements OnInit {
export class StepperComponent {
@Input()
public poll?: Poll;
public pollFormGroup: FormGroup;
public configurationFormGroup: FormGroup;
public choicesFormGroup: FormGroup;
public urlPrefix = '/participation/';
constructor(private fb: FormBuilder, private uuidService: UuidService) {}
ngOnInit(): void {
this.pollFormGroup = this.fb.group({
question: [this.poll ? this.poll.title : '', [Validators.required]],
slug: [this.poll ? this.poll.custom_url : this.uuidService.getUUID(), [Validators.required]],
description: [this.poll ? this.poll.description : ''],
});
this.configurationFormGroup = this.fb.group({
title: [this.poll ? this.poll : false, [Validators.required]],
isAboutDate: [this.poll ? this.poll.kind === 'date' : false, [Validators.required]],
isProtectedByPassword: [this.poll ? this.poll.password.length : false, [Validators.required]],
isOwnerNotifiedByEmailOnNewVote: [
this.poll ? this.poll.isOwnerNotifiedByEmailOnNewVote : false,
[Validators.required],
],
isOwnerNotifiedByEmailOnNewComment: [
this.poll ? this.poll.isOwnerNotifiedByEmailOnNewComment : false,
[Validators.required],
],
areResultsPublic: [this.poll ? this.poll.areResultsPublic : true, [Validators.required]],
expiracyNumberOfDays: [this.poll ? this.poll.default_expiracy_days_from_now : '60', [Validators.required]],
});
}
public savePoll(): void {
if (this.pollFormGroup.valid && this.configurationFormGroup.valid) {
console.log('Le sondage est correctement rempli, prêt à enregistrer.');
// TODO : save the poll
}
}
public step_current: number = 1;
@Input()
public step_max: number = 5;
}

View File

@ -1,106 +1,62 @@
@charset "UTF-8";
// ****************************** config ******************************
$theme-vars: 'violet'; // violet , blue
// ****************************** colors from styleguide https://app.zeplin.io/project/5d4d83d68866d6522ff2ff10/styleguide/colors?cid=5d502bb032e23e3516af8154
// colors from styleguide https://app.zeplin.io/project/5d4d83d68866d6522ff2ff10/styleguide/colors?cid=5d502bb032e23e3516af8154
$green: #64d16e;
$black: #000000;
$ugly-purple: #b24eb7;
$lavender-pink: #e9bdeb;
$white: #ffffff;
$dark-lavender: #7d6c99;
$dusty-orange: #f18647;
$violet: #bd10e0;
$red: #cd0000;
$cool-grey: #aeafb1;
$warm-grey: #807e7e;
$green: #64d16e;
$dusty-orange: #f18647;
$red: #cd0000;
$pink: #fa7c91;
$purple: #8a4d76;
$ugly-purple: #b24eb7;
$violet: #bd10e0;
$wisteria: #bf83c2;
$pale-purple: #d198d4;
$lavender-pink: #e9bdeb;
$dark-lavender: #7d6c99;
// themes ****************************** blue variation around styleguide
$blueish-green: #64d1a9;
$blueish-dusty-orange: #74a389;
$blueish-red: #9d00cd;
$blueish-pink: #d47cfa;
$blueish-purple: #4d4d8a;
$blueish-ugly-purple: #4d5b8a;
$blueish-violet: #5810bd;
$blueish-wisteria: #8b83bf;
$blueish-pale-purple: #8a9bd1;
$blueish-lavender-pink: #8a97e9;
$blueish-dark-lavender: #7d6c8a;
$blueish-brown: #636c77;
$purple: #8a4d76;
$pink: #fa7c91;
$brown: #757763;
$beige-light: #d0d1cd;
$beige-lighter: #eff0eb;
// ****************************** interpretations in app
// DINUM colors
$primary_color: $ugly-purple;
$primary: $ugly-purple;
$secondary_color: $lavender-pink;
$d-primary: #3e3882; // bleu 800
$d-primary-intense: #6359cf; // bleu 600
$d-grey: #f6f5fd; // bleu 30
$d-neutral: #767486; // bleu 30
$d-alt: #a9607f;
$d-info: #ecf4ff;
$d-info-text: #316ec7;
$d-success: #ecfff5;
$d-success-text: #128149;
$d-warning: #dcd3bb;
$d-warning-text: #86671b;
$d-error: #ffecee;
$d-error-text: #d51b38;
// interpretations in app
$primary_color: $d-primary;
$primary: $d-primary;
$secondary_color: $d-primary-intense;
$font_color: $black;
$logo_color: $dark-lavender;
$logo_color_2: $green;
$legend_color: $dark-lavender;
$legend_color_2: $dusty-orange;
$choice_select_border_color: $cool-grey;
$hover-color: $warm-grey;
$grey-dark: $warm-grey;
$grey-light: $beige-light;
$clicked-color: $wisteria;
$mini-button-color: $pale-purple;
$warning: $dusty-orange;
$danger: $red;
$success: $green;
// ****************************** render ******************************
@if $theme-vars == 'violet' {
$primary_color: $ugly-purple;
$primary: $ugly-purple;
$secondary_color: $lavender-pink;
$font_color: $black;
$logo_color: $dark-lavender;
$logo_color_2: $green;
$legend_color: $dark-lavender;
$legend_color_2: $dusty-orange;
$choice_select_border_color: $cool-grey;
$hover-color: $warm-grey;
$grey-dark: $warm-grey;
$grey-light: $beige-light;
$clicked-color: $wisteria;
$mini-button-color: $pale-purple;
$warning: $dusty-orange;
$danger: $red;
$success: $green;
$logo_color: $d-primary;
$logo_color_2: $d-primary-intense;
$legend_color: $d-info-text;
$legend_color_2: $d-info;
$choice_select_border_color: $d-info;
$hover-color: $d-neutral;
$border-color: $d-neutral;
$grey-dark: $d-primary;
$grey-lighter: $beige-light;
$clicked-color: $d-primary;
$mini-button-color: $d-primary-intense;
$warning: $d-warning;
$danger: $d-error;
$success: $d-success;
// FONT
$default_font: 'pt_sans';
$title_font: 'proza_libre', 'Brie Light', 'Arial', 'DejaVu Sans Mono';
} @else if $theme-vars == 'blue' {
$primary_color: $blueish-ugly-purple;
$primary: $blueish-ugly-purple;
$secondary_color: $blueish-lavender-pink;
$font_color: $black;
$logo_color: $blueish-dark-lavender;
$logo_color_2: $blueish-green;
$legend_color: $blueish-dark-lavender;
$legend_color_2: $blueish-dusty-orange;
$choice_select_border_color: $cool-grey;
$hover-color: $warm-grey;
$grey-dark: $warm-grey;
$grey-light: $beige-light;
$clicked-color: $blueish-wisteria;
$mini-button-color: $blueish-pale-purple;
$warning: $blueish-dusty-orange;
$danger: $blueish-red;
$success: $blueish-green;
// FONT
$default_font: 'pt_sans';
$title_font: 'proza_libre', 'Brie Light', 'Arial', 'DejaVu Sans Mono';
}
$default_font: 'pt_sans';
$title_font: 'proza_libre', 'Brie Light', 'Arial', 'DejaVu Sans Mono';

View File

@ -2150,6 +2150,13 @@ amdefine@>=0.0.4:
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
angular-date-value-accessor@^1.0.2:
version "1.2.1"
resolved "https://registry.yarnpkg.com/angular-date-value-accessor/-/angular-date-value-accessor-1.2.1.tgz#a5f07b11fef1c0d1fde5aa851057de177c510137"
integrity sha512-4lhVi5PRpaIKtsCDEHioue324u1j18t46ZrD/jI7+M6DrZeRyxfMeSGsZXWNOC6eaq9x/pzXyaE8slXSj3Qd5A==
dependencies:
tslib "^2.0.0"
ansi-align@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb"
@ -3755,6 +3762,11 @@ crypto-random-string@^2.0.0:
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
crypto@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037"
integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==
css-color-names@0.0.4, css-color-names@^0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
@ -9451,6 +9463,13 @@ pretty-format@^26.0.0, pretty-format@^26.1.0:
ansi-styles "^4.0.0"
react-is "^16.12.0"
primeng@^11.0.0:
version "11.4.5"
resolved "https://registry.yarnpkg.com/primeng/-/primeng-11.4.5.tgz#128137d727d555f68c212a1dcb1f2af3b0f4afd4"
integrity sha512-7f5LDHrvFsJA4670Ftmib5ndDxTqcaQiM88XXJrjWYNGjXsXT3Yc5g9fgPvDrg2D38/jjpcSYeW9kalNcvlbrQ==
dependencies:
tslib "^2.0.0"
prismjs@^1.20.0:
version "1.20.0"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.20.0.tgz#9b685fc480a3514ee7198eac6a3bf5024319ff03"