|
| 1 | +import { Link, Section, Text } from '@react-email/components' |
| 2 | +import { baseStyles } from '@/components/emails/_styles' |
| 3 | +import { EmailLayout } from '@/components/emails/components' |
| 4 | +import { UPGRADE_REASON_COPY, type UpgradeReason } from '@/lib/billing/upgrade-reasons' |
| 5 | +import { getBrandConfig } from '@/ee/whitelabeling' |
| 6 | + |
| 7 | +interface LimitThresholdEmailProps { |
| 8 | + /** `warning` = approaching the limit (~80%); `reached` = at/over the limit. */ |
| 9 | + kind: 'warning' | 'reached' |
| 10 | + /** Limit category, drives the shared copy. */ |
| 11 | + reason: UpgradeReason |
| 12 | + userName?: string |
| 13 | + /** Pre-formatted current usage, e.g. "4.2 GB", "48,000 rows", "9 seats". */ |
| 14 | + usageLabel: string |
| 15 | + /** Pre-formatted limit, e.g. "5 GB", "50,000 rows", "10 seats". */ |
| 16 | + limitLabel: string |
| 17 | + percentUsed: number |
| 18 | + upgradeLink: string |
| 19 | +} |
| 20 | + |
| 21 | +/** |
| 22 | + * Single template for the per-category usage-limit emails (storage, tables, |
| 23 | + * seats). Copy comes from {@link UPGRADE_REASON_COPY} so the email language |
| 24 | + * matches the upgrade-page header the user lands on. |
| 25 | + */ |
| 26 | +export function LimitThresholdEmail({ |
| 27 | + kind, |
| 28 | + reason, |
| 29 | + userName, |
| 30 | + usageLabel, |
| 31 | + limitLabel, |
| 32 | + percentUsed, |
| 33 | + upgradeLink, |
| 34 | +}: LimitThresholdEmailProps) { |
| 35 | + const brand = getBrandConfig() |
| 36 | + const copy = UPGRADE_REASON_COPY[reason] |
| 37 | + const lead = kind === 'reached' ? copy.reachedLead : copy.warningLead |
| 38 | + const previewText = `${brand.name}: ${lead}` |
| 39 | + |
| 40 | + return ( |
| 41 | + <EmailLayout preview={previewText} showUnsubscribe={true}> |
| 42 | + <Text style={{ ...baseStyles.paragraph, marginTop: 0 }}> |
| 43 | + {userName ? `Hi ${userName},` : 'Hi,'} |
| 44 | + </Text> |
| 45 | + |
| 46 | + <Text style={baseStyles.paragraph}> |
| 47 | + {lead} Upgrade your plan for more {copy.noun}. |
| 48 | + </Text> |
| 49 | + |
| 50 | + <Section style={baseStyles.infoBox}> |
| 51 | + <Text style={baseStyles.infoBoxTitle}>Usage</Text> |
| 52 | + <Text style={baseStyles.infoBoxList}> |
| 53 | + {usageLabel} of {limitLabel} used ({percentUsed}%) |
| 54 | + </Text> |
| 55 | + </Section> |
| 56 | + |
| 57 | + {/* Divider */} |
| 58 | + <div style={baseStyles.divider} /> |
| 59 | + |
| 60 | + <Link href={upgradeLink} style={{ textDecoration: 'none' }}> |
| 61 | + <Text style={baseStyles.button}>Upgrade</Text> |
| 62 | + </Link> |
| 63 | + |
| 64 | + {/* Divider */} |
| 65 | + <div style={baseStyles.divider} /> |
| 66 | + |
| 67 | + <Text style={{ ...baseStyles.footerText, textAlign: 'left' }}> |
| 68 | + {kind === 'reached' |
| 69 | + ? 'One-time notification at 100% usage.' |
| 70 | + : 'One-time notification at 80% usage.'} |
| 71 | + </Text> |
| 72 | + </EmailLayout> |
| 73 | + ) |
| 74 | +} |
| 75 | + |
| 76 | +export default LimitThresholdEmail |
0 commit comments