From 11656c29962723e52d33e9c6b0effb23623174b4 Mon Sep 17 00:00:00 2001 From: Arda Samadi Date: Sat, 27 Jun 2026 16:38:44 +0330 Subject: [PATCH] feat(home): seller brand chip (logo + name) on product tiles Show the seller's brand on the home product cards, like the design: a small logo circle + name overlaid above the title. - new SellerChip component: renders nothing without a name; falls back to the seller's initial when no logo is present (e.g. before the backend ships seller_logo). seller_name is already returned today, so the name shows immediately. - thread sellerName/sellerLogo/sellerUsername through ProductHomepage type, the home discounts + for-you mappings, and the MondrianProductList / HorizontalProductList card interfaces + overlays. Only renders where seller data is mapped (home), so seller-page and store-dashboard tiles are unaffected. Co-Authored-By: Claude Opus 4.8 --- app/components/HorizontalProductList.tsx | 8 ++++++ app/components/MondrianProductList.tsx | 5 ++++ app/components/SellerChip.tsx | 32 ++++++++++++++++++++++++ app/routes/_index.tsx | 6 +++++ src/api/types/models/index.ts | 12 +++++++++ 5 files changed, 63 insertions(+) create mode 100644 app/components/SellerChip.tsx diff --git a/app/components/HorizontalProductList.tsx b/app/components/HorizontalProductList.tsx index 58cd66a..66622d4 100644 --- a/app/components/HorizontalProductList.tsx +++ b/app/components/HorizontalProductList.tsx @@ -6,6 +6,7 @@ import { Skeleton } from "./ui/skeleton"; import { ErrorState } from "./UiProvider"; import discountRed from "~/assets/icons/product/discount-red.svg"; import placeholderImage from "~/assets/icons/product.png"; +import SellerChip from "./SellerChip"; interface HorizontalProduct { id?: string; @@ -14,6 +15,9 @@ interface HorizontalProduct { discountPercent?: number; discountPrice?: number; basePrice?: number; + sellerName?: string; + sellerLogo?: string | null; + sellerUsername?: string; } const HorizontalProductList = ({ @@ -138,6 +142,10 @@ const HorizontalProductList = ({ )} {/* Overlay info */}
+
{/* Title */}

diff --git a/app/components/MondrianProductList.tsx b/app/components/MondrianProductList.tsx index c5ada16..07d243a 100644 --- a/app/components/MondrianProductList.tsx +++ b/app/components/MondrianProductList.tsx @@ -11,6 +11,7 @@ import placeholderImage from "~/assets/icons/product.png"; import placeholderImageDark from "~/assets/icons/product-dark.png"; import { useRootData } from "~/hooks/use-root-data"; import discountRed from "~/assets/icons/product/discount-red.svg"; +import SellerChip from "./SellerChip"; interface MondrianList { id?: string; @@ -21,6 +22,9 @@ interface MondrianList { discountPercent?: number; discountPrice?: number; basePrice?: number; + sellerName?: string; + sellerLogo?: string | null; + sellerUsername?: string; } // Utility function to detect media type @@ -400,6 +404,7 @@ const ProductCard = ({ )} {/* Overlay info - Airbnb style */}
+
{/* Title */}

diff --git a/app/components/SellerChip.tsx b/app/components/SellerChip.tsx new file mode 100644 index 0000000..edd9c17 --- /dev/null +++ b/app/components/SellerChip.tsx @@ -0,0 +1,32 @@ +interface SellerChipProps { + name?: string; + logo?: string | null; +} + +/** + * Small brand chip (logo + name) shown over a product card's image overlay. + * Renders nothing when there's no seller name. Falls back to the seller's + * initial when no logo is available (e.g. before the backend exposes it). + */ +export default function SellerChip({ name, logo }: SellerChipProps) { + if (!name) return null; + return ( +
+ + {logo ? ( + { + e.currentTarget.style.display = "none"; + }} + /> + ) : ( + name.trim().charAt(0) + )} + + {name} +
+ ); +} diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index 3ae73a7..05eae74 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -151,6 +151,9 @@ export default function HomePage() { discountPercent: product?.discountPercent || 0, discountPrice: product?.discountPrice || 0, basePrice: product?.basePrice || 0, + sellerName: product?.sellerName, + sellerLogo: product?.sellerLogo, + sellerUsername: product?.sellerUsername, })) || [] } isLoading={isLoadingDiscounts} @@ -235,6 +238,9 @@ export default function HomePage() { discountPercent: product?.discountPercent || 0, discountPrice: product?.discountPrice || 0, basePrice: product?.basePrice || 0, + sellerName: product?.sellerName, + sellerLogo: product?.sellerLogo, + sellerUsername: product?.sellerUsername, })) || [] } fetchNextPage={fetchNextForYou} diff --git a/src/api/types/models/index.ts b/src/api/types/models/index.ts index 7406c12..220b9c1 100644 --- a/src/api/types/models/index.ts +++ b/src/api/types/models/index.ts @@ -3813,6 +3813,18 @@ export interface ProductHomepage { * @memberof ProductHomepage */ readonly sellerName?: string; + /** + * + * @type {string} + * @memberof ProductHomepage + */ + readonly sellerUsername?: string; + /** + * + * @type {string} + * @memberof ProductHomepage + */ + readonly sellerLogo?: string | null; } /** *