@learncard/react 2.12.0 → 2.12.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.
- package/dist/cjs/{BoostGenericCard-71899305.js → BoostGenericCard-06bedec7.js} +3 -3
- package/dist/cjs/{BoostGenericCard-71899305.js.map → BoostGenericCard-06bedec7.js.map} +1 -1
- package/dist/cjs/{CertificateDisplayCard-f10b46b1.js → CertificateDisplayCard-9c1d58da.js} +20 -14
- package/dist/cjs/CertificateDisplayCard-9c1d58da.js.map +1 -0
- package/dist/cjs/{MeritBadgeDisplayCard-d50cfb5e.js → MeritBadgeDisplayCard-201bf5ad.js} +4 -4
- package/dist/cjs/{MeritBadgeDisplayCard-d50cfb5e.js.map → MeritBadgeDisplayCard-201bf5ad.js.map} +1 -1
- package/dist/cjs/{MeritBadgeSkillsCount-e46503f5.js → MeritBadgeSkillsCount-ef283e0d.js} +2 -2
- package/dist/cjs/{MeritBadgeSkillsCount-e46503f5.js.map → MeritBadgeSkillsCount-ef283e0d.js.map} +1 -1
- package/dist/cjs/{SchoolIDCard-2d3cbb2c.js → SchoolIDCard-10796199.js} +1184 -3
- package/dist/cjs/SchoolIDCard-10796199.js.map +1 -0
- package/dist/cjs/{VCCard-42479c97.js → VCCard-d72176f3.js} +3 -3
- package/dist/cjs/{VCCard-42479c97.js.map → VCCard-d72176f3.js.map} +1 -1
- package/dist/cjs/{VCDisplayBackFace-d1cf9f73.js → VCDisplayBackFace-27460538.js} +3 -3
- package/dist/cjs/{VCDisplayBackFace-d1cf9f73.js.map → VCDisplayBackFace-27460538.js.map} +1 -1
- package/dist/cjs/{VCDisplayCard-cf46c224.js → VCDisplayCard-b05125ab.js} +3 -3
- package/dist/cjs/{VCDisplayCard-cf46c224.js.map → VCDisplayCard-b05125ab.js.map} +1 -1
- package/dist/cjs/{VCDisplayCard2-4a201a8a.js → VCDisplayCard2-78d4cc3f.js} +26 -18
- package/dist/cjs/VCDisplayCard2-78d4cc3f.js.map +1 -0
- package/dist/cjs/{VCVerificationPill-6c9dcf80.js → VCVerificationPill-3c130965.js} +2 -2
- package/dist/cjs/{VCVerificationPill-6c9dcf80.js.map → VCVerificationPill-3c130965.js.map} +1 -1
- package/dist/cjs/{VerifierStateBadgeAndText-934239ab.js → VerifierStateBadgeAndText-57a7b85f.js} +41 -4
- package/dist/cjs/VerifierStateBadgeAndText-57a7b85f.js.map +1 -0
- package/dist/cjs/{credential.helpers-17a10601.js → credential.helpers-3d0256cf.js} +2 -2
- package/dist/cjs/{credential.helpers-17a10601.js.map → credential.helpers-3d0256cf.js.map} +1 -1
- package/dist/cjs/{i18n-8fd90b2f.js → i18n-ddbb18e7.js} +12 -1
- package/dist/cjs/{i18n-8fd90b2f.js.map → i18n-ddbb18e7.js.map} +1 -1
- package/dist/cjs/index.js +14 -15
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/index14.js +14 -15
- package/dist/cjs/index14.js.map +1 -1
- package/dist/cjs/index22.js +6 -6
- package/dist/cjs/index31.js +1 -2
- package/dist/cjs/index31.js.map +1 -1
- package/dist/cjs/index39.js +11 -12
- package/dist/cjs/index39.js.map +1 -1
- package/dist/cjs/index4.js +4 -4
- package/dist/cjs/index40.js +4 -4
- package/dist/cjs/index41.js +5 -5
- package/dist/cjs/index42.js +7 -8
- package/dist/cjs/index42.js.map +1 -1
- package/dist/cjs/index43.js +1 -1
- package/dist/cjs/index46.js +2 -2
- package/dist/cjs/index7.js +5 -4
- package/dist/cjs/index7.js.map +1 -1
- package/dist/cjs/{types.esm-73624b33.js → types.esm-228757cd.js} +30 -2
- package/dist/cjs/types.esm-228757cd.js.map +1 -0
- package/dist/esm/{BoostGenericCard-3b3ff784.js → BoostGenericCard-d4ea46de.js} +3 -3
- package/dist/esm/{BoostGenericCard-3b3ff784.js.map → BoostGenericCard-d4ea46de.js.map} +1 -1
- package/dist/esm/{CertificateDisplayCard-f26ef278.js → CertificateDisplayCard-487a3b4e.js} +20 -14
- package/dist/esm/CertificateDisplayCard-487a3b4e.js.map +1 -0
- package/dist/esm/{MeritBadgeDisplayCard-0d0b28c7.js → MeritBadgeDisplayCard-13622cd4.js} +4 -4
- package/dist/esm/{MeritBadgeDisplayCard-0d0b28c7.js.map → MeritBadgeDisplayCard-13622cd4.js.map} +1 -1
- package/dist/esm/{MeritBadgeSkillsCount-09e211fc.js → MeritBadgeSkillsCount-11bd0ae3.js} +2 -2
- package/dist/esm/{MeritBadgeSkillsCount-09e211fc.js.map → MeritBadgeSkillsCount-11bd0ae3.js.map} +1 -1
- package/dist/esm/{SchoolIDCard-fbd1cf6c.js → SchoolIDCard-f82e40bc.js} +1183 -2
- package/dist/esm/SchoolIDCard-f82e40bc.js.map +1 -0
- package/dist/esm/{VCCard-7e5e00d7.js → VCCard-7fa8f15b.js} +3 -3
- package/dist/esm/{VCCard-7e5e00d7.js.map → VCCard-7fa8f15b.js.map} +1 -1
- package/dist/esm/{VCDisplayBackFace-ae74476d.js → VCDisplayBackFace-314c1107.js} +3 -3
- package/dist/esm/{VCDisplayBackFace-ae74476d.js.map → VCDisplayBackFace-314c1107.js.map} +1 -1
- package/dist/esm/{VCDisplayCard-ac1f367a.js → VCDisplayCard-652910f5.js} +3 -3
- package/dist/esm/{VCDisplayCard-ac1f367a.js.map → VCDisplayCard-652910f5.js.map} +1 -1
- package/dist/esm/{VCDisplayCard2-7011596e.js → VCDisplayCard2-a8b9a519.js} +26 -18
- package/dist/esm/VCDisplayCard2-a8b9a519.js.map +1 -0
- package/dist/esm/{VCVerificationPill-04ffdf56.js → VCVerificationPill-be1140c5.js} +2 -2
- package/dist/esm/{VCVerificationPill-04ffdf56.js.map → VCVerificationPill-be1140c5.js.map} +1 -1
- package/dist/esm/{VerifierStateBadgeAndText-750a6c24.js → VerifierStateBadgeAndText-97117c5d.js} +41 -4
- package/dist/{cjs/VerifierStateBadgeAndText-934239ab.js.map → esm/VerifierStateBadgeAndText-97117c5d.js.map} +1 -1
- package/dist/esm/{credential.helpers-4fbdd8e8.js → credential.helpers-3dfe6b60.js} +2 -2
- package/dist/esm/{credential.helpers-4fbdd8e8.js.map → credential.helpers-3dfe6b60.js.map} +1 -1
- package/dist/esm/{i18n-08b606cb.js → i18n-35209bfa.js} +12 -1
- package/dist/esm/{i18n-08b606cb.js.map → i18n-35209bfa.js.map} +1 -1
- package/dist/esm/index.js +14 -15
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index14.js +14 -15
- package/dist/esm/index14.js.map +1 -1
- package/dist/esm/index22.js +6 -6
- package/dist/esm/index31.js +1 -2
- package/dist/esm/index31.js.map +1 -1
- package/dist/esm/index39.js +11 -12
- package/dist/esm/index39.js.map +1 -1
- package/dist/esm/index4.js +4 -4
- package/dist/esm/index40.js +4 -4
- package/dist/esm/index41.js +5 -5
- package/dist/esm/index42.js +7 -8
- package/dist/esm/index42.js.map +1 -1
- package/dist/esm/index43.js +1 -1
- package/dist/esm/index46.js +2 -2
- package/dist/esm/index7.js +5 -4
- package/dist/esm/index7.js.map +1 -1
- package/dist/esm/{types.esm-5f75bd4a.js → types.esm-a67e86b1.js} +30 -2
- package/dist/esm/types.esm-a67e86b1.js.map +1 -0
- package/dist/main.css +1 -1
- package/dist/main.js +1 -1
- package/package.json +6 -10
- package/src/components/CertificateDisplayCard/AlignmentRow.tsx +4 -2
- package/src/components/CertificateDisplayCard/AlignmentsBox.tsx +12 -9
- package/src/components/CertificateDisplayCard/InfoBox.tsx +3 -1
- package/src/components/CertificateDisplayCard/VerifierStateBadgeAndText.tsx +10 -6
- package/src/components/CircleIcon/__tests__/CircleIcon.test.tsx +1 -1
- package/src/components/VCDisplayCard2/InfoBox.tsx +3 -1
- package/src/components/VCDisplayCard2/TruncateTextBox.tsx +4 -2
- package/src/components/VCDisplayCard2/VC2BackFace.tsx +6 -4
- package/src/components/VCDisplayCard2/VC2FrontFaceInfo.tsx +3 -1
- package/src/components/VCDisplayCard2/VCDisplayCard2.tsx +10 -2
- package/src/components/VCDisplayCard2/__tests__/VC2LocalizedLabels.test.tsx +122 -0
- package/src/helpers/credential.helpers.test.ts +1 -1
- package/src/i18n/index.tsx +12 -0
- package/dist/cjs/CertificateDisplayCard-f10b46b1.js.map +0 -1
- package/dist/cjs/SchoolIDCard-2d3cbb2c.js.map +0 -1
- package/dist/cjs/VCDisplayCard2-4a201a8a.js.map +0 -1
- package/dist/cjs/index-47efbf5b.js +0 -1186
- package/dist/cjs/index-47efbf5b.js.map +0 -1
- package/dist/cjs/types.esm-73624b33.js.map +0 -1
- package/dist/esm/CertificateDisplayCard-f26ef278.js.map +0 -1
- package/dist/esm/SchoolIDCard-fbd1cf6c.js.map +0 -1
- package/dist/esm/VCDisplayCard2-7011596e.js.map +0 -1
- package/dist/esm/VerifierStateBadgeAndText-750a6c24.js.map +0 -1
- package/dist/esm/index-cbd2e9db.js +0 -1184
- package/dist/esm/index-cbd2e9db.js.map +0 -1
- package/dist/esm/types.esm-5f75bd4a.js.map +0 -1
|
@@ -3,6 +3,7 @@ import UnknownVerifierBadge from '../svgs/UnknownVerifierBadge';
|
|
|
3
3
|
import VerifiedBadge from '../svgs/VerifiedBadge';
|
|
4
4
|
import PersonBadge from '../svgs/PersonBadge';
|
|
5
5
|
import RedFlag from '../svgs/RedFlag';
|
|
6
|
+
import { useT } from '../../i18n';
|
|
6
7
|
|
|
7
8
|
export const VERIFIER_STATES = {
|
|
8
9
|
selfVerified: 'Self Issued',
|
|
@@ -22,6 +23,7 @@ export type VerifierStateBadgeAndTextProps = {
|
|
|
22
23
|
|
|
23
24
|
const VerifierStateBadgeAndText = forwardRef<HTMLButtonElement, VerifierStateBadgeAndTextProps>(
|
|
24
25
|
({ verifierState, className = '', unknownVerifierTitle, onClick }, ref) => {
|
|
26
|
+
const t = useT();
|
|
25
27
|
// For Scouts: if we have a role-based title, show it with trusted styling
|
|
26
28
|
// BUT don't overwrite self-issued or untrusted status
|
|
27
29
|
const effectiveState =
|
|
@@ -37,35 +39,37 @@ const VerifierStateBadgeAndText = forwardRef<HTMLButtonElement, VerifierStateBad
|
|
|
37
39
|
{effectiveState === VERIFIER_STATES.selfVerified && (
|
|
38
40
|
<div className="flex items-center gap-0.5 font-poppins font-[500] text-[12px] leading-tight text-green-dark">
|
|
39
41
|
<PersonBadge />
|
|
40
|
-
<span className="whitespace-nowrap">
|
|
42
|
+
<span className="whitespace-nowrap">{t('verification.selfIssued')}</span>
|
|
41
43
|
</div>
|
|
42
44
|
)}
|
|
43
45
|
{effectiveState === VERIFIER_STATES.trustedVerifier && (
|
|
44
46
|
<div className="flex items-center gap-0.5 font-poppins font-[500] text-[12px] leading-tight text-green-600">
|
|
45
47
|
<VerifiedBadge />
|
|
46
48
|
<span className="whitespace-nowrap">
|
|
47
|
-
{unknownVerifierTitle ?? '
|
|
49
|
+
{unknownVerifierTitle ?? t('verification.trustedIssuer')}
|
|
48
50
|
</span>
|
|
49
51
|
</div>
|
|
50
52
|
)}
|
|
51
53
|
{effectiveState === VERIFIER_STATES.unknownVerifier && (
|
|
52
|
-
<div className="flex items-center gap-0.5 font-poppins font-[500] text-[12px] leading-tight text-orange-
|
|
54
|
+
<div className="flex items-center gap-0.5 font-poppins font-[500] text-[12px] leading-tight text-orange-800">
|
|
53
55
|
<UnknownVerifierBadge />
|
|
54
56
|
<span className="whitespace-nowrap">
|
|
55
|
-
{unknownVerifierTitle ??
|
|
57
|
+
{unknownVerifierTitle ?? t('verification.unknownIssuer')}
|
|
56
58
|
</span>
|
|
57
59
|
</div>
|
|
58
60
|
)}
|
|
59
61
|
{effectiveState === VERIFIER_STATES.appIssuer && (
|
|
60
62
|
<div className="flex items-center gap-0.5 font-poppins font-[500] text-[12px] leading-tight text-cyan-600">
|
|
61
63
|
<VerifiedBadge />
|
|
62
|
-
<span className="whitespace-nowrap">
|
|
64
|
+
<span className="whitespace-nowrap">{t('verification.appIssuer')}</span>
|
|
63
65
|
</div>
|
|
64
66
|
)}
|
|
65
67
|
{effectiveState === VERIFIER_STATES.untrustedVerifier && (
|
|
66
68
|
<div className="flex items-center gap-0.5 font-poppins font-[500] text-[12px] leading-tight text-red-mastercard">
|
|
67
69
|
<RedFlag />
|
|
68
|
-
<span className="whitespace-nowrap">
|
|
70
|
+
<span className="whitespace-nowrap">
|
|
71
|
+
{t('verification.untrustedIssuer')}
|
|
72
|
+
</span>
|
|
69
73
|
</div>
|
|
70
74
|
)}
|
|
71
75
|
</>
|
|
@@ -26,7 +26,7 @@ describe('Running Tests for CircleIcon', () => {
|
|
|
26
26
|
// });
|
|
27
27
|
|
|
28
28
|
// it('calls onClick', async () => {
|
|
29
|
-
// const handleOnClick =
|
|
29
|
+
// const handleOnClick = vi.fn();
|
|
30
30
|
// const user = userEvent.setup();
|
|
31
31
|
|
|
32
32
|
// const { container } = render(<CircleIcon onClick={handleOnClick} />);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { useT } from '../../i18n';
|
|
2
3
|
|
|
3
4
|
type InfoBoxProps = {
|
|
4
5
|
text: string;
|
|
@@ -7,6 +8,7 @@ type InfoBoxProps = {
|
|
|
7
8
|
};
|
|
8
9
|
|
|
9
10
|
const InfoBox: React.FC<InfoBoxProps> = ({ text, handleClose, backgroundColor = '#6366F1' }) => {
|
|
11
|
+
const t = useT();
|
|
10
12
|
const bgColorWithOpacity = `${backgroundColor}1F`; // 12% opacity
|
|
11
13
|
return (
|
|
12
14
|
<div
|
|
@@ -21,7 +23,7 @@ const InfoBox: React.FC<InfoBoxProps> = ({ text, handleClose, backgroundColor =
|
|
|
21
23
|
}}
|
|
22
24
|
className="text-indigo-500 font-[700] select-none"
|
|
23
25
|
>
|
|
24
|
-
|
|
26
|
+
{t('credential.close')}
|
|
25
27
|
</button>
|
|
26
28
|
</div>
|
|
27
29
|
);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
+
import { useT } from '../../i18n';
|
|
2
3
|
|
|
3
4
|
type TruncateTextBoxProps = {
|
|
4
5
|
headerText?: string;
|
|
@@ -29,6 +30,7 @@ const TruncateTextBox: React.FC<TruncateTextBoxProps> = ({
|
|
|
29
30
|
containerClassName = '',
|
|
30
31
|
textClassName = '',
|
|
31
32
|
}) => {
|
|
33
|
+
const t = useT();
|
|
32
34
|
const needsTruncate = text?.length > truncateThreshold;
|
|
33
35
|
const [showFullText, setShowFullText] = useState(false);
|
|
34
36
|
const truncated = needsTruncate && !showFullText;
|
|
@@ -61,7 +63,7 @@ const TruncateTextBox: React.FC<TruncateTextBoxProps> = ({
|
|
|
61
63
|
setShowFullText(true);
|
|
62
64
|
}}
|
|
63
65
|
>
|
|
64
|
-
|
|
66
|
+
{t('credential.more')}
|
|
65
67
|
</button>
|
|
66
68
|
</>
|
|
67
69
|
)}
|
|
@@ -75,7 +77,7 @@ const TruncateTextBox: React.FC<TruncateTextBoxProps> = ({
|
|
|
75
77
|
setShowFullText(false);
|
|
76
78
|
}}
|
|
77
79
|
>
|
|
78
|
-
|
|
80
|
+
{t('credential.close')}
|
|
79
81
|
</button>
|
|
80
82
|
</>
|
|
81
83
|
)}
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
VideoMetadata,
|
|
17
17
|
} from '../../types';
|
|
18
18
|
import LeftArrow from '../svgs/LeftArrow';
|
|
19
|
+
import { useT } from '../../i18n';
|
|
19
20
|
|
|
20
21
|
type FlippedComponentProps = React.PropsWithChildren<{
|
|
21
22
|
flipId?: string;
|
|
@@ -69,6 +70,7 @@ const VC2BackFace: React.FC<VC2BackFaceProps> = ({
|
|
|
69
70
|
enableLightbox,
|
|
70
71
|
customLinkedCredentialsComponent,
|
|
71
72
|
}) => {
|
|
73
|
+
const t = useT();
|
|
72
74
|
const expiration = credential.expirationDate
|
|
73
75
|
? format(new Date(credential.expirationDate), 'MMM dd, yyyy')
|
|
74
76
|
: undefined;
|
|
@@ -107,7 +109,7 @@ const VC2BackFace: React.FC<VC2BackFaceProps> = ({
|
|
|
107
109
|
|
|
108
110
|
{customDescription && (
|
|
109
111
|
<TruncateTextBox
|
|
110
|
-
headerText=
|
|
112
|
+
headerText={t('credential.about')}
|
|
111
113
|
text={description}
|
|
112
114
|
className="description-box"
|
|
113
115
|
>
|
|
@@ -116,7 +118,7 @@ const VC2BackFace: React.FC<VC2BackFaceProps> = ({
|
|
|
116
118
|
)}
|
|
117
119
|
{!customDescription && (description || expiration) && (
|
|
118
120
|
<TruncateTextBox
|
|
119
|
-
headerText=
|
|
121
|
+
headerText={t('credential.about')}
|
|
120
122
|
text={description}
|
|
121
123
|
className="description-box"
|
|
122
124
|
>
|
|
@@ -130,7 +132,7 @@ const VC2BackFace: React.FC<VC2BackFaceProps> = ({
|
|
|
130
132
|
|
|
131
133
|
{customCriteria && (
|
|
132
134
|
<TruncateTextBox
|
|
133
|
-
headerText=
|
|
135
|
+
headerText={t('credential.criteria')}
|
|
134
136
|
text={description}
|
|
135
137
|
className="description-box"
|
|
136
138
|
>
|
|
@@ -139,7 +141,7 @@ const VC2BackFace: React.FC<VC2BackFaceProps> = ({
|
|
|
139
141
|
)}
|
|
140
142
|
{!customCriteria && criteria && (
|
|
141
143
|
<TruncateTextBox
|
|
142
|
-
headerText=
|
|
144
|
+
headerText={t('credential.criteria')}
|
|
143
145
|
text={criteria}
|
|
144
146
|
className="criteria-box"
|
|
145
147
|
/>
|
|
@@ -13,6 +13,7 @@ import VerifierStateBadgeAndText, {
|
|
|
13
13
|
} from '../CertificateDisplayCard/VerifierStateBadgeAndText';
|
|
14
14
|
import { BoostAchievementCredential } from '../../types';
|
|
15
15
|
import { KnownDIDRegistryType } from '../../types';
|
|
16
|
+
import { useT } from '../../i18n';
|
|
16
17
|
|
|
17
18
|
type FlippedComponentProps = React.PropsWithChildren<{
|
|
18
19
|
flipId?: string;
|
|
@@ -82,6 +83,7 @@ const VC2FrontFaceInfo: React.FC<VC2FrontFaceInfoProps> = ({
|
|
|
82
83
|
unknownVerifierTitle,
|
|
83
84
|
onVerifierClick,
|
|
84
85
|
}) => {
|
|
86
|
+
const t = useT();
|
|
85
87
|
const issuerImage = getImageFromProfile(issuer ?? '');
|
|
86
88
|
const issueeImage = getImageFromProfile(issuee ?? '');
|
|
87
89
|
|
|
@@ -241,7 +243,7 @@ const VC2FrontFaceInfo: React.FC<VC2FrontFaceInfoProps> = ({
|
|
|
241
243
|
{!issuerDisplay.isMissing && (
|
|
242
244
|
<span className="issued-by max-w-full break-words text-center line-clamp-2 text-[14px]">
|
|
243
245
|
<span className="font-medium text-grayscale-900">
|
|
244
|
-
|
|
246
|
+
{t('credential.by')}
|
|
245
247
|
</span>{' '}
|
|
246
248
|
{issuerDisplay.isDidValue ? (
|
|
247
249
|
<span className="font-[600] font-poppins break-words">
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
import { CertificateDisplayCard } from '../CertificateDisplayCard';
|
|
30
30
|
import { MeritBadgeDisplayCard } from '../MeritBadgeDisplayCard';
|
|
31
31
|
import { KnownDIDRegistryType } from '../../types';
|
|
32
|
+
import { useT } from '../../i18n';
|
|
32
33
|
|
|
33
34
|
type FlippedComponentProps = React.PropsWithChildren<{
|
|
34
35
|
flipId?: string;
|
|
@@ -169,6 +170,7 @@ export const VCDisplayCard2: React.FC<VCDisplayCard2Props> = ({
|
|
|
169
170
|
hideFrontFaceDetails,
|
|
170
171
|
onVerifierClick,
|
|
171
172
|
}) => {
|
|
173
|
+
const t = useT();
|
|
172
174
|
const {
|
|
173
175
|
title = '',
|
|
174
176
|
createdAt,
|
|
@@ -537,12 +539,18 @@ export const VCDisplayCard2: React.FC<VCDisplayCard2Props> = ({
|
|
|
537
539
|
/>
|
|
538
540
|
)}
|
|
539
541
|
<div className="vc-footer-text font-montserrat flex flex-col items-center justify-center text-[12px] font-[700] leading-[15px] select-none">
|
|
540
|
-
<span className="text-[#4F4F4F]">
|
|
542
|
+
<span className="text-[#4F4F4F]">
|
|
543
|
+
{t('credential.verified')}
|
|
544
|
+
</span>
|
|
541
545
|
<span
|
|
542
546
|
className="vc-footer-status uppercase"
|
|
543
547
|
style={{ color: statusColor }}
|
|
544
548
|
>
|
|
545
|
-
{
|
|
549
|
+
{t(
|
|
550
|
+
`verification.status.${String(
|
|
551
|
+
worstVerificationStatus
|
|
552
|
+
).toLowerCase()}`
|
|
553
|
+
)}
|
|
546
554
|
</span>
|
|
547
555
|
</div>
|
|
548
556
|
<div
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { fireEvent, render, screen, within } from '@testing-library/react';
|
|
5
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { VerificationStatusEnum } from '@learncard/types';
|
|
8
|
+
|
|
9
|
+
import { I18nProvider } from '../../../i18n';
|
|
10
|
+
import VerifierStateBadgeAndText, {
|
|
11
|
+
VERIFIER_STATES,
|
|
12
|
+
} from '../../CertificateDisplayCard/VerifierStateBadgeAndText';
|
|
13
|
+
import VC2BackFace from '../VC2BackFace';
|
|
14
|
+
import VCDisplayCard2 from '../VCDisplayCard2';
|
|
15
|
+
|
|
16
|
+
vi.mock('react-flip-toolkit', () => ({
|
|
17
|
+
Flipper: ({ children }: React.PropsWithChildren) => <>{children}</>,
|
|
18
|
+
Flipped: ({ children }: React.PropsWithChildren) => <>{children}</>,
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
const translations: Record<string, string> = {
|
|
22
|
+
'credential.about': 'Acerca de',
|
|
23
|
+
'credential.criteria': 'Criterios',
|
|
24
|
+
'credential.alignments': 'Alineaciones',
|
|
25
|
+
'credential.alignmentInfo': 'Las alineaciones vinculan este logro con marcos establecidos.',
|
|
26
|
+
'credential.verifiedSource': 'Fuente verificada',
|
|
27
|
+
'credential.verifiedLabel': 'Verificada',
|
|
28
|
+
'credential.openAlignmentSource': 'Abrir la fuente de la alineación',
|
|
29
|
+
'credential.occupationsPrograms': 'Ocupaciones y programas',
|
|
30
|
+
'credential.more': 'Más',
|
|
31
|
+
'credential.close': 'Cerrar',
|
|
32
|
+
'credential.by': 'Por',
|
|
33
|
+
'credential.verified': 'Credencial verificada',
|
|
34
|
+
'verification.selfIssued': 'Autoemitido',
|
|
35
|
+
'verification.status.success': 'Éxito',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const renderLocalized = (node: React.ReactNode) =>
|
|
39
|
+
render(
|
|
40
|
+
<I18nProvider resolve={key => translations[key]} locale="es">
|
|
41
|
+
{node}
|
|
42
|
+
</I18nProvider>
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const credential = {
|
|
46
|
+
issuer: 'did:example:issuer',
|
|
47
|
+
issuanceDate: '2026-08-14T00:00:00.000Z',
|
|
48
|
+
credentialSubject: {
|
|
49
|
+
id: 'did:example:subject',
|
|
50
|
+
achievement: {
|
|
51
|
+
name: 'Critical Thinking',
|
|
52
|
+
description:
|
|
53
|
+
'A long description that deliberately exceeds the truncation threshold so the translated expansion control is rendered for this regression test.',
|
|
54
|
+
criteria: { narrative: 'Complete the critical-thinking requirements.' },
|
|
55
|
+
alignment: [
|
|
56
|
+
{
|
|
57
|
+
targetUrl: 'https://example.com/framework/critical-thinking',
|
|
58
|
+
targetName: 'Critical Thinking',
|
|
59
|
+
targetFramework: 'Example Framework',
|
|
60
|
+
targetType: 'ceterms:Credential',
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
display: { displayType: 'badge' },
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
describe('VCDisplayCard2 localized labels', () => {
|
|
69
|
+
it('localizes back-face headings, alignment copy, and truncation controls', () => {
|
|
70
|
+
const { container } = renderLocalized(
|
|
71
|
+
<VC2BackFace
|
|
72
|
+
credential={credential as never}
|
|
73
|
+
verificationItems={[]}
|
|
74
|
+
showFrontFace={vi.fn()}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
expect(screen.getByRole('heading', { name: 'Acerca de' })).toBeTruthy();
|
|
79
|
+
expect(screen.getByRole('heading', { name: 'Criterios' })).toBeTruthy();
|
|
80
|
+
|
|
81
|
+
const alignmentHeading = screen.getByRole('heading', { name: 'Alineaciones' });
|
|
82
|
+
expect(alignmentHeading.className).toContain('text-[20px]');
|
|
83
|
+
expect(alignmentHeading.className).not.toContain('text-[22px]');
|
|
84
|
+
|
|
85
|
+
fireEvent.click(screen.getByRole('button', { name: 'Más' }));
|
|
86
|
+
expect(screen.getByRole('button', { name: 'Cerrar' })).toBeTruthy();
|
|
87
|
+
|
|
88
|
+
const alignmentBox = alignmentHeading.closest('div.bg-white');
|
|
89
|
+
expect(alignmentBox).not.toBeNull();
|
|
90
|
+
fireEvent.click(within(alignmentBox as HTMLElement).getByRole('button'));
|
|
91
|
+
|
|
92
|
+
expect(
|
|
93
|
+
screen.getByText('Las alineaciones vinculan este logro con marcos establecidos.')
|
|
94
|
+
).toBeTruthy();
|
|
95
|
+
expect(screen.getByText('Fuente verificada')).toBeTruthy();
|
|
96
|
+
expect(screen.getByText('Verificada')).toBeTruthy();
|
|
97
|
+
expect(screen.getByRole('link', { name: 'Abrir la fuente de la alineación' })).toBeTruthy();
|
|
98
|
+
expect(container.textContent).not.toContain('Alignments');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('localizes the verifier badge used on the credential front face', () => {
|
|
102
|
+
renderLocalized(<VerifierStateBadgeAndText verifierState={VERIFIER_STATES.selfVerified} />);
|
|
103
|
+
|
|
104
|
+
expect(screen.getByText('Autoemitido')).toBeTruthy();
|
|
105
|
+
expect(screen.queryByText('Self Issued')).toBeNull();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('localizes the verified-credential footer and verification status', () => {
|
|
109
|
+
renderLocalized(
|
|
110
|
+
<VCDisplayCard2
|
|
111
|
+
credential={credential as never}
|
|
112
|
+
verificationItems={[{ status: VerificationStatusEnum.Success } as never]}
|
|
113
|
+
hideNavButtons
|
|
114
|
+
/>
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
expect(screen.getByText('Credencial verificada')).toBeTruthy();
|
|
118
|
+
expect(screen.getByText('Éxito')).toBeTruthy();
|
|
119
|
+
expect(screen.getByText('Por')).toBeTruthy();
|
|
120
|
+
expect(screen.queryByText('Verified Credential')).toBeNull();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
@@ -88,7 +88,7 @@ describe('Credential Helpers', () => {
|
|
|
88
88
|
...JffCredential,
|
|
89
89
|
issuanceDate: 'invalid-date-string',
|
|
90
90
|
};
|
|
91
|
-
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {
|
|
91
|
+
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
92
92
|
const result = getInfoFromCredential(credentialWithInvalidDate as any);
|
|
93
93
|
expect(result.createdAt).toEqual('');
|
|
94
94
|
expect(consoleSpy).toHaveBeenCalledWith(
|
package/src/i18n/index.tsx
CHANGED
|
@@ -32,7 +32,19 @@ export const EN_DEFAULTS: Record<string, string> = {
|
|
|
32
32
|
'verification.unknownIssuer': 'Unknown Issuer',
|
|
33
33
|
'verification.appIssuer': 'Trusted App',
|
|
34
34
|
'verification.untrustedIssuer': 'Untrusted Issuer',
|
|
35
|
+
'credential.about': 'About',
|
|
36
|
+
'credential.criteria': 'Criteria',
|
|
37
|
+
'credential.alignments': 'Alignments',
|
|
38
|
+
'credential.alignmentInfo':
|
|
39
|
+
'Alignments in your Open Badge credential link your achievement to established frameworks, standards, or competencies. Each alignment shows how your boost directly relates to skills, knowledge areas, and professional standards that are recognized in your field.',
|
|
40
|
+
'credential.verifiedSource': 'Verified source',
|
|
41
|
+
'credential.occupationsPrograms': 'Occupations & programs',
|
|
42
|
+
'credential.verifiedLabel': 'Verified',
|
|
43
|
+
'credential.openAlignmentSource': 'Open alignment source',
|
|
44
|
+
'credential.more': 'More',
|
|
45
|
+
'credential.close': 'Close',
|
|
35
46
|
'credential.by': 'By',
|
|
47
|
+
'credential.verified': 'Verified Credential',
|
|
36
48
|
'verification.title': 'Credential Verifications',
|
|
37
49
|
'verification.infoText':
|
|
38
50
|
'Credential verifications check the cryptographic proof of digital credentials to ensure their authenticity and accuracy.',
|