Aman-Mittal opened a new pull request, #526:
URL: https://github.com/apache/fineract-backoffice-ui/pull/526

   ## The headline defect
   
   The Guide button opened the **dashboard** tour on every route it did not 
recognise. Route matching was `url.includes('/loans')`, which also claimed any 
path with those characters anywhere in it.
   
   `/accounting` on `main` — the copy reads "the key areas of the dashboard" 
over a screen that is not one:
   
   ![Dashboard copy on the Accounting 
screen](https://raw.githubusercontent.com/Aman-Mittal/fineract-backoffice-ui/assets/issue-screenshots/guide-wrong-tour-before.png)
   
   The same screen on this branch:
   
   ![Accounting copy on the Accounting 
screen](https://raw.githubusercontent.com/Aman-Mittal/fineract-backoffice-ui/assets/issue-screenshots/guide-wrong-tour-after.png)
   
   ```
   before  /accounting → {"title":"Welcome to Fineract 
Backoffice","counter":"Step 1 of 2"}
   after   /accounting → {"title":"Accounting","counter":"Step 1 of 5"}
   ```
   
   Both frames are the same screen at the same moment — `main` at `55abe539` 
was served alongside the branch.
   
   ## Every screen gets its own tour
   
   URLs resolve through anchored patterns, most specific first. A screen with 
no hand-written copy gets a tour **composed** from its own route `title` plus 
one step per control that is actually on it, detected at open time. A 
hand-written tour that points at nothing gains those steps too, which took the 
section pages from one card to four.
   
   A step appears only because the control is there, so nothing is filler and 
nothing can go stale when a screen changes.
   
   ## Four selectors pointed at elements that cannot exist
   
   Each rendered its copy and highlighted nothing, which is invisible from the 
outside:
   
   | Selector | Why it never matched | Tours |
   |---|---|---|
   | `button[headerActions]` | the attribute sits on an `ion-button`, whose 
native button is in a shadow root that never carries it | 4 |
   | `mat-select[name="productId"]`, `[name="savingsAccountId"]` | Material 
leftovers; this application has no Angular Material | shares-create |
   | `.tab-group` | applied by **no template anywhere** — a dead style rule in 
five record views, from the Material port. All sixteen screens with tabs render 
an `ion-segment` | 4 |
   | `[headerActions]` alone | groups, centres and share accounts ask 
`app-data-table` for a create button instead of projecting one | 3 |
   
   Steps are also scoped now: a content step is searched inside `main`, so a 
loose selector can no longer reach the shell the way a bare `ul` once resolved 
to the sidebar's nav list. Resolution retries while the view settles rather 
than silently finding nothing on a screen that is still fetching.
   
   ## Walking all twenty guided views found three more
   
   At **412×839** and **1440×900**, stepping every step and checking whether 
the declared target actually took the highlight:
   
   - the business-date and Guide steps pointed at controls that move into the 
header's overflow menu on a narrow viewport, so both highlighted nothing;
   - the share-account form's last select sat 30px **under** the mobile sheet;
   - on the dashboard at 1440×900 the card painted over **77.6%** of the System 
Status card — that step's entire subject, with 48px showing.
   
   ![The dashboard step covering its own 
subject](https://raw.githubusercontent.com/Aman-Mittal/fineract-backoffice-ui/assets/issue-screenshots/guide-dashboard-occluded-before.png)
   
   Both widths now get room to scroll a target clear of the card. Re-measured: 
**0% covered**, and no step at either width fails to find its target.
   
   ![The same step, target clear of the 
card](https://raw.githubusercontent.com/Aman-Mittal/fineract-backoffice-ui/assets/issue-screenshots/guide-dashboard-occluded-after.png)
   
   The narrow layout is a full-width bottom sheet at the shared 768px shell 
breakpoint:
   
   ![The tour as a bottom sheet on a 
phone](https://raw.githubusercontent.com/Aman-Mittal/fineract-backoffice-ui/assets/issue-screenshots/guide-mobile-bottom-sheet.png)
   
   ## Two defects found in review, in code added by this PR
   
   Worth calling out rather than burying, since both were mine and both were 
caught by checking rather than by reading:
   
   - **Escape only worked while focus was inside the card.** It was a host 
binding, and the tour is non-modal by design, so a user who clicked the thing a 
step describes had no keyboard way out. It listens on `document` now, guarded 
so it does not answer an Escape meant for something else.
   - **A tour survived navigation.** Opening it on the dashboard and clicking 
Clients left the dashboard card over the client list, with Next explaining 
Fineract environment health and nothing highlighted — the same wrongness as the 
old fallback, reached by navigating instead of by pressing the button. It ends 
on `NavigationEnd`.
   
   Both have a regression test that fails without the fix.
   
   ## Accessibility, i18n and theming
   
   The card is a `dialog` named and described by its own copy, the step counter 
is a polite live region because Next replaces the text in place, Escape closes, 
and focus returns to the opener.
   
   "Step X of Y" and the button's own label were hardcoded English and are now 
translated.
   
   The highlight colour is a themed token instead of a hex in a component. One 
value cannot serve both themes — measured against the surfaces a highlight 
lands on:
   
   | | light | dark |
   |---|---|---|
   | `#b45309` | 4.23 – 5.02:1 | 3.32 – 3.87:1 |
   | `#f59e0b` | 1.81 – 2.15:1 | 7.76 – 9.05:1 |
   
   So each theme takes the value that clears WCAG 1.4.11's 3:1 comfortably. 
Measured live in dark mode afterwards: **8.72:1** for the outline against the 
surface behind it, **7.69:1** for the card text.
   
   ![The highlight in dark 
mode](https://raw.githubusercontent.com/Aman-Mittal/fineract-backoffice-ui/assets/issue-screenshots/guide-dark-highlight.png)
   
   The highlight also no longer sets `position` or `z-index`, which was enough 
to move a grid child while the tour was open.
   
   ## Verification
   
   | | |
   |---|---|
   | `npm run test:unit` | 237 files / **1454 tests**, exit 0 |
   | `npm run build` | clean |
   | e2e `mocked` / `mobile` | 5 passed 1 skipped / 1 passed 5 skipped — the 
skips are the viewport guards |
   | Mobile walkthrough, 20 views | no dead targets, nothing hidden by the 
card, no overflow |
   | Desktop walkthrough, 20 views | same |
   | lint, `check:translations`, `check:responsive`, `check:a11y-names`, 
`check:icons`, `check-license.sh`, `check:branding-path`, `typecheck:e2e` | 
clean |
   
   `playwright.config.ts` gains a `DUAL_VIEWPORT_SPECS` list rather than adding 
the spec to `MOBILE_SPECS`: that array doubles as the `mocked` project's 
`testIgnore`, so joining it would have removed the desktop half of the spec 
from the run entirely.
   
   `DOCS/GUIDED_TOUR.md` documents how a tour is chosen, how one is composed, 
and the selector traps above. `DOCS/MOBILE.md` said the narrow header *hides* 
the business date and guide — it moves them into a popover, which is what the 
new grouped selectors depend on, so that paragraph is corrected.
   
   ## Known and not addressed here
   
   - `/tellers` shows "This screen" rather than "Tellers": its `path: ''` child 
declares no `title`. 197 of 305 route entries have one; #355 covers that.
   - `role="dialog"` without a focus trap. Correct for a non-modal coach mark, 
but Tab still walks behind the card.
   - The blank `/accounting`, `/organization`, `/system` visible in the first 
screenshot, and `/security/audit-trails` silently redirecting to `/dashboard`. 
Both predate this branch and are filed separately.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to