This commit is contained in:
18
.env.example
18
.env.example
@@ -1,20 +1,6 @@
|
||||
API_KEY=
|
||||
DATABASE_URL=
|
||||
DATABASE_URL_UNPOOLED=
|
||||
PGDATABASE=
|
||||
PGHOST=
|
||||
PGHOST_UNPOOLED=
|
||||
PGPASSWORD=
|
||||
PGUSER=
|
||||
POSTGRES_DATABASE=
|
||||
POSTGRES_HOST=
|
||||
POSTGRES_PASSWORD=
|
||||
POSTGRES_PRISMA_URL=
|
||||
POSTGRES_URL=
|
||||
POSTGRES_URL_NON_POOLING=
|
||||
POSTGRES_URL_NO_SSL=
|
||||
POSTGRES_USER=
|
||||
RECIPIENT_EMAIL=
|
||||
RESEND_API_KEY=
|
||||
SENDER_EMAIL=
|
||||
SWEEGO_API_KEY=
|
||||
SWEEGO_FROM=
|
||||
DEFAULT_CATEGORY=
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:18-alpine AS builder
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -8,7 +8,9 @@ RUN npm install
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
FROM node:18-alpine
|
||||
FROM node:20-alpine
|
||||
|
||||
RUN apk add --no-cache openssl
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -17,6 +19,7 @@ ENV NODE_ENV=production
|
||||
COPY --from=builder /app/.next ./.next
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
COPY --from=builder /app/package.json ./package.json
|
||||
COPY --from=builder /app/prisma ./prisma
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
|
||||
19
README.md
19
README.md
@@ -134,23 +134,10 @@ Create a `.env` file with:
|
||||
```
|
||||
API_KEY=
|
||||
DATABASE_URL=
|
||||
DATABASE_URL_UNPOOLED=
|
||||
PGDATABASE=
|
||||
PGHOST=
|
||||
PGHOST_UNPOOLED=
|
||||
PGPASSWORD=
|
||||
PGUSER=
|
||||
POSTGRES_DATABASE=
|
||||
POSTGRES_HOST=
|
||||
POSTGRES_PASSWORD=
|
||||
POSTGRES_PRISMA_URL=
|
||||
POSTGRES_URL=
|
||||
POSTGRES_URL_NON_POOLING=
|
||||
POSTGRES_URL_NO_SSL=
|
||||
POSTGRES_USER=
|
||||
RECIPIENT_EMAIL=
|
||||
RESEND_API_KEY=
|
||||
SENDER_EMAIL=
|
||||
SWEEGO_API_KEY=
|
||||
SWEEGO_FROM=
|
||||
DEFAULT_CATEGORY=
|
||||
```
|
||||
|
||||
### 🗄️ Database Management
|
||||
|
||||
7441
package-lock.json
generated
Normal file
7441
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,6 @@
|
||||
"next": "^14.2.35",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"resend": "^4.1.1",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("POSTGRES_PRISMA_URL") // uses connection pooling
|
||||
directUrl = env("POSTGRES_URL_NON_POOLING") // uses a direct connection
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model Expense {
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
import { Resend } from 'resend';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import prisma from '@prisma/prisma';
|
||||
import { ReportExpenseData, ReportDayLogsData } from '@utils/types';
|
||||
|
||||
const SWEEGO_API_URL = 'https://api.sweego.io/send';
|
||||
|
||||
export class ExpenseReporter {
|
||||
private resend: Resend;
|
||||
private senderEmail: string;
|
||||
private recipientEmail: string;
|
||||
private sweegoApiKey: string;
|
||||
|
||||
constructor() {
|
||||
if (!process.env.RESEND_API_KEY) {
|
||||
throw new Error('RESEND_API_KEY environment variable is not set');
|
||||
if (!process.env.SWEEGO_API_KEY) {
|
||||
throw new Error('SWEEGO_API_KEY environment variable is not set');
|
||||
}
|
||||
if (!process.env.SENDER_EMAIL) {
|
||||
throw new Error('SENDER_EMAIL environment variable is not set');
|
||||
if (!process.env.SWEEGO_FROM) {
|
||||
throw new Error('SWEEGO_FROM environment variable is not set');
|
||||
}
|
||||
if (!process.env.RECIPIENT_EMAIL) {
|
||||
throw new Error('RECIPIENT_EMAIL environment variable is not set');
|
||||
}
|
||||
this.resend = new Resend(process.env.RESEND_API_KEY);
|
||||
this.senderEmail = process.env.SENDER_EMAIL;
|
||||
this.sweegoApiKey = process.env.SWEEGO_API_KEY;
|
||||
this.senderEmail = process.env.SWEEGO_FROM;
|
||||
this.recipientEmail = process.env.RECIPIENT_EMAIL;
|
||||
}
|
||||
|
||||
@@ -276,16 +277,28 @@ export class ExpenseReporter {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await this.resend.emails.send({
|
||||
from: this.senderEmail,
|
||||
to: this.recipientEmail,
|
||||
const response = await fetch(SWEEGO_API_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Api-Key': this.sweegoApiKey
|
||||
},
|
||||
body: JSON.stringify({
|
||||
channel: 'email',
|
||||
provider: 'sweego',
|
||||
recipients: [{ email: this.recipientEmail }],
|
||||
from: {
|
||||
email: this.senderEmail
|
||||
},
|
||||
subject: `Diary Report: ${from.toLocaleDateString('en-GB')} - ${to.toLocaleDateString('en-GB')}`,
|
||||
html: htmlContent,
|
||||
attachments
|
||||
'message-html': htmlContent,
|
||||
...(attachments.length > 0 && { attachments })
|
||||
})
|
||||
});
|
||||
|
||||
if (response.error) {
|
||||
throw new Error('Failed to send email: No id returned from Resend');
|
||||
if (!response.ok) {
|
||||
const error = await response.text();
|
||||
throw new Error(`Sweego API error: ${response.status} ${error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to send email:', error);
|
||||
|
||||
Reference in New Issue
Block a user