feat: initial commit
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
// Ported from legacy henza_pwa/src/store/cartStore.ts, adapted to our string
|
||||
// ids and flat (non-paginated) product list. Persisted the same way (a single
|
||||
// localStorage key), just via Pinia's own state instead of @vueuse's
|
||||
// useStorage wrapping a hand-rolled class.
|
||||
import { defineStore } from 'pinia'
|
||||
import { api, type ProductSummary } from '../api/client'
|
||||
|
||||
export interface CartItem {
|
||||
pid: string
|
||||
vid: string
|
||||
product: ProductSummary
|
||||
qty: number
|
||||
note?: string | null
|
||||
}
|
||||
|
||||
const STORAGE_KEY = 'appCart'
|
||||
|
||||
function loadFromStorage(): CartItem[] {
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY)
|
||||
return raw ? JSON.parse(raw) : []
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
function persist(items: CartItem[]) {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(items))
|
||||
}
|
||||
|
||||
export const useCartStore = defineStore('cart', {
|
||||
state: () => ({
|
||||
items: loadFromStorage() as CartItem[],
|
||||
}),
|
||||
actions: {
|
||||
// Re-syncs cart entries against fresh product data (e.g. price/weight
|
||||
// changes since the item was added), dropping entries whose
|
||||
// product/variant no longer exists — same intent as legacy's init().
|
||||
async init() {
|
||||
try {
|
||||
const products = await api.listProducts()
|
||||
const refreshed: CartItem[] = []
|
||||
for (const item of this.items) {
|
||||
const product = products.find((p) => p.id === item.pid)
|
||||
const variant = product?.variants.find((v) => v.id === item.vid)
|
||||
if (product && variant) {
|
||||
refreshed.push({ ...item, product })
|
||||
}
|
||||
}
|
||||
this.items = refreshed
|
||||
persist(this.items)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
addToCart(data: CartItem) {
|
||||
const index = this.find_index(data)
|
||||
if (index === -1) this.items.push(data)
|
||||
else {
|
||||
this.items[index].product = data.product
|
||||
this.items[index].qty = data.qty
|
||||
}
|
||||
persist(this.items)
|
||||
},
|
||||
remove(item: CartItem) {
|
||||
const index = this.find_index(item)
|
||||
if (index > -1) this.items.splice(index, 1)
|
||||
persist(this.items)
|
||||
},
|
||||
// Legacy's exact name (typo'd "Feild"), kept for consistency with the rest
|
||||
// of this faithfully-ported store's method names.
|
||||
updateFeild(value: unknown, index: number | null, item: Pick<CartItem, 'pid' | 'vid'>, field: keyof CartItem) {
|
||||
if (!this.isInCart(item)) return false
|
||||
const i = index ?? this.find_index(item)
|
||||
;(this.items[i] as any)[field] = value
|
||||
persist(this.items)
|
||||
return true
|
||||
},
|
||||
find_index(item: Pick<CartItem, 'pid' | 'vid'>) {
|
||||
return this.items.findIndex((cartItem) => cartItem.pid === item.pid && cartItem.vid === item.vid)
|
||||
},
|
||||
isInCart(item: Pick<CartItem, 'pid' | 'vid'>) {
|
||||
return this.find_index(item) > -1
|
||||
},
|
||||
variant(item: CartItem) {
|
||||
return item.product.variants.find((v) => v.id === item.vid)
|
||||
},
|
||||
total() {
|
||||
return this.items
|
||||
.reduce((sum, item) => {
|
||||
const v = this.variant(item)
|
||||
return sum + (v ? parseFloat(v.rashWeightGrams) * item.qty : 0)
|
||||
}, 0)
|
||||
.toFixed(2)
|
||||
},
|
||||
clear() {
|
||||
this.items = []
|
||||
persist(this.items)
|
||||
},
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user