import { defineStore } from 'pinia'; import type { Product } from '~~/types/product'; export interface CartItem { product: Product; quantity: number; } export type CouponType = 'percent' | 'fixed'; export interface CartCoupon { code: string; type: CouponType; value: number; description?: string; minSubtotal?: number; } interface CartState { items: CartItem[]; coupon: CartCoupon | null; } const CART_STORAGE_KEY = 'nuxt-shop-cart-v1'; const AVAILABLE_COUPONS: CartCoupon[] = [ { code: 'SALE10', type: 'percent', value: 10, description: '10% indirim', }, { code: 'WELCOME50', type: 'fixed', value: 50, description: '50 TL indirim', minSubtotal: 300, }, ]; export const useCartStore = defineStore('cart', { state: (): CartState => ({ items: [], coupon: null, }), getters: { totalQuantity: (state): number => state.items.reduce((total, item) => total + item.quantity, 0), subtotal: (state): number => state.items.reduce( (total, item) => total + item.product.price * item.quantity, 0 ), discountAmount(): number { if (!this.coupon) return 0; if (this.coupon.minSubtotal && this.subtotal < this.coupon.minSubtotal) { return 0; } const rawDiscount = this.coupon.type === 'percent' ? (this.subtotal * this.coupon.value) / 100 : this.coupon.value; return Math.min(rawDiscount, this.subtotal); }, total(): number { return Math.max(this.subtotal - this.discountAmount, 0); }, totalPrice(): number { return this.total; }, getItem: (state) => (slug: string): CartItem | undefined => state.items.find((item) => item.product.slug === slug), }, actions: { addItem(product: Product, quantity = 1): void { if (!Number.isFinite(quantity) || quantity <= 0) { return; } const existingItem = this.items.find( (item) => item.product.slug === product.slug ); if (existingItem) { existingItem.quantity += quantity; existingItem.product = product; return; } this.items.push({ product, quantity }); }, setItemQuantity(slug: string, quantity: number): void { if (!Number.isFinite(quantity)) { return; } const item = this.items.find((entry) => entry.product.slug === slug); if (!item) { return; } if (quantity <= 0) { this.items = this.items.filter( (entry) => entry.product.slug !== slug ); return; } item.quantity = Math.floor(quantity); }, removeItem(slug: string): void { this.items = this.items.filter( (item) => item.product.slug !== slug ); }, clearCart(): void { this.items = []; this.coupon = null; }, setItems(items: CartItem[]): void { this.items = items; }, applyCouponCode(code: string): boolean { const normalizedCode = code.trim().toUpperCase(); if (!normalizedCode) return false; const coupon = AVAILABLE_COUPONS.find( (entry) => entry.code === normalizedCode ); if (!coupon) return false; if (coupon.minSubtotal && this.subtotal < coupon.minSubtotal) { return false; } this.coupon = coupon; return true; }, clearCoupon(): void { this.coupon = null; }, setCoupon(coupon: CartCoupon | null): void { this.coupon = coupon; }, hydrateFromStorage(payload: string | null): void { if (!payload) return; try { const parsed = JSON.parse(payload) as { items?: CartItem[]; coupon?: CartCoupon | null; }; if (Array.isArray(parsed.items)) { this.items = parsed.items.filter( (entry) => entry && entry.product && typeof entry.product.slug === 'string' && typeof entry.quantity === 'number' ); } if (parsed.coupon && typeof parsed.coupon.code === 'string') { this.coupon = parsed.coupon; } } catch { // Ignore invalid storage payloads } }, toStoragePayload(): string { return JSON.stringify({ items: this.items, coupon: this.coupon, }); }, getStorageKey(): string { return CART_STORAGE_KEY; }, }, });