oggui/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.compon...

389 lines
13 KiB
TypeScript

import { inject } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import {Component, Inject, OnInit } from '@angular/core';
import {FormBuilder, FormGroup} from "@angular/forms";
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {HttpClient} from "@angular/common/http";
import {ToastrService} from "ngx-toastr";
import {ConfigService} from "@services/config.service";
@Component({
selector: 'app-create-task-schedule',
templateUrl: './create-task-schedule.component.html',
styleUrl: './create-task-schedule.component.css'
})
export class CreateTaskScheduleComponent implements OnInit{
public translate = inject(TranslateService);
form: FormGroup;
baseUrl: string;
apiUrl: string;
recurrenceTypes = [
{ value: 'none', label : this.translate.instant('withoutRepetition') },
{ value: 'custom', label : this.translate.instant('customRepeat') }
];
weekDays: string[] = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
isSingleDateSelected: boolean = true;
monthsList: string[] = [
'january', 'february', 'march', 'april', 'may', 'june',
'july', 'august', 'september', 'october', 'november', 'december'
];
monthRows: string[][] = [];
editing: boolean = false;
selectedMonths: { [key: string]: boolean } = {};
selectedDays: { [key: string]: boolean } = {};
nextExecutionDate: Date | null = null;
executionCount: number = 0;
constructor(
private fb: FormBuilder,
public dialogRef: MatDialogRef<CreateTaskScheduleComponent>,
private http: HttpClient,
private toastr: ToastrService,
private configService: ConfigService,
@Inject(MAT_DIALOG_DATA) public data: any
) {
this.baseUrl = this.configService.apiUrl;
this.apiUrl = `${this.baseUrl}/command-task-schedules`;
this.form = this.fb.group({
executionDate: [new Date()],
executionTime: ['08:00'],
recurrenceType: ['none'],
recurrenceDetails: this.fb.group({
daysOfWeek: [[]],
months: this.fb.control([]),
initDate: [null],
endDate: [null]
}),
enabled: [true]
});
if (this.data.schedule) {
this.editing = true;
this.loadData();
}
this.form.get('recurrenceType')?.valueChanges.subscribe((value) => {
if (value === 'none') {
this.form.get('recurrenceDetails')?.disable();
} else {
this.form.get('recurrenceDetails')?.enable();
}
});
}
ngOnInit(): void {
this.monthRows = [
this.monthsList.slice(0, 6),
this.monthsList.slice(6, 12)
];
}
loadData(): void {
this.http.get<any>(`${this.baseUrl}${this.data.schedule['@id']}`).subscribe(
(data) => {
const formattedExecutionTime = this.formatExecutionTime(data.executionTime);
this.form.patchValue({
executionDate: data.executionDate,
executionTime: formattedExecutionTime,
recurrenceType: data.recurrenceType,
recurrenceDetails: {
...data.recurrenceDetails,
initDate: data.recurrenceDetails.initDate || null,
endDate: data.recurrenceDetails.endDate || null,
daysOfWeek: data.recurrenceDetails.daysOfWeek || [],
months: data.recurrenceDetails.months || []
},
enabled: data.enabled
});
this.selectedDays = data.recurrenceDetails.daysOfWeek.reduce((acc: any, day: string) => {
acc[day] = true;
return acc;
}, {});
this.selectedMonths = data.recurrenceDetails.months.reduce((acc: any, month: string) => {
acc[month] = true;
return acc;
}, {});
},
(error) => {
console.error(this.translate.instant('errorLoadingScheduleData'), error);
}
);
}
formatExecutionTime(time: string | Date): string {
if (typeof time === 'string') {
const hhmmMatch = time.match(/^\d{2}:\d{2}/);
if (hhmmMatch) {
return hhmmMatch[0];
}
const parsed = new Date(time);
if (!isNaN(parsed.getTime())) {
const utcHours = parsed.getUTCHours();
const utcMinutes = parsed.getUTCMinutes();
const currentDate = new Date();
currentDate.setUTCHours(utcHours, utcMinutes, 0, 0);
const hours = String(currentDate.getHours()).padStart(2, '0');
const minutes = String(currentDate.getMinutes()).padStart(2, '0');
return `${hours}:${minutes}`;
}
return '';
}
if (time instanceof Date && !isNaN(time.getTime())) {
const hours = String(time.getHours()).padStart(2, '0');
const minutes = String(time.getMinutes()).padStart(2, '0');
return `${hours}:${minutes}`;
}
return '';
}
convertDateToLocalISO(date: Date): string {
date = new Date(date);
const adjustedDate = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
return adjustedDate.toISOString();
}
convertTimeToUTC(timeString: string): string {
const today = new Date();
const [hours, minutes] = timeString.split(':');
const localDateTime = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate(),
parseInt(hours, 10),
parseInt(minutes, 10),
0,
0
);
return localDateTime.toISOString();
}
onSubmit() {
const formData = this.form.value;
if (formData.recurrenceType === 'custom') {
const selectedDayNames = Object.keys(this.selectedDays).filter(day => this.selectedDays[day]);
const selectedMonthNames = Object.keys(this.selectedMonths).filter(month => this.selectedMonths[month]);
if (selectedDayNames.length === 0) {
this.toastr.error(this.translate.instant('youMustSelectAtLeastOne1'));
return;
}
if (selectedMonthNames.length === 0) {
this.toastr.error(this.translate.instant('youMustSelectAtLeastOne2'));
return;
}
const initDate = formData.recurrenceDetails?.initDate;
const endDate = formData.recurrenceDetails?.endDate;
if (!initDate || !endDate) {
this.toastr.error(this.translate.instant('youMustSpecifyStartDate'));
return;
}
if (new Date(endDate) <= new Date(initDate)) {
this.toastr.error(this.translate.instant('theEndDateMust'));
return;
}
}
const payload: any = {
commandTask: this.data.task['@id'],
executionDate: formData.recurrenceType === 'none' ? this.convertDateToLocalISO(formData.executionDate) : null,
executionTime: this.convertTimeToUTC(formData.executionTime),
recurrenceType: formData.recurrenceType,
recurrenceDetails: {
...formData.recurrenceDetails,
initDate: formData.recurrenceDetails?.initDate || null,
endDate: formData.recurrenceDetails?.endDate || null,
daysOfWeek: formData.recurrenceDetails?.daysOfWeek || [],
months: formData.recurrenceDetails?.months || []
},
enabled: formData.enabled
}
if (this.editing) {
const taskId = this.data.task.uuid;
this.http.patch<any>(`${this.baseUrl}${this.data.schedule['@id']}`, payload).subscribe({
next: () => {
this.toastr.success(this.translate.instant('updatedTaskScheduleWith'));
this.dialogRef.close(true);
},
error: () => {
this.toastr.error(this.translate.instant('errorUpdatingTask'));
}
});
} else {
this.http.post<any>(this.apiUrl, payload).subscribe({
next: () => {
this.toastr.success(this.translate.instant('taskScheduleCreatedWith'));
this.dialogRef.close(true);
},
error: () => {
this.toastr.error(this.translate.instant('errorCreatingTask'));
}
});
}
}
onCancel(): void {
this.dialogRef.close(false);
}
get summaryText(): string {
const recurrence = this.form.get('recurrenceType')?.value;
const start = this.form.get('recurrenceType')?.value === 'none' ? this.form.get('executionDate')?.value : this.form.get('recurrenceDetails.initDate')?.value;
const end = this.form.get('recurrenceType')?.value === 'none' ? this.form.get('executionDate')?.value : this.form.get('recurrenceDetails.endDate')?.value;
const time = this.form.get('executionTime')?.value;
const days = Object.keys(this.selectedDays).filter(day => this.selectedDays[day]);
const months = Object.keys(this.selectedMonths).filter(month => this.selectedMonths[month]);
this.calculateNextExecutionAndCount();
if (recurrence === 'none') {
return `Esta acción se ejecutará una sola vez el ${ this.formatDate(start)} a las ${time}.`;
}
return `Esta acción se ejecutará todos los ${days.join(', ')} de ${months.join(', ')}, desde el ${this.formatDate(start)} hasta el ${this.formatDate(end)} a las ${time}.`;
}
private calculateNextExecutionAndCount(): void {
const recurrence = this.form.get('recurrenceType')?.value;
const time = this.form.get('executionTime')?.value;
if (recurrence === 'none') {
const execDate = this.form.get('executionDate')?.value;
if (execDate && time) {
this.nextExecutionDate = new Date(execDate);
const [hours, minutes] = time.split(':');
this.nextExecutionDate.setHours(parseInt(hours), parseInt(minutes), 0, 0);
this.executionCount = 1;
}
return;
}
const startDateValue = this.form.get('recurrenceDetails.initDate')?.value;
const endDateValue = this.form.get('recurrenceDetails.endDate')?.value;
const selectedDayNames = Object.keys(this.selectedDays).filter(day => this.selectedDays[day]);
const selectedMonthNames = Object.keys(this.selectedMonths).filter(month => this.selectedMonths[month]);
if (!startDateValue || !endDateValue || selectedDayNames.length === 0 || selectedMonthNames.length === 0) {
this.nextExecutionDate = null;
this.executionCount = 0;
return;
}
const startDate = new Date(startDateValue);
const endDate = new Date(endDateValue);
const selectedDayIndices = new Set<number>(selectedDayNames.map(name => this.getDayIndexFromName(name)));
const selectedMonthIndices = new Set<number>(selectedMonthNames.map(name => this.getMonthIndexFromName(name)));
this.executionCount = this.calculateExecutionCountExact(startDate, endDate, selectedDayIndices, selectedMonthIndices);
this.nextExecutionDate = this.findNextExecutionDate(startDate, endDate, time, selectedDayIndices, selectedMonthIndices);
}
private calculateExecutionCountExact(startDate: Date, endDate: Date, selectedDays: Set<number>, selectedMonths: Set<number>): number {
const cursor = new Date(startDate);
cursor.setHours(0, 0, 0, 0);
const end = new Date(endDate);
end.setHours(23, 59, 59, 999);
let count = 0;
while (cursor <= end) {
if (selectedMonths.has(cursor.getMonth()) && selectedDays.has(cursor.getDay())) {
count += 1;
}
cursor.setDate(cursor.getDate() + 1);
}
return count;
}
private findNextExecutionDate(startDate: Date, endDate: Date, time: string, selectedDays: Set<number>, selectedMonths: Set<number>): Date | null {
const now = new Date();
const startCandidate = new Date(Math.max(new Date(startDate).setHours(0, 0, 0, 0), new Date(now).setHours(0, 0, 0, 0)));
const endLimit = new Date(endDate);
endLimit.setHours(23, 59, 59, 999);
const [hours, minutes] = (time || '00:00').split(':');
const candidate = new Date(startCandidate);
while (candidate <= endLimit) {
if (selectedMonths.has(candidate.getMonth()) && selectedDays.has(candidate.getDay())) {
const candidateDateTime = new Date(candidate);
candidateDateTime.setHours(parseInt(hours), parseInt(minutes), 0, 0);
if (candidateDateTime >= now) {
return candidateDateTime;
}
}
candidate.setDate(candidate.getDate() + 1);
}
return null;
}
private getDayIndexFromName(dayName: string): number {
const mapping: { [key: string]: number } = {
sunday: 0,
monday: 1,
tuesday: 2,
wednesday: 3,
thursday: 4,
friday: 5,
saturday: 6
};
return mapping[dayName.toLowerCase()] ?? -1;
}
private getMonthIndexFromName(monthName: string): number {
const mapping: { [key: string]: number } = {
january: 0,
february: 1,
march: 2,
april: 3,
may: 4,
june: 5,
july: 6,
august: 7,
september: 8,
october: 9,
november: 10,
december: 11
};
return mapping[monthName.toLowerCase()] ?? -1;
}
formatDate(date: string | Date): string {
const realDate = (date instanceof Date) ? date : new Date(date);
return new Intl.DateTimeFormat('es-ES', { dateStyle: 'long' }).format(realDate);
}
toggleDay(day: string) {
this.selectedDays[day] = !this.selectedDays[day];
const days = Object.keys(this.selectedDays).filter(d => this.selectedDays[d]);
this.form.get('recurrenceDetails.daysOfWeek')?.setValue(days);
}
toggleMonth(month: string) {
this.selectedMonths[month] = !this.selectedMonths[month];
const months = Object.keys(this.selectedMonths).filter(m => this.selectedMonths[m]);
this.form.get('recurrenceDetails.months')?.setValue(months);
}
}