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: BehaviorSubject = new BehaviorSubject(undefined); public readonly poll: Observable = 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 { 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) => { console.log('getAllAvailablePolls res', res); }); } catch (e) { console.error('getAllAvailablePolls e', e); } } public async loadPollBycustom_url(custom_url: string): Promise { 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 { 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 { // .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 { 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 { await this.apiService.createComment(this._poll.getValue().custom_url, comment); this.toastService.display('Votre commentaire a été enregistré.'); } public async deleteComments(): Promise { 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 []; } }