feat: email integration (nodemailer) + wire into agency/license flows
- src/lib/email.ts: SMTP client with pre-built templates: - sendAgencyApprovedEmail (reseller approval + discount) - sendAgencyRejectedEmail (reseller rejection + reason) - sendLicenseKeyEmail (license key delivery) - sendTicketCreatedEmail (ticket confirmation) - Agency approve route: sends approval email after DB update - Agency reject route: sends rejection email with reason - License creation route: sends license key email (fire-and-forget) - Graceful degradation: if SMTP not configured, logs warning + continues - nodemailer + @types/nodemailer installed
This commit is contained in:
1 parent
7a13dad693
commit
970986fef7
6 files changed
+158
-4
No files matched your search
@@ -72,16 +72,22 @@ export async function PATCH(req: Request, { params }: { params: Promise<{ id: st
|
||||
},
|
||||
})
|
||||
|
||||
// TODO (production): send email to company.email with subject
|
||||
// "Ihre Reseller-Bewerbung wurde genehmigt — {discountPct}% Rabatt"
|
||||
// containing the discount and a link to the agency portal.
|
||||
// Send approval email
|
||||
const { sendAgencyApprovedEmail } = await import('@/lib/email')
|
||||
if (application.company.email) {
|
||||
await sendAgencyApprovedEmail({
|
||||
to: application.company.email,
|
||||
companyName: application.company.name,
|
||||
discountPct,
|
||||
})
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
status: 'approved',
|
||||
discountPct,
|
||||
email: application.company.email,
|
||||
message: `Genehmigt mit ${discountPct}% Rabatt. E-Mail an ${application.company.email ?? '(keine E-Mail hinterlegt)'} würde versendet.`,
|
||||
message: `Genehmigt mit ${discountPct}% Rabatt.${application.company.email ? ` E-Mail an ${application.company.email} versendet.` : ' Keine E-Mail hinterlegt.'}`,
|
||||
})
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : 'internal server error'
|
||||
|
||||
@@ -60,6 +60,16 @@ export async function PATCH(req: Request, { params }: { params: Promise<{ id: st
|
||||
},
|
||||
})
|
||||
|
||||
// Send rejection email
|
||||
const { sendAgencyRejectedEmail } = await import('@/lib/email')
|
||||
if (application.company.email) {
|
||||
await sendAgencyRejectedEmail({
|
||||
to: application.company.email,
|
||||
companyName: application.company.name,
|
||||
reason,
|
||||
})
|
||||
}
|
||||
|
||||
return NextResponse.json({ ok: true, status: 'rejected', reason })
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : 'internal server error'
|
||||
|
||||
@@ -304,6 +304,18 @@ export async function POST(req: Request) {
|
||||
},
|
||||
})
|
||||
|
||||
// Send license key email to the customer
|
||||
const { sendLicenseKeyEmail } = await import('@/lib/email')
|
||||
if (company.email && !parentId) {
|
||||
// Only send for core licenses (not modules)
|
||||
sendLicenseKeyEmail({
|
||||
to: company.email,
|
||||
licenseKey: key,
|
||||
product,
|
||||
plan,
|
||||
}).catch(() => {}) // fire-and-forget, don't block response
|
||||
}
|
||||
|
||||
return NextResponse.json({ license, pricing: pricing.breakdown }, { status: 201 })
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : 'internal server error'
|
||||
|
||||
Reference in new issue
Block a user