add new GDPR page and handle account creation email
This commit is contained in:
@@ -11,11 +11,18 @@
|
||||
<div class="footer-inner px-8 py-16" class:sidebar>
|
||||
<div class="footer-row flex items-center justify-between gap-2">
|
||||
<span class="footer-star">✦</span>
|
||||
<span class="footer-copy"
|
||||
>© {new Date().getFullYear()}
|
||||
<span class="footer-text font-bold text-xl"><FamDone /></span> All rights reserved.</span
|
||||
<div class="footer-center">
|
||||
<span class="footer-copy"
|
||||
>© {new Date().getFullYear()}
|
||||
<span class="footer-text font-bold text-xl"><FamDone /></span> All rights reserved.</span
|
||||
>
|
||||
<span class="footer-links">
|
||||
<a href="/privacy">Privacy Policy</a>
|
||||
</span>
|
||||
</div>
|
||||
<aside
|
||||
class="footer-aside text-text-200 text-wash-300 flex flex-col justify-end text-right text-sm"
|
||||
>
|
||||
<aside class="footer-aside text-text-200 text-wash-300 flex flex-col justify-end text-right text-sm">
|
||||
<span>Built by humans</span>
|
||||
<a href="https://threejjjs.xyz">
|
||||
<h5 class="m-0 text-right font-tertiary text-xl md:text-3xl">
|
||||
@@ -53,6 +60,24 @@
|
||||
text-align: center;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
.footer-center {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
text-align: center;
|
||||
}
|
||||
.footer-links {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.footer-links a {
|
||||
color: #4c1d95;
|
||||
text-decoration: none;
|
||||
}
|
||||
.footer-links a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.footer-row {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// Code-specific email templates for successful access-code redemption.
|
||||
// Key = the raw access-code value a family enters (e.g. "copppermill03").
|
||||
// Add an entry here and its custom email is sent when that code is used.
|
||||
// If no entry matches, `defaultAccessEmailTemplate` is used.
|
||||
|
||||
export interface AccessEmailVars {
|
||||
famName: string;
|
||||
codeName: string;
|
||||
dashboardUrl: string;
|
||||
}
|
||||
|
||||
export interface AccessEmailTemplate {
|
||||
subject: (vars: AccessEmailVars) => string;
|
||||
html: (vars: AccessEmailVars) => string;
|
||||
}
|
||||
|
||||
const DEFAULT_TEMPLATE: AccessEmailTemplate = {
|
||||
subject: ({ famName }) => `Your ${famName} access is unlocked`,
|
||||
html: ({ famName, codeName, dashboardUrl }) => `
|
||||
<p>Hi${famName ? ` ${famName}` : ' there'}! 🎉</p>
|
||||
<p>Your access code (<strong>${codeName}</strong>) has been applied successfully.</p>
|
||||
<p>Your <strong>${famName}</strong> family on <strong>FamDone</strong> is now unlocked.</p>
|
||||
<p><a href="${dashboardUrl}">Open your family dashboard</a> to add kids, set up chores, and get going.</p>
|
||||
<p>If you have any questions, just reply to this email.</p>
|
||||
<p>Talk soon,<br />The FamDone team</p>
|
||||
`
|
||||
};
|
||||
|
||||
export const accessEmailTemplates: Record<string, AccessEmailTemplate> = {
|
||||
copppermill03: {
|
||||
subject: ({ famName }) => `Save a spot for ${famName} — access unlocked`,
|
||||
html: ({ famName, codeName, dashboardUrl }) => `
|
||||
<p>Hi${famName ? ` ${famName}` : ' there'}! 🎉</p>
|
||||
<p>Your access code (<strong>${codeName}</strong>) has been applied successfully.</p>
|
||||
<p>Your <strong>${famName}</strong> family on <strong>FamDone</strong> is now unlocked.</p>
|
||||
<p><a href="${dashboardUrl}">Open your family dashboard</a> to add kids, set up chores, and get going.</p>
|
||||
<p>If you have any questions, just reply to this email.</p>
|
||||
<p>Talk soon,<br />The FamDone team</p>
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
// Resolve the template for a redeemed code, falling back to the default.
|
||||
export function getAccessEmailTemplate(codeValue: string): AccessEmailTemplate {
|
||||
return accessEmailTemplates[codeValue] || DEFAULT_TEMPLATE;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Resend } from 'resend';
|
||||
import { RESEND_API } from '$app/env/private';
|
||||
import { getAccessEmailTemplate } from './email-templates';
|
||||
|
||||
const resend = new Resend(String(RESEND_API));
|
||||
|
||||
@@ -43,3 +44,53 @@ export async function sendParentInviteEmail(opts: {
|
||||
`
|
||||
});
|
||||
}
|
||||
|
||||
export async function sendAccessUnlockedEmail(opts: {
|
||||
to: string;
|
||||
famName: string;
|
||||
codeName: string;
|
||||
codeValue: string;
|
||||
dashboardUrl: string;
|
||||
}) {
|
||||
const { to, famName, codeName, codeValue, dashboardUrl } = opts;
|
||||
|
||||
const template = getAccessEmailTemplate(codeValue);
|
||||
const vars = { famName, codeName, dashboardUrl };
|
||||
|
||||
await resend.emails.send({
|
||||
from: 'no-reply@famchamp.ai',
|
||||
to,
|
||||
subject: template.subject(vars),
|
||||
html: template.html(vars)
|
||||
});
|
||||
}
|
||||
|
||||
export async function sendWelcomeEmail(opts: {
|
||||
to: string;
|
||||
famName: string;
|
||||
dashboardUrl: string;
|
||||
}) {
|
||||
const { to, famName, dashboardUrl } = opts;
|
||||
|
||||
await resend.emails.send({
|
||||
from: 'no-reply@famchamp.ai',
|
||||
to,
|
||||
subject: `Welcome to FamDone${famName ? `, ${famName}` : ''}!`,
|
||||
html: `
|
||||
<p>Hi${famName ? ` ${famName}` : ' there'}! 👋</p>
|
||||
<p>Welcome to <strong>FamDone</strong> — your family chore and pocket-money app.</p>
|
||||
<p>Your family is all set up. Here's how to get going:</p>
|
||||
<ul>
|
||||
<li>Open your <a href="${dashboardUrl}">family dashboard</a>.</li>
|
||||
<li>Add your kids and create join codes from <strong>Family Settings</strong>.</li>
|
||||
<li>Set up chores, rewards, and allowances.</li>
|
||||
</ul>
|
||||
<p>
|
||||
If you haven't already, you can pick a plan and pay from your dashboard to
|
||||
unlock your family.
|
||||
</p>
|
||||
<p>If you have any questions, just reply to this email — we're happy to help.</p>
|
||||
<p>Talk soon,<br />The FamDone team</p>
|
||||
`
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user