- Header logo (desktop variant) doubled: 40/48px -> 80/96px.
- Each dynamic store-specials carousel now shows an English caption
under its title at 50% opacity, derived from the group's real `key`
(e.g. "top-selling" -> "TOP SELLING") rather than inventing a
translation of the Persian title, which the API doesn't provide.
New SectionTitle `enSubtitle` prop (separate from the existing
inline `enTitle`) carries this.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- StoreSpecialCarousels now inserts one of the two banner sections
(TwoBanners/ThreeBanners, cycling) between every pair of carousels
instead of stacking all carousels together with the banners fixed
elsewhere on the page — works for any number of dynamic carousels.
- SectionTitle's action button is a real link now (actionHref), not an
inert <button>. Each carousel's "مشاهده همه" goes to
/products?specialId={group.id}, which renders that exact
admin-curated group in the full product grid — store-specials groups
have no pagination, so this is genuinely the complete set, not a
truncated preview. Also fixed BlogCarousel's dead "وبلاگ" button the
same way, now linking to /blog.
- Reduced FeaturedCategories' vertical padding (py-10/14 -> py-4/6).
- Desktop header logo was smaller than the mobile one (36px vs 46px) —
bumped to 40/48px so it reads properly at desktop width.
- CONTEXT.md: document the banner-interleaving and specialId patterns.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Replace the two hardcoded homepage carousels (SpecialSaleCarousel
pinned to store-specials group 0 only, TopSellingCarousel reading
from an unrelated plain product query) with StoreSpecialCarousels:
loops over every group GET /store-specials returns, using each
group's own title. A new carousel created in the admin panel (e.g.
the "بهترینها از نگاه شما" one just added) shows up automatically,
no code change needed.
- Remove the brand-groups integration and its "سامسونگ" carousel
entirely (getBrandGroups, BrandGroupCarousels) — brand-name
carousels aren't wanted on this site per explicit instruction.
- SectionTitle's enTitle is now optional, since dynamic store-specials
groups only have one title string, not a Persian/English pair.
- Move featured categories above the hero-adjacent special carousels
per the requested homepage order; drop the "دستهبندیهای پرطرفدار"
heading and its "همه دستهها" button, per request.
- Wire the header/footer logo and the favicon to the real business
data (logoUrl/logoDarkUrl/faviconUrl from GET business-info) instead
of static files; removed src/app/favicon.ico, which was silently
winning over the new dynamic <link rel="icon">.
- CONTEXT.md: document the dynamic-carousel contract and the
logo/favicon wiring so neither regresses to hardcoded.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Per api.meshkee.com/docs/website/AI_PROMPT.md's hard rules (which an
earlier pass on this branch missed): login, register, OTP, the real
cart, addresses, and payment are the customer dashboard's job
(customer.sanihome.ir), not this storefront's. This site should only
ever run a local guest mini-cart and hand off to the dashboard.
- Remove: AuthContext, LoginModal, lib/auth.ts, lib/cart.ts (the real
/businesses/{id}/cart integration), and the /checkout page entirely.
- Add lib/guestCart.ts: localStorage + shared cookie
(meshkee-guest-cart, Domain=.sanihome.ir) cart, storeItemVariantId
keyed, matching the spec's line shape and ~3500-char cookie-size
cutoff.
- CartContext is now a thin React wrapper over the guest cart (no
server round-trip, so add/update/remove are synchronous); CartPopup's
"Continue" builds the exact customer.sanihome.ir/checkout/cart
(or /login?redirect=...) URL from the spec, base64url-encoding the
cart and detecting an existing dashboard session via the shared
meshkee_customer_access_token cookie.
- ProductCard and ProductPurchasePanel add to the guest cart directly;
no login gate on add-to-cart anymore.
- Comments panel is a plain guest name/email/text form again (the
comments API never required auth — gating it on the now-removed
login system was wrong regardless).
- CONTEXT.md rewritten to document the guest-cart contract explicitly
and flag this exact mistake so it doesn't get reintroduced.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Pulled in from the parallel auth/cart work on origin/main that this
branch is superseding — these two pieces are independent of the auth
architecture and worth keeping: Next.js standalone output for a leaner
production deploy, and the production env file (public URLs only, no
secrets) it and the app read from.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Real in-site login/register (password + SMS OTP) against Meshkee's
/auth API, with self-healing access-token refresh (15 min lifetime) and
an in-flight-refresh guard so AuthContext and CartContext don't race
each other into a failed concurrent refresh.
- Real cart: header cart button/badge, a cart popup, and a working
"add to cart" on both product cards (where a specific variant id is
known) and the product/store-item detail buy-box (always resolves a
purchasable variant, even for single-SKU products with no selectable
variation).
- /checkout: address + cash/bank-transfer payment, posts to the real
checkout API and creates an order; refreshes the cart afterward so the
header badge doesn't go stale.
- New /store-items and /store-items/[id] pages (variant-level browsing,
separate from the product-level /products catalog), cross-referencing
the parent product for images/description/technical-info.
- Product gallery: click-to-open fullscreen lightbox alongside the
existing hover-zoom.
- Comments tab wired to the real comments API, gated to logged-in users
(a product decision — the API itself doesn't require auth) with a
login prompt otherwise.
- Similar-products row on product/store-item detail pages.
- Contact page wired to the real contact-submissions API, with a toast
and inline confirmation on success, and the form resetting.
- CONTEXT.md: a maintained architecture/conventions doc for this repo,
now auto-loaded via CLAUDE.md, covering the Meshkee integration quirks
and UI conventions established across this project.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Resolve product cards from group endpoints (store-specials,
brand-groups) that only return a productId, not a slug, via a new
/products/id/[id] route backed by GET /products/by-id/{id} — clicking
these was previously falling back to a name search instead of the
detail page.
- Derive discount price/percent generically in normalizeProduct so any
source with real old/new prices shows it, even without an explicit
discount field from the API.
- Product cards and the detail page buy-box: show the discount badge
beside the old (struck-through) price, current price alone on its
own line, matching the reference design.
- Equalize product card heights within a carousel row (Swiper's own
CSS doesn't stretch slides to the tallest sibling in slidesPerView:
"auto" + freeMode mode) so the add-to-cart button lines up across
cards regardless of whether a card has a discount line.
- Featured categories: 110px images with no border/radius, matching
the site's other category card treatment.
- Replace Vazirmatn with the client's IRANYekan font files — light
weight for body text, bold weight for headings only.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add a featured-categories list slot (published via /meshkee/static-image-slots
alongside the existing banner slots) so the homepage category strip can be
driven by admin-uploaded images instead of the category API, which has no
image field. Falls back to the current category list whenever the slot has
no images configured or the fetch fails.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Product detail: interactive image gallery (thumbnails, prev/next,
hover-zoom), tabbed spec/review/comments section matching the site's
standard pattern, variations/options display, and an availability
label instead of duplicating the contact-store message.
- Fix product.images normalization — the API returns {url} media objects,
not plain strings, so galleries were silently rendering empty.
- Prefer the Persian name (nameFa/productNameFa) everywhere a product
name is shown.
- Product cards: padded, rounded images instead of edge-to-edge with a
dashed divider.
- Blog: wire the homepage carousel to real posts (was static sample
data), drop the detail page's separate cover image, and make images
embedded in article/description HTML fill their container with
rounded corners.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add /products (list + detail) and /blog (list + detail) routes backed by
the real Meshkee API, a real category-hierarchy mega menu (level 2/3 only),
debounced instant search proxied through a same-origin API route, and
tel:-link fallbacks on product cards when no price is set. Also fixes
Product price normalization to read the real API shape instead of a
guessed one, and hardens product linking against catalog sources that
don't expose a slug.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Kept the local branch's homepage implementation (Meshkee product/category
API integration, redesigned header, Swiper carousels, hardcoded local
slider/banner images) as the source of truth for all conflicting sections,
since it reflects the most recent explicit direction.
Folded in the remote's non-conflicting additions: the static-image-slot
types/helpers in lib/meshkee.ts, the SlotImage component, and the
/meshkee/static-image-slots catalog route. These aren't wired into any
page yet since the live API's slot key ("home-hero") doesn't match the
keys this code expects ("slider", etc.) — worth reconciling once that's
settled.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>