/** * Shared API types, mirrored from winofyapifrontendintegrationguide.md + the * OpenAPI spec (source of truth for field names/shapes). Money fields are * integer Toman. Grouped to match src/lib/api/'s feature layout. * * Media fields (`icon`, `image`, `logo`, `cover_image`) are MinIO object keys, * not URLs — every one 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. */ // ---- Locations -------------------------------------------------------------- export interface City { uuid: string; name: string; slug?: string; } export interface Neighborhood { uuid: string; name: string; slug?: string; /** Nested object, confirmed against staging — not a bare uuid string. */ city: City; } // ---- Stores / Catalog --------------------------------------------------- export interface StoreCategory { uuid: string; name: string; icon: string | null; icon_url: string | null; order: number; } export interface StoreListItem { uuid: string; 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; min_order_amount: number; delivery_fee: number; free_delivery_threshold: number | null; is_open: boolean; } export interface WorkingHours { weekday: 0 | 1 | 2 | 3 | 4 | 5 | 6; // 0 = Saturday .. 6 = Friday opens_at: string | null; closes_at: string | null; is_closed: boolean; } export interface StoreDetail extends StoreListItem { description: string; address: string; phone_number: string; working_hours: WorkingHours[]; accepts_wallet: boolean; accepts_online: boolean; accepts_cash_on_delivery: boolean; } export type UnitType = "gram" | "ml" | "piece"; export interface ProductCategory { uuid: string; name: string; icon: string | null; icon_url: string | null; parent: string | null; } export interface ProductListItem { uuid: string; name: string; image: string | null; image_url: string | null; price: number; unit_type: UnitType; unit_value: number; is_active: boolean; is_out_of_stock: boolean; } export interface ProductDetail extends ProductListItem { description: string; category: ProductCategory; store: StoreListItem; } // ---- Addresses ---------------------------------------------------------- export type AddressLabel = "home" | "work" | "other"; export interface Address { uuid: string; label: AddressLabel; title: string; full_address: string; plaque: string; floor: string; unit: string; recipient_name: string; recipient_phone: string; city: City; neighborhood: Neighborhood | null; latitude: number; longitude: number; is_default: boolean; created_at: string; } // ---- Cart ----------------------------------------------------------------- export interface CartItem { uuid: string; product: ProductListItem; quantity: number; line_total: number; } export interface CartGroup { store: StoreListItem; items: CartItem[]; items_subtotal: number; delivery_fee: number; total: number; meets_minimum_order: boolean; } export interface Cart { groups: CartGroup[]; grand_total: number; } // ---- Checkout / Orders --------------------------------------------------- export type DeliveryType = "express" | "scheduled"; export type PaymentMethod = "wallet" | "online" | "cash_on_delivery"; export type PaymentStatus = "pending" | "paid" | "failed"; export type OrderStatus = "placed" | "preparing" | "ready_to_ship" | "handed_to_courier" | "delivered" | "cancelled"; export interface OrderItem { uuid: string; product: string | null; product_name_snapshot: string; unit_price_snapshot: number; quantity: number; line_total: number; } export interface OrderStatusLog { from_status: string; to_status: string; note: string; created_at: string; } export interface Order { uuid: string; store: StoreListItem; status: OrderStatus; items: OrderItem[]; items_subtotal: number; delivery_fee: number; commission_amount: number; seller_payout_amount: number; total_amount: number; cancel_reason: string; courier_name: string; courier_phone: string; placed_at: string; delivered_at: string | null; status_logs: OrderStatusLog[]; is_cancellable: boolean; } export interface OrderGroup { uuid: string; recipient_name: string; recipient_phone: string; full_address: string; delivery_type: DeliveryType; scheduled_at: string | null; payment_method: PaymentMethod; payment_status: PaymentStatus; notes: string; total_amount: number; orders: Order[]; created_at: string; /** `feature/payment` only. */ payment?: { method: PaymentMethod; status: string; payment_url?: string }; } // ---- Reviews -------------------------------------------------------------- export interface Review { uuid: string; store: string; product: string | null; rating: number; comment: string; seller_reply: string | null; customer_name: string; created_at: string; } // ---- Notifications -------------------------------------------------------- export type NotificationType = "new_order" | "settlement_done" | "new_review" | "order_cancelled"; export interface Notification { uuid: string; type: NotificationType; title: string; body: string; related_order: string | null; is_read: boolean; created_at: string; } // ---- Seller · Store --------------------------------------------------- export type SellerStoreStatus = "pending" | "approved" | "suspended"; export interface StoreBankAccount { iban: string; account_holder_name: string; } export interface SellerStore { uuid: string; name: string; category: StoreCategory; description: string; logo: string | null; logo_url: string | null; cover_image: string | null; cover_image_url: string | null; phone_number: string; city: City; address: string; service_neighborhoods: Neighborhood[]; /** DRF decimal-as-string, e.g. "5.00". */ delivery_radius_km: string; min_order_amount: number; delivery_fee: number; free_delivery_threshold: number | null; accepts_wallet: boolean; accepts_online: boolean; accepts_cash_on_delivery: boolean; rating_avg: string; rating_count: number; status: SellerStoreStatus; is_open: boolean; bank_account: StoreBankAccount | null; created_at: string; } // ---- Seller · Products --------------------------------------------------- export interface SellerProduct { uuid: string; name: string; description: string; image: string | null; image_url: string | null; category: ProductCategory; price: number; unit_type: UnitType; unit_value: number; stock_quantity: number; low_stock_threshold: number; is_active: boolean; sold_count: number; is_out_of_stock: boolean; is_low_stock: boolean; created_at: string; } // ---- Seller · Analytics --------------------------------------------------- export interface SalesChartPoint { bucket: string; sales: number; } export interface TopProduct { name: string; units_sold: number; revenue: number; } export interface SellerAnalytics { period: string; order_count: number; total_sales: number; cancellation_rate: number; average_order_value: number; chart: SalesChartPoint[]; top_products: TopProduct[]; }