import { prisma } from './database'; import { Prisma } from '@prisma/client'; import { DailyCheckbox, DailyView, CreateDailyCheckboxData, UpdateDailyCheckboxData, BusinessError, DailyCheckboxType, TaskStatus, TaskPriority, TaskSource } from '@/lib/types'; /** * 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 { // Normaliser la date (début de journée) const today = new Date(date); today.setHours(0, 0, 0, 0); const yesterday = new Date(today); yesterday.setDate(yesterday.getDate() - 1); // 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 { // 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 { // 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 { 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 { 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 { // 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 { 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 { return this.getDailyView(new Date()); } /** * Ajoute une checkbox pour aujourd'hui */ async addTodayCheckbox(text: string, taskId?: string): Promise { return this.addCheckbox({ date: new Date(), text, taskId }); } /** * Ajoute une checkbox pour hier */ async addYesterdayCheckbox(text: string, taskId?: string): Promise { 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 { 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();