diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..825c32f0 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1 @@ +# Changelog diff --git a/package-lock.json b/package-lock.json index 295defef..f676a5b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6515,6 +6515,11 @@ "which": "^1.2.9" } }, + "crypto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", + "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==" + }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", diff --git a/package.json b/package.json index c95d9b98..0c7ef0eb 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "build:prod": "ng build --prod", "build:prod:stats": "ng build --prod --stats-json", "build:prod:gitlabpage": "ng build --prod --baseHref=/framadate/funky-framadate-front/", - "build:prod:demobliss": "ng build --prod --baseHref=https://framadate-api.cipherbliss.com", + "build:prod:demobliss": "ng build --prod --baseHref=https://framadate-api.cipherbliss.com --stats-json ", "test": "jest", "test:watch": "jest --watch", "test:ci": "jest --ci", @@ -21,9 +21,9 @@ "mock:server": "json-server --port 8000 --watch ./mocks/db.json --routes ./mocks/routes.json", "start:proxy": "ng serve --proxy-config proxy.conf.json", "start:proxymock": "concurrently --kill-others \"yarn mock:server\" \"yarn start:proxy\"", - "i18n:init": "ngx-translate-extract --input ./src --output ./src/assets/i18n/template.json --key-as-default-value --replace --format json", - "i18n:extract": "ngx-translate-extract --input ./src --output ./src/assets/i18n/{en,da,de,fi,nb,nl,sv}.json --clean --format json" - }, + "i18n:init": "ngx-translate-extract --input ./src --output ./src/assets/i18n/template.json --key-as-default-value --replace --format json", + "i18n:extract": "ngx-translate-extract --input ./src --output ./src/assets/i18n/{en,da,de,fi,nb,nl,sv}.json --clean --format json" + }, "private": false, "dependencies": { "@angular/animations": "^9.1.1", @@ -47,11 +47,13 @@ "bulma": "^0.9.0", "bulma-switch": "^2.0.0", "chart.js": "^2.9.3", + "crypto": "^1.0.1", "fork-awesome": "^1.1.7", "ng2-charts": "^2.3.0", "ngx-clipboard": "^13.0.0", "ngx-markdown": "^9.0.0", "ngx-webstorage": "^5.0.0", + "node-forge": "^0.10.0", "primeng": "^9.0.6", "quill": "^1.3.7", "rxjs": "^6.5.5", diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 5e91c5eb..4a0e9f19 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,14 +1,9 @@ -import {NgModule} from '@angular/core'; -import {RouterModule} from '@angular/router'; -import {routes} from "./routes-framadate"; - +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { routes } from './routes-framadate'; @NgModule({ - imports: [ - RouterModule.forRoot(routes, { - // enableTracing: true, // <-- debugging purposes only - }), - ], + imports: [RouterModule.forRoot(routes, { useHash: true })], exports: [RouterModule], }) export class AppRoutingModule {} diff --git a/src/app/app.component.html b/src/app/app.component.html index 477450fe..ce833dc8 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -9,7 +9,7 @@
-
+

menu développeur diff --git a/src/app/app.component.ts b/src/app/app.component.ts index c4e0eb3d..f071ed2e 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -6,7 +6,6 @@ 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', diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 7db18013..1fb42f4d 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -23,7 +23,10 @@ import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { CoreModule } from './core/core.module'; import { SharedModule } from './shared/shared.module'; - +import { CguComponent } from './features/shared/components/ui/static-pages/cgu/cgu.component'; +import { LegalComponent } from './features/shared/components/ui/static-pages/legal/legal.component'; +import { PrivacyComponent } from './features/shared/components/ui/static-pages/privacy/privacy.component'; +import { CipheringComponent } from './features/shared/components/ui/static-pages/ciphering/ciphering.component'; registerLocaleData(localeEn, 'en-EN'); registerLocaleData(localeFr, 'fr-FR'); @@ -38,7 +41,7 @@ export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader { } @NgModule({ - declarations: [AppComponent], + declarations: [AppComponent, CguComponent, LegalComponent, PrivacyComponent, CipheringComponent], imports: [ AppRoutingModule, BrowserAnimationsModule, diff --git a/src/app/core/components/home/home.component.html b/src/app/core/components/home/home.component.html index 20641ab1..7e973eba 100644 --- a/src/app/core/components/home/home.component.html +++ b/src/app/core/components/home/home.component.html @@ -1,10 +1,20 @@
-

- {{ 'home.title' | translate }} - {{ env.appTitle }} -

+
+
+

+ {{ 'home.title' | translate }} + {{ env.appTitle }} +

+ + {{ + 'SENTENCES.framadate-is-an-online-service-for-planning-an-appointment-or-making-a-decision-quickly-and-easily' + | translate + }} +
+ image WIP +

@@ -19,50 +29,144 @@

+
- image WIP -

- {{ - 'SENTENCES.framadate-is-an-online-service-for-planning-an-appointment-or-making-a-decision-quickly-and-easily' - | translate - }} - {{ 'SENTENCES.here-is-how-it-works' | translate }} - {{ 'SENTENCES.send-the-poll-link-to-your-friends-or-colleagues' | translate }} -

-

- {{ 'SENTENCES.what-is-framadate' | translate }} - {{ 'SENTENCES.view-an-example' | translate }} - {{ 'SENTENCES.framadate-is-licensed-under-the' | translate }} - - GNU Affero v3 Licence - -

-

- {{ 'SENTENCES.grow-your-own' | translate }} - {{ - 'SENTENCES.if-you-want-to-install-the-software-for-your-own-use-and-thus-increase-your-independence-we-can-help' - | translate - }} - {{ - 'SENTENCES.to-participate-in-the-software-development-suggest-improvements-or-simply-download-it-please-visit' - | translate - }} - {{ 'SENTENCES.the-development-site' | translate }} -

+
+
+

+ + {{ 'SENTENCES.here-is-how-it-works' | translate }} +

+

+ {{ 'SENTENCES.send-the-poll-link-to-your-friends-or-colleagues' | translate }} + + {{ 'SENTENCES.what-you-can-do' | translate }} +

+

+ + {{ 'SENTENCES.view-an-example' | translate }} +

+

+ + Orange ou citron? + +

+

+ + + {{ 'SENTENCES.framadate-is-licensed-under-the' | translate }} + + + GNU Affero v3 Licence + +

+
+ +
+

+ + {{ 'SENTENCES.grow-your-own' | translate }} +

+

+ {{ + 'SENTENCES.if-you-want-to-install-the-software-for-your-own-use-and-thus-increase-your-independence-we-can-help' + | translate + }} + {{ + 'SENTENCES.to-participate-in-the-software-development-suggest-improvements-or-simply-download-it-please-visit' + | translate + }} + {{ 'SENTENCES.the-development-site' | translate }} +

+
+
+
+ +

Statistiques

+ +
+
+
+
+ + 62 346 +
+

sondages

+
+
+
+ + 223 124 +
+

votes

+
+ +
+
+ + 41 875 +
+

commentaires

+
+
+
+
+
+ + 44 985 +
+

sondages de type date

+
+ +
+
+ + 22 985 +
+

sondages de type classique

+
+
+
+ + 123 +
+

consensus parfaits

+
+
+
+
diff --git a/src/app/core/models/configuration.model.ts b/src/app/core/models/configuration.model.ts index 8ec766f2..8b723adc 100644 --- a/src/app/core/models/configuration.model.ts +++ b/src/app/core/models/configuration.model.ts @@ -3,26 +3,34 @@ import { DateService } from '../services/date.service'; export class PollConfiguration { constructor( - public isAboutDate: boolean = false, - public isProtectedByPassword: boolean = false, + public allowComments: boolean = true, + public areResultsPublic: boolean = true, + public dateCreated: Date = new Date(Date.now()), public password: string = '', + public isAboutDate: boolean = false, + public isAllowingtoChangeOwnAnswers: boolean = true, + public isMaybeAnswerAvailable: boolean = false, + public isProtectedByPassword: boolean = false, public isOwnerNotifiedByEmailOnNewVote: boolean = false, public isOwnerNotifiedByEmailOnNewComment: boolean = false, - public isMaybeAnswerAvailable: boolean = false, - public areResultsPublic: boolean = true, - public isAllowingtoChangeOwnAnswers: boolean = true, - public whoCanChangeAnswers: string = 'everybody', - public dateCreated: Date = new Date(Date.now()), - public expiresDaysDelay: number = environment.poll.defaultConfig.expiracyInDays, + public isZeroKnoledge: boolean = true, + public hasSeveralHours: boolean = false, + public hasMaxCountOfAnswers: boolean = false, + 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 voteChoices: string = environment.poll.defaultConfig.voteChoices, // possible answers to a vote choice: only "yes", "yes, maybe, no": number = environment.poll.defaultConfig.maxCountOfAnswers, + public maxCountOfAnswers: number = environment.poll.defaultConfig.maxCountOfAnswers, + public expiresDaysDelay: number = environment.poll.defaultConfig.expiresDaysDelay, public expiracyAfterLastModificationInDays: number = environment.poll.defaultConfig .expiracyAfterLastModificationInDays, - public expires: Date = DateService.addDaysToDate( - environment.poll.defaultConfig.expiracyInDays, + // date after creation day when people will not be able to vote anymore + public expiracyDate: Date = DateService.addDaysToDate( + environment.poll.defaultConfig.expiresDaysDelay, new Date(Date.now()) ) ) {} public static isArchived(configuration: PollConfiguration): boolean { - return configuration.expires ? DateService.isDateInPast(configuration.expires) : undefined; + return configuration.expiracyDate ? DateService.isDateInPast(configuration.expiracyDate) : undefined; } } diff --git a/src/app/core/models/poll.model.ts b/src/app/core/models/poll.model.ts index 8d616c3f..59c18a49 100644 --- a/src/app/core/models/poll.model.ts +++ b/src/app/core/models/poll.model.ts @@ -8,14 +8,18 @@ import { User } from './user.model'; export class Poll { constructor( public owner: User = new User(), - public slug: string = 'default-slug', - public title: string = 'default title', + public slug: string = '', + public title: string = '', public description?: string, + public creatorPseudo?: string, + public creatorEmail?: string, + public allowSeveralHours?: boolean, + public archiveNumberOfDays?: number, public configuration: PollConfiguration = new PollConfiguration(), public comments: Comment[] = [], public choices: Choice[] = [], - public dateChoices: Choice[] = [], - public timeChoices: Choice[] = [] + public dateChoices: Choice[] = [], // sets of days as strings, config to set identical time for days in a special days poll + public timeChoices: Choice[] = [] // ranges of time expressed as strings ) {} public getAdministrationUrl(): string { @@ -33,22 +37,22 @@ export class Poll { new User(item.owner.pseudo, item.owner.email, undefined), item.slug, item.title, - item.description, - item.configuration, - item.comments - .map( - (c: Pick) => - new Comment(c.author, c.content, new Date(c.dateCreated)) - ) - .sort(Comment.sortChronologically), - item.choices.map((c: Pick) => { - const choice = new Choice(c.label, c.imageUrl, new Map(c.participants)); - choice.participants.forEach((value, key) => { - choice.participants.set(key, new Set(value)); - }); - choice.updateCounts(); - return choice; - }) + item.description + // item.configuration, + // item.comments + // .map( + // (c: Pick) => + // new Comment(c.author, c.content, new Date(c.dateCreated)) + // ) + // .sort(Comment.sortChronologically), + // item.choices.map((c: Pick) => { + // const choice = new Choice(c.label, c.imageUrl, new Map(c.participants)); + // choice.participants.forEach((value, key) => { + // choice.participants.set(key, new Set(value)); + // }); + // choice.updateCounts(); + // return choice; + // }) ); } } diff --git a/src/app/core/services/api.service.ts b/src/app/core/services/api.service.ts index 12b14318..3bf4faeb 100644 --- a/src/app/core/services/api.service.ts +++ b/src/app/core/services/api.service.ts @@ -49,7 +49,7 @@ export class ApiService { public async createPoll(poll: Poll): Promise { // this.loader.setStatus(true); - console.log('config', poll); + console.log('createPoll config', poll); // const baseHref = this.useDevLocalServer ? 'http://localhost:8000' : apiBaseHref; // return this.http // .post(`${baseHref}${currentApiRoutes['api_new_poll']}`, poll, ApiService.makeHeaders()) diff --git a/src/app/core/services/poll.service.ts b/src/app/core/services/poll.service.ts index d597e52d..e8d16e15 100644 --- a/src/app/core/services/poll.service.ts +++ b/src/app/core/services/poll.service.ts @@ -64,7 +64,7 @@ export class PollService implements Resolve { console.log('getAllAvailablePolls res', res); }); } catch (e) { - console.log('getAllAvailablePolls e', e); + console.error('getAllAvailablePolls e', e); } } @@ -86,6 +86,7 @@ export class PollService implements Resolve { * @param config */ makeSlug(config: Poll): string { + console.log('config', config); let str = ''; str = config.configuration.dateCreated.getFullYear() + @@ -228,7 +229,6 @@ export class PollService implements Resolve { adminKey: '', // key to change config of the poll owner_modifier_token: '', // key to change a vote stack canModifyAnswers: newpoll.configuration.isAllowingtoChangeOwnAnswers, // bool for the frontend selector - whoModifiesAnswers: newpoll.configuration.whoCanChangeAnswers, // everybody, self, nobody (: just admin) whoCanChangeAnswers: newpoll.configuration.whoCanChangeAnswers, // everybody, self, nobody (: just admin) dateList: newpoll.dateChoices, // sets of days as strings, config to set identical time for days in a special days poll timeList: newpoll.timeChoices, // ranges of time expressed as strings diff --git a/src/app/features/administration/administration.module.ts b/src/app/features/administration/administration.module.ts index 051ead96..5a3b196b 100644 --- a/src/app/features/administration/administration.module.ts +++ b/src/app/features/administration/administration.module.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { ReactiveFormsModule } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { TranslateModule } from '@ngx-translate/core'; import { SharedModule } from '../../shared/shared.module'; @@ -10,16 +10,38 @@ import { StepperComponent } from './stepper/stepper.component'; import { NamingComponent } from './naming/naming.component'; import { FormComponent } from './form/form.component'; import { DateValueAccessorModule } from 'angular-date-value-accessor'; +import { SuccessComponent } from './success/success.component'; +import { DateSelectComponent } from './form/date-select/date-select.component'; +import { TextSelectComponent } from './form/text-select/text-select.component'; +import { KindSelectComponent } from './form/kind-select/kind-select.component'; +import { BaseConfigComponent } from './form/base-config/base-config.component'; +import { AdvancedConfigComponent } from './form/advanced-config/advanced-config.component'; +import { CalendarModule } from 'primeng'; +import { DragDropModule } from '@angular/cdk/drag-drop'; @NgModule({ - declarations: [AdministrationComponent, StepperComponent, NamingComponent, FormComponent], + declarations: [ + AdministrationComponent, + StepperComponent, + NamingComponent, + FormComponent, + SuccessComponent, + DateSelectComponent, + TextSelectComponent, + KindSelectComponent, + BaseConfigComponent, + AdvancedConfigComponent, + ], imports: [ + CalendarModule, AdministrationRoutingModule, CommonModule, ReactiveFormsModule, SharedModule, + FormsModule, TranslateModule.forChild({ extend: true }), DateValueAccessorModule, + DragDropModule, ], }) export class AdministrationModule {} diff --git a/src/app/features/administration/form/advanced-config/advanced-config.component.html b/src/app/features/administration/form/advanced-config/advanced-config.component.html new file mode 100644 index 00000000..1bd574b7 --- /dev/null +++ b/src/app/features/administration/form/advanced-config/advanced-config.component.html @@ -0,0 +1,165 @@ +
+
+

{{ 'creation.advanced' | translate }}

+ + + + +
+ + +
+ {{ urlPrefix }} + + {{ form.controls.slug.value }} + + + + + + +
+
+ Nombre de jours avant expiration de la possibilité de voter, après le sondage reste + consultable + + +
+
+ Nombre de jours avant archivage, après quoi le sondage n'est plus visible par le public + + +
+ + Les participants pourront consulter les résultats + +

+ + Accès sécurisé +

+ + + Le sondage sera protégé par un mot de passe + + + + +

+ + Notifications +

+ + Vous recevrez un mail à chaque nouvelle participation + + + Vous recevrez un mail à chaque nouveau commentaire + + + La réponse « peut-être » sera disponible + +
+ +
+

+ Fonctionnalités pas encore disponibles: +

+ + + Spécifier un lien unique de vote à des participants définis + + + Autoriser les commentaires + + + Nombre de réponses limitées à ce nombre + + + + + Les informations du sondage seront chiffrés en base de données + +
+
diff --git a/src/app/features/administration/form/advanced-config/advanced-config.component.scss b/src/app/features/administration/form/advanced-config/advanced-config.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/features/administration/form/advanced-config/advanced-config.component.spec.ts b/src/app/features/administration/form/advanced-config/advanced-config.component.spec.ts new file mode 100644 index 00000000..5407c267 --- /dev/null +++ b/src/app/features/administration/form/advanced-config/advanced-config.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AdvancedConfigComponent } from './advanced-config.component'; + +describe('AdvancedConfigComponent', () => { + let component: AdvancedConfigComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [AdvancedConfigComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AdvancedConfigComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/administration/form/advanced-config/advanced-config.component.ts b/src/app/features/administration/form/advanced-config/advanced-config.component.ts new file mode 100644 index 00000000..cfc1b286 --- /dev/null +++ b/src/app/features/administration/form/advanced-config/advanced-config.component.ts @@ -0,0 +1,19 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { Poll } from '../../../../core/models/poll.model'; +import { FormGroup } from '@angular/forms'; + +@Component({ + selector: 'app-advanced-config', + templateUrl: './advanced-config.component.html', + styleUrls: ['./advanced-config.component.scss'], +}) +export class AdvancedConfigComponent implements OnInit { + public urlPrefix: string = window.location.origin + '/participation/'; + @Input() + public poll?: Poll; + @Input() + public form: FormGroup; + constructor() {} + + ngOnInit(): void {} +} diff --git a/src/app/features/administration/form/base-config/base-config.component.html b/src/app/features/administration/form/base-config/base-config.component.html new file mode 100644 index 00000000..85decc75 --- /dev/null +++ b/src/app/features/administration/form/base-config/base-config.component.html @@ -0,0 +1,102 @@ +
+
+
+

+ {{ 'creation.choose_title' | translate }} +

+

slug: {{ form.value.slug }}

+
+ + + +
+
+ + + +
+ + + +
+ +
+
+ +
+
+
+ image WIP +
+

+ {{ 'choices.title' | translate }} +

+ {{ 'dates.add' | translate }} +

+ + {{ 'choices.helper' | translate }} + +

+ {{ 'choices.answer_preset_1' | translate }} + {{ 'choices.add' | translate }} + {{ 'choices.continue' | translate }} +
+
+
+
+ +
+ +
+ +
+
diff --git a/src/app/features/administration/form/base-config/base-config.component.scss b/src/app/features/administration/form/base-config/base-config.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/features/administration/form/base-config/base-config.component.spec.ts b/src/app/features/administration/form/base-config/base-config.component.spec.ts new file mode 100644 index 00000000..4acc1c58 --- /dev/null +++ b/src/app/features/administration/form/base-config/base-config.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { BaseConfigComponent } from './base-config.component'; + +describe('BaseConfigComponent', () => { + let component: BaseConfigComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [BaseConfigComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(BaseConfigComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/administration/form/base-config/base-config.component.ts b/src/app/features/administration/form/base-config/base-config.component.ts new file mode 100644 index 00000000..2a27d8e1 --- /dev/null +++ b/src/app/features/administration/form/base-config/base-config.component.ts @@ -0,0 +1,69 @@ +import { ChangeDetectorRef, Component, Inject, Input, OnInit } from '@angular/core'; +import { ToastService } from '../../../../core/services/toast.service'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { UuidService } from '../../../../core/services/uuid.service'; +import { PollService } from '../../../../core/services/poll.service'; +import { ApiService } from '../../../../core/services/api.service'; +import { Router } from '@angular/router'; +import { DOCUMENT } from '@angular/common'; +import { Poll } from '../../../../core/models/poll.model'; + +@Component({ + selector: 'app-base-config', + templateUrl: './base-config.component.html', + styleUrls: ['./base-config.component.scss'], +}) +export class BaseConfigComponent { + @Input() + public poll?: Poll; + @Input() + public form: FormGroup; + + constructor( + private fb: FormBuilder, + private cd: ChangeDetectorRef, + private uuidService: UuidService, + private toastService: ToastService, + private pollService: PollService, + private apiService: ApiService, + private router: Router, + @Inject(DOCUMENT) private document: Document + ) {} + + askInitFormDefault(): void { + // this.initFormDefault(false); + this.toastService.display('formulaire réinitialisé'); + } + + public createPoll(): void { + console.log('this.form', this.form); + const newpoll = this.pollService.newPollFromForm(this.form); + console.log('newpoll', newpoll); + const router = this.router; + + if (this.form.valid) { + console.log('Le sondage est correctement rempli, prêt à enregistrer.'); + const newpoll = this.pollService.newPollFromForm(this.form); + // TODO : save the poll + + this.apiService.createPoll(newpoll).then((resp) => { + console.log('resp', resp); + router.navigate(['success']); + }); + } else { + this.toastService.display('invalid form'); + } + } + + public updateSlug(): void { + const newValueFormatted = 'TODO'; + this.form.patchValue({ slug: newValueFormatted }); + } + + /** + * set the poll slug from other data of the poll + */ + automaticSlug() { + this.form.patchValue({ slug: this.pollService.makeSlug(this.form.value) }); + } +} diff --git a/src/app/features/administration/form/date-select/date-select.component.html b/src/app/features/administration/form/date-select/date-select.component.html new file mode 100644 index 00000000..6ebedc37 --- /dev/null +++ b/src/app/features/administration/form/date-select/date-select.component.html @@ -0,0 +1,238 @@ +
+
+ + +
+

{{ 'dates.add_interval' | translate }}

+
+
+ {{ 'dates.interval_propose' | translate }} +
+
+ + +
+
+
+
+ {{ 'dates.interval_span' | translate }} +
+
+ + +
+
+ +
+
+
+ +
+ + Chaque jour aura ses plages de temps personnalisées + + + Tous les jours auront les mêmes plages de temps + +
+
+
+
+
+ + + +
+
+
+

+ + {{ 'dates.count_time' | translate }} + (identique pour chaque jour) + +

+
+ + {{ timeList.length }} + +
+
+
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+ + +
+
+ + {{ dateList.length }} + + + {{ 'dates.count_dates' | translate }} + +
+
+ +
+
+ +

Dates

+
+ {{ id }}) + + + +
+ plage horaire distincte +
+
+ + +
+
+
+
+
+ + + + +
+
+ +
+
+
+
+
+
diff --git a/src/app/features/administration/form/date-select/date-select.component.scss b/src/app/features/administration/form/date-select/date-select.component.scss new file mode 100644 index 00000000..e1f049d0 --- /dev/null +++ b/src/app/features/administration/form/date-select/date-select.component.scss @@ -0,0 +1,43 @@ +:host { + .time-choice { + background: rgba(255, 255, 255, 0.8); + border: solid 1px #dedede; + padding: 0.5em; + //padding: 20px 10px; + border-bottom: solid 1px #ccc; + color: rgba(0, 0, 0, 0.87); + box-sizing: border-box; + cursor: move; + background: white; + font-size: 14px; + } + .btn i + span { + margin-left: 1ch; + } + .btn + .btn { + margin-left: 1em; + } + + .cdk-drag-preview { + box-sizing: border-box; + border-radius: 4px; + box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); + border: 2px solid #ccc; + background: rgba(255, 255, 255, 0.8); + } + + .cdk-drag-placeholder { + * { + opacity: 0; + } + background: #dedede; + } + + .cdk-drag-animating { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); + } + .movable { + cursor: move; + } +} diff --git a/src/app/features/administration/form/date-select/date-select.component.spec.ts b/src/app/features/administration/form/date-select/date-select.component.spec.ts new file mode 100644 index 00000000..d5f4b90f --- /dev/null +++ b/src/app/features/administration/form/date-select/date-select.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DateSelectComponent } from './date-select.component'; + +describe('DateSelectComponent', () => { + let component: DateSelectComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [DateSelectComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DateSelectComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/administration/form/date-select/date-select.component.ts b/src/app/features/administration/form/date-select/date-select.component.ts new file mode 100644 index 00000000..4ed63371 --- /dev/null +++ b/src/app/features/administration/form/date-select/date-select.component.ts @@ -0,0 +1,259 @@ +import { ChangeDetectorRef, Component, Inject, Input, OnInit } from '@angular/core'; +import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { UuidService } from '../../../../core/services/uuid.service'; +import { ToastService } from '../../../../core/services/toast.service'; +import { PollService } from '../../../../core/services/poll.service'; +import { DateUtilities } from '../../../old-stuff/config/DateUtilities'; +import { ApiService } from '../../../../core/services/api.service'; +import { Router } from '@angular/router'; +import { DOCUMENT } from '@angular/common'; +import { DateChoice, moreTimeOfDay, otherDefaultDates, TimeSlices } from '../../../old-stuff/config/defaultConfigs'; +import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; +import { TranslateService } from '@ngx-translate/core'; + +@Component({ + selector: 'app-date-select', + templateUrl: './date-select.component.html', + styleUrls: ['./date-select.component.scss'], +}) +export class DateSelectComponent implements OnInit { + @Input() + public form: FormGroup; + + public showDateInterval = true; + public allowSeveralHours = true; + today = new Date(); + startDateInterval: string; + endDateInterval: string; + intervalDays: any; + intervalDaysDefault = 7; + dateList: DateChoice[] = otherDefaultDates; // sets of days as strings, config to set identical time for days in a special days poll + timeList: TimeSlices[] = moreTimeOfDay; // ranges of time expressed as strings + dateCalendarEnum: Date[] = [new Date('02/09/2021')]; + selectionKind = 'range'; + + constructor( + private fb: FormBuilder, + private cd: ChangeDetectorRef, + private uuidService: UuidService, + private toastService: ToastService, + private pollService: PollService, + public dateUtilities: DateUtilities, + private apiService: ApiService, + private router: Router, + private translateService: TranslateService, + @Inject(DOCUMENT) private document: any + ) {} + + ngOnInit(): void { + // this.setDefaultDatesForInterval(); + } + + get choices(): FormArray { + return this.form.get('choices') as FormArray; + } + + /** + * default interval of dates proposed is from today to 7 days more + */ + setDefaultDatesForInterval(): void { + const dateCurrent = new Date(); + const dateJson = dateCurrent.toISOString(); + this.startDateInterval = dateJson.substring(0, 10); + this.endDateInterval = this.dateUtilities + .addDaysToDate(this.intervalDaysDefault, dateCurrent) + .toISOString() + .substring(0, 10); + this.form.patchValue({ + startDateInterval: this.startDateInterval, + endDateInterval: this.endDateInterval, + }); + this.dateCalendarEnum = [dateCurrent, this.dateUtilities.addDaysToDate(this.intervalDaysDefault, dateCurrent)]; + this.countDays(); + } + + countDays(): void { + this.intervalDays = this.dateUtilities.countDays( + this.dateUtilities.parseInputDateToDateObject(this.startDateInterval), + this.dateUtilities.parseInputDateToDateObject(this.endDateInterval) + ); + // this.cd.detectChanges(); + } + + /** + * add all the dates between the start and end dates in the interval section + */ + addIntervalOfDates(): void { + const newIntervalArray = this.dateUtilities.getDatesInRange( + this.dateUtilities.parseInputDateToDateObject(this.startDateInterval), + this.dateUtilities.parseInputDateToDateObject(this.endDateInterval), + 1 + ); + + const converted = []; + newIntervalArray.forEach((element) => { + converted.push({ + literal: element.literal, + date_object: element.date_object, + timeList: [], + }); + }); + this.dateList = [...new Set(converted)]; + // add only dates that are not already present with a Set of unique items + console.log('this.dateList', this.dateList); + this.showDateInterval = false; + + this.form.patchValue({ choices: this.dateList }); + // this.dateList.forEach(elem=>{ + // const newControlGroup = this.fb.group({ + // label: this.fb.control('', [Validators.required]), + // imageUrl: ['', [Validators.required]], + // }); + // + // this.choices.push(newControlGroup); + // }) + + this.toastService.display(`les dates ont été ajoutées aux réponses possibles.`); + } + + /** + * change time spans + */ + addTime() { + this.timeList.push({ + literal: '', + }); + } + + removeAllTimes() { + this.timeList = []; + } + + resetTimes() { + this.timeList = otherDefaultDates; + } + + /** + * add a time period to a specific date choice, + * focus on the new input + * @param config + * @param id + */ + addTimeToDate(config: any, id: number) { + this.timeList.push({ + literal: '', + }); + const selector = '[ng-reflect-choice_label="dateTime_' + id + '_Choices_' + (this.timeList.length - 1) + '"]'; + // this.cd.detectChanges(); + const elem = this.document.querySelector(selector); + if (elem) { + elem.focus(); + } + } + + get dateChoices() { + return this.form.get('dateChoices') as FormArray; + } + + addChoice(optionalLabel = ''): void { + const newControlGroup = this.fb.group({ + label: this.fb.control('', [Validators.required]), + imageUrl: ['', [Validators.required]], + }); + + if (optionalLabel) { + newControlGroup.patchValue({ + label: optionalLabel, + imageUrl: 'mon url', + }); + } + this.dateChoices.push(newControlGroup); + // this.cd.detectChanges(); + console.log('this.choices.length', this.choices.length); + + this.focusOnChoice(this.choices.length - 1); + } + + focusOnChoice(index): void { + const selector = '#choice_label_' + index; + const elem = this.document.querySelector(selector); + if (elem) { + elem.focus(); + } + } + + deleteChoiceField(index: number): void { + if (this.choices.length !== 1) { + this.choices.removeAt(index); + } + } + + reinitChoices(): void { + this.choices.setValue([]); + } + + /** + * handle keyboard shortcuts + * @param $event + * @param choice_number + */ + keyOnChoice($event: KeyboardEvent, choice_number: number): void { + $event.preventDefault(); + + console.log('this.choices.length', this.choices.length); + console.log('choice_number', choice_number); + const lastChoice = this.choices.length - 1 === choice_number; + // TODO handle shortcuts + // reset field with Ctrl + D + // add a field with Ctrl + N + // go to previous choice with arrow up + // go to next choice with arrow down + console.log('$event', $event); + + if ($event.key == 'ArrowUp' && choice_number > 0) { + this.focusOnChoice(choice_number - 1); + } + if ($event.key == 'ArrowDown') { + // add a field if we are on the last choice + if (lastChoice) { + this.addChoice(); + this.toastService.display('choix ajouté par raccourci "flèche bas"'); + } else { + this.focusOnChoice(choice_number + 1); + } + } + if ($event.ctrlKey && $event.key == 'Backspace') { + this.deleteChoiceField(choice_number); + this.toastService.display('choix supprimé par raccourci "Ctrl + retour"'); + // this.cd.detectChanges(); + this.focusOnChoice(Math.min(choice_number - 1, 0)); + } + if ($event.ctrlKey && $event.key == 'Enter') { + // go to other fields + const elem = this.document.querySelector('#creatorEmail'); + if (elem) { + elem.focus(); + } + } + } + + setDemoValues(): void { + this.addChoice('orange'); + this.addChoice('raisin'); + this.addChoice('abricot'); + } + + dropTimeItem(event: any) { + // moveItemInArray(this.timeList, event.previousIndex, event.currentIndex); + if (event.previousContainer === event.container) { + moveItemInArray(event.container.data, event.previousIndex, event.currentIndex); + } else { + transferArrayItem( + event.previousContainer.data, + event.container.data, + event.previousIndex, + event.currentIndex + ); + } + } +} diff --git a/src/app/features/administration/form/form.component.html b/src/app/features/administration/form/form.component.html index 922e9258..1938a652 100644 --- a/src/app/features/administration/form/form.component.html +++ b/src/app/features/administration/form/form.component.html @@ -1,421 +1,69 @@ -
-

- {{ 'creation.title' | translate }} -

- - image WIP - - - - -
- {{ poll.slug }} -
-
- le formulaire est invalide -
-
- {{ form.errors | json }}
-		
-
-
-
- - {{ timeList.length }} - - - {{ 'dates.count_time' | translate }} - (pour chaque jour) - -
-
- - - -
- -
-
-
- - - -
-
-
-
- - {{ dateList.length }} - - - {{ 'dates.count_dates' | translate }} - - -
- {{ id }}) - - - -
-
- - -
-
-
-
-
- +
-
- - {{ 'creation.want' | translate }} - -
-
- -
-
- -
-
- - - {{ 'creation.choose_title' | translate }} - - - - -
- -
- -
- - -
-

{{ 'dates.add_interval' | translate }}

-
-
- {{ 'dates.interval_propose' | translate }} -
-
- - -
-
-
-
- {{ 'dates.interval_span' | translate }} -
-
- - -
-
- -
-
- -
-

- {{ 'choices.title' | translate }} -

- {{ 'dates.add' | translate }} -

- - {{ 'choices.helper' | translate }} - -

- {{ 'choices.answer_preset_1' | translate }} - {{ 'choices.add' | translate }} - {{ 'choices.continue' | translate }} - - - - - - - - - - -

- {{ 'creation.choices_hint' | translate }} -

- -
-
-
- - {{ i * 1 + 1 }}) -
-
- - -
- - -
-
-
-
-
-
- -
- - - - -
- -
- -
- -
-

{{ 'creation.advanced' | translate }}

- - - - -
- - -
- {{ urlPrefix }} - - {{ form.controls.slug.value }} - - - - - - -
-
- Nombre de jours avant expiration - - -
- - Les participants pourront consulter les résultats - - - Les choix possibles concerneront des dates - - - Le sondage sera protégé par un mot de passe - - - Vous recevrez un mail à chaque nouvelle participation - - - Vous recevrez un mail à chaque nouveau commentaire - - - La réponse « peut-être » sera disponible - -
-
-
+
-
+
+
+
+
+
+

+ {{ 'creation.want' | translate }} +

+ + + + + + + + + + + +
+
+
+

Debug data

+
+				form values :
+					{{ form.value | json }}
+				
+
+				poll initial values :
+				{{ poll | json }}
+				
+
+
+
+
+ le formulaire est invalide +
+		 {{ form.errors | json }}
+		
+
diff --git a/src/app/features/administration/form/form.component.scss b/src/app/features/administration/form/form.component.scss index d5ce7a9c..3814f6aa 100644 --- a/src/app/features/administration/form/form.component.scss +++ b/src/app/features/administration/form/form.component.scss @@ -83,4 +83,7 @@ border-left: $success 3px solid; padding-left: 1em; } + .btn { + margin: 0.5em; + } } diff --git a/src/app/features/administration/form/form.component.ts b/src/app/features/administration/form/form.component.ts index 308d390c..aae22552 100644 --- a/src/app/features/administration/form/form.component.ts +++ b/src/app/features/administration/form/form.component.ts @@ -1,14 +1,12 @@ import { ChangeDetectorRef, Component, Inject, Input, OnInit } from '@angular/core'; import { Poll } from '../../../core/models/poll.model'; -import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { UuidService } from '../../../core/services/uuid.service'; import { ApiService } from '../../../core/services/api.service'; import { ToastService } from '../../../core/services/toast.service'; import { PollService } from '../../../core/services/poll.service'; -import { DateUtilities } from '../../old-stuff/config/DateUtilities'; import { DOCUMENT } from '@angular/common'; -import { DateChoice, otherDefaultDates } from '../../old-stuff/config/defaultConfigs'; -import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; +import { Router } from '@angular/router'; @Component({ selector: 'app-admin-form', @@ -20,16 +18,8 @@ export class FormComponent implements OnInit { public poll?: Poll; public form: FormGroup; - public urlPrefix: string = window.location.origin + '/participation/'; public advancedDisplayEnabled = false; - public showDateInterval = true; - public allowSeveralHours = true; - startDateInterval: string; - endDateInterval: string; - intervalDays: any; - intervalDaysDefault = 7; - dateList: any = otherDefaultDates; // sets of days as strings, config to set identical time for days in a special days poll - timeList: DateChoice[] = otherDefaultDates; // ranges of time expressed as strings + public show_debug_data = false; constructor( private fb: FormBuilder, @@ -37,291 +27,106 @@ export class FormComponent implements OnInit { private uuidService: UuidService, private toastService: ToastService, private pollService: PollService, - public dateUtilities: DateUtilities, - private apiService: ApiService, + public apiService: ApiService, + private router: Router, @Inject(DOCUMENT) private document: any ) {} - drop(event: CdkDragDrop) { - // moveItemInArray(this.choices, event.previousIndex, event.currentIndex); - } - get choices(): FormArray { - return this.form.get('choices') as FormArray; - } ngOnInit(): void { this.initFormDefault(); - // TO remove after - // this.createPoll(); + const pollsAvailable = this.pollService.getAllAvailablePolls(); console.log('pollsAvailable', pollsAvailable); } - public createPoll(): void { - console.log('this.form', this.form); - const newpoll = this.pollService.newPollFromForm(this.form); - console.log('newpoll', newpoll); - this.apiService.createPoll(newpoll); - // if (this.form.valid) { - // console.log('Le sondage est correctement rempli, prêt à enregistrer.'); - // const newpoll = this.pollService.newPollFromForm(this.form); - // // TODO : save the poll - // this.apiService.createPoll(newpoll); - // } else { - // this.toastService.display('invalid form'); - // } - } - - public updateSlug(): void { - const newValueFormatted = 'TODO'; - this.form.patchValue({ slug: newValueFormatted }); - } - - addChoice(optionalLabel = ''): void { - const newControlGroup = this.fb.group({ - label: this.fb.control('', [Validators.required]), - imageUrl: ['', [Validators.required]], - }); - - if (optionalLabel) { - newControlGroup.patchValue({ - label: optionalLabel, - imageUrl: 'mon url', - }); - } - this.choices.push(newControlGroup); - this.cd.detectChanges(); - console.log('this.choices.length', this.choices.length); - - this.focusOnChoice(this.choices.length - 1); - } - - focusOnChoice(index): void { - const selector = '#choice_label_' + index; - const elem = this.document.querySelector(selector); - if (elem) { - elem.focus(); - } - } - - deleteChoiceField(index: number): void { - if (this.choices.length !== 1) { - this.choices.removeAt(index); - } - } - - reinitChoices(): void { - this.choices.setValue([]); - } - initFormDefault(showDemoValues = true): void { + const creationDate = new Date(); + this.form = this.fb.group({ title: ['', [Validators.required, Validators.minLength(12)]], creatorPseudo: ['', [Validators.required]], creatorEmail: ['', [Validators.required]], slug: [this.uuidService.getUUID(), [Validators.required]], description: ['', [Validators.required]], - choices: new FormArray([]), - whoModifiesAnswers: ['', [Validators.required]], - whoCanChangeAnswers: ['', [Validators.required]], - isAboutDate: [true, [Validators.required]], + choices: this.fb.array([ + this.fb.group({ + label: ['', [Validators.required]], + imageUrl: ['', [Validators.required]], + }), + ]), + dateChoices: this.fb.array([ + this.fb.group({ + label: ['', [Validators.required]], + // if we have enabled detailed time choices per date choice, we have to make a time property for each date choice + timeChoices: this.fb.array([ + this.fb.group({ + label: ['', [Validators.required]], + }), + ]), + }), + ]), + timeChoices: this.fb.array([ + this.fb.group({ + label: ['', [Validators.required]], + }), + ]), + kind: ['', [Validators.required]], + configuration: this.fb.group({ + areResultsPublic: [true, [Validators.required]], + whoCanChangeAnswers: ['everybody', [Validators.required]], + isProtectedByPassword: [false, [Validators.required]], + isOwnerNotifiedByEmailOnNewVote: [false, [Validators.required]], + isOwnerNotifiedByEmailOnNewComment: [false, [Validators.required]], + isMaybeAnswerAvailable: [false, [Validators.required]], + + isAboutDate: [true, [Validators.required]], + isZeroKnoledge: [false, [Validators.required]], + expiresDaysDelay: [60, [Validators.required, Validators.min(1)]], + maxCountOfAnswers: [150, [Validators.required, Validators.min(1)]], + allowComments: [true, [Validators.required]], + password: [this.uuidService.getUUID(), [Validators.required]], + dateCreated: [creationDate, [Validators.required]], + hasSeveralHours: [true, [Validators.required]], + hasMaxCountOfAnswers: [true, [Validators.required, Validators.min(1)]], + }), startDateInterval: ['', [Validators.required]], endDateInterval: ['', [Validators.required]], - isProtectedByPassword: [false, [Validators.required]], - isOwnerNotifiedByEmailOnNewVote: [false, [Validators.required]], - isOwnerNotifiedByEmailOnNewComment: [false, [Validators.required]], - isMaybeAnswerAvailable: [false, [Validators.required]], - areResultsPublic: [true, [Validators.required]], - expiracyNumberOfDays: [60, [Validators.required, Validators.min(0)]], }); console.log('this.form ', this.form); - this.setDefaultDatesForInterval(); if (showDemoValues) { this.setDemoValues(); + this.toastService.display('default values filled for demo'); } } /** - * default interval of dates proposed is from today to 7 days more - */ - setDefaultDatesForInterval(): void { - const dateCurrent = new Date(); - const dateJson = dateCurrent.toISOString(); - this.startDateInterval = dateJson.substring(0, 10); - this.endDateInterval = this.dateUtilities - .addDaysToDate(this.intervalDaysDefault, dateCurrent) - .toISOString() - .substring(0, 10); - this.form.patchValue({ - startDateInterval: this.startDateInterval, - endDateInterval: this.endDateInterval, - }); - this.countDays(); - } - - /** - * add example values to the form + * add example values to the form, overrides defaults of PollConfiguration */ setDemoValues(): void { - this.addChoice('orange'); - this.addChoice('raisin'); - this.addChoice('abricot'); - this.form.patchValue({ - title: 'mon titre', + title: '', description: 'répondez SVP <3 ! *-* ', slug: this.uuidService.getUUID(), creatorPseudo: 'Chuck Norris', creatorEmail: 'chucknorris@example.com', isAboutDate: true, - whoModifiesAnswers: 'everybody', - whoCanChangeAnswers: 'everybody', - isProtectedByPassword: false, - isOwnerNotifiedByEmailOnNewVote: false, - isOwnerNotifiedByEmailOnNewComment: false, - isMaybeAnswerAvailable: false, - areResultsPublic: true, - expiracyNumberOfDays: 60, + // hasSeveralHours: true, + kind: 'date', + // TODO aplatir les contrôles + configuration: { + whoCanChangeAnswers: 'everybody', + isProtectedByPassword: false, + isOwnerNotifiedByEmailOnNewVote: false, + isOwnerNotifiedByEmailOnNewComment: false, + isMaybeAnswerAvailable: false, + areResultsPublic: true, + expiresDaysDelay: 60, + }, + comments: [], + choices: [], + dateChoices: [], + timeChoices: [], }); - this.automaticSlug(); - } - - askInitFormDefault(): void { - this.initFormDefault(false); - this.toastService.display('formulaire réinitialisé'); - } - - countDays(): void { - this.intervalDays = this.dateUtilities.countDays( - this.dateUtilities.parseInputDateToDateObject(this.startDateInterval), - this.dateUtilities.parseInputDateToDateObject(this.endDateInterval) - ); - this.cd.detectChanges(); - } - - /** - * add all the dates between the start and end dates in the interval section - */ - addIntervalOfDates(): void { - const newIntervalArray = this.dateUtilities.getDatesInRange( - this.dateUtilities.parseInputDateToDateObject(this.startDateInterval), - this.dateUtilities.parseInputDateToDateObject(this.endDateInterval), - 1 - ); - - const converted = []; - newIntervalArray.forEach((element) => { - converted.push({ - literal: element.literal, - date_object: element.date_object, - timeList: [], - }); - }); - this.dateList = [...new Set(converted)]; - // add only dates that are not already present with a Set of unique items - console.log('this.dateList', this.dateList); - this.showDateInterval = false; - - this.form.patchValue({ choices: this.dateList }); - // this.dateList.forEach(elem=>{ - // const newControlGroup = this.fb.group({ - // label: this.fb.control('', [Validators.required]), - // imageUrl: ['', [Validators.required]], - // }); - // - // this.choices.push(newControlGroup); - // }) - - this.toastService.display(`les dates ont été ajoutées aux réponses possibles.`); - } - - /** - * handle keyboard shortcuts - * @param $event - * @param choice_number - */ - keyOnChoice($event: KeyboardEvent, choice_number: number): void { - $event.preventDefault(); - - console.log('this.choices.length', this.choices.length); - console.log('choice_number', choice_number); - const lastChoice = this.choices.length - 1 === choice_number; - // reset field with Ctrl + D - // add a field with Ctrl + N - // go to previous choice with arrow up - // go to next choice with arrow down - console.log('$event', $event); - - if ($event.key == 'ArrowUp' && choice_number > 0) { - this.focusOnChoice(choice_number - 1); - } - if ($event.key == 'ArrowDown') { - // add a field if we are on the last choice - if (lastChoice) { - this.addChoice(); - this.toastService.display('choix ajouté par raccourci "flèche bas"'); - } else { - this.focusOnChoice(choice_number + 1); - } - } - if ($event.ctrlKey && $event.key == 'Backspace') { - this.deleteChoiceField(choice_number); - this.toastService.display('choix supprimé par raccourci "Ctrl + retour"'); - this.cd.detectChanges(); - this.focusOnChoice(Math.min(choice_number - 1, 0)); - } - if ($event.ctrlKey && $event.key == 'Enter') { - // go to other fields - const elem = this.document.querySelector('#creatorEmail'); - if (elem) { - elem.focus(); - } - } - } - - /** - * change time spans - */ - addTime() { - this.timeList.push({ - literal: '', - timeList: [], - date_object: new Date(), - }); - } - - removeAllTimes() { - this.timeList = []; - } - - resetTimes() { - this.timeList = otherDefaultDates; - } - - /** - * add a time period to a specific date choice, - * focus on the new input - * @param config - * @param id - */ - addTimeToDate(config: any, id: number) { - this.timeList.push({ - literal: '', - timeList: [], - date_object: new Date(), - }); - const selector = '[ng-reflect-choice_label="dateTime_' + id + '_Choices_' + (this.timeList.length - 1) + '"]'; - this.cd.detectChanges(); - const elem = this.document.querySelector(selector); - if (elem) { - elem.focus(); - } - } - - /** - * set the poll slug from other data of the poll - */ - automaticSlug() { - this.poll.slug = this.pollService.makeSlug(this.poll); } } diff --git a/src/app/features/administration/form/kind-select/kind-select.component.html b/src/app/features/administration/form/kind-select/kind-select.component.html new file mode 100644 index 00000000..f322436f --- /dev/null +++ b/src/app/features/administration/form/kind-select/kind-select.component.html @@ -0,0 +1,48 @@ +
+
+
+
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
diff --git a/src/app/features/administration/form/kind-select/kind-select.component.scss b/src/app/features/administration/form/kind-select/kind-select.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/features/administration/form/kind-select/kind-select.component.spec.ts b/src/app/features/administration/form/kind-select/kind-select.component.spec.ts new file mode 100644 index 00000000..a1ad23c5 --- /dev/null +++ b/src/app/features/administration/form/kind-select/kind-select.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { KindSelectComponent } from './kind-select.component'; + +describe('KindSelectComponent', () => { + let component: KindSelectComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [KindSelectComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(KindSelectComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/administration/form/kind-select/kind-select.component.ts b/src/app/features/administration/form/kind-select/kind-select.component.ts new file mode 100644 index 00000000..4cd7695a --- /dev/null +++ b/src/app/features/administration/form/kind-select/kind-select.component.ts @@ -0,0 +1,20 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { Poll } from '../../../../core/models/poll.model'; +import { FormGroup } from '@angular/forms'; + +@Component({ + selector: 'app-kind-select', + templateUrl: './kind-select.component.html', + styleUrls: ['./kind-select.component.scss'], +}) +export class KindSelectComponent implements OnInit { + public template_questions_answers = true; + @Input() + public poll?: Poll; + @Input() + public form: FormGroup; + + constructor() {} + + ngOnInit(): void {} +} diff --git a/src/app/features/administration/form/text-select/text-select.component.html b/src/app/features/administration/form/text-select/text-select.component.html new file mode 100644 index 00000000..8e20cf9e --- /dev/null +++ b/src/app/features/administration/form/text-select/text-select.component.html @@ -0,0 +1,53 @@ +
+
+ + + + + + + + + + + {{ 'creation.choices_hint' | translate }} + +
+
+
+
+ + {{ i * 1 + 1 }}) +
+
+ + +
+ + +
+
+
+
+
+
diff --git a/src/app/features/administration/form/text-select/text-select.component.scss b/src/app/features/administration/form/text-select/text-select.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/features/administration/form/text-select/text-select.component.spec.ts b/src/app/features/administration/form/text-select/text-select.component.spec.ts new file mode 100644 index 00000000..5eb68bf3 --- /dev/null +++ b/src/app/features/administration/form/text-select/text-select.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TextSelectComponent } from './text-select.component'; + +describe('TextSelectComponent', () => { + let component: TextSelectComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [TextSelectComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TextSelectComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/administration/form/text-select/text-select.component.ts b/src/app/features/administration/form/text-select/text-select.component.ts new file mode 100644 index 00000000..35d77dd5 --- /dev/null +++ b/src/app/features/administration/form/text-select/text-select.component.ts @@ -0,0 +1,21 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { FormGroup } from '@angular/forms'; + +@Component({ + selector: 'app-text-select', + templateUrl: './text-select.component.html', + styleUrls: ['./text-select.component.scss'], +}) +export class TextSelectComponent implements OnInit { + @Input() + public form: FormGroup; + public choices = []; + + constructor() {} + + ngOnInit(): void {} + reinitChoices(): void {} + addChoice(): void {} + deleteChoiceField(i): void {} + keyOnChoice($event, i): void {} +} diff --git a/src/app/features/administration/stepper/stepper.component.html b/src/app/features/administration/stepper/stepper.component.html index 00d5d761..7eb0f8c7 100644 --- a/src/app/features/administration/stepper/stepper.component.html +++ b/src/app/features/administration/stepper/stepper.component.html @@ -72,22 +72,22 @@ - + Les participants pourront consulter les résultats - + Les choix possibles concerneront des dates - + Le sondage sera protégé par un mot de passe - + Vous recevrez un mail à chaque nouvelle participation - + Vous recevrez un mail à chaque nouveau commentaire - + La réponse « peut-être » sera disponible diff --git a/src/app/features/administration/stepper/stepper.component.ts b/src/app/features/administration/stepper/stepper.component.ts index eb797594..d527c416 100644 --- a/src/app/features/administration/stepper/stepper.component.ts +++ b/src/app/features/administration/stepper/stepper.component.ts @@ -50,7 +50,7 @@ export class StepperComponent implements OnInit { ], areResultsPublic: [this.poll ? this.poll.configuration.areResultsPublic : true, [Validators.required]], expiracyNumberOfDays: [ - this.poll ? DateService.diffInDays(new Date(), this.poll.configuration.expires) : 60, + this.poll ? DateService.diffInDays(new Date(), this.poll.configuration.expiracyDate) : 60, [Validators.required], ], }); diff --git a/src/app/features/administration/success/success.component.html b/src/app/features/administration/success/success.component.html new file mode 100644 index 00000000..cb3015cf --- /dev/null +++ b/src/app/features/administration/success/success.component.html @@ -0,0 +1,16 @@ +
+
+
+

+ Création de sondage réussie +

+

+ Bravo! partagez le lien de votre sondage. Un récapitulatif a été envoyé à votre adresse email. +

+
+
+
+
+
+ image succès +
diff --git a/src/app/features/administration/success/success.component.scss b/src/app/features/administration/success/success.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/features/administration/success/success.component.spec.ts b/src/app/features/administration/success/success.component.spec.ts new file mode 100644 index 00000000..1e4f6a41 --- /dev/null +++ b/src/app/features/administration/success/success.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SuccessComponent } from './success.component'; + +describe('SuccessComponent', () => { + let component: SuccessComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [SuccessComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SuccessComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/administration/success/success.component.ts b/src/app/features/administration/success/success.component.ts new file mode 100644 index 00000000..13e175db --- /dev/null +++ b/src/app/features/administration/success/success.component.ts @@ -0,0 +1,12 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-success', + templateUrl: './success.component.html', + styleUrls: ['./success.component.scss'], +}) +export class SuccessComponent implements OnInit { + constructor() {} + + ngOnInit(): void {} +} diff --git a/src/app/features/consultation/consultation.component.html b/src/app/features/consultation/consultation.component.html index b32322e7..7991312b 100644 --- a/src/app/features/consultation/consultation.component.html +++ b/src/app/features/consultation/consultation.component.html @@ -9,7 +9,7 @@

{{ poll.title }}

-

author : {{ poll.owner?.pseudo }}

+
diff --git a/src/app/features/old-stuff/config/PollConfig.ts b/src/app/features/old-stuff/config/PollConfig.ts index f6eb71b8..483b5539 100644 --- a/src/app/features/old-stuff/config/PollConfig.ts +++ b/src/app/features/old-stuff/config/PollConfig.ts @@ -62,7 +62,6 @@ export class PollConfig { adminKey = ''; // key to change config of the poll owner_modifier_token = ''; // key to change a vote stack canModifyAnswers = true; // bool for the frontend selector - whoModifiesAnswers = 'everybody'; // everybody, self, nobody (= just admin) whoCanChangeAnswers = 'everybody'; // everybody, self, nobody (= just admin) dateList: any = otherDefaultDates; // sets of days as strings, config to set identical time for days in a special days poll timeList: DateChoice[] = otherDefaultDates; // ranges of time expressed as strings diff --git a/src/app/features/old-stuff/pages/visibility/visibility.component.html b/src/app/features/old-stuff/pages/visibility/visibility.component.html index 624751bc..14abb51a 100644 --- a/src/app/features/old-stuff/pages/visibility/visibility.component.html +++ b/src/app/features/old-stuff/pages/visibility/visibility.component.html @@ -73,7 +73,7 @@ name="modificationScope" id="modificationScope" *ngIf="true == !!config.canModifyAnswers" - [(ngModel)]="config.whoModifiesAnswers" + [(ngModel)]="config.whoCanChangeAnswers" [disabled]="false == !!config.canModifyAnswers" >
+
+
+
+ + + +
+
+
@@ -23,17 +36,4 @@
-
-
-
- - -
-
-
diff --git a/src/app/features/user-profile/user-profile.module.ts b/src/app/features/user-profile/user-profile.module.ts index 0dc60659..ad45254b 100644 --- a/src/app/features/user-profile/user-profile.module.ts +++ b/src/app/features/user-profile/user-profile.module.ts @@ -5,9 +5,16 @@ import { TranslateModule } from '@ngx-translate/core'; import { SharedModule } from '../../shared/shared.module'; import { UserPollsComponent } from './user-polls/user-polls.component'; import { UserProfileRoutingModule } from './user-profile-routing.module'; +import { AppModule } from '../../app.module'; @NgModule({ declarations: [UserPollsComponent], - imports: [CommonModule, UserProfileRoutingModule, SharedModule, TranslateModule.forChild({ extend: true })], + imports: [ + CommonModule, + UserProfileRoutingModule, + SharedModule, + TranslateModule.forChild({ extend: true }), + AppModule, + ], }) export class UserProfileModule {} diff --git a/src/app/routes-framadate.ts b/src/app/routes-framadate.ts index 671b46c1..8c95dacf 100644 --- a/src/app/routes-framadate.ts +++ b/src/app/routes-framadate.ts @@ -2,6 +2,12 @@ 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 { SuccessComponent } from './features/administration/success/success.component'; +import { WipTodoComponent } from './shared/components/ui/wip-todo/wip-todo.component'; +import { CguComponent } from './features/shared/components/ui/static-pages/cgu/cgu.component'; +import { LegalComponent } from './features/shared/components/ui/static-pages/legal/legal.component'; +import { PrivacyComponent } from './features/shared/components/ui/static-pages/privacy/privacy.component'; +import { CipheringComponent } from './features/shared/components/ui/static-pages/ciphering/ciphering.component'; export const routes: Routes = [ { path: '', component: HomeComponent }, @@ -35,6 +41,30 @@ export const routes: Routes = [ path: 'oldstuff', loadChildren: () => import('./features/old-stuff/old-stuff.module').then((m) => m.OldStuffModule), }, + { + path: 'success', + component: SuccessComponent, + }, + { + path: 'todo', + component: WipTodoComponent, + }, + { + path: 'cgu', + component: CguComponent, + }, + { + path: 'legal', + component: LegalComponent, + }, + { + path: 'privacy', + component: PrivacyComponent, + }, + { + path: 'ciphering', + component: CipheringComponent, + }, { path: 'page-not-found', component: PageNotFoundComponent }, { path: '**', redirectTo: 'page-not-found', pathMatch: 'full' }, ]; diff --git a/src/app/shared/components/selectors/language-selector/language-selector.component.ts b/src/app/shared/components/selectors/language-selector/language-selector.component.ts index 9cb904c4..a7ce3d6e 100644 --- a/src/app/shared/components/selectors/language-selector/language-selector.component.ts +++ b/src/app/shared/components/selectors/language-selector/language-selector.component.ts @@ -1,8 +1,6 @@ import { Component, DoCheck, OnInit } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; import { Language } from '../../../../core/enums/language.enum'; -import { StorageService } from '../../../../core/services/storage.service'; import { LanguageService } from '../../../../core/services/language.service'; @Component({ diff --git a/src/app/shared/components/ui/copy-text/copy-text.component.html b/src/app/shared/components/ui/copy-text/copy-text.component.html index 60b17a8a..c4265506 100644 --- a/src/app/shared/components/ui/copy-text/copy-text.component.html +++ b/src/app/shared/components/ui/copy-text/copy-text.component.html @@ -1,5 +1,7 @@ diff --git a/src/app/shared/components/ui/copy-text/copy-text.component.ts b/src/app/shared/components/ui/copy-text/copy-text.component.ts index 31c295b9..ae3cd96f 100644 --- a/src/app/shared/components/ui/copy-text/copy-text.component.ts +++ b/src/app/shared/components/ui/copy-text/copy-text.component.ts @@ -11,6 +11,7 @@ import { ToastService } from '../../../../core/services/toast.service'; export class CopyTextComponent implements OnInit { @Input() public textToCopy: string; public displayContentToCopy = false; + @Input() public displayLabelButton = true; constructor(private _clipboardService: ClipboardService, private toastService: ToastService) {} diff --git a/src/app/shared/components/ui/wip-todo/wip-todo.component.html b/src/app/shared/components/ui/wip-todo/wip-todo.component.html new file mode 100644 index 00000000..4e86e638 --- /dev/null +++ b/src/app/shared/components/ui/wip-todo/wip-todo.component.html @@ -0,0 +1,11 @@ +
+
+
+ +
+
+ Cette fonctionnalité est en cours de développement, vous pouvez contribuer à son + amélioration avec le bouton de feedback. +
+
+
diff --git a/src/app/shared/components/ui/wip-todo/wip-todo.component.scss b/src/app/shared/components/ui/wip-todo/wip-todo.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/shared/components/ui/wip-todo/wip-todo.component.spec.ts b/src/app/shared/components/ui/wip-todo/wip-todo.component.spec.ts new file mode 100644 index 00000000..ee227b25 --- /dev/null +++ b/src/app/shared/components/ui/wip-todo/wip-todo.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { WipTodoComponent } from './wip-todo.component'; + +describe('WipTodoComponent', () => { + let component: WipTodoComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [WipTodoComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(WipTodoComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/ui/wip-todo/wip-todo.component.ts b/src/app/shared/components/ui/wip-todo/wip-todo.component.ts new file mode 100644 index 00000000..9e861c15 --- /dev/null +++ b/src/app/shared/components/ui/wip-todo/wip-todo.component.ts @@ -0,0 +1,12 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-wip-todo', + templateUrl: './wip-todo.component.html', + styleUrls: ['./wip-todo.component.scss'], +}) +export class WipTodoComponent implements OnInit { + constructor() {} + + ngOnInit(): void {} +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index d75e7988..1ecfed1c 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -25,6 +25,7 @@ import { SettingsComponent } from './components/settings/settings.component'; import { SpinnerComponent } from './components/spinner/spinner.component'; import { CopyTextComponent } from './components/ui/copy-text/copy-text.component'; import { ErasableInputComponent } from './components/ui/erasable-input/erasable-input.component'; +import { WipTodoComponent } from './components/ui/wip-todo/wip-todo.component'; const COMPONENTS = [ ChoiceDetailsComponent, @@ -37,6 +38,7 @@ const COMPONENTS = [ ThemeSelectorComponent, CopyTextComponent, ErasableInputComponent, + WipTodoComponent, ]; const ANGULAR_MODULES = [CommonModule, ChartsModule, FormsModule, TranslateModule]; diff --git a/src/assets/i18n/EN.json b/src/assets/i18n/EN.json index 6085c5df..993cee82 100644 --- a/src/assets/i18n/EN.json +++ b/src/assets/i18n/EN.json @@ -584,5 +584,41 @@ "NL": "Néérlandais", "OC": "oc", "SV": "sv" + }, + + "calendar_widget" : { + "startsWith": "Starts with", + "contains": "Contains", + "notContains": "Not contains", + "endsWith": "Ends with", + "equals": "Equals", + "notEquals": "Not equals", + "noFilter": "No Filter", + "lt": "Less than", + "lte": "Less than or equal to", + "gt": "Greater than", + "gte": "Great then or equals", + "is": "Is", + "isNot": "Is not", + "before": "Before", + "after": "After", + "clear": "Clear", + "apply": "Apply", + "matchAll": "Match All", + "matchAny": "Match Any", + "addRule": "Add Rule", + "removeRule": "Remove Rule", + "accept": "Yes", + "reject": "No", + "choose": "Choose", + "upload": "Upload", + "cancel": "Cancel", + "dayNames": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + "dayNamesShort": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + "dayNamesMin": ["Su","Mo","Tu","We","Th","Fr","Sa"], + "monthNames": ["January","February","March","April","May","June","July","August","September","October","November","December"], + "monthNamesShort": ["Jan", "Feb", "Mar", "Apr", "May", "Jun","Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + "today": "Today", + "weekHeader": "Wk" } } diff --git a/src/assets/i18n/FR.json b/src/assets/i18n/FR.json index df1c8d17..2721c87e 100644 --- a/src/assets/i18n/FR.json +++ b/src/assets/i18n/FR.json @@ -38,6 +38,8 @@ "choices_hint": "Utilisez les flèches haut ⬆️ et bas ⬇️ pour passer d'un choix à un autre", "name": "Je peux aussi préciser mon nom si je le souhaite", "name_placeholder": "mon nom", + "email": "Mon email", + "email_placeholder": "mon-email@example.com", "description": "et la description serait", "description_placeholder": "description" }, @@ -149,7 +151,8 @@ "do-you-want-to": "Voulez-vous", "framadate-is-an-online-service-for-planning-an-appointment-or-making-a-decision-quickly-and-easily-n": "Framadate est un service en ligne permettant de planifier un rendez-vous ou prendre des décisions rapidement et simplement. Aucune inscription préalable n’est nécessaire.", "here-is-how-it-works": "Voici comment ça fonctionne :", - "send-the-poll-link-to-your-friends-or-colleagues": "Envoyez le lien du sondage à vos ami·e·s ou collègues", + "send-the-poll-link-to-your-friends-or-colleagues": "Créez un sondage en choisissant les réponses possibles, et vous recevez un lien par email. Envoyez le lien du sondage à vos ami·e·s ou collègues.", + "what-you-can-do": "Vous pouvez faire des propositions de dates et horaires de rendez-vous, limiter le nombre de participants, poser des questions de toutes sortes, permettre de la finesse dans les réponses, exporter les données... tout reste sous votre contrôle et vos libertés seront toujours respectées, car c'est un logiciel libre.", "what-is-framadate": "Prise en main", "view-an-example": "voir un exemple ?", "cecill-b-license": "licence CeCILL-B", @@ -585,5 +588,40 @@ "NL": "Néérlandais", "OC": "oc", "SV": "sv" - } + }, + "calendar_widget" : { + "startsWith": "Starts with", + "contains": "Contains", + "notContains": "Not contains", + "endsWith": "Ends with", + "equals": "Equals", + "notEquals": "Not equals", + "noFilter": "No Filter", + "lt": "Less than", + "lte": "Less than or equal to", + "gt": "Greater than", + "gte": "Great then or equals", + "is": "Is", + "isNot": "Is not", + "before": "Before", + "after": "After", + "clear": "Clear", + "apply": "Apply", + "matchAll": "Match All", + "matchAny": "Match Any", + "addRule": "Add Rule", + "removeRule": "Remove Rule", + "accept": "Yes", + "reject": "No", + "choose": "Choose", + "upload": "Upload", + "cancel": "Cancel", + "dayNames": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + "dayNamesShort": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + "dayNamesMin": ["Su","Mo","Tu","We","Th","Fr","Sa"], + "monthNames": ["Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Août","Septembre","Octobre","Novembre","Décembre"], + "monthNamesShort": ["Jan", "Feb", "Mar", "Apr", "May", "Jun","Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + "today": "Aujourd'hui", + "weekHeader": "Wk" +} } diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index 605f23be..7f6e47f0 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -2,17 +2,28 @@ const backendApiUrlsInDev = { local: '/api/v1', remote: 'https://framadate-api.cipherbliss.com/api/v1', }; +const apiV1 = { + baseHref: 'http://localhost:8000/api/v1', + api_new_poll: '/poll/', + api_get_poll: '/poll/{id}', + 'api_test-mail-poll': '/api/v1/poll/mail/test-mail-poll/{emailChoice}', + 'app.swagger': '/api/doc.json', +}; export const environment = { production: true, - appTitle: 'FramaDate', - appVersion: '2.0.0', - appLogo: '/assets/img/logo.png', + appTitle: 'FramaDate Funky', + appVersion: '2.1.0', + appLogo: 'assets/img/logo.png', api: { + versionToUse: 'apiV1', + version: { + apiV1, + }, baseHref: backendApiUrlsInDev.remote, endpoints: { polls: { - name: '/polls', + name: '/poll', choices: { name: '/choices', }, @@ -39,8 +50,12 @@ export const environment = { }, poll: { defaultConfig: { - expiracyInDays: 60, + maxCountOfAnswers: 150, + expiresDaysDelay: 60, expiracyAfterLastModificationInDays: 180, + whoCanChangeAnswers: 'everybody', + visibility: 'link_only', + voteChoices: 'only_yes', }, }, localStorage: { diff --git a/src/environments/environment.ts b/src/environments/environment.ts index d4c9aff8..91c038d9 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -4,10 +4,10 @@ const backendApiUrlsInDev = { local: '/api/v1', - remote: 'https://framadate-api.cipherbliss.com/api/v1', + remote: 'http://localhost:8000/api/v1', }; const apiV1 = { - baseHref: 'https://framadate-api.cipherbliss.com/api/v1', + baseHref: 'http://localhost:8000/api/v1', api_new_poll: '/poll/', api_get_poll: '/poll/{id}', 'api_test-mail-poll': '/api/v1/poll/mail/test-mail-poll/{emailChoice}', @@ -17,7 +17,7 @@ const apiV1 = { export const environment = { production: false, appTitle: 'FramaDate Funky', - appVersion: '2.0.0', + appVersion: '2.1.0', appLogo: 'assets/img/logo.png', api: { versionToUse: 'apiV1', @@ -54,8 +54,12 @@ export const environment = { }, poll: { defaultConfig: { - expiracyInDays: 60, + maxCountOfAnswers: 150, + expiresDaysDelay: 60, expiracyAfterLastModificationInDays: 180, + whoCanChangeAnswers: 'everybody', + visibility: 'link_only', + voteChoices: 'only_yes', }, }, localStorage: { diff --git a/src/proxy.conf.json b/src/proxy.conf.json index 709cdb6c..5b9f3ff5 100644 --- a/src/proxy.conf.json +++ b/src/proxy.conf.json @@ -1,6 +1,6 @@ { "/api/*": { - "target": "http://localhost:8000", + "target": "http://localhost:3001", "secure": false, "logLevel": "debug" } diff --git a/src/styles/dev-utilities/_helpers.scss b/src/styles/dev-utilities/_helpers.scss index 9d5784b0..656c7dd4 100644 --- a/src/styles/dev-utilities/_helpers.scss +++ b/src/styles/dev-utilities/_helpers.scss @@ -15,6 +15,12 @@ box-shadow: $dark-lavender 0 0 10px; } +.is-boxed { + border: 1px solid #ddd; + padding: 1em; + margin: 1em 0; +} + .nobold { font-weight: normal; } @@ -22,3 +28,7 @@ .hidden { display: none; } + +.padded { + padding: 1em; +} diff --git a/src/styles/libraries/_overrides.scss b/src/styles/libraries/_overrides.scss index af040a3e..12c528d7 100644 --- a/src/styles/libraries/_overrides.scss +++ b/src/styles/libraries/_overrides.scss @@ -11,3 +11,7 @@ $body-background-color: $black; $control-border-width: 2px; $input-border-color: transparent; $input-shadow: none; + +.notification { + margin: 1em 0; +} diff --git a/src/styles/themes/_base.scss b/src/styles/themes/_base.scss index 4d7250bc..5e2a778e 100644 --- a/src/styles/themes/_base.scss +++ b/src/styles/themes/_base.scss @@ -2,6 +2,7 @@ background: $primary; main { + padding: 0; margin-bottom: 2em; padding-bottom: 5em; padding-top: 1em; diff --git a/src/styles/themes/_light.scss b/src/styles/themes/_light.scss index eab5078e..7b12ab78 100644 --- a/src/styles/themes/_light.scss +++ b/src/styles/themes/_light.scss @@ -11,7 +11,9 @@ } main { - .container { + padding-top: 0; + + > .container { background: #fff; padding-bottom: 10em; } diff --git a/yarn.lock b/yarn.lock index aa1f8a9f..24afad82 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8193,6 +8193,11 @@ node-forge@0.9.0: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ== +node-forge@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" + integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"