feat: complete integration of macOS reminders with filtering and logging

- Marked tasks in TODO.md as completed for macOS reminders integration.
- Enhanced RemindersService to filter reminders based on enabled lists and added detailed logging for better debugging.
- Implemented methods for retrieving reminders from specific lists and parsing output from AppleScript.
This commit is contained in:
Julien Froidefond
2025-09-13 13:49:35 +02:00
parent c5f0a71e22
commit f751e5966e
6 changed files with 527 additions and 39 deletions

100
src/app/api/config/route.ts Normal file
View File

@@ -0,0 +1,100 @@
import { NextResponse } from 'next/server';
import { getConfig, getTargetRemindersList, getEnabledRemindersLists } from '@/lib/config';
import { remindersService } from '@/services/reminders';
/**
* API route pour récupérer la configuration actuelle
*/
export async function GET() {
try {
const config = getConfig();
const availableLists = await remindersService.getReminderLists();
return NextResponse.json({
success: true,
config,
availableLists,
currentTarget: getTargetRemindersList(),
enabledLists: getEnabledRemindersLists()
});
} catch (error) {
console.error('❌ Erreur lors de la récupération de la config:', error);
return NextResponse.json({
success: false,
error: error instanceof Error ? error.message : 'Erreur inconnue'
}, { status: 500 });
}
}
/**
* API route pour tester l'accès à une liste spécifique
*/
export async function POST(request: Request) {
try {
const body = await request.json();
const { listName, action } = body;
if (!listName) {
return NextResponse.json({
success: false,
error: 'listName est requis'
}, { status: 400 });
}
let result: any = {};
switch (action) {
case 'test':
// Tester l'accès à une liste spécifique
const reminders = await remindersService.getRemindersByList(listName);
result = {
listName,
accessible: true,
reminderCount: reminders.length,
sample: reminders.slice(0, 3).map(r => ({
title: r.title,
completed: r.completed,
priority: r.priority
}))
};
break;
case 'preview':
// Prévisualiser les rappels d'une liste
const previewReminders = await remindersService.getRemindersByList(listName);
result = {
listName,
reminders: previewReminders.map(r => ({
id: r.id,
title: r.title,
completed: r.completed,
priority: r.priority,
tags: r.tags || []
}))
};
break;
default:
return NextResponse.json({
success: false,
error: 'Action non supportée. Utilisez "test" ou "preview"'
}, { status: 400 });
}
return NextResponse.json({
success: true,
action,
result
});
} catch (error) {
console.error('❌ Erreur lors du test de liste:', error);
return NextResponse.json({
success: false,
error: error instanceof Error ? error.message : 'Erreur inconnue'
}, { status: 500 });
}
}

View File

@@ -0,0 +1,60 @@
import { NextResponse } from 'next/server';
import { taskProcessorService } from '@/services/task-processor';
/**
* API route pour synchroniser les rappels macOS avec la base de données
*/
export async function POST() {
try {
console.log('🔄 Début de la synchronisation des rappels...');
const syncResult = await taskProcessorService.syncRemindersToDatabase();
return NextResponse.json({
success: true,
message: 'Synchronisation des rappels terminée',
syncLog: syncResult
});
} catch (error) {
console.error('❌ Erreur lors de la synchronisation:', error);
return NextResponse.json({
success: false,
error: error instanceof Error ? error.message : 'Erreur inconnue lors de la synchronisation'
}, { status: 500 });
}
}
/**
* API route pour obtenir le statut de la dernière synchronisation
*/
export async function GET() {
try {
// Récupérer les derniers logs de sync
const { prisma } = await import('@/services/database');
const lastSyncLogs = await prisma.syncLog.findMany({
where: { source: 'reminders' },
orderBy: { createdAt: 'desc' },
take: 5
});
const taskStats = await taskProcessorService.getTaskStats();
return NextResponse.json({
success: true,
lastSyncLogs,
taskStats,
message: 'Statut de synchronisation récupéré'
});
} catch (error) {
console.error('❌ Erreur lors de la récupération du statut:', error);
return NextResponse.json({
success: false,
error: error instanceof Error ? error.message : 'Erreur inconnue'
}, { status: 500 });
}
}

View File

@@ -0,0 +1,93 @@
import { NextResponse } from 'next/server';
import { taskProcessorService } from '@/services/task-processor';
import { TaskStatus } from '@/lib/types';
/**
* API route pour récupérer les tâches avec filtres optionnels
*/
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
// Extraire les paramètres de filtre
const filters: any = {};
const status = searchParams.get('status');
if (status) {
filters.status = status.split(',') as TaskStatus[];
}
const source = searchParams.get('source');
if (source) {
filters.source = source.split(',');
}
const search = searchParams.get('search');
if (search) {
filters.search = search;
}
const limit = searchParams.get('limit');
if (limit) {
filters.limit = parseInt(limit);
}
const offset = searchParams.get('offset');
if (offset) {
filters.offset = parseInt(offset);
}
// Récupérer les tâches
const tasks = await taskProcessorService.getTasks(filters);
const stats = await taskProcessorService.getTaskStats();
return NextResponse.json({
success: true,
data: tasks,
stats,
filters: filters,
count: tasks.length
});
} catch (error) {
console.error('❌ Erreur lors de la récupération des tâches:', error);
return NextResponse.json({
success: false,
error: error instanceof Error ? error.message : 'Erreur inconnue'
}, { status: 500 });
}
}
/**
* API route pour mettre à jour le statut d'une tâche
*/
export async function PATCH(request: Request) {
try {
const body = await request.json();
const { taskId, status } = body;
if (!taskId || !status) {
return NextResponse.json({
success: false,
error: 'taskId et status sont requis'
}, { status: 400 });
}
const updatedTask = await taskProcessorService.updateTaskStatus(taskId, status);
return NextResponse.json({
success: true,
data: updatedTask,
message: `Tâche ${taskId} mise à jour avec le statut ${status}`
});
} catch (error) {
console.error('❌ Erreur lors de la mise à jour de la tâche:', error);
return NextResponse.json({
success: false,
error: error instanceof Error ? error.message : 'Erreur inconnue'
}, { status: 500 });
}
}