mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
magic link email tempalte live
This commit is contained in:
parent
a264686552
commit
73efe32801
5 changed files with 988 additions and 258 deletions
1145
package-lock.json
generated
1145
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -52,7 +52,6 @@
|
|||
"next-auth": "^4.22.1",
|
||||
"next-axiom": "^1.9.2",
|
||||
"next-themes": "^0.3.0",
|
||||
"nodemailer": "^6.10.1",
|
||||
"pg": "^8.11.1",
|
||||
"postcss": "^8.5.6",
|
||||
"react": "18.3.1",
|
||||
|
|
@ -70,6 +69,7 @@
|
|||
"devDependencies": {
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@testing-library/cypress": "^10.0.3",
|
||||
"@types/nodemailer": "^7.0.2",
|
||||
"@types/pg": "^8.10.2",
|
||||
"cypress": "^14.5.3",
|
||||
"cypress-social-logins": "^1.14.1",
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ export const AuthOptions: NextAuthOptions = {
|
|||
},
|
||||
from: EMAIL_FROM,
|
||||
maxAge: 60 * 60, // magic link valid for 1 hour
|
||||
sendVerificationRequest: MagicLinksEmail,
|
||||
}),
|
||||
],
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,97 @@
|
|||
// click a verification email to sign in to the app, should they choose to sign in with magic
|
||||
// links
|
||||
|
||||
export async function MagicLinksEmail() {
|
||||
return null;
|
||||
import { createTransport } from "nodemailer";
|
||||
|
||||
export async function MagicLinksEmail({
|
||||
identifier,
|
||||
url,
|
||||
provider,
|
||||
}: {
|
||||
identifier: string;
|
||||
url: string;
|
||||
provider: { server: any; from: string };
|
||||
}) {
|
||||
const { host } = new URL(url);
|
||||
|
||||
const transport = createTransport(provider.server);
|
||||
|
||||
const brandColor = "#14163d"; // brand blue
|
||||
const accentColor = "#2d348f"; // deep blue
|
||||
const brown = "#c4a47c"; // brand brown
|
||||
const background = "#F9F9F9";
|
||||
|
||||
const result = await transport.sendMail({
|
||||
to: identifier,
|
||||
from: provider.from,
|
||||
subject: "Your secure Domna IQ sign-in link",
|
||||
text: plainText({ url, host }),
|
||||
html: domnaHtml({ url, host, brandColor, accentColor, brown, background }),
|
||||
});
|
||||
|
||||
const failed = result.rejected.filter(Boolean);
|
||||
if (failed.length) {
|
||||
throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`);
|
||||
}
|
||||
}
|
||||
|
||||
function domnaHtml({
|
||||
url,
|
||||
host,
|
||||
brandColor,
|
||||
accentColor,
|
||||
brown,
|
||||
background,
|
||||
}: {
|
||||
url: string;
|
||||
host: string;
|
||||
brandColor: string;
|
||||
accentColor: string;
|
||||
brown: string;
|
||||
background: string;
|
||||
}) {
|
||||
const escapedHost = host.replace(/\./g, "​.");
|
||||
|
||||
return `
|
||||
<body style="background: ${background}; font-family: Helvetica, Arial, sans-serif; margin: 0; padding: 0;">
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="0"
|
||||
style="max-width: 600px; margin: 40px auto; background: #fff; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 12px rgba(0,0,0,0.05);">
|
||||
<tr>
|
||||
<td align="center" style="background: linear-gradient(90deg, ${brandColor}, ${accentColor}); padding: 12px 8px;">
|
||||
<img
|
||||
src="https://145275138.fs1.hubspotusercontent-eu1.net/hubfs/145275138/base_logo_transparent_background.png"
|
||||
alt="Domna Logo"
|
||||
width="120"
|
||||
height="auto"
|
||||
style="margin-bottom: 4px;"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" style="padding: 10px 10px 10px; color: #333;">
|
||||
<h2 style="color: ${brandColor}; font-size: 22px; margin-bottom: 16px;">Welcome back to Domna IQ</h2>
|
||||
<p style="font-size: 16px; line-height: 1.6; color: #444; margin-bottom: 32px;">
|
||||
Click below to securely sign in to your account and continue your retrofit journey.
|
||||
</p>
|
||||
<a href="${url}" target="_blank"
|
||||
style="display: inline-block; padding: 14px 28px; background: ${brown}; color: #fff; text-decoration: none; border-radius: 6px; font-weight: 600; font-size: 16px;">
|
||||
Sign in to Domna IQ
|
||||
</a>
|
||||
<p style="margin-top: 36px; font-size: 13px; color: #777;">
|
||||
If you didn’t request this email, you can safely ignore it.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" style="padding: 20px; font-size: 12px; color: #999; border-top: 1px solid #eee;">
|
||||
© ${new Date().getFullYear()} Domna Homes • <span style="color: ${accentColor};">${escapedHost}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
`;
|
||||
}
|
||||
|
||||
function plainText({ url, host }: { url: string; host: string }) {
|
||||
return `Sign in to Domna IQ\n${url}\n\nIf you did not request this email, you can safely ignore it.\n`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ export async function middleware(req: NextRequest) {
|
|||
const token = await getToken({ req });
|
||||
const { pathname } = req.nextUrl;
|
||||
|
||||
console.log("token", token);
|
||||
console.log("onboarded", token?.onboarded);
|
||||
|
||||
// If no session, send user to sign-in page
|
||||
if (!token) {
|
||||
return NextResponse.redirect(new URL("/", req.url));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue