parent
4f0a29e806
commit
355fed53f3
@ -1 +0,0 @@
|
||||
<p>login works!</p>
|
@ -1,12 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
templateUrl: './login.component.html',
|
||||
styleUrls: ['./login.component.scss'],
|
||||
})
|
||||
export class LoginComponent implements OnInit {
|
||||
constructor() {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<div class="control has-icons-left">
|
||||
<select class="select is-small" [(ngModel)]="currentLang">
|
||||
<ng-container *ngFor="let language of languagesAvailable">
|
||||
<option value="{{ language }}">{{ 'LANGUAGES.' + language | translate }}</option>
|
||||
</ng-container>
|
||||
</select>
|
||||
<div class="icon is-left">
|
||||
<i class="fa fa-globe"></i>
|
||||
</div>
|
||||
</div>
|
@ -1,38 +0,0 @@
|
||||
import { Component, DoCheck, OnInit } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { Language } from '../../../enums/language.enum';
|
||||
import { StorageService } from '../../../services/storage.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-language-selector',
|
||||
templateUrl: './language-selector.component.html',
|
||||
styleUrls: ['./language-selector.component.scss'],
|
||||
})
|
||||
export class LanguageSelectorComponent implements OnInit, DoCheck {
|
||||
public currentLang: Language;
|
||||
public languagesAvailable: string[] = Object.values(Language);
|
||||
|
||||
constructor(private translate: TranslateService, private storageService: StorageService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
const currentBrowserLanguage: Language = this.translate.getBrowserLang().toUpperCase() as Language;
|
||||
if (this.storageService.language && Object.keys(Language).includes(this.storageService.language)) {
|
||||
this.currentLang = this.storageService.language;
|
||||
} else if (Object.keys(Language).includes(currentBrowserLanguage)) {
|
||||
this.currentLang = currentBrowserLanguage;
|
||||
} else {
|
||||
this.currentLang = Language.EN;
|
||||
}
|
||||
this.updateLanguage();
|
||||
}
|
||||
|
||||
ngDoCheck(): void {
|
||||
this.updateLanguage();
|
||||
}
|
||||
|
||||
public updateLanguage(): void {
|
||||
this.translate.use(this.currentLang.toString().toUpperCase());
|
||||
this.storageService.language = this.currentLang;
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
<div class="buttons has-addons is-centered">
|
||||
<button class="button is-small is-static">Theme</button>
|
||||
<button
|
||||
class="button is-small"
|
||||
[ngClass]="{ 'is-active': (currentTheme | async) === themeEnum.LIGHT }"
|
||||
(click)="selectTheme('LIGHT')"
|
||||
>
|
||||
<i class="fa fa-sun-o"></i>
|
||||
</button>
|
||||
<button
|
||||
class="button is-small"
|
||||
[ngClass]="{ 'is-active': (currentTheme | async) === themeEnum.DARK }"
|
||||
(click)="selectTheme('DARK')"
|
||||
>
|
||||
<i class="fa fa-moon"></i>
|
||||
</button>
|
||||
<button
|
||||
class="button is-small"
|
||||
[ngClass]="{ 'is-active': (currentTheme | async) === themeEnum.RED }"
|
||||
(click)="selectTheme('RED')"
|
||||
>
|
||||
<i class="fa fa-adjust"></i>
|
||||
</button>
|
||||
</div>
|
@ -1,4 +0,0 @@
|
||||
export enum AnswerGranularity {
|
||||
BASIC = 'BASIC',
|
||||
COMPLEX = 'COMPLEX',
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
export enum AnswerType {
|
||||
export enum Response {
|
||||
YES = 'YES',
|
||||
NO = 'NO',
|
||||
MAYBE = 'MAYBE',
|
@ -1,5 +1,5 @@
|
||||
export enum UserRole {
|
||||
ANONYMOUS = 'ANONYMOUS',
|
||||
REGISTERED = 'ADMIN',
|
||||
REGISTERED = 'REGISTERED',
|
||||
ADMIN = 'ADMIN',
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
export enum WorkflowStep {
|
||||
DESCRIPTION = 'DESCRIPTION',
|
||||
OPTIONS = 'OPTIONS',
|
||||
CHOICES = 'CHOICES',
|
||||
CONFIGURATION = 'CONFIGURATION',
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
export interface DateOption {
|
||||
timeList: any;
|
||||
literal: string;
|
||||
date_object?: object;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { AnswerType } from '../enums/answer-type.enum';
|
||||
import { PollOption } from './poll-options.model';
|
||||
import { Response } from '../enums/response.enum';
|
||||
import { Choice } from './choice.model';
|
||||
|
||||
export class Answer {
|
||||
constructor(public pollOption: PollOption, public type: AnswerType, public userPseudo: string) {}
|
||||
constructor(public author: string, public choice: Choice, public response: Response) {}
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
import { Response } from '../enums/response.enum';
|
||||
|
||||
export class Choice {
|
||||
constructor(public label: string, public responses: Response[] = [Response.YES, Response.NO]) {}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
export class Comment {
|
||||
constructor(public author: string, public content: string) {}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { DateUtilsService } from '../utils/date-utils.service';
|
||||
|
||||
export class Configuration {
|
||||
constructor(
|
||||
public isAboutDate: boolean = false,
|
||||
public slug: string = uuidv4(),
|
||||
public isProtectedByPassword: boolean = false,
|
||||
public isMaybeAnswerAvailable: boolean = false,
|
||||
public creationDate: Date = new Date(Date.now()),
|
||||
public expirationDate: Date = DateUtilsService.addDaysToDate(
|
||||
environment.poll.defaultConfig.expiracyInDays,
|
||||
new Date(Date.now())
|
||||
)
|
||||
) {}
|
||||
|
||||
public getAdministrationUrl(): string {
|
||||
return `${environment.api.baseHref}/administration/${environment.api.endpoints.polls}/${this.slug}`;
|
||||
}
|
||||
|
||||
public getParticipationUrl(): string {
|
||||
return `${environment.api.baseHref}/participation/${environment.api.endpoints.polls}/${this.slug}`;
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import { AnswerGranularity } from '../enums/answer-granularity.enum';
|
||||
|
||||
export class PollConfig {
|
||||
constructor(
|
||||
public allowSeveralHours = true,
|
||||
public isVisibleToAnyoneWithTheLink: boolean = true,
|
||||
public answerType: AnswerGranularity = AnswerGranularity.BASIC,
|
||||
public creationDate: Date = new Date(),
|
||||
public expirationDate?: Date,
|
||||
public canVotersModifyTheirAnswers = true,
|
||||
public isProtectedByPassword: boolean = false
|
||||
) {}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
import * as moment from 'moment';
|
||||
|
||||
export class PollOption {
|
||||
constructor(public label: string, public url?: string, public subOptions?: PollOption[]) {}
|
||||
|
||||
public isDatePoll(): boolean {
|
||||
return moment(this.label).isValid();
|
||||
}
|
||||
}
|
@ -1,23 +1,17 @@
|
||||
import { Answer } from './answer.model';
|
||||
import { PollConfig } from './poll-config.model';
|
||||
import { PollOption } from './poll-options.model';
|
||||
import { Choice } from './choice.model';
|
||||
import { Comment } from './comment.model';
|
||||
import { Configuration } from './configuration.model';
|
||||
import { Question } from './question.model';
|
||||
import { User } from './user.model';
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
export class Poll {
|
||||
constructor(
|
||||
public isDateType: boolean,
|
||||
public title: string,
|
||||
public description: string,
|
||||
public slug: string,
|
||||
public id: string,
|
||||
public owner?: User,
|
||||
public config?: PollConfig,
|
||||
public options: PollOption[] = [],
|
||||
public answers: Answer[] = []
|
||||
public owner: User,
|
||||
public question: Question,
|
||||
public choices: Choice[],
|
||||
public configuration: Configuration = new Configuration(),
|
||||
public answers: Answer[] = [],
|
||||
public comments: Comment[] = []
|
||||
) {}
|
||||
|
||||
public getUrl(): string {
|
||||
return `${environment.api.baseHref}/${this.slug}`;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,3 @@
|
||||
export class Question {
|
||||
constructor(public label: string, public description: string) {}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
import { Poll } from './poll.model';
|
||||
import { UserRole } from '../enums/user-role.enum';
|
||||
import { Poll } from './poll.model';
|
||||
|
||||
export class User {
|
||||
constructor(
|
||||
public pseudo: string,
|
||||
public email: string,
|
||||
public role: UserRole = UserRole.ANONYMOUS,
|
||||
public isOwner: boolean = false,
|
||||
public pseudo?: string,
|
||||
public email?: string,
|
||||
public polls?: Poll[]
|
||||
) {}
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LanguageService } from './language.service';
|
||||
|
||||
describe('LanguageService', () => {
|
||||
let service: LanguageService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(LanguageService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,66 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { TranslateService, LangChangeEvent } from '@ngx-translate/core';
|
||||
|
||||
import { Language } from '../enums/language.enum';
|
||||
import { StorageService } from './storage.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class LanguageService {
|
||||
constructor(private translate: TranslateService, private storageService: StorageService) {}
|
||||
|
||||
public getLangage(): Language {
|
||||
return this.translate.currentLang as Language;
|
||||
}
|
||||
|
||||
public setLanguage(language: Language): void {
|
||||
this.translate.use(language.toString().toUpperCase());
|
||||
}
|
||||
|
||||
public getAvailableLanguages(): string[] {
|
||||
return this.translate.getLangs();
|
||||
}
|
||||
|
||||
public configureAndInitTranslations(): void {
|
||||
// always save in storage the currentLang used
|
||||
this.translate.onLangChange.subscribe((event: LangChangeEvent) => {
|
||||
this.storageService.language = event.lang as Language;
|
||||
});
|
||||
|
||||
// set all languages available
|
||||
this.translate.addLangs(Object.keys(Language));
|
||||
|
||||
// set language
|
||||
this.setLanguageOnInit();
|
||||
}
|
||||
|
||||
private setLanguageOnInit(): void {
|
||||
// set language from storage
|
||||
if (!this.translate.currentLang) {
|
||||
this.setLanguageFromStorage();
|
||||
}
|
||||
|
||||
// or set language from browser
|
||||
if (!this.translate.currentLang) {
|
||||
this.setLanguageFromBrowser();
|
||||
}
|
||||
|
||||
// set default language
|
||||
if (!this.translate.currentLang) {
|
||||
this.setLanguage(Language.EN);
|
||||
}
|
||||
}
|
||||
|
||||
private setLanguageFromStorage(): void {
|
||||
if (this.storageService.language && this.translate.getLangs().includes(this.storageService.language)) {
|
||||
this.setLanguage(this.storageService.language);
|
||||
}
|
||||
}
|
||||
private setLanguageFromBrowser(): void {
|
||||
const currentBrowserLanguage: Language = this.translate.getBrowserLang().toUpperCase() as Language;
|
||||
if (this.translate.getLangs().includes(currentBrowserLanguage)) {
|
||||
this.setLanguage(currentBrowserLanguage);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LoaderService } from './loader.service';
|
||||
|
||||
describe('LoaderService', () => {
|
||||
let service: LoaderService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(LoaderService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,14 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class LoaderService {
|
||||
private _loadingStatus: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
public readonly isLoading: Observable<boolean> = this._loadingStatus.asObservable();
|
||||
|
||||
public setStatus(status: boolean): void {
|
||||
this._loadingStatus.next(status);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ModalService } from './modal.service';
|
||||
|
||||
describe('ModalService', () => {
|
||||
let service: ModalService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(ModalService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,15 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DialogService } from 'primeng';
|
||||
|
||||
import { SettingsComponent } from '../../shared/components/settings/settings.component';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ModalService {
|
||||
constructor(public dialogService: DialogService) {}
|
||||
|
||||
public openSettingsComponent(): void {
|
||||
this.dialogService.open(SettingsComponent, { header: 'Paramรจtres', dismissableMask: true });
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { UrlService } from './url.service';
|
||||
|
||||
describe('UrlService', () => {
|
||||
let service: UrlService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(UrlService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,23 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRoute, UrlSegment } from '@angular/router';
|
||||
|
||||
import { LoaderService } from './loader.service';
|
||||
import { PollService } from './poll.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class UrlService {
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private pollService: PollService,
|
||||
private loaderService: LoaderService
|
||||
) {}
|
||||
|
||||
public async loadPollFromUrl(): Promise<void> {
|
||||
this.loaderService.setStatus(true);
|
||||
const wantedSlug: string = this.route.snapshot.firstChild.firstChild.url[1].path;
|
||||
await this.pollService.getPollByIdentifier(wantedSlug);
|
||||
this.loaderService.setStatus(false);
|
||||
}
|
||||
}
|
@ -1,7 +1,30 @@
|
||||
<h1>Participation</h1>
|
||||
<div class="p-grid">
|
||||
<div class="p-col has-text-centered">
|
||||
<h1>Participation</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a role="button" class="button" routerLink="../participation/poll/groSlug">
|
||||
Participer au sondage ยซ Gros slug ยป
|
||||
</a>
|
||||
<div *ngIf="_isLoading | async" class="p-grid p-justify-center">
|
||||
<div class="p-col has-text-centered">
|
||||
<p-progressSpinner></p-progressSpinner>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
<ng-container *ngIf="!(_isLoading | async)">
|
||||
<ng-container *ngIf="!(_poll | async)">
|
||||
<app-page-not-found [message]="'PAGE_NOT_FOUND.POLL'"></app-page-not-found>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="_poll | async">
|
||||
<div class="p-grid">
|
||||
<div class="p-col">
|
||||
<app-poll></app-poll>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-grid">
|
||||
<div class="p-col">
|
||||
<app-poll-comment></app-poll-comment>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
@ -0,0 +1 @@
|
||||
<p>poll-comment works!</p>
|
@ -0,0 +1,24 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PollCommentComponent } from './poll-comment.component';
|
||||
|
||||
describe('PollCommentComponent', () => {
|
||||
let component: PollCommentComponent;
|
||||
let fixture: ComponentFixture<PollCommentComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PollCommentComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PollCommentComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,12 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-poll-comment',
|
||||
templateUrl: './poll-comment.component.html',
|
||||
styleUrls: ['./poll-comment.component.scss'],
|
||||
})
|
||||
export class PollCommentComponent implements OnInit {
|
||||
constructor() {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
}
|
@ -1,12 +1,6 @@
|
||||
<p-progressSpinner *ngIf="isLoading" class="has-text-centered"></p-progressSpinner>
|
||||
|
||||
<ng-container *ngIf="!isLoading">
|
||||
<ng-container *ngIf="poll | async">
|
||||
<!-- <app-poll-presentation></app-poll-presentation> -->
|
||||
<h1>Sondage : {{ poll.title | async }}</h1>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!(poll | async)">
|
||||
<app-page-not-found [message]="'PAGE_NOT_FOUND.POLL'"></app-page-not-found>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="_poll | async as poll">
|
||||
<h1>Titre:{{ poll.question.label }}</h1>
|
||||
<p>description: {{ poll.question.description }}</p>
|
||||
<p>isDateType:{{ poll.configuration.isAboutDate }}</p>
|
||||
<p>slug:{{ poll.configuration.slug }}</p>
|
||||
</ng-container>
|
||||
|