Skip to content

Commit a89226b

Browse files
committed
UI: work in progress to support upload of csv for EHIC for dev/test
1 parent b5a811d commit a89226b

File tree

1 file changed

+109
-59
lines changed

1 file changed

+109
-59
lines changed

internal/ui/static/ui.js

+109-59
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ function displaySecureMenyItems() {
4747
hideAElement("show-login-form-btn");
4848
}
4949

50+
/**
51+
* @returns {string} containing UUID v4
52+
*/
5053
const generateUUID = () => {
51-
//UUID v4
5254
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
5355
var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
5456
return v.toString(16);
@@ -628,6 +630,7 @@ function buildDocumentsTableWithoutContent() {
628630
const headerRow = document.createElement('tr');
629631

630632
const headers = [
633+
{title: 'Action', abbr: null},
631634
{title: 'Document ID', abbr: null},
632635
{title: 'Collect ID', abbr: null},
633636
{title: 'Document type', abbr: null},
@@ -636,7 +639,7 @@ function buildDocumentsTableWithoutContent() {
636639
{title: 'Family name', abbr: null},
637640
{title: 'Given name', abbr: null},
638641
{title: 'Birthdate', abbr: null},
639-
{title: 'Action', abbr: null}
642+
{title: 'QR credential offer url', abbr: null}
640643
];
641644

642645
headers.forEach(header => {
@@ -938,6 +941,46 @@ function displayDeleteDocumentInModal(rowData) {
938941
function buildDocumentTableRow(doc) {
939942
const row = document.createElement('tr');
940943

944+
//------select start-------------------
945+
const tdActions = document.createElement('td');
946+
const divSelect = document.createElement('div');
947+
divSelect.className = 'select'; // is-small';
948+
949+
const select = document.createElement('select');
950+
select.id = generateUUID();
951+
952+
const optionDefault = document.createElement('option');
953+
optionDefault.value = '';
954+
optionDefault.textContent = 'select...';
955+
select.appendChild(optionDefault);
956+
957+
const optionViewDocument = document.createElement('option');
958+
optionViewDocument.value = 'VIEW_COMPLETE_DOCUMENT';
959+
optionViewDocument.textContent = 'View complete document';
960+
select.appendChild(optionViewDocument);
961+
962+
const optionViewQR = document.createElement('option');
963+
optionViewQR.value = 'VIEW_QR';
964+
optionViewQR.textContent = 'View QR';
965+
select.appendChild(optionViewQR);
966+
967+
const optionCreateCredential = document.createElement('option');
968+
optionCreateCredential.value = 'CREATE_CREDENTIAL';
969+
optionCreateCredential.textContent = 'Create credential';
970+
select.appendChild(optionCreateCredential);
971+
972+
select.appendChild(document.createElement('hr'));
973+
974+
const optionDeleteDocument = document.createElement('option');
975+
optionDeleteDocument.value = 'DELETE_DOCUMENT';
976+
optionDeleteDocument.textContent = 'Delete document';
977+
select.appendChild(optionDeleteDocument);
978+
979+
divSelect.appendChild(select);
980+
tdActions.appendChild(divSelect);
981+
row.appendChild(tdActions);
982+
//-------------------------
983+
941984
const tdDocumentId = document.createElement('td');
942985
const documentId = doc.meta?.document_id || "";
943986
tdDocumentId.textContent = documentId;
@@ -990,39 +1033,10 @@ function buildDocumentTableRow(doc) {
9901033
tdBirthDate.innerHTML = bdStringBuilder.join("<br>");
9911034
row.appendChild(tdBirthDate);
9921035

993-
const tdActions = document.createElement('td');
994-
const divSelect = document.createElement('div');
995-
divSelect.className = 'select'; // is-small';
996-
997-
const select = document.createElement('select');
998-
select.id = generateUUID();
999-
1000-
const optionDefault = document.createElement('option');
1001-
optionDefault.value = '';
1002-
optionDefault.textContent = 'select...';
1003-
select.appendChild(optionDefault);
1004-
1005-
const optionViewDocument = document.createElement('option');
1006-
optionViewDocument.value = 'VIEW_COMPLETE_DOCUMENT';
1007-
optionViewDocument.textContent = 'View complete document';
1008-
select.appendChild(optionViewDocument);
1009-
1010-
const optionViewQR = document.createElement('option');
1011-
optionViewQR.value = 'VIEW_QR';
1012-
optionViewQR.textContent = 'View QR';
1013-
select.appendChild(optionViewQR);
1014-
1015-
const optionCreateCredential = document.createElement('option');
1016-
optionCreateCredential.value = 'CREATE_CREDENTIAL';
1017-
optionCreateCredential.textContent = 'Create credential';
1018-
select.appendChild(optionCreateCredential);
1019-
1020-
select.appendChild(document.createElement('hr'));
1021-
1022-
const optionDeleteDocument = document.createElement('option');
1023-
optionDeleteDocument.value = 'DELETE_DOCUMENT';
1024-
optionDeleteDocument.textContent = 'Delete document';
1025-
select.appendChild(optionDeleteDocument);
1036+
const tdQRCredentialOfferUrl = document.createElement('td');
1037+
const credentialOfferUrl = doc.qr?.credential_offer || "";
1038+
tdQRCredentialOfferUrl.textContent = credentialOfferUrl;
1039+
row.appendChild(tdQRCredentialOfferUrl);
10261040

10271041
const rowData = {
10281042
documentId: documentId,
@@ -1054,31 +1068,62 @@ function buildDocumentTableRow(doc) {
10541068
this.value = '';
10551069
});
10561070

1057-
divSelect.appendChild(select);
1058-
tdActions.appendChild(divSelect);
1059-
row.appendChild(tdActions);
1060-
10611071
return row;
10621072
}
10631073

10641074
function displayDocumentsTable(data, divResultContainer) {
10651075
divResultContainer.appendChild(document.createElement("br"));
10661076
divResultContainer.appendChild(document.createElement("br"));
10671077

1068-
if (Array.isArray(data.documents) && data.documents.length === 0) {
1078+
if (data.documents == null || (Array.isArray(data.documents) && data.documents.length === 0)) {
10691079
displayInfoTag("No matching documents found", divResultContainer);
10701080
return;
10711081
} else if (data.has_more_results) {
10721082
displayWarningTag("There are more search results available. Narrow down your search criteria to view them all.", divResultContainer);
10731083
}
10741084

1085+
const exportToCsvButton = document.createElement("button");
1086+
exportToCsvButton.id = generateUUID();
1087+
exportToCsvButton.classList.add("button");
1088+
exportToCsvButton.textContent = "Export result to csv file";
1089+
exportToCsvButton.disabled = false;
1090+
divResultContainer.appendChild(exportToCsvButton);
1091+
10751092
const tableBasis = buildDocumentsTableWithoutContent();
1093+
exportToCsvButton.addEventListener('click', () => exportTableToCSV(tableBasis.table));
10761094
divResultContainer.appendChild(tableBasis.table);
10771095
data.documents.forEach(doc => {
10781096
tableBasis.tbody.appendChild(buildDocumentTableRow(doc));
10791097
});
10801098
}
10811099

1100+
function exportTableToCSV(table) {
1101+
const rows = table.querySelectorAll('tr');
1102+
let csvContent = "";
1103+
1104+
1105+
rows.forEach(row => {
1106+
const cells = row.querySelectorAll('th, td');
1107+
const rowContent = Array.from(cells)
1108+
.map(cell => `"${cell.innerText}"`) // Wrap cell values in quotes to handle commas
1109+
.join(","); // Join cell values with a comma
1110+
csvContent += rowContent + "\n";
1111+
});
1112+
1113+
1114+
const blob = new Blob([csvContent], {type: 'text/csv'});
1115+
const url = URL.createObjectURL(blob);
1116+
1117+
const a = document.createElement('a');
1118+
a.href = url;
1119+
a.download = 'search_result.csv';
1120+
document.body.appendChild(a);
1121+
a.click();
1122+
1123+
document.body.removeChild(a);
1124+
URL.revokeObjectURL(url);
1125+
}
1126+
10821127
const addSearchDocumentsFormArticleToContainer = () => {
10831128
const buildFormElements = () => {
10841129

@@ -1133,7 +1178,7 @@ const addSearchDocumentsFormArticleToContainer = () => {
11331178

11341179
limit: parseInt(limitInput.value, 10),
11351180

1136-
fields: ["meta.document_id", "meta.authentic_source", "meta.document_type", "meta.collect.id", "identities"],
1181+
fields: ["meta.document_id", "meta.authentic_source", "meta.document_type", "meta.collect.id", "identities", "qr.credential_offer"],
11371182
};
11381183

11391184
if (checkboxShowCompleteDocsAsRawJson.checked) {
@@ -1195,7 +1240,6 @@ const addSearchDocumentsFormArticleToContainer = () => {
11951240
document.getElementById(articleIdBasis.articleID).querySelector('input').focus();
11961241
};
11971242

1198-
11991243
const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
12001244
const buildFormElements = () => {
12011245
const fileDiv = document.createElement('div');
@@ -1208,7 +1252,6 @@ const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
12081252
input.className = 'file-input';
12091253
input.type = 'file';
12101254
input.name = 'resume';
1211-
//input.id = 'csvFile';
12121255
input.id = generateUUID();
12131256
input.accept = '.csv';
12141257

@@ -1230,7 +1273,6 @@ const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
12301273

12311274
const fileName = document.createElement('span');
12321275
fileName.className = 'file-name';
1233-
//fileName.id = 'fileName';
12341276
fileName.id = generateUUID();
12351277
fileName.textContent = 'No file selected';
12361278

@@ -1318,44 +1360,40 @@ const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
13181360
articleContainer.prepend(articleDiv);
13191361

13201362
function createUploadRequestFrom(row) {
1363+
const generatedDocumentId = generateUUID();
13211364
return {
1322-
//TODO remove default values (or maybe some needs to be hardcoded?)
13231365
meta: {
13241366
authentic_source: row.authentic_source,
13251367
document_version: row.document_version || "1.0.0",
1326-
document_type: row.document_type || "EHIC", //ta in via dropdown alt. analys av csv
1327-
document_id: row.document_id || generateUUID(),
1368+
document_type: row.document_type || "EHIC",
1369+
document_id: row.document_id || generatedDocumentId,
13281370
real_data: row.real_data === "true",
13291371
credential_valid_from: row.credential_valid_from || null,
13301372
credential_valid_to: row.credential_valid_to || null,
13311373
document_data_validation: row.document_data_validation || null,
1332-
"collect": {
1333-
id: generateUUID(),
1334-
valid_until: 909567558
1374+
collect: {
1375+
id: row.collect_id || generatedDocumentId,
1376+
valid_until: convertToUnixTimestampOrNull(row.ehic_expiry_date),
13351377
},
13361378
},
13371379
identities: [
13381380
{
1339-
authentic_source_person_id: row.pid_id || generateUUID(),
1381+
authentic_source_person_id: prefixWithAuthenticSourcePersonIdOrNull(row.pid_id),
13401382
schema: {
13411383
name: row.pid_issuing_country,
13421384
version: row.schema_version || "1.0.0",
13431385
},
13441386
family_name: row.family_name,
13451387
given_name: row.given_name,
1346-
birth_date: "1973-05-02", //TODO: row.birth_date -> hantera felaktigt format i csv YYYY/MM/DD
1347-
gender: row.gender || null,
1348-
nationality: row.nationality || null,
1349-
resident_address: row.resident_address || null,
1350-
resident_country: row.resident_country || null,
1388+
birth_date: row.birth_date,
13511389
},
13521390
],
13531391
document_display: null,
13541392
document_data: {
13551393
subject: {
13561394
forename: row.given_name,
13571395
family_name: row.family_name,
1358-
date_of_birth: "1973-05-02" //TODO: row.birth_date -> hantera felaktigt format i csv YYYY/MM/DD
1396+
date_of_birth: row.birth_date,
13591397
},
13601398
social_security_pin: row.social_security_pin,
13611399
period_entitlement: {
@@ -1366,7 +1404,7 @@ const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
13661404
competent_institution: {
13671405
institution_id: row.ehic_institution_id,
13681406
institution_name: row.ehic_institution_name,
1369-
institution_country: row.ehic_institution_country_code_
1407+
institution_country: row.ehic_institution_country_code,
13701408
}
13711409
},
13721410
document_data_version: row.document_data_version || "1.0.0",
@@ -1375,7 +1413,6 @@ const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
13751413

13761414
function displayCSV(data, table) {
13771415
const rows = data.split('\n');
1378-
//const table = document.getElementById('csvTable');
13791416
table.innerHTML = ''; // Clear previous content
13801417

13811418
rows.forEach((row, rowIndex) => {
@@ -1390,6 +1427,10 @@ const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
13901427
});
13911428
}
13921429

1430+
function prefixWithAuthenticSourcePersonIdOrNull(pid_id) {
1431+
return pid_id ? `authentic_source_person_id_${pid_id}` : null;
1432+
}
1433+
13931434
function csvToJson(csv) {
13941435
const lines = csv.split('\n');
13951436
const headers = lines[0].split(',').map((header) => header.trim());
@@ -1408,6 +1449,15 @@ const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
14081449
}
14091450
};
14101451

1452+
/**
1453+
* @param dateString YYYY-MM-DD
1454+
*/
1455+
function convertToUnixTimestampOrNull(dateString) {
1456+
if (dateString == null) return null;
1457+
const date = new Date(dateString);
1458+
return Math.floor(date.getTime() / 1000);
1459+
}
1460+
14111461
async function fetchData(url, options) {
14121462
const response = await fetch(url, options);
14131463
if (!response.ok) {

0 commit comments

Comments
 (0)