From 96c1e49e23c9facc17a5d021b2ac349f36ba569b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Corentin=20S=C3=A9chet?= Date: Wed, 28 Feb 2024 20:04:30 +0100 Subject: [PATCH] qrcode: add retry button to refetch metadata on error (#86091) --- .../apps/qrcode/static/qrcode/css/style.scss | 27 +++++++++++++--- .../qrcode/static/qrcode/js/qrcode-reader.js | 28 ++++++++++++----- tests/js/qrcode.test.js | 31 +++++++++++++++++++ 3 files changed, 74 insertions(+), 12 deletions(-) diff --git a/passerelle/apps/qrcode/static/qrcode/css/style.scss b/passerelle/apps/qrcode/static/qrcode/css/style.scss index 59a3714e..65140085 100644 --- a/passerelle/apps/qrcode/static/qrcode/css/style.scss +++ b/passerelle/apps/qrcode/static/qrcode/css/style.scss @@ -12,6 +12,12 @@ qrcode-reader { display: grid; } +%button { + margin: 5px 10px 10px 10px; + padding: 5px; + font-size: 1.2rem; +} + .qrcode-reader { &--video-wrapper { @@ -115,9 +121,7 @@ qrcode-reader { } &--close-popup-button { - margin: 5px 10px 10px 10px; - padding: 5px; - font-size: 1.2rem; + @extend %button; } } @@ -231,10 +235,21 @@ qrcode-reader-validity { qrcode-reader-data { .qrcode-reader-section--content { display: grid; - grid-template-columns: auto 1fr; } .qrcode-reader-data { + &--retry-button { + @extend %button; + font-size: 1rem; + display: none; + + } + + &--items { + display: grid; + grid-template-columns: auto 1fr; + } + &--item-label { font-weight: bold; justify-self: end; @@ -245,4 +260,8 @@ qrcode-reader-data { flex-wrap: wrap; } } + + .qrcode-reader-section.error .qrcode-reader-data--retry-button { + display: block; + } } diff --git a/passerelle/apps/qrcode/static/qrcode/js/qrcode-reader.js b/passerelle/apps/qrcode/static/qrcode/js/qrcode-reader.js index 215a95f2..97ce6e79 100644 --- a/passerelle/apps/qrcode/static/qrcode/js/qrcode-reader.js +++ b/passerelle/apps/qrcode/static/qrcode/js/qrcode-reader.js @@ -405,6 +405,11 @@ class QRCodeReaderValidity extends QRCodeReaderSection { window.customElements.define('qrcode-reader-validity', QRCodeReaderValidity) +const dataTemplate = template(` + +
+`) + const dataItemTemplate = template(` {label} :  {value} @@ -418,24 +423,32 @@ class QRCodeReaderData extends QRCodeReaderSection { async refresh(data, metadataUrl, certificateUUID) { this.reset() - this.contentElement.innerHTML = '' + const contentElement = dataTemplate.content.cloneNode(true) + const itemsElement = contentElement.querySelector('.qrcode-reader-data--items') + const retryButton = contentElement.querySelector('.qrcode-reader-data--retry-button') + + retryButton.addEventListener('click', () => { + this.refresh(data, metadataUrl, certificateUUID) + }) + + this.setContent(contentElement) for (const [key, value] of Object.entries(data)) { - this.#addItem(key, value) + this.#addItem(itemsElement, key, value) } await this.load(async () => { - await this.#showMetadata(metadataUrl, certificateUUID) + await this.#showMetadata(itemsElement, metadataUrl, certificateUUID) }) } - #addItem(label, value) { + #addItem(itemsElement, label, value) { const dataItem = dataItemTemplate.cloneNode(true) dataItem.innerHTML = dataItem.innerHTML.replace('{label}', label).replace('{value}', value) - this.contentElement.append(dataItem.content) + itemsElement.append(dataItem.content) } - async #showMetadata(metadataUrl, certificateUUID) { + async #showMetadata(itemsElement, metadataUrl, certificateUUID) { if(metadataUrl === null) { return } @@ -446,7 +459,7 @@ class QRCodeReaderData extends QRCodeReaderSection { } for (const [key, value] of Object.entries(metadata)) { - this.#addItem(key, value) + this.#addItem(itemsElement, key, value) } } @@ -474,7 +487,6 @@ class QRCodeReaderData extends QRCodeReaderSection { return metadata } - } window.customElements.define('qrcode-reader-data', QRCodeReaderData) diff --git a/tests/js/qrcode.test.js b/tests/js/qrcode.test.js index 0f3cbb8a..a06dbb74 100644 --- a/tests/js/qrcode.test.js +++ b/tests/js/qrcode.test.js @@ -382,6 +382,37 @@ qrcodeReaderMetadataTest("qrcode reader doesn't refetch metadata for the same ce expect(reader.querySelectorAll('.qrcode-reader-data--item-value').length).toStrictEqual(3) }) +qrcodeReaderMetadataTest('retry button refetches metadata', async ({mock, loadMetadata}) => { + const { reader, scan } = mock + + await loadMetadata(okCodeData, async (url) => { + return { + ok: true, + json: () => new Promise((resolve) => { + resolve({'err': 1}) + }) + } + }) + + const section = reader.querySelector('qrcode-reader-data .qrcode-reader-section') + expect(section.classList.contains('error')).toBe(true) + + const retryButton = reader.querySelector('.qrcode-reader-data--retry-button') + expect(retryButton).not.toBe(null) + + fetch.mockImplementationOnce(async (url) => { + return { + ok: true, + json: async () => ({'err': 0, 'data': {'Classe': 'Oui', 'Ravioles': 'Non'}}) + } + }) + + retryButton.dispatchEvent(new Event('click')) + await new Promise(resolve => setTimeout(resolve)) + + expect(section.classList.contains('error')).toBe(false) +}) + const qrcodeReaderTallyTest = qrcodeReaderTest.extend({ loadTally: async ({ task, mock }, use) => { const loadTally = async (qrCodeData, mockFetch) => {