@learncard/email-templates 1.0.6 → 1.1.0
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.
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/previews/credential-updated-scenarios.d.ts +9 -0
- package/dist/previews/credential-updated-scenarios.d.ts.map +1 -0
- package/dist/previews/credential-updated-scenarios.js +7 -0
- package/dist/previews/credential-updated-scenarios.js.map +1 -0
- package/dist/render.d.ts +12 -0
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +9 -1
- package/dist/render.js.map +1 -1
- package/dist/templates/credential-updated.d.ts +33 -0
- package/dist/templates/credential-updated.d.ts.map +1 -0
- package/dist/templates/credential-updated.js +104 -0
- package/dist/templates/credential-updated.js.map +1 -0
- package/dist/templates/index.d.ts +5 -3
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/index.js +4 -3
- package/dist/templates/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/render.test.ts +147 -26
- package/src/index.ts +1 -0
- package/src/previews/credential-updated-scenarios.tsx +61 -0
- package/src/render.ts +22 -0
- package/src/templates/credential-updated.tsx +309 -0
- package/src/templates/index.ts +15 -3
package/dist/index.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export { resolveCatalogLocale } from './i18n';
|
|
|
18
18
|
export type { NotificationLocale } from './i18n';
|
|
19
19
|
export { renderEmail } from './render';
|
|
20
20
|
export type { RenderedEmail, TemplateId, TemplateDataMap } from './render';
|
|
21
|
-
export type { VerificationCodeData, EmailVerificationData, InboxClaimData, GuardianApprovalData, AccountApprovedData, RecoveryKeyData, EndorsementRequestData, CredentialAwaitingGuardianData, GuardianApprovedClaimData, GuardianCredentialApprovalData, GuardianEmailOtpData, GuardianRejectedCredentialData, } from './render';
|
|
21
|
+
export type { VerificationCodeData, EmailVerificationData, InboxClaimData, GuardianApprovalData, AccountApprovedData, RecoveryKeyData, EndorsementRequestData, CredentialAwaitingGuardianData, GuardianApprovedClaimData, GuardianCredentialApprovalData, GuardianEmailOtpData, GuardianRejectedCredentialData, CredentialUpdatedData, } from './render';
|
|
22
22
|
export { renderSms } from './sms';
|
|
23
23
|
export type { SmsTemplateId, SmsTemplateDataMap, SmsInboxClaimData, SmsVerificationData, } from './sms';
|
|
24
24
|
export { resolveTenantFromRequest, registerOriginMapping, registerTenantBranding, } from './tenant-registry';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/D,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAC9C,YAAY,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAGjD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3E,YAAY,EACR,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,sBAAsB,EACtB,8BAA8B,EAC9B,yBAAyB,EACzB,8BAA8B,EAC9B,oBAAoB,EACpB,8BAA8B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/D,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAC9C,YAAY,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAGjD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3E,YAAY,EACR,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,sBAAsB,EACtB,8BAA8B,EAC9B,yBAAyB,EACzB,8BAA8B,EAC9B,oBAAoB,EACpB,8BAA8B,EAC9B,qBAAqB,GACxB,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,YAAY,EACR,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,GACtB,MAAM,OAAO,CAAC;AAGf,OAAO,EACH,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,WAAW;AACX,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG/D,iBAAiB;AACjB,OAAO,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAG9C,kBAAkB;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,WAAW;AACX,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG/D,iBAAiB;AACjB,OAAO,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAG9C,kBAAkB;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAkBvC,gBAAgB;AAChB,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAQlC,gCAAgC;AAChC,OAAO,EACH,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,GACzB,MAAM,mBAAmB,CAAC;AAG3B,yEAAyE;AACzE,uEAAuE;AACvE,8EAA8E;AAC9E,+DAA+D;AAC/D,yDAAyD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* credential-updated — minimal-context update notice scenarios.
|
|
3
|
+
*
|
|
4
|
+
* Shows the title/no-title fallback and locale variants so reviewers can verify
|
|
5
|
+
* the email never renders grades, subject details, or issuer summaries.
|
|
6
|
+
*/
|
|
7
|
+
import * as React from 'react';
|
|
8
|
+
export default function CredentialUpdatedScenarios(): React.JSX.Element;
|
|
9
|
+
//# sourceMappingURL=credential-updated-scenarios.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-updated-scenarios.d.ts","sourceRoot":"","sources":["../../src/previews/credential-updated-scenarios.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,CAAC,OAAO,UAAU,0BAA0B,sBAgDjD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CredentialUpdated } from '../templates/credential-updated';
|
|
3
|
+
import { LEARNCARD_BRANDING, VETPASS_BRANDING, ScenarioDivider } from './_fixtures';
|
|
4
|
+
export default function CredentialUpdatedScenarios() {
|
|
5
|
+
return (_jsxs(_Fragment, { children: [_jsx(ScenarioDivider, { label: "English \u2014 with credential title" }), _jsx(CredentialUpdated, { branding: LEARNCARD_BRANDING, issuer: { name: 'Inbox Demo School' }, credential: { name: 'Introduction to Biology' } }), _jsx(ScenarioDivider, { label: "English \u2014 title unavailable (generic fallback)" }), _jsx(CredentialUpdated, { branding: LEARNCARD_BRANDING, issuer: { name: 'Inbox Demo School' } }), _jsx(ScenarioDivider, { label: "Spanish" }), _jsx(CredentialUpdated, { branding: LEARNCARD_BRANDING, issuer: { name: 'Escuela Demo' }, credential: { name: 'Introducción a la Biología' }, locale: "es" }), _jsx(ScenarioDivider, { label: "French" }), _jsx(CredentialUpdated, { branding: LEARNCARD_BRANDING, issuer: { name: 'École Démo' }, credential: { name: 'Introduction à la biologie' }, locale: "fr" }), _jsx(ScenarioDivider, { label: "Arabic (RTL)" }), _jsx(CredentialUpdated, { branding: LEARNCARD_BRANDING, issuer: { name: 'مدرسة تجريبية' }, credential: { name: 'مقدمة في علم الأحياء' }, locale: "ar" }), _jsx(ScenarioDivider, { label: "VetPass branding" }), _jsx(CredentialUpdated, { branding: VETPASS_BRANDING, issuer: { name: 'VetPass Academy' }, credential: { name: 'Veterinary Ethics' } })] }));
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=credential-updated-scenarios.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-updated-scenarios.js","sourceRoot":"","sources":["../../src/previews/credential-updated-scenarios.tsx"],"names":[],"mappings":";AASA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEpF,MAAM,CAAC,OAAO,UAAU,0BAA0B;IAC9C,OAAO,CACH,8BACI,KAAC,eAAe,IAAC,KAAK,EAAC,sCAAiC,GAAG,EAC3D,KAAC,iBAAiB,IACd,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,EACrC,UAAU,EAAE,EAAE,IAAI,EAAE,yBAAyB,EAAE,GACjD,EAEF,KAAC,eAAe,IAAC,KAAK,EAAC,qDAAgD,GAAG,EAC1E,KAAC,iBAAiB,IACd,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,GACvC,EAEF,KAAC,eAAe,IAAC,KAAK,EAAC,SAAS,GAAG,EACnC,KAAC,iBAAiB,IACd,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,EAChC,UAAU,EAAE,EAAE,IAAI,EAAE,4BAA4B,EAAE,EAClD,MAAM,EAAC,IAAI,GACb,EAEF,KAAC,eAAe,IAAC,KAAK,EAAC,QAAQ,GAAG,EAClC,KAAC,iBAAiB,IACd,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,EAC9B,UAAU,EAAE,EAAE,IAAI,EAAE,4BAA4B,EAAE,EAClD,MAAM,EAAC,IAAI,GACb,EAEF,KAAC,eAAe,IAAC,KAAK,EAAC,cAAc,GAAG,EACxC,KAAC,iBAAiB,IACd,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,EACjC,UAAU,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,EAC5C,MAAM,EAAC,IAAI,GACb,EAEF,KAAC,eAAe,IAAC,KAAK,EAAC,kBAAkB,GAAG,EAC5C,KAAC,iBAAiB,IACd,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,EACnC,UAAU,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,GAC3C,IACH,CACN,CAAC;AACN,CAAC"}
|
package/dist/render.d.ts
CHANGED
|
@@ -61,6 +61,8 @@ export interface TemplateDataMap {
|
|
|
61
61
|
'guardian-email-otp': GuardianEmailOtpData;
|
|
62
62
|
/** Sent to student: guardian rejected credential */
|
|
63
63
|
'guardian-rejected-credential': GuardianRejectedCredentialData;
|
|
64
|
+
/** brain-service: managed credential refresh update notice (LC-2198) */
|
|
65
|
+
'credential-updated': CredentialUpdatedData;
|
|
64
66
|
}
|
|
65
67
|
export type TemplateId = keyof TemplateDataMap;
|
|
66
68
|
export interface VerificationCodeData {
|
|
@@ -173,6 +175,16 @@ export interface GuardianRejectedCredentialData {
|
|
|
173
175
|
email?: string;
|
|
174
176
|
};
|
|
175
177
|
}
|
|
178
|
+
export interface CredentialUpdatedData {
|
|
179
|
+
issuer?: {
|
|
180
|
+
name?: string;
|
|
181
|
+
logoUrl?: string;
|
|
182
|
+
};
|
|
183
|
+
/** Bounded credential display title. Omitted when unavailable. */
|
|
184
|
+
credential?: {
|
|
185
|
+
name?: string;
|
|
186
|
+
};
|
|
187
|
+
}
|
|
176
188
|
/**
|
|
177
189
|
* Render a fully branded email for the given template.
|
|
178
190
|
*
|
package/dist/render.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
package/dist/render.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { render } from '@react-email/render';
|
|
11
11
|
import * as React from 'react';
|
|
12
12
|
import { resolveBranding } from './branding';
|
|
13
|
-
import { VerificationCode, getVerificationCodeSubject, InboxClaim, getInboxClaimSubject, GuardianApproval, getGuardianApprovalSubject, AccountApproved, getAccountApprovedSubject, RecoveryKey, getRecoveryKeySubject, EndorsementRequest, getEndorsementRequestSubject, CredentialAwaitingGuardian, getCredentialAwaitingGuardianSubject, GuardianApprovedClaim, getGuardianApprovedClaimSubject, GuardianCredentialApproval, getGuardianCredentialApprovalSubject, GuardianEmailOtp, getGuardianEmailOtpSubject, GuardianRejectedCredential, getGuardianRejectedCredentialSubject, EmailVerification, getEmailVerificationSubject, } from './templates';
|
|
13
|
+
import { VerificationCode, getVerificationCodeSubject, InboxClaim, getInboxClaimSubject, GuardianApproval, getGuardianApprovalSubject, AccountApproved, getAccountApprovedSubject, RecoveryKey, getRecoveryKeySubject, EndorsementRequest, getEndorsementRequestSubject, CredentialAwaitingGuardian, getCredentialAwaitingGuardianSubject, GuardianApprovedClaim, getGuardianApprovedClaimSubject, GuardianCredentialApproval, getGuardianCredentialApprovalSubject, GuardianEmailOtp, getGuardianEmailOtpSubject, GuardianRejectedCredential, getGuardianRejectedCredentialSubject, EmailVerification, getEmailVerificationSubject, CredentialUpdated, getCredentialUpdatedSubject, } from './templates';
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
15
|
// renderEmail()
|
|
16
16
|
// ---------------------------------------------------------------------------
|
|
@@ -147,6 +147,14 @@ function buildElement(templateId, branding, data, locale) {
|
|
|
147
147
|
subject: getGuardianRejectedCredentialSubject(branding, locale),
|
|
148
148
|
};
|
|
149
149
|
}
|
|
150
|
+
case 'credential-updated': {
|
|
151
|
+
const d = data;
|
|
152
|
+
const props = { branding, ...d, locale };
|
|
153
|
+
return {
|
|
154
|
+
element: React.createElement(CredentialUpdated, props),
|
|
155
|
+
subject: getCredentialUpdatedSubject(branding, locale),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
150
158
|
default: {
|
|
151
159
|
const _exhaustive = templateId;
|
|
152
160
|
throw new Error(`Unknown template: ${_exhaustive}`);
|
package/dist/render.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,EACH,gBAAgB,EAChB,0BAA0B,EAC1B,UAAU,EACV,oBAAoB,EACpB,gBAAgB,EAChB,0BAA0B,EAC1B,eAAe,EACf,yBAAyB,EACzB,WAAW,EACX,qBAAqB,EACrB,kBAAkB,EAClB,4BAA4B,EAC5B,0BAA0B,EAC1B,oCAAoC,EACpC,qBAAqB,EACrB,+BAA+B,EAC/B,0BAA0B,EAC1B,oCAAoC,EACpC,gBAAgB,EAChB,0BAA0B,EAC1B,0BAA0B,EAC1B,oCAAoC,EACpC,iBAAiB,EACjB,2BAA2B,GAC9B,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CredentialUpdated — privacy-minimal notice that an issuer published a new
|
|
3
|
+
* version of a credential.
|
|
4
|
+
*
|
|
5
|
+
* Used by: brain-service credential-refresh publication (templateId:
|
|
6
|
+
* 'credential-updated').
|
|
7
|
+
*
|
|
8
|
+
* Deliberately minimal context: the issuer display name and the credential
|
|
9
|
+
* display title are the only dynamic values. No grades, subject/recipient
|
|
10
|
+
* details, evidence, body, or issuer-authored update summary is rendered. The
|
|
11
|
+
* CTA points at the recipient's own notifications page (never a claim URL and
|
|
12
|
+
* never a bearer token), so a forwarded email cannot be used to access the
|
|
13
|
+
* credential.
|
|
14
|
+
*/
|
|
15
|
+
import * as React from 'react';
|
|
16
|
+
import type { TenantBranding } from '../branding';
|
|
17
|
+
export interface CredentialUpdatedProps {
|
|
18
|
+
branding: TenantBranding;
|
|
19
|
+
issuer?: {
|
|
20
|
+
name?: string;
|
|
21
|
+
logoUrl?: string;
|
|
22
|
+
};
|
|
23
|
+
/** Bounded credential display title. Omitted when unavailable. */
|
|
24
|
+
credential?: {
|
|
25
|
+
name?: string;
|
|
26
|
+
};
|
|
27
|
+
/** Recipient locale (BCP-47). Defaults to English. */
|
|
28
|
+
locale?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare const CredentialUpdated: React.FC<CredentialUpdatedProps>;
|
|
31
|
+
export declare const getCredentialUpdatedSubject: (_branding: TenantBranding, locale?: string) => string;
|
|
32
|
+
export default function Preview(): React.JSX.Element;
|
|
33
|
+
//# sourceMappingURL=credential-updated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-updated.d.ts","sourceRoot":"","sources":["../../src/templates/credential-updated.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AASlD,MAAM,WAAW,sBAAsB;IACnC,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,CAAC,EAAE;QACL,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,kEAAkE;IAClE,UAAU,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAiLD,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CA8C9D,CAAC;AAEF,eAAO,MAAM,2BAA2B,GAAI,WAAW,cAAc,EAAE,SAAS,MAAM,KAAG,MACxC,CAAC;AAmClD,MAAM,CAAC,OAAO,UAAU,OAAO,sBAQ9B"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* CredentialUpdated — privacy-minimal notice that an issuer published a new
|
|
4
|
+
* version of a credential.
|
|
5
|
+
*
|
|
6
|
+
* Used by: brain-service credential-refresh publication (templateId:
|
|
7
|
+
* 'credential-updated').
|
|
8
|
+
*
|
|
9
|
+
* Deliberately minimal context: the issuer display name and the credential
|
|
10
|
+
* display title are the only dynamic values. No grades, subject/recipient
|
|
11
|
+
* details, evidence, body, or issuer-authored update summary is rendered. The
|
|
12
|
+
* CTA points at the recipient's own notifications page (never a claim URL and
|
|
13
|
+
* never a bearer token), so a forwarded email cannot be used to access the
|
|
14
|
+
* credential.
|
|
15
|
+
*/
|
|
16
|
+
import { Text, Section } from '@react-email/components';
|
|
17
|
+
import { DEFAULT_BRANDING } from '../branding';
|
|
18
|
+
import { Layout } from '../components/Layout';
|
|
19
|
+
import { EmailButton } from '../components/EmailButton';
|
|
20
|
+
import { IssuerLogo } from '../components/IssuerLogo';
|
|
21
|
+
import { LinkFallback } from '../components/LinkFallback';
|
|
22
|
+
import { resolveCatalogLocale, interpolate, SHARED } from '../i18n';
|
|
23
|
+
const ldquo = '\u201C';
|
|
24
|
+
const rdquo = '\u201D';
|
|
25
|
+
const EN = {
|
|
26
|
+
preview: 'Your credential has been updated',
|
|
27
|
+
heading: 'Your credential was updated',
|
|
28
|
+
body: (issuerName, credentialName) => issuerName ? (credentialName ? (_jsxs(_Fragment, { children: [_jsx("strong", { children: issuerName }), " updated your", ' ', _jsxs("strong", { children: [ldquo, credentialName, rdquo] }), ' ', "certificate."] })) : (_jsxs(_Fragment, { children: [_jsx("strong", { children: issuerName }), " updated one of your credentials."] }))) : credentialName ? (_jsxs(_Fragment, { children: ["Your", ' ', _jsxs("strong", { children: [ldquo, credentialName, rdquo] }), ' ', "certificate was updated."] })) : (_jsx(_Fragment, { children: "One of your credentials was updated." })),
|
|
29
|
+
signIn: 'Sign in to view the latest version.',
|
|
30
|
+
button: 'View Updates',
|
|
31
|
+
sincerely: 'Sincerely,',
|
|
32
|
+
subject: 'Your credential was updated',
|
|
33
|
+
};
|
|
34
|
+
const ES = {
|
|
35
|
+
preview: 'Tu credencial se ha actualizado',
|
|
36
|
+
heading: 'Tu credencial se actualizó',
|
|
37
|
+
body: (issuerName, credentialName) => issuerName ? (credentialName ? (_jsxs(_Fragment, { children: [_jsx("strong", { children: issuerName }), " actualiz\u00F3 tu certificado", ' ', _jsxs("strong", { children: [ldquo, credentialName, rdquo] }), "."] })) : (_jsxs(_Fragment, { children: [_jsx("strong", { children: issuerName }), " actualiz\u00F3 una de tus credenciales."] }))) : credentialName ? (_jsxs(_Fragment, { children: ["Tu certificado", ' ', _jsxs("strong", { children: [ldquo, credentialName, rdquo] }), ' ', "se actualiz\u00F3."] })) : (_jsx(_Fragment, { children: "Una de tus credenciales se actualiz\u00F3." })),
|
|
38
|
+
signIn: 'Inicia sesión para ver la última versión.',
|
|
39
|
+
button: 'Ver actualizaciones',
|
|
40
|
+
sincerely: 'Atentamente,',
|
|
41
|
+
subject: 'Tu credencial se actualizó',
|
|
42
|
+
};
|
|
43
|
+
const FR = {
|
|
44
|
+
preview: 'Votre titre a été mis à jour',
|
|
45
|
+
heading: 'Votre titre a été mis à jour',
|
|
46
|
+
body: (issuerName, credentialName) => issuerName ? (credentialName ? (_jsxs(_Fragment, { children: [_jsx("strong", { children: issuerName }), " a mis \u00E0 jour votre certificat", ' ', _jsxs("strong", { children: [ldquo, credentialName, rdquo] }), "."] })) : (_jsxs(_Fragment, { children: [_jsx("strong", { children: issuerName }), " a mis \u00E0 jour l'un de vos titres."] }))) : credentialName ? (_jsxs(_Fragment, { children: ["Votre certificat", ' ', _jsxs("strong", { children: [ldquo, credentialName, rdquo] }), ' ', "a \u00E9t\u00E9 mis \u00E0 jour."] })) : (_jsx(_Fragment, { children: "L'un de vos titres a \u00E9t\u00E9 mis \u00E0 jour." })),
|
|
47
|
+
signIn: 'Connectez-vous pour voir la dernière version.',
|
|
48
|
+
button: 'Voir les mises à jour',
|
|
49
|
+
sincerely: 'Cordialement,',
|
|
50
|
+
subject: 'Votre titre a été mis à jour',
|
|
51
|
+
};
|
|
52
|
+
const AR = {
|
|
53
|
+
preview: 'تم تحديث شهادتك',
|
|
54
|
+
heading: 'تم تحديث شهادتك',
|
|
55
|
+
body: (issuerName, credentialName) => issuerName ? (credentialName ? (_jsxs(_Fragment, { children: ["\u0642\u0627\u0645 ", _jsx("strong", { children: issuerName }), " \u0628\u062A\u062D\u062F\u064A\u062B \u0634\u0647\u0627\u062F\u062A\u0643", ' ', _jsxs("strong", { children: [ldquo, credentialName, rdquo] }), "."] })) : (_jsxs(_Fragment, { children: ["\u0642\u0627\u0645 ", _jsx("strong", { children: issuerName }), " \u0628\u062A\u062D\u062F\u064A\u062B \u0625\u062D\u062F\u0649 \u0634\u0647\u0627\u062F\u0627\u062A\u0643."] }))) : credentialName ? (_jsxs(_Fragment, { children: ["\u062A\u0645 \u062A\u062D\u062F\u064A\u062B \u0634\u0647\u0627\u062F\u062A\u0643", ' ', _jsxs("strong", { children: [ldquo, credentialName, rdquo] }), "."] })) : (_jsx(_Fragment, { children: "\u062A\u0645 \u062A\u062D\u062F\u064A\u062B \u0625\u062D\u062F\u0649 \u0634\u0647\u0627\u062F\u0627\u062A\u0643." })),
|
|
56
|
+
signIn: 'سجّل الدخول لعرض أحدث إصدار.',
|
|
57
|
+
button: 'عرض التحديثات',
|
|
58
|
+
sincerely: 'مع التحيات،',
|
|
59
|
+
subject: 'تم تحديث شهادتك',
|
|
60
|
+
};
|
|
61
|
+
const STRINGS = { en: EN, es: ES, fr: FR, ar: AR };
|
|
62
|
+
/** Notifications page of the configured app (never a claim or token URL). */
|
|
63
|
+
const notificationsUrl = (branding) => `${branding.appUrl.replace(/\/+$/, '')}/notifications`;
|
|
64
|
+
export const CredentialUpdated = ({ branding, issuer, credential, locale, }) => {
|
|
65
|
+
const s = STRINGS[resolveCatalogLocale(locale)];
|
|
66
|
+
const issuerName = issuer?.name;
|
|
67
|
+
const credentialName = credential?.name;
|
|
68
|
+
const updatesUrl = notificationsUrl(branding);
|
|
69
|
+
return (_jsxs(Layout, { branding: branding, locale: locale, preview: s.preview, showHeaderLogo: !issuer?.logoUrl, children: [_jsx(IssuerLogo, { logoUrl: issuer?.logoUrl, alt: issuerName ? `${issuerName} logo` : undefined }), _jsx(Text, { style: heading, children: s.heading }), _jsx(Text, { style: paragraph, children: s.body(issuerName, credentialName) }), _jsx(Text, { style: paragraph, children: s.signIn }), _jsx(Section, { style: buttonWrapper, children: _jsx(EmailButton, { href: updatesUrl, branding: branding, children: s.button }) }), _jsxs(Text, { style: signOff, children: [s.sincerely, _jsx("br", {}), interpolate(SHARED[resolveCatalogLocale(locale)].teamSignature, {
|
|
70
|
+
brandName: branding.brandName,
|
|
71
|
+
})] }), _jsx(LinkFallback, { href: updatesUrl, locale: locale })] }));
|
|
72
|
+
};
|
|
73
|
+
export const getCredentialUpdatedSubject = (_branding, locale) => STRINGS[resolveCatalogLocale(locale)].subject;
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// Styles
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
const heading = {
|
|
78
|
+
fontSize: 24,
|
|
79
|
+
fontWeight: 600,
|
|
80
|
+
color: '#111827',
|
|
81
|
+
margin: '0 0 24px',
|
|
82
|
+
};
|
|
83
|
+
const paragraph = {
|
|
84
|
+
fontSize: 16,
|
|
85
|
+
color: '#374151',
|
|
86
|
+
lineHeight: '24px',
|
|
87
|
+
margin: '0 0 24px',
|
|
88
|
+
};
|
|
89
|
+
const buttonWrapper = {
|
|
90
|
+
margin: '0 0 24px',
|
|
91
|
+
};
|
|
92
|
+
const signOff = {
|
|
93
|
+
fontSize: 14,
|
|
94
|
+
color: '#374151',
|
|
95
|
+
lineHeight: '20px',
|
|
96
|
+
margin: '24px 0 0',
|
|
97
|
+
};
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// Preview
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
export default function Preview() {
|
|
102
|
+
return (_jsx(CredentialUpdated, { branding: DEFAULT_BRANDING, issuer: { name: 'Inbox Demo School' }, credential: { name: 'Introduction to Biology' } }));
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=credential-updated.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-updated.js","sourceRoot":"","sources":["../../src/templates/credential-updated.tsx"],"names":[],"mappings":"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"}
|
|
@@ -10,16 +10,18 @@ export { RecoveryKey, getRecoveryKeySubject } from './recovery-key';
|
|
|
10
10
|
export type { RecoveryKeyProps } from './recovery-key';
|
|
11
11
|
export { EndorsementRequest, getEndorsementRequestSubject } from './endorsement-request';
|
|
12
12
|
export type { EndorsementRequestProps } from './endorsement-request';
|
|
13
|
-
export { CredentialAwaitingGuardian, getCredentialAwaitingGuardianSubject } from './credential-awaiting-guardian';
|
|
13
|
+
export { CredentialAwaitingGuardian, getCredentialAwaitingGuardianSubject, } from './credential-awaiting-guardian';
|
|
14
14
|
export type { CredentialAwaitingGuardianProps } from './credential-awaiting-guardian';
|
|
15
15
|
export { GuardianApprovedClaim, getGuardianApprovedClaimSubject } from './guardian-approved-claim';
|
|
16
16
|
export type { GuardianApprovedClaimProps } from './guardian-approved-claim';
|
|
17
|
-
export { GuardianCredentialApproval, getGuardianCredentialApprovalSubject } from './guardian-credential-approval';
|
|
17
|
+
export { GuardianCredentialApproval, getGuardianCredentialApprovalSubject, } from './guardian-credential-approval';
|
|
18
18
|
export type { GuardianCredentialApprovalProps } from './guardian-credential-approval';
|
|
19
19
|
export { GuardianEmailOtp, getGuardianEmailOtpSubject } from './guardian-email-otp';
|
|
20
20
|
export type { GuardianEmailOtpProps } from './guardian-email-otp';
|
|
21
|
-
export { GuardianRejectedCredential, getGuardianRejectedCredentialSubject } from './guardian-rejected-credential';
|
|
21
|
+
export { GuardianRejectedCredential, getGuardianRejectedCredentialSubject, } from './guardian-rejected-credential';
|
|
22
22
|
export type { GuardianRejectedCredentialProps } from './guardian-rejected-credential';
|
|
23
23
|
export { EmailVerification, getEmailVerificationSubject } from './email-verification';
|
|
24
24
|
export type { EmailVerificationProps } from './email-verification';
|
|
25
|
+
export { CredentialUpdated, getCredentialUpdatedSubject } from './credential-updated';
|
|
26
|
+
export type { CredentialUpdatedProps } from './credential-updated';
|
|
25
27
|
//# 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,
|
|
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"}
|
package/dist/templates/index.js
CHANGED
|
@@ -4,10 +4,11 @@ export { GuardianApproval, getGuardianApprovalSubject } from './guardian-approva
|
|
|
4
4
|
export { AccountApproved, getAccountApprovedSubject } from './account-approved';
|
|
5
5
|
export { RecoveryKey, getRecoveryKeySubject } from './recovery-key';
|
|
6
6
|
export { EndorsementRequest, getEndorsementRequestSubject } from './endorsement-request';
|
|
7
|
-
export { CredentialAwaitingGuardian, getCredentialAwaitingGuardianSubject } from './credential-awaiting-guardian';
|
|
7
|
+
export { CredentialAwaitingGuardian, getCredentialAwaitingGuardianSubject, } from './credential-awaiting-guardian';
|
|
8
8
|
export { GuardianApprovedClaim, getGuardianApprovedClaimSubject } from './guardian-approved-claim';
|
|
9
|
-
export { GuardianCredentialApproval, getGuardianCredentialApprovalSubject } from './guardian-credential-approval';
|
|
9
|
+
export { GuardianCredentialApproval, getGuardianCredentialApprovalSubject, } from './guardian-credential-approval';
|
|
10
10
|
export { GuardianEmailOtp, getGuardianEmailOtpSubject } from './guardian-email-otp';
|
|
11
|
-
export { GuardianRejectedCredential, getGuardianRejectedCredentialSubject } from './guardian-rejected-credential';
|
|
11
|
+
export { GuardianRejectedCredential, getGuardianRejectedCredentialSubject, } from './guardian-rejected-credential';
|
|
12
12
|
export { EmailVerification, getEmailVerificationSubject } from './email-verification';
|
|
13
|
+
export { CredentialUpdated, getCredentialUpdatedSubject } from './credential-updated';
|
|
13
14
|
//# 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,
|
|
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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@learncard/email-templates",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
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",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@types/react": "^18.3.0",
|
|
27
27
|
"react-email": "^3.0.0",
|
|
28
28
|
"typescript": "^5.0.0",
|
|
29
|
-
"vitest": "4.1.
|
|
29
|
+
"vitest": "4.1.11"
|
|
30
30
|
},
|
|
31
31
|
"author": "Learning Economy Foundation (www.learningeconomy.io)",
|
|
32
32
|
"license": "MIT",
|
|
@@ -130,6 +130,11 @@ const TEMPLATE_FIXTURES: { [K in TemplateId]: TemplateDataMap[K] } = {
|
|
|
130
130
|
credential: { name: 'Diploma' },
|
|
131
131
|
recipient: { email: 'student@example.com' },
|
|
132
132
|
},
|
|
133
|
+
|
|
134
|
+
'credential-updated': {
|
|
135
|
+
issuer: { name: 'Inbox Demo School' },
|
|
136
|
+
credential: { name: 'Introduction to Biology' },
|
|
137
|
+
},
|
|
133
138
|
};
|
|
134
139
|
|
|
135
140
|
const ALL_TEMPLATE_IDS = Object.keys(TEMPLATE_FIXTURES) as TemplateId[];
|
|
@@ -139,38 +144,40 @@ const ALL_TEMPLATE_IDS = Object.keys(TEMPLATE_FIXTURES) as TemplateId[];
|
|
|
139
144
|
// ---------------------------------------------------------------------------
|
|
140
145
|
|
|
141
146
|
describe('renderEmail — smoke tests', () => {
|
|
142
|
-
it.each(ALL_TEMPLATE_IDS)(
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
147
|
+
it.each(ALL_TEMPLATE_IDS)('"%s" renders with default branding', async templateId => {
|
|
148
|
+
const result = await renderEmail(
|
|
149
|
+
templateId,
|
|
150
|
+
DEFAULT_BRANDING,
|
|
151
|
+
TEMPLATE_FIXTURES[templateId]
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
expect(result.html).toBeTruthy();
|
|
155
|
+
expect(result.html).toContain('<!DOCTYPE');
|
|
156
|
+
expect(result.text).toBeTruthy();
|
|
157
|
+
expect(result.subject).toBeTruthy();
|
|
158
|
+
expect(result.subject.length).toBeGreaterThan(0);
|
|
159
|
+
});
|
|
154
160
|
|
|
155
|
-
it.each(ALL_TEMPLATE_IDS)(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
161
|
+
it.each(ALL_TEMPLATE_IDS)('"%s" renders with custom (VetPass) branding', async templateId => {
|
|
162
|
+
const result = await renderEmail(
|
|
163
|
+
templateId,
|
|
164
|
+
VETPASS_BRANDING,
|
|
165
|
+
TEMPLATE_FIXTURES[templateId]
|
|
166
|
+
);
|
|
159
167
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
);
|
|
168
|
+
expect(result.html).toBeTruthy();
|
|
169
|
+
expect(result.text).toBeTruthy();
|
|
170
|
+
expect(result.subject).toBeTruthy();
|
|
171
|
+
});
|
|
165
172
|
|
|
166
173
|
it.each(ALL_TEMPLATE_IDS)(
|
|
167
174
|
'"%s" renders with empty branding (falls back to defaults)',
|
|
168
|
-
async
|
|
175
|
+
async templateId => {
|
|
169
176
|
const result = await renderEmail(templateId, {}, TEMPLATE_FIXTURES[templateId]);
|
|
170
177
|
|
|
171
178
|
expect(result.html).toBeTruthy();
|
|
172
179
|
expect(result.subject).toBeTruthy();
|
|
173
|
-
}
|
|
180
|
+
}
|
|
174
181
|
);
|
|
175
182
|
});
|
|
176
183
|
|
|
@@ -292,6 +299,89 @@ describe('renderEmail — content assertions', () => {
|
|
|
292
299
|
});
|
|
293
300
|
});
|
|
294
301
|
|
|
302
|
+
// ---------------------------------------------------------------------------
|
|
303
|
+
// credential-updated — minimal-context update email (LC-2198)
|
|
304
|
+
// ---------------------------------------------------------------------------
|
|
305
|
+
|
|
306
|
+
describe('renderEmail — credential-updated', () => {
|
|
307
|
+
it('includes the issuer display name and credential title', async () => {
|
|
308
|
+
const data = TEMPLATE_FIXTURES['credential-updated'];
|
|
309
|
+
const { html } = await renderEmail('credential-updated', DEFAULT_BRANDING, data);
|
|
310
|
+
|
|
311
|
+
expect(html).toContain('Inbox Demo School');
|
|
312
|
+
expect(html).toContain('Introduction to Biology');
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('links the CTA to the configured app notifications page, not a claim or token URL', async () => {
|
|
316
|
+
const { html } = await renderEmail('credential-updated', VETPASS_BRANDING, {
|
|
317
|
+
issuer: { name: 'Vet School' },
|
|
318
|
+
credential: { name: 'Veterinary Ethics' },
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
expect(html).toContain('https://vetpass.app/notifications');
|
|
322
|
+
expect(html).not.toContain('/claim');
|
|
323
|
+
expect(html).not.toContain('token=');
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('falls back to generic copy when no credential title is available', async () => {
|
|
327
|
+
const { html, text } = await renderEmail('credential-updated', DEFAULT_BRANDING, {
|
|
328
|
+
issuer: { name: 'Inbox Demo School' },
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
expect(html).toContain('Inbox Demo School');
|
|
332
|
+
// Generic copy confirms an update without inventing a title.
|
|
333
|
+
expect(html.toLowerCase()).toContain('updated');
|
|
334
|
+
expect(text.toLowerCase()).toContain('updated');
|
|
335
|
+
expect(html).not.toContain('undefined');
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('never renders issuer-authored summary or credential body content', async () => {
|
|
339
|
+
// The data shape only carries issuer + title; assert nothing else leaks.
|
|
340
|
+
const { html } = await renderEmail('credential-updated', DEFAULT_BRANDING, {
|
|
341
|
+
issuer: { name: 'Inbox Demo School' },
|
|
342
|
+
credential: { name: 'Introduction to Biology' },
|
|
343
|
+
} as unknown as (typeof TEMPLATE_FIXTURES)['credential-updated']);
|
|
344
|
+
|
|
345
|
+
expect(html).not.toContain('updateSummary');
|
|
346
|
+
expect(html).not.toContain('credentialSubject');
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it.each([
|
|
350
|
+
{ locale: 'es', expected: 'actualiz' },
|
|
351
|
+
{ locale: 'fr', expected: 'mis' },
|
|
352
|
+
{ locale: 'ar', expected: 'تم' },
|
|
353
|
+
])('renders localized copy for $locale', async ({ locale, expected }) => {
|
|
354
|
+
const data = TEMPLATE_FIXTURES['credential-updated'];
|
|
355
|
+
const { html, subject } = await renderEmail(
|
|
356
|
+
'credential-updated',
|
|
357
|
+
DEFAULT_BRANDING,
|
|
358
|
+
data,
|
|
359
|
+
locale
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
expect(subject).toBeTruthy();
|
|
363
|
+
expect(html).toContain(expected);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it('plain text output is readable and free of HTML tags', async () => {
|
|
367
|
+
const data = TEMPLATE_FIXTURES['credential-updated'];
|
|
368
|
+
const { text } = await renderEmail('credential-updated', DEFAULT_BRANDING, data);
|
|
369
|
+
|
|
370
|
+
expect(text).not.toMatch(/<[a-z][\s\S]*>/i);
|
|
371
|
+
expect(text).toContain('Inbox Demo School');
|
|
372
|
+
expect(text).toContain('Introduction to Biology');
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it('flows tenant branding through to the rendered email', async () => {
|
|
376
|
+
const data = TEMPLATE_FIXTURES['credential-updated'];
|
|
377
|
+
const { html } = await renderEmail('credential-updated', VETPASS_BRANDING, data);
|
|
378
|
+
|
|
379
|
+
expect(html).toContain('VetPass');
|
|
380
|
+
expect(html).toContain('#1B5E20');
|
|
381
|
+
expect(html).toContain('support@vetpass.app');
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
|
|
295
385
|
// ---------------------------------------------------------------------------
|
|
296
386
|
// Branding tests — custom branding flows through to rendered output
|
|
297
387
|
// ---------------------------------------------------------------------------
|
|
@@ -366,10 +456,33 @@ describe('renderEmail — subjects', () => {
|
|
|
366
456
|
expect(subject).toBe('Verify Your Email');
|
|
367
457
|
});
|
|
368
458
|
|
|
459
|
+
it('credential-updated subject is localized and generic', async () => {
|
|
460
|
+
const [en, es] = await Promise.all([
|
|
461
|
+
renderEmail(
|
|
462
|
+
'credential-updated',
|
|
463
|
+
DEFAULT_BRANDING,
|
|
464
|
+
TEMPLATE_FIXTURES['credential-updated']
|
|
465
|
+
),
|
|
466
|
+
renderEmail(
|
|
467
|
+
'credential-updated',
|
|
468
|
+
DEFAULT_BRANDING,
|
|
469
|
+
TEMPLATE_FIXTURES['credential-updated'],
|
|
470
|
+
'es'
|
|
471
|
+
),
|
|
472
|
+
]);
|
|
473
|
+
|
|
474
|
+
expect(en.subject).toBe('Your credential was updated');
|
|
475
|
+
expect(es.subject).toBe('Tu credencial se actualizó');
|
|
476
|
+
});
|
|
477
|
+
|
|
369
478
|
it('Postmark alias pairs produce the same subject', async () => {
|
|
370
479
|
const [a, b] = await Promise.all([
|
|
371
480
|
renderEmail('inbox-claim', DEFAULT_BRANDING, TEMPLATE_FIXTURES['inbox-claim']),
|
|
372
|
-
renderEmail(
|
|
481
|
+
renderEmail(
|
|
482
|
+
'universal-inbox-claim',
|
|
483
|
+
DEFAULT_BRANDING,
|
|
484
|
+
TEMPLATE_FIXTURES['inbox-claim']
|
|
485
|
+
),
|
|
373
486
|
]);
|
|
374
487
|
|
|
375
488
|
expect(a.subject).toBe(b.subject);
|
|
@@ -382,13 +495,21 @@ describe('renderEmail — subjects', () => {
|
|
|
382
495
|
|
|
383
496
|
describe('renderEmail — plain text', () => {
|
|
384
497
|
it('plain text output does not contain HTML tags', async () => {
|
|
385
|
-
const { text } = await renderEmail(
|
|
498
|
+
const { text } = await renderEmail(
|
|
499
|
+
'inbox-claim',
|
|
500
|
+
DEFAULT_BRANDING,
|
|
501
|
+
TEMPLATE_FIXTURES['inbox-claim']
|
|
502
|
+
);
|
|
386
503
|
|
|
387
504
|
expect(text).not.toMatch(/<[a-z][\s\S]*>/i);
|
|
388
505
|
});
|
|
389
506
|
|
|
390
507
|
it('plain text includes key content', async () => {
|
|
391
|
-
const { text } = await renderEmail(
|
|
508
|
+
const { text } = await renderEmail(
|
|
509
|
+
'recovery-key',
|
|
510
|
+
DEFAULT_BRANDING,
|
|
511
|
+
TEMPLATE_FIXTURES['recovery-key']
|
|
512
|
+
);
|
|
392
513
|
|
|
393
514
|
expect(text).toContain('ABCD-EFGH-1234-5678');
|
|
394
515
|
});
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* credential-updated — minimal-context update notice scenarios.
|
|
3
|
+
*
|
|
4
|
+
* Shows the title/no-title fallback and locale variants so reviewers can verify
|
|
5
|
+
* the email never renders grades, subject details, or issuer summaries.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as React from 'react';
|
|
9
|
+
|
|
10
|
+
import { CredentialUpdated } from '../templates/credential-updated';
|
|
11
|
+
import { LEARNCARD_BRANDING, VETPASS_BRANDING, ScenarioDivider } from './_fixtures';
|
|
12
|
+
|
|
13
|
+
export default function CredentialUpdatedScenarios() {
|
|
14
|
+
return (
|
|
15
|
+
<>
|
|
16
|
+
<ScenarioDivider label="English — with credential title" />
|
|
17
|
+
<CredentialUpdated
|
|
18
|
+
branding={LEARNCARD_BRANDING}
|
|
19
|
+
issuer={{ name: 'Inbox Demo School' }}
|
|
20
|
+
credential={{ name: 'Introduction to Biology' }}
|
|
21
|
+
/>
|
|
22
|
+
|
|
23
|
+
<ScenarioDivider label="English — title unavailable (generic fallback)" />
|
|
24
|
+
<CredentialUpdated
|
|
25
|
+
branding={LEARNCARD_BRANDING}
|
|
26
|
+
issuer={{ name: 'Inbox Demo School' }}
|
|
27
|
+
/>
|
|
28
|
+
|
|
29
|
+
<ScenarioDivider label="Spanish" />
|
|
30
|
+
<CredentialUpdated
|
|
31
|
+
branding={LEARNCARD_BRANDING}
|
|
32
|
+
issuer={{ name: 'Escuela Demo' }}
|
|
33
|
+
credential={{ name: 'Introducción a la Biología' }}
|
|
34
|
+
locale="es"
|
|
35
|
+
/>
|
|
36
|
+
|
|
37
|
+
<ScenarioDivider label="French" />
|
|
38
|
+
<CredentialUpdated
|
|
39
|
+
branding={LEARNCARD_BRANDING}
|
|
40
|
+
issuer={{ name: 'École Démo' }}
|
|
41
|
+
credential={{ name: 'Introduction à la biologie' }}
|
|
42
|
+
locale="fr"
|
|
43
|
+
/>
|
|
44
|
+
|
|
45
|
+
<ScenarioDivider label="Arabic (RTL)" />
|
|
46
|
+
<CredentialUpdated
|
|
47
|
+
branding={LEARNCARD_BRANDING}
|
|
48
|
+
issuer={{ name: 'مدرسة تجريبية' }}
|
|
49
|
+
credential={{ name: 'مقدمة في علم الأحياء' }}
|
|
50
|
+
locale="ar"
|
|
51
|
+
/>
|
|
52
|
+
|
|
53
|
+
<ScenarioDivider label="VetPass branding" />
|
|
54
|
+
<CredentialUpdated
|
|
55
|
+
branding={VETPASS_BRANDING}
|
|
56
|
+
issuer={{ name: 'VetPass Academy' }}
|
|
57
|
+
credential={{ name: 'Veterinary Ethics' }}
|
|
58
|
+
/>
|
|
59
|
+
</>
|
|
60
|
+
);
|
|
61
|
+
}
|
package/src/render.ts
CHANGED
|
@@ -39,6 +39,8 @@ import {
|
|
|
39
39
|
getGuardianRejectedCredentialSubject,
|
|
40
40
|
EmailVerification,
|
|
41
41
|
getEmailVerificationSubject,
|
|
42
|
+
CredentialUpdated,
|
|
43
|
+
getCredentialUpdatedSubject,
|
|
42
44
|
} from './templates';
|
|
43
45
|
|
|
44
46
|
import type {
|
|
@@ -53,6 +55,7 @@ import type {
|
|
|
53
55
|
GuardianEmailOtpProps,
|
|
54
56
|
GuardianRejectedCredentialProps,
|
|
55
57
|
EmailVerificationProps,
|
|
58
|
+
CredentialUpdatedProps,
|
|
56
59
|
} from './templates';
|
|
57
60
|
|
|
58
61
|
// ---------------------------------------------------------------------------
|
|
@@ -146,6 +149,9 @@ export interface TemplateDataMap {
|
|
|
146
149
|
|
|
147
150
|
/** Sent to student: guardian rejected credential */
|
|
148
151
|
'guardian-rejected-credential': GuardianRejectedCredentialData;
|
|
152
|
+
|
|
153
|
+
/** brain-service: managed credential refresh update notice (LC-2198) */
|
|
154
|
+
'credential-updated': CredentialUpdatedData;
|
|
149
155
|
}
|
|
150
156
|
|
|
151
157
|
export type TemplateId = keyof TemplateDataMap;
|
|
@@ -223,6 +229,12 @@ export interface GuardianRejectedCredentialData {
|
|
|
223
229
|
recipient?: { email?: string };
|
|
224
230
|
}
|
|
225
231
|
|
|
232
|
+
export interface CredentialUpdatedData {
|
|
233
|
+
issuer?: { name?: string; logoUrl?: string };
|
|
234
|
+
/** Bounded credential display title. Omitted when unavailable. */
|
|
235
|
+
credential?: { name?: string };
|
|
236
|
+
}
|
|
237
|
+
|
|
226
238
|
// ---------------------------------------------------------------------------
|
|
227
239
|
// renderEmail()
|
|
228
240
|
// ---------------------------------------------------------------------------
|
|
@@ -420,6 +432,16 @@ function buildElement(
|
|
|
420
432
|
};
|
|
421
433
|
}
|
|
422
434
|
|
|
435
|
+
case 'credential-updated': {
|
|
436
|
+
const d = data as CredentialUpdatedData;
|
|
437
|
+
const props: CredentialUpdatedProps = { branding, ...d, locale };
|
|
438
|
+
|
|
439
|
+
return {
|
|
440
|
+
element: React.createElement(CredentialUpdated, props),
|
|
441
|
+
subject: getCredentialUpdatedSubject(branding, locale),
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
423
445
|
default: {
|
|
424
446
|
const _exhaustive: never = templateId;
|
|
425
447
|
throw new Error(`Unknown template: ${_exhaustive}`);
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CredentialUpdated — privacy-minimal notice that an issuer published a new
|
|
3
|
+
* version of a credential.
|
|
4
|
+
*
|
|
5
|
+
* Used by: brain-service credential-refresh publication (templateId:
|
|
6
|
+
* 'credential-updated').
|
|
7
|
+
*
|
|
8
|
+
* Deliberately minimal context: the issuer display name and the credential
|
|
9
|
+
* display title are the only dynamic values. No grades, subject/recipient
|
|
10
|
+
* details, evidence, body, or issuer-authored update summary is rendered. The
|
|
11
|
+
* CTA points at the recipient's own notifications page (never a claim URL and
|
|
12
|
+
* never a bearer token), so a forwarded email cannot be used to access the
|
|
13
|
+
* credential.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { Text, Section } from '@react-email/components';
|
|
17
|
+
import * as React from 'react';
|
|
18
|
+
|
|
19
|
+
import type { TenantBranding } from '../branding';
|
|
20
|
+
import { DEFAULT_BRANDING } from '../branding';
|
|
21
|
+
import { Layout } from '../components/Layout';
|
|
22
|
+
import { EmailButton } from '../components/EmailButton';
|
|
23
|
+
import { IssuerLogo } from '../components/IssuerLogo';
|
|
24
|
+
import { LinkFallback } from '../components/LinkFallback';
|
|
25
|
+
import type { NotificationLocale } from '../i18n';
|
|
26
|
+
import { resolveCatalogLocale, interpolate, SHARED } from '../i18n';
|
|
27
|
+
|
|
28
|
+
export interface CredentialUpdatedProps {
|
|
29
|
+
branding: TenantBranding;
|
|
30
|
+
issuer?: {
|
|
31
|
+
name?: string;
|
|
32
|
+
logoUrl?: string;
|
|
33
|
+
};
|
|
34
|
+
/** Bounded credential display title. Omitted when unavailable. */
|
|
35
|
+
credential?: {
|
|
36
|
+
name?: string;
|
|
37
|
+
};
|
|
38
|
+
/** Recipient locale (BCP-47). Defaults to English. */
|
|
39
|
+
locale?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const ldquo = '\u201C';
|
|
43
|
+
const rdquo = '\u201D';
|
|
44
|
+
|
|
45
|
+
type Strings = {
|
|
46
|
+
preview: string;
|
|
47
|
+
heading: string;
|
|
48
|
+
body: (issuerName: string | undefined, credentialName: string | undefined) => React.ReactNode;
|
|
49
|
+
signIn: string;
|
|
50
|
+
button: string;
|
|
51
|
+
sincerely: string;
|
|
52
|
+
subject: string;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const EN: Strings = {
|
|
56
|
+
preview: 'Your credential has been updated',
|
|
57
|
+
heading: 'Your credential was updated',
|
|
58
|
+
body: (issuerName, credentialName) =>
|
|
59
|
+
issuerName ? (
|
|
60
|
+
credentialName ? (
|
|
61
|
+
<>
|
|
62
|
+
<strong>{issuerName}</strong> updated your{' '}
|
|
63
|
+
<strong>
|
|
64
|
+
{ldquo}
|
|
65
|
+
{credentialName}
|
|
66
|
+
{rdquo}
|
|
67
|
+
</strong>{' '}
|
|
68
|
+
certificate.
|
|
69
|
+
</>
|
|
70
|
+
) : (
|
|
71
|
+
<>
|
|
72
|
+
<strong>{issuerName}</strong> updated one of your credentials.
|
|
73
|
+
</>
|
|
74
|
+
)
|
|
75
|
+
) : credentialName ? (
|
|
76
|
+
<>
|
|
77
|
+
Your{' '}
|
|
78
|
+
<strong>
|
|
79
|
+
{ldquo}
|
|
80
|
+
{credentialName}
|
|
81
|
+
{rdquo}
|
|
82
|
+
</strong>{' '}
|
|
83
|
+
certificate was updated.
|
|
84
|
+
</>
|
|
85
|
+
) : (
|
|
86
|
+
<>One of your credentials was updated.</>
|
|
87
|
+
),
|
|
88
|
+
signIn: 'Sign in to view the latest version.',
|
|
89
|
+
button: 'View Updates',
|
|
90
|
+
sincerely: 'Sincerely,',
|
|
91
|
+
subject: 'Your credential was updated',
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const ES: Strings = {
|
|
95
|
+
preview: 'Tu credencial se ha actualizado',
|
|
96
|
+
heading: 'Tu credencial se actualizó',
|
|
97
|
+
body: (issuerName, credentialName) =>
|
|
98
|
+
issuerName ? (
|
|
99
|
+
credentialName ? (
|
|
100
|
+
<>
|
|
101
|
+
<strong>{issuerName}</strong> actualizó tu certificado{' '}
|
|
102
|
+
<strong>
|
|
103
|
+
{ldquo}
|
|
104
|
+
{credentialName}
|
|
105
|
+
{rdquo}
|
|
106
|
+
</strong>
|
|
107
|
+
.
|
|
108
|
+
</>
|
|
109
|
+
) : (
|
|
110
|
+
<>
|
|
111
|
+
<strong>{issuerName}</strong> actualizó una de tus credenciales.
|
|
112
|
+
</>
|
|
113
|
+
)
|
|
114
|
+
) : credentialName ? (
|
|
115
|
+
<>
|
|
116
|
+
Tu certificado{' '}
|
|
117
|
+
<strong>
|
|
118
|
+
{ldquo}
|
|
119
|
+
{credentialName}
|
|
120
|
+
{rdquo}
|
|
121
|
+
</strong>{' '}
|
|
122
|
+
se actualizó.
|
|
123
|
+
</>
|
|
124
|
+
) : (
|
|
125
|
+
<>Una de tus credenciales se actualizó.</>
|
|
126
|
+
),
|
|
127
|
+
signIn: 'Inicia sesión para ver la última versión.',
|
|
128
|
+
button: 'Ver actualizaciones',
|
|
129
|
+
sincerely: 'Atentamente,',
|
|
130
|
+
subject: 'Tu credencial se actualizó',
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const FR: Strings = {
|
|
134
|
+
preview: 'Votre titre a été mis à jour',
|
|
135
|
+
heading: 'Votre titre a été mis à jour',
|
|
136
|
+
body: (issuerName, credentialName) =>
|
|
137
|
+
issuerName ? (
|
|
138
|
+
credentialName ? (
|
|
139
|
+
<>
|
|
140
|
+
<strong>{issuerName}</strong> a mis à jour votre certificat{' '}
|
|
141
|
+
<strong>
|
|
142
|
+
{ldquo}
|
|
143
|
+
{credentialName}
|
|
144
|
+
{rdquo}
|
|
145
|
+
</strong>
|
|
146
|
+
.
|
|
147
|
+
</>
|
|
148
|
+
) : (
|
|
149
|
+
<>
|
|
150
|
+
<strong>{issuerName}</strong> a mis à jour l'un de vos titres.
|
|
151
|
+
</>
|
|
152
|
+
)
|
|
153
|
+
) : credentialName ? (
|
|
154
|
+
<>
|
|
155
|
+
Votre certificat{' '}
|
|
156
|
+
<strong>
|
|
157
|
+
{ldquo}
|
|
158
|
+
{credentialName}
|
|
159
|
+
{rdquo}
|
|
160
|
+
</strong>{' '}
|
|
161
|
+
a été mis à jour.
|
|
162
|
+
</>
|
|
163
|
+
) : (
|
|
164
|
+
<>L'un de vos titres a été mis à jour.</>
|
|
165
|
+
),
|
|
166
|
+
signIn: 'Connectez-vous pour voir la dernière version.',
|
|
167
|
+
button: 'Voir les mises à jour',
|
|
168
|
+
sincerely: 'Cordialement,',
|
|
169
|
+
subject: 'Votre titre a été mis à jour',
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const AR: Strings = {
|
|
173
|
+
preview: 'تم تحديث شهادتك',
|
|
174
|
+
heading: 'تم تحديث شهادتك',
|
|
175
|
+
body: (issuerName, credentialName) =>
|
|
176
|
+
issuerName ? (
|
|
177
|
+
credentialName ? (
|
|
178
|
+
<>
|
|
179
|
+
قام <strong>{issuerName}</strong> بتحديث شهادتك{' '}
|
|
180
|
+
<strong>
|
|
181
|
+
{ldquo}
|
|
182
|
+
{credentialName}
|
|
183
|
+
{rdquo}
|
|
184
|
+
</strong>
|
|
185
|
+
.
|
|
186
|
+
</>
|
|
187
|
+
) : (
|
|
188
|
+
<>
|
|
189
|
+
قام <strong>{issuerName}</strong> بتحديث إحدى شهاداتك.
|
|
190
|
+
</>
|
|
191
|
+
)
|
|
192
|
+
) : credentialName ? (
|
|
193
|
+
<>
|
|
194
|
+
تم تحديث شهادتك{' '}
|
|
195
|
+
<strong>
|
|
196
|
+
{ldquo}
|
|
197
|
+
{credentialName}
|
|
198
|
+
{rdquo}
|
|
199
|
+
</strong>
|
|
200
|
+
.
|
|
201
|
+
</>
|
|
202
|
+
) : (
|
|
203
|
+
<>تم تحديث إحدى شهاداتك.</>
|
|
204
|
+
),
|
|
205
|
+
signIn: 'سجّل الدخول لعرض أحدث إصدار.',
|
|
206
|
+
button: 'عرض التحديثات',
|
|
207
|
+
sincerely: 'مع التحيات،',
|
|
208
|
+
subject: 'تم تحديث شهادتك',
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const STRINGS: Record<NotificationLocale, Strings> = { en: EN, es: ES, fr: FR, ar: AR };
|
|
212
|
+
|
|
213
|
+
/** Notifications page of the configured app (never a claim or token URL). */
|
|
214
|
+
const notificationsUrl = (branding: TenantBranding): string =>
|
|
215
|
+
`${branding.appUrl.replace(/\/+$/, '')}/notifications`;
|
|
216
|
+
|
|
217
|
+
export const CredentialUpdated: React.FC<CredentialUpdatedProps> = ({
|
|
218
|
+
branding,
|
|
219
|
+
issuer,
|
|
220
|
+
credential,
|
|
221
|
+
locale,
|
|
222
|
+
}) => {
|
|
223
|
+
const s = STRINGS[resolveCatalogLocale(locale)];
|
|
224
|
+
const issuerName = issuer?.name;
|
|
225
|
+
const credentialName = credential?.name;
|
|
226
|
+
const updatesUrl = notificationsUrl(branding);
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
<Layout
|
|
230
|
+
branding={branding}
|
|
231
|
+
locale={locale}
|
|
232
|
+
preview={s.preview}
|
|
233
|
+
showHeaderLogo={!issuer?.logoUrl}
|
|
234
|
+
>
|
|
235
|
+
<IssuerLogo
|
|
236
|
+
logoUrl={issuer?.logoUrl}
|
|
237
|
+
alt={issuerName ? `${issuerName} logo` : undefined}
|
|
238
|
+
/>
|
|
239
|
+
|
|
240
|
+
<Text style={heading}>{s.heading}</Text>
|
|
241
|
+
|
|
242
|
+
<Text style={paragraph}>{s.body(issuerName, credentialName)}</Text>
|
|
243
|
+
|
|
244
|
+
<Text style={paragraph}>{s.signIn}</Text>
|
|
245
|
+
|
|
246
|
+
<Section style={buttonWrapper}>
|
|
247
|
+
<EmailButton href={updatesUrl} branding={branding}>
|
|
248
|
+
{s.button}
|
|
249
|
+
</EmailButton>
|
|
250
|
+
</Section>
|
|
251
|
+
|
|
252
|
+
<Text style={signOff}>
|
|
253
|
+
{s.sincerely}
|
|
254
|
+
<br />
|
|
255
|
+
{interpolate(SHARED[resolveCatalogLocale(locale)].teamSignature, {
|
|
256
|
+
brandName: branding.brandName,
|
|
257
|
+
})}
|
|
258
|
+
</Text>
|
|
259
|
+
|
|
260
|
+
<LinkFallback href={updatesUrl} locale={locale} />
|
|
261
|
+
</Layout>
|
|
262
|
+
);
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
export const getCredentialUpdatedSubject = (_branding: TenantBranding, locale?: string): string =>
|
|
266
|
+
STRINGS[resolveCatalogLocale(locale)].subject;
|
|
267
|
+
|
|
268
|
+
// ---------------------------------------------------------------------------
|
|
269
|
+
// Styles
|
|
270
|
+
// ---------------------------------------------------------------------------
|
|
271
|
+
|
|
272
|
+
const heading: React.CSSProperties = {
|
|
273
|
+
fontSize: 24,
|
|
274
|
+
fontWeight: 600,
|
|
275
|
+
color: '#111827',
|
|
276
|
+
margin: '0 0 24px',
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const paragraph: React.CSSProperties = {
|
|
280
|
+
fontSize: 16,
|
|
281
|
+
color: '#374151',
|
|
282
|
+
lineHeight: '24px',
|
|
283
|
+
margin: '0 0 24px',
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const buttonWrapper: React.CSSProperties = {
|
|
287
|
+
margin: '0 0 24px',
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const signOff: React.CSSProperties = {
|
|
291
|
+
fontSize: 14,
|
|
292
|
+
color: '#374151',
|
|
293
|
+
lineHeight: '20px',
|
|
294
|
+
margin: '24px 0 0',
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// ---------------------------------------------------------------------------
|
|
298
|
+
// Preview
|
|
299
|
+
// ---------------------------------------------------------------------------
|
|
300
|
+
|
|
301
|
+
export default function Preview() {
|
|
302
|
+
return (
|
|
303
|
+
<CredentialUpdated
|
|
304
|
+
branding={DEFAULT_BRANDING}
|
|
305
|
+
issuer={{ name: 'Inbox Demo School' }}
|
|
306
|
+
credential={{ name: 'Introduction to Biology' }}
|
|
307
|
+
/>
|
|
308
|
+
);
|
|
309
|
+
}
|
package/src/templates/index.ts
CHANGED
|
@@ -16,20 +16,32 @@ export type { RecoveryKeyProps } from './recovery-key';
|
|
|
16
16
|
export { EndorsementRequest, getEndorsementRequestSubject } from './endorsement-request';
|
|
17
17
|
export type { EndorsementRequestProps } from './endorsement-request';
|
|
18
18
|
|
|
19
|
-
export {
|
|
19
|
+
export {
|
|
20
|
+
CredentialAwaitingGuardian,
|
|
21
|
+
getCredentialAwaitingGuardianSubject,
|
|
22
|
+
} from './credential-awaiting-guardian';
|
|
20
23
|
export type { CredentialAwaitingGuardianProps } from './credential-awaiting-guardian';
|
|
21
24
|
|
|
22
25
|
export { GuardianApprovedClaim, getGuardianApprovedClaimSubject } from './guardian-approved-claim';
|
|
23
26
|
export type { GuardianApprovedClaimProps } from './guardian-approved-claim';
|
|
24
27
|
|
|
25
|
-
export {
|
|
28
|
+
export {
|
|
29
|
+
GuardianCredentialApproval,
|
|
30
|
+
getGuardianCredentialApprovalSubject,
|
|
31
|
+
} from './guardian-credential-approval';
|
|
26
32
|
export type { GuardianCredentialApprovalProps } from './guardian-credential-approval';
|
|
27
33
|
|
|
28
34
|
export { GuardianEmailOtp, getGuardianEmailOtpSubject } from './guardian-email-otp';
|
|
29
35
|
export type { GuardianEmailOtpProps } from './guardian-email-otp';
|
|
30
36
|
|
|
31
|
-
export {
|
|
37
|
+
export {
|
|
38
|
+
GuardianRejectedCredential,
|
|
39
|
+
getGuardianRejectedCredentialSubject,
|
|
40
|
+
} from './guardian-rejected-credential';
|
|
32
41
|
export type { GuardianRejectedCredentialProps } from './guardian-rejected-credential';
|
|
33
42
|
|
|
34
43
|
export { EmailVerification, getEmailVerificationSubject } from './email-verification';
|
|
35
44
|
export type { EmailVerificationProps } from './email-verification';
|
|
45
|
+
|
|
46
|
+
export { CredentialUpdated, getCredentialUpdatedSubject } from './credential-updated';
|
|
47
|
+
export type { CredentialUpdatedProps } from './credential-updated';
|