add receipts support

This commit is contained in:
2026-06-26 23:07:43 -04:00
parent 85df7c4627
commit b9a9b813d2
55 changed files with 3239 additions and 441 deletions
+3 -66
View File
@@ -2,12 +2,7 @@ import { type NextRequest, NextResponse } from "next/server";
import { eq } from "drizzle-orm";
import { db } from "~/server/db";
import { users } from "~/server/db/schema";
import { Resend } from "resend";
import { env } from "~/env";
import { APP_EMAIL_DOMAIN } from "~/lib/app-email";
import { getAppUrl } from "~/lib/app-url";
import { generatePasswordResetEmailTemplate } from "~/lib/email-templates";
import crypto from "crypto";
import { sendPasswordResetForUser } from "~/lib/password-reset";
export async function POST(request: NextRequest) {
try {
@@ -17,7 +12,6 @@ export async function POST(request: NextRequest) {
return NextResponse.json({ error: "Email is required" }, { status: 400 });
}
// Validate email format
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
return NextResponse.json(
@@ -26,13 +20,11 @@ export async function POST(request: NextRequest) {
);
}
// Check if user exists
const user = await db.query.users.findFirst({
where: eq(users.email, email.toLowerCase()),
columns: { id: true },
});
// Always return success to prevent email enumeration attacks
// Don't reveal whether the user exists or not
if (!user) {
return NextResponse.json(
{
@@ -44,62 +36,7 @@ export async function POST(request: NextRequest) {
);
}
// Generate reset token
const resetToken = crypto.randomBytes(32).toString("hex");
const resetTokenExpiry = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
// Update user with reset token
await db
.update(users)
.set({
resetToken,
resetTokenExpiry,
})
.where(eq(users.id, user.id));
if (!env.RESEND_API_KEY) {
console.warn(
"Password reset requested, but RESEND_API_KEY is not configured.",
);
return NextResponse.json(
{
success: true,
message:
"If an account with that email exists, password reset instructions have been sent.",
},
{ status: 200 },
);
}
// Send password reset email using Resend
try {
const resend = new Resend(env.RESEND_API_KEY);
const resetUrl = `${getAppUrl()}/auth/reset-password?token=${resetToken}`;
const emailTemplate = generatePasswordResetEmailTemplate({
userEmail: email,
userName: user.name ?? undefined,
resetToken,
resetUrl,
expiryHours: 24,
});
const fromDomain = env.RESEND_DOMAIN ?? APP_EMAIL_DOMAIN;
await resend.emails.send({
from: `beenvoice <noreply@${fromDomain}>`,
to: email,
subject: emailTemplate.subject,
html: emailTemplate.html,
text: emailTemplate.text,
});
console.log(`Password reset email sent to: ${email}`);
} catch (emailError) {
console.error("Failed to send password reset email:", emailError);
// Continue execution - don't fail the request if email fails
// This prevents revealing whether an account exists based on email delivery
}
await sendPasswordResetForUser(user.id);
return NextResponse.json(
{