- {product.image && (
+ {product.image_url && (
// eslint-disable-next-line @next/next/no-img-element
diff --git a/src/components/customer/cart-item-row.tsx b/src/components/customer/cart-item-row.tsx
index aaf8c10..87fb5fd 100644
--- a/src/components/customer/cart-item-row.tsx
+++ b/src/components/customer/cart-item-row.tsx
@@ -3,7 +3,6 @@
import { useTransition } from "react";
import { useRouter } from "next/navigation";
import { updateCartItemQuantity, removeCartItem } from "@/lib/actions/cart";
-import { resolveClientMediaUrl } from "@/lib/api/media-client";
import type { CartItem } from "@/types/api";
export function CartItemRow({ item }: { item: CartItem }) {
@@ -24,9 +23,9 @@ export function CartItemRow({ item }: { item: CartItem }) {
return (
- {item.product.image && (
+ {item.product.image_url && (
// eslint-disable-next-line @next/next/no-img-element
-
+
)}
diff --git a/src/components/home/site-header.tsx b/src/components/home/site-header.tsx
index e837de3..acf7761 100644
--- a/src/components/home/site-header.tsx
+++ b/src/components/home/site-header.tsx
@@ -14,9 +14,9 @@ export function SiteHeader({
return (
-
- {locationLabel ?? "انتخاب محله"}
+ {locationLabel ?? "انتخاب محله"}
+
{isAuthenticated ? (
diff --git a/src/components/home/store-card.tsx b/src/components/home/store-card.tsx
index eda3c66..bbc42c0 100644
--- a/src/components/home/store-card.tsx
+++ b/src/components/home/store-card.tsx
@@ -1,5 +1,4 @@
import Link from "next/link";
-import { resolveMediaUrl } from "@/lib/api/media";
import type { StoreListItem } from "@/types/api";
/** winofyfrontenddoc (1).md §3.5 store-card. */
@@ -10,9 +9,9 @@ export function StoreCard({ store }: { store: StoreListItem }) {
className="flex items-center gap-3 rounded-xl border border-gray-300 bg-white p-3 shadow-sm"
>
- {store.logo && (
+ {store.logo_url && (
// eslint-disable-next-line @next/next/no-img-element
-
+
)}
diff --git a/src/lib/api/media-client.ts b/src/lib/api/media-client.ts
deleted file mode 100644
index 3a1361e..0000000
--- a/src/lib/api/media-client.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-const MEDIA_ORIGIN = process.env.NEXT_PUBLIC_WINOFY_MEDIA_ORIGIN!;
-
-/** Client-safe counterpart to lib/api/media.ts's resolveMediaUrl. */
-export function resolveClientMediaUrl(path: string | null): string | null {
- if (!path) return null;
- if (path.startsWith("http://") || path.startsWith("https://")) return path;
- return MEDIA_ORIGIN + (path.startsWith("/") ? path : `/${path}`);
-}
diff --git a/src/lib/api/media.ts b/src/lib/api/media.ts
deleted file mode 100644
index 8bcbeff..0000000
--- a/src/lib/api/media.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import "server-only";
-
-const API_ORIGIN = new URL(process.env.WINOFY_API_BASE_URL!).origin;
-
-/** Store/product image fields are `null` or an absolute/relative media URL — see FRONTEND_GUIDE.md §4.5. */
-export function resolveMediaUrl(path: string | null): string | null {
- if (!path) return null;
- if (path.startsWith("http://") || path.startsWith("https://")) return path;
- return API_ORIGIN + (path.startsWith("/") ? path : `/${path}`);
-}
diff --git a/src/types/api.ts b/src/types/api.ts
index bc92b32..fc80d4d 100644
--- a/src/types/api.ts
+++ b/src/types/api.ts
@@ -1,4 +1,12 @@
-/** Shared API types mirrored from FRONTEND_GUIDE.md. Money fields are integer Toman. */
+/**
+ * Shared API types mirrored from FRONTEND_GUIDE.md. Money fields are integer Toman.
+ *
+ * Media fields (`icon`, `image`, `logo`, `cover_image`) are MinIO object keys, not
+ * URLs — per FRONTEND_GUIDE.md §4.7 (feature/minio-integration), every one of them
+ * has a `_url` sibling that's a freshly presigned, already-absolute URL.
+ * Always render the `_url` field directly; never resolve the raw key yourself, and
+ * don't cache `_url` past the response — it's re-signed (and can change) on every read.
+ */
export interface City {
uuid: string;
@@ -17,6 +25,7 @@ export interface StoreCategory {
uuid: string;
name: string;
icon: string | null;
+ icon_url: string | null;
order: number;
}
@@ -25,7 +34,9 @@ export interface StoreListItem {
name: string;
category: StoreCategory;
logo: string | null;
+ logo_url: string | null;
cover_image: string | null;
+ cover_image_url: string | null;
/** DRF serializes DecimalField as a string, e.g. "3.76" — confirmed against staging. */
rating_avg: string;
rating_count: number;
@@ -58,6 +69,8 @@ export type UnitType = "gram" | "ml" | "piece";
export interface ProductCategory {
uuid: string;
name: string;
+ icon: string | null;
+ icon_url: string | null;
parent: string | null;
}
@@ -65,6 +78,7 @@ export interface ProductListItem {
uuid: string;
name: string;
image: string | null;
+ image_url: string | null;
price: number;
unit_type: UnitType;
unit_value: number;