shipd 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/base-package/app/globals.css +126 -0
  2. package/base-package/app/layout.tsx +53 -0
  3. package/base-package/app/page.tsx +15 -0
  4. package/base-package/base.config.json +57 -0
  5. package/base-package/components/ui/avatar.tsx +53 -0
  6. package/base-package/components/ui/badge.tsx +46 -0
  7. package/base-package/components/ui/button.tsx +59 -0
  8. package/base-package/components/ui/card.tsx +92 -0
  9. package/base-package/components/ui/chart.tsx +353 -0
  10. package/base-package/components/ui/checkbox.tsx +32 -0
  11. package/base-package/components/ui/dialog.tsx +135 -0
  12. package/base-package/components/ui/dropdown-menu.tsx +257 -0
  13. package/base-package/components/ui/form.tsx +167 -0
  14. package/base-package/components/ui/input.tsx +21 -0
  15. package/base-package/components/ui/label.tsx +24 -0
  16. package/base-package/components/ui/progress.tsx +31 -0
  17. package/base-package/components/ui/resizable.tsx +56 -0
  18. package/base-package/components/ui/select.tsx +185 -0
  19. package/base-package/components/ui/separator.tsx +28 -0
  20. package/base-package/components/ui/sheet.tsx +139 -0
  21. package/base-package/components/ui/skeleton.tsx +13 -0
  22. package/base-package/components/ui/sonner.tsx +25 -0
  23. package/base-package/components/ui/switch.tsx +31 -0
  24. package/base-package/components/ui/tabs.tsx +66 -0
  25. package/base-package/components/ui/textarea.tsx +18 -0
  26. package/base-package/components/ui/toggle-group.tsx +73 -0
  27. package/base-package/components/ui/toggle.tsx +47 -0
  28. package/base-package/components/ui/tooltip.tsx +61 -0
  29. package/base-package/components.json +21 -0
  30. package/base-package/eslint.config.mjs +16 -0
  31. package/base-package/lib/utils.ts +6 -0
  32. package/base-package/middleware.ts +12 -0
  33. package/base-package/next.config.ts +27 -0
  34. package/base-package/package.json +49 -0
  35. package/base-package/postcss.config.mjs +5 -0
  36. package/base-package/public/favicon.svg +4 -0
  37. package/base-package/tailwind.config.ts +89 -0
  38. package/base-package/tsconfig.json +27 -0
  39. package/dist/index.js +1862 -948
  40. package/features/ai-chat/README.md +258 -0
  41. package/features/ai-chat/app/api/chat/route.ts +16 -0
  42. package/features/ai-chat/app/dashboard/_components/chatbot.tsx +39 -0
  43. package/features/ai-chat/app/dashboard/chat/page.tsx +73 -0
  44. package/features/ai-chat/feature.config.json +22 -0
  45. package/features/analytics/README.md +308 -0
  46. package/features/analytics/feature.config.json +20 -0
  47. package/features/analytics/lib/posthog.ts +36 -0
  48. package/features/auth/README.md +336 -0
  49. package/features/auth/app/api/auth/[...all]/route.ts +4 -0
  50. package/features/auth/app/dashboard/layout.tsx +15 -0
  51. package/features/auth/app/dashboard/page.tsx +140 -0
  52. package/features/auth/app/sign-in/page.tsx +228 -0
  53. package/features/auth/app/sign-up/page.tsx +243 -0
  54. package/features/auth/auth-schema.ts +47 -0
  55. package/features/auth/components/auth/setup-instructions.tsx +123 -0
  56. package/features/auth/feature.config.json +33 -0
  57. package/features/auth/lib/auth-client.ts +8 -0
  58. package/features/auth/lib/auth.ts +295 -0
  59. package/features/auth/lib/email-stub.ts +55 -0
  60. package/features/auth/lib/email.ts +47 -0
  61. package/features/auth/middleware.patch.ts +43 -0
  62. package/features/database/README.md +256 -0
  63. package/features/database/db/drizzle.ts +48 -0
  64. package/features/database/db/schema.ts +21 -0
  65. package/features/database/drizzle.config.ts +13 -0
  66. package/features/database/feature.config.json +30 -0
  67. package/features/email/README.md +282 -0
  68. package/features/email/emails/components/layout.tsx +181 -0
  69. package/features/email/emails/password-reset.tsx +67 -0
  70. package/features/email/emails/payment-failed.tsx +167 -0
  71. package/features/email/emails/subscription-confirmation.tsx +129 -0
  72. package/features/email/emails/welcome.tsx +100 -0
  73. package/features/email/feature.config.json +22 -0
  74. package/features/email/lib/email.ts +118 -0
  75. package/features/file-upload/README.md +271 -0
  76. package/features/file-upload/app/api/upload-image/route.ts +64 -0
  77. package/features/file-upload/app/dashboard/upload/page.tsx +324 -0
  78. package/features/file-upload/feature.config.json +23 -0
  79. package/features/file-upload/lib/upload-image.ts +28 -0
  80. package/features/marketing-landing/README.md +266 -0
  81. package/features/marketing-landing/app/page.tsx +25 -0
  82. package/features/marketing-landing/components/homepage/cli-workflow-section.tsx +231 -0
  83. package/features/marketing-landing/components/homepage/features-section.tsx +152 -0
  84. package/features/marketing-landing/components/homepage/footer.tsx +53 -0
  85. package/features/marketing-landing/components/homepage/hero-section.tsx +112 -0
  86. package/features/marketing-landing/components/homepage/integrations.tsx +124 -0
  87. package/features/marketing-landing/components/homepage/navigation.tsx +116 -0
  88. package/features/marketing-landing/components/homepage/news-section.tsx +82 -0
  89. package/features/marketing-landing/components/homepage/pricing-section.tsx +98 -0
  90. package/features/marketing-landing/components/homepage/testimonials-section.tsx +34 -0
  91. package/features/marketing-landing/components/logos/BetterAuth.tsx +21 -0
  92. package/features/marketing-landing/components/logos/NeonPostgres.tsx +41 -0
  93. package/features/marketing-landing/components/logos/Nextjs.tsx +72 -0
  94. package/features/marketing-landing/components/logos/Polar.tsx +7 -0
  95. package/features/marketing-landing/components/logos/TailwindCSS.tsx +27 -0
  96. package/features/marketing-landing/components/logos/index.ts +6 -0
  97. package/features/marketing-landing/components/logos/shadcnui.tsx +8 -0
  98. package/features/marketing-landing/feature.config.json +23 -0
  99. package/features/payments/README.md +306 -0
  100. package/features/payments/app/api/subscription/route.ts +25 -0
  101. package/features/payments/app/dashboard/payment/_components/manage-subscription.tsx +22 -0
  102. package/features/payments/app/dashboard/payment/page.tsx +126 -0
  103. package/features/payments/app/success/page.tsx +123 -0
  104. package/features/payments/feature.config.json +31 -0
  105. package/features/payments/lib/polar-products.ts +49 -0
  106. package/features/payments/lib/subscription.ts +148 -0
  107. package/features/payments/payments-schema.ts +30 -0
  108. package/features/seo/README.md +244 -0
  109. package/features/seo/app/blog/[slug]/page.tsx +314 -0
  110. package/features/seo/app/blog/page.tsx +107 -0
  111. package/features/seo/app/robots.txt +13 -0
  112. package/features/seo/app/sitemap.ts +70 -0
  113. package/features/seo/feature.config.json +19 -0
  114. package/features/seo/lib/seo-utils.ts +163 -0
  115. package/package.json +3 -1
@@ -0,0 +1,167 @@
1
+ import { Text, Link, Section } from '@react-email/components';
2
+ import { EmailLayout, styles } from './components/layout';
3
+
4
+ interface PaymentFailedEmailProps {
5
+ planName: string;
6
+ retryDate: string;
7
+ }
8
+
9
+ export function PaymentFailedEmail({
10
+ planName,
11
+ retryDate,
12
+ }: PaymentFailedEmailProps) {
13
+ return (
14
+ <EmailLayout preview="Payment failed - Action required">
15
+ <Text style={styles.h1}>Payment Failed</Text>
16
+
17
+ <Section style={alertBox}>
18
+ <Text style={alertText}>
19
+ <strong>Action Required:</strong> We couldn't process your payment for the {planName} subscription.
20
+ </Text>
21
+ </Section>
22
+
23
+ <Text style={styles.p}>
24
+ We attempted to charge your payment method on file, but the payment was declined. This can happen for several reasons:
25
+ </Text>
26
+
27
+ <ul style={list}>
28
+ <li style={listItem}>
29
+ <Text style={listText}>Insufficient funds</Text>
30
+ </li>
31
+ <li style={listItem}>
32
+ <Text style={listText}>Expired card</Text>
33
+ </li>
34
+ <li style={listItem}>
35
+ <Text style={listText}>Card blocked or frozen</Text>
36
+ </li>
37
+ <li style={listItem}>
38
+ <Text style={listText}>Incorrect billing information</Text>
39
+ </li>
40
+ </ul>
41
+
42
+ <Text style={styles.h2}>What Happens Next?</Text>
43
+
44
+ <Section style={infoBox}>
45
+ <table style={table}>
46
+ <tbody>
47
+ <tr>
48
+ <td style={labelCell}>Next retry:</td>
49
+ <td style={valueCell}>{retryDate}</td>
50
+ </tr>
51
+ <tr>
52
+ <td style={labelCell}>Status:</td>
53
+ <td style={valueCell}>Access maintained until retry</td>
54
+ </tr>
55
+ </tbody>
56
+ </table>
57
+ </Section>
58
+
59
+ <Text style={styles.p}>
60
+ Your access to SaaS Scaffold will remain active until our next retry attempt. To avoid any interruption, please update your payment method as soon as possible.
61
+ </Text>
62
+
63
+ <Link href="https://saas-scaffold.com/dashboard/billing" style={styles.button}>
64
+ Update Payment Method
65
+ </Link>
66
+
67
+ <Text style={styles.p}>
68
+ If the payment issue isn't resolved by the retry date, your subscription will be automatically canceled and access will be revoked.
69
+ </Text>
70
+
71
+ <Section style={supportBox}>
72
+ <Text style={supportText}>
73
+ Need help? Contact our support team at{' '}
74
+ <Link href="mailto:support@saas-scaffold.com" style={supportLink}>
75
+ support@saas-scaffold.com
76
+ </Link>
77
+ </Text>
78
+ </Section>
79
+
80
+ <Text style={styles.p}>
81
+ Thanks,<br />
82
+ The SaaS Scaffold Team
83
+ </Text>
84
+ </EmailLayout>
85
+ );
86
+ }
87
+
88
+ // Additional styles
89
+ const alertBox = {
90
+ backgroundColor: '#2a1a1a',
91
+ border: '1px solid #ff5722',
92
+ borderRadius: '6px',
93
+ padding: '16px',
94
+ margin: '0 0 24px',
95
+ };
96
+
97
+ const alertText = {
98
+ fontSize: '14px',
99
+ lineHeight: '20px',
100
+ color: '#ff9a80',
101
+ margin: 0,
102
+ };
103
+
104
+ const list = {
105
+ margin: '16px 0',
106
+ padding: '0 0 0 20px',
107
+ };
108
+
109
+ const listItem = {
110
+ margin: '8px 0',
111
+ };
112
+
113
+ const listText = {
114
+ fontSize: '14px',
115
+ lineHeight: '20px',
116
+ color: '#cccccc',
117
+ margin: 0,
118
+ };
119
+
120
+ const infoBox = {
121
+ backgroundColor: '#1a1a1a',
122
+ border: '1px solid #2a2a2a',
123
+ borderRadius: '6px',
124
+ padding: '16px',
125
+ margin: '16px 0',
126
+ };
127
+
128
+ const table = {
129
+ width: '100%',
130
+ borderCollapse: 'collapse' as const,
131
+ };
132
+
133
+ const labelCell = {
134
+ fontSize: '14px',
135
+ color: '#999999',
136
+ padding: '8px 0',
137
+ width: '140px',
138
+ };
139
+
140
+ const valueCell = {
141
+ fontSize: '14px',
142
+ color: '#ffffff',
143
+ fontWeight: '600',
144
+ padding: '8px 0',
145
+ };
146
+
147
+ const supportBox = {
148
+ backgroundColor: '#1a1a1a',
149
+ border: '1px solid #2a2a2a',
150
+ borderRadius: '6px',
151
+ padding: '16px',
152
+ margin: '24px 0',
153
+ };
154
+
155
+ const supportText = {
156
+ fontSize: '14px',
157
+ lineHeight: '20px',
158
+ color: '#cccccc',
159
+ margin: 0,
160
+ };
161
+
162
+ const supportLink = {
163
+ color: '#ff5722',
164
+ textDecoration: 'none',
165
+ };
166
+
167
+ export default PaymentFailedEmail;
@@ -0,0 +1,129 @@
1
+ import { Text, Link, Section } from '@react-email/components';
2
+ import { EmailLayout, styles } from './components/layout';
3
+
4
+ interface SubscriptionConfirmationEmailProps {
5
+ planName: string;
6
+ amount: string;
7
+ }
8
+
9
+ export function SubscriptionConfirmationEmail({
10
+ planName,
11
+ amount,
12
+ }: SubscriptionConfirmationEmailProps) {
13
+ return (
14
+ <EmailLayout preview={`Your ${planName} subscription is confirmed`}>
15
+ <Text style={styles.h1}>Subscription Confirmed! 🎉</Text>
16
+
17
+ <Text style={styles.p}>
18
+ Thank you for subscribing to SaaS Scaffold! Your subscription has been successfully activated.
19
+ </Text>
20
+
21
+ <Section style={summaryBox}>
22
+ <Text style={summaryTitle}>Subscription Summary</Text>
23
+ <table style={table}>
24
+ <tbody>
25
+ <tr>
26
+ <td style={labelCell}>Plan:</td>
27
+ <td style={valueCell}>{planName}</td>
28
+ </tr>
29
+ <tr>
30
+ <td style={labelCell}>Amount:</td>
31
+ <td style={valueCell}>{amount}</td>
32
+ </tr>
33
+ <tr>
34
+ <td style={labelCell}>Billing:</td>
35
+ <td style={valueCell}>Monthly (auto-renews)</td>
36
+ </tr>
37
+ </tbody>
38
+ </table>
39
+ </Section>
40
+
41
+ <Text style={styles.h2}>What's Next?</Text>
42
+
43
+ <Text style={styles.p}>
44
+ You now have access to all premium features:
45
+ </Text>
46
+
47
+ <ul style={list}>
48
+ <li style={listItem}>
49
+ <Text style={listText}>Generate unlimited projects with our CLI</Text>
50
+ </li>
51
+ <li style={listItem}>
52
+ <Text style={listText}>Access to all premium templates</Text>
53
+ </li>
54
+ <li style={listItem}>
55
+ <Text style={listText}>Priority support and updates</Text>
56
+ </li>
57
+ <li style={listItem}>
58
+ <Text style={listText}>Exclusive community access</Text>
59
+ </li>
60
+ </ul>
61
+
62
+ <Link href="https://saas-scaffold.com/dashboard" style={styles.button}>
63
+ Go to Dashboard
64
+ </Link>
65
+
66
+ <Text style={styles.p}>
67
+ You can manage your subscription, update payment methods, or view invoices anytime from your dashboard.
68
+ </Text>
69
+
70
+ <Text style={styles.p}>
71
+ Thanks for your support!<br />
72
+ The SaaS Scaffold Team
73
+ </Text>
74
+ </EmailLayout>
75
+ );
76
+ }
77
+
78
+ // Additional styles
79
+ const summaryBox = {
80
+ backgroundColor: '#1a1a1a',
81
+ border: '1px solid #2a2a2a',
82
+ borderRadius: '6px',
83
+ padding: '24px',
84
+ margin: '24px 0',
85
+ };
86
+
87
+ const summaryTitle = {
88
+ fontSize: '18px',
89
+ fontWeight: '600',
90
+ color: '#ffffff',
91
+ margin: '0 0 16px',
92
+ };
93
+
94
+ const table = {
95
+ width: '100%',
96
+ borderCollapse: 'collapse' as const,
97
+ };
98
+
99
+ const labelCell = {
100
+ fontSize: '14px',
101
+ color: '#999999',
102
+ padding: '8px 0',
103
+ width: '100px',
104
+ };
105
+
106
+ const valueCell = {
107
+ fontSize: '14px',
108
+ color: '#ffffff',
109
+ fontWeight: '600',
110
+ padding: '8px 0',
111
+ };
112
+
113
+ const list = {
114
+ margin: '16px 0',
115
+ padding: '0 0 0 20px',
116
+ };
117
+
118
+ const listItem = {
119
+ margin: '12px 0',
120
+ };
121
+
122
+ const listText = {
123
+ fontSize: '14px',
124
+ lineHeight: '20px',
125
+ color: '#cccccc',
126
+ margin: 0,
127
+ };
128
+
129
+ export default SubscriptionConfirmationEmail;
@@ -0,0 +1,100 @@
1
+ import { Text, Link, Section } from '@react-email/components';
2
+ import { EmailLayout, styles } from './components/layout';
3
+
4
+ interface WelcomeEmailProps {
5
+ userName?: string;
6
+ }
7
+
8
+ export function WelcomeEmail({ userName = 'there' }: WelcomeEmailProps) {
9
+ return (
10
+ <EmailLayout preview="Welcome to SaaS Scaffold! Let's get you started.">
11
+ <Text style={styles.h1}>Welcome to SaaS Scaffold! 👋</Text>
12
+
13
+ <Text style={styles.p}>
14
+ Hi {userName},
15
+ </Text>
16
+
17
+ <Text style={styles.p}>
18
+ Thanks for joining SaaS Scaffold! We're excited to help you build and ship your SaaS product faster than ever.
19
+ </Text>
20
+
21
+ <Section style={cardContainer}>
22
+ <Text style={cardTitle}>What's included in your subscription:</Text>
23
+ <ul style={list}>
24
+ <li style={listItem}>
25
+ <Text style={listText}><strong>Premium Templates</strong> - Production-ready Next.js templates</Text>
26
+ </li>
27
+ <li style={listItem}>
28
+ <Text style={listText}><strong>CLI Tool</strong> - Generate projects in seconds</Text>
29
+ </li>
30
+ <li style={listItem}>
31
+ <Text style={listText}><strong>Authentication</strong> - Better Auth with Polar.sh integration</Text>
32
+ </li>
33
+ <li style={listItem}>
34
+ <Text style={listText}><strong>Billing</strong> - Subscriptions and payments pre-configured</Text>
35
+ </li>
36
+ <li style={listItem}>
37
+ <Text style={listText}><strong>Priority Support</strong> - Get help when you need it</Text>
38
+ </li>
39
+ </ul>
40
+ </Section>
41
+
42
+ <Text style={styles.h2}>Get Started</Text>
43
+
44
+ <Text style={styles.p}>
45
+ Ready to create your first project? Run this command in your terminal:
46
+ </Text>
47
+
48
+ <Section style={styles.codeBlock}>
49
+ npx saas-scaffold init my-project
50
+ </Section>
51
+
52
+ <Link href="https://saas-scaffold.com/docs/getting-started" style={styles.button}>
53
+ View Documentation
54
+ </Link>
55
+
56
+ <Text style={styles.p}>
57
+ If you have any questions or need help getting started, don't hesitate to reach out to our support team.
58
+ </Text>
59
+
60
+ <Text style={styles.p}>
61
+ Happy building!<br />
62
+ The SaaS Scaffold Team
63
+ </Text>
64
+ </EmailLayout>
65
+ );
66
+ }
67
+
68
+ // Additional styles
69
+ const cardContainer = {
70
+ backgroundColor: '#1a1a1a',
71
+ border: '1px solid #2a2a2a',
72
+ borderRadius: '6px',
73
+ padding: '24px',
74
+ margin: '24px 0',
75
+ };
76
+
77
+ const cardTitle = {
78
+ fontSize: '18px',
79
+ fontWeight: '600',
80
+ color: '#ffffff',
81
+ margin: '0 0 16px',
82
+ };
83
+
84
+ const list = {
85
+ margin: '0',
86
+ padding: '0 0 0 20px',
87
+ };
88
+
89
+ const listItem = {
90
+ margin: '12px 0',
91
+ };
92
+
93
+ const listText = {
94
+ fontSize: '14px',
95
+ lineHeight: '20px',
96
+ color: '#cccccc',
97
+ margin: 0,
98
+ };
99
+
100
+ export default WelcomeEmail;
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "email",
3
+ "version": "1.0.0",
4
+ "description": "Resend email integration with React Email templates",
5
+ "dependencies": {
6
+ "resend": "^6.6.0",
7
+ "@react-email/components": "^1.0.2",
8
+ "@react-email/render": "^2.0.0"
9
+ },
10
+ "devDependencies": {},
11
+ "envVars": [
12
+ "RESEND_API_KEY",
13
+ "EMAIL_FROM"
14
+ ],
15
+ "files": [
16
+ "lib/email.ts",
17
+ "emails/**/*"
18
+ ],
19
+ "requires": [],
20
+ "conflicts": []
21
+ }
22
+
@@ -0,0 +1,118 @@
1
+ import { Resend } from 'resend';
2
+
3
+ // Check if email is configured
4
+ const isEmailConfigured = !!process.env.RESEND_API_KEY;
5
+
6
+ if (!isEmailConfigured && process.env.NODE_ENV === 'development') {
7
+ console.warn('⚠️ Resend not configured - email sending disabled. Set RESEND_API_KEY to enable emails.');
8
+ }
9
+
10
+ export const resend = isEmailConfigured ? new Resend(process.env.RESEND_API_KEY) : null;
11
+
12
+ /**
13
+ * Send an email using Resend
14
+ * @param to - Recipient email address
15
+ * @param subject - Email subject line
16
+ * @param react - React email component
17
+ * @param from - Sender email (defaults to noreply@yourdomain.com)
18
+ */
19
+ export async function sendEmail({
20
+ to,
21
+ subject,
22
+ react,
23
+ from = process.env.EMAIL_FROM || 'SaaS Scaffold <noreply@saas-scaffold.com>',
24
+ }: {
25
+ to: string;
26
+ subject: string;
27
+ react: React.ReactElement;
28
+ from?: string;
29
+ }) {
30
+ // Skip if email is not configured
31
+ if (!resend) {
32
+ console.log(`📧 Email not sent (Resend not configured): ${subject} to ${to}`);
33
+ return { success: true, skipped: true };
34
+ }
35
+
36
+ try {
37
+ const { data, error } = await resend.emails.send({
38
+ from,
39
+ to,
40
+ subject,
41
+ react,
42
+ });
43
+
44
+ if (error) {
45
+ console.error('Failed to send email:', error);
46
+ throw new Error(`Email send failed: ${error.message}`);
47
+ }
48
+
49
+ console.log('Email sent successfully:', data);
50
+ return { success: true, data };
51
+ } catch (error) {
52
+ console.error('Email send error:', error);
53
+ return {
54
+ success: false,
55
+ error: error instanceof Error ? error.message : 'Unknown error'
56
+ };
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Send welcome email to new users
62
+ */
63
+ export async function sendWelcomeEmail(email: string, name?: string) {
64
+ const { WelcomeEmail } = await import('@/emails/welcome');
65
+
66
+ return sendEmail({
67
+ to: email,
68
+ subject: 'Welcome to SaaS Scaffold!',
69
+ react: WelcomeEmail({ userName: name || 'there' }),
70
+ });
71
+ }
72
+
73
+ /**
74
+ * Send password reset email
75
+ */
76
+ export async function sendPasswordResetEmail(email: string, resetUrl: string) {
77
+ const { PasswordResetEmail } = await import('@/emails/password-reset');
78
+
79
+ return sendEmail({
80
+ to: email,
81
+ subject: 'Reset your password',
82
+ react: PasswordResetEmail({ resetUrl }),
83
+ });
84
+ }
85
+
86
+ /**
87
+ * Send subscription confirmation email
88
+ */
89
+ export async function sendSubscriptionConfirmationEmail(
90
+ email: string,
91
+ planName: string,
92
+ amount: string
93
+ ) {
94
+ const { SubscriptionConfirmationEmail } = await import('@/emails/subscription-confirmation');
95
+
96
+ return sendEmail({
97
+ to: email,
98
+ subject: `Subscription confirmed: ${planName}`,
99
+ react: SubscriptionConfirmationEmail({ planName, amount }),
100
+ });
101
+ }
102
+
103
+ /**
104
+ * Send payment failed email
105
+ */
106
+ export async function sendPaymentFailedEmail(
107
+ email: string,
108
+ planName: string,
109
+ retryDate: string
110
+ ) {
111
+ const { PaymentFailedEmail } = await import('@/emails/payment-failed');
112
+
113
+ return sendEmail({
114
+ to: email,
115
+ subject: 'Payment failed - Action required',
116
+ react: PaymentFailedEmail({ planName, retryDate }),
117
+ });
118
+ }