Readme
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
import { prisma } from "@/lib/db/prisma";
|
||||
import { EmailService } from "@/lib/services/email.service";
|
||||
|
||||
let hasWarnedMissingNotificationTable = false;
|
||||
|
||||
@@ -547,9 +548,9 @@ export class NotificationService {
|
||||
* Checks for upcoming contract renewals/expirations and creates notifications
|
||||
*
|
||||
* Scans all contracts for a user and creates DEADLINE notifications for:
|
||||
* - 30 days before expiration (CRITICAL)
|
||||
* - 15 days before expiration (WARNING)
|
||||
* - 7 days before expiration (URGENT)
|
||||
* - 30 days before expiration
|
||||
* - 14 days before expiration
|
||||
* - 7 days before expiration
|
||||
*
|
||||
* @param userId - The user's ID
|
||||
* @returns Promise with count of created notifications
|
||||
@@ -557,7 +558,7 @@ export class NotificationService {
|
||||
* Steps:
|
||||
* 1. Query all COMPLETED contracts with endDate for the user
|
||||
* 2. Calculate days until expiration
|
||||
* 3. Create notification if contract expiring in 30, 15, or 7 days
|
||||
* 3. Create notification if contract expiring in 30, 14, or 7 days
|
||||
* 4. Check for existing notification to avoid duplicates
|
||||
* 5. Return summary of created notifications
|
||||
*
|
||||
@@ -573,6 +574,15 @@ export class NotificationService {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
select: {
|
||||
email: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Query all contracts with endDate for this user
|
||||
const contracts = await prisma.contract.findMany({
|
||||
where: {
|
||||
@@ -610,12 +620,12 @@ export class NotificationService {
|
||||
if (daysUntilExpiration === 7) {
|
||||
shouldNotify = true;
|
||||
level = "URGENT";
|
||||
} else if (daysUntilExpiration === 15) {
|
||||
} else if (daysUntilExpiration === 14) {
|
||||
shouldNotify = true;
|
||||
level = "WARNING";
|
||||
} else if (daysUntilExpiration === 30) {
|
||||
shouldNotify = true;
|
||||
level = "CRITICAL";
|
||||
level = "NOTICE";
|
||||
}
|
||||
|
||||
if (shouldNotify) {
|
||||
@@ -634,18 +644,21 @@ export class NotificationService {
|
||||
// Only create if not already notified today
|
||||
if (!existingNotification) {
|
||||
const notificationTitle =
|
||||
level === "CRITICAL"
|
||||
? `🔴 Contract Expiring in 30 Days`
|
||||
level === "NOTICE"
|
||||
? "Contract renewal reminder (30 days)"
|
||||
: level === "WARNING"
|
||||
? `🟠 Contract Expiring in 15 Days`
|
||||
: `🟡 Contract Expiring in 7 Days`;
|
||||
? "Contract renewal window (14 days)"
|
||||
: "Contract deadline in 7 days";
|
||||
|
||||
const providerLabel = contract.provider || "your provider";
|
||||
const contractLabel = contract.title || "your contract";
|
||||
|
||||
const notificationMessage =
|
||||
level === "CRITICAL"
|
||||
? `${contract.title} from ${contract.provider} will expire on ${contractEnd.toLocaleDateString()}. Time to renew!`
|
||||
level === "NOTICE"
|
||||
? `${contractLabel} from ${providerLabel} will expire on ${contractEnd.toLocaleDateString()}. Plan your renewal.`
|
||||
: level === "WARNING"
|
||||
? `${contract.title} from ${contract.provider} expires in 15 days. Consider scheduling renewal.`
|
||||
: `${contract.title} from ${contract.provider} expires in 7 days. Renew now!`;
|
||||
? `${contractLabel} from ${providerLabel} expires in 14 days. Please review renewal steps.`
|
||||
: `${contractLabel} from ${providerLabel} expires in 7 days. Action is required.`;
|
||||
|
||||
const result = await this.create({
|
||||
userId,
|
||||
@@ -654,7 +667,7 @@ export class NotificationService {
|
||||
message: notificationMessage,
|
||||
contractId: contract.id,
|
||||
actionType: `RENEWAL_${level}`,
|
||||
icon: level === "CRITICAL" ? "AlertCircle" : "AlertTriangle",
|
||||
icon: level === "URGENT" ? "AlertCircle" : "AlertTriangle",
|
||||
expiresIn: 24 * 60 * 60 * 1000, // 24 hours
|
||||
actionData: {
|
||||
level,
|
||||
@@ -667,6 +680,29 @@ export class NotificationService {
|
||||
|
||||
if (result.success) {
|
||||
createdNotifications.push(contract.id);
|
||||
|
||||
if (user?.email) {
|
||||
try {
|
||||
await EmailService.sendContractDeadlineReminderEmail({
|
||||
to: user.email,
|
||||
userDisplayName:
|
||||
`${user.firstName ?? ""} ${user.lastName ?? ""}`.trim() ||
|
||||
null,
|
||||
contractId: contract.id,
|
||||
contractTitle: contract.title,
|
||||
contractProvider: contract.provider,
|
||||
contractEndDate: contractEnd,
|
||||
daysUntilExpiration,
|
||||
});
|
||||
} catch (emailError) {
|
||||
console.warn(
|
||||
"Deadline email failed:",
|
||||
emailError instanceof Error
|
||||
? emailError.message
|
||||
: emailError,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user