funky-framadate-front/src/app/core/services/poll.service.ts

259 lines
8.4 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 { DateUtilitiesService } from './date.utilities.service';
@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 dateUtils: DateUtilitiesService,
private titleService: Title,
private toastService: ToastService
) {
this._poll.next(new Poll(null, 'titre', 'custom-title'));
}
/**
* 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> {
console.log('resolve route,state', route, state);
const segments: string[] = state.url.split('/');
const wantedcustom_url: string = segments.includes('poll') ? segments[segments.indexOf('poll') + 1] : '';
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é`);
}
} else {
this.toastService.display(`sondage sans custom url : ${custom_url}`);
}
}
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 {
console.log('update poll with: ', poll);
if (!this.storageService.vote_stack.id || this.storageService.vote_stack.poll_custom_url !== poll.custom_url) {
console.log('set base choices', poll.choices);
// set the choices only the first time the poll loads
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 poll
*/
makecustom_url(poll: Poll): string {
console.log('config', poll);
let str = '';
const creation_date = new Date(poll.creation_date);
str =
creation_date.getFullYear() +
'_' +
(creation_date.getMonth() + 1) +
'_' +
creation_date.getDate() +
'_' +
poll.owner.pseudo +
'_' +
poll.title;
return this.convertTextToSlug(str) + '-' + this.uuidService.getUUID();
}
public convertTextToSlug(str: string) {
str = str.trim();
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;
}
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);
console.log('pollKeys, formFields', pollKeys, formFields);
newpoll.allowed_answers = ['yes'];
for (const pk of pollKeys) {
if (formFields.indexOf(pk) !== -1) {
const field = form.value[pk];
newpoll[pk] = field;
} else {
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.has_several_hours = form.value.hasSeveralHours;
newpoll.hasSeveralHours = form.value.hasSeveralHours;
newpoll.max_count_of_answers = form.value.allowComments;
newpoll.maxCountOfAnswers = form.value.maxCountOfAnswers;
newpoll.password = form.value.password;
newpoll.kind = form.value.kind;
newpoll.allow_comments = form.value.allowComments;
// merge choices from storage
newpoll.choices = Object.assign([], this.storageService.choices);
newpoll.dateChoices = Object.assign([], this.storageService.dateChoices);
newpoll.timeSlices = Object.assign([], this.storageService.timeSlices);
console.log('this.storageService.timeSlices', this.storageService.timeSlices, newpoll.timeSlices);
return newpoll;
}
public getAdministrationUrl(): string {
let url = '';
if (this._poll && this._poll.getValue) {
const polltemp = this._poll.getValue();
if (polltemp) {
url = `${environment.frontDomain}#/poll/admin/${polltemp.admin_key}`;
}
}
return url;
}
public getParticipationUrl(): string {
let url = '';
if (this._poll && this._poll.getValue) {
const polltemp = this._poll.getValue();
if (polltemp) {
url = `${environment.frontDomain}#/poll/${polltemp.custom_url}/consultation`;
}
}
// TODO handle pass access
return url;
}
}