/account renders a bare Card with no site header and no links of any kind. Once a customer opens it there is no way back to the storefront short of the browser back button or editing the URL. The only navigate() calls in the file are the logout redirect and the sign-in guard.
Requested behaviour
Make it a modal with a close control that returns the customer to the page they came from.
Design consideration worth settling first
/account is a real, linkable URL. A customer may bookmark it, and the header links to it directly. If the account view exists only as a modal, then a direct visit to /account has nothing to render behind it and nowhere to close back to.
Suggested resolution — support both, from one component:
Opened from within the app (header link): a modal over the current page, closing back to it
Entered directly by URL or bookmark: a full page with site chrome, so the header itself provides the way out
That keeps the URL working, keeps it shareable, and still gives the in-app experience asked for. Worth deciding explicitly rather than by accident, because it determines whether /account stays a route at all.
Related
Part of a wider pattern — see the sibling issues for the other affected pages. The root cause is shared: only /, /admin and /cart render Layout + Header; every other customer route renders a bare card.
## Problem
`/account` renders a bare `Card` with no site header and **no links of any kind**. Once a customer opens it there is no way back to the storefront short of the browser back button or editing the URL. The only `navigate()` calls in the file are the logout redirect and the sign-in guard.
## Requested behaviour
Make it a modal with a close control that returns the customer to the page they came from.
## Design consideration worth settling first
`/account` is a real, linkable URL. A customer may bookmark it, and the header links to it directly. If the account view exists only as a modal, then a direct visit to `/account` has nothing to render behind it and nowhere to close back to.
Suggested resolution — support both, from one component:
- Opened from within the app (header link): a modal over the current page, closing back to it
- Entered directly by URL or bookmark: a full page **with site chrome**, so the header itself provides the way out
That keeps the URL working, keeps it shareable, and still gives the in-app experience asked for. Worth deciding explicitly rather than by accident, because it determines whether `/account` stays a route at all.
## Related
Part of a wider pattern — see the sibling issues for the other affected pages. The root cause is shared: only `/`, `/admin` and `/cart` render `Layout` + `Header`; every other customer route renders a bare card.
bermudalamb
self-assigned this 2026-08-18 11:43:20 -05:00
bermudalamb
added this to the Initial Build project 2026-08-18 11:43:26 -05:00
How should the modal-versus-page tension be settled?
A modal over the storefront, always — rather than the dual-mode arrangement the issue suggested. Opening it in-app renders a modal over the current page; a direct visit renders the storefront behind and opens the same modal. Chosen over dual-mode because dual-mode means two layouts of the same view that can drift apart as the account page grows, and this option gives one code path, one visual treatment, and a close action that always lands somewhere real.
When opened from the header, should the URL become /account?
Yes. The modal is a real route, so it stays bookmarkable and shareable, browser Back closes it, and refreshing keeps the view open. This also matters practically: the header link and four post-authentication redirects (Login, Register, ResetPassword, VerifyEmail) all navigate to /account already, and would have had to change if it stopped being a route.
Branch and commit naming
Branch 48-my-account-modal, following the pattern Gitea generates from an issue. Worth being precise about how the linking actually works: in Gitea the reference comes from the #48 in the commit message and PR, not from the branch name — the name is for humans. The commit carries Closes #48, so merging closes this issue automatically.
Implemented on 48-my-account-modal
main.tsx gains an AppRoutes component that renders the route table against a backdrop location. When the path is /account, the backdrop is the page named in location.state.background (supplied by the header link) or, failing that, the storefront. The account modal renders on top of it.
Closing calls navigate(-1) when there is somewhere to go back to, so the close control and the Back button do the same thing and neither leaves a dead history entry. A direct visit closes with navigate('/', { replace: true }) instead.
Account.tsx is now a titled, closable Modal rather than a bare Card, and takes an onClose from the route.
The header link passes state={{ background: location }}, so closing returns to the storefront with its filters intact rather than to a default view.
Verification
68 end-to-end tests, 5 of them new, all passing; type checking clean. No backend changes. The new spec covers: opening over a filtered storefront and closing back to it with the filter still applied, the Back button closing it, a direct visit rendering the storefront behind so closing lands somewhere real, surviving a reload, and the account contents being shown.
Note on duplicates
This issue and #51 describe the same work, as do #49 and #52. #51 and #52 were created later and are the redundant pair. Worth closing them as duplicates so the board does not carry the same work twice — I have not touched them.
## Design questions resolved
**How should the modal-versus-page tension be settled?**
A modal over the storefront, always — rather than the dual-mode arrangement the issue suggested. Opening it in-app renders a modal over the current page; a direct visit renders the storefront behind and opens the same modal. Chosen over dual-mode because dual-mode means two layouts of the same view that can drift apart as the account page grows, and this option gives one code path, one visual treatment, and a close action that always lands somewhere real.
**When opened from the header, should the URL become `/account`?**
Yes. The modal is a real route, so it stays bookmarkable and shareable, browser Back closes it, and refreshing keeps the view open. This also matters practically: the header link and four post-authentication redirects (`Login`, `Register`, `ResetPassword`, `VerifyEmail`) all navigate to `/account` already, and would have had to change if it stopped being a route.
**Branch and commit naming**
Branch `48-my-account-modal`, following the pattern Gitea generates from an issue. Worth being precise about how the linking actually works: in Gitea the reference comes from the `#48` in the commit message and PR, not from the branch name — the name is for humans. The commit carries `Closes #48`, so merging closes this issue automatically.
## Implemented on `48-my-account-modal`
- `main.tsx` gains an `AppRoutes` component that renders the route table against a *backdrop* location. When the path is `/account`, the backdrop is the page named in `location.state.background` (supplied by the header link) or, failing that, the storefront. The account modal renders on top of it.
- Closing calls `navigate(-1)` when there is somewhere to go back to, so the close control and the Back button do the same thing and neither leaves a dead history entry. A direct visit closes with `navigate('/', { replace: true })` instead.
- `Account.tsx` is now a titled, closable `Modal` rather than a bare `Card`, and takes an `onClose` from the route.
- The header link passes `state={{ background: location }}`, so closing returns to the storefront with its filters intact rather than to a default view.
## Verification
68 end-to-end tests, 5 of them new, all passing; type checking clean. No backend changes. The new spec covers: opening over a filtered storefront and closing back to it with the filter still applied, the Back button closing it, a direct visit rendering the storefront behind so closing lands somewhere real, surviving a reload, and the account contents being shown.
## Note on duplicates
This issue and #51 describe the same work, as do #49 and #52. #51 and #52 were created later and are the redundant pair. Worth closing them as duplicates so the board does not carry the same work twice — I have not touched them.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
/accountrenders a bareCardwith no site header and no links of any kind. Once a customer opens it there is no way back to the storefront short of the browser back button or editing the URL. The onlynavigate()calls in the file are the logout redirect and the sign-in guard.Requested behaviour
Make it a modal with a close control that returns the customer to the page they came from.
Design consideration worth settling first
/accountis a real, linkable URL. A customer may bookmark it, and the header links to it directly. If the account view exists only as a modal, then a direct visit to/accounthas nothing to render behind it and nowhere to close back to.Suggested resolution — support both, from one component:
That keeps the URL working, keeps it shareable, and still gives the in-app experience asked for. Worth deciding explicitly rather than by accident, because it determines whether
/accountstays a route at all.Related
Part of a wider pattern — see the sibling issues for the other affected pages. The root cause is shared: only
/,/adminand/cartrenderLayout+Header; every other customer route renders a bare card.Design questions resolved
How should the modal-versus-page tension be settled?
A modal over the storefront, always — rather than the dual-mode arrangement the issue suggested. Opening it in-app renders a modal over the current page; a direct visit renders the storefront behind and opens the same modal. Chosen over dual-mode because dual-mode means two layouts of the same view that can drift apart as the account page grows, and this option gives one code path, one visual treatment, and a close action that always lands somewhere real.
When opened from the header, should the URL become
/account?Yes. The modal is a real route, so it stays bookmarkable and shareable, browser Back closes it, and refreshing keeps the view open. This also matters practically: the header link and four post-authentication redirects (
Login,Register,ResetPassword,VerifyEmail) all navigate to/accountalready, and would have had to change if it stopped being a route.Branch and commit naming
Branch
48-my-account-modal, following the pattern Gitea generates from an issue. Worth being precise about how the linking actually works: in Gitea the reference comes from the#48in the commit message and PR, not from the branch name — the name is for humans. The commit carriesCloses #48, so merging closes this issue automatically.Implemented on
48-my-account-modalmain.tsxgains anAppRoutescomponent that renders the route table against a backdrop location. When the path is/account, the backdrop is the page named inlocation.state.background(supplied by the header link) or, failing that, the storefront. The account modal renders on top of it.navigate(-1)when there is somewhere to go back to, so the close control and the Back button do the same thing and neither leaves a dead history entry. A direct visit closes withnavigate('/', { replace: true })instead.Account.tsxis now a titled, closableModalrather than a bareCard, and takes anonClosefrom the route.state={{ background: location }}, so closing returns to the storefront with its filters intact rather than to a default view.Verification
68 end-to-end tests, 5 of them new, all passing; type checking clean. No backend changes. The new spec covers: opening over a filtered storefront and closing back to it with the filter still applied, the Back button closing it, a direct visit rendering the storefront behind so closing lands somewhere real, surviving a reload, and the account contents being shown.
Note on duplicates
This issue and #51 describe the same work, as do #49 and #52. #51 and #52 were created later and are the redundant pair. Worth closing them as duplicates so the board does not carry the same work twice — I have not touched them.