312 lines
7.5 KiB
TypeScript
312 lines
7.5 KiB
TypeScript
/**
|
|
* 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 `<field>_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[];
|
|
}
|