Commit Graph

18 Commits

Author SHA1 Message Date
0360780411 feat(admin): admin-panel foundation shell + overview (slice 0)
- /admin opted out of shopper chrome in MyLayout; /admin added to server
  protectedRoutes; useRequireAdmin() gates to superusers (UserProfile.isSuperuser).
- Admin shell (admin.tsx) with sidebar nav (Overview live; other sections stubbed)
  and a mobile top bar; Overview dashboard (KPI cards + 14-day orders chart) via
  use-admin-hooks.ts hitting /api/adminpanel/v1/overview/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 12:00:49 +03:30
0b18438a97 fix(notif+auth): camelCase badge fields, seller push prompt, only 401 signs out
- app/components/MyLayout.tsx / app/components/home/HomePageTopBar.tsx /
  app/routes/profile._index.tsx: the BadgeCounts type was declared with
  snake_case fields (order_updates, seller_orders) while the API's global
  camelCase renderer sends orderUpdates / sellerOrders on the wire — every
  read went to undefined, so the "buyer activity" dot on the profile icon
  and the order-badge on the store dashboard were silently stuck at 0.
  Fixed by renaming the interface to match the wire and adding sellerChat
  (per-store roll-up) so the store dashboard sidebar reads
  badges.sellerChat[storeId] instead of the buyer-side chat count.
- app/hooks/useBadgeCounts.ts: interface + EMPTY constant updated to
  camelCase + new sellerChat map.
- app/utils/api-error-handler.ts: 403 no longer force-redirects to /logout.
  It used to force-log-out on ANY 403/401, so an approved-but-unbadged
  owner (Ehsan / Noelabel) whose store dashboard fired the Instagram-tab
  query got a 403 → forced logout → the store page vanished mid-load
  and the seller landed on the home screen convinced they'd been kicked
  off their own store. Only 401 signs the session out now.
- app/components/store/StorePushPromptCard.tsx: new dashboard-level card
  that nudges the store owner/staff to enable browser push. Unlike the
  global buyer banner it's not dismissible-forever; "بعداً یادآوری کن"
  hides for 24h and it comes back until the user actually subscribes.
  Handles the permission="denied" path with an in-browser-settings hint.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-18 13:18:08 +00:00
0a482c70fa fix(discounts): enable desktop chrome for /discounts
/discounts was missing from MyLayout's isDesktopReady allowlist, so on desktop it
stayed in the narrow mobile column with no desktop header/footer. Add it so it
gets the full-width desktop canvas; the page's lg:max-w container + Mondrian
4-column masonry then render like /sellers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 11:41:09 +03:30
a642fc0fae feat(seller-team): multi-user dashboard — store switcher, role gating, team UI
- useMyStores + team hooks (invite by phone / list / remove) in use-seller-hooks.
- useStoreOwnership rewritten to allow staff (not just the owner) via my-stores;
  exposes `role` so callers can gate owner-only UI, and no longer redirects
  members away from a store they help manage.
- Store settings: owner-only items (financial, shipping, edit store, instagram
  sync, team) hidden from staff; new "مدیریت اعضای تیم" entry (owner-only).
- New /store/:storeId/team page: invite by phone + members list with pending/
  active status + remove (owner-only, redirects staff). MyLayout keeps store mode
  on the team route.
- StoreForm edit is owner-only (redirects staff). Profile "enter my store" now
  routes owners to their store and staff to the store they manage.
- Chat already split earlier: seller inbox vs personal buyer inbox.

Depends on the seller-team backend; ships on this branch, not main.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 16:43:53 +03:30
b4d5f8d8db fix(ios): respect safe-area insets so chrome clears the notch/home bar
Content was drawing under the iOS status bar and home indicator because
the app uses viewport-fit=cover + black-translucent but the fixed/sticky
chrome didn't reserve the safe areas.

- bottom nav (MyLayout): move the 50px row into an inner box and let the
  bar extend by env(safe-area-inset-bottom) so icons sit above the home
  indicator (previously the fixed height clipped the inset padding).
- top headers gain env(safe-area-inset-top): HomePageTopBar, ExploreTopBar,
  SearchTopBar, CartHeader, ChatHeader, and wrapper-padded HeaderWithSupport
  / ProfilePagesHeader (so their absolutely-positioned buttons shift too).
- chat input pads bottom by the inset; chat scroll area height accounts for
  the taller header/input.
- _index.tsx no longer overrides the viewport meta (it was dropping
  viewport-fit=cover on the home page); the global one in root.tsx wins.

env(safe-area-inset-*) is 0 on non-notch devices, so desktop/Android render
identically — only iOS gains the padding.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 13:42:51 +03:30
fef53fd003 feat(notifications): web push opt-in + unread nav badges
Surfaces three events without a full notification center:
- service worker (public/sw.js) gains push + notificationclick handlers
  (RTL, focuses an existing tab or opens the target URL).
- usePushNotifications hook: permission + VAPID subscribe/unsubscribe
  against the backend push endpoints.
- opt-in UI both ways: a one-time dismissible post-login banner
  (PushPermissionBanner, rendered in MyLayout) and a permanent toggle
  (PushSettingToggle) on buyer profile settings and seller store settings.
- useBadgeCounts polls /api/notif/v1/badges/; small red badges on the
  bottom-nav profile icon (chat + order updates), the profile sidebar
  (پیام‌ها / سفارش‌ها) and the seller dashboard sidebar. Visiting orders
  clears its badge.

Degrades gracefully: if the backend endpoints are absent the counts fall
back to zero and nothing throws.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 14:02:56 +03:30
4af143bccf Desktop: seller dashboard shell + gate carousel arrows to product gallery
- new store.$storeId.tsx layout: sticky admin sidebar (store/products/orders/
  financial/shipping/threads/settings) beside content at lg; mobile unchanged
- MyLayout: store/* gets a full-width desktop canvas (own sidebar), no shopper
  header/footer, mobile store-nav hidden at lg
- store home: hide the redundant mobile store header at lg
- ProductImageCarousel: prev/next arrows now opt-in (showArrows) so they only
  appear on the product gallery, not every masonry card
2026-06-17 12:28:59 +03:30
24449fe5e9 Desktop: sticky-footer layout (remove gray gap above + empty area below footer)
- MyLayout: make the desktop shell a flex column with the content area
  flex-1, so the footer sits flush and pins to the bottom on short pages
- DesktopFooter: drop the mt-24 that exposed the wrapper bg as a gray band
- also fixes the light-gray patches in dark mode (wrapper bg no longer shows)
2026-06-16 14:46:39 +03:30
3156fb4204 Desktop: account area (shared sidebar) + brands list
- new profile.tsx layout: sticky desktop sidebar (user card + menu) wrapping all
  /profile/* pages; mobile renders page content only (unchanged)
- ProfilePagesHeader hidden at lg (one change covers all account sub-pages +
  cart); profile index shows a welcome on desktop (menu lives in the sidebar)
- sellers: 5-col brand grid with name overlay, contained, mobile header hidden
- MyLayout: desktop gate now covers /profile/* and /sellers
2026-06-16 12:46:22 +03:30
96034fe61a Desktop: cart checkout two-column + profile account grid
- cart checkout (/cart/$cartId): steps on the left, sticky order summary on the
  right at lg (1320px container); CartSummary becomes an inline card on desktop
  (fixed bottom bar on mobile)
- profile (/profile): contained account layout; menu becomes a 2-col card grid
  on desktop with a heading
- MyLayout: desktop gate now includes /cart/* and /profile
2026-06-16 11:19:55 +03:30
7845ab5e75 Desktop: explore page (category grid + contained layout)
- explore: hide mobile search bar at lg (global header has search); contain
  content to 1320px; category grid 2-col mobile -> 4-col desktop with taller tiles
- MyLayout: desktop gate now includes /explore
2026-06-16 11:11:46 +03:30
60d6a2a6e4 Desktop: product detail two-column layout
- ProductDetailView: gallery | info two-column grid on desktop with breadcrumb;
  gallery sticky; reviews + similar products full-width below. Mobile stack
  unchanged (only lg: utilities + a moved BottomBar, which is position:fixed so
  its DOM location doesn't affect mobile)
- BottomBar: static inline buy card on desktop (fixed bottom bar on mobile)
- ProductInfo: larger title + tightened top spacing at lg
- MyLayout: desktop gate now includes /product/*

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 22:35:06 +03:30
cf55e16a9a Desktop: seller brand header redesign + collections list/detail
- seller: desktop brand header matching the design — cover, overlapping rounded
  logo, name + verified badge + @handle, horizontal stats, Follow/Message
  actions, description; mobile blocks hidden at lg; feed = responsive masonry
- /collections: 4-column card grid on desktop (was a stretched single column)
- /collection/<id>: two-column hero (cover + info) on desktop, contained width,
  mobile header hidden at lg; products use the responsive masonry
- MyLayout: desktop gate now includes /collections and /collection/*

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 22:00:49 +03:30
d0571f8253 Login: 6-digit OTP + desktop layout
- OTP input now 6 digits (matches backend 6-digit codes): maxLength 6, six
  slots with responsive widths, verify enabled at length === 6
- login page: centered desktop card on a neutral canvas with brand mark
- MyLayout: auth pages (/login, /logout) get full-width desktop canvas and no
  mobile bottom nav at lg (no shopping header/footer)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 21:36:42 +03:30
232f7d1b3c Desktop responsive: collections grid + seller page
- HorizontalCollectionsList: 4-column grid at lg (overrides mobile fixed-width
  cards), hide scroll arrows on desktop
- seller page: contained desktop layout, hide mobile back-header at lg, show
  store name; feed uses the responsive masonry
- MyLayout: desktop chrome gate now includes /seller/*

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 21:28:25 +03:30
9650073b04 Desktop responsive: search page, cart list, masonry grid
- MondrianProductList: add desktop 4-column masonry (mobile 2-col unchanged);
  improves home "for you", search results and seller feed at lg+
- search: hide mobile SearchTopBar at lg, add results heading + centered
  1320px container
- cart list: responsive 2-column grid of cart cards + desktop heading
- MyLayout: desktop chrome gate now covers / , /search/* and /cart

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 21:06:34 +03:30
e1c5899002 Add responsive desktop layout for home page
Single responsive tree (Tailwind lg:) — mobile experience unchanged; desktop
chrome is gated to the home route for now.

- DesktopHeader / DesktopFooter components (visible only at lg+), wired to
  real routes with live cart badge and working search
- MyLayout: render desktop header/footer on home, expand container and hide
  mobile bottom nav at lg
- Home: hide mobile top bar at lg, 1320px centered container, desktop hero
  grid (carousel + 2 promos), larger section headers
- SellerTilesGrid: 2-col mobile -> 5-col desktop with name overlay

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 20:07:47 +03:30
0293655fc1 first 2026-04-29 01:44:16 +03:30