mirror of
https://framagit.org/framasoft/framadate/funky-framadate-front.git
synced 2023-08-25 13:53:14 +02:00
Merge branch 'testing-admin-rework' into 'develop'
Testing admin rework See merge request framasoft/framadate/funky-framadate-front!45
This commit is contained in:
commit
c3972694cb
@ -2,7 +2,8 @@
|
||||
image: node:latest
|
||||
|
||||
stages:
|
||||
- pages
|
||||
- build
|
||||
# - pages
|
||||
- test
|
||||
# - e2e
|
||||
|
||||
@ -10,38 +11,36 @@ cache:
|
||||
paths:
|
||||
- node_modules/
|
||||
|
||||
pages:
|
||||
stage: pages
|
||||
script:
|
||||
- yarn install --pure-lockfile
|
||||
- yarn build:prod:gitlabpage
|
||||
- mv dist/framadate/ public/
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
expire_in: '2 hours'
|
||||
only:
|
||||
- develop
|
||||
#pages:
|
||||
# stage: pages
|
||||
# script:
|
||||
# - yarn install --pure-lockfile
|
||||
# - yarn build:prod:gitlabpage
|
||||
# - mv dist/framadate/ public/
|
||||
# artifacts:
|
||||
# paths:
|
||||
# - public
|
||||
# expire_in: '2 hours'
|
||||
# only:
|
||||
# - develop
|
||||
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- npm i
|
||||
- pkill Xvfb
|
||||
- npm run test:ci
|
||||
artifacts:
|
||||
paths:
|
||||
- coverage/
|
||||
cache:
|
||||
policy: pull
|
||||
#test:
|
||||
# stage: test
|
||||
# script:
|
||||
# - npm i
|
||||
# - pkill Xvfb
|
||||
# - npm run test:ci
|
||||
# artifacts:
|
||||
# paths:
|
||||
# - coverage/
|
||||
# cache:
|
||||
# policy: pull
|
||||
|
||||
test-build:
|
||||
stage: test
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- yarn install --pure-lockfile
|
||||
- npx ng build --prod
|
||||
only:
|
||||
- master
|
||||
cache:
|
||||
policy: pull
|
||||
|
||||
|
@ -96,7 +96,7 @@ L'export d'un sondage et des résultats d'un sondage est possible au format CSV.
|
||||
# Nouveautés secondaires
|
||||
|
||||
* Choix de réponses possibles. Proposer de ne répondre que « oui » ou rien, ou aller dans la nuance en proposant « oui », « peut-être », « non », « ? ». *# Redondance ou le choix de réponses possibles de la première phrase concerne un autre choix ?*
|
||||
* Insertion d'images dans le sondage de type texte, avec des URL uniquement. Une seule image par question possible ou rien.
|
||||
* Insertion d'images dans le sondage de type texte, avec des URL uniquement. Une seule image par title possible ou rien.
|
||||
* Thème sombre.
|
||||
* Boutons pour copier dans le presse-papier les liens publics et privés / admin des sondages.
|
||||
* Limiter le nombre de participants maximum
|
||||
|
@ -19,7 +19,7 @@
|
||||
"expires": "2020-12-31"
|
||||
},
|
||||
"ownerId": 1,
|
||||
"question": "Quelle date pour le picnic ?",
|
||||
"title": "Quelle date pour le picnic ?",
|
||||
"description": "Gros badass picnic en plein air ! Come on !"
|
||||
},
|
||||
{
|
||||
@ -37,7 +37,7 @@
|
||||
"expires": "2020-11-30"
|
||||
},
|
||||
"ownerId": 2,
|
||||
"question": "On fait quoi pendant les vacances ?",
|
||||
"title": "On fait quoi pendant les vacances ?",
|
||||
"description": "Vacances en famille"
|
||||
}
|
||||
],
|
||||
|
@ -6,10 +6,14 @@
|
||||
<mat-sidenav-content>
|
||||
<div id="big_container" [class]="themeClass">
|
||||
<div class="container">
|
||||
<mat-slide-toggle (change)="sidenav.toggle()">Dev Menu</mat-slide-toggle>
|
||||
<app-header [appTitle]="appTitle" [appLogo]="appLogo"></app-header>
|
||||
<main>
|
||||
<router-outlet></router-outlet>
|
||||
<div *ngIf="devModeEnabled">
|
||||
<br />
|
||||
<mat-slide-toggle (change)="sidenav.toggle()" label="dev menu"> </mat-slide-toggle> menu
|
||||
développeur
|
||||
</div>
|
||||
</main>
|
||||
<app-footer></app-footer>
|
||||
<app-feedback></app-feedback>
|
||||
|
@ -1,12 +1,12 @@
|
||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {Title} from '@angular/platform-browser';
|
||||
import {Subscription} from 'rxjs';
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import {environment} from '../environments/environment';
|
||||
import {Theme} from './core/enums/theme.enum';
|
||||
import {LanguageService} from './core/services/language.service';
|
||||
import {ThemeService} from './core/services/theme.service';
|
||||
import {MockingService} from './core/services/mocking.service';
|
||||
import { environment } from '../environments/environment';
|
||||
import { Theme } from './core/enums/theme.enum';
|
||||
import { LanguageService } from './core/services/language.service';
|
||||
import { ThemeService } from './core/services/theme.service';
|
||||
import { MockingService } from './core/services/mocking.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@ -18,21 +18,18 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
public appLogo: string = environment.appLogo;
|
||||
public themeClass: string;
|
||||
public isSidebarOpened = false;
|
||||
public devModeEnabled = !environment.production;
|
||||
private themeSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private titleService: Title,
|
||||
private themeService: ThemeService,
|
||||
private languageService: LanguageService,
|
||||
private mockingService: MockingService
|
||||
) {
|
||||
}
|
||||
private languageService: LanguageService // private mockingService: MockingService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (!environment.production) {
|
||||
this.appTitle += ' [DEV]';
|
||||
// TODO: to be removed
|
||||
this.mockingService.init();
|
||||
}
|
||||
this.titleService.setTitle(this.appTitle);
|
||||
this.languageService.configureAndInitTranslations();
|
||||
|
@ -28,24 +28,15 @@
|
||||
|
||||
<div id="navbarBasicExample" class="navbar-menu">
|
||||
<div class="navbar-start">
|
||||
<a class="navbar-item" routerLink="/administration" routerLinkActive="is-active">
|
||||
{{ 'config.title' | translate }}
|
||||
</a>
|
||||
<a class="navbar-item" routerLink="user/polls" routerLinkActive="is-active">
|
||||
{{ 'config.find_my_polls' | translate }}
|
||||
<a class="navbar-item btn btn--primary" routerLink="administration" routerLinkActive="is-active">
|
||||
<i class="fa fa-plus-circle"></i> {{ 'config.title' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="navbar-end">
|
||||
<div class="navbar-item" #container>
|
||||
<div class="buttons has-addons is-centered clickable" (click)="openDialog()">
|
||||
<button class="button is-static"><i class="fa fa-user-circle" aria-hidden="true"></i></button>
|
||||
<button class="button is-static" *ngIf="_user | async">
|
||||
{{ (_user | async)?.pseudo || 'anonyme' }}
|
||||
</button>
|
||||
<button class="button is-static"><i class="fa fa-cogs" aria-hidden="true"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<a class="navbar-item btn btn-primary" routerLink="user/polls" routerLinkActive="is-active">
|
||||
<i class="fa fa-user"></i> {{ 'config.find_my_polls' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
@ -1,5 +1,8 @@
|
||||
:host {
|
||||
header {
|
||||
nav {
|
||||
padding-right: 1em;
|
||||
}
|
||||
.container {
|
||||
padding: 0;
|
||||
}
|
||||
|
@ -21,8 +21,4 @@ export class HeaderComponent implements OnInit {
|
||||
constructor(private userService: UserService, private modalService: ModalService) {}
|
||||
|
||||
public ngOnInit(): void {}
|
||||
|
||||
public openDialog(): void {
|
||||
this.modalService.openModal(SettingsComponent);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { DateService } from '../services/date.service';
|
||||
|
||||
export class Configuration {
|
||||
export class PollConfiguration {
|
||||
constructor(
|
||||
public isAboutDate: boolean = false,
|
||||
public isProtectedByPassword: boolean = false,
|
||||
@ -16,7 +16,7 @@ export class Configuration {
|
||||
)
|
||||
) {}
|
||||
|
||||
public static isArchived(configuration: Configuration): boolean {
|
||||
public static isArchived(configuration: PollConfiguration): boolean {
|
||||
return configuration.expires ? DateService.isDateInPast(configuration.expires) : undefined;
|
||||
}
|
||||
}
|
||||
|
@ -2,16 +2,16 @@ import { environment } from 'src/environments/environment';
|
||||
|
||||
import { Choice } from './choice.model';
|
||||
import { Comment } from './comment.model';
|
||||
import { Configuration } from './configuration.model';
|
||||
import { PollConfiguration } from './configuration.model';
|
||||
import { User } from './user.model';
|
||||
|
||||
export class Poll {
|
||||
constructor(
|
||||
public owner: User,
|
||||
public slug: string,
|
||||
public question: string,
|
||||
public title: string,
|
||||
public description?: string,
|
||||
public configuration: Configuration = new Configuration(),
|
||||
public configuration: PollConfiguration = new PollConfiguration(),
|
||||
public comments: Comment[] = [],
|
||||
public choices: Choice[] = []
|
||||
) {}
|
||||
@ -25,12 +25,12 @@ export class Poll {
|
||||
}
|
||||
|
||||
public static adaptFromLocalJsonServer(
|
||||
item: Pick<Poll, 'owner' | 'question' | 'description' | 'slug' | 'configuration' | 'comments' | 'choices'>
|
||||
item: Pick<Poll, 'owner' | 'title' | 'description' | 'slug' | 'configuration' | 'comments' | 'choices'>
|
||||
): Poll {
|
||||
const poll = new Poll(
|
||||
new User(item.owner.pseudo, item.owner.email, undefined),
|
||||
item.slug,
|
||||
item.question,
|
||||
item.title,
|
||||
item.description,
|
||||
item.configuration,
|
||||
item.comments
|
||||
|
@ -47,10 +47,13 @@ export class PollService implements Resolve<Poll> {
|
||||
}
|
||||
|
||||
public async loadPollBySlug(slug: string): Promise<void> {
|
||||
console.log('slug', slug);
|
||||
if (slug) {
|
||||
const poll: Poll | undefined = await this.apiService.getPollBySlug(slug);
|
||||
console.log({ loadPollBySlugResponse: poll });
|
||||
this.updateCurrentPoll(poll);
|
||||
}
|
||||
}
|
||||
|
||||
public updateCurrentPoll(poll: Poll): void {
|
||||
this._poll.next(poll);
|
||||
|
@ -2,8 +2,12 @@ import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { AdministrationComponent } from './administration.component';
|
||||
import { NamingComponent } from './naming/naming.component';
|
||||
|
||||
const routes: Routes = [{ path: '', component: AdministrationComponent }];
|
||||
const routes: Routes = [
|
||||
{ path: '', component: AdministrationComponent },
|
||||
{ path: 'naming', component: NamingComponent },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<!-- <app-stepper [poll]="poll"></app-stepper>-->
|
||||
<app-admin-form [poll]="poll"></app-admin-form>
|
||||
<h1 class="title is-1"><i class="fa fa-calendar" aria-hidden="true"></i> {{ 'dates.title' | translate }}</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -14,15 +14,14 @@ import { SettingsComponent } from '../../shared/components/settings/settings.com
|
||||
})
|
||||
export class AdministrationComponent implements OnInit, OnDestroy {
|
||||
public poll: Poll;
|
||||
public form: Object;
|
||||
private routeSubscription: Subscription;
|
||||
|
||||
constructor(private route: ActivatedRoute, private userService: UserService, private modalService: ModalService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (!this.userService.isCurrentUserIdentifiable()) {
|
||||
this.modalService.openModal(SettingsComponent);
|
||||
}
|
||||
this.routeSubscription = this.route.data.subscribe((data: { poll: Poll }) => {
|
||||
console.log('data', data);
|
||||
if (data.poll) {
|
||||
this.poll = data.poll;
|
||||
}
|
||||
|
@ -7,9 +7,11 @@ import { SharedModule } from '../../shared/shared.module';
|
||||
import { AdministrationRoutingModule } from './administration-routing.module';
|
||||
import { AdministrationComponent } from './administration.component';
|
||||
import { StepperComponent } from './stepper/stepper.component';
|
||||
import { NamingComponent } from './naming/naming.component';
|
||||
import { FormComponent } from './form/form.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AdministrationComponent, StepperComponent],
|
||||
declarations: [AdministrationComponent, StepperComponent, NamingComponent, FormComponent],
|
||||
imports: [
|
||||
AdministrationRoutingModule,
|
||||
CommonModule,
|
||||
|
145
src/app/features/administration/form/form.component.html
Normal file
145
src/app/features/administration/form/form.component.html
Normal file
@ -0,0 +1,145 @@
|
||||
<div class="admin-form">
|
||||
<h1 i18n>
|
||||
{{ 'creation.title' | translate }}
|
||||
</h1>
|
||||
<span class="pre-selector" i18n>
|
||||
{{ 'creation.want' | translate }}
|
||||
</span>
|
||||
<button class="btn btn--warning">
|
||||
Reset all
|
||||
</button>
|
||||
|
||||
<div class="simple">
|
||||
<form [formGroup]="pollFormGroup">
|
||||
<label for="title">Titre</label>
|
||||
<input
|
||||
#title
|
||||
matInput
|
||||
placeholder="title posée, sujet"
|
||||
formControlName="title"
|
||||
id="title"
|
||||
autofocus="autofocus"
|
||||
(change)="updateSlug()"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
mat-button
|
||||
*ngIf="title.value"
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="Clear"
|
||||
(click)="title.value = ''"
|
||||
>
|
||||
<i class="fa fa-close"></i>
|
||||
</button>
|
||||
|
||||
<label for="descr">Description</label>
|
||||
<textarea
|
||||
#description
|
||||
matInput
|
||||
id="descr"
|
||||
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>
|
||||
<h2>Choix de réponses</h2>
|
||||
<pre class="debug padded warning">
|
||||
choicesFormArray :
|
||||
{{ choicesFormArray | json }}
|
||||
</pre
|
||||
>
|
||||
|
||||
<label for="slug"
|
||||
>Url pour les participants
|
||||
|
||||
<button
|
||||
mat-button
|
||||
*ngIf="slug.value"
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="Clear"
|
||||
(click)="slug.value = ''"
|
||||
>
|
||||
<i class="fa fa-close"></i>
|
||||
</button>
|
||||
</label>
|
||||
<br />
|
||||
<span
|
||||
>{{ urlPrefix }}
|
||||
<strong>
|
||||
{{ slug.value }}
|
||||
</strong>
|
||||
</span>
|
||||
<input #slug matInput id="slug" placeholder="Url" formControlName="slug" required />
|
||||
<br />
|
||||
</form>
|
||||
</div>
|
||||
<div class="complete" *ngIf="longFormVersionEnabled">
|
||||
<form [formGroup]="configurationFormGroup">
|
||||
<h2>Version complète du formulaire</h2>
|
||||
<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>
|
||||
|
||||
<button
|
||||
mat-button
|
||||
(click)="createPoll()"
|
||||
[disabled]="!pollFormGroup.valid || !configurationFormGroup.valid"
|
||||
>
|
||||
Enregistrer le sondage
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<pre class="debug padded warning">
|
||||
poll :
|
||||
{{ poll | json }}
|
||||
</pre
|
||||
>
|
||||
</div>
|
7
src/app/features/administration/form/form.component.scss
Normal file
7
src/app/features/administration/form/form.component.scss
Normal file
@ -0,0 +1,7 @@
|
||||
:host {
|
||||
input,
|
||||
textarea {
|
||||
padding: 0.5em;
|
||||
border: solid #eee;
|
||||
}
|
||||
}
|
24
src/app/features/administration/form/form.component.spec.ts
Normal file
24
src/app/features/administration/form/form.component.spec.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FormComponent } from './form.component';
|
||||
|
||||
describe('FormComponent', () => {
|
||||
let component: FormComponent;
|
||||
let fixture: ComponentFixture<FormComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [FormComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FormComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
83
src/app/features/administration/form/form.component.ts
Normal file
83
src/app/features/administration/form/form.component.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Poll } from '../../../core/models/poll.model';
|
||||
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { UuidService } from '../../../core/services/uuid.service';
|
||||
import { DateService } from '../../../core/services/date.service';
|
||||
import { ApiService } from '../../../core/services/api.service';
|
||||
import { Choice } from '../../../core/models/choice.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-admin-form',
|
||||
templateUrl: './form.component.html',
|
||||
styleUrls: ['./form.component.scss'],
|
||||
})
|
||||
export class FormComponent implements OnInit {
|
||||
@Input()
|
||||
public poll?: Poll;
|
||||
public pollFormGroup: FormGroup;
|
||||
public configurationFormGroup: FormGroup;
|
||||
|
||||
public choicesFormArray: FormArray; // possible choices to answer
|
||||
|
||||
public longFormVersionEnabled = true;
|
||||
|
||||
public urlPrefix: string = window.location.origin + '/participation/';
|
||||
|
||||
constructor(private fb: FormBuilder, private uuidService: UuidService, private apiService: ApiService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.pollFormGroup = this.fb.group({
|
||||
title: [this.poll ? this.poll.title : '', [Validators.required]],
|
||||
slug: [this.poll ? this.poll.slug : this.uuidService.getUUID(), [Validators.required]],
|
||||
description: [this.poll ? this.poll.description : ''],
|
||||
});
|
||||
// add dynamically elements to add choices
|
||||
this.choicesFormArray = this.fb.array([
|
||||
{
|
||||
choices: this.poll.choices.forEach((elem: Choice) => {
|
||||
return {
|
||||
label: [elem.label, [Validators.required]],
|
||||
imageUrl: [elem.imageUrl, null],
|
||||
};
|
||||
}),
|
||||
},
|
||||
]);
|
||||
|
||||
this.configurationFormGroup = this.fb.group({
|
||||
isAboutDate: [this.poll ? this.poll.configuration.isAboutDate : false, [Validators.required]],
|
||||
isProtectedByPassword: [
|
||||
this.poll ? this.poll.configuration.isProtectedByPassword : false,
|
||||
[Validators.required],
|
||||
],
|
||||
isOwnerNotifiedByEmailOnNewVote: [
|
||||
this.poll ? this.poll.configuration.isOwnerNotifiedByEmailOnNewVote : false,
|
||||
[Validators.required],
|
||||
],
|
||||
isOwnerNotifiedByEmailOnNewComment: [
|
||||
this.poll ? this.poll.configuration.isOwnerNotifiedByEmailOnNewComment : false,
|
||||
[Validators.required],
|
||||
],
|
||||
isMaybeAnswerAvailable: [
|
||||
this.poll ? this.poll.configuration.isMaybeAnswerAvailable : false,
|
||||
[Validators.required],
|
||||
],
|
||||
areResultsPublic: [this.poll ? this.poll.configuration.areResultsPublic : true, [Validators.required]],
|
||||
expiracyNumberOfDays: [
|
||||
this.poll ? DateService.diffInDays(new Date(), this.poll.configuration.expires) : 60,
|
||||
[Validators.required],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
public createPoll(): void {
|
||||
if (this.pollFormGroup.valid && this.configurationFormGroup.valid) {
|
||||
console.log('Le sondage est correctement rempli, prêt à enregistrer.');
|
||||
// TODO : save the poll
|
||||
this.apiService.createPoll(this.poll);
|
||||
}
|
||||
}
|
||||
public updateSlug() {
|
||||
let newValueFormatted = 'TODO';
|
||||
this.pollFormGroup.patchValue({ slug: newValueFormatted });
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
<p>naming works!</p>
|
@ -0,0 +1,24 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { NamingComponent } from './naming.component';
|
||||
|
||||
describe('NamingComponent', () => {
|
||||
let component: NamingComponent;
|
||||
let fixture: ComponentFixture<NamingComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [NamingComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(NamingComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
12
src/app/features/administration/naming/naming.component.ts
Normal file
12
src/app/features/administration/naming/naming.component.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-naming',
|
||||
templateUrl: './naming.component.html',
|
||||
styleUrls: ['./naming.component.scss'],
|
||||
})
|
||||
export class NamingComponent implements OnInit {
|
||||
constructor() {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
}
|
@ -3,34 +3,10 @@
|
||||
<form [formGroup]="pollFormGroup">
|
||||
<ng-template matStepLabel>Informations du sondage</ng-template>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Question posée, sujet, etc.</mat-label>
|
||||
<input #question matInput placeholder="Question posée, sujet" formControlName="question" required />
|
||||
<button
|
||||
mat-button
|
||||
*ngIf="question.value"
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="Clear"
|
||||
(click)="question.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-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
|
||||
@ -51,7 +27,21 @@
|
||||
<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>
|
||||
@ -60,7 +50,7 @@
|
||||
|
||||
<mat-step [stepControl]="configurationFormGroup">
|
||||
<form [formGroup]="configurationFormGroup">
|
||||
<ng-template matStepLabel>Configuration du sondage</ng-template>
|
||||
<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
|
||||
|
@ -24,12 +24,13 @@ export class StepperComponent implements OnInit {
|
||||
|
||||
ngOnInit(): void {
|
||||
this.pollFormGroup = this.fb.group({
|
||||
question: [this.poll ? this.poll.question : '', [Validators.required]],
|
||||
question: [this.poll ? this.poll.title : '', [Validators.required]],
|
||||
slug: [this.poll ? this.poll.slug : this.uuidService.getUUID(), [Validators.required]],
|
||||
description: [this.poll ? this.poll.description : ''],
|
||||
});
|
||||
|
||||
this.configurationFormGroup = this.fb.group({
|
||||
title: [this.poll ? this.poll.configuration : false, [Validators.required]],
|
||||
isAboutDate: [this.poll ? this.poll.configuration.isAboutDate : false, [Validators.required]],
|
||||
isProtectedByPassword: [
|
||||
this.poll ? this.poll.configuration.isProtectedByPassword : false,
|
||||
|
@ -8,7 +8,7 @@
|
||||
<div class="column">
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
<p class="card-header-title">{{ poll.question }}</p>
|
||||
<p class="card-header-title">{{ poll.title }}</p>
|
||||
<p class="card-header-icon">author : {{ poll.owner?.pseudo }}</p>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
|
@ -2,7 +2,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import { Configuration } from '../../core/models/configuration.model';
|
||||
import { PollConfiguration } from '../../core/models/configuration.model';
|
||||
import { Poll } from '../../core/models/poll.model';
|
||||
import { ModalService } from '../../core/services/modal.service';
|
||||
import { UserService } from '../../core/services/user.service';
|
||||
@ -33,7 +33,7 @@ export class ConsultationComponent implements OnInit, OnDestroy {
|
||||
this.routeSubscription = this.activatedRoute.data.subscribe((data: { poll: Poll }) => {
|
||||
if (data.poll) {
|
||||
this.poll = data.poll;
|
||||
this.isArchived = Configuration.isArchived(data.poll.configuration);
|
||||
this.isArchived = PollConfiguration.isArchived(data.poll.configuration);
|
||||
} else {
|
||||
this.router.navigate(['/page-not-found']);
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
<div class="container has-text-centered">
|
||||
<ng-container *ngIf="['REGISTERED', 'ADMIN'].includes((_user | async)?.role)">
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<h1>Mes sondages</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="pollsAreLoaded">
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth">
|
||||
<thead></thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let poll of (_user | async)?.polls">
|
||||
<th>{{ poll.question }}</th>
|
||||
<th>{{ poll.title }}</th>
|
||||
<td>
|
||||
<a routerLink="{{ '../../poll/' + poll.slug + '/consultation' }}">
|
||||
{{ poll.slug }}
|
||||
@ -22,38 +22,15 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="['ANONYMOUS'].includes((_user | async)?.role)">
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<a class="button is-primary" role="button" routerLink="/">
|
||||
J’ai un compte, je me connecte
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<span>OU</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<button class="button is-primary" (click)="toggleModal()">
|
||||
Je n’ai pas de compte : envoyez-moi la liste par email
|
||||
<form (submit)="sendRetrieveEmail()">
|
||||
<input type="email" autofocus="autofocus" placeholder="contact@exemple.com" />
|
||||
<button class="button is-primary">
|
||||
envoyez-moi la liste par email
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div class="modal" [class.is-active]="isModalOpened">
|
||||
<div class="modal-background" (click)="toggleModal()"></div>
|
||||
<div class="modal-content has-background-light">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input" type="email" placeholder="Email" />
|
||||
<button class="button is-primary is-fullwidth">Envoyez le mail !</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -12,12 +12,13 @@ import { UserService } from '../../../core/services/user.service';
|
||||
export class UserPollsComponent implements OnInit {
|
||||
public _user: Observable<User> = this.userService.user;
|
||||
public isModalOpened = false;
|
||||
public pollsAreLoaded = false;
|
||||
|
||||
constructor(private userService: UserService) {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
public toggleModal(): void {
|
||||
this.isModalOpened = !this.isModalOpened;
|
||||
sendRetrieveEmail() {
|
||||
alert('TODO');
|
||||
}
|
||||
}
|
||||
|
@ -1,46 +1,40 @@
|
||||
import {Routes} from "@angular/router";
|
||||
import {HomeComponent} from "./core/components/home/home.component";
|
||||
import {PollService} from "./core/services/poll.service";
|
||||
import {PageNotFoundComponent} from "./shared/components/page-not-found/page-not-found.component";
|
||||
import { Routes } from '@angular/router';
|
||||
import { HomeComponent } from './core/components/home/home.component';
|
||||
import { PollService } from './core/services/poll.service';
|
||||
import { PageNotFoundComponent } from './shared/components/page-not-found/page-not-found.component';
|
||||
|
||||
export const routes: Routes = [
|
||||
{path: '', component: HomeComponent},
|
||||
{ path: '', component: HomeComponent },
|
||||
{
|
||||
path: 'user',
|
||||
loadChildren: () => import('./features/user-profile/user-profile.module')
|
||||
.then((m) => m.UserProfileModule),
|
||||
loadChildren: () => import('./features/user-profile/user-profile.module').then((m) => m.UserProfileModule),
|
||||
},
|
||||
{
|
||||
path: 'administration',
|
||||
loadChildren: () =>
|
||||
import('./features/administration/administration.module')
|
||||
.then((m) => m.AdministrationModule),
|
||||
resolve: {poll: PollService},
|
||||
import('./features/administration/administration.module').then((m) => m.AdministrationModule),
|
||||
// resolve: {poll: PollService},
|
||||
},
|
||||
{
|
||||
path: 'poll/:slug/administration',
|
||||
loadChildren: () =>
|
||||
import('./features/administration/administration.module')
|
||||
.then((m) => m.AdministrationModule),
|
||||
resolve: {poll: PollService},
|
||||
import('./features/administration/administration.module').then((m) => m.AdministrationModule),
|
||||
resolve: { poll: PollService },
|
||||
},
|
||||
{
|
||||
path: 'poll/:slug/consultation',
|
||||
loadChildren: () => import('./features/consultation/consultation.module')
|
||||
.then((m) => m.ConsultationModule),
|
||||
resolve: {poll: PollService},
|
||||
loadChildren: () => import('./features/consultation/consultation.module').then((m) => m.ConsultationModule),
|
||||
resolve: { poll: PollService },
|
||||
},
|
||||
{
|
||||
path: 'poll/:slug/participation',
|
||||
loadChildren: () => import('./features/participation/participation.module')
|
||||
.then((m) => m.ParticipationModule),
|
||||
resolve: {poll: PollService},
|
||||
loadChildren: () => import('./features/participation/participation.module').then((m) => m.ParticipationModule),
|
||||
resolve: { poll: PollService },
|
||||
},
|
||||
{
|
||||
path: 'oldstuff',
|
||||
loadChildren: () => import('./features/old-stuff/old-stuff.module')
|
||||
.then((m) => m.OldStuffModule),
|
||||
loadChildren: () => import('./features/old-stuff/old-stuff.module').then((m) => m.OldStuffModule),
|
||||
},
|
||||
{path: 'page-not-found', component: PageNotFoundComponent},
|
||||
{path: '**', redirectTo: 'page-not-found', pathMatch: 'full'},
|
||||
{ path: 'page-not-found', component: PageNotFoundComponent },
|
||||
{ path: '**', redirectTo: 'page-not-found', pathMatch: 'full' },
|
||||
];
|
||||
|
@ -16,11 +16,7 @@ export class SettingsComponent implements OnInit {
|
||||
|
||||
constructor(private userService: UserService, public dialogRef: MatDialogRef<SettingsComponent>) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.userSubscription = this.userService.user.subscribe((user: User) => {
|
||||
this.user = user;
|
||||
});
|
||||
}
|
||||
ngOnInit(): void {}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.userSubscription) {
|
||||
|
@ -6,6 +6,7 @@ const backendApiUrlsInDev = {
|
||||
export const environment = {
|
||||
production: true,
|
||||
appTitle: 'FramaDate',
|
||||
appVersion: '2.0.0',
|
||||
appLogo: '/assets/img/logo.png',
|
||||
api: {
|
||||
baseHref: backendApiUrlsInDev.remote,
|
||||
|
@ -10,7 +10,8 @@ const backendApiUrlsInDev = {
|
||||
export const environment = {
|
||||
production: false,
|
||||
appTitle: 'FramaDate',
|
||||
appLogo: '/assets/img/icon_voter_yes.png',
|
||||
appVersion: '2.0.0',
|
||||
appLogo: 'assets/img/logo.png',
|
||||
api: {
|
||||
baseHref: backendApiUrlsInDev.local,
|
||||
endpoints: {
|
||||
|
Loading…
Reference in New Issue
Block a user