- Introduced utility functions for workday calculations in `workday-utils.ts`, including `getPreviousWorkday`, `getNextWorkday`, `isWorkday`, and `getDayName`. - Updated `DailyService` and `DailyPageClient` to utilize `getPreviousWorkday` for accurate date handling instead of simple date subtraction.
277 lines
7.9 KiB
TypeScript
277 lines
7.9 KiB
TypeScript
import { prisma } from './database';
|
|
import { Prisma } from '@prisma/client';
|
|
import { DailyCheckbox, DailyView, CreateDailyCheckboxData, UpdateDailyCheckboxData, BusinessError, DailyCheckboxType, TaskStatus, TaskPriority, TaskSource } from '@/lib/types';
|
|
import { getPreviousWorkday } from '@/lib/workday-utils';
|
|
|
|
/**
|
|
* Service pour la gestion des checkboxes daily
|
|
*/
|
|
export class DailyService {
|
|
|
|
/**
|
|
* Récupère la vue daily pour une date donnée (checkboxes d'hier et d'aujourd'hui)
|
|
*/
|
|
async getDailyView(date: Date): Promise<DailyView> {
|
|
// Normaliser la date (début de journée)
|
|
const today = new Date(date);
|
|
today.setHours(0, 0, 0, 0);
|
|
|
|
// Utiliser la logique de jour de travail précédent au lieu de jour-1
|
|
const yesterday = getPreviousWorkday(today);
|
|
|
|
// Récupérer les checkboxes des deux jours
|
|
const [yesterdayCheckboxes, todayCheckboxes] = await Promise.all([
|
|
this.getCheckboxesByDate(yesterday),
|
|
this.getCheckboxesByDate(today)
|
|
]);
|
|
|
|
return {
|
|
date: today,
|
|
yesterday: yesterdayCheckboxes,
|
|
today: todayCheckboxes
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Récupère toutes les checkboxes d'une date donnée
|
|
*/
|
|
async getCheckboxesByDate(date: Date): Promise<DailyCheckbox[]> {
|
|
// Normaliser la date (début de journée)
|
|
const normalizedDate = new Date(date);
|
|
normalizedDate.setHours(0, 0, 0, 0);
|
|
|
|
const checkboxes = await prisma.dailyCheckbox.findMany({
|
|
where: { date: normalizedDate },
|
|
include: { task: true },
|
|
orderBy: { order: 'asc' }
|
|
});
|
|
|
|
return checkboxes.map(this.mapPrismaCheckbox);
|
|
}
|
|
|
|
/**
|
|
* Ajoute une checkbox à une date donnée
|
|
*/
|
|
async addCheckbox(data: CreateDailyCheckboxData): Promise<DailyCheckbox> {
|
|
// Normaliser la date
|
|
const normalizedDate = new Date(data.date);
|
|
normalizedDate.setHours(0, 0, 0, 0);
|
|
|
|
// Calculer l'ordre suivant pour cette date
|
|
const maxOrder = await prisma.dailyCheckbox.aggregate({
|
|
where: { date: normalizedDate },
|
|
_max: { order: true }
|
|
});
|
|
|
|
const order = data.order ?? ((maxOrder._max.order ?? -1) + 1);
|
|
|
|
const checkbox = await prisma.dailyCheckbox.create({
|
|
data: {
|
|
date: normalizedDate,
|
|
text: data.text.trim(),
|
|
type: data.type ?? 'task',
|
|
taskId: data.taskId,
|
|
order,
|
|
isChecked: data.isChecked ?? false
|
|
},
|
|
include: { task: true }
|
|
});
|
|
|
|
return this.mapPrismaCheckbox(checkbox);
|
|
}
|
|
|
|
/**
|
|
* Met à jour une checkbox
|
|
*/
|
|
async updateCheckbox(checkboxId: string, data: UpdateDailyCheckboxData): Promise<DailyCheckbox> {
|
|
const updateData: Prisma.DailyCheckboxUpdateInput = {};
|
|
|
|
if (data.text !== undefined) updateData.text = data.text.trim();
|
|
if (data.isChecked !== undefined) updateData.isChecked = data.isChecked;
|
|
if (data.type !== undefined) updateData.type = data.type;
|
|
if (data.taskId !== undefined) {
|
|
if (data.taskId === null) {
|
|
updateData.task = { disconnect: true };
|
|
} else {
|
|
updateData.task = { connect: { id: data.taskId } };
|
|
}
|
|
}
|
|
if (data.order !== undefined) updateData.order = data.order;
|
|
|
|
const checkbox = await prisma.dailyCheckbox.update({
|
|
where: { id: checkboxId },
|
|
data: updateData,
|
|
include: { task: true }
|
|
});
|
|
|
|
return this.mapPrismaCheckbox(checkbox);
|
|
}
|
|
|
|
/**
|
|
* Supprime une checkbox
|
|
*/
|
|
async deleteCheckbox(checkboxId: string): Promise<void> {
|
|
const checkbox = await prisma.dailyCheckbox.findUnique({
|
|
where: { id: checkboxId }
|
|
});
|
|
|
|
if (!checkbox) {
|
|
throw new BusinessError('Checkbox non trouvée');
|
|
}
|
|
|
|
await prisma.dailyCheckbox.delete({
|
|
where: { id: checkboxId }
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Réordonne les checkboxes d'une date donnée
|
|
*/
|
|
async reorderCheckboxes(date: Date, checkboxIds: string[]): Promise<void> {
|
|
// Normaliser la date
|
|
const normalizedDate = new Date(date);
|
|
normalizedDate.setHours(0, 0, 0, 0);
|
|
|
|
await prisma.$transaction(async (prisma) => {
|
|
for (let i = 0; i < checkboxIds.length; i++) {
|
|
await prisma.dailyCheckbox.update({
|
|
where: { id: checkboxIds[i] },
|
|
data: { order: i }
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Recherche dans les checkboxes
|
|
*/
|
|
async searchCheckboxes(query: string, limit: number = 20): Promise<DailyCheckbox[]> {
|
|
const checkboxes = await prisma.dailyCheckbox.findMany({
|
|
where: {
|
|
text: {
|
|
contains: query
|
|
}
|
|
},
|
|
include: { task: true },
|
|
orderBy: { date: 'desc' },
|
|
take: limit
|
|
});
|
|
|
|
return checkboxes.map(this.mapPrismaCheckbox);
|
|
}
|
|
|
|
/**
|
|
* Récupère l'historique des checkboxes (groupées par date)
|
|
*/
|
|
async getCheckboxHistory(limit: number = 30): Promise<{ date: Date; checkboxes: DailyCheckbox[] }[]> {
|
|
// Récupérer les dates distinctes des dernières checkboxes
|
|
const distinctDates = await prisma.dailyCheckbox.findMany({
|
|
select: { date: true },
|
|
distinct: ['date'],
|
|
orderBy: { date: 'desc' },
|
|
take: limit
|
|
});
|
|
|
|
const history = [];
|
|
for (const { date } of distinctDates) {
|
|
const checkboxes = await this.getCheckboxesByDate(date);
|
|
if (checkboxes.length > 0) {
|
|
history.push({ date, checkboxes });
|
|
}
|
|
}
|
|
|
|
return history;
|
|
}
|
|
|
|
/**
|
|
* Récupère la vue daily d'aujourd'hui
|
|
*/
|
|
async getTodaysDailyView(): Promise<DailyView> {
|
|
return this.getDailyView(new Date());
|
|
}
|
|
|
|
/**
|
|
* Ajoute une checkbox pour aujourd'hui
|
|
*/
|
|
async addTodayCheckbox(text: string, taskId?: string): Promise<DailyCheckbox> {
|
|
return this.addCheckbox({
|
|
date: new Date(),
|
|
text,
|
|
taskId
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Ajoute une checkbox pour hier
|
|
*/
|
|
async addYesterdayCheckbox(text: string, taskId?: string): Promise<DailyCheckbox> {
|
|
const yesterday = new Date();
|
|
yesterday.setDate(yesterday.getDate() - 1);
|
|
|
|
return this.addCheckbox({
|
|
date: yesterday,
|
|
text,
|
|
taskId
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Mappe une checkbox Prisma vers notre interface
|
|
*/
|
|
private mapPrismaCheckbox(checkbox: Prisma.DailyCheckboxGetPayload<{ include: { task: true } }>): DailyCheckbox {
|
|
return {
|
|
id: checkbox.id,
|
|
date: checkbox.date,
|
|
text: checkbox.text,
|
|
isChecked: checkbox.isChecked,
|
|
type: checkbox.type as DailyCheckboxType,
|
|
order: checkbox.order,
|
|
taskId: checkbox.taskId || undefined,
|
|
task: checkbox.task ? {
|
|
id: checkbox.task.id,
|
|
title: checkbox.task.title,
|
|
description: checkbox.task.description || undefined,
|
|
status: checkbox.task.status as TaskStatus,
|
|
priority: checkbox.task.priority as TaskPriority,
|
|
source: checkbox.task.source as TaskSource,
|
|
sourceId: checkbox.task.sourceId || undefined,
|
|
tags: [], // Les tags seront chargés séparément si nécessaire
|
|
dueDate: checkbox.task.dueDate || undefined,
|
|
completedAt: checkbox.task.completedAt || undefined,
|
|
createdAt: checkbox.task.createdAt,
|
|
updatedAt: checkbox.task.updatedAt,
|
|
jiraProject: checkbox.task.jiraProject || undefined,
|
|
jiraKey: checkbox.task.jiraKey || undefined,
|
|
assignee: checkbox.task.assignee || undefined
|
|
} : undefined,
|
|
createdAt: checkbox.createdAt,
|
|
updatedAt: checkbox.updatedAt
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Récupère toutes les dates qui ont des checkboxes (pour le calendrier)
|
|
*/
|
|
async getDailyDates(): Promise<string[]> {
|
|
const checkboxes = await prisma.dailyCheckbox.findMany({
|
|
select: {
|
|
date: true
|
|
},
|
|
distinct: ['date'],
|
|
orderBy: {
|
|
date: 'desc'
|
|
}
|
|
});
|
|
|
|
return checkboxes.map(checkbox => {
|
|
const date = checkbox.date;
|
|
const year = date.getFullYear();
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
return `${year}-${month}-${day}`;
|
|
});
|
|
}
|
|
}
|
|
|
|
// Instance singleton du service
|
|
export const dailyService = new DailyService(); |