admin user and ui panel

This commit is contained in:
s.esmaeili
2026-09-21 08:32:31 +03:30
parent 79226c9f13
commit ef1d4638cc
341 changed files with 2270 additions and 657 deletions
+26 -1
View File
@@ -14,6 +14,13 @@ async function request<T>(path: string, options?: RequestInit): Promise<T> {
return res.json();
}
export interface ProductImageSummary {
id: string;
url: string;
sortOrder: number;
role: 'FEATURED' | 'FEATURED_MOBILE' | 'GALLERY' | 'GALLERY_MOBILE';
}
export interface ProductVariantSummary {
id: string;
title: string;
@@ -25,6 +32,12 @@ export interface ProductVariantSummary {
/// can read them.
qty?: number;
isPreOrder?: boolean;
/// The gallery image chosen for this variant in the admin panel. It is one of
/// the product's OWN images — the same ProductImage row, not a copy — so
/// several variants (e.g. different weights of one design) may share it.
/// Null when no picture was picked; callers fall back to the product image.
imageId?: string | null;
image?: ProductImageSummary | null;
}
export interface CategorySummary {
@@ -53,7 +66,9 @@ export interface ProductSummary {
/// GET /catalog/products.
productCode?: string | null;
variants: ProductVariantSummary[];
images: Array<{ url: string }>;
/// Returned sorted by sortOrder, so images[0] really is the product's main
/// photo rather than whichever row the database happened to hand back.
images: ProductImageSummary[];
category: CategorySummary | null;
brand: BrandSummary | null;
collections: Array<{ collectionId: string; collection: CollectionSummary }>;
@@ -132,6 +147,13 @@ export interface GoldPriceQuote {
quotedAt: string;
}
/** One admin-uploaded home banner slide — raw shape as saved by the admin
* panel's manage/Const.vue "اسلایدر موبایل" tab (image + optional link). */
export interface AdminSlide {
image: string;
link: string;
}
export const api = {
listProducts: () => request<ProductSummary[]>('/catalog/products'),
listCustomers: () => request<CustomerSummary[]>('/customers'),
@@ -141,4 +163,7 @@ export const api = {
createOrder: (dto: CreateOrderDto) => request<OrderSummary>('/orders', { method: 'POST', body: JSON.stringify(dto) }),
getCustomerOrders: (customerId: string) => request<OrderDetail[]>(`/customers/${customerId}/orders`),
getLatestGoldPrice: (karatPerMille = 750) => request<GoldPriceQuote>(`/pricing/latest?karatPerMille=${karatPerMille}`),
/** GET /home/slider — public, no auth. Empty array when the admin hasn't
* configured any slides (the caller falls back to a derived hero). */
getHomeSlider: () => request<AdminSlide[]>('/home/slider'),
};