Commit Graph

134 Commits

Author SHA1 Message Date
sdarbinyan
d8c078ad5a fix: review findings from full-diff audit (7 fixed)
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
- popularSearches sent translated display text as the actual search
  query instead of the canonical term - useSuggestion() now prefers
  target.query.q when present.
- CartService.addItem() dedup guard resolved immediately instead of
  awaiting the real in-flight add; now tracks the pending Promise per
  itemID so concurrent callers await the actual result.
- addItem()'s Promise never rejected on failure (resolve() in both
  next/error branches) - now rejects on error; buyNow() catches and
  shows an error toast instead of navigating on a failed add.
- Quick View had no stale-response guard - a slower earlier request
  could overwrite a faster later one. Added a request-generation
  counter.
- cart autoSubmitPurchase() set paymentStatus to null synchronously
  right after firing the async submit call, blanking the success
  screen while the request was still in flight. Removed the
  redundant/harmful line.
- Order terminal-status guard (cancelled/refunded can't be reopened)
  lived only in the page component. Moved enforcement into the
  gateway (single write path) via a shared TERMINAL_ORDER_STATUSES
  const, so no future caller can bypass it.
- TranslatePipe's per-instance memoization cache had no eviction,
  so bindings with volatile params (pagination counts) grew it
  unbounded for the component's lifetime. Capped at 50 entries.

Not changed: the dark-mode color override was flagged as clobbering
admin branding, but it's the exact palette explicitly requested this
session for the global dark default - not a bug.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 17:20:00 +04:00
sdarbinyan
bad3002006 fix: WCAG 2.2.2 hero autoplay pause control, invisible keyboard-focusable cart button, literal hex token
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
- Hero widget autoplay had no pause control and ignored
  prefers-reduced-motion (WCAG 2.2.2 requires a way to pause
  auto-updating content lasting >5s). Added a pause/resume toggle
  button and skip autoplay entirely when the OS prefers reduced motion.
- Cart's swipe-reveal delete-btn-mobile was reachable by Tab even
  while invisible (opacity: 0, only the touch-swipe gesture could
  reveal it) - a confusing, unusable focus stop for keyboard users.
  Now tabindex=-1 + aria-hidden until swiped. Keyboard users already
  had a full removal path via the always-visible header remove button;
  this just stops the redundant hidden button from being a dead tab
  stop.
- stars.component.scss hardcoded #cdd6d5 for the unfilled-star color
  instead of the --border-color design token.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 10:12:41 +04:00
sdarbinyan
8937aea57c fix: checkout payment-description fallback hardcoded Russian regardless of locale
getPaymentDescription()'s final fallback ('Покупка на Маркетплейсе')
ignored the active language. Moved to a translated key.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 09:09:12 +04:00
sdarbinyan
6231128288 fix: static-page loadByKey/loadByPath had no error handler, infinite spinner on failure
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
resolveByKey/resolveByRoute subscribed with only a next callback -
a resolver failure left loading=true forever with no error branch to
recover from. Added an error signal, error subscribe handler, and a
distinct error state UI (separate from the existing 404 not-found
state) with a way back home.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 08:56:25 +04:00
sdarbinyan
4ef5ea2f58 fix: cart payment/order currency ignored the selected currency
createPayment() and recordOrder() hardcoded currency: 'RUB' regardless
of LanguageService.currentCurrency() (app supports RUB/USD/EUR/AMD).
Widened CartPaymentRequest.currency from a 'RUB' literal to string and
use the actual selected currency in both calls.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 07:39:35 +04:00
sdarbinyan
4c4417dc1d fix: cart email/phone capture form was never rendered
recordOrder() and autoSubmitPurchase() read userEmail()/userPhone()
signals and submitEmail() was fully implemented (validation, error
handling), but the success screen's template never rendered the
inputs - so the form was unreachable and the fallback auto-submit
always sent blank email/phone.

- Added the email/phone form to the payment-success screen, wired to
  the existing signals/handlers.
- autoSubmitPurchase() (the 5s fallback if the user doesn't submit
  manually) no longer navigates home via an unconditional setTimeout(0)
  fired before the submission result is known - it now waits for
  submitPurchaseEmail() to settle, same as the manual path, and skips
  entirely if the user already submitted (new purchaseSubmitted flag).
- It also now sends whatever the user has typed instead of
  hardcoded-blank fields, and shows a toast instead of only logging to
  console when no Telegram user id is available.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 07:37:36 +04:00
sdarbinyan
9fa3321322 fix: stop sending client-computed price on order creation
createOrder() sent a discount-applied price per line item that the
client computed itself, with no server revalidation. Items now only
carry productId/name/quantity - the backend must price from its own
catalog. createPayment()'s amount (required to actually charge the
payment gateway) is unchanged; backend must revalidate it instead,
tracked in BACKEND-API-REFERENCE.md §12.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 07:24:08 +04:00
sdarbinyan
7a2f2a452f refactor: migrate cart payment modals to shared app-dialog primitive
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Third attempt, done properly this time - first two were reverted
(one stopped cleanly on real conflicts, one botched sequencing and
deleted the old focus-trap before finishing the swap).

DialogComponent gains closeOnEscape/closeOnBackdropClick (default true,
backward-compatible with its 13 other call sites) and ariaLabel (for
dialogs with no visible title header). FOCUSABLE_SELECTOR now includes
iframe for the bank-payment panel's focus trap.

Cart wires closeOnBackdropClick=false on both dialogs (in-flight payment
shouldn't cancel on a stray click) and closeOnEscape tied to the bank
popup's open state, so Escape closes the nested bank iframe first and
falls back to the QR view - matches the original priority exactly.

Original geometry (500px QR modal/40px padding, 960x760 bank modal/
56-16-16 padding, both mobile breakpoints) preserved via :host ::ng-deep
overrides scoped per dialog instance - same pattern already used by
product-carousel-widget.component.ts.

cart.component.ts loses ~90 lines of hand-rolled ViewChild/HostListener/
focus-trap code - app-dialog owns all of it now.

Verified live in browser: dialog sizing/padding/aria-label correct at
mobile+desktop, backdrop-click confirmed inert, Escape-priority confirmed
(bank closes first, then QR), initial focus lands on close button.
83/83 tests pass, tsc/build clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 11:13:33 +04:00
sdarbinyan
3e54e88db7 fix(storefront): add missing placeholder image asset and onerror fallback
getMainImage() referenced /assets/images/placeholder.svg as the no-image
fallback, but src/assets/images/ never existed - any item with zero
photos rendered a browser broken-image icon instead of a placeholder.
Added the asset.

Also added an (error) handler (onImageError) on every dynamic <img> that
renders a user/admin-supplied URL (product card, cart line item, cart
payment QR code, product gallery main + thumbnails) so a 404'd/broken
image URL swaps to the shared placeholder instead of shipping broken.
2026-07-26 00:12:43 +04:00
sdarbinyan
6c6fa00ccf fix(ui): replace native confirm()/alert() with shared dialogs and toasts
New app-confirm-dialog (wraps existing app-dialog + app-button) replaces
every native confirm() across media library bulk-delete, static pages
editor (delete/bulk-delete), builder save-bar (publish/reset-draft),
project-editor-page (reset-section), homepage/languages/widgets sections
(remove block/language/widget), and cart (clear-cart).

Cart's native alert() calls (delivery/terms validation, email send
success/failure) now route through the existing UserNotificationService
toast pipeline instead.

No native confirm()/alert()/prompt() remain in production UI.
2026-07-26 00:08:00 +04:00
sdarbinyan
a670ca994f chore(cleanup): delete unrouted legacy pages, update docs
pages/category, pages/search, pages/item-detail, pages/info/**,
pages/legal/** (40+ files) were entirely unrouted dead code:
- category/:id, category/:id/items, search all redirect/route to
  CatalogContainerComponent
- product/:id routes to ProductDetailsContainerComponent, not item-detail
- cmsContentRoutes (meant to route info/legal) is a literal empty array;
  static/legal content is served by the CMS-driven :staticPath ->
  StaticPageComponent route instead

dynamic-renderer/ is unrelated and stays - confirmed active, it's the
live homepage rendering pipeline (HomeComponent -> WebsiteRuntimeFacade
-> PageRendererService/PageResolverService -> DynamicPageLayoutComponent).

Updated docs/TODO.md, docs/KNOWN-ISSUES.md, docs/FRONTEND-ROADMAP.md,
docs/PROJECT_INDEX.md to reflect the resolution.
2026-07-25 23:56:13 +04:00
sdarbinyan
1163bfd88a fix(storefront): replace hardcoded strings with i18n, neutral empty-state wording
- Route aria-label/alt/title strings (rating, discount, carousel arrows,
  hero slides, dialog close, toast dismiss, QR code, bank payment iframe,
  guest checkout fallback) through the translate pipe/service instead of
  literal English.
- Drop the "Oops!"/"Упс!" apology framing from category/subcategory empty
  states (en/ru/hy) - zero results is not an error.
2026-07-25 23:54:08 +04:00
sdarbinyan
e0bcf9dfb8 chore: remove confirmed dead code
Dead code sweep verified manually against app.routes.ts, DI registries, and
cross-repo grep for every candidate (per prior false-positive incident with
knip on pages/**). Deleted only what has zero reachable reference:

Auth (unregistered, comment-only mention):
- core/auth/guards/ed25519-auth.guard.ts - ed25519AuthGuard never imported;
  only mentioned inside a doc-comment in admin-login-page.component.ts.
- core/auth/guards/permission.guard.ts - permissionGuard never imported.
- core/auth/interceptors/auth.interceptor.ts - authInterceptor not present
  in app.config.ts's withInterceptors([...]) list; not imported elsewhere.

Search feature:
- features/search/services/search-analytics.service.ts - SearchAnalyticsService
  never imported outside its own file.
- features/search/components/empty-results/* - app-search-empty-results
  selector never used in any template; search-bar.component.html implements
  its own inline @if (noResults) empty state instead.

Content management:
- features/content-management/pages/content-management-page.component.ts -
  thin wrapper around StaticPagesEditorComponent with zero route pointing at
  it in app.routes.ts. The rest of features/content-management/* (facade,
  static-pages-editor, page-editor, etc.) remains: it is used by
  project-editor and stays.

Backoffice CRUD scaffolding (re-verified the UI-COMPOSITION-REVIEW.md claim
independently): app.routes.ts backoffice section only loads
features/admin/{dashboard,products,categories,transactions,orders,customers,
moderation,users,monitoring,analytics} and features/backoffice/media. Grepped
every other backoffice/* folder for cross-references - none found.
- features/backoffice/{categories,customers,inventory,orders,products,settings}
  - each contained only a placeholder .gitkeep from the original scaffold
  commit (b957112); no real components were ever added, so this is not the
  "duplicate implementation" the prior doc described, just unused scaffold
  dirs. Removing corrects that doc's premise.
- features/backoffice/shared/backoffice-coming-soon-page.component.* - only
  consumer would have been those scaffold dirs; unreferenced elsewhere.
- assets/mock/backoffice/{customers,orders}/list.json - mock data with no
  corresponding fetch call; BackofficeDataProvider only exposes
  loadProducts()/loadCategories(), backed by the products/categories mock
  files, which are kept.

Dead shared barrels/models (no importer anywhere in src/app):
- shared/index.ts, shared/models/index.ts, shared/types/index.ts - unused
  re-export barrels.
- shared/models/domain/index.ts + user-preferences.model.ts (whole domain/
  subfolder) - UserPreferences interface has zero consumers.

Storefront pages (pages/public/platform-home.component.ts) - PlatformHomeComponent
has no route in app.routes.ts and is not imported anywhere; distinct from the
pages/category, pages/search, pages/info/**, pages/legal/**, pages/item-detail
components which ARE routed and were correctly left untouched.

Verification: npx tsc --noEmit -p tsconfig.app.json clean after each batch;
npm run build succeeded (pre-existing initial-bundle-budget warning only,
unrelated to this change).
2026-07-25 18:36:45 +04:00
sdarbinyan
0a1acbd610 fix(storefront): release-candidate walkthrough fixes
- Cart item description showed a stray literal "..." when the item had no
  description text (cart.component.html) — now only renders the trailing
  ellipsis when a description is present.
- Compare table showed raw internal stock enum values ("high"/"low"/etc.)
  instead of localized labels (compare-table.component.ts) — now reuses the
  same stock-label mapping used by product cards.
- Search with zero results incorrectly showed the empty-category messaging
  ("browse categories" / "go to parent category") stacked on top of the
  search's own "nothing found" message (catalog-container.component.ts) —
  isEmptyCategoryState now excludes active search queries so only the
  search-appropriate empty state renders.
- Footer "About" link pointed to /about, which 404s; the actual CMS page
  route is /about-us (bootstrap.json mock nav data) — corrected the route.
- Added missing public/assets/images/placeholder.svg, the fallback image
  referenced by getMainImage() for items without photos (previously 404s
  if that fallback path is ever hit).

Investigated and left as-is (not code bugs): /images/*.webp 404s on
product cards are references to a real backend/CDN not present in local
dev (confirmed via mock-data.interceptor.ts and api.service.ts image-URL
resolution) — expected dev-only gap. Footer "Contacts" link (/contacts)
has no corresponding static page content at all in mock data; flagging
for a content decision rather than fabricating copy.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 09:46:51 +04:00
sdarbinyan
fb1afb72d4 fix(storefront): WCAG 2.1 AA accessibility fixes
RC A11Y-01 audit pass, storefront + shared app-shell chrome only. Builds
on RC-Visual-02/RC-Premium-01/RC STORE-01 without redoing that work.

- Skip link: added first-focusable "skip to main content" link (app.html,
  styles.scss .skip-link/.sr-only), targeting new #main-content landmark.
  New app.skipToContent i18n key in en/ru/hy.
- Header: mobile menu items stayed keyboard-focusable and screen-reader
  reachable while visually collapsed (max-height:0 with no visibility
  toggle) - fixed with visibility:hidden + matched transition-delay.
  Desktop search input (readonly, click-to-navigate) had no keyboard
  activation - added aria-label + (keydown.enter).
- Cart payment/bank-payment modals: custom (non-app-dialog) UI had no
  focus trap, no Escape handling, and never returned focus to the
  triggering element - ported app-dialog's confirmed-correct
  focus-trap/Escape/return-focus pattern directly onto cart.component.ts.
  Added role="dialog"/aria-modal/aria-label to both panels and
  role="status"|"alert"/aria-live to every payment-status screen so
  screen readers announce state changes (creating/waiting/success/
  error/timeout).
- Search combobox: suggestion listbox had no role="combobox" wiring on
  the input and suggestion buttons weren't role="option" - added
  aria-autocomplete, aria-controls, aria-activedescendant, aria-selected
  so the existing arrow-key navigation is announced to screen readers.
- Product tabs: tablist/tab pattern was incomplete (no role="tablist",
  no tabpanel) - added role="tablist" + ids to product-tabs.component,
  role="tabpanel"/aria-labelledby to the content panel in
  product-details-container.
- Review form: rating/text validation errors weren't associated with
  their controls (no aria-describedby, no role="alert") - fixed; added
  aria-required to the review textarea.
- delivery-selector: added aria-required to the delivery <select> when
  a selection is mandatory.
- Shared app-icon component: doc comment claimed "decorative by default
  (aria-hidden)" but no aria-hidden was ever applied - fixed to actually
  set aria-hidden="true" when undecorated, and role="img"/aria-label
  when ariaLabel is passed. Shared component, affects every icon-only
  usage app-wide, no visual change.
- Color contrast: --text-light fails WCAG AA 4.5:1 for normal text in
  every theme (dexar 3.39:1, lavero/novo 2.54:1 against white). The two
  in-scope usages (company-details org-short/basis, review-form
  upload-placeholder) switched to --text-secondary (4.55:1-7.56:1,
  passes), same visual family, no layout change.

Flagged, not fixed (design-system decisions, not polish):
- --border-color fails WCAG 1.4.11 3:1 for UI-component boundaries in
  every theme (dexar 1.42:1, lavero/novo 1.24:1 vs white) - pervasive
  token used by hundreds of borders app-wide; needs theme-owner sign-off.
- --success-color/--warning-color/--error-color/--info-color used as
  plain text-on-white in several places (product-information,
  question-card, review-form, compare-page) fail 4.5:1 (2.15-3.76:1) -
  genuine brand semantic colors, changing them to pass would visibly
  shift the palette; needs a deliberate token decision.
- Header mobile-menu max-height/padding transition (pre-existing,
  unrelated to this fix) flagged by design lint as layout-thrashing;
  left as-is per the "no layout/business-logic changes" constraint.

Verified: npx tsc --noEmit clean; npm run build green (only the
pre-existing bundle-budget warning, unrelated to this pass).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 08:46:18 +04:00
sdarbinyan
ce96ef184d chore(storefront): remove dead cart email-capture markup and CSS
Post-payment email/phone-capture form in cart.component.html was
commented-out markup (never rendered), with a matching ~90-line dead
.email-form CSS block still shipping in the bundle. Removed both.
Closes KNOWN-ISSUES.md item 10.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 23:51:10 +04:00
sdarbinyan
2e854954ac fix(storefront): use shared app-skeleton in category/search loading state
Category and Search pages still hand-rolled their infinite-scroll
loading skeleton (.skeleton-card/.skeleton-image/.skeleton-line
divs with their own hardcoded-hex shimmer animation) instead of the
shared app-skeleton primitive already used by catalog-container and
product-details-container. Swapped both to app-skeleton (shape=rect
for image/button, shape=text for lines), removed the now-dead
per-page shimmer CSS/hex colors. Closes KNOWN-ISSUES.md item 9.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 23:50:59 +04:00
sdarbinyan
d5603c229e fix(storefront): premium UX polish for static pages
- faq-{ru,en,hy}.component.html: convert each FAQ entry from an always-
  expanded <div>/<h3> block into a native <details class="faq-item">/
  <summary> disclosure, reusing the global expander-chevron pattern
  already defined in styles.scss (no bespoke accordion component built);
  answer body wrapped in .faq-answer for spacing
- faq.component.scss: restyle .faq-item for the details/summary shape
  (summary uses tokenized font-size/weight, focus-visible ring, [open]
  state gets a stronger shadow instead of the old always-on hover-lift);
  hardcoded `all 0.3s ease` replaced with --transition-normal on the
  specific properties that change; added a reduced-motion override
- shared-legal.scss: hardcoded `transition: all 0.3s ease` (4 call sites:
  info-card, features-list feature, contact-item/contact-link,
  contact-email) normalized to --transition-normal on transform/
  box-shadow/background; paragraphs and lists get max-width: 70ch so
  long-form legal/info text keeps a readable line length within the
  wider 900px .legal-container
- static-page.component.scss (CMS-driven static-page renderer): spacing
  converted to --space-* tokens; prose now capped at 70ch; added actual
  content styling (headings, lists, links, images, blockquote, table)
  for arbitrary CMS-authored HTML rendered via [innerHTML], since the
  previous rules only styled h2/h3 margins and left every other tag
  unstyled; line-height moved to --line-height-relaxed token

Build verified green via `npm run build`.

Out of scope / skipped:
- info/contacts has no contact form (plain link list) - no app-input/
  app-form-field polish applicable
- no breadcrumbs/anchor nav exist on any page in scope - nothing to
  align focus-visible on
- legal-page/info scss files (about, delivery, guarantee, company-
  details, payment-terms, privacy-policy, public-offer, return-policy)
  already used design tokens with no hex literals and had no accordion/
  form elements - left untouched
- shared-legal.scss's border-left accent on .legal-section/.info-box/
  .highlight and the fadeIn entrance animation durations left as-is;
  pre-existing sitewide pattern, not a new introduction, changing it is
  a redesign call outside this pass's scope

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 12:07:14 +04:00
sdarbinyan
99560202c3 fix(storefront): premium UX polish for cart, checkout
- cart.component.scss: normalize hardcoded hex colors to design tokens
  (--text-primary, --text-secondary, --bg-primary/--bg-secondary/
  --bg-tertiary, --border-color, --error-color, --success-color,
  --warning-color, --shadow-*, --transition-*, --radius-* fallbacks)
  across cart items, quantity controls, summary, login gate, terms
  checkbox, payment modal, payment-active QR screen, and bank-payment
  iframe modal
- cart.component.scss: deduplicate an accidental duplicate
  .close-modal-btn rule block (identical CSS repeated twice)
- cart.component.scss: add focus-visible rings to clear-cart, remove,
  quantity, checkout, close-modal, retry-payment, copy/open-link,
  telegram-login, and card-payment buttons
- cart.component.scss: delivery-required warning now pairs an icon
  with the text instead of relying on color/background alone
- cart.component.html: add warning icon + role="alert" to the
  delivery-required notice; add aria-live/aria-label to the quantity
  value so screen readers announce quantity changes
- delivery-selector.component.scss: normalize hardcoded hex colors to
  design tokens; remove dead :host-context(.cart-container.alt) rules
  left over after the .alt theme was removed from cart.component in
  RC-Visual-02 (cart-container never carries an .alt class anymore);
  add hover/focus-visible states to the delivery <select>

Build verified green via `npm run build`.

Out of scope / skipped:
- Did not restructure the payment modal or bank-payment iframe overlay
  into shared app-dialog - it has custom multi-step state (creating/
  waiting/success/error/timeout) and an already-implemented manual
  focus-trap; restructuring it is a composition change, not visual
  polish
- Did not convert clearCart()'s native confirm() to a custom
  confirm-remove dialog - no existing storefront confirm-dialog
  pattern to follow, and adding one is a composition/architecture
  change
- spinner-large/spinner-small left untouched per RC-Visual-02 guidance
  (in-progress action state, not content loading)
- .email-form block (email/phone capture after payment success) is
  dead CSS behind commented-out markup; left in place rather than
  deleting, since removing it is a code-cleanup call, not visual
  polish
- region-selector/language-selector are header-only, not part of the
  cart/checkout flow - left untouched
- no dedicated checkout page exists; checkout is the payment section
  of the cart page, covered above

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 11:57:23 +04:00
sdarbinyan
9ea8c98faf fix(storefront): premium UX polish for home, catalog, search
- product-card: normalize hardcoded hex colors to design tokens
  (--text-primary, --border-color, --primary-color, --bg-tertiary,
  --bg-secondary); stock bar and stock badge now use semantic
  --success-color/--warning-color/--error-color instead of
  near-duplicate literal hex; add-to-cart hover uses --primary-hover
  and --transition-* tokens; card hover shadow uses --shadow-lg
- product-card: add aria-pressed to favorite/compare toggle buttons
  so their selected state isn't color-only
- filters-panel: add aria-pressed to color/size/rating filter chips;
  add a visible checkmark glyph on selected color swatches plus a
  focus-style selection ring, so selection isn't conveyed by border
  color alone
- layout-switcher: add aria-pressed to the active layout button
- catalog-container: add aria-current to the mobile sort-sheet and
  grid-sheet option buttons; active sort option gets a checkmark
  and bold weight instead of color-only highlighting
- category-grid: normalize hardcoded border/background/text colors
  to tokens; align focus ring with the color-mix pattern used
  elsewhere in catalog
- search-results, sorting-control: normalize skeleton/select colors
  to tokens; sort <select> gets a hover border state
- home: convert loading-grid/empty-state spacing to --space-* tokens

Build verified green via `npm run build`.

Out of scope / skipped:
- pages/category and pages/search retain their existing hand-rolled
  skeleton markup (not app-skeleton) - replacing it is a composition
  change, not covered by this visual-polish pass
- product-card rating-stars color and legacy pages/category,
  pages/search hex literals left as-is where no exact token match
  exists, to avoid an unintended visual shift

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 11:34:20 +04:00
sdarbinyan
2e31e80e28 fix(storefront): composition audit fixes for cart, catalog, product, compare, wishlist, static pages
- Replace hand-rolled loading/error/empty markup with shared app-skeleton,
  app-empty-state, and app-button across catalog, product details, cart,
  compare, wishlist, and the public static-page renderer
- Fix hardcoded hex colors that bypassed theme CSS variables (catalog,
  product details), restoring multi-tenant theme correctness
- Remove ~1100 lines of dead "alt" cart theme CSS (never applied by the
  template) from cart.component.scss, bringing it back under the 40kB
  build budget (89.49kB -> 59.39kB cart-component chunk)
- Swap legacy global .btn/.btn-ghost/.btn-primary classes for app-button
  in compare and wishlist empty/toolbar actions
2026-07-23 10:37:06 +04:00
sdarbinyan
f261800159 feat(payment): add qrDescription/customerID fields, TTL-based QR polling
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
- CartPaymentRequest gains qrDescription (brandName > hostname > fallback
  text) and customerID (telegram id)
- QrCreateResponse gains qrTTL; polling window now derived from it
  (min 60s) instead of a fixed 3-minute/36-check cap
- PAYMENT_MAX_CHECKS replaced by PAYMENT_MIN_POLL_SECONDS
2026-07-23 00:26:35 +04:00
sdarbinyan
5c54541b4c style(design-system): normalize font-weight literals (400/500/600/700) to tokens
Mechanical, value-preserving: font-weight: 400/500/600/700 -> var(--font-weight-normal/medium/semibold/bold, <same value>) across src/app.
Note: cart.component.scss now sits ~771 bytes over its per-file budget
in angular.json due to longer var() strings; non-fatal build warning,
noted in docs/UI-DESIGN-REVIEW.md as a follow-up (either bump the
component style budget slightly or accept the warning).
2026-07-20 03:28:56 +04:00
sdarbinyan
be59db2e2d style(design-system): normalize exact-match border-radius literals to tokens
Mechanical sweep for border-radius: 4px/8px/12px/13px/999px replaced
with var(--radius-xs/sm/md/lg/full, <same value>) across src/app.
Only exact matches to existing token values were touched (20px, 16px,
10px, 6px, 3px, 2px etc. were left as-is since no token maps to them
without a visible size change on at least one tenant theme — see
docs/UI-DESIGN-REVIEW.md).
2026-07-20 03:27:25 +04:00
sdarbinyan
7cb1c8c3c6 style(design-system): roll out font-size scale across storefront/builder/backoffice
Mechanical, value-preserving substitution: every literal font-size
declaration across src/app (89 files) that matched one of the 9
typography scale steps introduced earlier (--font-size-xs..4xl) was
replaced with var(--font-size-STEP, <same-or-nearest-step-value>).

Values within ~0.03rem/1px of a scale step were snapped to that step
(e.g. 0.85rem and 0.8rem both -> --font-size-sm/0.8125rem; 0.9rem and
0.875rem -> --font-size-base/0.875rem) to consolidate roughly 15
near-duplicate sizes down to the 9-step scale, per the RC design-system
finalization brief. This eliminates most of the font-size fragmentation
found across the app (previously: 0.7/0.72/0.75/0.78/0.8/0.8125/0.85/
0.875/0.9/0.9375/0.95/1/1.05/1.1/1.125/1.15/1.2/1.25/1.3/1.35/1.4/1.5/
1.75/2rem all in live use simultaneously).

Not touched (deliberately, see docs/UI-DESIGN-REVIEW.md): 3rem+ display
sizes (too large a jump to any existing step, would need a --font-size-5xl
addition), font-size values expressed via clamp()/calc(), and any
component listed as intentionally distinct (code-editor syntax tokens,
theme brand colors).
2026-07-20 03:26:17 +04:00
sdarbinyan
fbe56015b5 fix(icons): icon-only button accessibility pass
Swept every icon-only button app-wide for an accessible name. Found
three relying on title-only (not reliably announced by screen
readers) or nothing at all: region-selector's detect-location button,
the carousel add-to-cart button, and the subcategories add-to-cart
button (had no label at all). All now have aria-label.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 03:02:14 +04:00
sdarbinyan
e1112bbd50 fix(icons): replace remaining hand-rolled inline SVGs with Lucide
telegram-login: close X and lock icons (auth-gate icon reused across
telegram-login and cart - same 'log in required' concept, now the
same lock icon in both instead of two different hand-drawn shapes);
retry/refresh icon (QR expired/error states, was duplicated). Added
missing aria-label on the close button (had none).

catalog-empty-state, category, subcategories, item-detail: empty-state
illustrations (package/search/grid), add-to-cart icons, success/error
status icons, and thumbs up/down vote icons replaced. Rating stars
(item-detail, both product rating and per-review rating) now use one
Star icon with a color input and a .dx-star--filled CSS class for the
solid/outline toggle, instead of hand-toggling raw fill/stroke SVG
attributes - fixes the same rating-star pattern being drawn two
different ways (outline-only in the carousel earlier, fill-toggling
here).

Added color input to app-icon (was stroke-only via currentColor
before) and four more icons to the registry: refresh, thumbsUp/Down,
locate/mapPin (added earlier this session).

Also fixed the currency-dropdown chevron in language-selector that a
prior replace_all missed (same markup, different [class.rotated]
binding target).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 02:53:52 +04:00
sdarbinyan
3837ddfb2d fix(icons): replace hand-rolled inline SVGs with Lucide (cart, selectors, carousel)
Cart: trash/X/plus/minus/lock icons replaced with app-icon. Removed
the standalone EmptyCartIconComponent entirely - it was a duplicate
80px shopping-cart glyph with no unique illustration, only ever used
in one place; now app-icon name="cart" inline.

Language/region selectors: dropdown chevrons (duplicated 3x with
identical path data across two components) unified on
chevronDown; region pin, locate (crosshair), and globe icons replaced.
New mapPin/locate icons added to the registry.

Items carousel: rating star and add-to-cart icons replaced.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 02:45:37 +04:00
sdarbinyan
6b0ad6455b fix(icons): replace hand-rolled inline SVGs with Lucide (header, search)
Header: same magnifying-glass path was hand-duplicated twice with two
different hex fills (#576463 desktop, #1e3c38 mobile) - now one
app-icon name="search", color inherited via currentColor. Wishlist/
compare buttons used bare '♥'/'⇄' text glyphs, entirely outside any
icon system - replaced with heart/scale icons. Cart icon, mobile-menu
home/catalog icons, and three duplicated inline chevron SVGs replaced
with app-icon equivalents. Cleaned up now-dead CSS that targeted the
old raw svg/path selectors.

Search: the same magnifying-glass path was hand-duplicated 4 times
(input icon, empty-query state, no-results state, no-query state) at
three sizes and three colors. Replaced all four with app-icon,
preserving each state's intended color via a color property on the
wrapper (icons default to currentColor).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 02:37:23 +04:00
sdarbinyan
fd5a436220 api doc
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
2026-07-20 01:02:36 +04:00
sdarbinyan
2734734752 fix(storefront): polish static-pages
Add role=status/aria-live to the CMS static-page loading state
(matching the pattern applied across home/search/catalog/product) and
a :focus-visible outline to the 404 back-home link.

The per-locale legal/info pages (about, contacts, delivery, faq,
guarantee, privacy-policy, public-offer, return-policy, payment-terms,
company-details) are static translated marketing content with no
interactive elements — reviewed, no changes needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19 23:41:36 +04:00
sdarbinyan
f5225ac326 fix(storefront): polish cart
Fix real regression: the payment success checkmark and timeout clock
icons had been corrupted to literal '?' glyphs (confirmed via git
history — ✓ and ⏱ were replaced), so a customer who just paid saw a
confusing '?' instead of a success indicator. Restored both icons and
marked them aria-hidden since the adjacent heading already conveys
the status.

Add missing accessible names to icon-only buttons that had none:
quantity increase/decrease controls and the mobile delete button
(desktop remove button had a title attribute only, which is not
reliably announced by screen readers — added aria-label alongside it).
New cart.increaseQuantity/decreaseQuantity keys added across all
three locales.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19 23:39:14 +04:00
sdarbinyan
bb461e007e fix(storefront): polish search
Add accessible label to the search input (was placeholder-only),
role=status/alert + aria-live on loading and error states so screen
reader users get announced updates, type=button on retry, and a
:focus-visible outline on the retry button for keyboard users.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19 23:26:32 +04:00
sdarbinyan
695312f1bb fix(storefront): polish home
Replace hardcoded loading text with skeleton state (app-skeleton) and
plain empty-state text with shared EmptyStateComponent. Remove ~900
lines of dead CSS from two unused prior redesigns (.alt-* / .platform-*)
that had no template references.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19 23:19:08 +04:00
sdarbinyan
96a338ef6f chore: remove orphaned backoffice/builder dead code
Sprint 2 high-priority cleanup: backoffice-dashboard.component.ts and
builder-sandbox.component.ts were not routed anywhere, superseded by
features/backoffice and features/project-editor. Their sole facades
(BackofficeFacade, BuilderConfigFacade) had no other consumers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 02:43:46 +04:00
sdarbinyan
7d6c09a346 feat(cms): add static pages module 2026-07-10 13:52:01 +04:00
sdarbinyan
8d652c8259 feat(platform): sprint 11.5 standardization
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
2026-07-09 02:29:12 +04:00
sdarbinyan
6550250d13 cleanup: remove tenant variant logic and enforce config-driven UI 2026-07-05 04:07:25 +04:00
sdarbinyan
79a12c0ec2 fix DI errors and stabilize static page navigation 2026-07-05 03:41:13 +04:00
sdarbinyan
b0c5c5e051 feat static pages system with dynamic footer and safe html rendering 2026-07-05 03:37:35 +04:00
sdarbinyan
0089790d41 feat ui foundation layer for page container sections and grid 2026-07-05 02:50:53 +04:00
sdarbinyan
c3d1153f0e Sprint 8: add widget manifest and data source engine 2026-07-05 02:08:15 +04:00
sdarbinyan
91d9444875 Sprint 7: add section engine 2026-07-05 01:55:41 +04:00
sdarbinyan
d4a5daeb4c product details implementation 2026-07-05 01:43:56 +04:00
sdarbinyan
0efcfb5225 product grid creating 2026-07-05 01:36:21 +04:00
sdarbinyan
d2f0f0de54 CAtegory component making 2026-07-05 01:24:54 +04:00
sdarbinyan
01d2b26021 Support variant-aware cart lines 2026-07-05 01:12:07 +04:00
sdarbinyan
3f5aa2af2a Polish marketplace search states 2026-07-05 01:10:56 +04:00
sdarbinyan
3974eefbfe Support nested marketplace categories 2026-07-05 01:09:55 +04:00
sdarbinyan
b676cec4e9 Add related products to detail page 2026-07-05 01:07:53 +04:00