user-app: extend the redesign across the account screens

Phase 2, completing the app-wide rollout of the home/product-detail design
language (LESS colour tokens, BEM class names, hairline-bordered cards,
SectionHead, dashed empty states) onto the account side: dashboard, orders,
transactions, profile, login and register.

Reuse over re-implementation: the dashboard's live rate block is now
components/home/RateStrip.vue rather than a second hand-built strip, and
every screen uses components/ui/PageBar.vue for its chrome.

OrderCard and OrderItemCard are restyled to match. OrderItemCard drops its
always-empty note row: our OrderItem schema has no note field (legacy's
per-item note was a real column there; ours is not), so it could only ever
print a dash.

OrdersView swaps ant Tabs for the same scrolling chip rail the rest of the
redesign uses, and its full-screen Modal with hand-written CSS overrides for
a bottom Drawer, matching how every other detail surface opens.

Deleted AppHeader.vue, orphaned once every screen moved to PageBar. Its
shutter animation was driven by transitionFlag, which nothing reads any
more — the router afterEach comment claiming otherwise is corrected rather
than left asserting something untrue, and the now-inert half is flagged in
place. ScrollFetchSearch loses its isFav prop: it gated two empty-state
branches that rendered the identical image, and its only caller
(FavoritesView) now renders its own.

Behaviour is preserved throughout. Orders still reads GET
/customers/:id/orders and filters client-side; transactions still reads
GET /customers/:id/ledger-entries with legacy's CREDIT/DEBIT colour meaning
intact; profile stays read-only over real fields; login keeps the real
customer lookup plus the documented OTP stub; register stays stubbed with
copy that does not claim an account was created.

Verified in a real browser against the running API and native database:
dashboard 4 tiles with a real balance, orders 1 real order card, profile 4
real spec rows, transactions the correct empty state for a customer with no
ledger rows, and login/register confirmed with the session cleared (the
guard bounces a signed-in user away from /login, which is why they needed a
separate pass). No console errors, no horizontal overflow. vue-tsc and vite
build both clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
s.esmaeili
2026-09-15 01:34:30 +03:30
co-authored by Claude Opus 5
parent cc62975dd0
commit 0e5f9ccd7b
11 changed files with 1853 additions and 714 deletions
@@ -1,10 +1,12 @@
<!--
Ported from legacy henza_pwa/src/components/ui/ScrollFetchSearch.vue.
EXISTING ISSUE, ported as-is: both the isFav and non-isFav empty states use
the same `favoritEmpty` image (legacy imported cartEmpty/emp_search/
emp_favorite too, but never actually used them in the template — those
unused imports are dropped here as genuinely dead code; the duplicate-image
*behavior* itself is preserved).
Legacy rendered two separate empty states, gated on an `isFav` prop, that
both used the SAME favoritEmpty image — a distinction without a difference,
preserved verbatim while this was a faithful port. The only caller that ever
passed `is-fav` was FavoritesView, which now renders its own empty state in
the redesigned language, so the prop had no remaining callers and the two
identical branches collapse to one.
-->
<template>
<main
@@ -14,8 +16,7 @@
>
<slot></slot>
<Spinner cls="my-[10px]" :spinning="loading" :indicator="true" tip="درحال دریافت اطلاعات" />
<EmptyState v-if="flag && !isFav" :image="favoritEmpty" />
<EmptyState v-if="flag && isFav" :image="favoritEmpty" />
<EmptyState v-if="flag" :image="favoritEmpty" />
</main>
</template>
@@ -32,7 +33,6 @@ withDefaults(
loading: boolean
flag: boolean
padding?: string
isFav?: boolean
}>(),
{},
)