additional-email-templates

This commit is contained in:
kirukib 2025-12-21 19:09:45 +03:00
parent e232c50e52
commit 9d889e6209
15 changed files with 2331 additions and 8 deletions

View File

@ -13,7 +13,11 @@ export const CustomizationPanel: React.FC<CustomizationPanelProps> = ({ active }
const [showBackgroundPicker, setShowBackgroundPicker] = useState(false);
useEffect(() => {
// Send initial config to preview
// Save to localStorage for persistence and cross-tab sync
if (typeof window !== "undefined") {
localStorage.setItem("email-branding-config", JSON.stringify(config));
// Send message for immediate updates
window.postMessage(
{
type: "CUSTOMIZATION_UPDATE",
@ -21,6 +25,14 @@ export const CustomizationPanel: React.FC<CustomizationPanelProps> = ({ active }
},
"*"
);
// Dispatch custom event for same-tab updates
window.dispatchEvent(
new CustomEvent("customization-update", {
detail: { config },
})
);
}
}, [config]);
const handleColorChange = (colorType: "primary" | "secondary" | "background") => (

5
.storybook/manager.ts Normal file
View File

@ -0,0 +1,5 @@
import { addons } from "@storybook/manager-api";
addons.setConfig({
panelPosition: "bottom",
});

View File

@ -2,6 +2,22 @@ import type { Preview } from "@storybook/react";
import { CustomizationDecorator } from "../stories/CustomizationDecorator";
import React from "react";
// Load Google Fonts for better rendering in Storybook
const googleFonts = [
"Roboto",
"Open+Sans",
"Lato",
"Montserrat",
"Poppins",
];
if (typeof document !== "undefined") {
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = `https://fonts.googleapis.com/css2?${googleFonts.map(font => `family=${font}:wght@400;600;700`).join("&")}&display=swap`;
document.head.appendChild(link);
}
const preview: Preview = {
parameters: {
actions: { argTypesRegex: "^on[A-Z].*" },

198
README.md Normal file
View File

@ -0,0 +1,198 @@
# Fortune System Email Templates
A collection of React Email templates for iGaming systems with live customization capabilities. Preview templates in Storybook and customize colors, fonts, and branding in real-time.
## Features
- 📧 **Email Templates**: 5 professional email templates for promotional and reporting purposes
- Promotional: Raffle, Referral Bonus, Deposit Bonus
- Reports: Weekly Activity Report, Monthly Activity Report
- 🎨 **Live Customization**: Real-time preview updates as you change colors and fonts
- 🎯 **Color Pickers**: Visual color pickers for primary, secondary, and background colors
- 🔤 **Font Selection**: Dropdown with 10 popular web-safe and Google Fonts
- ⚙️ **Configurable Branding**: Easy configuration through a centralized config file
- 📱 **Email Compatible**: Uses React Email components for maximum email client compatibility
- 🎭 **Storybook Preview**: Professional preview system for showcasing templates to clients
## Project Structure
```
fortune-sys-emails/
├── src/
│ ├── emails/
│ │ ├── promotional/ # Promotional email templates
│ │ └── reports/ # Report email templates
│ ├── components/ # Reusable email components
│ ├── config/ # Branding configuration
│ ├── hooks/ # React hooks
│ └── utils/ # Helper functions
├── .storybook/ # Storybook configuration
├── stories/ # Storybook stories
└── package.json
```
## Installation
1. Install dependencies:
```bash
npm install
```
2. Start Storybook:
```bash
npm run dev
```
3. Open your browser to `http://localhost:6006`
## Usage
### Viewing Templates
1. Start Storybook with `npm run dev`
2. Navigate to the "Emails" section in the Storybook sidebar
3. Browse through the available templates:
- **Promotional**: Raffle Email, Referral Bonus Email, Deposit Bonus Email
- **Reports**: Weekly Report Email, Monthly Report Email
### Customizing Branding
#### Method 1: Live Customization Panel
1. Navigate to "Customization > Customization Panel" in Storybook
2. Use the controls to:
- Select a font from the dropdown (10 popular fonts available)
- Pick colors using the color pickers:
- Primary Color
- Secondary Color
- Background Color
3. Changes are applied instantly to all email templates
4. Customizations are saved in browser localStorage for persistence
#### Method 2: Configuration File
Edit `src/config/branding.config.ts` to set default branding:
```typescript
export const defaultBrandingConfig: BrandingConfig = {
companyName: "Your Company Name",
logoUrl: "https://your-logo-url.com/logo.png",
colors: {
primary: "#0066CC",
secondary: "#00CC66",
background: "#F5F5F5",
text: "#333333",
},
font: {
family: "Arial, sans-serif",
},
contact: {
email: "support@yourcompany.com",
},
};
```
### Available Fonts
The following fonts are available in the customization panel:
- Arial
- Helvetica
- Times New Roman
- Georgia
- Verdana
- Roboto
- Open Sans
- Lato
- Montserrat
- Poppins
## Email Templates
### Promotional Templates
#### Raffle Email
- **Purpose**: Promote raffle events and contests
- **Props**: `raffleName`, `prizeAmount`, `entryDeadline`, `drawDate`, `entryLink`, `participantName`
#### Referral Bonus Email
- **Purpose**: Encourage user referrals with bonus offers
- **Props**: `referrerName`, `referralBonus`, `referredBonus`, `referralCode`, `referralLink`, `expirationDate`
#### Deposit Bonus Email
- **Purpose**: Promote deposit bonuses and special offers
- **Props**: `playerName`, `bonusPercentage`, `maxBonus`, `minimumDeposit`, `bonusCode`, `depositLink`, `expirationDate`
### Report Templates
#### Weekly Report Email
- **Purpose**: Weekly activity summary for administrators
- **Props**: `reportPeriod`, `totalDeposits`, `totalWithdrawals`, `activeUsers`, `newUsers`, `totalRevenue`, `topGames`
#### Monthly Report Email
- **Purpose**: Comprehensive monthly activity report
- **Props**: `reportMonth`, `totalDeposits`, `totalWithdrawals`, `activeUsers`, `newUsers`, `totalRevenue`, `averageDeposit`, `retentionRate`, `topGames`, `growthStats`
## Customization Workflow
1. **Open Storybook**: Run `npm run dev`
2. **Open Customization Panel**: Navigate to "Customization > Customization Panel"
3. **Customize**: Adjust colors and fonts using the controls
4. **Preview**: Navigate to any email template to see the changes
5. **Share**: Share the Storybook URL with clients for feedback
6. **Export**: Copy the customization values and update `branding.config.ts` for persistence
## Development
### Adding New Templates
1. Create a new component in `src/emails/` (appropriate subfolder)
2. Use the `EmailLayout` component as a wrapper
3. Use `useBrandingConfig` hook to access branding configuration
4. Create a story file in `stories/` directory
Example:
```typescript
import { EmailLayout } from "../../components/EmailLayout";
import { useBrandingConfig } from "../../hooks/useBrandingConfig";
export const MyNewEmail = () => {
const config = useBrandingConfig();
return (
<EmailLayout title="My Email">
{/* Your email content */}
</EmailLayout>
);
};
```
### Building
Build Storybook for static hosting:
```bash
npm run build
```
The built files will be in the `storybook-static` directory.
## Technologies Used
- **React Email**: For email-compatible React components
- **Storybook**: For component preview and documentation
- **TypeScript**: For type safety
- **React Color**: For color picker functionality
## Notes
- All templates are responsive and tested for email client compatibility
- Customizations made in the panel are stored in browser localStorage
- The configuration file (`branding.config.ts`) sets the default values
- Google Fonts (Roboto, Open Sans, Lato, Montserrat, Poppins) need to be loaded in your email system or use web-safe fonts for maximum compatibility
## License
Private project - All rights reserved

View File

@ -0,0 +1,343 @@
import {
Section,
Text,
Heading,
Hr,
Row,
Column,
} from "@react-email/components";
import { EmailLayout } from "../../components/EmailLayout";
import { useBrandingConfig } from "../../hooks/useBrandingConfig";
import { formatCurrency, formatDate } from "../../utils/emailHelpers";
interface SportsbookTicketIssuesEmailProps {
ticketId?: string;
issueType?: "void" | "cancellation" | "correction" | "settlement_error";
ticketDetails?: {
ticketNumber: string;
betType: string;
event: string;
selection: string;
stake: number;
potentialPayout: number;
status: string;
placedDate: Date | string;
};
reason?: string;
actionTaken?: string;
affectedUser?: {
username: string;
email: string;
accountId: string;
};
resolutionNotes?: string;
administrator?: string;
}
export const SportsbookTicketIssuesEmail = ({
ticketId = "TKT-2024-001234",
issueType = "void",
ticketDetails = {
ticketNumber: "TKT-2024-001234",
betType: "Single",
event: "Manchester United vs Liverpool",
selection: "Manchester United Win",
stake: 100,
potentialPayout: 250,
status: "Void",
placedDate: new Date(),
},
reason = "Event cancellation - Match postponed due to weather conditions",
actionTaken = "Ticket voided and stake refunded to user account",
affectedUser = {
username: "player123",
email: "player@example.com",
accountId: "ACC-12345",
},
resolutionNotes = "Refund processed automatically. User notified via email.",
administrator = "Admin Team",
}: SportsbookTicketIssuesEmailProps) => {
const config = useBrandingConfig();
const getIssueTypeLabel = (type: string) => {
switch (type) {
case "void":
return "Ticket Voided";
case "cancellation":
return "Ticket Cancelled";
case "correction":
return "Ticket Correction";
case "settlement_error":
return "Settlement Error";
default:
return "Ticket Issue";
}
};
const getSeverityColor = (type: string) => {
switch (type) {
case "settlement_error":
return "#dc3545"; // Red for errors
case "correction":
return "#ffc107"; // Yellow for corrections
default:
return config.colors.primary;
}
};
return (
<EmailLayout title={`⚠️ ${getIssueTypeLabel(issueType)} - ${ticketId}`}>
<Section>
<Section
style={{
backgroundColor: getSeverityColor(issueType) + "15",
padding: "20px",
borderRadius: "8px",
marginBottom: "20px",
border: `2px solid ${getSeverityColor(issueType)}`,
}}
>
<Heading
style={{
fontSize: "24px",
color: getSeverityColor(issueType),
marginTop: 0,
marginBottom: "10px",
}}
>
{getIssueTypeLabel(issueType)}
</Heading>
<Text
style={{ fontSize: "16px", fontWeight: "bold", margin: "5px 0" }}
>
Ticket ID: {ticketId}
</Text>
<Text style={{ fontSize: "14px", color: "#666666", margin: "5px 0" }}>
Issue Type: {issueType.toUpperCase()}
</Text>
</Section>
<Hr style={{ borderColor: config.colors.primary, margin: "30px 0" }} />
{/* Affected User Information */}
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
👤 Affected User
</Heading>
<Section
style={{
backgroundColor: config.colors.background,
padding: "15px",
borderRadius: "4px",
}}
>
<Row>
<Column>
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>Username:</strong> {affectedUser.username}
</Text>
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>Email:</strong> {affectedUser.email}
</Text>
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>Account ID:</strong> {affectedUser.accountId}
</Text>
</Column>
</Row>
</Section>
</Section>
{/* Ticket Details */}
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
🎫 Ticket Details
</Heading>
<Section
style={{
backgroundColor: config.colors.background,
padding: "15px",
borderRadius: "4px",
}}
>
<Row>
<Column style={{ width: "50%" }}>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Ticket Number:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Bet Type:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Event:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Selection:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Placed Date:</strong>
</Text>
</Column>
<Column>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
{ticketDetails.ticketNumber}
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
{ticketDetails.betType}
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
{ticketDetails.event}
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
{ticketDetails.selection}
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
{formatDate(ticketDetails.placedDate)}
</Text>
</Column>
</Row>
<Hr style={{ borderColor: "#ddd", margin: "15px 0" }} />
<Row>
<Column style={{ width: "50%" }}>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Stake:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Potential Payout:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Status:</strong>
</Text>
</Column>
<Column>
<Text
style={{
fontSize: "14px",
fontWeight: "bold",
color: config.colors.primary,
margin: "8px 0",
}}
>
{formatCurrency(ticketDetails.stake)}
</Text>
<Text
style={{
fontSize: "14px",
fontWeight: "bold",
color: config.colors.secondary,
margin: "8px 0",
}}
>
{formatCurrency(ticketDetails.potentialPayout)}
</Text>
<Text
style={{
fontSize: "14px",
fontWeight: "bold",
color: getSeverityColor(issueType),
margin: "8px 0",
}}
>
{ticketDetails.status}
</Text>
</Column>
</Row>
</Section>
</Section>
{/* Issue Information */}
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
📋 Issue Information
</Heading>
<Section
style={{
backgroundColor: "#fff3cd",
padding: "15px",
borderRadius: "4px",
border: "1px solid #ffc107",
}}
>
<Text
style={{
fontSize: "14px",
fontWeight: "bold",
margin: "0 0 10px 0",
}}
>
Reason:
</Text>
<Text style={{ fontSize: "14px", margin: "0 0 15px 0" }}>
{reason}
</Text>
<Text
style={{
fontSize: "14px",
fontWeight: "bold",
margin: "0 0 10px 0",
}}
>
Action Taken:
</Text>
<Text style={{ fontSize: "14px", margin: "0 0 15px 0" }}>
{actionTaken}
</Text>
{resolutionNotes && (
<>
<Text
style={{
fontSize: "14px",
fontWeight: "bold",
margin: "0 0 10px 0",
}}
>
Resolution Notes:
</Text>
<Text style={{ fontSize: "14px", margin: 0 }}>
{resolutionNotes}
</Text>
</>
)}
</Section>
</Section>
<Hr style={{ borderColor: config.colors.primary, margin: "30px 0" }} />
<Text
style={{ fontSize: "12px", color: "#666666", fontStyle: "italic" }}
>
This is an automated notification from the {config.companyName}{" "}
sportsbook system.
<br />
Processed by: {administrator}
<br />
Timestamp: {new Date().toLocaleString()}
</Text>
</Section>
</EmailLayout>
);
};

View File

@ -0,0 +1,300 @@
import { Section, Text, Heading, Hr, Row, Column } from "@react-email/components";
import { EmailLayout } from "../../components/EmailLayout";
import { useBrandingConfig } from "../../hooks/useBrandingConfig";
import { formatDate } from "../../utils/emailHelpers";
interface SystemAlertEmailProps {
alertId?: string;
alertType?: "critical" | "warning" | "info" | "maintenance";
alertTitle?: string;
alertDescription?: string;
affectedSystems?: string[];
severity?: "high" | "medium" | "low";
detectedAt?: Date | string;
resolvedAt?: Date | string;
status?: "active" | "resolved" | "investigating";
actionRequired?: string;
technicalDetails?: string;
incidentNumber?: string;
}
export const SystemAlertEmail = ({
alertId = "ALERT-2024-001",
alertType = "warning",
alertTitle = "High Transaction Volume Detected",
alertDescription = "Transaction processing system is experiencing higher than normal load. Response times may be slightly delayed.",
affectedSystems = ["Payment Gateway", "Transaction Processor", "User Accounts"],
severity = "medium",
detectedAt = new Date(),
resolvedAt,
status = "investigating",
actionRequired = "Monitor system performance and scale resources if needed.",
technicalDetails = "CPU usage: 85%, Memory usage: 72%, Response time: 1.2s (avg)",
incidentNumber = "INC-2024-1234",
}: SystemAlertEmailProps) => {
const config = useBrandingConfig();
const getAlertColor = (type: string) => {
switch (type) {
case "critical":
return "#dc3545"; // Red
case "warning":
return "#ffc107"; // Yellow
case "maintenance":
return "#17a2b8"; // Blue
case "info":
return config.colors.primary;
default:
return config.colors.primary;
}
};
const getSeverityColor = (severity: string) => {
switch (severity) {
case "high":
return "#dc3545";
case "medium":
return "#ffc107";
case "low":
return "#28a745";
default:
return config.colors.primary;
}
};
const getStatusColor = (status: string) => {
switch (status) {
case "resolved":
return "#28a745";
case "investigating":
return "#ffc107";
case "active":
return "#dc3545";
default:
return config.colors.primary;
}
};
return (
<EmailLayout title={`🔔 System Alert - ${alertTitle}`}>
<Section>
<Section
style={{
backgroundColor: getAlertColor(alertType) + "15",
padding: "20px",
borderRadius: "8px",
marginBottom: "20px",
border: `2px solid ${getAlertColor(alertType)}`,
}}
>
<Heading
style={{
fontSize: "24px",
color: getAlertColor(alertType),
marginTop: 0,
marginBottom: "10px",
}}
>
{alertTitle}
</Heading>
<Row>
<Column>
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>Alert ID:</strong> {alertId}
</Text>
{incidentNumber && (
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>Incident #:</strong> {incidentNumber}
</Text>
)}
</Column>
<Column>
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>Type:</strong> {alertType.toUpperCase()}
</Text>
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>Severity:</strong>{" "}
<span style={{ color: getSeverityColor(severity), fontWeight: "bold" }}>
{severity.toUpperCase()}
</span>
</Text>
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>Status:</strong>{" "}
<span style={{ color: getStatusColor(status), fontWeight: "bold" }}>
{status.toUpperCase()}
</span>
</Text>
</Column>
</Row>
</Section>
<Hr style={{ borderColor: config.colors.primary, margin: "30px 0" }} />
{/* Alert Description */}
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
📋 Alert Description
</Heading>
<Section
style={{
backgroundColor: config.colors.background,
padding: "15px",
borderRadius: "4px",
}}
>
<Text style={{ fontSize: "14px", lineHeight: "22px", margin: 0 }}>
{alertDescription}
</Text>
</Section>
</Section>
{/* Affected Systems */}
{affectedSystems && affectedSystems.length > 0 && (
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
🔧 Affected Systems
</Heading>
<Section
style={{
backgroundColor: config.colors.background,
padding: "15px",
borderRadius: "4px",
}}
>
<ul style={{ margin: 0, paddingLeft: "20px" }}>
{affectedSystems.map((system, index) => (
<li key={index} style={{ fontSize: "14px", margin: "8px 0" }}>
{system}
</li>
))}
</ul>
</Section>
</Section>
)}
{/* Timeline */}
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
Timeline
</Heading>
<Section
style={{
backgroundColor: config.colors.background,
padding: "15px",
borderRadius: "4px",
}}
>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Detected At:</strong> {formatDate(detectedAt)} (
{new Date(detectedAt).toLocaleTimeString()})
</Text>
{resolvedAt && (
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Resolved At:</strong> {formatDate(resolvedAt)} (
{new Date(resolvedAt).toLocaleTimeString()})
</Text>
)}
{!resolvedAt && (
<Text style={{ fontSize: "14px", margin: "8px 0", color: "#ffc107" }}>
<strong>Status:</strong> Under Investigation
</Text>
)}
</Section>
</Section>
{/* Technical Details */}
{technicalDetails && (
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
🔍 Technical Details
</Heading>
<Section
style={{
backgroundColor: "#f8f9fa",
padding: "15px",
borderRadius: "4px",
border: "1px solid #dee2e6",
}}
>
<Text
style={{
fontSize: "13px",
fontFamily: "monospace",
lineHeight: "20px",
margin: 0,
whiteSpace: "pre-wrap",
}}
>
{technicalDetails}
</Text>
</Section>
</Section>
)}
{/* Action Required */}
{actionRequired && (
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
Action Required
</Heading>
<Section
style={{
backgroundColor: "#fff3cd",
padding: "15px",
borderRadius: "4px",
border: "1px solid #ffc107",
}}
>
<Text style={{ fontSize: "14px", margin: 0 }}>{actionRequired}</Text>
</Section>
</Section>
)}
<Hr style={{ borderColor: config.colors.primary, margin: "30px 0" }} />
<Text style={{ fontSize: "12px", color: "#666666", fontStyle: "italic" }}>
This is an automated system alert from {config.companyName}.
<br />
Timestamp: {new Date().toLocaleString()}
<br />
Please monitor the system dashboard for updates.
</Text>
</Section>
</EmailLayout>
);
};

View File

@ -0,0 +1,247 @@
import { Section, Text, Heading, Hr } from "@react-email/components";
import { EmailLayout } from "../../components/EmailLayout";
import { useBrandingConfig } from "../../hooks/useBrandingConfig";
import { formatDate } from "../../utils/emailHelpers";
interface UserSuspensionEmailProps {
userId?: string;
username?: string;
email?: string;
suspensionType?: "temporary" | "permanent" | "warning";
suspensionReason?: string;
suspensionDuration?: number; // in days
suspensionStartDate?: Date | string;
suspensionEndDate?: Date | string;
violationDetails?: string[];
administrator?: string;
appealInformation?: string;
}
export const UserSuspensionEmail = ({
userId = "ACC-12345",
username = "player123",
email = "player@example.com",
suspensionType = "temporary",
suspensionReason = "Violation of terms of service - Suspicious betting patterns detected",
suspensionDuration = 30,
suspensionStartDate = new Date(),
suspensionEndDate = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
violationDetails = [
"Multiple accounts detected",
"Violation of betting rules",
"Suspicious activity patterns",
],
administrator = "Security Team",
appealInformation = "To appeal this decision, please contact support@example.com within 7 days.",
}: UserSuspensionEmailProps) => {
const config = useBrandingConfig();
const getSuspensionColor = (type: string) => {
switch (type) {
case "permanent":
return "#dc3545"; // Red
case "temporary":
return "#ffc107"; // Yellow
case "warning":
return "#17a2b8"; // Blue
default:
return config.colors.primary;
}
};
const getSuspensionLabel = (type: string) => {
switch (type) {
case "permanent":
return "Permanent Suspension";
case "temporary":
return "Temporary Suspension";
case "warning":
return "Account Warning";
default:
return "Account Action";
}
};
return (
<EmailLayout title={`🚫 ${getSuspensionLabel(suspensionType)} - Action Required`}>
<Section>
<Section
style={{
backgroundColor: getSuspensionColor(suspensionType) + "15",
padding: "20px",
borderRadius: "8px",
marginBottom: "20px",
border: `2px solid ${getSuspensionColor(suspensionType)}`,
}}
>
<Heading
style={{
fontSize: "24px",
color: getSuspensionColor(suspensionType),
marginTop: 0,
marginBottom: "10px",
}}
>
{getSuspensionLabel(suspensionType)}
</Heading>
<Text style={{ fontSize: "16px", fontWeight: "bold", margin: "5px 0" }}>
User: {username}
</Text>
<Text style={{ fontSize: "14px", color: "#666666", margin: "5px 0" }}>
Account ID: {userId}
</Text>
</Section>
<Hr style={{ borderColor: config.colors.primary, margin: "30px 0" }} />
{/* User Information */}
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
👤 Account Information
</Heading>
<Section
style={{
backgroundColor: config.colors.background,
padding: "15px",
borderRadius: "4px",
}}
>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Username:</strong> {username}
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Email:</strong> {email}
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Account ID:</strong> {userId}
</Text>
</Section>
</Section>
{/* Suspension Details */}
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
Suspension Details
</Heading>
<Section
style={{
backgroundColor: "#fff3cd",
padding: "15px",
borderRadius: "4px",
border: "1px solid #ffc107",
}}
>
<Text style={{ fontSize: "14px", fontWeight: "bold", margin: "0 0 10px 0" }}>
Reason:
</Text>
<Text style={{ fontSize: "14px", margin: "0 0 20px 0" }}>{suspensionReason}</Text>
{suspensionType === "temporary" && (
<>
<Text style={{ fontSize: "14px", fontWeight: "bold", margin: "0 0 10px 0" }}>
Suspension Period:
</Text>
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>Start Date:</strong> {formatDate(suspensionStartDate)}
</Text>
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>End Date:</strong> {formatDate(suspensionEndDate)}
</Text>
<Text style={{ fontSize: "14px", margin: "5px 0 0 0" }}>
<strong>Duration:</strong> {suspensionDuration} days
</Text>
</>
)}
{suspensionType === "permanent" && (
<Text style={{ fontSize: "14px", margin: "10px 0 0 0", fontWeight: "bold" }}>
This suspension is permanent. Your account access has been revoked indefinitely.
</Text>
)}
</Section>
</Section>
{/* Violation Details */}
{violationDetails && violationDetails.length > 0 && (
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
📋 Violation Details
</Heading>
<Section
style={{
backgroundColor: config.colors.background,
padding: "15px",
borderRadius: "4px",
}}
>
<ul style={{ margin: 0, paddingLeft: "20px" }}>
{violationDetails.map((detail, index) => (
<li key={index} style={{ fontSize: "14px", margin: "8px 0" }}>
{detail}
</li>
))}
</ul>
</Section>
</Section>
)}
{/* Appeal Information */}
{appealInformation && (
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
📞 Appeal Process
</Heading>
<Section
style={{
backgroundColor: config.colors.primary + "10",
padding: "15px",
borderRadius: "4px",
border: `1px solid ${config.colors.primary}`,
}}
>
<Text style={{ fontSize: "14px", margin: 0 }}>{appealInformation}</Text>
</Section>
</Section>
)}
<Hr style={{ borderColor: config.colors.primary, margin: "30px 0" }} />
<Text style={{ fontSize: "12px", color: "#666666", fontStyle: "italic" }}>
This is an automated notification from the {config.companyName} security system.
<br />
Processed by: {administrator}
<br />
Timestamp: {new Date().toLocaleString()}
</Text>
</Section>
</EmailLayout>
);
};

View File

@ -0,0 +1,139 @@
import { Section, Text, Heading, Hr } from "@react-email/components";
import { EmailLayout } from "../../components/EmailLayout";
import { Button } from "../../components/Button";
import { useBrandingConfig } from "../../hooks/useBrandingConfig";
interface AccountVerificationEmailProps {
playerName?: string;
verificationLink?: string;
verificationCode?: string;
expirationTime?: number; // in hours
supportEmail?: string;
}
export const AccountVerificationEmail = ({
playerName = "John",
verificationLink = "https://example.com/verify?token=abc123",
verificationCode,
expirationTime = 24,
supportEmail,
}: AccountVerificationEmailProps) => {
const config = useBrandingConfig();
return (
<EmailLayout title="✅ Verify Your Account">
<Section>
<Text style={{ fontSize: "18px", lineHeight: "26px", marginBottom: "20px" }}>
Hi {playerName},
</Text>
<Text style={{ fontSize: "16px", lineHeight: "24px", marginBottom: "20px" }}>
Thank you for signing up with {config.companyName}! To complete your registration and
start playing, please verify your email address.
</Text>
<Section
style={{
backgroundColor: config.colors.primary + "10",
padding: "20px",
borderRadius: "8px",
margin: "30px 0",
border: `2px solid ${config.colors.primary}`,
textAlign: "center" as const,
}}
>
<Text
style={{
fontSize: "14px",
color: config.colors.text,
margin: "0 0 20px 0",
fontWeight: "bold",
}}
>
Click the button below to verify your email address:
</Text>
<Button href={verificationLink}>Verify Email Address</Button>
</Section>
{verificationCode && (
<Section
style={{
backgroundColor: config.colors.background,
padding: "20px",
borderRadius: "8px",
margin: "30px 0",
}}
>
<Text
style={{
fontSize: "14px",
color: config.colors.text,
margin: "0 0 10px 0",
fontWeight: "bold",
}}
>
Or enter this verification code:
</Text>
<Text
style={{
fontSize: "28px",
fontWeight: "bold",
color: config.colors.primary,
letterSpacing: "4px",
textAlign: "center" as const,
fontFamily: "monospace",
margin: 0,
}}
>
{verificationCode}
</Text>
</Section>
)}
<Hr style={{ borderColor: config.colors.primary, margin: "30px 0" }} />
<Section
style={{
backgroundColor: "#fff3cd",
padding: "15px",
borderRadius: "4px",
border: "1px solid #ffc107",
marginBottom: "20px",
}}
>
<Text style={{ fontSize: "13px", color: "#856404", margin: "0 0 5px 0", fontWeight: "bold" }}>
Important:
</Text>
<Text style={{ fontSize: "13px", color: "#856404", margin: 0 }}>
This verification link will expire in {expirationTime} hours. Please verify your
account as soon as possible.
</Text>
</Section>
<Text style={{ fontSize: "14px", lineHeight: "22px", marginBottom: "10px" }}>
If the button doesn't work, copy and paste this link into your browser:
</Text>
<Text
style={{
fontSize: "12px",
color: config.colors.primary,
wordBreak: "break-all",
marginBottom: "20px",
}}
>
{verificationLink}
</Text>
<Text style={{ fontSize: "14px", lineHeight: "22px", marginTop: "20px" }}>
If you didn't create an account with {config.companyName}, please ignore this email.
</Text>
{supportEmail && (
<Text style={{ fontSize: "12px", color: "#666666", marginTop: "30px" }}>
Need help? Contact us at {supportEmail}
</Text>
)}
</Section>
</EmailLayout>
);
};

View File

@ -0,0 +1,274 @@
import { Section, Text, Heading, Hr, Row, Column } from "@react-email/components";
import { EmailLayout } from "../../components/EmailLayout";
import { useBrandingConfig } from "../../hooks/useBrandingConfig";
import { formatCurrency, formatDate } from "../../utils/emailHelpers";
interface BetConfirmationEmailProps {
playerName?: string;
ticketNumber?: string;
betType?: string;
selections?: Array<{
event: string;
market: string;
selection: string;
odds: number;
}>;
stake?: number;
potentialPayout?: number;
currency?: string;
placedDate?: Date | string;
status?: "pending" | "won" | "lost" | "void";
accountLink?: string;
}
export const BetConfirmationEmail = ({
playerName = "John",
ticketNumber = "TKT-2024-001234",
betType = "Accumulator",
selections = [
{
event: "Manchester United vs Liverpool",
market: "Match Result",
selection: "Manchester United Win",
odds: 2.5,
},
{
event: "Barcelona vs Real Madrid",
market: "Total Goals",
selection: "Over 2.5 Goals",
odds: 1.8,
},
],
stake = 50,
potentialPayout = 225,
currency = "USD",
placedDate = new Date(),
status = "pending",
accountLink = "https://example.com/account",
}: BetConfirmationEmailProps) => {
const config = useBrandingConfig();
const getStatusColor = (status: string) => {
switch (status) {
case "won":
return config.colors.secondary;
case "lost":
return "#dc3545";
case "void":
return "#6c757d";
default:
return config.colors.primary;
}
};
const getStatusLabel = (status: string) => {
switch (status) {
case "won":
return "Won";
case "lost":
return "Lost";
case "void":
return "Void";
default:
return "Pending";
}
};
return (
<EmailLayout title="🎫 Bet Confirmation">
<Section>
<Text style={{ fontSize: "18px", lineHeight: "26px", marginBottom: "20px" }}>
Hi {playerName},
</Text>
<Text style={{ fontSize: "16px", lineHeight: "24px", marginBottom: "20px" }}>
Your bet has been successfully placed! Good luck!
</Text>
<Section
style={{
backgroundColor: config.colors.primary + "15",
padding: "20px",
borderRadius: "8px",
margin: "30px 0",
border: `2px solid ${config.colors.primary}`,
textAlign: "center" as const,
}}
>
<Text
style={{
fontSize: "18px",
color: config.colors.text,
margin: "0 0 10px 0",
fontWeight: "bold",
}}
>
Ticket Number
</Text>
<Text
style={{
fontSize: "32px",
fontWeight: "bold",
color: config.colors.primary,
letterSpacing: "2px",
fontFamily: "monospace",
margin: "5px 0",
}}
>
{ticketNumber}
</Text>
<Text
style={{
fontSize: "16px",
color: getStatusColor(status),
fontWeight: "bold",
margin: "10px 0 0 0",
}}
>
Status: {getStatusLabel(status)}
</Text>
</Section>
<Hr style={{ borderColor: config.colors.primary, margin: "30px 0" }} />
{/* Bet Details */}
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
📋 Bet Details
</Heading>
<Section
style={{
backgroundColor: config.colors.background,
padding: "15px",
borderRadius: "4px",
}}
>
<Row>
<Column style={{ width: "50%" }}>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Bet Type:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Stake:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Potential Payout:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Placed Date:</strong>
</Text>
</Column>
<Column>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>{betType}</Text>
<Text
style={{
fontSize: "14px",
fontWeight: "bold",
color: config.colors.primary,
margin: "8px 0",
}}
>
{formatCurrency(stake, currency)}
</Text>
<Text
style={{
fontSize: "14px",
fontWeight: "bold",
color: config.colors.secondary,
margin: "8px 0",
}}
>
{formatCurrency(potentialPayout, currency)}
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
{formatDate(placedDate)}
</Text>
</Column>
</Row>
</Section>
</Section>
{/* Selections */}
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
🎯 Your Selections
</Heading>
{selections.map((selection, index) => (
<Section
key={index}
style={{
backgroundColor: config.colors.background,
padding: "15px",
borderRadius: "4px",
marginBottom: "10px",
borderLeft: `4px solid ${config.colors.primary}`,
}}
>
<Text style={{ fontSize: "14px", fontWeight: "bold", margin: "0 0 5px 0" }}>
Selection {index + 1}
</Text>
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>Event:</strong> {selection.event}
</Text>
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>Market:</strong> {selection.market}
</Text>
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>Selection:</strong> {selection.selection}
</Text>
<Text
style={{
fontSize: "14px",
fontWeight: "bold",
color: config.colors.primary,
margin: "5px 0 0 0",
}}
>
Odds: {selection.odds.toFixed(2)}
</Text>
</Section>
))}
</Section>
<Section
style={{
backgroundColor: "#d1ecf1",
padding: "15px",
borderRadius: "4px",
border: "1px solid #bee5eb",
marginBottom: "20px",
}}
>
<Text style={{ fontSize: "13px", color: "#0c5460", margin: 0 }}>
<strong>Note:</strong> This bet is now active. You'll receive an email notification
once the bet is settled.
</Text>
</Section>
<Text style={{ fontSize: "14px", lineHeight: "22px", marginTop: "20px" }}>
Good luck with your bet! We'll keep you updated on the outcome.
</Text>
<Text style={{ fontSize: "14px", lineHeight: "22px", marginTop: "30px" }}>
Best regards,
<br />
The {config.companyName} Team
</Text>
</Section>
</EmailLayout>
);
};

View File

@ -0,0 +1,200 @@
import { Section, Text, Heading, Hr, Row, Column } from "@react-email/components";
import { EmailLayout } from "../../components/EmailLayout";
import { Button } from "../../components/Button";
import { useBrandingConfig } from "../../hooks/useBrandingConfig";
import { formatCurrency, formatDate } from "../../utils/emailHelpers";
interface DepositConfirmationEmailProps {
playerName?: string;
transactionId?: string;
amount?: number;
currency?: string;
paymentMethod?: string;
depositDate?: Date | string;
newBalance?: number;
bonusAmount?: number;
bonusCode?: string;
accountLink?: string;
}
export const DepositConfirmationEmail = ({
playerName = "John",
transactionId = "TXN-2024-001234",
amount = 100,
currency = "USD",
paymentMethod = "Credit Card",
depositDate = new Date(),
newBalance = 500,
bonusAmount,
bonusCode,
accountLink = "https://example.com/account",
}: DepositConfirmationEmailProps) => {
const config = useBrandingConfig();
return (
<EmailLayout title="✅ Deposit Confirmed">
<Section>
<Text style={{ fontSize: "18px", lineHeight: "26px", marginBottom: "20px" }}>
Hi {playerName},
</Text>
<Text style={{ fontSize: "16px", lineHeight: "24px", marginBottom: "20px" }}>
Your deposit has been successfully processed and credited to your account!
</Text>
<Section
style={{
backgroundColor: config.colors.secondary + "15",
padding: "25px",
borderRadius: "8px",
margin: "30px 0",
border: `2px solid ${config.colors.secondary}`,
}}
>
<Heading
style={{
fontSize: "28px",
color: config.colors.secondary,
marginTop: 0,
marginBottom: "15px",
textAlign: "center" as const,
}}
>
{formatCurrency(amount, currency)} Deposited
</Heading>
</Section>
<Hr style={{ borderColor: config.colors.primary, margin: "30px 0" }} />
{/* Transaction Details */}
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
📋 Transaction Details
</Heading>
<Section
style={{
backgroundColor: config.colors.background,
padding: "15px",
borderRadius: "4px",
}}
>
<Row>
<Column style={{ width: "50%" }}>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Transaction ID:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Amount:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Payment Method:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Date:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>New Balance:</strong>
</Text>
</Column>
<Column>
<Text style={{ fontSize: "14px", margin: "8px 0", fontFamily: "monospace" }}>
{transactionId}
</Text>
<Text
style={{
fontSize: "14px",
fontWeight: "bold",
color: config.colors.secondary,
margin: "8px 0",
}}
>
{formatCurrency(amount, currency)}
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>{paymentMethod}</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
{formatDate(depositDate)}
</Text>
<Text
style={{
fontSize: "14px",
fontWeight: "bold",
color: config.colors.primary,
margin: "8px 0",
}}
>
{formatCurrency(newBalance, currency)}
</Text>
</Column>
</Row>
</Section>
</Section>
{/* Bonus Information */}
{bonusAmount && bonusAmount > 0 && (
<Section
style={{
backgroundColor: config.colors.primary + "10",
padding: "20px",
borderRadius: "8px",
margin: "30px 0",
border: `2px solid ${config.colors.primary}`,
textAlign: "center" as const,
}}
>
<Text
style={{
fontSize: "18px",
color: config.colors.primary,
fontWeight: "bold",
margin: "0 0 10px 0",
}}
>
🎁 Bonus Added!
</Text>
<Text
style={{
fontSize: "24px",
color: config.colors.primary,
fontWeight: "bold",
margin: "5px 0",
}}
>
+{formatCurrency(bonusAmount, currency)}
</Text>
{bonusCode && (
<Text style={{ fontSize: "14px", color: "#666666", margin: "10px 0 0 0" }}>
Applied bonus code: {bonusCode}
</Text>
)}
</Section>
)}
<Section style={{ textAlign: "center" as const, margin: "30px 0" }}>
<Button href={accountLink}>View Account</Button>
</Section>
<Text style={{ fontSize: "14px", lineHeight: "22px", marginTop: "20px" }}>
Your funds are now available in your account. Start playing your favorite games and
good luck!
</Text>
<Text style={{ fontSize: "14px", lineHeight: "22px", marginTop: "30px" }}>
Best regards,
<br />
The {config.companyName} Team
</Text>
<Text style={{ fontSize: "12px", color: "#666666", marginTop: "20px", fontStyle: "italic" }}>
If you did not make this deposit, please contact our support team immediately.
</Text>
</Section>
</EmailLayout>
);
};

View File

@ -0,0 +1,151 @@
import { Section, Text, Heading, Hr } from "@react-email/components";
import { EmailLayout } from "../../components/EmailLayout";
import { Button } from "../../components/Button";
import { useBrandingConfig } from "../../hooks/useBrandingConfig";
interface PasswordResetEmailProps {
playerName?: string;
resetLink?: string;
resetCode?: string;
expirationTime?: number; // in minutes
ipAddress?: string;
supportEmail?: string;
}
export const PasswordResetEmail = ({
playerName = "John",
resetLink = "https://example.com/reset-password?token=abc123",
resetCode,
expirationTime = 30,
ipAddress,
supportEmail,
}: PasswordResetEmailProps) => {
const config = useBrandingConfig();
return (
<EmailLayout title="🔐 Password Reset Request">
<Section>
<Text style={{ fontSize: "18px", lineHeight: "26px", marginBottom: "20px" }}>
Hi {playerName},
</Text>
<Text style={{ fontSize: "16px", lineHeight: "24px", marginBottom: "20px" }}>
We received a request to reset your password for your {config.companyName} account. If
you made this request, click the button below to reset your password.
</Text>
<Section
style={{
backgroundColor: config.colors.primary + "10",
padding: "20px",
borderRadius: "8px",
margin: "30px 0",
border: `2px solid ${config.colors.primary}`,
textAlign: "center" as const,
}}
>
<Button href={resetLink}>Reset Password</Button>
</Section>
{resetCode && (
<Section
style={{
backgroundColor: config.colors.background,
padding: "20px",
borderRadius: "8px",
margin: "30px 0",
}}
>
<Text
style={{
fontSize: "14px",
color: config.colors.text,
margin: "0 0 10px 0",
fontWeight: "bold",
}}
>
Or enter this reset code:
</Text>
<Text
style={{
fontSize: "28px",
fontWeight: "bold",
color: config.colors.primary,
letterSpacing: "4px",
textAlign: "center" as const,
fontFamily: "monospace",
margin: 0,
}}
>
{resetCode}
</Text>
</Section>
)}
<Hr style={{ borderColor: config.colors.primary, margin: "30px 0" }} />
<Section
style={{
backgroundColor: "#fff3cd",
padding: "15px",
borderRadius: "4px",
border: "1px solid #ffc107",
marginBottom: "20px",
}}
>
<Text style={{ fontSize: "13px", color: "#856404", margin: "0 0 5px 0", fontWeight: "bold" }}>
Important:
</Text>
<Text style={{ fontSize: "13px", color: "#856404", margin: 0 }}>
This password reset link will expire in {expirationTime} minutes for security
purposes.
</Text>
</Section>
<Text style={{ fontSize: "14px", lineHeight: "22px", marginBottom: "10px" }}>
If the button doesn't work, copy and paste this link into your browser:
</Text>
<Text
style={{
fontSize: "12px",
color: config.colors.primary,
wordBreak: "break-all",
marginBottom: "20px",
}}
>
{resetLink}
</Text>
<Section
style={{
backgroundColor: "#d1ecf1",
padding: "15px",
borderRadius: "4px",
border: "1px solid #bee5eb",
marginBottom: "20px",
}}
>
<Text style={{ fontSize: "13px", color: "#0c5460", margin: "0 0 5px 0", fontWeight: "bold" }}>
🔒 Security Notice:
</Text>
<Text style={{ fontSize: "13px", color: "#0c5460", margin: 0 }}>
If you didn't request a password reset, please ignore this email. Your password will
remain unchanged.
</Text>
{ipAddress && (
<Text style={{ fontSize: "12px", color: "#0c5460", margin: "5px 0 0 0" }}>
Request originated from: {ipAddress}
</Text>
)}
</Section>
{supportEmail && (
<Text style={{ fontSize: "12px", color: "#666666", marginTop: "30px" }}>
If you have concerns about your account security, please contact us immediately at{" "}
{supportEmail}
</Text>
)}
</Section>
</EmailLayout>
);
};

View File

@ -0,0 +1,150 @@
import { Section, Text, Heading, Hr } from "@react-email/components";
import { EmailLayout } from "../../components/EmailLayout";
import { Button } from "../../components/Button";
import { useBrandingConfig } from "../../hooks/useBrandingConfig";
interface WelcomeEmailProps {
playerName?: string;
username?: string;
welcomeBonus?: number;
bonusCode?: string;
depositLink?: string;
supportEmail?: string;
}
export const WelcomeEmail = ({
playerName = "John",
username = "player123",
welcomeBonus = 100,
bonusCode = "WELCOME100",
depositLink = "https://example.com/deposit",
supportEmail,
}: WelcomeEmailProps) => {
const config = useBrandingConfig();
return (
<EmailLayout title="🎉 Welcome to the Team!">
<Section>
<Text style={{ fontSize: "18px", lineHeight: "26px", marginBottom: "20px" }}>
Hi {playerName},
</Text>
<Text style={{ fontSize: "16px", lineHeight: "24px", marginBottom: "20px" }}>
Welcome to {config.companyName}! We're thrilled to have you join our gaming community.
Get ready for an exciting experience with top-notch games, amazing bonuses, and
fantastic rewards.
</Text>
{/* Welcome Bonus Section */}
{welcomeBonus > 0 && (
<Section
style={{
backgroundColor: config.colors.secondary + "20",
padding: "25px",
borderRadius: "8px",
margin: "30px 0",
border: `2px solid ${config.colors.secondary}`,
textAlign: "center" as const,
}}
>
<Heading
style={{
fontSize: "32px",
color: config.colors.secondary,
marginTop: 0,
marginBottom: "10px",
fontWeight: "bold",
}}
>
${welcomeBonus} Welcome Bonus!
</Heading>
{bonusCode && (
<Text
style={{
fontSize: "18px",
color: config.colors.text,
margin: "10px 0",
fontWeight: "bold",
}}
>
Use code: {bonusCode}
</Text>
)}
<Text style={{ fontSize: "14px", color: "#666666", margin: "10px 0 0 0" }}>
Claim your welcome bonus on your first deposit!
</Text>
</Section>
)}
<Hr style={{ borderColor: config.colors.primary, margin: "30px 0" }} />
{/* Getting Started */}
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
🚀 Getting Started
</Heading>
<Text style={{ fontSize: "14px", lineHeight: "22px", margin: "8px 0" }}>
1. <strong>Verify your account</strong> - Check your email for verification link
</Text>
<Text style={{ fontSize: "14px", lineHeight: "22px", margin: "8px 0" }}>
2. <strong>Make your first deposit</strong> - Choose from our secure payment methods
</Text>
<Text style={{ fontSize: "14px", lineHeight: "22px", margin: "8px 0" }}>
3. <strong>Claim your bonus</strong> - Use your welcome bonus code when depositing
</Text>
<Text style={{ fontSize: "14px", lineHeight: "22px", margin: "8px 0" }}>
4. <strong>Start playing</strong> - Explore our games and enjoy!
</Text>
</Section>
{/* Account Info */}
<Section
style={{
backgroundColor: config.colors.background,
padding: "15px",
borderRadius: "4px",
marginBottom: "25px",
}}
>
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>Username:</strong> {username}
</Text>
<Text style={{ fontSize: "14px", margin: "5px 0" }}>
<strong>Account Status:</strong> Active
</Text>
</Section>
<Section style={{ textAlign: "center" as const, margin: "30px 0" }}>
<Button href={depositLink}>Make Your First Deposit</Button>
</Section>
<Text style={{ fontSize: "14px", lineHeight: "22px", marginTop: "30px" }}>
If you have any questions, our support team is available 24/7 to assist you.
</Text>
<Text style={{ fontSize: "14px", lineHeight: "22px" }}>
Best of luck and enjoy your gaming experience!
</Text>
<Text style={{ fontSize: "14px", lineHeight: "22px", marginTop: "30px" }}>
Best regards,
<br />
The {config.companyName} Team
</Text>
{supportEmail && (
<Text style={{ fontSize: "12px", color: "#666666", marginTop: "20px" }}>
Need help? Contact us at {supportEmail}
</Text>
)}
</Section>
</EmailLayout>
);
};

View File

@ -0,0 +1,213 @@
import { Section, Text, Heading, Hr, Row, Column } from "@react-email/components";
import { EmailLayout } from "../../components/EmailLayout";
import { useBrandingConfig } from "../../hooks/useBrandingConfig";
import { formatCurrency, formatDate } from "../../utils/emailHelpers";
interface WithdrawalConfirmationEmailProps {
playerName?: string;
transactionId?: string;
amount?: number;
currency?: string;
withdrawalMethod?: string;
requestDate?: Date | string;
estimatedProcessingTime?: string;
processingFee?: number;
netAmount?: number;
newBalance?: number;
accountLink?: string;
}
export const WithdrawalConfirmationEmail = ({
playerName = "John",
transactionId = "WD-2024-001234",
amount = 500,
currency = "USD",
withdrawalMethod = "Bank Transfer",
requestDate = new Date(),
estimatedProcessingTime = "3-5 business days",
processingFee = 5,
netAmount,
newBalance = 200,
accountLink = "https://example.com/account",
}: WithdrawalConfirmationEmailProps) => {
const config = useBrandingConfig();
const netWithdrawalAmount = netAmount || amount - processingFee;
return (
<EmailLayout title="✅ Withdrawal Request Confirmed">
<Section>
<Text style={{ fontSize: "18px", lineHeight: "26px", marginBottom: "20px" }}>
Hi {playerName},
</Text>
<Text style={{ fontSize: "16px", lineHeight: "24px", marginBottom: "20px" }}>
Your withdrawal request has been received and is being processed. We'll notify you once
the funds have been transferred to your account.
</Text>
<Section
style={{
backgroundColor: config.colors.primary + "15",
padding: "25px",
borderRadius: "8px",
margin: "30px 0",
border: `2px solid ${config.colors.primary}`,
}}
>
<Heading
style={{
fontSize: "28px",
color: config.colors.primary,
marginTop: 0,
marginBottom: "15px",
textAlign: "center" as const,
}}
>
{formatCurrency(amount, currency)} Withdrawal Requested
</Heading>
{processingFee > 0 && (
<Text style={{ fontSize: "14px", color: "#666666", margin: "5px 0", textAlign: "center" as const }}>
Processing Fee: {formatCurrency(processingFee, currency)}
</Text>
)}
</Section>
<Hr style={{ borderColor: config.colors.primary, margin: "30px 0" }} />
{/* Transaction Details */}
<Section style={{ marginBottom: "25px" }}>
<Heading
style={{
fontSize: "20px",
color: config.colors.text,
marginTop: "20px",
marginBottom: "15px",
}}
>
📋 Withdrawal Details
</Heading>
<Section
style={{
backgroundColor: config.colors.background,
padding: "15px",
borderRadius: "4px",
}}
>
<Row>
<Column style={{ width: "50%" }}>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Transaction ID:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Withdrawal Amount:</strong>
</Text>
{processingFee > 0 && (
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Processing Fee:</strong>
</Text>
)}
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Net Amount:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Withdrawal Method:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Request Date:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Estimated Processing:</strong>
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
<strong>Remaining Balance:</strong>
</Text>
</Column>
<Column>
<Text style={{ fontSize: "14px", margin: "8px 0", fontFamily: "monospace" }}>
{transactionId}
</Text>
<Text
style={{
fontSize: "14px",
fontWeight: "bold",
color: config.colors.primary,
margin: "8px 0",
}}
>
{formatCurrency(amount, currency)}
</Text>
{processingFee > 0 && (
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
{formatCurrency(processingFee, currency)}
</Text>
)}
<Text
style={{
fontSize: "14px",
fontWeight: "bold",
color: config.colors.secondary,
margin: "8px 0",
}}
>
{formatCurrency(netWithdrawalAmount, currency)}
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>{withdrawalMethod}</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
{formatDate(requestDate)}
</Text>
<Text style={{ fontSize: "14px", margin: "8px 0" }}>
{estimatedProcessingTime}
</Text>
<Text
style={{
fontSize: "14px",
fontWeight: "bold",
color: config.colors.text,
margin: "8px 0",
}}
>
{formatCurrency(newBalance, currency)}
</Text>
</Column>
</Row>
</Section>
</Section>
<Section
style={{
backgroundColor: "#d1ecf1",
padding: "15px",
borderRadius: "4px",
border: "1px solid #bee5eb",
marginBottom: "20px",
}}
>
<Text style={{ fontSize: "13px", color: "#0c5460", margin: "0 0 5px 0", fontWeight: "bold" }}>
Processing Information:
</Text>
<Text style={{ fontSize: "13px", color: "#0c5460", margin: 0 }}>
Your withdrawal is being processed and will be completed within{" "}
{estimatedProcessingTime}. You'll receive a notification email once the funds have
been transferred.
</Text>
</Section>
<Text style={{ fontSize: "14px", lineHeight: "22px", marginTop: "20px" }}>
If you have any questions about your withdrawal, please don't hesitate to contact our
support team.
</Text>
<Text style={{ fontSize: "14px", lineHeight: "22px", marginTop: "30px" }}>
Best regards,
<br />
The {config.companyName} Team
</Text>
<Text style={{ fontSize: "12px", color: "#666666", marginTop: "20px", fontStyle: "italic" }}>
If you did not request this withdrawal, please contact our support team immediately to
secure your account.
</Text>
</Section>
</EmailLayout>
);
};

View File

@ -61,18 +61,57 @@ export const CustomizationDecorator = ({ children }: CustomizationDecoratorProps
}
};
const handleCustomEvent = (e: CustomEvent) => {
if (e.detail?.config) {
setConfig((prev) => ({
...prev,
...e.detail.config,
colors: {
...prev.colors,
...(e.detail.config.colors || {}),
},
font: {
...prev.font,
...(e.detail.config.font || {}),
},
}));
}
};
const handleMessage = (event: MessageEvent) => {
if (event.data?.type === "CUSTOMIZATION_UPDATE") {
updateConfig(event.data.config);
}
};
// Poll localStorage for changes (for same-tab updates)
const pollInterval = setInterval(() => {
const saved = localStorage.getItem(CUSTOMIZATION_STORAGE_KEY);
if (saved) {
try {
const savedConfig = JSON.parse(saved);
setConfig((prev) => {
const prevStr = JSON.stringify(prev);
if (prevStr !== saved) {
return { ...defaultBrandingConfig, ...savedConfig };
}
return prev;
});
} catch (e) {
// Ignore parse errors
}
}
}, 500);
window.addEventListener("storage", handleStorageChange);
window.addEventListener("message", handleMessage);
window.addEventListener("customization-update" as any, handleCustomEvent as EventListener);
return () => {
clearInterval(pollInterval);
window.removeEventListener("storage", handleStorageChange);
window.removeEventListener("message", handleMessage);
window.removeEventListener("customization-update" as any, handleCustomEvent as EventListener);
};
}, [updateConfig]);

View File

@ -0,0 +1,36 @@
import type { Meta, StoryObj } from "@storybook/react";
import { CustomizationPanel } from "../.storybook/CustomizationPanel";
import React, { useState } from "react";
const meta: Meta<typeof CustomizationPanel> = {
title: "Customization/Customization Panel",
component: CustomizationPanel,
parameters: {
layout: "padded",
},
};
export default meta;
type Story = StoryObj<typeof CustomizationPanel>;
export const Panel: Story = {
render: () => {
const [active, setActive] = useState(true);
return (
<div>
<button
onClick={() => setActive(!active)}
style={{
marginBottom: "20px",
padding: "10px 20px",
fontSize: "14px",
cursor: "pointer",
}}
>
{active ? "Hide" : "Show"} Customization Panel
</button>
<CustomizationPanel active={active} />
</div>
);
},
};