@@ -360,6 +364,7 @@ export function Header({
open={drawerOpen}
onClose={() => setDrawerOpen(false)}
categoryTree={categoryTree}
+ logoUrl={logoUrl}
/>
);
diff --git a/src/components/home/SpecialSaleCarousel.tsx b/src/components/home/SpecialSaleCarousel.tsx
deleted file mode 100644
index 66ff990..0000000
--- a/src/components/home/SpecialSaleCarousel.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import { Carousel } from "@/components/ui/Carousel";
-import { Placeholder } from "@/components/ui/Placeholder";
-import { ProductCard } from "@/components/ui/ProductCard";
-import { SectionTitle } from "@/components/ui/SectionTitle";
-import { EmptyState } from "@/components/ui/EmptyState";
-import { productHref, type Product } from "@/lib/meshkee";
-
-function SpecialSaleBanner() {
- return (
-
-
-
- );
-}
-
-export function SpecialSaleCarousel({
- products,
- contactPhone,
-}: {
- products: Product[];
- contactPhone?: string;
-}) {
- return (
-
-
-
- {products.length === 0 ? (
-
- ) : (
-
-
- {products.map((product) => (
-
- ))}
-
- )}
-
-
- );
-}
diff --git a/src/components/home/BrandGroupCarousels.tsx b/src/components/home/StoreSpecialCarousels.tsx
similarity index 63%
rename from src/components/home/BrandGroupCarousels.tsx
rename to src/components/home/StoreSpecialCarousels.tsx
index 6174403..717fc3d 100644
--- a/src/components/home/BrandGroupCarousels.tsx
+++ b/src/components/home/StoreSpecialCarousels.tsx
@@ -1,33 +1,29 @@
import { Carousel } from "@/components/ui/Carousel";
import { ProductCard } from "@/components/ui/ProductCard";
import { SectionTitle } from "@/components/ui/SectionTitle";
-import { EmptyState } from "@/components/ui/EmptyState";
import { productHref, type ProductGroup } from "@/lib/meshkee";
-export function BrandGroupCarousels({
- brandGroups,
+// Renders every admin-managed carousel from GET /store-specials — whatever
+// groups exist there, in their configured order. Nothing here is keyed off
+// a specific group id/key/title, so a new carousel created in the Meshkee
+// dashboard (any name) shows up on the homepage automatically, with no code
+// change. Groups with no items are skipped (honest empty state — no heading
+// over nothing).
+export function StoreSpecialCarousels({
+ groups,
contactPhone,
}: {
- brandGroups: ProductGroup[];
+ groups: ProductGroup[];
contactPhone?: string;
}) {
- if (brandGroups.length === 0) {
- return (
-
- );
- }
+ const visibleGroups = groups.filter((group) => group.items.length > 0);
return (
<>
- {brandGroups.map((group) => (
+ {visibleGroups.map((group) => (
-
+
{group.items.map((product) => (
-
-
- {products.length === 0 ? (
-
- ) : (
-
- {products.map((product) => (
-
- ))}
-
- )}
-
-
- );
-}
diff --git a/src/components/ui/SectionTitle.tsx b/src/components/ui/SectionTitle.tsx
index 12047d2..4339b4f 100644
--- a/src/components/ui/SectionTitle.tsx
+++ b/src/components/ui/SectionTitle.tsx
@@ -1,6 +1,6 @@
type SectionTitleProps = {
title: string;
- enTitle: string;
+ enTitle?: string;
subtitle?: string;
action?: string;
};
@@ -11,13 +11,15 @@ export function SectionTitle({ title, enTitle, subtitle, action }: SectionTitleP
{title}
-
- {enTitle}
-
+ {enTitle && (
+
+ {enTitle}
+
+ )}
{subtitle && (
{subtitle}
diff --git a/src/lib/meshkee.ts b/src/lib/meshkee.ts
index 37b1847..e3b7ca9 100644
--- a/src/lib/meshkee.ts
+++ b/src/lib/meshkee.ts
@@ -51,6 +51,7 @@ export type BusinessInfo = {
about: string;
vision: string;
logoUrl: string | null;
+ logoDarkUrl: string | null;
faviconUrl: string | null;
emails: string[];
phoneNumbers: string[];
@@ -490,27 +491,28 @@ export type ProductGroup = {
id: string;
key: string;
title: string;
+ sortOrder: number;
items: Product[];
};
function normalizeProductGroups(items: Record
[] | undefined): ProductGroup[] {
- return (items ?? []).map((group) => ({
- id: String(group.id ?? group.key ?? ""),
- key: String(group.key ?? group.id ?? ""),
- title: String(group.title ?? ""),
- items: Array.isArray(group.items)
- ? (group.items as Record[]).map(normalizeProduct)
- : [],
- }));
-}
-
-export async function getBrandGroups(): Promise {
- const res = await apiGet<{ items: Record[] }>(
- `/tenants/${DOMAIN}/website/brand-groups`,
- );
- return normalizeProductGroups(res?.items);
+ return (items ?? [])
+ .map((group) => ({
+ id: String(group.id ?? group.key ?? ""),
+ key: String(group.key ?? group.id ?? ""),
+ title: String(group.title ?? ""),
+ sortOrder: Number(group.sortOrder ?? 0),
+ items: Array.isArray(group.items)
+ ? (group.items as Record[]).map(normalizeProduct)
+ : [],
+ }))
+ .sort((a, b) => a.sortOrder - b.sortOrder);
}
+// Admin-managed, named product carousels ("Special Sale", "پرفروشها",
+// "بهترینها از نگاه شما", ...) — the whole list, not a fixed set of known
+// keys, so a new one created in the dashboard shows up on the homepage
+// automatically. See StoreSpecialCarousels.tsx.
export async function getStoreSpecials(): Promise {
const res = await apiGet<{ items: Record[] }>(
`/tenants/${DOMAIN}/store-specials`,