281 lines
5.4 KiB
TypeScript
281 lines
5.4 KiB
TypeScript
export interface Scent {
|
|
id: number
|
|
name: string
|
|
description?: string | null
|
|
}
|
|
|
|
export interface Category {
|
|
id: number
|
|
name: string
|
|
imageUrl?: string | null
|
|
_count?: { products: number }
|
|
createdAt?: string
|
|
updatedAt?: string
|
|
}
|
|
|
|
export interface Variant {
|
|
id: number
|
|
size: string
|
|
price: number | null
|
|
bomItems?: BomItem[]
|
|
}
|
|
|
|
export interface RawMaterial {
|
|
id: number
|
|
name: string
|
|
unit: string
|
|
pricePerUnit: number
|
|
}
|
|
|
|
export interface BomItem {
|
|
id?: number
|
|
rawMaterialId: number
|
|
rawMaterial?: RawMaterial
|
|
quantity: number
|
|
}
|
|
|
|
export interface ProductImage {
|
|
id: number
|
|
url: string
|
|
order: number
|
|
}
|
|
|
|
export interface Product {
|
|
id: number
|
|
name: string
|
|
description: string | null
|
|
details: string | null
|
|
price: number | null
|
|
categoryId: number
|
|
category: Category
|
|
scent: Scent
|
|
variants: Variant[]
|
|
images: ProductImage[]
|
|
}
|
|
|
|
export const API_BASE = (typeof import.meta !== 'undefined' && (import.meta as any).env?.VITE_API_URL)
|
|
|| ((globalThis as any).process?.env?.VITE_API_URL)
|
|
|| 'http://localhost:3000/api'
|
|
|
|
export const CATEGORY_IMAGES: Record<string, string> = {
|
|
'Oil Ozone': '/images/oil_ozone.png',
|
|
'Aroma Oil': '/images/oil_ozone.png',
|
|
'Reed Diffuser': '/images/reed_diffuser.png',
|
|
'Room Spray': '/images/reed_diffuser.png',
|
|
'Car Diffuser': '/images/oil_ozone.png',
|
|
}
|
|
|
|
export function getCategoryImage(name: string): string {
|
|
return CATEGORY_IMAGES[name] ?? '/images/oil_ozone.png'
|
|
}
|
|
|
|
export function formatPrice(price: number | null | undefined): string {
|
|
if (price == null) return '—'
|
|
return `฿${price.toLocaleString()}`
|
|
}
|
|
|
|
export interface Hero {
|
|
id: number
|
|
tagline: string
|
|
title: string
|
|
description: string
|
|
imageUrl: string
|
|
buttonText: string
|
|
buttonLink: string
|
|
isActive: boolean
|
|
createdAt: string
|
|
updatedAt: string
|
|
}
|
|
|
|
export interface StoreSettings {
|
|
id: number
|
|
shippingFee: number
|
|
bankName: string
|
|
bankAccountName: string
|
|
bankAccountNumber: string
|
|
pointsEarnRate: number
|
|
}
|
|
|
|
export interface OrderItem {
|
|
id: number
|
|
orderId: number
|
|
productId: number
|
|
variantId?: number | null
|
|
quantity: number
|
|
priceAtPurchase: number
|
|
productName: string
|
|
variantSize?: string | null
|
|
productImage?: string | null
|
|
}
|
|
|
|
export interface Order {
|
|
id: number
|
|
customerName: string
|
|
customerEmail: string
|
|
customerPhone: string
|
|
shippingAddress: string
|
|
|
|
subtotal?: number
|
|
promoLevel1Name?: string | null
|
|
promoLevel1Disc?: number
|
|
promoLevel2Name?: string | null
|
|
promoLevel2Disc?: number
|
|
|
|
couponCode?: string | null
|
|
discountAmount?: number
|
|
|
|
pointsUsed?: number
|
|
pointsDiscount?: number
|
|
pointsEarned?: number
|
|
|
|
totalAmount: number
|
|
shippingFee: number
|
|
status: string
|
|
paymentSlipUrl?: string | null
|
|
trackingNo?: string | null
|
|
customerId?: number | null
|
|
customer?: any | null
|
|
items: OrderItem[]
|
|
createdAt: string
|
|
updatedAt: string
|
|
}
|
|
|
|
export interface Article {
|
|
id: number
|
|
slug: string
|
|
title: string
|
|
coverImage: string | null
|
|
content: string
|
|
isPublished: boolean
|
|
createdAt: string
|
|
updatedAt: string
|
|
}
|
|
|
|
export interface CartItem {
|
|
cartItemId: string
|
|
productId: number
|
|
variantId?: number | null
|
|
quantity: number
|
|
price: number
|
|
productName: string
|
|
variantSize?: string | null
|
|
productImage?: string | null
|
|
}
|
|
|
|
export interface Page {
|
|
id: number
|
|
slug: string
|
|
title: string
|
|
isPublished: boolean
|
|
sections?: PageSection[]
|
|
createdAt?: string
|
|
updatedAt?: string
|
|
}
|
|
|
|
export interface PageSection {
|
|
id: number
|
|
pageId: number
|
|
type: string // e.g. 'HERO' | 'CATEGORIES' | 'PRODUCTS' | 'BANNER' | 'TEXT'
|
|
order: number
|
|
payload: any // Specific payload depending on type
|
|
isActive: boolean
|
|
createdAt?: string
|
|
updatedAt?: string
|
|
}
|
|
|
|
export interface HeroSectionPayload {
|
|
tagline: string
|
|
title: string
|
|
description: string
|
|
imageUrl: string
|
|
buttonText: string
|
|
buttonLink: string
|
|
}
|
|
|
|
export interface CategoriesSectionPayload {
|
|
title: string
|
|
subtitle?: string
|
|
categoryIds?: number[]
|
|
}
|
|
|
|
export interface ProductsSectionPayload {
|
|
title: string
|
|
subtitle?: string
|
|
type: 'featured' | 'scent' | 'custom'
|
|
scentId?: number
|
|
productIds?: number[]
|
|
limit?: number
|
|
layout?: 'grid' | 'carousel'
|
|
enableQuickShop?: boolean
|
|
}
|
|
|
|
export interface BannerSectionPayload {
|
|
imageUrl: string
|
|
linkUrl?: string
|
|
title?: string
|
|
description?: string
|
|
buttonText?: string
|
|
}
|
|
|
|
export interface TextSectionPayload {
|
|
title?: string
|
|
content: string
|
|
textAlign?: 'left' | 'center' | 'right'
|
|
}
|
|
|
|
export interface AnnouncementBarSectionPayload {
|
|
slides: string[]
|
|
backgroundColor?: string
|
|
textColor?: string
|
|
speed?: number
|
|
}
|
|
|
|
export interface NewsletterSectionPayload {
|
|
title: string
|
|
description: string
|
|
buttonText: string
|
|
placeholderText?: string
|
|
showPrivacyCheckbox: boolean
|
|
privacyText?: string;
|
|
}
|
|
|
|
export interface EditorialTileSectionPayload {
|
|
title: string
|
|
description: string
|
|
imageUrl: string
|
|
imagePosition: 'left' | 'right'
|
|
buttonText?: string
|
|
buttonLink?: string
|
|
backgroundColor?: string
|
|
textColor?: string
|
|
}
|
|
|
|
export interface EditorialCarouselSectionPayload {
|
|
title: string
|
|
slides: {
|
|
category: string
|
|
title: string
|
|
description: string
|
|
imageUrl: string
|
|
buttonText?: string
|
|
buttonLink?: string
|
|
}[]
|
|
}
|
|
|
|
export interface CustomerAddress {
|
|
id: number
|
|
customerId: number
|
|
recipientName: string
|
|
phone: string
|
|
addressLine: string
|
|
subdistrict: string
|
|
district: string
|
|
province: string
|
|
zipcode: string
|
|
isDefault: boolean
|
|
createdAt?: string
|
|
updatedAt?: string
|
|
}
|
|
|
|
|