first commit
This commit is contained in:
18
app/stores/banner.ts
Normal file
18
app/stores/banner.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import type { Banner } from '~~/types/banner';
|
||||
|
||||
interface BannerState {
|
||||
banner: Banner[];
|
||||
}
|
||||
|
||||
export const useBannerStore = defineStore('banner', {
|
||||
state: (): BannerState => ({
|
||||
banner: [],
|
||||
}),
|
||||
actions: {
|
||||
setBanner(newBanner: Banner[]): void {
|
||||
this.banner = newBanner;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
177
app/stores/cart.ts
Normal file
177
app/stores/cart.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
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;
|
||||
},
|
||||
},
|
||||
});
|
||||
17
app/stores/productTree.ts
Normal file
17
app/stores/productTree.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import type { ProductTree } from '~~/types/banner';
|
||||
|
||||
interface ProductTreeState {
|
||||
productTree: ProductTree[];
|
||||
}
|
||||
|
||||
export const useProductTreeStore = defineStore('productTree', {
|
||||
state: (): ProductTreeState => ({
|
||||
productTree: [],
|
||||
}),
|
||||
actions: {
|
||||
setProductTree(newProductTree: ProductTree[]): void {
|
||||
this.productTree = newProductTree;
|
||||
}
|
||||
}
|
||||
});
|
||||
17
app/stores/setting.ts
Normal file
17
app/stores/setting.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import type { Setting } from '~~/types/setting';
|
||||
|
||||
interface SettingState {
|
||||
settings: Setting | null;
|
||||
}
|
||||
|
||||
export const useSettingStore = defineStore('setting', {
|
||||
state: (): SettingState => ({
|
||||
settings: null,
|
||||
}),
|
||||
actions: {
|
||||
setSettings(newSettings: Setting | null): void {
|
||||
this.settings = newSettings;
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user