241 lines
7.8 KiB
TypeScript
241 lines
7.8 KiB
TypeScript
import { Injectable } from '@angular/core';
|
||
import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router';
|
||
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
|
||
|
||
import { Answer } from '../enums/answer.enum';
|
||
import { Choice } from '../models/choice.model';
|
||
import { Poll } from '../models/poll.model';
|
||
import { Owner } from '../models/owner.model';
|
||
import { ApiService } from './api.service';
|
||
import { ToastService } from './toast.service';
|
||
import { UserService } from './user.service';
|
||
import { UuidService } from './uuid.service';
|
||
import { HttpClient } from '@angular/common/http';
|
||
import { environment } from '../../../environments/environment';
|
||
import { StorageService } from './storage.service';
|
||
import { Title } from '@angular/platform-browser';
|
||
import { TimeSlices } from '../../../../mocks/old-stuff/config/defaultConfigs';
|
||
|
||
@Injectable({
|
||
providedIn: 'root',
|
||
})
|
||
export class PollService implements Resolve<Poll> {
|
||
_poll: BehaviorSubject<Poll | undefined> = new BehaviorSubject<Poll | undefined>(undefined);
|
||
public readonly poll: Observable<Poll | undefined> = this._poll.asObservable();
|
||
|
||
constructor(
|
||
private http: HttpClient,
|
||
private router: Router,
|
||
private apiService: ApiService,
|
||
private storageService: StorageService,
|
||
private userService: UserService,
|
||
private uuidService: UuidService,
|
||
private titleService: Title,
|
||
private toastService: ToastService
|
||
) {}
|
||
|
||
/**
|
||
* auto fetch a poll when route is looking for one in the administration pattern
|
||
* @param route
|
||
* @param state
|
||
*/
|
||
public async resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<Poll> {
|
||
const segments: string[] = state.url.split('/');
|
||
const wantedcustom_url: string = segments.includes('poll') ? segments[segments.indexOf('poll') + 1] : '';
|
||
|
||
// FIXME should be handled by routing
|
||
if (!wantedcustom_url && state.url.includes('administration')) {
|
||
// creation of new poll
|
||
const poll = new Poll(this.userService.getCurrentUser(), this.uuidService.getUUID(), '');
|
||
this._poll.next(poll);
|
||
this.router.navigate(['poll/' + poll.custom_url + '/administration']);
|
||
}
|
||
if (
|
||
!this._poll.getValue() ||
|
||
!this._poll.getValue().custom_url ||
|
||
this._poll.getValue().custom_url !== wantedcustom_url
|
||
) {
|
||
await this.loadPollBycustom_url(wantedcustom_url);
|
||
}
|
||
if (this._poll.getValue()) {
|
||
return this._poll.getValue();
|
||
} else {
|
||
this.router.navigate(['page-not-found']);
|
||
return;
|
||
}
|
||
}
|
||
|
||
getAllAvailablePolls() {
|
||
const baseHref = environment.api.version.apiV1.baseHref;
|
||
console.log('getAllAvailablePolls baseHref', baseHref);
|
||
const headers = ApiService.makeHeaders();
|
||
console.log('getAllAvailablePolls headers', headers);
|
||
try {
|
||
this.http.get(`${baseHref}/poll`, headers).subscribe((res: Observable<any>) => {
|
||
console.log('getAllAvailablePolls res', res);
|
||
});
|
||
} catch (e) {
|
||
console.error('getAllAvailablePolls e', e);
|
||
}
|
||
}
|
||
|
||
public async loadPollBycustom_url(custom_url: string): Promise<void> {
|
||
console.log('custom_url', custom_url);
|
||
if (custom_url) {
|
||
const poll: Poll | undefined = await this.apiService.getPollByCustomUrl(custom_url);
|
||
|
||
console.log({ loadPollBycustom_urlResponse: poll });
|
||
if (poll) {
|
||
this.updateCurrentPoll(poll);
|
||
this.titleService.setTitle(`☑️ ${poll.title} - ${environment.appTitle}`);
|
||
} else {
|
||
this.toastService.display(`sondage ${custom_url} non trouvé`);
|
||
}
|
||
}
|
||
}
|
||
public async loadPollBycustom_urlWithPasswordHash(custom_url: string, hash: string): Promise<void> {
|
||
console.log('custom_url', custom_url);
|
||
if (custom_url) {
|
||
const poll: Poll | undefined = await this.apiService.getPollByCustomUrlWithHash(custom_url, hash);
|
||
console.log({ loadPollBycustom_urlResponse: poll });
|
||
this.updateCurrentPoll(poll);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* update poll and parse its fields
|
||
* @param poll
|
||
*/
|
||
public updateCurrentPoll(poll: Poll): void {
|
||
if (poll.kind == 'date') {
|
||
poll.choices = this.parseDateChoices(poll.choices);
|
||
}
|
||
this.storageService.setChoicesForVoteStack(poll.choices);
|
||
|
||
this.toastService.display('sondage bien mis à jour', 'success');
|
||
|
||
console.log('poll', poll);
|
||
this._poll.next(poll);
|
||
}
|
||
|
||
/**
|
||
* make a uniq custom_url for the current poll creation
|
||
* @param config
|
||
*/
|
||
makecustom_url(config: Poll): string {
|
||
console.log('config', config);
|
||
let str = '';
|
||
str =
|
||
config.configuration.dateCreated.getFullYear() +
|
||
'_' +
|
||
(config.configuration.dateCreated.getMonth() + 1) +
|
||
'_' +
|
||
config.configuration.dateCreated.getDate() +
|
||
'_' +
|
||
config.owner.pseudo +
|
||
'_' +
|
||
config.title;
|
||
str = str.replace(/^\s+|\s+$/g, ''); // trim
|
||
str = str.toLowerCase();
|
||
|
||
// remove accents, swap ñ for n, etc
|
||
const from = 'àáäâèéëêìíïîòóöôùúüûñç·/_,:;';
|
||
const to = 'aaaaeeeeiiiioooouuuunc------';
|
||
for (let i = 0, l = from.length; i < l; i++) {
|
||
str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
|
||
}
|
||
|
||
str = str
|
||
.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
|
||
.replace(/\s+/g, '-') // collapse whitespace and replace by -
|
||
.replace(/-+/g, '-'); // collapse dashes
|
||
|
||
return str + '-' + this.uuidService.getUUID();
|
||
}
|
||
|
||
public async saveCurrentPoll(): Promise<Subscription> {
|
||
// .then((resp) => {
|
||
// console.log('resp', resp);
|
||
// if (pollUrl) {
|
||
// console.log('pollUrl', pollUrl);
|
||
// this.toastService.display('Le sondage a été enregistré.');
|
||
// // TODO: redirect to view
|
||
// } else {
|
||
// this.toastService.display('Le sondage n’a été correctement enregistré, veuillez ré-essayer.');
|
||
// }
|
||
// })
|
||
// .catch((err) => {
|
||
// console.error('err', err);
|
||
// });
|
||
return await this.apiService.createPoll(this._poll.getValue());
|
||
}
|
||
|
||
public saveParticipation(choice: Choice, user: Owner, response: Answer): void {
|
||
const currentPoll = this._poll.getValue();
|
||
currentPoll.choices.find((c) => c.name === choice.name)?.updateParticipation(user, response);
|
||
this.updateCurrentPoll(currentPoll);
|
||
this.apiService.createParticipation(currentPoll.custom_url, choice.name, user.pseudo, response);
|
||
this.toastService.display('Votre participation au sondage a été enregistrée.');
|
||
}
|
||
|
||
public async deleteAllAnswers(): Promise<void> {
|
||
await this.apiService.deletePollAnswers(this._poll.getValue().custom_url);
|
||
this.toastService.display('Les participations des votants à ce sondage ont été supprimées.');
|
||
}
|
||
|
||
public async addComment(comment: string): Promise<void> {
|
||
await this.apiService.createComment(this._poll.getValue().custom_url, comment);
|
||
this.toastService.display('Votre commentaire a été enregistré.');
|
||
}
|
||
|
||
public async deleteComments(): Promise<void> {
|
||
await this.apiService.deletePollComments(this._poll.getValue().custom_url);
|
||
this.toastService.display('Les commentaires de ce sondage ont été supprimés.');
|
||
}
|
||
|
||
/**
|
||
* @description convert to API version 1 data transition object
|
||
* @param form
|
||
*/
|
||
newPollFromForm(form: any): Poll {
|
||
const newOwner = this.storageService.vote_stack.owner;
|
||
|
||
const newpoll = new Poll(newOwner, form.value.custom_url, form.value.title);
|
||
|
||
const pollKeys = Object.keys(newpoll);
|
||
const formFields = Object.keys(form.value);
|
||
|
||
for (const fieldOfForm of formFields) {
|
||
if (pollKeys.indexOf(fieldOfForm) !== -1) {
|
||
newpoll[fieldOfForm] = form.value[fieldOfForm];
|
||
}
|
||
}
|
||
newpoll.dateChoices = this.storageService.dateList;
|
||
newpoll.timeSlices = this.storageService.timeSlices;
|
||
|
||
console.log('newpoll', newpoll);
|
||
return newpoll;
|
||
}
|
||
|
||
public parseDateChoices(choices: Choice[]) {
|
||
const SEPARATOR_DATE_TIME_SLICE = ' >>> ';
|
||
const parsedChoices = [];
|
||
|
||
for (const c of choices) {
|
||
const time_list = [];
|
||
const choice = { name: c.name };
|
||
if (c.name.includes(SEPARATOR_DATE_TIME_SLICE)) {
|
||
const date_string = '';
|
||
const time_slice = '';
|
||
choice.name = time_slice;
|
||
}
|
||
parsedChoices.push({
|
||
date_string: choice,
|
||
choices: c,
|
||
});
|
||
}
|
||
console.log('parsedChoices', parsedChoices);
|
||
return [];
|
||
}
|
||
}
|