scripts/ordre-du-jour/odj/src/app/app.component.ts

383 lines
11 KiB
TypeScript

import {Component, OnDestroy, OnInit} from '@angular/core';
import {CommonModule} from '@angular/common';
import {RouterOutlet} from '@angular/router';
import {FormsModule} from "@angular/forms";
interface Topic {
id: number, // numéro du sujet
title: string, // titre du sujet à aborder
notes: string, // titre du sujet à aborder
duration: number, // nombre de minutes du sujet
author: string,// auteur du sujet qui anime la discussion
startDate: Date, // date de début du sujet
endDate: Date,// date de fin du sujet
finished: boolean,// si le sujet est terminé
spentSeconds: number, // nombre de secondes passées au sujet
}
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, RouterOutlet, FormsModule],
templateUrl: './app.component.html',
styleUrl: './app.component.scss',
})
export class AppComponent implements OnInit, OnDestroy {
title = 'odj';
subjects: Array<Topic> = [];
currentSubjectId = 0;
startTime: string = "20:30";
// startTime: string = "17:00";
endTime: string = "22:00";
today: any = new Date();
// champs habituels pour le compte rendu:
scribe: string = 'tykayn';
private timekeeper: string = 'Chuck Norris';
private animator: string = 'Covid Copperfield';
presents: string = '- tykayn';
pasteLand: string = "* Présentation du suivi sur Nextcloud - 5min (tykayn)\n" +
"* Réduction de bus factor - 10min (tykayn)\n" +
"* Réunion avec Wikimedia France - 25min (tykayn)\n" +
"";
statsExplication: string = ''
hints: string = "";
Math:Math = Math
showDebug: boolean = true;
startDate: Date = new Date();
endDate: Date = new Date();
private topicChangeDate: Date = new Date();
updateTopicChangeDate(): void {
const currentTime = new Date();
const timeDifferenceInMilliseconds = this.topicChangeDate.getTime() - currentTime.getTime();
const timeDifferenceInSeconds = Math.abs(timeDifferenceInMilliseconds / 1000);
console.log(`Spent ${timeDifferenceInSeconds} seconds`);
this.subjects[this.currentSubjectId].spentSeconds += timeDifferenceInSeconds;
this.topicChangeDate = currentTime;
this.makeStatisticsOnTopicsSpentSeconds()
}
round(val: number) {
if (val < 60) {
return Math.round(val) + ' s'
}
return (Math.round(val / 60) * 60) + ' min'
}
parseTheListOfTopicsInPasteLand() {
let newTopics: any = []
let topics: any = this.pasteLand.split('*')
let accumulatedDuration: number = 0;
let ii = 0;
topics.forEach((topic: string) => {
let boom = topic.split('-')
if (boom[0]) {
let duration = this.findMinutesDurationInDescription(topic) | 0
accumulatedDuration += duration
newTopics.push({
id: ii,
title: boom[0],
duration: duration,
spentSeconds: 0,
author: this.findAuthorInDescription(topic),
notes: '',
finished: false,
startDate: this.getEndDateAfterDuration(accumulatedDuration, this.startDate),
endDate: this.getEndDateAfterDuration(duration + accumulatedDuration, this.startDate),
})
}
ii += 1;
})
this.subjects = newTopics
}
/**
* Creates a new Date object set to the specified time in the current time zone.
*
* @param {string} hour - A string representation of the hour, in 24-hour format.
* @param {string} [minute='00'] - A string representation of the minute (00-59).
* @returns {Date} A new Date object set to the specified time.
*/
makeDateFromHourToday(hourInput: string){
let [hour, minute] = hourInput.split(":");
let date = new Date();
if (!minute) {
return date;
}
date.setHours(parseInt(hour));
date.setMinutes(parseInt(minute));
console.log('hourInput', hourInput, date)
return date;
}
/**
* Computes the remaining time for a given topic, based on the current time and the start and end times of the topic.
*
* @param {Topic} topic - The topic for which to compute the remaining time.
*/
computeResteTopicMinutes(topic: Topic): number {
let currentSubjectDuration = topic.duration; // The duration of the current subject, in minutes
let currentSubjectStartTime = new Date(this.startTime); // The start time of the current subject
let currentSubjectEndTime = new Date(currentSubjectStartTime.getTime() + currentSubjectDuration * 60000); // The end time of the current subject
return currentSubjectEndTime.getTime() - new Date().getTime(); // The remaining time, in milliseconds
}
interval: any;
ngOnInit() {
this.parseTheListOfTopicsInPasteLand()
this.startDate = this.makeDateFromHourToday(this.startTime);
this.endDate = this.makeDateFromHourToday(this.endTime);
// let self = this;
// this.interval = setInterval(() => {
// self.updateTopicChangeDate()
// }, 5000)
}
ngOnDestroy(): void {
clearInterval(this.interval);
}
nextSubject() {
this.updateTopicChangeDate()
if (this.currentSubjectId < this.subjects.length - 1) {
this.currentSubjectId++
}
}
findMinutesDurationInDescription(topic: string): number {
let durationRegex = /-\s(\d+)\s?min/g;
let matches = durationRegex.exec(topic);
if (matches) {
return parseInt(matches[1]);
}
return 0;
}
private getEndDateAfterDuration(minutes: number, startDate: Date) {
return new Date(startDate.getTime() + minutes * 60000);
}
getStartDateAfterDuration(accumulatedDuration: string) {
return this.makeDateFromHourToday(accumulatedDuration)
}
isTopicRunning(topic: Topic) {
let now = new Date();
return now >= topic.startDate && now <= topic.endDate && !topic.finished;
}
countRemainingMinutes(topic: Topic) {
let now = new Date();
return Math.floor((topic.endDate.getTime() - now.getTime()) / 60000);
}
getPercentProgressTimeForTopic(topic: Topic) {
let now = new Date();
console.log('topic démarré', topic.startDate.getTime())
console.log('topic va se finir', topic.endDate.getTime(), topic.endDate.getTime() - topic.startDate.getTime())
return Math.floor((now.getTime() - topic.startDate.getTime()) / (topic.endDate.getTime() - topic.startDate.getTime()) * 100);
}
finishTopic(currentSubjectId: number) {
this.subjects[currentSubjectId].finished = true
}
/**
* only had one second to the current topic
*/
updateProgressEveryPeriod() {
this.subjects[this.currentSubjectId].spentSeconds += 1;
console.log('ajout au topic', this.currentSubjectId)
}
resteTopicMinutes(topic: Topic) {
return this.round(topic.spentSeconds / topic.duration * 60)
}
convertTextToHTMLLinks(text: string): string {
let urlRegex = /(https?:\/\/[^\s<]+[^<.,:;\"\'\]\s])(?!["\])\s])/g;
let matches = urlRegex.exec(text);
while (matches) {
let url = matches[1];
let linkText = url;
if (url.length > 30) {
linkText = url.substring(0, 30) + "...";
}
text = text.replace(url, `<a href="${url}">${linkText}</a>`);
matches = urlRegex.exec(text);
}
return text;
}
previousSubject() {
this.updateTopicChangeDate()
this.currentSubjectId < 1 ? this.currentSubjectId = 0 : this.currentSubjectId -= 1;
}
makeStatisticsOnTopicsSpentSeconds() {
let totalSeconds = 0;
for (const topic of this.subjects) {
totalSeconds += topic.spentSeconds;
}
let averageSeconds = totalSeconds / this.subjects.length;
let longestTopic = this.subjects[0];
let longestSeconds = longestTopic.spentSeconds;
for (const topic of this.subjects) {
if (topic.spentSeconds > longestSeconds) {
longestSeconds = topic.spentSeconds;
longestTopic = topic;
}
}
let shortestTopic = this.subjects[0];
let shortestSeconds = shortestTopic.spentSeconds;
for (const topic of this.subjects) {
if (topic.spentSeconds < shortestSeconds) {
shortestSeconds = topic.spentSeconds;
shortestTopic = topic;
}
}
this.statsExplication = `Temps passé: ${this.round(totalSeconds)}
Moyenne par sujet: ${this.round(averageSeconds)}
Sujet le plus long: ${longestTopic.title.replace('*', '')} (${this.round(longestSeconds)} )
Sujet le plus court : ${shortestTopic.title.replace('*', '')} (${this.round(shortestSeconds)})`;
}
setSubject(i: number) {
this.currentSubjectId = i;
this.updateTopicChangeDate()
}
compteRendu: string = ''
now:Date = new Date();
formatDateYMD(date: Date) {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
return `${year}-${month}-${day}`;
}
buildCompteRendu() {
let compteRendu = ` Compte rendu du ${this.formatDateYMD(this.today)}\n\n`;
compteRendu += `début: ${this.startTime}, fin:${this.endTime}.\n`;
compteRendu += `Présents:\n${this.formatPresentLines()}.\n`;
if (this.scribe) {
compteRendu += `Scribe: ${this.scribe}.\n`;
}
if (this.timekeeper) {
compteRendu += `Gardien du temps: ${this.timekeeper}.\n`;
}
if (this.animator) {
compteRendu += `Animation: ${this.animator}.\n`;
}
compteRendu += `Statistiques:\n
${this.statsExplication}.`;
for (const topic of this.subjects) {
compteRendu += `* ${topic.title}-`;
compteRendu += ` ${topic.duration} min`;
compteRendu += ` (${topic.author})\n`;
compteRendu += ` ${topic.notes}\n`;
if (topic.spentSeconds) {
compteRendu += `Temps écoulé : ${this.round(topic.spentSeconds)}\n\n`;
}
}
this.compteRendu = compteRendu
return compteRendu
}
/**
* returns each present person for each line with a dash at the beggining if missing
*/
formatPresentLines() {
let lines = ''
if (this.presents) {
lines += this.presents.split('\n').map(line => {
if (!line.length) {
return '';
}
if (!line.startsWith('- ')) {
return `- ${line}`;
}
return line;
}).join('\n') + '\n'
}
return lines.trim();
}
copyCompteRenduToClipboard() {
navigator.clipboard.writeText(this.compteRendu);
}
private findAuthorInDescription(topic: string): string {
let authorRegex = /\(([^)]+)\)/g;
let matches = authorRegex.exec(topic);
if (matches) {
return matches[1];
}
return '';
}
countLinesInPresent() {
return this.presents.split('\n').length;
}
downloadCompteRendu() {
let fichier = new Blob([this.buildCompteRendu()], {type: 'text/plain'});
let lien = document.createElement('a');
lien.setAttribute('href', window.URL.createObjectURL(fichier));
lien.setAttribute('download', 'compte-rendu.txt');
lien.click();
}
getMinutesBetweenTwoDates(date1: Date = new Date(), date2: Date) {
return Math.floor((date2.getTime() - date1.getTime()) / 60000);
}
getSecondsBetweenTwoDates(date1: Date | null, date2: Date) {
if (!date1) {
date1 = new Date()
}
return Math.floor((date2.getTime() - date1.getTime()) / 1000);
}
isNowTimeBetweenTwoDates(date1: Date, date2: Date) {
let min = Math.min(date1.getTime(),date2.getTime());
let max = Math.max(date1.getTime(),date2.getTime());
let now = new Date().getTime();
console.log('min', min, now , max)
return min < now && max > now;
}
}