:gears: refacto date and poll utilities functions in a separate class

This commit is contained in:
Baptiste Lemoine 2020-02-05 11:13:36 +01:00
parent ab23b9b256
commit c5b5276400
6 changed files with 168 additions and 154 deletions

View File

@ -0,0 +1,59 @@
export class DateUtilities {
/**
* add some days to a date, to compute intervals
* @param days
* @param date
*/
addDaysToDate(days: number, date: Date) {
date = new Date(date.valueOf());
date.setDate(date.getDate() + days);
return date;
};
/**
*
* @param d1
* @param d2
* @param interval
*/
getDatesInRange(d1: Date, d2: Date, interval: number) {
d1 = new Date(d1);
d2 = new Date(d2);
const dates = [];
while (+d1 < +d2) {
dates.push({
literal: this.formateDate(d1),
date_object: d1
});
d1.setDate(d1.getDate() + interval)
}
return dates.slice(0);
}
/**
* get the number of days between two dates
* @param d1
* @param d2
*/
dayDiff(d1: Date, d2: Date): Number {
return Number(((d2.getTime()) - (d1.getTime()) / 31536000000));
}
/**
* format a date object to the date format used by the inputs of type date
* YYYY-MM-DD
* @param date
*/
formateDate(date) {
return [
date.getFullYear(),
this.getDoubleDigits(date.getMonth() + 1),
this.getDoubleDigits(date.getDate()),
].join('-')
}
getDoubleDigits(str) {
return ("00" + str).slice(-2);
}
}

View File

@ -0,0 +1,61 @@
import {HttpHeaders} from "@angular/common/http";
import {PollConfig} from "./PollConfig";
export class PollUtilities {
// utils functions
/**
* generate unique id to have a default url for future poll
*/
makeUuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
/**
* make a uniq slug for the current poll creation
* @param str
*/
makeSlug(config: PollConfig) {
let str = '';
str = config.creationDate.getFullYear() + '_' + (config.creationDate.getMonth() + 1) + '_' + config.creationDate.getDate() + '_' + config.myName + '_' + config.title;
str = str.replace(/^\s+|\s+$/g, ''); // trim
str = str.toLowerCase();
// remove accents, swap ñ for n, etc
var from = "àáäâèéëêìíïîòóöôùúüûñç·/_,:;";
var to = "aaaaeeeeiiiioooouuuunc------";
for (var 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;
}
/**
* prepare headers like the charset and json type for any call to the backend
* @param bodyContent
*/
makeHeaders(bodyContent?: any) {
const headerDict = {
'Charset': 'UTF-8',
'Content-Type': 'application/json',
'Accept': 'application/json',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Origin': '*'
};
const requestOptions = {
headers: new HttpHeaders(headerDict),
body: bodyContent
};
return requestOptions;
}
}

View File

@ -4,6 +4,7 @@ import {BaseComponent} from '../base-page/base.component';
import {DOCUMENT} from '@angular/common';
import {MessageService} from "primeng/api";
import {defaultTimeOfDay} from "../../config/defaultConfigs";
import {DateUtilities} from "../../config/DateUtilities";
@Component({
selector: 'framadate-dates',
@ -20,6 +21,7 @@ export class DatesComponent extends BaseComponent implements OnInit {
constructor(public config: ConfigService,
private cd: ChangeDetectorRef,
private messageService: MessageService,
private dateUtilities: DateUtilities,
@Inject(DOCUMENT) private document: any
) {
super(config);
@ -28,7 +30,7 @@ export class DatesComponent extends BaseComponent implements OnInit {
countDays() {
// compute the number of days in the date interval
if (this.endDateInterval && this.startDateInterval) {
this.intervalDays = (this.dayDiff(this.endDateInterval, this.startDateInterval)).toFixed(0)
this.intervalDays = (this.dateUtilities.dayDiff(this.endDateInterval, this.startDateInterval)).toFixed(0)
}
}
@ -39,7 +41,7 @@ export class DatesComponent extends BaseComponent implements OnInit {
let dateCurrent = new Date();
const dateJson = dateCurrent.toISOString();
this.startDateInterval = dateJson.substring(0, 10);
this.endDateInterval = this.addDaysToDate(this.intervalDaysDefault, dateCurrent).toISOString().substring(0, 10);
this.endDateInterval = this.dateUtilities.addDaysToDate(this.intervalDaysDefault, dateCurrent).toISOString().substring(0, 10);
}
addDate() {
@ -77,16 +79,6 @@ export class DatesComponent extends BaseComponent implements OnInit {
this.config.timeList = defaultTimeOfDay;
}
/**
* add some days to a date, to compute intervals
* @param days
* @param date
*/
addDaysToDate(days: number, date: Date) {
date = new Date(date.valueOf());
date.setDate(date.getDate() + days);
return date;
};
/**
* add a time period to a specific date choice,
@ -123,7 +115,7 @@ export class DatesComponent extends BaseComponent implements OnInit {
* add all the dates between the start and end dates in the interval section
*/
addIntervalOfDates() {
let newIntervalArray = this.getDatesInRange(this.startDateInterval, this.endDateInterval, 1);
let newIntervalArray = this.dateUtilities.getDatesInRange(this.startDateInterval, this.endDateInterval, 1);
const converted = [];
newIntervalArray.forEach(element => {
@ -144,49 +136,5 @@ export class DatesComponent extends BaseComponent implements OnInit {
}
/**
*
* @param d1
* @param d2
* @param interval
*/
getDatesInRange(d1: Date, d2: Date, interval: number) {
d1 = new Date(d1);
d2 = new Date(d2);
const dates = [];
while (+d1 < +d2) {
dates.push({
literal: this.formateDate(d1),
date_object: d1
});
d1.setDate(d1.getDate() + interval)
}
return dates.slice(0);
}
/**
* get the number of days between two dates
* @param d1
* @param d2
*/
dayDiff(d1: Date, d2: Date): Number {
return Number(((d2.getTime()) - (d1.getTime()) / 31536000000));
}
/**
* format a date object to the date format used by the inputs of type date
* YYYY-MM-DD
* @param date
*/
formateDate(date) {
return [
date.getFullYear(),
this.getDoubleDigits(date.getMonth() + 1),
this.getDoubleDigits(date.getDate()),
].join('-')
}
getDoubleDigits(str) {
return ("00" + str).slice(-2);
}
}

View File

@ -9,19 +9,18 @@
<div
class='loaded-poll'
*ngIf='!config.loading && config.currentPoll' >
<div id='table' >
<!-- <framadate-voting-navigation ></framadate-voting-navigation >-->
<framadate-voting-summary ></framadate-voting-summary >
</div >
<div id='poll_comments' >
<framadate-comments-list ></framadate-comments-list >
</div >
<div id='choices' >
<framadate-choices-list ></framadate-choices-list >
</div >
<div id='table' >
<!-- <framadate-voting-navigation ></framadate-voting-navigation >-->
<framadate-voting-summary ></framadate-voting-summary >
</div >
<div id='poll_comments' >
<framadate-comments-list ></framadate-comments-list >
</div >
<div id='graph' >
<!--<framadate-voting-graph ></framadate-voting-graph >-->
</div >

View File

@ -2,6 +2,7 @@ import {Component, OnInit} from '@angular/core';
import {BaseComponent} from '../base-page/base.component';
import {ConfigService} from '../../services/config.service';
import {environment} from "../../../environments/environment";
import {PollUtilities} from "../../config/PollUtilities";
@Component({
selector: 'framadate-visibility',
@ -13,12 +14,13 @@ export class VisibilityComponent extends BaseComponent implements OnInit {
baseUrl = environment.baseApiHref;
environment = environment;
constructor(public config: ConfigService) {
constructor(public config: ConfigService,
public utils: PollUtilities) {
super(config);
}
ngOnInit() {
this.config.customUrl = this.config.makeSlug();
this.config.customUrl = this.utils.makeSlug(this.config);
this.config.expirationDate = (this.config.addDaysToDate(this.config.expiracyDateDefaultInDays, new Date())).toISOString().substring(0, 10);
}

View File

@ -1,6 +1,6 @@
import {Injectable} from '@angular/core';
import {PollConfig} from '../config/PollConfig';
import {HttpClient, HttpHeaders} from "@angular/common/http";
import {HttpClient} from "@angular/common/http";
import {environment} from "../../environments/environment";
import {ConfirmationService, MessageService} from 'primeng/api';
import {Router} from "@angular/router";
@ -8,6 +8,7 @@ import {mockMyPolls} from "../config/mocks/mockmypolls";
import {defaultAnswers, defaultDates, defaultTimeOfDay} from "../config/defaultConfigs";
import {mockPoll3} from "../config/mocks/mock-poll3";
import {mockSuccessVote} from "../config/mocks/mock-success-vote";
import {PollUtilities} from "../config/PollUtilities";
/**
* le service transverse à chaque page qui permet de syncroniser la configuration de sondage souhaitée
@ -24,10 +25,20 @@ export class ConfigService extends PollConfig {
constructor(private http: HttpClient,
private messageService: MessageService,
private router: Router,
private utils: PollUtilities,
private confirmationService: ConfirmationService,
) {
super();
// fill in mock values if we are not in production environment
this.fillValuesOnDevEnv();
}
set(key, val) {
this[key] = val;
}
// fill in mock values if we are not in production environment
fillValuesOnDevEnv() {
if (!environment.production) {
console.info(' ######### framadate ######### we are not in production env, filling with mock values');
this.currentPoll = mockPoll3;
@ -38,50 +49,6 @@ export class ConfigService extends PollConfig {
}
}
set(key, val) {
this[key] = val;
}
clear() {
this.messageService.clear();
}
// utils functions
/**
* generate unique id to have a default url for future poll
*/
makeUuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
/**
* make a uniq slug for the current poll creation
* @param str
*/
makeSlug(str?: string) {
if (!str) {
str = this.creationDate.getFullYear() + '_' + (this.creationDate.getMonth() + 1) + '_' + this.creationDate.getDate() + '_' + this.myName + '_' + this.title;
}
str = str.replace(/^\s+|\s+$/g, ''); // trim
str = str.toLowerCase();
// remove accents, swap ñ for n, etc
var from = "àáäâèéëêìíïîòóöôùúüûñç·/_,:;";
var to = "aaaaeeeeiiiioooouuuunc------";
for (var 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;
}
/**
* add some days to a date, to compute intervals
* @param days
@ -128,39 +95,18 @@ export class ConfigService extends PollConfig {
return jsonConfig
}
/**
* prepare headers like the charset and json type for any call to the backend
* @param bodyContent
*/
makeHeaders(bodyContent?: any) {
const headerDict = {
'Charset': 'UTF-8',
'Content-Type': 'application/json',
'Accept': 'application/json',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Origin': '*'
};
const requestOptions = {
headers: new HttpHeaders(headerDict),
body: bodyContent
};
return requestOptions;
}
checkIfSlugIsUniqueInDatabase(slug: string = '') {
this.customUrlIsUnique = null;
if (!slug) {
slug = this.makeSlug();
slug = this.utils.makeSlug(this);
}
this.loading = true;
// TODO
this.todo('check slug is unique');
this.http.get(`${this.baseHref}/check-slug-is-uniq/${slug}`,
this.makeHeaders({slug: this.customUrl}),
this.utils.makeHeaders({slug: this.customUrl}),
)
.subscribe((res: any) => {
@ -177,7 +123,6 @@ export class ConfigService extends PollConfig {
*/
findPollsByEmail(email: string) {
this.findLocalStorageData();
// If no key is found in the localstorage, ask the backend to send an email to the user
@ -187,7 +132,7 @@ export class ConfigService extends PollConfig {
this.todo('send email for real : TODO');
this.loading = true;
this.http.get(`${this.baseHref}/send-polls-to-user/${this.myEmail}`,
this.makeHeaders(),
this.utils.makeHeaders(),
)
.subscribe(res => {
// message: 'Trouvé! Allez voir votre boite email',
@ -232,7 +177,7 @@ export class ConfigService extends PollConfig {
getPollByURL(url: string) {
this.todo();
return this.http.get(`${this.baseHref}/poll/slug/${url}`, this.makeHeaders())
return this.http.get(`${this.baseHref}/poll/slug/${url}`, this.utils.makeHeaders())
}
/**
@ -244,7 +189,7 @@ export class ConfigService extends PollConfig {
return this.http
.get(`${this.baseHref}/poll/${id}`,
this.makeHeaders({body: password}))
this.utils.makeHeaders({body: password}))
}
fetchPollFromRoute(event) {
@ -259,7 +204,7 @@ export class ConfigService extends PollConfig {
getMyPolls(ownerEmail: string) {
this.http
.get(`${this.baseHref}/my-polls`,
this.makeHeaders({ownerEmail: ownerEmail})
this.utils.makeHeaders({ownerEmail: ownerEmail})
)
.subscribe(
(res: any) => {
@ -313,7 +258,7 @@ export class ConfigService extends PollConfig {
this.myEmail = voteStack.email;
this.voteStackId = voteStack.id;
this.myVoteStack = voteStack;
let keys = Object.keys(voteStack.votes)
let keys = Object.keys(voteStack.votes);
console.log('voteStack', voteStack);
this.resetCurrentChoicesAnswers();
keys.forEach((id: any) => {
@ -326,7 +271,7 @@ export class ConfigService extends PollConfig {
let foundChoiceToModify = this.currentPoll.choices.find(choicesItem => {
return voteItem.choice_id == choicesItem.id
});
console.log('foundChoiceToModify', foundChoiceToModify)
console.log('foundChoiceToModify', foundChoiceToModify);
if (foundChoiceToModify) {
foundChoiceToModify.answer = voteItem.value;
}
@ -344,7 +289,7 @@ export class ConfigService extends PollConfig {
console.log('config', config);
return this.http.post(`${this.baseHref}/poll`,
config,
this.makeHeaders())
this.utils.makeHeaders())
.subscribe((res: any) => {
// redirect to the page to administrate the new poll
this.messageService.add({severity: 'success', summary: 'Sondage Créé',});
@ -406,7 +351,7 @@ export class ConfigService extends PollConfig {
this.http.post(
`${this.baseHref}/poll/${this.pollId}/vote`,
voteStack,
this.makeHeaders())
this.utils.makeHeaders())
.subscribe((res: any) => {
this.handleVoteAdded(res);
@ -439,7 +384,7 @@ export class ConfigService extends PollConfig {
this.http.patch(
`${this.baseHref}/vote-stack/${voteStack.id}/token/${this.owner_modifier_token}`,
voteStack,
this.makeHeaders())
this.utils.makeHeaders())
.subscribe((res: any) => {
this.messageService.add({severity: 'success', summary: 'Vote mis à jour'});
this.updateCurrentPollFromResponse(res);
@ -468,7 +413,7 @@ export class ConfigService extends PollConfig {
this.http.post(
`${this.baseHref}/poll/${this.pollId}/comment`,
comment,
this.makeHeaders())
this.utils.makeHeaders())
.subscribe((res: any) => {
this.messageService.add({
severity: 'success',
@ -499,7 +444,7 @@ export class ConfigService extends PollConfig {
accept: () => {
this.http.delete(
`${this.baseHref}/poll/${this.pollId}/comments`,
this.makeHeaders())
this.utils.makeHeaders())
.subscribe((res: any) => {
this.messageService.add({
severity: 'success',
@ -522,7 +467,7 @@ export class ConfigService extends PollConfig {
accept: () => {
this.http.delete(
`${this.baseHref}/poll/${this.pollId}/votes`,
this.makeHeaders())
this.utils.makeHeaders())
.subscribe((res: any) => {
this.messageService.add({
severity: 'success',
@ -553,7 +498,7 @@ export class ConfigService extends PollConfig {
accept: () => {
this.http.delete(
`${this.baseHref}/poll/${this.pollId}`,
this.makeHeaders())
this.utils.makeHeaders())
.subscribe((res: any) => {
this.messageService.add({
severity: 'success',
@ -580,7 +525,7 @@ export class ConfigService extends PollConfig {
this.http.put(
`${this.baseHref}/poll/${this.pollId}`,
voteStack,
this.makeHeaders()
this.utils.makeHeaders()
)
.subscribe((res: any) => {
this.messageService.add({
@ -644,7 +589,7 @@ export class ConfigService extends PollConfig {
rows = [headers, listOfChoices, rows, headersComments, comments];
let convertedCsv = rows.map(elem => {
console.log('elem', elem)
console.log('elem', elem);
return elem.map(item => {
console.log('item', item);
if (typeof item === typeof Array) {
@ -658,11 +603,11 @@ export class ConfigService extends PollConfig {
let csvContent = "data:text/csv;charset=utf-8,"
+ convertedCsv;
console.log('csvContent', csvContent)
console.log('csvContent', csvContent);
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
let exportFileName = (this.urlPublic ? this.urlPublic : this.makeSlug()) + "_export_" + new Date() + ".csv";
let exportFileName = (this.urlPublic ? this.urlPublic : this.utils.makeSlug(this)) + "_export_" + new Date() + ".csv";
link.setAttribute("download", exportFileName);
document.body.appendChild(link); // Required for FF
link.click(); // This will download the data file named "my_data.csv".