winofy-front/src/types/api.ts
Afra ‌ 3609c97e34 feat: guest-home/C04 shell, location onboarding (L01/L04/L06), profile placeholder
Implements winofyfrontenddoc (1).md §3-4: unified guest-home/authenticated-home
screen (header with login chip vs cart badge, pill search bar, dismissible
location-reminder banner, category chips, store cards, interleaved seller
promo card, sticky bottom nav), plus the full post-OTP location-onboarding
sub-flow (geolocation permission -> error/retry -> manual neighborhood
search, unified idle/results/empty states per the doc's own recommendation).

Location state persists in a plain (non-httpOnly) cookie readable both
client- and server-side, since it drives SSR store queries (neighborhood
or lat/lng) as well as client interactions.

Moved cart/checkout/store/product/orders/addresses under a new (shop) route
group so the new home-shell header doesn't double up with the existing
simple nav header on inner pages.

Real bug caught via live staging data: Neighborhood.city is a nested
{uuid, name, slug} object, not a bare uuid string as typed -- broke both
the address form's city filter and the new neighborhood search. Fixed and
verified against real API responses, not just assumed from the guide.
2026-08-17 17:24:27 +03:30

183 lines
3.9 KiB
TypeScript

/** Shared API types mirrored from FRONTEND_GUIDE.md. Money fields are integer Toman. */
export interface City {
uuid: string;
name: string;
slug?: string;
}
export interface Neighborhood {
uuid: string;
name: string;
/** Nested object, confirmed against staging — not a bare uuid string. */
city: City;
}
export interface StoreCategory {
uuid: string;
name: string;
icon: string | null;
order: number;
}
export interface StoreListItem {
uuid: string;
name: string;
category: StoreCategory;
logo: string | null;
cover_image: 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;
closes_at: string;
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;
parent: string | null;
}
export interface ProductListItem {
uuid: string;
name: string;
image: 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;
}
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;
}
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;
}
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;
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 };
}