feat: implement Daily management features and update UI
- Marked tasks as completed in TODO for Daily management service, data model, and interactive checkboxes. - Added a new link to the Daily page in the Header component for easy navigation. - Introduced DailyCheckbox model in Prisma schema and corresponding TypeScript interfaces for better data handling. - Updated database schema to include daily checkboxes, enhancing task management capabilities.
This commit is contained in:
244
services/daily.ts
Normal file
244
services/daily.ts
Normal file
@@ -0,0 +1,244 @@
|
||||
import { prisma } from './database';
|
||||
import { DailyCheckbox, DailyView, CreateDailyCheckboxData, UpdateDailyCheckboxData, BusinessError } 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<DailyView> {
|
||||
// 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<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(),
|
||||
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: any = {};
|
||||
|
||||
if (data.text !== undefined) updateData.text = data.text.trim();
|
||||
if (data.isChecked !== undefined) updateData.isChecked = data.isChecked;
|
||||
if (data.taskId !== undefined) updateData.taskId = 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,
|
||||
mode: 'insensitive'
|
||||
}
|
||||
},
|
||||
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: any): DailyCheckbox {
|
||||
return {
|
||||
id: checkbox.id,
|
||||
date: checkbox.date,
|
||||
text: checkbox.text,
|
||||
isChecked: checkbox.isChecked,
|
||||
order: checkbox.order,
|
||||
taskId: checkbox.taskId,
|
||||
task: checkbox.task ? {
|
||||
id: checkbox.task.id,
|
||||
title: checkbox.task.title,
|
||||
description: checkbox.task.description,
|
||||
status: checkbox.task.status,
|
||||
priority: checkbox.task.priority,
|
||||
source: checkbox.task.source,
|
||||
sourceId: checkbox.task.sourceId,
|
||||
tags: [], // Les tags seront chargés séparément si nécessaire
|
||||
dueDate: checkbox.task.dueDate,
|
||||
completedAt: checkbox.task.completedAt,
|
||||
createdAt: checkbox.task.createdAt,
|
||||
updatedAt: checkbox.task.updatedAt,
|
||||
jiraProject: checkbox.task.jiraProject,
|
||||
jiraKey: checkbox.task.jiraKey,
|
||||
assignee: checkbox.task.assignee
|
||||
} : undefined,
|
||||
createdAt: checkbox.createdAt,
|
||||
updatedAt: checkbox.updatedAt
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Instance singleton du service
|
||||
export const dailyService = new DailyService();
|
||||
Reference in New Issue
Block a user