refactor: remove email templates and consolidate locale utility functions

- Delete email template files: `email-formats.ts`, `newsletter-welcome.tsx`, `reset-password.tsx`, and `verify-email.tsx`
- Move `getLocaleFromRequest` utility function from `auth.ts` to `utils.ts`
- Update Chinese translation for newsletter and copyright text
- Improve code organization and remove redundant email-related files
This commit is contained in:
javayhu 2025-03-08 12:02:37 +08:00
parent 074a6d9f1e
commit 8c3f64d0aa
7 changed files with 21 additions and 359 deletions

View File

@ -1,61 +0,0 @@
/**
* https://demo.react.email/preview/welcome/stripe-welcome
*/
export const main = {
fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
};
export const container = {
};
export const box = {
padding: "8px",
};
export const hr = {
borderColor: "#e6ebf1",
margin: "20px 0",
};
export const paragraph = {
color: "#525f7f",
fontSize: "16px",
lineHeight: "24px",
textAlign: "left" as const,
};
export const anchor = {
color: "#556cd6",
};
export const button = {
backgroundColor: "#656ee8",
borderRadius: "5px",
color: "#fff",
fontSize: "16px",
fontWeight: "bold",
textDecoration: "none",
textAlign: "center" as const,
display: "block",
width: "100%",
padding: "10px",
};
export const footer = {
width: "100%",
color: "#8898aa",
fontSize: "12px",
lineHeight: "16px",
display: "table",
tableLayout: "fixed" as const,
};
export const footerLeft = {
display: "table-cell",
textAlign: "left" as const,
};
export const footerRight = {
display: "table-cell",
textAlign: "right" as const,
};

View File

@ -1,91 +0,0 @@
import { siteConfig } from "@/config/site";
import {
Body,
Container,
Head,
Hr,
Html,
Img,
Link,
Preview,
Section,
Text,
} from "@react-email/components";
import {
anchor,
box,
container,
footer,
footerLeft,
footerRight,
hr,
main,
paragraph,
} from "./email-formats";
import { getBaseUrl } from "@/lib/urls/get-base-url";
/**
* email for newsletter welcome
*/
export const NewsletterWelcomeEmail = ({ email }: { email: string }) => {
const unsubscribeUrl = `${getBaseUrl()}/unsubscribe?email=${encodeURIComponent(email)}`;
return (
<Html>
<Head />
<Preview>Welcome to {siteConfig.name}!</Preview>
<Body style={main}>
<Container style={container}>
<Section style={box}>
<Img
src={`${getBaseUrl()}/logo.png`}
width="32"
height="32"
alt="Logo"
/>
<Hr style={hr} />
<Text style={paragraph}>
Welcome to our community!
</Text>
<Text style={paragraph}>
We value your participation and feedback. Please don't hesitate to
reach out to us if you have any questions or suggestions.
</Text>
<Text style={paragraph}>
Thanks, <br />
The{" "}
<Link style={anchor} href={getBaseUrl()}>
{siteConfig.name}
</Link>{" "}
team
</Text>
<Hr style={hr} />
<Text style={footer}>
<span style={footerLeft}>
&copy; {new Date().getFullYear()}
&nbsp; All Rights Reserved.
</span>
<span style={footerRight}>
</span>
</Text>
<Text style={footer}>
<span>
If you wish to unsubscribe, please{" "}
<Link style={anchor} href={unsubscribeUrl} target="_blank">
click here
</Link>
.
</span>
</Text>
</Section>
</Container>
</Body>
</Html>
);
};
NewsletterWelcomeEmail.PreviewProps = {
email: "support@mksaas.com",
};
export default NewsletterWelcomeEmail;

View File

@ -1,101 +0,0 @@
import { siteConfig } from "@/config/site";
import {
Body,
Button,
Container,
Head,
Hr,
Html,
Img,
Link,
Preview,
Section,
Text,
} from "@react-email/components";
import {
anchor,
box,
button,
container,
footer,
footerLeft,
footerRight,
hr,
main,
paragraph,
} from "./email-formats";
import { getBaseUrl } from "@/lib/urls/get-base-url";
interface ResetPasswordEmailProps {
userName?: string;
resetLink?: string;
}
/**
* email for reset password
*/
export const ResetPasswordEmail = ({
userName,
resetLink,
}: ResetPasswordEmailProps) => {
return (
<Html>
<Head />
<Preview>Reset your password</Preview>
<Body style={main}>
<Container style={container}>
<Section style={box}>
<Img
src={`${getBaseUrl()}/logo.png`}
width="32"
height="32"
alt="Logo"
/>
<Hr style={hr} />
<Text style={paragraph}>Hi {userName},</Text>
<Text style={paragraph}>
Someone recently requested a password change for your account. If
this was you, you can set a new password here:
</Text>
<Button style={button} href={resetLink}>
Reset password
</Button>
<Hr style={hr} />
<Text style={paragraph}>
If you don&apos;t want to change your password or didn&apos;t
request this, just ignore and delete this message.
</Text>
<Text style={paragraph}>
To keep your account secure, please don&apos;t forward this email
to anyone.
</Text>
<Text style={paragraph}>
Thanks, <br />
The{" "}
<Link style={anchor} href={getBaseUrl()}>
{siteConfig.name}
</Link>{" "}
team
</Text>
<Hr style={hr} />
<Text style={footer}>
<span style={footerLeft}>
&copy; {new Date().getFullYear()}
&nbsp;&nbsp; All Rights Reserved.
</span>
<span style={footerRight}>
</span>
</Text>
</Section>
</Container>
</Body>
</Html>
);
};
ResetPasswordEmail.PreviewProps = {
userName: "Mksaas",
resetLink: "https://demo.mksaas.com",
} as ResetPasswordEmailProps;
export default ResetPasswordEmail;

View File

@ -1,93 +0,0 @@
import { siteConfig } from "@/config/site";
import {
Body,
Button,
Container,
Head,
Hr,
Html,
Img,
Link,
Preview,
Section,
Text,
} from "@react-email/components";
import {
anchor,
box,
button,
container,
footer,
footerLeft,
footerRight,
hr,
main,
paragraph,
} from "./email-formats";
import { getBaseUrl } from "@/lib/urls/get-base-url";
interface VerifyEmailProps {
confirmLink?: string;
}
/**
* email for verify email
*/
export const VerifyEmail = ({ confirmLink }: VerifyEmailProps) => {
return (
<Html>
<Head />
<Preview>Confirm your email address</Preview>
<Body style={main}>
<Container style={container}>
<Section style={box}>
<Img
src={`${getBaseUrl()}/logo.png`}
width="32"
height="32"
alt="Logo"
/>
<Hr style={hr} />
<Text style={paragraph}>Confirm your email address</Text>
<Text style={paragraph}>
Thanks for starting the new account creation process. We want to
make sure it's really you. Please click the confirmation link to
continue.
</Text>
<Button style={button} href={confirmLink}>
Confirm Email
</Button>
<Hr style={hr} />
<Text style={paragraph}>
If you don&apos;t want to create an account, you can ignore this
message.
</Text>
<Text style={paragraph}>
Thanks, <br />
The{" "}
<Link style={anchor} href={getBaseUrl()}>
{siteConfig.name}
</Link>{" "}
team
</Text>
<Hr style={hr} />
<Text style={footer}>
<span style={footerLeft}>
&copy; {new Date().getFullYear()}
&nbsp;&nbsp; All Rights Reserved.
</span>
<span style={footerRight}>
</span>
</Text>
</Section>
</Container>
</Body>
</Html>
);
};
VerifyEmail.PreviewProps = {
confirmLink: "https://demo.mksaas.com",
} as VerifyEmailProps;
export default VerifyEmail;

View File

@ -70,7 +70,7 @@
"mail": {
"common": {
"team": "{name} 团队",
"copyright": "版权所有 {year}。保留所有权利。"
"copyright": "版权所有 {year}"
},
"verifyEmail": {
"title": "你好, {name}.",
@ -85,7 +85,7 @@
"subject": "重置您的密码"
},
"subscribeNewsletter": {
"body": "感谢您订阅我们的邮件列表,我们将持续为您提供最新新闻和更新。",
"body": "感谢您订阅我们的邮件列表,我们将持续为您带来最新的新闻和更新。",
"subject": "感谢您的订阅"
}
}

View File

@ -1,23 +1,14 @@
import { siteConfig } from "@/config/site";
import db from "@/db/index";
import { account, session, user, verification } from "@/db/schema";
import { Locale, LOCALE_COOKIE_NAME, routing } from "@/i18n/routing";
import { send } from "@/mail/send";
import { getLocaleFromRequest } from "@/lib/utils";
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { admin } from "better-auth/plugins";
import { parse as parseCookies } from "cookie";
const from = process.env.RESEND_FROM || "delivered@resend.dev";
const getLocaleFromRequest = (request?: Request) => {
const cookies = parseCookies(request?.headers.get("cookie") ?? "");
return (
(cookies[LOCALE_COOKIE_NAME] as Locale) ??
routing.defaultLocale
);
};
export const auth = betterAuth({
appName: siteConfig.name,
database: drizzleAdapter(db, {

View File

@ -1,5 +1,7 @@
import { AppInfo } from "@/constants/app-info";
import { Locale, LOCALE_COOKIE_NAME, routing } from "@/i18n/routing";
import { type ClassValue, clsx } from "clsx";
import { parse as parseCookies } from "cookie";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
@ -61,4 +63,19 @@ export function getLocaleDate(input: string | number): string {
const month = (date.getMonth() + 1).toString().padStart(2, "0");
const day = date.getDate().toString().padStart(2, "0");
return `${year}/${month}/${day}`;
}
}
/**
* Gets the locale from a request by parsing the cookies
* If no locale is found in the cookies, returns the default locale
*
* @param request - The request to get the locale from
* @returns The locale from the request or the default locale
*/
export const getLocaleFromRequest = (request?: Request) => {
const cookies = parseCookies(request?.headers.get("cookie") ?? "");
return (
(cookies[LOCALE_COOKIE_NAME] as Locale) ??
routing.defaultLocale
);
};