diff --git a/utils/commands/report.ts b/utils/commands/report.ts index c821a45..41a40bb 100644 --- a/utils/commands/report.ts +++ b/utils/commands/report.ts @@ -1,6 +1,7 @@ import { Resend } from 'resend'; +import { Prisma } from '@prisma/client'; import prisma from '@prisma/prisma'; -import { ReportData } from '@utils/types'; +import { ReportExpenseData, ReportDayLogsData } from '@utils/types'; export class ExpenseReporter { private resend: Resend; @@ -22,7 +23,10 @@ export class ExpenseReporter { this.recipientEmail = process.env.RECIPIENT_EMAIL; } - private async generateReport(from: Date, to: Date): Promise { + private async generateExpenses( + from: Date, + to: Date + ): Promise { const startDate = new Date(from); startDate.setHours(0, 0, 0, 0); @@ -77,7 +81,38 @@ export class ExpenseReporter { }; } - private generateHtmlReport(data: ReportData): string { + private async generateDayLogs( + from: Date, + to: Date + ): Promise { + const startDate = new Date(from); + startDate.setHours(0, 0, 0, 0); + + const endDate = new Date(to); + endDate.setHours(23, 59, 59, 999); + + const dayLogs = await prisma.dayLog.findMany({ + where: { + createdAt: { + gte: startDate, + lte: endDate + } + }, + orderBy: { + createdAt: 'desc' + } + }); + + return { + dayLogs, + dateRange: { from, to } + }; + } + + private generateHtmlReport( + expenses: ReportExpenseData, + dayLogs: ReportDayLogsData + ): string { const formatDate = (date: Date) => date.toLocaleDateString('en-US', { year: 'numeric', @@ -105,12 +140,12 @@ export class ExpenseReporter { -

Expense Report

-

From ${formatDate(data.dateRange.from)} to ${formatDate(data.dateRange.to)}

+

Diary Report

+

From ${formatDate(expenses.dateRange.from)} to ${formatDate(expenses.dateRange.to)}

Summary

-

Total Expenses: ${formatCurrency(data.summary.totalExpenses)}

+

Total Expenses: ${formatCurrency(expenses.summary.totalExpenses)}

Expenses by Category

@@ -120,7 +155,7 @@ export class ExpenseReporter { Total Count - ${data.summary.byCategory + ${expenses.summary.byCategory .map( cat => ` @@ -144,7 +179,7 @@ export class ExpenseReporter { Category Amount - ${data.expenses + ${expenses.expenses .map( exp => ` @@ -158,6 +193,33 @@ export class ExpenseReporter { ) .join('')} + +

Day Logs Report

+

From ${formatDate(dayLogs.dateRange.from)} to ${formatDate(dayLogs.dateRange.to)}

+ + + + + + + ${dayLogs.dayLogs + .filter( + (dl): dl is typeof dl & { comments: any[] } => + dl.comments !== null && Array.isArray(dl.comments) + ) + .flatMap(dl => + dl.comments.map( + comment => ` + + + + + + ` + ) + ) + .join('')} +
IDDateLog
${dl.id}${formatDate(dl.createdAt)}${comment.text}
`; @@ -168,16 +230,27 @@ export class ExpenseReporter { to: Date, includeJson: boolean = false ): Promise { - const reportData = await this.generateReport(from, to); - const htmlContent = this.generateHtmlReport(reportData); + const reportExpenseData = await this.generateExpenses(from, to); + const reportDayLogData = await this.generateDayLogs(from, to); + const htmlContent = this.generateHtmlReport( + reportExpenseData, + reportDayLogData + ); const attachments = []; if (includeJson) { - const jsonData = JSON.stringify(reportData, null, 2); + const jsonExpenseData = JSON.stringify(reportExpenseData, null, 2); attachments.push({ - filename: 'expense-report.json', - content: Buffer.from(jsonData).toString('base64'), - contentType: 'application/json' // Added MIME type + filename: 'expenses.json', + content: Buffer.from(jsonExpenseData).toString('base64'), + contentType: 'application/json' + }); + + const jsonDayLogData = JSON.stringify(reportDayLogData, null, 2); + attachments.push({ + filename: 'day-logs.json', + content: Buffer.from(jsonDayLogData).toString('base64'), + contentType: 'application/json' }); } @@ -185,7 +258,7 @@ export class ExpenseReporter { const response = await this.resend.emails.send({ from: this.senderEmail, to: this.recipientEmail, - subject: `Expense Report: ${from.toLocaleDateString()} - ${to.toLocaleDateString()}`, + subject: `Diary Report: ${from.toLocaleDateString()} - ${to.toLocaleDateString()}`, html: htmlContent, attachments }); diff --git a/utils/types.ts b/utils/types.ts index 715e2fa..c72f76a 100644 --- a/utils/types.ts +++ b/utils/types.ts @@ -1,4 +1,4 @@ -import { Category, Expense } from '@prisma/client'; +import { Category, DayLog, Expense } from '@prisma/client'; import { z } from 'zod'; interface Flag { @@ -40,7 +40,7 @@ const ExpenseSchema = z.object({ export type ExpenseType = z.infer; -export interface ReportData { +export interface ReportExpenseData { expenses: (Expense & { category: Category })[]; summary: { totalExpenses: number; @@ -55,3 +55,11 @@ export interface ReportData { to: Date; }; } + +export interface ReportDayLogsData { + dayLogs: DayLog[]; + dateRange: { + from: Date; + to: Date; + }; +}