1
0
mirror of https://github.com/pocket-id/pocket-id.git synced 2026-02-15 13:25:04 +00:00

refactor: use react email for email templates (#734)

Co-authored-by: Alessandro (Ale) Segala <43508+ItalyPaleAle@users.noreply.github.com>
Co-authored-by: Elias Schneider <login@eliasschneider.com>
This commit is contained in:
Kyle Mendell
2025-08-31 11:54:13 -05:00
committed by GitHub
parent 6c843228eb
commit 802754c24c
33 changed files with 5092 additions and 336 deletions

View File

@@ -0,0 +1,55 @@
import { Text } from "@react-email/components";
import { BaseTemplate } from "../components/base-template";
import CardHeader from "../components/card-header";
import { sharedPreviewProps, sharedTemplateProps } from "../props";
interface ApiKeyExpiringData {
name: string;
apiKeyName: string;
expiresAt: string;
}
interface ApiKeyExpiringEmailProps {
logoURL: string;
appName: string;
data: ApiKeyExpiringData;
}
export const ApiKeyExpiringEmail = ({
logoURL,
appName,
data,
}: ApiKeyExpiringEmailProps) => (
<BaseTemplate logoURL={logoURL} appName={appName}>
<CardHeader title="API Key Expiring Soon" warning />
<Text>
Hello {data.name}, <br />
This is a reminder that your API key <strong>
{data.apiKeyName}
</strong>{" "}
will expire on <strong>{data.expiresAt}</strong>.
</Text>
<Text>Please generate a new API key if you need continued access.</Text>
</BaseTemplate>
);
export default ApiKeyExpiringEmail;
ApiKeyExpiringEmail.TemplateProps = {
...sharedTemplateProps,
data: {
name: "{{.Data.Name}}",
apiKeyName: "{{.Data.APIKeyName}}",
expiresAt: '{{.Data.ExpiresAt.Format "2006-01-02 15:04:05 MST"}}',
},
};
ApiKeyExpiringEmail.PreviewProps = {
...sharedPreviewProps,
data: {
name: "Elias Schneider",
apiKeyName: "My API Key",
expiresAt: "September 30, 2024",
},
};

View File

@@ -0,0 +1,104 @@
import { Column, Heading, Row, Text } from "@react-email/components";
import { BaseTemplate } from "../components/base-template";
import CardHeader from "../components/card-header";
import { sharedPreviewProps, sharedTemplateProps } from "../props";
interface SignInData {
city?: string;
country?: string;
ipAddress: string;
device: string;
dateTime: string;
}
interface NewSignInEmailProps {
logoURL: string;
appName: string;
data: SignInData;
}
export const NewSignInEmail = ({
logoURL,
appName,
data,
}: NewSignInEmailProps) => (
<BaseTemplate logoURL={logoURL} appName={appName}>
<CardHeader title="New Sign-In Detected" warning />
<Text>
Your {appName} account was recently accessed from a new IP address or
browser. If you recognize this activity, no further action is required.
</Text>
<Heading
style={{
fontSize: "1rem",
fontWeight: "bold",
margin: "30px 0 10px 0",
}}
as="h4"
>
Details
</Heading>
<Row>
<Column style={detailsBoxStyle}>
<Text style={detailsLabelStyle}>Approximate Location</Text>
<Text style={detailsBoxValueStyle}>
{data.city}, {data.country}
</Text>
</Column>
<Column style={detailsBoxStyle}>
<Text style={detailsLabelStyle}>IP Address</Text>
<Text style={detailsBoxValueStyle}>{data.ipAddress}</Text>
</Column>
</Row>
<Row style={{ marginTop: "10px" }}>
<Column style={detailsBoxStyle}>
<Text style={detailsLabelStyle}>Device</Text>
<Text style={detailsBoxValueStyle}>{data.device}</Text>
</Column>
<Column style={detailsBoxStyle}>
<Text style={detailsLabelStyle}>Sign-In Time</Text>
<Text style={detailsBoxValueStyle}>{data.dateTime}</Text>
</Column>
</Row>
</BaseTemplate>
);
export default NewSignInEmail;
const detailsBoxStyle = {
width: "225px",
};
const detailsLabelStyle = {
margin: 0,
fontSize: "12px",
color: "gray",
};
const detailsBoxValueStyle = {
margin: 0,
};
NewSignInEmail.TemplateProps = {
...sharedTemplateProps,
data: {
city: "{{.Data.City}}",
country: "{{.Data.Country}}",
ipAddress: "{{.Data.IPAddress}}",
device: "{{.Data.Device}}",
dateTime: '{{.Data.DateTime.Format "January 2, 2006 at 3:04 PM MST"}}',
},
};
NewSignInEmail.PreviewProps = {
...sharedPreviewProps,
data: {
city: "San Francisco",
country: "USA",
ipAddress: "127.0.0.1",
device: "Chrome on macOS",
dateTime: "2024-01-01 12:00 PM UTC",
},
};

View File

@@ -0,0 +1,71 @@
import { Link, Text } from "@react-email/components";
import { BaseTemplate } from "../components/base-template";
import { Button } from "../components/button";
import CardHeader from "../components/card-header";
import { sharedPreviewProps, sharedTemplateProps } from "../props";
interface OneTimeAccessData {
code: string;
loginLink: string;
buttonCodeLink: string;
expirationString: string;
}
interface OneTimeAccessEmailProps {
logoURL: string;
appName: string;
data: OneTimeAccessData;
}
export const OneTimeAccessEmail = ({
logoURL,
appName,
data,
}: OneTimeAccessEmailProps) => (
<BaseTemplate logoURL={logoURL} appName={appName}>
<CardHeader title="Your Login Code" />
<Text>
Click the button below to sign in to {appName} with a login code.
<br />
Or visit{" "}
<Link href={data.loginLink} style={linkStyle}>
{data.loginLink}
</Link>{" "}
and enter the code <strong>{data.code}</strong>.
<br />
<br />
This code expires in {data.expirationString}.
</Text>
<Button href={data.buttonCodeLink}>Sign In</Button>
</BaseTemplate>
);
export default OneTimeAccessEmail;
const linkStyle = {
color: "#000",
textDecoration: "underline",
fontFamily: "Arial, sans-serif",
};
OneTimeAccessEmail.TemplateProps = {
...sharedTemplateProps,
data: {
code: "{{.Data.Code}}",
loginLink: "{{.Data.LoginLink}}",
buttonCodeLink: "{{.Data.LoginLinkWithCode}}",
expirationString: "{{.Data.ExpirationString}}",
},
};
OneTimeAccessEmail.PreviewProps = {
...sharedPreviewProps,
data: {
code: "123456",
loginLink: "https://example.com/login",
buttonCodeLink: "https://example.com/login?code=123456",
expirationString: "15 minutes",
},
};

View File

@@ -0,0 +1,26 @@
import { Text } from "@react-email/components";
import { BaseTemplate } from "../components/base-template";
import CardHeader from "../components/card-header";
import { sharedPreviewProps, sharedTemplateProps } from "../props";
interface TestEmailProps {
logoURL: string;
appName: string;
}
export const TestEmail = ({ logoURL, appName }: TestEmailProps) => (
<BaseTemplate logoURL={logoURL} appName={appName}>
<CardHeader title="Test Email" />
<Text>Your email setup is working correctly!</Text>
</BaseTemplate>
);
export default TestEmail;
TestEmail.TemplateProps = {
...sharedTemplateProps,
};
TestEmail.PreviewProps = {
...sharedPreviewProps,
};