Skip to content

fix: Scan Physical ID above the search bar on Add Credentials - #415

Merged
smncd merged 3 commits into
release/sirosidfrom
fix/307-scan-tile-at-top
Oct 29, 2026
Merged

smncd merged 3 commits into
release/sirosidfrom
fix/307-scan-tile-at-top

Conversation

@jessevanmuijden

Copy link
Copy Markdown
Contributor

Closes #307.

1. Placement

QueryableList rendered its extraSection between the Recent grid and the All heading, so the Scan Physical ID tile sat below recently used credentials instead of at the top of the page.

It is the page's own entry point, not one of the queryable items, so it now renders above the search box, Recent and All:

Before After
search → Recent → tile → All tile → search → Recent → All

Hiding it while a search is active is unchanged — a search is about the issuer list, and the entry point would only be noise in the results.

2. In Recent

This one needed a mechanism, not a move. Every other Recent entry is derived from a stored credential matched against a configuration from /issuer/all:

const recentConfigs = recentList.map(recentItem =>
  filteredList.find(config => getElementPropValue(config, identifierField) === recentItem))

Scan Physical ID is a local route (add/digital-id), not an issuer's credential configuration, so it has no identifier to match and could never have appeared there.

QueryableList gains a recentExtra slot, rendered first in the Recent grid, which AddCredentials fills once the flow has been used. Starting the flow is what makes it recent — the only signal available without tying the entry to one particular issued credential.

It therefore appears twice once used: pinned at the top (always available) and under Recent (recently used). Per the decision on this, that duplication is intended.

A bug this surfaced: both the Recent and All headings were gated purely on there being matched recent configurations, so a wallet with no credentials yet would have shown the new entry floating under no heading at all. Both now account for recentExtra.

The usage flag

A per-device convenience in localStorage: no personal data, nothing depends on it, and losing it only means the entry is absent from Recent until the next scan. Both accessors swallow failure — which matters more here than usual, because this test environment has no localStorage object at all; that is why several of the suite's pre-existing failures are modules touching it at import time. Covered for a storage that refuses, and for no storage object.

Tests, and why they are in a new file

They live in a new QueryableList.placement.test.tsx rather than QueryableList.test.tsx, because that file imports @/i18n, which reads localStorage at module scope and so never loads — a test added there would not have run. The new file uses the react-i18next stand-in the repo already uses in usePresentCredentialsFlow.test.tsx.

The placement assertion was mutation-proved: moving the section back between Recent and All fails it with "extraSection should precede the search input".

Not unit-tested: AddCredentials' own wiring, because AddCredentials.test.jsx is one of the five files that already fail to load. The QueryableList contract and the storage helper are covered; the three lines joining them are not.

Verification

Base This branch
Tests 1353 pass, 0 fail 1364 pass, 0 fail
Failing files 5 the same 5
Typecheck 100 errors 100 — exactly base
Build — succeeds

Not verified: a click-through in the wrapper app. The entry point only renders when window.nativeWrapper.startScanPhysicalId exists, so the visual result needs the native build.

Closes #307.

Placement. QueryableList rendered its extraSection between the Recent
grid and the All heading, so the Scan Physical ID tile sat below
recently used credentials rather than at the top of the page as the
designs have it. It is the page's own entry point rather than one of the
queryable items, so it now renders above the search box, Recent and All.
Showing it only when no search is active is unchanged: a search is about
the issuer list, and the entry point would be noise in the results.

Recent. Every other Recent entry is derived from a stored credential
matched against a configuration from /issuer/all. Scan Physical ID is a
local route (add/digital-id), not an issuer's credential configuration,
so there is nothing to derive it from and it could never appear there.
QueryableList gains a recentExtra slot, rendered first in the Recent
grid, and AddCredentials fills it once the flow has been used. Starting
the flow is what makes it recent, which is the only signal available
without tying it to a particular issued credential.

Both headings were gated on there being matched recent configurations,
so a wallet with no credentials yet would have shown the new entry
floating under no heading; they now account for recentExtra too.

The usage flag is a per-device convenience in localStorage: no personal
data, nothing depends on it, and losing it only means the entry is
absent from Recent until the next scan. Both accessors swallow failure,
which matters more here than usual -- this test environment has no
localStorage object at all, which is why several of the suite's
pre-existing failures are modules touching it at import time.

Tests live in a new QueryableList.placement.test.tsx rather than
QueryableList.test.tsx, because that file imports @/i18n, reads
localStorage at module scope and so never loads; a test added there
would not have run. It uses the react-i18next stand-in the repo already
uses in usePresentCredentialsFlow.test.tsx. The placement assertion was
mutation-proved by moving the section back and watching it fail.

AddCredentials' own wiring is not unit-tested: AddCredentials.test.jsx
is one of the five files that already fail to load.

Verified: 1364 tests pass, 0 fail (base: 1353, 0); the same five
pre-existing file failures; typecheck 100 errors, exactly base; build
succeeds.
@changeset-bot

changeset-bot Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2e49787

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
wallet-frontend Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@smncd
smncd self-requested a review October 29, 2026 11:19

@smncd smncd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think rather than putting the "Scan physical id" entrypoint in the same list as the preconfigured credential offers, it should sit on its own, above the list and searchbar.

So:

| ------------------------------|
| title                         |
| description                   |
| ------------------------------|
| Scan Physical ID              | <- here, separate from the QueryableList
| ------------------------------|
| search bar                    |
| recent credential offers      |
| all credential offers         |
| ------------------------------|

react-router v7's navigate returns a promise. SonarCloud's
new_reliability_rating gate flagged it (javascript:S9383); void matches
how Credential.tsx already handles it.
@jessevanmuijden
jessevanmuijden requested a review from a team as a code owner October 29, 2026 13:54
Review on #415: the entry point should sit above the list and the search
bar rather than inside QueryableList, so it is not presented as one of the
preconfigured credential offers.

Add Credentials now renders the section itself, between the page
description and the list. That makes QueryableList's extraSection prop
dead -- it was added for this entry point and had no other caller -- so it
goes, along with the tests for it, and QueryableList returns to exactly
what it was before.

Dropped with it: the Recent entry and the localStorage that tracked
whether the flow had been used, which only existed to place the tile in
Recent.

One deliberate behaviour change: inside QueryableList the section hid as
soon as a query was typed. Above the search bar it is not part of what the
query filters, so it stays. Covered by a test.

The placement test is mutation-proven: moving the section back below the
list fails it.
@jessevanmuijden

Copy link
Copy Markdown
Contributor Author

Taken — the section now renders in AddCredentials itself, between the page description and QueryableList, exactly as sketched:

| title                         |
| description                   |
| Scan Physical ID              |
| search bar                    |
| recent credential offers      |
| all credential offers         |

Two consequences worth flagging:

QueryableList.extraSection is gone. It was added by d183e34f for this entry point and had no other caller (ShareCredentials does not use it), so moving the section out left it dead. QueryableList.tsx is now byte-identical to the base apart from the three removed lines, and QueryableList.test.tsx went with it — all three of its cases tested extraSection.

The Recent entry is dropped too, along with the localStorage that tracked whether the flow had been used. That only existed to place the tile in Recent, which your layout does not have.

One deliberate behaviour change: inside QueryableList the section was gated on !searchQuery, so it disappeared the moment you typed. Above the search bar it is not part of what the query filters, so it now stays visible. That seemed right for a permanent entry point, but say the word if you would rather it still hid.

Verification: full suite 105 files / 1378 passed, no type errors; eslint clean on the three touched files; npm run build OK. The placement test is mutation-proven — moving the section back below the list fails it.

@sonarqubecloud

Copy link
Copy Markdown

@jessevanmuijden jessevanmuijden changed the title fix: Scan Physical ID at the top of Add Credentials, and in Recent fix: Scan Physical ID above the search bar on Add Credentials Oct 29, 2026

@smncd smncd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Beautiful!

@smncd
smncd merged commit a9467c0 into release/sirosid Oct 29, 2026
13 checks passed
@smncd
smncd deleted the fix/307-scan-tile-at-top branch October 29, 2026 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Clarify behavior of Scan Physical ID tile and Recent Credentials

2 participants