@learncard/email-templates 1.2.1 → 1.2.2

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 (42) hide show
  1. package/dist/i18n.d.ts +15 -0
  2. package/dist/i18n.d.ts.map +1 -1
  3. package/dist/i18n.js +31 -0
  4. package/dist/i18n.js.map +1 -1
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/previews/account-secured-scenarios.d.ts +6 -0
  9. package/dist/previews/account-secured-scenarios.d.ts.map +1 -0
  10. package/dist/previews/account-secured-scenarios.js +7 -0
  11. package/dist/previews/account-secured-scenarios.js.map +1 -0
  12. package/dist/previews/escrow-pin-sign-in-scenarios.d.ts +6 -0
  13. package/dist/previews/escrow-pin-sign-in-scenarios.d.ts.map +1 -0
  14. package/dist/previews/escrow-pin-sign-in-scenarios.js +7 -0
  15. package/dist/previews/escrow-pin-sign-in-scenarios.js.map +1 -0
  16. package/dist/render.d.ts +11 -0
  17. package/dist/render.d.ts.map +1 -1
  18. package/dist/render.js +27 -1
  19. package/dist/render.js.map +1 -1
  20. package/dist/templates/account-secured.d.ts +27 -0
  21. package/dist/templates/account-secured.d.ts.map +1 -0
  22. package/dist/templates/account-secured.js +118 -0
  23. package/dist/templates/account-secured.js.map +1 -0
  24. package/dist/templates/escrow-pin-sign-in.d.ts +24 -0
  25. package/dist/templates/escrow-pin-sign-in.d.ts.map +1 -0
  26. package/dist/templates/escrow-pin-sign-in.js +96 -0
  27. package/dist/templates/escrow-pin-sign-in.js.map +1 -0
  28. package/dist/templates/index.d.ts +21 -38
  29. package/dist/templates/index.d.ts.map +1 -1
  30. package/dist/templates/index.js +20 -14
  31. package/dist/templates/index.js.map +1 -1
  32. package/package.json +2 -2
  33. package/src/__tests__/i18n.test.ts +32 -1
  34. package/src/__tests__/render.test.ts +115 -0
  35. package/src/i18n.ts +33 -0
  36. package/src/index.ts +2 -0
  37. package/src/previews/account-secured-scenarios.tsx +41 -0
  38. package/src/previews/escrow-pin-sign-in-scenarios.tsx +52 -0
  39. package/src/render.ts +51 -0
  40. package/src/templates/account-secured.tsx +236 -0
  41. package/src/templates/escrow-pin-sign-in.tsx +197 -0
  42. package/src/templates/index.ts +95 -35
@@ -1,39 +1,22 @@
1
- export { VerificationCode, getVerificationCodeSubject } from './verification-code';
2
- export type { VerificationCodeProps, VerificationCodeVariant } from './verification-code';
3
- export { InboxClaim, getInboxClaimSubject } from './inbox-claim';
4
- export type { InboxClaimProps } from './inbox-claim';
5
- export { GuardianApproval, getGuardianApprovalSubject } from './guardian-approval';
6
- export type { GuardianApprovalProps } from './guardian-approval';
7
- export { AccountApproved, getAccountApprovedSubject } from './account-approved';
8
- export type { AccountApprovedProps } from './account-approved';
9
- export { RecoveryKey, getRecoveryKeySubject } from './recovery-key';
10
- export type { RecoveryKeyProps } from './recovery-key';
11
- export { EndorsementRequest, getEndorsementRequestSubject } from './endorsement-request';
12
- export type { EndorsementRequestProps } from './endorsement-request';
13
- export { CredentialAwaitingGuardian, getCredentialAwaitingGuardianSubject, } from './credential-awaiting-guardian';
14
- export type { CredentialAwaitingGuardianProps } from './credential-awaiting-guardian';
15
- export { GuardianApprovedClaim, getGuardianApprovedClaimSubject } from './guardian-approved-claim';
16
- export type { GuardianApprovedClaimProps } from './guardian-approved-claim';
17
- export { GuardianCredentialApproval, getGuardianCredentialApprovalSubject, } from './guardian-credential-approval';
18
- export type { GuardianCredentialApprovalProps } from './guardian-credential-approval';
19
- export { GuardianEmailOtp, getGuardianEmailOtpSubject } from './guardian-email-otp';
20
- export type { GuardianEmailOtpProps } from './guardian-email-otp';
21
- export { GuardianRejectedCredential, getGuardianRejectedCredentialSubject, } from './guardian-rejected-credential';
22
- export type { GuardianRejectedCredentialProps } from './guardian-rejected-credential';
23
- export { EmailVerification, getEmailVerificationSubject } from './email-verification';
24
- export type { EmailVerificationProps } from './email-verification';
25
- export { CredentialUpdated, getCredentialUpdatedSubject } from './credential-updated';
26
- export type { CredentialUpdatedProps } from './credential-updated';
27
- export { AccountSignInChanged, getAccountSignInChangedSubject } from './account-sign-in-changed';
28
- export type { AccountSignInChangedProps } from './account-sign-in-changed';
29
- export { EscrowHoldStarted, getEscrowHoldStartedSubject } from './escrow-hold-started';
30
- export type { EscrowHoldStartedProps } from './escrow-hold-started';
31
- export { EscrowHoldReminder, getEscrowHoldReminderSubject } from './escrow-hold-reminder';
32
- export type { EscrowHoldReminderProps } from './escrow-hold-reminder';
33
- export { EscrowHoldReleased, getEscrowHoldReleasedSubject } from './escrow-hold-released';
34
- export type { EscrowHoldReleasedProps } from './escrow-hold-released';
35
- export { EscrowHoldCancelled, getEscrowHoldCancelledSubject } from './escrow-hold-cancelled';
36
- export type { EscrowHoldCancelledProps, EscrowHoldCancelledReason } from './escrow-hold-cancelled';
37
- export { EscrowPinLocked, getEscrowPinLockedSubject } from './escrow-pin-locked';
38
- export type { EscrowPinLockedProps } from './escrow-pin-locked';
1
+ export { VerificationCode, getVerificationCodeSubject, type VerificationCodeProps, type VerificationCodeVariant, } from './verification-code';
2
+ export { InboxClaim, getInboxClaimSubject, type InboxClaimProps } from './inbox-claim';
3
+ export { GuardianApproval, getGuardianApprovalSubject, type GuardianApprovalProps, } from './guardian-approval';
4
+ export { AccountApproved, getAccountApprovedSubject, type AccountApprovedProps, } from './account-approved';
5
+ export { RecoveryKey, getRecoveryKeySubject, type RecoveryKeyProps } from './recovery-key';
6
+ export { EndorsementRequest, getEndorsementRequestSubject, type EndorsementRequestProps, } from './endorsement-request';
7
+ export { CredentialAwaitingGuardian, getCredentialAwaitingGuardianSubject, type CredentialAwaitingGuardianProps, } from './credential-awaiting-guardian';
8
+ export { GuardianApprovedClaim, getGuardianApprovedClaimSubject, type GuardianApprovedClaimProps, } from './guardian-approved-claim';
9
+ export { GuardianCredentialApproval, getGuardianCredentialApprovalSubject, type GuardianCredentialApprovalProps, } from './guardian-credential-approval';
10
+ export { GuardianEmailOtp, getGuardianEmailOtpSubject, type GuardianEmailOtpProps, } from './guardian-email-otp';
11
+ export { GuardianRejectedCredential, getGuardianRejectedCredentialSubject, type GuardianRejectedCredentialProps, } from './guardian-rejected-credential';
12
+ export { EmailVerification, getEmailVerificationSubject, type EmailVerificationProps, } from './email-verification';
13
+ export { CredentialUpdated, getCredentialUpdatedSubject, type CredentialUpdatedProps, } from './credential-updated';
14
+ export { AccountSignInChanged, getAccountSignInChangedSubject, type AccountSignInChangedProps, } from './account-sign-in-changed';
15
+ export { EscrowHoldStarted, getEscrowHoldStartedSubject, type EscrowHoldStartedProps, } from './escrow-hold-started';
16
+ export { EscrowHoldReminder, getEscrowHoldReminderSubject, type EscrowHoldReminderProps, } from './escrow-hold-reminder';
17
+ export { EscrowHoldReleased, getEscrowHoldReleasedSubject, type EscrowHoldReleasedProps, } from './escrow-hold-released';
18
+ export { EscrowHoldCancelled, getEscrowHoldCancelledSubject, type EscrowHoldCancelledProps, type EscrowHoldCancelledReason, } from './escrow-hold-cancelled';
19
+ export { EscrowPinLocked, getEscrowPinLockedSubject, type EscrowPinLockedProps, } from './escrow-pin-locked';
20
+ export { EscrowPinSignIn, getEscrowPinSignInSubject, type EscrowPinSignInProps, } from './escrow-pin-sign-in';
21
+ export { AccountSecured, getAccountSecuredSubject, type AccountSecuredProps, } from './account-secured';
39
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACnF,YAAY,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAE1F,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACjE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACnF,YAAY,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEjE,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAChF,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACpE,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,EAAE,kBAAkB,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AACzF,YAAY,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAErE,OAAO,EACH,0BAA0B,EAC1B,oCAAoC,GACvC,MAAM,gCAAgC,CAAC;AACxC,YAAY,EAAE,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AAEtF,OAAO,EAAE,qBAAqB,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAC;AACnG,YAAY,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAE5E,OAAO,EACH,0BAA0B,EAC1B,oCAAoC,GACvC,MAAM,gCAAgC,CAAC;AACxC,YAAY,EAAE,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AAEtF,OAAO,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AACpF,YAAY,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAElE,OAAO,EACH,0BAA0B,EAC1B,oCAAoC,GACvC,MAAM,gCAAgC,CAAC;AACxC,YAAY,EAAE,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AAEtF,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACtF,YAAY,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACtF,YAAY,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAC;AACjG,YAAY,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAE3E,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AACvF,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEpE,OAAO,EAAE,kBAAkB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAC1F,YAAY,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAC1F,YAAY,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAC7F,YAAY,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAEnG,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACjF,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAKA,OAAO,EACH,gBAAgB,EAChB,0BAA0B,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,GAC/B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAEvF,OAAO,EACH,gBAAgB,EAChB,0BAA0B,EAC1B,KAAK,qBAAqB,GAC7B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACH,eAAe,EACf,yBAAyB,EACzB,KAAK,oBAAoB,GAC5B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAE3F,OAAO,EACH,kBAAkB,EAClB,4BAA4B,EAC5B,KAAK,uBAAuB,GAC/B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACH,0BAA0B,EAC1B,oCAAoC,EACpC,KAAK,+BAA+B,GACvC,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACH,qBAAqB,EACrB,+BAA+B,EAC/B,KAAK,0BAA0B,GAClC,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACH,0BAA0B,EAC1B,oCAAoC,EACpC,KAAK,+BAA+B,GACvC,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACH,gBAAgB,EAChB,0BAA0B,EAC1B,KAAK,qBAAqB,GAC7B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,0BAA0B,EAC1B,oCAAoC,EACpC,KAAK,+BAA+B,GACvC,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACH,iBAAiB,EACjB,2BAA2B,EAC3B,KAAK,sBAAsB,GAC9B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,iBAAiB,EACjB,2BAA2B,EAC3B,KAAK,sBAAsB,GAC9B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,oBAAoB,EACpB,8BAA8B,EAC9B,KAAK,yBAAyB,GACjC,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACH,iBAAiB,EACjB,2BAA2B,EAC3B,KAAK,sBAAsB,GAC9B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACH,kBAAkB,EAClB,4BAA4B,EAC5B,KAAK,uBAAuB,GAC/B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACH,kBAAkB,EAClB,4BAA4B,EAC5B,KAAK,uBAAuB,GAC/B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACH,mBAAmB,EACnB,6BAA6B,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,GACjC,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACH,eAAe,EACf,yBAAyB,EACzB,KAAK,oBAAoB,GAC5B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACH,eAAe,EACf,yBAAyB,EACzB,KAAK,oBAAoB,GAC5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,cAAc,EACd,wBAAwB,EACxB,KAAK,mBAAmB,GAC3B,MAAM,mBAAmB,CAAC"}
@@ -1,20 +1,26 @@
1
- export { VerificationCode, getVerificationCodeSubject } from './verification-code';
1
+ // One export declaration per template module. Projects that resolve this package
2
+ // through its `development` condition (source) typecheck without `jsx`, and TypeScript
3
+ // reports TS6142 once per declaration that imports a .tsx module from this .ts file;
4
+ // a separate `export type` line for the same module would add a second report.
5
+ export { VerificationCode, getVerificationCodeSubject, } from './verification-code';
2
6
  export { InboxClaim, getInboxClaimSubject } from './inbox-claim';
3
- export { GuardianApproval, getGuardianApprovalSubject } from './guardian-approval';
4
- export { AccountApproved, getAccountApprovedSubject } from './account-approved';
7
+ export { GuardianApproval, getGuardianApprovalSubject, } from './guardian-approval';
8
+ export { AccountApproved, getAccountApprovedSubject, } from './account-approved';
5
9
  export { RecoveryKey, getRecoveryKeySubject } from './recovery-key';
6
- export { EndorsementRequest, getEndorsementRequestSubject } from './endorsement-request';
10
+ export { EndorsementRequest, getEndorsementRequestSubject, } from './endorsement-request';
7
11
  export { CredentialAwaitingGuardian, getCredentialAwaitingGuardianSubject, } from './credential-awaiting-guardian';
8
- export { GuardianApprovedClaim, getGuardianApprovedClaimSubject } from './guardian-approved-claim';
12
+ export { GuardianApprovedClaim, getGuardianApprovedClaimSubject, } from './guardian-approved-claim';
9
13
  export { GuardianCredentialApproval, getGuardianCredentialApprovalSubject, } from './guardian-credential-approval';
10
- export { GuardianEmailOtp, getGuardianEmailOtpSubject } from './guardian-email-otp';
14
+ export { GuardianEmailOtp, getGuardianEmailOtpSubject, } from './guardian-email-otp';
11
15
  export { GuardianRejectedCredential, getGuardianRejectedCredentialSubject, } from './guardian-rejected-credential';
12
- export { EmailVerification, getEmailVerificationSubject } from './email-verification';
13
- export { CredentialUpdated, getCredentialUpdatedSubject } from './credential-updated';
14
- export { AccountSignInChanged, getAccountSignInChangedSubject } from './account-sign-in-changed';
15
- export { EscrowHoldStarted, getEscrowHoldStartedSubject } from './escrow-hold-started';
16
- export { EscrowHoldReminder, getEscrowHoldReminderSubject } from './escrow-hold-reminder';
17
- export { EscrowHoldReleased, getEscrowHoldReleasedSubject } from './escrow-hold-released';
18
- export { EscrowHoldCancelled, getEscrowHoldCancelledSubject } from './escrow-hold-cancelled';
19
- export { EscrowPinLocked, getEscrowPinLockedSubject } from './escrow-pin-locked';
16
+ export { EmailVerification, getEmailVerificationSubject, } from './email-verification';
17
+ export { CredentialUpdated, getCredentialUpdatedSubject, } from './credential-updated';
18
+ export { AccountSignInChanged, getAccountSignInChangedSubject, } from './account-sign-in-changed';
19
+ export { EscrowHoldStarted, getEscrowHoldStartedSubject, } from './escrow-hold-started';
20
+ export { EscrowHoldReminder, getEscrowHoldReminderSubject, } from './escrow-hold-reminder';
21
+ export { EscrowHoldReleased, getEscrowHoldReleasedSubject, } from './escrow-hold-released';
22
+ export { EscrowHoldCancelled, getEscrowHoldCancelledSubject, } from './escrow-hold-cancelled';
23
+ export { EscrowPinLocked, getEscrowPinLockedSubject, } from './escrow-pin-locked';
24
+ export { EscrowPinSignIn, getEscrowPinSignInSubject, } from './escrow-pin-sign-in';
25
+ export { AccountSecured, getAccountSecuredSubject, } from './account-secured';
20
26
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAGnF,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAGjE,OAAO,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAGnF,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAGhF,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAGpE,OAAO,EAAE,kBAAkB,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AAGzF,OAAO,EACH,0BAA0B,EAC1B,oCAAoC,GACvC,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EAAE,qBAAqB,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAC;AAGnG,OAAO,EACH,0BAA0B,EAC1B,oCAAoC,GACvC,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAGpF,OAAO,EACH,0BAA0B,EAC1B,oCAAoC,GACvC,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AAGtF,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AAEtF,OAAO,EAAE,oBAAoB,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAC;AAGjG,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAGvF,OAAO,EAAE,kBAAkB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAG1F,OAAO,EAAE,kBAAkB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAG1F,OAAO,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAG7F,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,uFAAuF;AACvF,qFAAqF;AACrF,+EAA+E;AAE/E,OAAO,EACH,gBAAgB,EAChB,0BAA0B,GAG7B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAwB,MAAM,eAAe,CAAC;AAEvF,OAAO,EACH,gBAAgB,EAChB,0BAA0B,GAE7B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACH,eAAe,EACf,yBAAyB,GAE5B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAyB,MAAM,gBAAgB,CAAC;AAE3F,OAAO,EACH,kBAAkB,EAClB,4BAA4B,GAE/B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACH,0BAA0B,EAC1B,oCAAoC,GAEvC,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACH,qBAAqB,EACrB,+BAA+B,GAElC,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACH,0BAA0B,EAC1B,oCAAoC,GAEvC,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACH,gBAAgB,EAChB,0BAA0B,GAE7B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,0BAA0B,EAC1B,oCAAoC,GAEvC,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACH,iBAAiB,EACjB,2BAA2B,GAE9B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,iBAAiB,EACjB,2BAA2B,GAE9B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,oBAAoB,EACpB,8BAA8B,GAEjC,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACH,iBAAiB,EACjB,2BAA2B,GAE9B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACH,kBAAkB,EAClB,4BAA4B,GAE/B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACH,kBAAkB,EAClB,4BAA4B,GAE/B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACH,mBAAmB,EACnB,6BAA6B,GAGhC,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACH,eAAe,EACf,yBAAyB,GAE5B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACH,eAAe,EACf,yBAAyB,GAE5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,cAAc,EACd,wBAAwB,GAE3B,MAAM,mBAAmB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@learncard/email-templates",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Git-managed, tenant-branded email and SMS templates for LearnCard services",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "dependencies": {
21
21
  "@react-email/components": "^0.0.36",
22
- "@react-email/render": "^1.0.5",
22
+ "@react-email/render": "^2.2.0",
23
23
  "react": "^18.3.1"
24
24
  },
25
25
  "devDependencies": {
@@ -13,7 +13,7 @@ import { describe, it, expect } from 'vitest';
13
13
  import { renderEmail } from '../render';
14
14
  import { renderSms } from '../sms';
15
15
  import { DEFAULT_BRANDING } from '../branding';
16
- import { resolveCatalogLocale, htmlDir } from '../i18n';
16
+ import { resolveCatalogLocale, htmlDir, localeProp } from '../i18n';
17
17
  import type { NotificationLocale } from '../i18n';
18
18
  import type { TemplateId, TemplateDataMap } from '../render';
19
19
 
@@ -120,6 +120,11 @@ const FIXTURES: { [K in TemplateId]: TemplateDataMap[K] } = {
120
120
  releaseAfter: 'October 2, 2026, 3:00 PM',
121
121
  cancelUrl: 'https://learncard.app/recovery/cancel?token=abc123',
122
122
  },
123
+ 'escrow-pin-sign-in': {
124
+ signedInAt: 'October 2, 2026, 3:00 PM',
125
+ secureUrl: 'https://learncard.app/account/secure',
126
+ },
127
+ 'account-secured': { securedAt: 'October 2, 2026, 3:00 PM' },
123
128
  };
124
129
 
125
130
  const ALL_TEMPLATE_IDS = Object.keys(FIXTURES) as TemplateId[];
@@ -162,6 +167,7 @@ describe('i18n — non-EN locales localize content', () => {
162
167
  'credential-awaiting-guardian',
163
168
  'escrow-hold-started',
164
169
  'escrow-hold-cancelled',
170
+ 'account-secured',
165
171
  ];
166
172
 
167
173
  for (const templateId of SAMPLES) {
@@ -363,4 +369,29 @@ describe('i18n — renderSms localizes', () => {
363
369
  expect(es).toContain('Tu código de verificación de LearnCard es:');
364
370
  expect(en).toContain('999222');
365
371
  });
372
+
373
+ it('localeProp omits an absent locale instead of passing undefined', () => {
374
+ expect(localeProp(undefined)).toEqual({});
375
+ expect(localeProp(null)).toEqual({});
376
+ expect('locale' in localeProp(undefined)).toBe(false);
377
+ expect(localeProp('fr')).toEqual({ locale: 'fr' });
378
+ });
379
+
380
+ it('PIN sign-in and account-secured notices are unchanged for EN vs undefined', async () => {
381
+ for (const [id, data] of [
382
+ [
383
+ 'escrow-pin-sign-in',
384
+ {
385
+ signedInAt: 'October 2, 2026',
386
+ secureUrl: 'https://learncard.app/account/secure',
387
+ },
388
+ ],
389
+ ['account-secured', { securedAt: 'October 2, 2026' }],
390
+ ] as const) {
391
+ const en = await renderEmail(id, DEFAULT_BRANDING, data, 'en');
392
+ const none = await renderEmail(id, DEFAULT_BRANDING, data);
393
+ expect(none.html).toBe(en.html);
394
+ expect(none.subject).toBe(en.subject);
395
+ }
396
+ });
366
397
  });
@@ -166,6 +166,13 @@ const TEMPLATE_FIXTURES: { [K in TemplateId]: TemplateDataMap[K] } = {
166
166
  releaseAfter: 'October 2, 2026, 3:00 PM',
167
167
  cancelUrl: 'https://learncard.app/recovery/cancel?token=abc123',
168
168
  },
169
+ 'escrow-pin-sign-in': {
170
+ signedInAt: 'October 2, 2026, 3:00 PM',
171
+ secureUrl: 'https://learncard.app/account/secure',
172
+ },
173
+ 'account-secured': {
174
+ securedAt: 'October 2, 2026, 3:00 PM',
175
+ },
169
176
  };
170
177
 
171
178
  const ALL_TEMPLATE_IDS = Object.keys(TEMPLATE_FIXTURES) as TemplateId[];
@@ -552,6 +559,114 @@ describe('renderEmail — escrow hold lifecycle', () => {
552
559
  expect(html).not.toContain('undefined');
553
560
  });
554
561
 
562
+ it('escrow-pin-sign-in includes the sign-in date and the secure-account link', async () => {
563
+ const data = TEMPLATE_FIXTURES['escrow-pin-sign-in'];
564
+ const { html, text, subject } = await renderEmail(
565
+ 'escrow-pin-sign-in',
566
+ DEFAULT_BRANDING,
567
+ data
568
+ );
569
+
570
+ expect(html).toContain(data.signedInAt);
571
+ expect(html).toContain(data.secureUrl);
572
+ expect(text).toContain('Not you? Secure your account.');
573
+ expect(text).toContain('Secure my account');
574
+ expect(subject).toBe('New device signed in with your PIN');
575
+ assertNoJargon(html);
576
+ assertNoJargon(text);
577
+ assertNoJargon(subject);
578
+ });
579
+
580
+ it('escrow-pin-sign-in formats the ISO timestamp lca-api sends, per locale', async () => {
581
+ const iso = '2026-11-02T15:04:05.123Z';
582
+ const en = await renderEmail('escrow-pin-sign-in', DEFAULT_BRANDING, {
583
+ signedInAt: iso,
584
+ secureUrl: 'https://learncard.app/account/secure',
585
+ });
586
+ const fr = await renderEmail(
587
+ 'escrow-pin-sign-in',
588
+ DEFAULT_BRANDING,
589
+ { signedInAt: iso, secureUrl: 'https://learncard.app/account/secure' },
590
+ 'fr'
591
+ );
592
+
593
+ expect(en.text).not.toContain(iso);
594
+ expect(en.text).toContain('November 2, 2026');
595
+ expect(en.text).toContain('UTC');
596
+ expect(fr.text).toContain('2 novembre 2026');
597
+ });
598
+
599
+ it('escrow-pin-sign-in carries tenant branding', async () => {
600
+ const { html } = await renderEmail('escrow-pin-sign-in', VETPASS_BRANDING, {
601
+ signedInAt: 'October 2, 2026, 3:00 PM',
602
+ secureUrl: 'https://vetpass.app/account/secure',
603
+ });
604
+
605
+ expect(html).toContain('VetPass');
606
+ expect(html).toContain('https://vetpass.app/account/secure');
607
+ });
608
+
609
+ it('account-secured works for an owner who did not do it (no secure link, support first)', async () => {
610
+ const data = TEMPLATE_FIXTURES['account-secured'];
611
+ const { html, text, subject } = await renderEmail(
612
+ 'account-secured',
613
+ DEFAULT_BRANDING,
614
+ data
615
+ );
616
+
617
+ expect(html).toContain(data.securedAt);
618
+ expect(subject).toBe('Other devices were signed out of your account');
619
+ // The owner's login may be gone, so the notice must not depend on the in-app action.
620
+ expect(html).not.toContain('/account/secure');
621
+ expect(text).toContain('your own sign-in may have been removed');
622
+ // The revoke reset every recovery method and removed automatic recovery, so the
623
+ // lost-login path is not offered as the way back; support is.
624
+ expect(text).toContain('reset its recovery methods');
625
+ expect(text).not.toContain('I lost access to my school email or login');
626
+ expect(text).toContain(`Contact ${DEFAULT_BRANDING.supportEmail} right away`);
627
+ expect(html).toContain(`href="${DEFAULT_BRANDING.appUrl}"`);
628
+ assertNoJargon(html);
629
+ assertNoJargon(text);
630
+ assertNoJargon(subject);
631
+ });
632
+
633
+ it('account-secured formats the ISO timestamp lca-api sends, per locale', async () => {
634
+ const iso = '2026-11-02T15:04:05.123Z';
635
+ const en = await renderEmail('account-secured', DEFAULT_BRANDING, { securedAt: iso });
636
+ const es = await renderEmail('account-secured', DEFAULT_BRANDING, { securedAt: iso }, 'es');
637
+
638
+ expect(en.text).not.toContain(iso);
639
+ expect(en.text).toContain('November 2, 2026');
640
+ expect(en.text).toContain('UTC');
641
+ expect(es.text).toContain('2 de noviembre de 2026');
642
+ expect(es.subject).not.toBe(en.subject);
643
+ });
644
+
645
+ it('account-secured carries tenant branding and the tenant support address', async () => {
646
+ const { html, text } = await renderEmail('account-secured', VETPASS_BRANDING, {
647
+ securedAt: 'October 2, 2026, 3:00 PM',
648
+ });
649
+
650
+ expect(html).toContain('VetPass');
651
+ expect(text).toContain(`Contact ${VETPASS_BRANDING.supportEmail} right away`);
652
+ expect(html).toContain(`href="${VETPASS_BRANDING.appUrl}"`);
653
+ expect(text).not.toContain(DEFAULT_BRANDING.supportEmail);
654
+ });
655
+
656
+ it('account-secured points to the organization when the tenant has no support address', async () => {
657
+ const { text } = await renderEmail(
658
+ 'account-secured',
659
+ { ...DEFAULT_BRANDING, supportEmail: '' },
660
+ TEMPLATE_FIXTURES['account-secured']
661
+ );
662
+
663
+ expect(text).not.toContain('Contact right away');
664
+ expect(text).toContain(
665
+ `Contact the organization that gave you access to ${DEFAULT_BRANDING.brandName} right away`
666
+ );
667
+ expect(text).not.toContain('I lost access to my school email or login');
668
+ });
669
+
555
670
  it('all escrow hold templates include the "This wasn\'t me" cancel CTA when a cancel URL is present', async () => {
556
671
  const started = await renderEmail(
557
672
  'escrow-hold-started',
package/src/i18n.ts CHANGED
@@ -108,3 +108,36 @@ export const interpolate = (template: string, params: Record<string, string | un
108
108
  const value = params[key];
109
109
  return value === undefined ? match : value;
110
110
  });
111
+
112
+ /**
113
+ * `{ locale }` when set, `{}` otherwise — spread into props whose `locale` is optional
114
+ * so an absent locale is omitted rather than passed as `undefined`
115
+ * (safe under `exactOptionalPropertyTypes`).
116
+ */
117
+ export const localeProp = (locale: string | null | undefined): { locale?: string } =>
118
+ locale === undefined || locale === null ? {} : { locale };
119
+
120
+ /**
121
+ * lca-api passes ISO timestamps for security notices; show them as a readable date in
122
+ * the recipient's language. The recipient's time zone is unknown, so the time is shown
123
+ * in UTC and labelled as such. Anything that is not an ISO timestamp (previews,
124
+ * pre-formatted text) is shown as is.
125
+ */
126
+ export const formatNoticeTimestamp = (value: string, locale: NotificationLocale): string => {
127
+ if (!/^\d{4}-\d{2}-\d{2}T/.test(value)) return value;
128
+
129
+ const date = new Date(value);
130
+ if (Number.isNaN(date.getTime())) return value;
131
+
132
+ try {
133
+ return new Intl.DateTimeFormat(locale, {
134
+ dateStyle: 'long',
135
+ timeStyle: 'short',
136
+ timeZone: 'UTC',
137
+ })
138
+ .format(date)
139
+ .concat(' UTC');
140
+ } catch {
141
+ return value;
142
+ }
143
+ };
package/src/index.ts CHANGED
@@ -44,6 +44,8 @@ export type {
44
44
  EscrowHoldReleasedData,
45
45
  EscrowHoldCancelledData,
46
46
  EscrowPinLockedData,
47
+ EscrowPinSignInData,
48
+ AccountSecuredData,
47
49
  } from './render';
48
50
  export type { EscrowHoldCancelledReason } from './templates/escrow-hold-cancelled';
49
51
 
@@ -0,0 +1,41 @@
1
+ /**
2
+ * account-secured — all preview scenarios stacked.
3
+ */
4
+
5
+ import * as React from 'react';
6
+
7
+ import { AccountSecured } from '../templates/account-secured';
8
+ import { LEARNCARD_BRANDING, VETPASS_BRANDING, ScenarioDivider } from './_fixtures';
9
+
10
+ export default function AccountSecuredScenarios() {
11
+ return (
12
+ <>
13
+ <ScenarioDivider label="Default (LearnCard)" />
14
+ <AccountSecured branding={LEARNCARD_BRANDING} securedAt="October 2, 2026, 3:00 PM" />
15
+
16
+ <ScenarioDivider label="Spanish" />
17
+ <AccountSecured
18
+ branding={LEARNCARD_BRANDING}
19
+ securedAt="2 de octubre de 2026, 3:00 p.m."
20
+ locale="es"
21
+ />
22
+
23
+ <ScenarioDivider label="French" />
24
+ <AccountSecured
25
+ branding={LEARNCARD_BRANDING}
26
+ securedAt="2 octobre 2026, 15h00"
27
+ locale="fr"
28
+ />
29
+
30
+ <ScenarioDivider label="Arabic (RTL)" />
31
+ <AccountSecured
32
+ branding={LEARNCARD_BRANDING}
33
+ securedAt="2 أكتوبر 2026، 3:00 م"
34
+ locale="ar"
35
+ />
36
+
37
+ <ScenarioDivider label="VetPass tenant branding" />
38
+ <AccountSecured branding={VETPASS_BRANDING} securedAt="October 2, 2026, 3:00 PM" />
39
+ </>
40
+ );
41
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * escrow-pin-sign-in — all preview scenarios stacked.
3
+ */
4
+
5
+ import * as React from 'react';
6
+
7
+ import { EscrowPinSignIn } from '../templates/escrow-pin-sign-in';
8
+ import { LEARNCARD_BRANDING, VETPASS_BRANDING, ScenarioDivider } from './_fixtures';
9
+
10
+ export default function EscrowPinSignInScenarios() {
11
+ return (
12
+ <>
13
+ <ScenarioDivider label="Default (LearnCard)" />
14
+ <EscrowPinSignIn
15
+ branding={LEARNCARD_BRANDING}
16
+ signedInAt="October 2, 2026, 3:00 PM"
17
+ secureUrl="https://learncard.app/account/secure"
18
+ />
19
+
20
+ <ScenarioDivider label="Spanish" />
21
+ <EscrowPinSignIn
22
+ branding={LEARNCARD_BRANDING}
23
+ signedInAt="2 de octubre de 2026, 3:00 p.m."
24
+ secureUrl="https://learncard.app/account/secure"
25
+ locale="es"
26
+ />
27
+
28
+ <ScenarioDivider label="French" />
29
+ <EscrowPinSignIn
30
+ branding={LEARNCARD_BRANDING}
31
+ signedInAt="2 octobre 2026, 15h00"
32
+ secureUrl="https://learncard.app/account/secure"
33
+ locale="fr"
34
+ />
35
+
36
+ <ScenarioDivider label="Arabic (RTL)" />
37
+ <EscrowPinSignIn
38
+ branding={LEARNCARD_BRANDING}
39
+ signedInAt="2 أكتوبر 2026، 3:00 م"
40
+ secureUrl="https://learncard.app/account/secure"
41
+ locale="ar"
42
+ />
43
+
44
+ <ScenarioDivider label="VetPass tenant branding" />
45
+ <EscrowPinSignIn
46
+ branding={VETPASS_BRANDING}
47
+ signedInAt="October 2, 2026, 3:00 PM"
48
+ secureUrl="https://vetpass.app/account/secure"
49
+ />
50
+ </>
51
+ );
52
+ }
package/src/render.ts CHANGED
@@ -53,6 +53,10 @@ import {
53
53
  getEscrowHoldCancelledSubject,
54
54
  EscrowPinLocked,
55
55
  getEscrowPinLockedSubject,
56
+ EscrowPinSignIn,
57
+ getEscrowPinSignInSubject,
58
+ AccountSecured,
59
+ getAccountSecuredSubject,
56
60
  } from './templates';
57
61
 
58
62
  import type {
@@ -75,7 +79,10 @@ import type {
75
79
  EscrowHoldCancelledProps,
76
80
  EscrowHoldCancelledReason,
77
81
  EscrowPinLockedProps,
82
+ EscrowPinSignInProps,
83
+ AccountSecuredProps,
78
84
  } from './templates';
85
+ import { localeProp } from './i18n';
79
86
 
80
87
  // ---------------------------------------------------------------------------
81
88
  // Public types
@@ -190,6 +197,12 @@ export interface TemplateDataMap {
190
197
 
191
198
  /** lca-api: recovery PIN locked after too many failed attempts */
192
199
  'escrow-pin-locked': EscrowPinLockedData;
200
+
201
+ /** lca-api: a new device signed in with the recovery PIN — links to "Secure my account" */
202
+ 'escrow-pin-sign-in': EscrowPinSignInData;
203
+
204
+ /** lca-api: "Secure my account" signed out every other device and login */
205
+ 'account-secured': AccountSecuredData;
193
206
  }
194
207
 
195
208
  export type TemplateId = keyof TemplateDataMap;
@@ -304,6 +317,15 @@ export interface EscrowPinLockedData {
304
317
  cancelUrl?: string;
305
318
  }
306
319
 
320
+ export interface EscrowPinSignInData {
321
+ signedInAt: string;
322
+ secureUrl: string;
323
+ }
324
+
325
+ export interface AccountSecuredData {
326
+ securedAt: string;
327
+ }
328
+
307
329
  // ---------------------------------------------------------------------------
308
330
  // renderEmail()
309
331
  // ---------------------------------------------------------------------------
@@ -570,6 +592,35 @@ function buildElement(
570
592
  };
571
593
  }
572
594
 
595
+ case 'escrow-pin-sign-in': {
596
+ const d = data as EscrowPinSignInData;
597
+ const props: EscrowPinSignInProps = {
598
+ branding,
599
+ signedInAt: d.signedInAt,
600
+ secureUrl: d.secureUrl,
601
+ ...localeProp(locale),
602
+ };
603
+
604
+ return {
605
+ element: React.createElement(EscrowPinSignIn, props),
606
+ subject: getEscrowPinSignInSubject(branding, locale),
607
+ };
608
+ }
609
+
610
+ case 'account-secured': {
611
+ const d = data as AccountSecuredData;
612
+ const props: AccountSecuredProps = {
613
+ branding,
614
+ securedAt: d.securedAt,
615
+ ...localeProp(locale),
616
+ };
617
+
618
+ return {
619
+ element: React.createElement(AccountSecured, props),
620
+ subject: getAccountSecuredSubject(branding, locale),
621
+ };
622
+ }
623
+
573
624
  default: {
574
625
  const _exhaustive: never = templateId;
575
626
  throw new Error(`Unknown template: ${_exhaustive}`);