@learncard/email-templates 1.0.1 → 1.0.3

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 (77) hide show
  1. package/README.md +43 -43
  2. package/dist/previews/account-approved-scenarios.d.ts +2 -1
  3. package/dist/previews/account-approved-scenarios.d.ts.map +1 -1
  4. package/dist/previews/endorsement-request-scenarios.d.ts +2 -1
  5. package/dist/previews/endorsement-request-scenarios.d.ts.map +1 -1
  6. package/dist/previews/guardian-approval-scenarios.d.ts +2 -1
  7. package/dist/previews/guardian-approval-scenarios.d.ts.map +1 -1
  8. package/dist/previews/guardian-credential-scenarios.d.ts +2 -1
  9. package/dist/previews/guardian-credential-scenarios.d.ts.map +1 -1
  10. package/dist/previews/inbox-claim-scenarios.d.ts +2 -1
  11. package/dist/previews/inbox-claim-scenarios.d.ts.map +1 -1
  12. package/dist/previews/recovery-key-scenarios.d.ts +2 -1
  13. package/dist/previews/recovery-key-scenarios.d.ts.map +1 -1
  14. package/dist/previews/verification-code-scenarios.d.ts +2 -1
  15. package/dist/previews/verification-code-scenarios.d.ts.map +1 -1
  16. package/dist/templates/account-approved.d.ts +1 -1
  17. package/dist/templates/account-approved.d.ts.map +1 -1
  18. package/dist/templates/credential-awaiting-guardian.d.ts +1 -1
  19. package/dist/templates/credential-awaiting-guardian.d.ts.map +1 -1
  20. package/dist/templates/email-verification.d.ts +1 -1
  21. package/dist/templates/email-verification.d.ts.map +1 -1
  22. package/dist/templates/endorsement-request.d.ts +1 -1
  23. package/dist/templates/endorsement-request.d.ts.map +1 -1
  24. package/dist/templates/guardian-approval.d.ts +1 -1
  25. package/dist/templates/guardian-approval.d.ts.map +1 -1
  26. package/dist/templates/guardian-approved-claim.d.ts +1 -1
  27. package/dist/templates/guardian-approved-claim.d.ts.map +1 -1
  28. package/dist/templates/guardian-credential-approval.d.ts +1 -1
  29. package/dist/templates/guardian-credential-approval.d.ts.map +1 -1
  30. package/dist/templates/guardian-email-otp.d.ts +1 -1
  31. package/dist/templates/guardian-email-otp.d.ts.map +1 -1
  32. package/dist/templates/guardian-rejected-credential.d.ts +1 -1
  33. package/dist/templates/guardian-rejected-credential.d.ts.map +1 -1
  34. package/dist/templates/inbox-claim.d.ts +1 -1
  35. package/dist/templates/inbox-claim.d.ts.map +1 -1
  36. package/dist/templates/recovery-key.d.ts +1 -1
  37. package/dist/templates/recovery-key.d.ts.map +1 -1
  38. package/dist/templates/verification-code.d.ts +1 -1
  39. package/dist/templates/verification-code.d.ts.map +1 -1
  40. package/dist/templates/verification-code.js +9 -9
  41. package/dist/templates/verification-code.js.map +1 -1
  42. package/package.json +49 -39
  43. package/src/__tests__/render.test.ts +432 -0
  44. package/src/__tests__/sms.test.ts +95 -0
  45. package/src/__tests__/tenant-registry.test.ts +257 -0
  46. package/src/branding.ts +61 -0
  47. package/src/components/CodeBlock.tsx +61 -0
  48. package/src/components/EmailButton.tsx +36 -0
  49. package/src/components/IssuerLogo.tsx +41 -0
  50. package/src/components/Layout.tsx +192 -0
  51. package/src/components/LinkFallback.tsx +50 -0
  52. package/src/index.ts +50 -0
  53. package/src/previews/_fixtures.tsx +51 -0
  54. package/src/previews/account-approved-scenarios.tsx +31 -0
  55. package/src/previews/endorsement-request-scenarios.tsx +50 -0
  56. package/src/previews/guardian-approval-scenarios.tsx +39 -0
  57. package/src/previews/guardian-credential-scenarios.tsx +88 -0
  58. package/src/previews/inbox-claim-scenarios.tsx +66 -0
  59. package/src/previews/recovery-key-scenarios.tsx +32 -0
  60. package/src/previews/verification-code-scenarios.tsx +60 -0
  61. package/src/render.ts +409 -0
  62. package/src/sms.ts +68 -0
  63. package/src/templates/account-approved.tsx +105 -0
  64. package/src/templates/credential-awaiting-guardian.tsx +137 -0
  65. package/src/templates/email-verification.tsx +110 -0
  66. package/src/templates/endorsement-request.tsx +157 -0
  67. package/src/templates/guardian-approval.tsx +122 -0
  68. package/src/templates/guardian-approved-claim.tsx +114 -0
  69. package/src/templates/guardian-credential-approval.tsx +127 -0
  70. package/src/templates/guardian-email-otp.tsx +101 -0
  71. package/src/templates/guardian-rejected-credential.tsx +103 -0
  72. package/src/templates/inbox-claim.tsx +141 -0
  73. package/src/templates/index.ts +35 -0
  74. package/src/templates/recovery-key.tsx +102 -0
  75. package/src/templates/verification-code.tsx +164 -0
  76. package/src/tenant-registry.ts +204 -0
  77. package/LICENSE +0 -21
package/src/index.ts ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @learncard/email-templates
3
+ *
4
+ * Git-managed, tenant-branded email and SMS templates for LearnCard services.
5
+ *
6
+ * Usage:
7
+ * import { renderEmail, renderSms, resolveBranding } from '@learncard/email-templates';
8
+ *
9
+ * const { html, text, subject } = await renderEmail('inbox-claim', branding, {
10
+ * claimUrl: 'https://...',
11
+ * credential: { name: 'Badge' },
12
+ * issuer: { name: 'Acme' },
13
+ * });
14
+ */
15
+
16
+ // Branding
17
+ export { resolveBranding, DEFAULT_BRANDING } from './branding';
18
+ export type { TenantBranding } from './branding';
19
+
20
+ // Email rendering
21
+ export { renderEmail } from './render';
22
+ export type { RenderedEmail, TemplateId, TemplateDataMap } from './render';
23
+ export type {
24
+ VerificationCodeData,
25
+ EmailVerificationData,
26
+ InboxClaimData,
27
+ GuardianApprovalData,
28
+ AccountApprovedData,
29
+ RecoveryKeyData,
30
+ EndorsementRequestData,
31
+ CredentialAwaitingGuardianData,
32
+ GuardianApprovedClaimData,
33
+ GuardianCredentialApprovalData,
34
+ GuardianEmailOtpData,
35
+ GuardianRejectedCredentialData,
36
+ } from './render';
37
+
38
+ // SMS rendering
39
+ export { renderSms } from './sms';
40
+ export type { SmsTemplateId, SmsTemplateDataMap, SmsInboxClaimData, SmsVerificationData } from './sms';
41
+
42
+ // Server-side tenant resolution
43
+ export { resolveTenantFromRequest, registerOriginMapping, registerTenantBranding } from './tenant-registry';
44
+ export type { ResolvedTenant, RequestHeaders } from './tenant-registry';
45
+
46
+ // Template components are intentionally NOT re-exported from the barrel.
47
+ // They contain JSX (.tsx) and would force every transitive consumer to
48
+ // configure `jsx` in their tsconfig. Use renderEmail() / renderSms() instead.
49
+ // For direct component access (testing / preview), import from
50
+ // '@learncard/email-templates/src/templates' explicitly.
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Shared preview fixtures — reusable branding configs and data objects
3
+ * for multi-scenario email previews.
4
+ */
5
+
6
+ import * as React from 'react';
7
+
8
+ import { DEFAULT_BRANDING, resolveBranding } from '../branding';
9
+ import type { TenantBranding } from '../branding';
10
+
11
+ // ---------------------------------------------------------------------------
12
+ // Branding presets
13
+ // ---------------------------------------------------------------------------
14
+
15
+ export const LEARNCARD_BRANDING = DEFAULT_BRANDING;
16
+
17
+ export const VETPASS_BRANDING: TenantBranding = resolveBranding({
18
+ brandName: 'VetPass',
19
+ logoUrl: 'https://vetpass.app/assets/icon/icon.png',
20
+ logoAlt: 'VetPass',
21
+ primaryColor: '#1B5E20',
22
+ primaryTextColor: '#ffffff',
23
+ supportEmail: 'support@vetpass.app',
24
+ websiteUrl: 'https://www.vetpass.app',
25
+ appUrl: 'https://vetpass.app',
26
+ fromDomain: 'vetpass.app',
27
+ copyrightHolder: 'VetPass',
28
+ });
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // Scenario divider — renders a labeled horizontal rule between scenarios
32
+ // ---------------------------------------------------------------------------
33
+
34
+ export const ScenarioDivider: React.FC<{ label: string }> = ({ label }) => (
35
+ <div
36
+ style={{
37
+ padding: '24px 0 16px',
38
+ textAlign: 'center',
39
+ fontFamily: 'ui-monospace, monospace',
40
+ fontSize: 11,
41
+ fontWeight: 600,
42
+ color: '#6b7280',
43
+ letterSpacing: '0.05em',
44
+ textTransform: 'uppercase',
45
+ borderTop: '2px dashed #d1d5db',
46
+ marginTop: 48,
47
+ }}
48
+ >
49
+ {label}
50
+ </div>
51
+ );
@@ -0,0 +1,31 @@
1
+ /**
2
+ * account-approved — all preview scenarios stacked.
3
+ */
4
+
5
+ import * as React from 'react';
6
+
7
+ import { AccountApproved } from '../templates/account-approved';
8
+ import { LEARNCARD_BRANDING, VETPASS_BRANDING, ScenarioDivider } from './_fixtures';
9
+
10
+ export default function AccountApprovedScenarios() {
11
+ return (
12
+ <>
13
+ <ScenarioDivider label="With user display name" />
14
+ <AccountApproved
15
+ branding={LEARNCARD_BRANDING}
16
+ user={{ displayName: 'Jane Doe' }}
17
+ />
18
+
19
+ <ScenarioDivider label="No user info (fallback greeting)" />
20
+ <AccountApproved
21
+ branding={LEARNCARD_BRANDING}
22
+ />
23
+
24
+ <ScenarioDivider label="VetPass tenant branding" />
25
+ <AccountApproved
26
+ branding={VETPASS_BRANDING}
27
+ user={{ displayName: 'Sgt. Alex Rivera' }}
28
+ />
29
+ </>
30
+ );
31
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * endorsement-request — all preview scenarios stacked.
3
+ */
4
+
5
+ import * as React from 'react';
6
+
7
+ import { EndorsementRequest } from '../templates/endorsement-request';
8
+ import { LEARNCARD_BRANDING, VETPASS_BRANDING, ScenarioDivider } from './_fixtures';
9
+
10
+ export default function EndorsementRequestScenarios() {
11
+ return (
12
+ <>
13
+ <ScenarioDivider label="Full — issuer + credential + message + recipient" />
14
+ <EndorsementRequest
15
+ branding={LEARNCARD_BRANDING}
16
+ shareLink="https://learncard.app/share/xyz789"
17
+ recipient={{ name: 'Dr. Emily Chen' }}
18
+ issuer={{ name: 'John Doe', logoUrl: 'https://cdn.filestackcontent.com/J6suaVcQ467W9o1k48Kj' }}
19
+ credential={{ name: 'Professional Teaching Certificate' }}
20
+ message="I would greatly appreciate your endorsement of my teaching credential. We worked together at Springfield Academy for 3 years."
21
+ />
22
+
23
+ <ScenarioDivider label="Minimal — no recipient name, no credential, no message" />
24
+ <EndorsementRequest
25
+ branding={LEARNCARD_BRANDING}
26
+ shareLink="https://learncard.app/share/xyz789"
27
+ issuer={{ name: 'John Doe' }}
28
+ />
29
+
30
+ <ScenarioDivider label="With message, no credential name" />
31
+ <EndorsementRequest
32
+ branding={LEARNCARD_BRANDING}
33
+ shareLink="https://learncard.app/share/xyz789"
34
+ recipient={{ name: 'Dr. Emily Chen' }}
35
+ issuer={{ name: 'John Doe' }}
36
+ message="Would you be willing to endorse my professional qualifications?"
37
+ />
38
+
39
+ <ScenarioDivider label="VetPass tenant branding" />
40
+ <EndorsementRequest
41
+ branding={VETPASS_BRANDING}
42
+ shareLink="https://vetpass.app/share/abc456"
43
+ recipient={{ name: 'Col. Sarah Mitchell' }}
44
+ issuer={{ name: 'Sgt. Alex Rivera' }}
45
+ credential={{ name: 'Leadership Training Certificate' }}
46
+ message="Requesting your endorsement for my leadership training completed at Fort Bragg."
47
+ />
48
+ </>
49
+ );
50
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * guardian-approval — all preview scenarios stacked.
3
+ */
4
+
5
+ import * as React from 'react';
6
+
7
+ import { GuardianApproval } from '../templates/guardian-approval';
8
+ import { LEARNCARD_BRANDING, VETPASS_BRANDING, ScenarioDivider } from './_fixtures';
9
+
10
+ export default function GuardianApprovalScenarios() {
11
+ return (
12
+ <>
13
+ <ScenarioDivider label="Full — requester name + guardian email" />
14
+ <GuardianApproval
15
+ branding={LEARNCARD_BRANDING}
16
+ approvalUrl="https://learncard.app/approve?token=abc123"
17
+ approvalToken="abc123"
18
+ requester={{ displayName: 'Alex Smith', profileId: 'alex-smith-123' }}
19
+ guardian={{ email: 'parent@example.com' }}
20
+ />
21
+
22
+ <ScenarioDivider label="Minimal — no requester name (fallback to 'Someone')" />
23
+ <GuardianApproval
24
+ branding={LEARNCARD_BRANDING}
25
+ approvalUrl="https://learncard.app/approve?token=abc123"
26
+ approvalToken="abc123"
27
+ />
28
+
29
+ <ScenarioDivider label="VetPass tenant branding" />
30
+ <GuardianApproval
31
+ branding={VETPASS_BRANDING}
32
+ approvalUrl="https://vetpass.app/approve?token=xyz789"
33
+ approvalToken="xyz789"
34
+ requester={{ displayName: 'Jamie Rodriguez' }}
35
+ guardian={{ email: 'guardian@example.com' }}
36
+ />
37
+ </>
38
+ );
39
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Guardian credential flow — approval, awaiting, approved, rejected scenarios.
3
+ */
4
+
5
+ import * as React from 'react';
6
+
7
+ import { GuardianCredentialApproval } from '../templates/guardian-credential-approval';
8
+ import { CredentialAwaitingGuardian } from '../templates/credential-awaiting-guardian';
9
+ import { GuardianApprovedClaim } from '../templates/guardian-approved-claim';
10
+ import { GuardianRejectedCredential } from '../templates/guardian-rejected-credential';
11
+ import { GuardianEmailOtp } from '../templates/guardian-email-otp';
12
+ import { LEARNCARD_BRANDING, VETPASS_BRANDING, ScenarioDivider } from './_fixtures';
13
+
14
+ export default function GuardianCredentialScenarios() {
15
+ return (
16
+ <>
17
+ <ScenarioDivider label="Guardian credential approval — full" />
18
+ <GuardianCredentialApproval
19
+ branding={LEARNCARD_BRANDING}
20
+ approvalUrl="https://learncard.app/guardian/approve?token=abc123"
21
+ approvalToken="abc123"
22
+ issuer={{ name: 'Springfield School District', logoUrl: 'https://cdn.filestackcontent.com/J6suaVcQ467W9o1k48Kj' }}
23
+ credential={{ name: 'Perfect Attendance Award' }}
24
+ recipient={{ email: 'student@example.com' }}
25
+ />
26
+
27
+ <ScenarioDivider label="Guardian credential approval — minimal (no issuer logo)" />
28
+ <GuardianCredentialApproval
29
+ branding={LEARNCARD_BRANDING}
30
+ approvalUrl="https://learncard.app/guardian/approve?token=abc123"
31
+ approvalToken="abc123"
32
+ credential={{ name: 'Science Fair Winner' }}
33
+ recipient={{ email: 'kid@example.com' }}
34
+ />
35
+
36
+ <ScenarioDivider label="Credential awaiting guardian — full" />
37
+ <CredentialAwaitingGuardian
38
+ branding={LEARNCARD_BRANDING}
39
+ issuer={{ name: 'Springfield School District', logoUrl: 'https://cdn.filestackcontent.com/J6suaVcQ467W9o1k48Kj' }}
40
+ credential={{ name: 'Perfect Attendance Award' }}
41
+ recipient={{ email: 'student@example.com' }}
42
+ />
43
+
44
+ <ScenarioDivider label="Guardian approved claim — full" />
45
+ <GuardianApprovedClaim
46
+ branding={LEARNCARD_BRANDING}
47
+ issuer={{ name: 'Springfield School District', logoUrl: 'https://cdn.filestackcontent.com/J6suaVcQ467W9o1k48Kj' }}
48
+ credential={{ name: 'Perfect Attendance Award' }}
49
+ />
50
+
51
+ <ScenarioDivider label="Guardian approved claim — no credential name" />
52
+ <GuardianApprovedClaim
53
+ branding={LEARNCARD_BRANDING}
54
+ issuer={{ name: 'Springfield School District' }}
55
+ />
56
+
57
+ <ScenarioDivider label="Guardian rejected credential — full" />
58
+ <GuardianRejectedCredential
59
+ branding={LEARNCARD_BRANDING}
60
+ issuer={{ name: 'Springfield School District' }}
61
+ credential={{ name: 'Perfect Attendance Award' }}
62
+ recipient={{ email: 'student@example.com' }}
63
+ />
64
+
65
+ <ScenarioDivider label="Guardian rejected credential — no credential name" />
66
+ <GuardianRejectedCredential
67
+ branding={LEARNCARD_BRANDING}
68
+ issuer={{ name: 'Springfield School District' }}
69
+ />
70
+
71
+ <ScenarioDivider label="Guardian email OTP" />
72
+ <GuardianEmailOtp
73
+ branding={LEARNCARD_BRANDING}
74
+ verificationCode="847293"
75
+ />
76
+
77
+ <ScenarioDivider label="VetPass — guardian credential approval" />
78
+ <GuardianCredentialApproval
79
+ branding={VETPASS_BRANDING}
80
+ approvalUrl="https://vetpass.app/guardian/approve?token=xyz789"
81
+ approvalToken="xyz789"
82
+ issuer={{ name: 'VA Medical Center' }}
83
+ credential={{ name: 'Health Records Access' }}
84
+ recipient={{ email: 'veteran@example.com' }}
85
+ />
86
+ </>
87
+ );
88
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * inbox-claim — all preview scenarios stacked.
3
+ *
4
+ * Covers: full info, minimal info, no issuer, no credential name,
5
+ * no recipient name, and custom tenant branding.
6
+ */
7
+
8
+ import * as React from 'react';
9
+
10
+ import { InboxClaim } from '../templates/inbox-claim';
11
+ import { LEARNCARD_BRANDING, VETPASS_BRANDING, ScenarioDivider } from './_fixtures';
12
+
13
+ export default function InboxClaimScenarios() {
14
+ return (
15
+ <>
16
+ <ScenarioDivider label="Full — issuer + credential + recipient" />
17
+ <InboxClaim
18
+ branding={LEARNCARD_BRANDING}
19
+ claimUrl="https://learncard.app/claim/abc123"
20
+ recipient={{ name: 'Jane Doe', email: 'jane@example.com' }}
21
+ issuer={{ name: 'Acme University', logoUrl: 'https://cdn.filestackcontent.com/J6suaVcQ467W9o1k48Kj' }}
22
+ credential={{ name: 'Bachelor of Science', type: 'Achievement' }}
23
+ />
24
+
25
+ <ScenarioDivider label="Minimal — no issuer, no credential name, no recipient name" />
26
+ <InboxClaim
27
+ branding={LEARNCARD_BRANDING}
28
+ claimUrl="https://learncard.app/claim/abc123"
29
+ />
30
+
31
+ <ScenarioDivider label="No issuer branding (no logo, no name)" />
32
+ <InboxClaim
33
+ branding={LEARNCARD_BRANDING}
34
+ claimUrl="https://learncard.app/claim/abc123"
35
+ recipient={{ name: 'Jane Doe' }}
36
+ credential={{ name: 'Professional Teaching Certificate', type: 'Achievement' }}
37
+ />
38
+
39
+ <ScenarioDivider label="Issuer name only (no logo)" />
40
+ <InboxClaim
41
+ branding={LEARNCARD_BRANDING}
42
+ claimUrl="https://learncard.app/claim/abc123"
43
+ recipient={{ name: 'Jane Doe' }}
44
+ issuer={{ name: 'Springfield School District' }}
45
+ credential={{ name: 'Perfect Attendance Award' }}
46
+ />
47
+
48
+ <ScenarioDivider label="No credential name (fallback to 'achievement')" />
49
+ <InboxClaim
50
+ branding={LEARNCARD_BRANDING}
51
+ claimUrl="https://learncard.app/claim/abc123"
52
+ recipient={{ name: 'Jane Doe' }}
53
+ issuer={{ name: 'Acme University', logoUrl: 'https://cdn.filestackcontent.com/J6suaVcQ467W9o1k48Kj' }}
54
+ />
55
+
56
+ <ScenarioDivider label="VetPass tenant branding" />
57
+ <InboxClaim
58
+ branding={VETPASS_BRANDING}
59
+ claimUrl="https://vetpass.app/claim/xyz789"
60
+ recipient={{ name: 'Sgt. Alex Rivera' }}
61
+ issuer={{ name: 'US Department of Veterans Affairs' }}
62
+ credential={{ name: 'DD-214 Service Record', type: 'record' }}
63
+ />
64
+ </>
65
+ );
66
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * recovery-key — all preview scenarios stacked.
3
+ */
4
+
5
+ import * as React from 'react';
6
+
7
+ import { RecoveryKey } from '../templates/recovery-key';
8
+ import { LEARNCARD_BRANDING, VETPASS_BRANDING, ScenarioDivider } from './_fixtures';
9
+
10
+ export default function RecoveryKeyScenarios() {
11
+ return (
12
+ <>
13
+ <ScenarioDivider label="Default — LearnCard branding" />
14
+ <RecoveryKey
15
+ branding={LEARNCARD_BRANDING}
16
+ recoveryKey="mango-delta-fox-echo-bravo-seven-lima-niner"
17
+ />
18
+
19
+ <ScenarioDivider label="Long recovery key (wrapping test)" />
20
+ <RecoveryKey
21
+ branding={LEARNCARD_BRANDING}
22
+ recoveryKey="alpha-bravo-charlie-delta-echo-foxtrot-golf-hotel-india-juliet-kilo-lima"
23
+ />
24
+
25
+ <ScenarioDivider label="VetPass tenant branding" />
26
+ <RecoveryKey
27
+ branding={VETPASS_BRANDING}
28
+ recoveryKey="sierra-tango-uniform-victor-whiskey-xray"
29
+ />
30
+ </>
31
+ );
32
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * verification-code — all variant + branding scenarios stacked.
3
+ */
4
+
5
+ import * as React from 'react';
6
+
7
+ import { VerificationCode } from '../templates/verification-code';
8
+ import { LEARNCARD_BRANDING, VETPASS_BRANDING, ScenarioDivider } from './_fixtures';
9
+
10
+ export default function VerificationCodeScenarios() {
11
+ return (
12
+ <>
13
+ <ScenarioDivider label="Login — with email" />
14
+ <VerificationCode
15
+ branding={LEARNCARD_BRANDING}
16
+ verificationCode="847293"
17
+ verificationEmail="jane@example.com"
18
+ variant="login"
19
+ />
20
+
21
+ <ScenarioDivider label="Login — no email" />
22
+ <VerificationCode
23
+ branding={LEARNCARD_BRANDING}
24
+ verificationCode="847293"
25
+ variant="login"
26
+ />
27
+
28
+ <ScenarioDivider label="Recovery email — with email" />
29
+ <VerificationCode
30
+ branding={LEARNCARD_BRANDING}
31
+ verificationCode="192837"
32
+ verificationEmail="backup@example.com"
33
+ variant="recovery-email"
34
+ />
35
+
36
+ <ScenarioDivider label="Embed verification — with email" />
37
+ <VerificationCode
38
+ branding={LEARNCARD_BRANDING}
39
+ verificationCode="564738"
40
+ verificationEmail="student@school.edu"
41
+ variant="embed-verification"
42
+ />
43
+
44
+ <ScenarioDivider label="Contact method" />
45
+ <VerificationCode
46
+ branding={LEARNCARD_BRANDING}
47
+ verificationCode="029384"
48
+ variant="contact-method"
49
+ />
50
+
51
+ <ScenarioDivider label="VetPass — login variant" />
52
+ <VerificationCode
53
+ branding={VETPASS_BRANDING}
54
+ verificationCode="738291"
55
+ verificationEmail="vet@example.com"
56
+ variant="login"
57
+ />
58
+ </>
59
+ );
60
+ }