Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 103 additions & 26 deletions packages/embed/src/ekyc.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ <h1>
crossorigin="anonymous"
></script>

<main>
<main hidden>
<section id="loading-screen" class="flow center">
<div class="nav justify-right">
<button data-type="icon" type="button" class="close-iframe">
Expand Down Expand Up @@ -98,12 +98,18 @@ <h1>
<br />
<p class="spinner"></p>

<h1 style="--flow-space: 4rem">Setting up</h1>
<h1 style="--flow-space: 4rem" data-i18n="pages.loading.title">
Setting up
</h1>

<p>
Just a few more seconds
<span data-i18n="pages.loading.subtitle"
>Just a few more seconds</span
>
<br />
We are setting up your verification flow
<span data-i18n="pages.loading.description"
>We are setting up your verification flow</span
>
</p>

<p class="center credits" hidden>
Expand Down Expand Up @@ -197,27 +203,44 @@ <h1 style="--flow-space: 4rem">Setting up</h1>
>
</button>
</div>
<h1 class="center font-size-500 max-width:100ch">Select ID Type</h1>
<h1
class="center font-size-500 max-width:100ch"
data-i18n="pages.idSelection.title"
>
Select ID Type
</h1>

<form name="hosted-web-config" class="flow flow-space:800">
<div class="split-pair flow-space:400">
<div class="flow input-group">
<label for="country"> Select Country </label>
<label for="country" data-i18n="pages.idSelection.selectCountry">
Select Country
</label>
<select disabled required id="country" name="country">
<option value="">--Please Select--</option>
<option value="" data-i18n="pages.idSelection.placeholder">
--Please Select--
</option>
</select>
</div>

<div class="flow input-group">
<label for="id_type"> Select ID Type </label>
<label for="id_type" data-i18n="pages.idSelection.selectIdType">
Select ID Type
</label>
<select required id="id_type" name="id_type" disabled>
<option value="" disabled>Select Country First</option>
<option
value=""
disabled
data-i18n="pages.idSelection.selectCountryFirst"
>
Select Country First
</option>
</select>
</div>
</div>

<button data-variant="solid" type="submit" id="submitConfig">
Continue
<span data-i18n="common.continue">Continue</span>
<svg
aria-hidden="true"
width="25"
Expand Down Expand Up @@ -275,7 +298,7 @@ <h1 class="center font-size-500 max-width:100ch">Select ID Type</h1>
/>
</svg>
</button>
<div class="back-button-text">Back</div>
<div class="back-button-text" data-i18n="common.back">Back</div>
</div>
<button data-type="icon" type="button" class="close-iframe">
<svg
Expand All @@ -299,7 +322,9 @@ <h1 class="center font-size-500 max-width:100ch">Select ID Type</h1>
>
</button>
</div>
<h1 class="center">Enter ID Information</h1>
<h1 class="center" data-i18n="pages.idInfo.title">
Enter ID Information
</h1>

<p class="demo-tip" data-variant="yellow" hidden>
<svg
Expand Down Expand Up @@ -335,20 +360,34 @@ <h1 class="center">Enter ID Information</h1>

<form name="user-details" class="flow">
<fieldset hidden id="bank-code" data-variant="start">
<label class="required" for="bank_code"> Bank </label>
<label
class="required"
for="bank_code"
data-i18n="pages.idInfo.bank"
>
Bank
</label>

<select
aria-required="true"
name="bank_code"
id="bank_code"
required
>
<option key="" value="">--Select Bank--</option>
<option key="" value="" data-i18n="pages.idInfo.selectBank">
--Select Bank--
</option>
</select>
</fieldset>

<div hidden id="id-number" class="input-group flow">
<label class="required" for="id_number"> ID Number </label>
<label
class="required"
for="id_number"
data-i18n="pages.idInfo.idNumber"
>
ID Number
</label>

<input
aria-required="true"
Expand All @@ -360,7 +399,13 @@ <h1 class="center">Enter ID Information</h1>

<fieldset hidden id="names" class="split-pair" data-variant="start">
<div class="input-group flow">
<label class="required" for="first_name"> First Name </label>
<label
class="required"
for="first_name"
data-i18n="pages.idInfo.firstName"
>
First Name
</label>

<input
aria-required="true"
Expand All @@ -373,7 +418,13 @@ <h1 class="center">Enter ID Information</h1>
</div>

<div class="input-group flow">
<label class="required" for="last_name"> Last Name </label>
<label
class="required"
for="last_name"
data-i18n="pages.idInfo.lastName"
>
Last Name
</label>

<input
aria-required="true"
Expand All @@ -386,25 +437,39 @@ <h1 class="center">Enter ID Information</h1>
</div>
</fieldset>
<fieldset hidden id="citizenships" data-variant="start">
<label class="required" for="citizenship"> Citizenship </label>
<label
class="required"
for="citizenship"
data-i18n="pages.idInfo.citizenship"
>
Citizenship
</label>

<select
aria-required="true"
name="citizenship"
id="citizenship"
required
>
<option key="" value="">Select Citizenship Type</option>
<option
key=""
value=""
data-i18n="pages.idInfo.selectCitizenship"
>
Select Citizenship Type
</option>
<option value="Kenyan">Kenyan</option>
<option value="Alien">Alien</option>
</select>
</fieldset>
<fieldset hidden id="dob" class="flow">
<legend>Date of Birth</legend>
<legend data-i18n="pages.idInfo.dob">Date of Birth</legend>

<div class="dob">
<div class="input-group flow">
<label class="required" for="day"> Day </label>
<label class="required" for="day" data-i18n="pages.idInfo.day">
Day
</label>

<input
aria-required="true"
Expand All @@ -417,7 +482,13 @@ <h1 class="center">Enter ID Information</h1>
</div>

<div class="input-group flow">
<label class="required" for="last_name"> Month </label>
<label
class="required"
for="month"
data-i18n="pages.idInfo.month"
>
Month
</label>

<input
aria-required="true"
Expand All @@ -430,7 +501,13 @@ <h1 class="center">Enter ID Information</h1>
</div>

<div class="input-group flow">
<label class="required" for="year"> Year </label>
<label
class="required"
for="year"
data-i18n="pages.idInfo.year"
>
Year
</label>

<input
aria-required="true"
Expand All @@ -445,7 +522,7 @@ <h1 class="center">Enter ID Information</h1>
</fieldset>

<button data-variant="solid" type="button" id="submitForm">
Continue
<span data-i18n="common.continue">Continue</span>
<svg
aria-hidden="true"
width="25"
Expand Down Expand Up @@ -504,9 +581,9 @@ <h1 class="center">Enter ID Information</h1>
/>
</svg>

<h1>Submission Complete</h1>
<h1 data-i18n="pages.complete.title">Submission Complete</h1>

<p id="thank-you-message">
<p id="thank-you-message" data-i18n="pages.complete.description">
That's all you need to verify your identity
</p>

Expand Down
62 changes: 55 additions & 7 deletions packages/embed/src/js/ekyc.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import validate from 'validate.js';
import '@smileid/web-components/combobox';
import '@smileid/web-components/end-user-consent';
import { setCurrentLocale } from '@smileid/web-components/localisation';
import {
setCurrentLocale,
translate,
translateHtml,
getDirection,
} from '@smileid/web-components/localisation';
import { version as sdkVersion } from '../../package.json';
import { getHeaders } from './request';

Expand Down Expand Up @@ -110,6 +115,19 @@ import { getHeaders } from './request';
}
}

function applyPageTranslations() {
document.querySelectorAll('[data-i18n]').forEach((el) => {
const key = el.getAttribute('data-i18n');
if (key) {
try {
el.textContent = translate(key);
} catch (e) {
console.error(`Translation failed for key: ${key}`, e);
}
}
});
}
Comment on lines +118 to +129
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Using textContent will remove any child HTML elements (like icons or nested spans). This could break UI components that contain both text and HTML. Consider checking if the element has child nodes before replacing content, or use a data attribute to mark text-only elements. [possible issue, importance: 9]

Suggested change
function applyPageTranslations() {
document.querySelectorAll('[data-i18n]').forEach((el) => {
const key = el.getAttribute('data-i18n');
if (key) {
try {
el.textContent = translate(key);
} catch (e) {
console.error(`Translation failed for key: ${key}`, e);
}
}
});
}
function applyPageTranslations() {
document.querySelectorAll('[data-i18n]').forEach((el) => {
const key = el.getAttribute('data-i18n');
if (key) {
try {
if (el.children.length === 0) {
el.textContent = translate(key);
} else {
const textNodes = Array.from(el.childNodes).filter(node => node.nodeType === Node.TEXT_NODE);
if (textNodes.length === 1) {
textNodes[0].textContent = translate(key);
}
}
} catch (e) {
console.error(`Translation failed for key: ${key}`, e);
}
}
});
}


window.addEventListener(
'message',
async (event) => {
Expand All @@ -119,7 +137,11 @@ import { getHeaders } from './request';
event.data.includes('SmileIdentity::Configuration')
) {
config = JSON.parse(event.data);
setCurrentLocale(config.translation?.language || 'en');
await setCurrentLocale(config.translation?.language || 'en');
document.documentElement.dir = getDirection();
applyPageTranslations();
document.querySelector('main').hidden = false;
Comment on lines +140 to +143
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: If applyPageTranslations() fails or throws an error, the main element will remain hidden, leaving users with a blank screen. Wrap the translation logic in a try-catch block to ensure the UI is always shown, even if translations fail. [general, importance: 7]

Suggested change
await setCurrentLocale(config.translation?.language || 'en');
document.documentElement.dir = getDirection();
applyPageTranslations();
document.querySelector('main').hidden = false;
await setCurrentLocale(config.translation?.language || 'en');
document.documentElement.dir = getDirection();
try {
applyPageTranslations();
} catch (e) {
console.error('Failed to apply page translations', e);
}
document.querySelector('main').hidden = false;


LoadingScreen.querySelector('.credits').hidden =
config.hide_attribution;
const attributions = document.querySelectorAll('.credits');
Expand Down Expand Up @@ -260,7 +282,9 @@ import { getHeaders } from './request';
selectIDType.innerHTML = '';
const initialOption = document.createElement('option');
initialOption.setAttribute('value', '');
initialOption.textContent = '--Please Select--';
initialOption.textContent = translate(
'pages.idSelection.placeholder',
);
selectIDType.appendChild(initialOption);

// ACTION: Load ID Types as <option>s
Expand Down Expand Up @@ -519,10 +543,10 @@ import { getHeaders } from './request';
autocomplete.setAttribute('id', 'bank_code');
autocomplete.innerHTML = `
<smileid-combobox-trigger
label="Search Bank">
label="${translate('pages.idInfo.searchBank')}">
</smileid-combobox-trigger>

<smileid-combobox-listbox empty-label="No bank found">
<smileid-combobox-listbox empty-label="${translate('pages.idInfo.noBankFound')}">
${bankCodes
.map(
(bank) =>
Expand Down Expand Up @@ -647,6 +671,24 @@ import { getHeaders } from './request';
validationMessages.forEach((el) => el.remove());
}

// Map field names to their translation keys
const fieldTranslationKeys = {
id_number: 'pages.idInfo.idNumber',
first_name: 'pages.idInfo.firstName',
last_name: 'pages.idInfo.lastName',
day: 'pages.idInfo.day',
month: 'pages.idInfo.month',
year: 'pages.idInfo.year',
citizenship: 'pages.idInfo.citizenship',
bank_code: 'pages.idInfo.bank',
};

function getTranslatedValidationMessage(field) {
const fieldKey = fieldTranslationKeys[field];
const fieldLabel = fieldKey ? translate(fieldKey) : field;
return translateHtml('pages.validation.isRequired', { field: fieldLabel });
}

function validateInputs(payload) {
const validationConstraints = {};

Expand Down Expand Up @@ -763,7 +805,7 @@ import { getHeaders } from './request';
const errorDiv = document.createElement('div');
errorDiv.setAttribute('id', `${field}-hint`);
errorDiv.setAttribute('class', 'validation-message');
errorDiv.textContent = errors[field][0];
errorDiv.textContent = getTranslatedValidationMessage(field);

input.insertAdjacentElement('afterend', errorDiv);
});
Expand Down Expand Up @@ -853,7 +895,13 @@ import { getHeaders } from './request';
productConstraints[id_info.country].id_types[id_info.id_type].label;

const thankYouMessage = CompleteScreen.querySelector('#thank-you-message');
thankYouMessage.textContent = `We will process your ${countryName} - ${idTypeName} information to verify your identity`;
thankYouMessage.textContent = translateHtml(
'pages.complete.processingInfo',
{
country: countryName,
idType: idTypeName,
},
);

setActiveScreen(CompleteScreen);
handleSuccess();
Expand Down
Loading
Loading