#!/usr/bin/env node /** * Daily script to send due date reminders for projects * Runs nightly to check for projects due in 3 days and 1 day */ import db from "./src/lib/db.js"; import { createNotification, NOTIFICATION_TYPES } from "./src/lib/notifications.js"; import { addDays, isBefore, parseISO, startOfDay } from "date-fns"; async function sendDueDateReminders() { try { console.log("🔍 Checking for projects with upcoming due dates..."); const today = startOfDay(new Date()); const threeDaysFromNow = addDays(today, 3); const oneDayFromNow = addDays(today, 1); // Get projects that are not fulfilled and have finish dates const projects = db.prepare(` SELECT p.project_id, p.project_name, p.finish_date, p.address, p.project_status, c.customer FROM projects p LEFT JOIN contracts c ON p.contract_id = c.contract_id WHERE p.finish_date IS NOT NULL AND p.project_status != 'fulfilled' AND p.project_status != 'cancelled' `).all(); console.log(`📋 Found ${projects.length} active projects with due dates`); let remindersSent = 0; for (const project of projects) { try { const finishDate = parseISO(project.finish_date); const finishDateStart = startOfDay(finishDate); // Check if due in 3 days if (finishDateStart.getTime() === threeDaysFromNow.getTime()) { await sendReminder(project, 3); remindersSent++; } // Check if due in 1 day else if (finishDateStart.getTime() === oneDayFromNow.getTime()) { await sendReminder(project, 1); remindersSent++; } } catch (error) { console.error(`❌ Error processing project ${project.project_id}:`, error); } } console.log(`✅ Sent ${remindersSent} due date reminders`); } catch (error) { console.error("❌ Error in due date reminder script:", error); } } async function sendReminder(project, daysUntilDue) { try { // Get users who should receive notifications (admins and team leads) const recipients = db.prepare(` SELECT id, name, role FROM users WHERE role IN ('admin', 'team_lead') AND is_active = 1 `).all(); if (recipients.length === 0) { console.log("⚠️ No active admin or team lead users found to notify"); return; } const dayText = daysUntilDue === 1 ? "dzień" : "dni"; const title = `Projekt kończy się za ${daysUntilDue} ${dayText}`; const message = `Projekt "${project.project_name}" (${project.customer || 'Brak klienta'}) kończy się ${new Date(project.finish_date).toLocaleDateString('pl-PL')}. Adres: ${project.address || 'Brak adresu'}.`; for (const user of recipients) { await createNotification({ userId: user.id, type: NOTIFICATION_TYPES.DUE_DATE_REMINDER, title, message, resourceType: "project", resourceId: project.project_id.toString(), actionUrl: `/projects/${project.project_id}`, priority: daysUntilDue === 1 ? "urgent" : "high" }); console.log(`📢 Reminder sent to ${user.name} (${user.role}) for project: ${project.project_name}`); } } catch (error) { console.error(`❌ Failed to send reminder for project ${project.project_id}:`, error); } } // Run the script sendDueDateReminders();