Commit Graph
14 Commits
Author SHA1 Message Date
amirhosein.ashourlooandClaude Sonnet 5 7089078b4c Use bundled logo from public/ instead of the API
Header, footer and og:image now read public/images/logo.png via
LOGO_SRC in config.ts. The API's /website/favicon returned another
business's mark, so getFavicon()/BrandAssets are removed and the tab
icon is the bundled favicon.png. Footer logo is now 70px like the
header (108px was sized for the old square mark; the new 200x48
wordmark would be 450px wide).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 00:13:53 +03:30
amirhosein.ashourlooandClaude Sonnet 5 8e82370b64 Shrink desktop header logo to 70px
Header row height (lg:h-32 -> lg:h-25) and the logo's own height
(h-[108px] -> h-[70px]) both come down together so the row doesn't
carry leftover empty space around the smaller mark. Footer logo is
unchanged (still 108px) — the two are sized independently.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 17:56:27 +03:30
websites-deploy 990e1999b9 Use Next.js standalone output for lean production runtime.
Deploy can drop full node_modules and run .next/standalone/server.js (~100MB RSS).
2026-09-08 06:54:07 +00:00
amirhosein.ashourlooandClaude Sonnet 5 e44fc90d96 Make blog cards square + clickable, add fallback article detail pages
- Blog card thumbnails (homepage magazine carousel, /blog listing, and
  the "more posts" carousel) are now square instead of 16:9.
- Fallback blog cards (src/data/fallbackBlogs.ts) were previously
  plain, non-clickable divs since /blogs is still empty on this
  tenant and no real detail page existed for them. They now link to a
  real local /blog/{id}/{slug} page via getFallbackBlogById() — image
  and title are both inside the link. That page shows the real
  title/image/category we have plus a "coming soon" note instead of
  fabricating article body content.
- Homepage magazine section's fallback posts now link to their own
  detail page instead of generically to /blog.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 14:55:58 +03:30
amirhosein.ashourlooandClaude Sonnet 5 4ffdf03727 Rewrite cart as client-only guest cart per AI_PROMPT.md spec
Replaces the previous server-cart implementation (which wrongly called
the customer-dashboard-only /businesses/{id}/cart* API) with the
documented guest-cart architecture:

- src/lib/guestCart.ts: storage key/cookie name, cookie attributes,
  line shape, and encodeGuestCart() copied verbatim from AI_PROMPT.md
- CartProvider/CartButton: pure client state (localStorage + mirrored
  cookie), no bearer auth, no businessId
- CartButton's "ادامه" builds the exact documented Continue URL,
  branching on hasCustomerSessionCookie() to either
  customer.<domain>/checkout/cart?guestCart=<encoded> or
  .../login?redirect=<encoded checkout path>
- Auth cookie corrected to the real documented name
  (meshkee_customer_access_token, possibly chunked) via a shared
  reassembleChunkedCookie() helper used by both auth.ts (server) and
  authUser.ts (client)
- ProductBuyPanel/product pages switched to the documented
  GET .../store-items/by-product/{id} endpoint (getStoreItemByProduct)
- isInStock() treats stockQuantity === null as unlimited stock, not
  out-of-stock, per spec
- AGENTS.md updated to describe this architecture and remove the
  incorrect server-cart documentation

Manually verified in-browser: badge count, popup lines/qty/remove/
total all update correctly against injected guest-cart data; tsc,
eslint, and next build all pass clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 13:29:30 +03:30
amirhosein.ashourlooandClaude Sonnet 5 d624ad8a32 Add shopping cart, store-items pages, contact form toast; skip workshops+portfolio
Neither workshops nor portfolio is in this tenant's enabledModules
(["products","blog","finance"]) - same reasoning as before, page/nav entry
withheld until either is actually enabled.

Shopping cart (new):
- CartProvider (client context): live cart state, add/update/remove/refresh,
  reads AUTH_TOKEN_COOKIE, calls the real /businesses/{id}/cart* endpoints
  (bearer-only, no guest cart - by design, not a gap)
- CartButton: header/bottom-nav icon with a live count badge and a popup
  preview; "ادامه" hands off to the customer portal's own cart/checkout,
  since this storefront has no checkout UI (address/payment) to hand off to
  internally - out of scope for this pass
- ProductBuyPanel: quantity stepper, wired to CartProvider.addItem() instead
  of its own ad-hoc fetch+token logic, toast on success
- Cart/CartItem types are a best-effort guess at an undocumented response
  shape (OpenAPI gives no field-level schema) - unverified against real data
  since store-items are still empty; read every field defensively

Store-items pages (new): /store-items (flat listing of purchasable variants,
always priced unlike /products) and /store-items/{id} (detail - no slug,
resolves the variant's productId and reuses the product's own gallery/
description/technical-info/comments/related-products, just with that
variant preselected).

Contact form: now shows a toast + inline success text and resets while
staying on screen, instead of swapping to a separate "thank you" panel.

New shared providers: ToastProvider (useToast) and CartProvider, both
mounted once in layout.tsx.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 08:56:04 +03:30
amirhosein.ashourlooandClaude Sonnet 5 e676397bae Fix hero slider pagination dots showing swiper's black/blue defaults
.swiper-pagination-bullet{background:#fff} had the same specificity as
swiper's own .swiper-pagination-bullet{background:var(...)} rule and lost
the cascade depending on chunk order, so dots rendered swiper's actual
defaults (black inactive, iOS-blue active) instead of white.

Fix: set swiper's own theming variables (--swiper-pagination-bullet-
inactive-color, --swiper-pagination-color, etc.) scoped to .hero-dots
instead of fighting the background property directly - this is swiper's
documented way to theme bullets and is cascade-order-proof. The active
pill shape (22px, 4px radius) has no variable of its own, so that rule
stays as a plain override, scoped under .hero-dots for higher specificity
instead of !important.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 08:01:06 +03:30
amirhosein.ashourlooandClaude Sonnet 5 0ffbd953b3 Show real titleFa captions, 3x logo size, fix category hover border
- CategoryCarousel: caption under each circle now comes from the slot
  image's own titleFa (as the business typed it) instead of the resolved
  category's API name - identity resolution via linkUrl slug is still used
  for the href, just not for the visible label
- Replace the hover ring (box-shadow) with a real 1px border - the ring
  rendered oddly against Swiper's transformed slide track, looking like it
  "leaked" into the row above; a border participates in normal box layout
  and doesn't have that problem (border-box sizing means zero layout shift)
- Header/footer logo: h-9 (36px) -> h-[108px], 3x on request; header row
  height bumped to fit. Note: the currently-uploaded (wrong-business) logo
  has a lot of baked-in padding, so it still reads small even at 3x - that's
  the asset, not the sizing
- Re-verified the static-image-slot wiring end to end against the original
  spec (url->img, linkUrl->href, aspectRatio from API, placeholder on
  empty/fail) - all still holds

Also add a Deployment section to AGENTS.md: this repo's whole point is
CI/CD from origin/main, and local commits sitting unpushed (as 3 commits
were, until now) look indistinguishable from unfixed bugs to whoever is
testing the deployed site.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 07:53:20 +03:30
amirhosein.ashourlooandClaude Sonnet 5 2249a07dee Fix category-slot matching: identity by linkUrl slug, not array position
The homepage category carousel and installments highlights matched
slot.images[i] to categoryList[i] by array index, assuming the business's
CMS upload order lines up with this site's own category sort order. It
doesn't - live data showed a laptop photo landing on "موبایل" and "لوازم
برقی" appearing on the site despite no photo ever being uploaded for it,
purely from index luck. titleFa isn't reliable either: the same laptop image
was titled "تبلت" in the CMS, contradicting its own linkUrl.

Fix: resolve each image's category from the `category` query param on its
own linkUrl (categorySlugFromLinkUrl() in slug.ts, matched against
ApiCategory.slug via the new findNodeBySlug()). The homepage carousel is now
fully slot-driven - it iterates slot.images (in the CMS's own sortOrder) and
simply omits any category with no matching image, per explicit product
direction, rather than falling back to a placeholder. Installments keeps its
curated HIGHLIGHT_IDS list with a placeholder for uncovered categories,
since that page always shows the same fixed set, but now uses the same
identity-based lookup instead of position.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 07:36:24 +03:30
amirhosein.ashourlooandClaude Sonnet 5 db7d00e473 Add about/contact/installments pages, fix category slot bugs, wire live branding
- Enlarge category carousel thumbnails (90px -> 104-140px responsive) and
  confirm the slider/categories/banner static-image slots are all reading
  correctly from the CMS (verified live, not a wiring bug)
- Fix installments page dropping "هندزفری و هدفون": it's a level-3 category,
  not level-2, so level2.find() silently missed it - use findNode() over the
  whole tree instead
- Extend gen-category-placeholders.mjs to generate a placeholder for every
  category at every level (was level-2 only), needed for the fix above
- Add /about, /contact, /installments pages
  - About: real copy transcribed from the live moalem.shop theme, real
    product photos from the API, text-only brand strip (no scraped logos)
  - Contact: ContactForm.tsx posts to the real POST /contact-submissions,
    branch cards with key-less Google Maps embeds
  - Installments: flat brand-colored hero (no photo/gradient), category
    highlights reusing the same categories slot images as the homepage
- Replace the placeholder header/footer phone number with the real one, add
  real branch addresses and Instagram/Telegram links (src/data/site.ts),
  pulled from the live theme's footer
- Wire logo/favicon to GET /website/favicon (getFavicon() in api.ts) instead
  of the static bundled files, so a dashboard upload now shows automatically;
  layout.tsx metadata is now generateMetadata() to support this. The tenant's
  uploaded logo/favicon currently belongs to a different business - the
  wiring is correct and will self-correct once that's fixed in the dashboard

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 07:22:54 +03:30
amirhosein.ashourlooandClaude Sonnet 5 09a409b3e7 Update banners.psd design source
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 14:02:15 +03:30
amirhosein.ashourloo a49a233f8b first commit 2026-09-02 17:11:12 +03:30
amirhosein.ashourloo e2dc87e00a first commit 2026-09-02 17:06:42 +03:30
amirhosein.ashourloo 1bd131e9d8 first commit 2026-09-02 17:03:23 +03:30