Compare commits

...

15 Commits

36 changed files with 296 additions and 192 deletions

View File

@ -6,6 +6,9 @@
</a> </a>
<a class="navbar-item title is-size-1-fullhd is-size-4-touch has-text-black" routerLink="/"> <a class="navbar-item title is-size-1-fullhd is-size-4-touch has-text-black" routerLink="/">
{{ appTitle }} {{ appTitle }}
<sub>
{{ environment.appVersion }}
</sub>
</a> </a>
</div> </div>
<div class="navbar-start"> <div class="navbar-start">

View File

@ -1,6 +1,12 @@
import { Answer } from '../enums/answer.enum'; import { Answer } from '../enums/answer.enum';
import { Owner } from './owner.model'; import { Owner } from './owner.model';
export class ChoiceGroup {
date_string: string;
subSetToYes = false; // to know if all the choices are set to YES, to toggle them all at once without checking them individually
choices: Choice[];
}
export class Choice { export class Choice {
public id: number; public id: number;
public name: string; public name: string;

View File

@ -1,12 +1,8 @@
import { Choice } from './choice.model'; import { Choice, ChoiceGroup } from './choice.model';
import { Comment } from './comment.model'; import { Comment } from './comment.model';
import { Owner } from './owner.model'; import { Owner } from './owner.model';
import { DateChoice, TimeSlices } from '../../../../mocks/old-stuff/config/defaultConfigs'; import { DateChoice, TimeSlices } from './dateChoice.model';
import { defaultTimeOfDay } from '../../../../mocks/old-stuff/config/defaultConfigs';
export class ChoiceGroup {
date_string: string;
choices: Choice[];
}
export class Poll { export class Poll {
public id = 0; public id = 0;
@ -58,13 +54,13 @@ export class Poll {
public stacks = []; public stacks = [];
public allowed_answers = []; public allowed_answers = ['yes'];
public modification_policy = 'everybody'; public modification_policy = 'everybody';
public dateChoices: DateChoice[] = []; public dateChoices: DateChoice[] = [];
// sets of dateChoices as strings, config to set identical time for dateChoices in a special dateChoices poll // sets of dateChoices as strings, config to set identical time for dateChoices in a special dateChoices poll
public timeSlices: TimeSlices[] = []; // ranges of time expressed as strings public timeSlices: TimeSlices[] = Object.create(defaultTimeOfDay); // ranges of time expressed as strings
constructor(public owner: Owner = new Owner(), public title = 'mon titre', public custom_url: string = '') {} constructor(public owner: Owner = new Owner(), public title = 'mon titre', public custom_url: string = '') {}
} }

View File

@ -3,8 +3,8 @@ import { Owner } from './owner.model';
export class Stack { export class Stack {
public id: number; public id: number;
public pseudo: string = 'Choque Nourrice'; public pseudo = 'Choque Nourrice';
public comment: string = 'Le beau commentaire de Choque Nourrice'; public comment = 'Le beau commentaire de Choque Nourrice';
public owner: Owner = new Owner(); public owner: Owner = new Owner();
public votes: Vote[]; public votes: Vote[] = [];
} }

View File

@ -20,9 +20,6 @@ const apiEndpoints = environment.api.endpoints;
providedIn: 'root', providedIn: 'root',
}) })
export class ApiService { export class ApiService {
private static loader: LoaderService;
private useDevLocalServer = true;
private devLocalServerBaseHref = 'http://localhost:8000/';
private axiosInstance: AxiosInstance; private axiosInstance: AxiosInstance;
private readonly pollsEndpoint = apiEndpoints.polls.name; private readonly pollsEndpoint = apiEndpoints.polls.name;
private readonly answersEndpoint = apiEndpoints.polls.answers.name; private readonly answersEndpoint = apiEndpoints.polls.answers.name;
@ -32,8 +29,9 @@ export class ApiService {
private readonly usersPollsEndpoint = apiEndpoints.users.polls.name; private readonly usersPollsEndpoint = apiEndpoints.users.polls.name;
private readonly usersPollsSendEmailEndpoint = apiEndpoints.users.polls.sendEmail.name; private readonly usersPollsSendEmailEndpoint = apiEndpoints.users.polls.sendEmail.name;
private baseHref: string; private baseHref: string;
private static loaderService: LoaderService;
constructor(private http: HttpClient, private loader: LoaderService, private toastService: ToastService) { constructor(private http: HttpClient, private loaderService: LoaderService) {
this.baseHref = apiBaseHref; this.baseHref = apiBaseHref;
this.axiosInstance = axios.create({ baseURL: apiBaseHref }); this.axiosInstance = axios.create({ baseURL: apiBaseHref });
@ -41,7 +39,7 @@ export class ApiService {
this.axiosInstance.defaults.headers.post['Content-Type'] = 'application/json'; this.axiosInstance.defaults.headers.post['Content-Type'] = 'application/json';
this.axiosInstance.defaults.headers.post['Accept'] = 'application/json'; this.axiosInstance.defaults.headers.post['Accept'] = 'application/json';
this.axiosInstance.defaults.headers.post['Charset'] = 'UTF-8'; this.axiosInstance.defaults.headers.post['Charset'] = 'UTF-8';
this.axiosInstance.defaults.headers.post['Accept-Charset'] = 'UTF-8'; // this.axiosInstance.defaults.headers.post['Accept-Charset'] = 'UTF-8';
this.axiosInstance.defaults.headers.post['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'; this.axiosInstance.defaults.headers.post['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS';
this.axiosInstance.defaults.headers.post['Referrer-Policy'] = 'origin-when-cross-origin'; this.axiosInstance.defaults.headers.post['Referrer-Policy'] = 'origin-when-cross-origin';
this.axiosInstance.defaults.headers.post['Access-Control-Allow-Origin'] = '*'; this.axiosInstance.defaults.headers.post['Access-Control-Allow-Origin'] = '*';
@ -81,7 +79,7 @@ export class ApiService {
} }
private static handleError(error): void { private static handleError(error): void {
// this.loader.setStatus(true); // this.loaderService.setStatus(true);
if (error.response) { if (error.response) {
// The request was made and the server responded with a status code // The request was made and the server responded with a status code
// that falls out of the range of 2xx // that falls out of the range of 2xx
@ -98,13 +96,12 @@ export class ApiService {
console.log('Error', error.message); console.log('Error', error.message);
} }
console.log(error.config); console.log(error.config);
this.loader.setStatus(false); // this.loaderService.setStatus(false);
} }
public async createPoll(poll: Poll): Promise<Subscription> { public async createPoll(poll: Poll): Promise<Subscription> {
// this.loader.setStatus(true); // this.loaderService.setStatus(true);
console.log('createPoll config', poll); console.log('createPoll config', poll);
this.loader.setStatus(true);
return this.axiosInstance.post( return this.axiosInstance.post(
`${this.baseHref}${currentApiRoutes['api_new_poll']}`, `${this.baseHref}${currentApiRoutes['api_new_poll']}`,
poll, poll,
@ -117,14 +114,14 @@ export class ApiService {
* @param poll * @param poll
* @param vote_stack * @param vote_stack
*/ */
public sendNewVoteStackOfPoll(poll: Poll, vote_stack: Stack): Observable<any> { public sendNewVoteStackOfPoll(poll: Poll, vote_stack: Stack): Promise<void> {
// api_new_vote_stack POST ANY ANY /api/v1/poll/{id}/answer // api_new_vote_stack POST ANY ANY /api/v1/poll/{id}/answer
console.log('vote_stack', vote_stack); console.log('vote_stack', vote_stack);
console.log('this.baseHref', this.baseHref); console.log('this.baseHref', this.baseHref);
const headers = ApiService.makeHeaders(vote_stack); const headers = ApiService.makeHeaders(vote_stack);
console.log('headers', headers); console.log('headers', headers);
const url = `${this.baseHref}/poll/${poll.custom_url}/answer`; const url = `${this.baseHref}/vote/poll/${poll.custom_url}/answer`;
const axiosconf = { const axiosconf = {
url, url,
@ -133,14 +130,7 @@ export class ApiService {
headers, headers,
}; };
return this.http.post(url, vote_stack, { return this.axiosInstance.post(url, vote_stack);
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Accept,Accept-Language,Content-Language,Content-Type',
},
});
} }
////////// //////////
@ -304,17 +294,18 @@ export class ApiService {
ApiService.handleError(error); ApiService.handleError(error);
} }
} }
///////////////////// /////////////////////
// PRIVATE METHODS // // PRIVATE METHODS //
///////////////////// /////////////////////
public async sendEmailToUserOfItsPollsList(email: string): Promise<void> { public async sendEmailToUserOfItsPollsList(email: string): Promise<void> {
if (this.loader.isLoading) { // if (this.loaderService.isLoading) {
return; // return;
} // }
// If user is not authenticated: the list of polls is send to user's email by the backend. // If user is not authenticated: the list of polls is send to user's email by the backend.
try { try {
this.loader.setStatus(false); // this.loaderService.setStatus(false);
await this.axiosInstance.get<Poll[]>( await this.axiosInstance.get<Poll[]>(
`${this.usersEndpoint}/${email}${this.usersPollsEndpoint}${this.usersPollsSendEmailEndpoint}` `${this.usersEndpoint}/${email}${this.usersPollsEndpoint}${this.usersPollsSendEmailEndpoint}`
); );

View File

@ -96,10 +96,12 @@ export class DateUtilitiesService {
*/ */
makeDefaultDateChoices(): DateChoice[] { makeDefaultDateChoices(): DateChoice[] {
const today = new Date(); const today = new Date();
const ladate = this.addDaysToDate(1, today); const ladate = this.addDaysToDate(0, today);
const ladate2 = this.addDaysToDate(2, today); const ladate2 = this.addDaysToDate(1, today);
const ladate3 = this.addDaysToDate(3, today); const ladate3 = this.addDaysToDate(2, today);
const ladate4 = this.addDaysToDate(4, today); const ladate4 = this.addDaysToDate(3, today);
const ladate5 = this.addDaysToDate(4, today);
const ladate6 = this.addDaysToDate(5, today);
return [ return [
{ {
@ -122,6 +124,16 @@ export class DateUtilitiesService {
timeSlices: Object.create(defaultTimeOfDay), timeSlices: Object.create(defaultTimeOfDay),
date_object: ladate4, date_object: ladate4,
}, },
{
literal: this.formateDateToInputStringNg(ladate5),
timeSlices: Object.create(defaultTimeOfDay),
date_object: ladate5,
},
{
literal: this.formateDateToInputStringNg(ladate6),
timeSlices: Object.create(defaultTimeOfDay),
date_object: ladate6,
},
]; ];
} }
} }

View File

@ -198,14 +198,23 @@ export class PollService implements Resolve<Poll> {
const formFields = Object.keys(form.value); const formFields = Object.keys(form.value);
console.log('pollKeys, formFields', pollKeys, formFields); console.log('pollKeys, formFields', pollKeys, formFields);
newpoll.allowed_answers = ['yes'];
for (const pk of pollKeys) { for (const pk of pollKeys) {
if (formFields.indexOf(pk) !== -1) { if (formFields.indexOf(pk) !== -1) {
newpoll[pk] = form.value[pk]; const field = form.value[pk];
newpoll[pk] = field;
} else { } else {
console.log('manque pollKey', pk); console.log('manque pollKey', pk);
} }
} }
if (form.value.isMaybeAnswerAvailable) {
newpoll.allowed_answers.push('maybe');
}
if (form.value.isNoAnswerAvailable) {
newpoll.allowed_answers.push('no');
}
newpoll.description = form.value.description; newpoll.description = form.value.description;
newpoll.has_several_hours = form.value.hasSeveralHours; newpoll.has_several_hours = form.value.hasSeveralHours;
newpoll.hasSeveralHours = form.value.hasSeveralHours; newpoll.hasSeveralHours = form.value.hasSeveralHours;
@ -215,9 +224,11 @@ export class PollService implements Resolve<Poll> {
newpoll.kind = form.value.kind; newpoll.kind = form.value.kind;
newpoll.allow_comments = form.value.allowComments; newpoll.allow_comments = form.value.allowComments;
// merge choices from storage // merge choices from storage
newpoll.choices = this.storageService.choices; newpoll.choices = Object.assign([], this.storageService.choices);
newpoll.dateChoices = this.storageService.dateChoices; newpoll.dateChoices = Object.assign([], this.storageService.dateChoices);
newpoll.timeSlices = this.storageService.timeSlices; newpoll.timeSlices = Object.assign([], this.storageService.timeSlices);
console.log('this.storageService.timeSlices', this.storageService.timeSlices, newpoll.timeSlices);
return newpoll; return newpoll;
} }

View File

@ -18,6 +18,7 @@ import {
import { Poll } from '../models/poll.model'; import { Poll } from '../models/poll.model';
import { Owner } from '../models/owner.model'; import { Owner } from '../models/owner.model';
import { DateUtilitiesService } from './date.utilities.service'; import { DateUtilitiesService } from './date.utilities.service';
import { ToastService } from './toast.service';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
@ -44,8 +45,13 @@ export class StorageService {
@LocalStorage() @LocalStorage()
public choices: Choice[] = []; public choices: Choice[] = [];
constructor(public dateUtilities: DateUtilitiesService) { constructor(
public dateUtilities: DateUtilitiesService,
private toastService: ToastService
) {
if (environment.autofill) { if (environment.autofill) {
this.toastService.display('autofill des sondages utilisateur');
this.userPolls.push(new Poll(new Owner(), 'Démo: Anniversaire de tonton Patrick', 'aujourdhui-ou-demain')); this.userPolls.push(new Poll(new Owner(), 'Démo: Anniversaire de tonton Patrick', 'aujourdhui-ou-demain'));
this.userPolls.push(new Poll(new Owner(), 'Démo: Atelier cuisine du quartier', 'aujourdhui-ou-demain')); this.userPolls.push(new Poll(new Owner(), 'Démo: Atelier cuisine du quartier', 'aujourdhui-ou-demain'));
this.userPolls.push( this.userPolls.push(
@ -64,7 +70,9 @@ export class StorageService {
// text choices // text choices
for (const choice of choices_list) { for (const choice of choices_list) {
if (environment.autofill) { if (environment.autofill) {
this.vote_stack.votes.push(new Vote(choice.id, 'yes')); this.toastService.display('autofill au hasard des votes à ce sondage');
const defaultvalue = Math.random() > 0.75 ? 'yes' : '';
this.vote_stack.votes.push(new Vote(choice.id, defaultvalue));
} else { } else {
this.vote_stack.votes.push(new Vote(choice.id)); this.vote_stack.votes.push(new Vote(choice.id));
} }
@ -94,4 +102,14 @@ export class StorageService {
} }
return false; return false;
} }
setAllSubchoicesTo(groupe, newAnswer = 'yes') {
groupe.choices.map((choice) => {
for (const vote of this.vote_stack.votes) {
if (vote.choice_id == choice.id) {
vote.value = newAnswer;
}
}
});
}
} }

View File

@ -2,11 +2,14 @@
<div class="columns"> <div class="columns">
<div class="column"> <div class="column">
<label for="title"> <label for="title">
<span>
{{ 'creation.choose_title' | translate }} {{ 'creation.choose_title' | translate }}
</span>
</label> </label>
<br />
<input <input
class="input" class="input"
matInput
[placeholder]="'creation.choose_title_placeholder' | translate" [placeholder]="'creation.choose_title_placeholder' | translate"
formControlName="title" formControlName="title"
id="title" id="title"
@ -15,13 +18,12 @@
#title #title
/> />
<button <button
(click)="form.patchValue({ title: '' })"
*ngIf="form.value.title"
aria-label="Clear"
mat-button mat-button
mat-icon-button *ngIf="form.value.title"
matSuffix matSuffix
maxlength="400" mat-icon-button
aria-label="Clear"
(click)="form.patchValue({ title: '' })"
> >
<i class="fa fa-close"></i> <i class="fa fa-close"></i>
</button> </button>
@ -90,20 +92,4 @@
<hr /> <hr />
</div> </div>
Url personnalisée:
{{ form.value.custom_url }}
<hr />
<div class="column">
<button class="btn btn--warning" (click)="askInitFormDefault()">
<i class="fa fa-refresh"></i>
Tout réinitialiser
</button>
<br />
<br />
<button class="btn is-default" (click)="automaticSlug()">
<i class="fa fa-refresh"></i>
Slug automatique
</button>
</div>
</form> </form>

View File

@ -0,0 +1,4 @@
#title {
display: block;
width: 80%;
}

View File

@ -33,28 +33,12 @@ export class BaseConfigComponent {
@Inject(DOCUMENT) private document: Document @Inject(DOCUMENT) private document: Document
) {} ) {}
askInitFormDefault(): void {
this.toastService.display('formulaire réinitialisé', 'info');
}
public updateSlug(): void { public updateSlug(): void {
const newValueFormatted = this.pollService.convertTextToSlug(this.form.value.title); const newValueFormatted = this.pollService.convertTextToSlug(this.form.value.title);
console.log('newValueFormatted', newValueFormatted); console.log('newValueFormatted', newValueFormatted);
this.form.patchValue({ custom_url: newValueFormatted }); this.form.patchValue({ custom_url: newValueFormatted });
} }
/**
* set the poll custom_url from other data of the poll
*/
automaticSlug(): void {
this.form.patchValue({
custom_url:
this.pollService.convertTextToSlug(this.form.value.title) +
'_' +
this.utilitiesService.makeUuid().substr(0, 12),
});
}
getErrorMessage(fieldControl) { getErrorMessage(fieldControl) {
return fieldControl.hasError('required') return fieldControl.hasError('required')
? 'You must enter a value' ? 'You must enter a value'

View File

@ -91,7 +91,13 @@
<hr /> <hr />
<div class="main-box is-boxed"> <div class="main-box is-boxed">
liste de jours : <h2>Dates</h2>
<button class="btn button-help" mat-raised-button (click)="openSimple()">
💁 Raccourcis
</button>
<app-shortcuts-help *ngIf="display"></app-shortcuts-help>
<br />
<br />
<app-day-list <app-day-list
[form]="form" [form]="form"
[dateChoices]="dateChoices" [dateChoices]="dateChoices"

View File

@ -1,9 +1,7 @@
:host { :host {
.time-choice { .time-choice {
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
//border: solid 1px #dedede;
padding: 0.5em; padding: 0.5em;
//padding: 20px 10px;
border-bottom: solid 1px #ccc; border-bottom: solid 1px #ccc;
color: rgba(0, 0, 0, 0.87); color: rgba(0, 0, 0, 0.87);
box-sizing: border-box; box-sizing: border-box;

View File

@ -31,6 +31,7 @@ export class DateSelectComponent implements OnInit {
timeSlices: TimeSlices[] = []; // ranges of time expressed as strings timeSlices: TimeSlices[] = []; // ranges of time expressed as strings
selectionKind = 'range'; selectionKind = 'range';
display: any;
constructor( constructor(
private fb: FormBuilder, private fb: FormBuilder,
@ -71,4 +72,8 @@ export class DateSelectComponent implements OnInit {
this.dateChoices.map((elem) => (elem.timeSlices = Object.create(slices))); this.dateChoices.map((elem) => (elem.timeSlices = Object.create(slices)));
this.toastService.display('périodes horaires réinitialisées'); this.toastService.display('périodes horaires réinitialisées');
} }
openSimple() {
this.display = !this.display;
}
} }

View File

@ -23,13 +23,6 @@
(cdkDropListDropped)="dropDayItem($event)" (cdkDropListDropped)="dropDayItem($event)"
> >
<div class="column"> <div class="column">
<h2>Dates</h2>
<button class="btn button-help" mat-raised-button (click)="openSimple()">
💁 Raccourcis
</button>
<app-shortcuts-help *ngIf="display"></app-shortcuts-help>
<br />
<br />
<div <div
*ngFor="let choice of dateChoices; index as id" *ngFor="let choice of dateChoices; index as id"
class="date-choice padded" class="date-choice padded"

View File

@ -1,5 +1,5 @@
.day-weekend { .day-weekend {
background: #dedede; background: #dccfed;
} }
.button { .button {
min-width: 9ch; min-width: 9ch;
@ -11,6 +11,15 @@
} }
.several-times { .several-times {
padding-left: 2em; padding-left: 2em;
width: 96.5%;
}
.date-choice {
&:nth-child(odd) {
background: #fbf8ff;
&.day-weekend {
background: #d7cae9;
}
}
} }
.date-choice-item { .date-choice-item {
width: 75%; width: 75%;

View File

@ -12,6 +12,14 @@
<i class="fa fa-save"></i> <i class="fa fa-save"></i>
Enregistrer le sondage (sans vérifier) Enregistrer le sondage (sans vérifier)
</button> </button>
<button class="btn btn--warning" (click)="askInitFormDefault()">
<i class="fa fa-refresh"></i>
Tout réinitialiser
</button>
<button class="btn is-default" (click)="automaticSlug()">
<i class="fa fa-refresh"></i>
Slug automatique
</button>
<main class="columns"> <main class="columns">
<div class="column"> <div class="column">
<label class="label is-medium" for="kind"> <label class="label is-medium" for="kind">

View File

@ -39,6 +39,7 @@ export class FormComponent implements OnInit, AfterViewInit {
public apiService: ApiService, public apiService: ApiService,
public dateUtils: DateUtilitiesService, public dateUtils: DateUtilitiesService,
private router: Router, private router: Router,
private utilitiesService: PollUtilitiesService,
@Inject(DOCUMENT) private document: any @Inject(DOCUMENT) private document: any
) {} ) {}
@ -94,7 +95,7 @@ export class FormComponent implements OnInit, AfterViewInit {
}); });
// take back values from pollservice // take back values from pollservice
this.form.patchValue(this.pollService.poll); // this.form.patchValue(this.pollService.poll);
this.setDefaultFormValues(); this.setDefaultFormValues();
if (showDemoValues) { if (showDemoValues) {
@ -116,7 +117,7 @@ export class FormComponent implements OnInit, AfterViewInit {
creatorEmail: '', creatorEmail: '',
description: 'RSVP', description: 'RSVP',
isAboutDate: true, isAboutDate: true,
hasSeveralHours: true, hasSeveralHours: false,
kind: 'date', kind: 'date',
password: '', password: '',
whoCanChangeAnswers: 'everybody', whoCanChangeAnswers: 'everybody',
@ -134,18 +135,17 @@ export class FormComponent implements OnInit, AfterViewInit {
allowNewDateTime: false, allowNewDateTime: false,
startDateInterval: dateStart, startDateInterval: dateStart,
endDateInterval: dateEnd, endDateInterval: dateEnd,
comments: [],
}); });
this.automaticSlug();
} }
/** /**
* add example values to the form, overrides defaults of PollConfiguration * add example values to the form, overrides defaults of PollConfiguration
*/ */
setDemoValues(): void { setDemoValues(): void {
const title = 'le titre de démo oh oh ' + new Date().getTime(); const title = 'le titre de démo __ ' + new Date().getTime();
// this.form.patchValue(this.pollService.poll); this.form.patchValue({ creatorPseudo: 'Chuck Norris', creatorEmail: 'chucknorris@example.com' });
// this.form.patchValue({ creatorPseudo: 'Chuck Norris', creatorEmail: 'chucknorris@example.com' });
const dateStart = this.dateUtils.formateDateToInputStringNg(new Date()); const dateStart = this.dateUtils.formateDateToInputStringNg(new Date());
const dateEnd = this.dateUtils.formateDateToInputStringNg(this.dateUtils.addDaysToDate(5, new Date())); const dateEnd = this.dateUtils.formateDateToInputStringNg(this.dateUtils.addDaysToDate(5, new Date()));
@ -156,6 +156,24 @@ export class FormComponent implements OnInit, AfterViewInit {
description: 'répondez SVP <3 ! *-*', description: 'répondez SVP <3 ! *-*',
creatorPseudo: 'Chuck Norris', creatorPseudo: 'Chuck Norris',
creatorEmail: 'chucknorris@example.com', creatorEmail: 'chucknorris@example.com',
dateStart,
dateEnd,
});
}
askInitFormDefault(): void {
this.toastService.display('formulaire réinitialisé', 'info');
}
/**
* set the poll custom_url from other data of the poll
*/
automaticSlug(): void {
this.form.patchValue({
custom_url:
this.pollService.convertTextToSlug(this.form.value.title) +
'_' +
this.utilitiesService.makeUuid().substr(0, 12),
}); });
} }

View File

@ -0,0 +1,5 @@
#kind {
width: 100%;
max-width: 100%;
display: block;
}

View File

@ -72,7 +72,7 @@
Pour être sûr de retrouver ces liens, nous pouvons vous les envoyer sur votre mail : Pour être sûr de retrouver ces liens, nous pouvons vous les envoyer sur votre mail :
</label> </label>
<br /> <br />
<input type="email" id="email" name="email" [(ngModel)]="mailToRecieve" placeholder="email" /> <input type="email" id="email" name="email" [(ngModel)]="poll.creatorEmail" placeholder="email" />
<br /> <br />
<button class="btn btn--primary" (click)="sendToEmail()"> <button class="btn btn--primary" (click)="sendToEmail()">
Envoyer les liens du sondage Envoyer les liens du sondage

View File

@ -61,6 +61,7 @@
<div class="card"> <div class="card">
<header class="card-header"> <header class="card-header">
<p class="card-header-title is-1 title">{{ poll.title }}</p> <p class="card-header-title is-1 title">{{ poll.title }}</p>
<div class="voters-count padded"><i class="fa fa-users"></i> {{ poll.stacks.length }} votants</div>
<!-- <p class="card-header-icon">author : {{ poll.owner?.pseudo }}</p>--> <!-- <p class="card-header-icon">author : {{ poll.owner?.pseudo }}</p>-->
</header> </header>

View File

@ -52,6 +52,7 @@ export class ConsultationComponent implements OnInit, OnDestroy {
if (newpoll) { if (newpoll) {
this.isArchived = new Date(newpoll.expiracy_date) < new Date(); this.isArchived = new Date(newpoll.expiracy_date) < new Date();
this.poll.is_archived = this.isArchived; this.poll.is_archived = this.isArchived;
this.poll.choices_grouped.map((elem) => (elem.subSetToYes = false));
} }
}); });
@ -87,19 +88,11 @@ export class ConsultationComponent implements OnInit, OnDestroy {
} }
addVoteStack(): void { addVoteStack(): void {
this.api.sendNewVoteStackOfPoll(this.poll, this.storageService.vote_stack).subscribe((resp) => { this.toastService.display('envoi du vote ....');
console.log('sendNewVoteStackOfPoll resp', resp); this.api.sendNewVoteStackOfPoll(this.poll, this.storageService.vote_stack).then((resp) => {
console.log('resp', resp);
this.toastService.display('vote ajouté', 'success'); this.pollService.loadPollBycustom_url(this.poll.custom_url);
if (resp) {
const response: Promise<Poll | undefined> = this.api.getPollByCustomUrl(this.poll.custom_url);
response.then((res: Poll | undefined) => {
this.pollService._poll.next(res);
});
} else {
this.toastService.display('erreur à la réception du nouveau vote', 'error');
}
}); });
} }

View File

@ -2,13 +2,19 @@
<div class="date-choices" *ngIf="poll.kind == 'date'"> <div class="date-choices" *ngIf="poll.kind == 'date'">
<div class="box" *ngFor="let group of poll.choices_grouped"> <div class="box" *ngFor="let group of poll.choices_grouped">
<h3 class="title is-3"> <h3 class="title is-3">
{{ group.date_string }} <button
class="icon button padded"
(click)="toggleAllOfChoice(group)"
[ngClass]="{ 'has-background-primary': group.subSetToYes }"
>
<i class="fa fa-check-circle-o fa"></i>
</button>
{{ showAsDate(group.date_string) | date: 'fullDate':'Europe/Paris':'fr_FR' }}
</h3> </h3>
<div class="box" *ngFor="let choice of group.choices"> <div class="time-slice-choice" *ngFor="let choice of group.choices">
<div class="columns is-vcentered is-mobile"> <div class="columns is-vcentered is-mobile">
<div class="column"> <div class="column">
<label class="label"> <label class="label">
<!-- {{choice.id}} )-->
{{ choice.name }} {{ choice.name }}
</label> </label>
</div> </div>
@ -18,9 +24,9 @@
</span> </span>
</div> </div>
<div class="column is-narrow"> <div class="column is-narrow">
<button class="button is-white" (click)="openModal(poll, choice)"> <!-- <button class="button is-white" (click)="openModal(poll, choice)">-->
<i class="fa fa-info-circle"></i> <!-- <i class="fa fa-info-circle"></i>-->
</button> <!-- </button>-->
</div> </div>
<div class="column is-narrow"> <div class="column is-narrow">
<div class="buttons has-addons is-right"> <div class="buttons has-addons is-right">

View File

@ -16,7 +16,6 @@ import { StorageService } from '../../../core/services/storage.service';
export class PollResultsCompactComponent implements OnInit { export class PollResultsCompactComponent implements OnInit {
@Input() public poll: Poll; @Input() public poll: Poll;
public answerEnum = Answer; public answerEnum = Answer;
constructor(private modalService: ModalService, private storageService: StorageService) {} constructor(private modalService: ModalService, private storageService: StorageService) {}
ngOnInit(): void { ngOnInit(): void {
@ -31,4 +30,23 @@ export class PollResultsCompactComponent implements OnInit {
toggleAnswer(choice_id: number, value: string) { toggleAnswer(choice_id: number, value: string) {
this.storageService.toggleAnswer(choice_id, value); this.storageService.toggleAnswer(choice_id, value);
} }
showAsDate(date_string: string) {
return new Date(date_string);
}
toggleAllOfChoice(groupe: any) {
console.log('groupe', groupe);
if (!groupe.subSetToYes) {
this.storageService.setAllSubchoicesTo(groupe, 'yes');
groupe.subSetToYes = true;
} else {
this.storageService.setAllSubchoicesTo(groupe, '');
groupe.subSetToYes = false;
}
// savoir si on a déjà tout mis en "yes"
// si oui, on enlève toutes les réponses
// autrement on met tout à "yes"
}
} }

View File

@ -8,7 +8,7 @@
<!-- {{choice.id}}--> <!-- {{choice.id}}-->
<span class="label" *ngIf="poll.kind == 'text'">{{ choice.name }} </span> <span class="label" *ngIf="poll.kind == 'text'">{{ choice.name }} </span>
<span class="label" *ngIf="poll.kind == 'date'"> <span class="label" *ngIf="poll.kind == 'date'">
{{ choice.name | date: 'short':'Europe/Paris':'fr_FR' }} {{ make_date(choice.name) | date: 'fullDate':'Europe/Paris':'fr_FR' }}
</span> </span>
</th> </th>
</tr> </tr>

View File

@ -10,6 +10,11 @@
background: #ffd7d7; background: #ffd7d7;
} }
table {
overflow: scroll;
max-width: 90vw !important;
display: block;
}
table { table {
th, th,
th * { th * {

View File

@ -1,6 +1,5 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { Answer } from '../../../core/enums/answer.enum';
import { Poll } from '../../../core/models/poll.model'; import { Poll } from '../../../core/models/poll.model';
import { PollService } from '../../../core/services/poll.service'; import { PollService } from '../../../core/services/poll.service';
@ -24,4 +23,10 @@ export class PollResultsDetailedComponent {
} }
return null; return null;
} }
make_date(name: string) {
name = name.substr(0, 24);
console.log('name.length', name.length, name);
return new Date(name);
}
} }

View File

@ -1,5 +1,5 @@
<button <button
class="button is-white" class="choice-button is-white"
[ngClass]="{ 'is-primary': storageService.choiceHasAnswerOfValue(choice.id, answerEnum[answerKind]) }" [ngClass]="{ 'is-primary': storageService.choiceHasAnswerOfValue(choice.id, answerEnum[answerKind]) }"
(click)="storageService.toggleAnswer(choice.id, answerEnum[answerKind])" (click)="storageService.toggleAnswer(choice.id, answerEnum[answerKind])"
*ngIf="poll.allowed_answers.indexOf(answerEnum[answerKind]) !== -1" *ngIf="poll.allowed_answers.indexOf(answerEnum[answerKind]) !== -1"

View File

@ -0,0 +1,12 @@
.choice-button {
padding: 1.5em;
border-radius: 10em;
border: solid 3px #ccc;
height: 5em;
width: 5em;
display: inline-block;
&:focus,
&:active {
border-color: #6c99ff;
}
}

View File

@ -0,0 +1,48 @@
export const backendApiUrlsInDev = {
local: 'http://tktest.lan/api/v1',
remote: 'http://tktest.lan/api/v1',
// remote: 'https://framadate-api.cipherbliss.com/api/v1',
};
export const apiV1 = {
baseHref: 'http://tktest.lan/api/v1',
// baseHref: 'https://framadate-api.cipherbliss.com/api/v1',
api_new_poll: '/poll/',
api_get_poll: '/poll/{id}',
api_new_vote_stack: '/poll/{id}/answer',
'api_test-mail-poll': '/api/v1/poll/mail/test-mail-poll/{emailChoice}',
'app.swagger': '/api/doc.json',
};
export const endpoints = {
versionToUse: 'apiV1',
version: {
apiV1,
},
baseHref: backendApiUrlsInDev.local,
endpoints: {
polls: {
name: '/poll',
choices: {
name: '/choices',
},
comments: {
name: '/comments',
},
slugs: {
name: '/slugs',
},
answers: {
name: '/answers',
},
},
users: {
name: '/users',
polls: {
name: '/polls',
sendEmail: {
name: '/send-email',
},
},
},
},
};

View File

@ -17,7 +17,6 @@ export const environment = {
showDemoWarning: true, showDemoWarning: true,
autofill: false, autofill: false,
autoSendNewPoll: false, autoSendNewPoll: false,
interval_days_default: 7,
appTitle: 'FramaDate Funky', appTitle: 'FramaDate Funky',
appVersion: '2.1.0', appVersion: '2.1.0',
appLogo: 'assets/img/logo.png', appLogo: 'assets/img/logo.png',
@ -54,6 +53,7 @@ export const environment = {
}, },
}, },
}, },
interval_days_default: 7,
poll: { poll: {
defaultConfig: { defaultConfig: {
maxCountOfAnswers: 150, maxCountOfAnswers: 150,

View File

@ -2,77 +2,26 @@
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`. // The list of file replacements can be found in `angular.json`.
const backendApiUrlsInDev = { import { apiV1, endpoints } from './endpoints';
local: 'http://tktest.lan/api/v1', import { poll_conf } from './poll_conf';
remote: 'http://tktest.lan/api/v1',
// remote: 'https://framadate-api.cipherbliss.com/api/v1', endpoints.baseHref = apiV1.baseHref;
};
const apiV1 = {
baseHref: 'http://tktest.lan/api/v1',
// baseHref: 'https://framadate-api.cipherbliss.com/api/v1',
api_new_poll: '/poll/',
api_get_poll: '/poll/{id}',
api_new_vote_stack: '/poll/{id}/answer',
'api_test-mail-poll': '/api/v1/poll/mail/test-mail-poll/{emailChoice}',
'app.swagger': '/api/doc.json',
};
export const environment = { export const environment = {
frontDomain: 'http://tktest.lan', frontDomain: 'http://127.0.0.1:4200',
production: false, production: false,
display_routes: false, display_routes: true,
autofill: true, autofill: true,
showDemoWarning: false, showDemoWarning: false,
autoSendNewPoll: false, autoSendNewPoll: false,
interval_days_default: 7, interval_days_default: 7,
appTitle: 'FramaDate Funky', appTitle: 'funky',
appVersion: '2.1.0', appVersion: '0.6.0',
appLogo: 'assets/img/logo.png', appLogo: 'assets/img/logo.png',
api: { api: endpoints,
versionToUse: 'apiV1', poll: poll_conf,
version: {
apiV1,
},
baseHref: backendApiUrlsInDev.local,
endpoints: {
polls: {
name: '/poll',
choices: {
name: '/choices',
},
comments: {
name: '/comments',
},
slugs: {
name: '/slugs',
},
answers: {
name: '/answers',
},
},
users: {
name: '/users',
polls: {
name: '/polls',
sendEmail: {
name: '/send-email',
},
},
},
},
},
poll: {
defaultConfig: {
maxCountOfAnswers: 150,
expiresDaysDelay: 60,
expiracyAfterLastModificationInDays: 180,
whoCanChangeAnswers: 'everybody',
visibility: 'link_only',
voteChoices: 'only_yes',
},
},
localStorage: { localStorage: {
key: 'FramaSondage', key: 'FramaDateFunky',
}, },
}; };
@ -83,4 +32,5 @@ export const environment = {
* This import should be commented out in production mode because it will have a negative impact * This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown. * on performance if an error is thrown.
*/ */
import 'zone.js/dist/zone-error'; // Included with Angular CLI. import 'zone.js/dist/zone-error';
// Included with Angular CLI.

View File

@ -0,0 +1,10 @@
export const poll_conf = {
defaultConfig: {
maxCountOfAnswers: 150,
expiresDaysDelay: 60,
expiracyAfterLastModificationInDays: 180,
whoCanChangeAnswers: 'everybody',
visibility: 'link_only',
voteChoices: 'only_yes',
},
};

View File

@ -15,3 +15,7 @@ $input-shadow: none;
.notification { .notification {
margin: 1em 0; margin: 1em 0;
} }
.select {
display: block !important;
width: 80%;
}

View File

@ -133,7 +133,6 @@ mat-checkbox {
.cdk-drag { .cdk-drag {
cursor: pointer; cursor: pointer;
//border-left: 3px white solid;
&:hover { &:hover {
background: #fefefe; background: #fefefe;
} }
@ -208,7 +207,7 @@ mat-checkbox {
} }
.ng-pristine, .ng-pristine,
.ng-dirty { .ng-dirty {
border-left: $white 3px solid; //border-left: #ccc 3px solid;
padding-left: 1em; padding-left: 1em;
} }
.ng-touched.ng-invalid { .ng-touched.ng-invalid {

View File

@ -6,7 +6,7 @@
width: 45%; width: 45%;
} }
.date-choice > input:first-of-type { .date-choice > input:first-of-type {
width: 80%; width: 75%;
} }
.date-choice .btn--primary, .date-choice .btn--primary,
.several-times { .several-times {
@ -15,7 +15,7 @@
} }
.time-choice { .time-choice {
input { input {
width: 70%; width: 80%;
} }
} }
} }