Ship Expo Router screens, seeded stores, and polished UX so auth, shop, checkout, prescriptions, loyalty, family, and account processes work end-to-end offline. Co-authored-by: Cursor <cursoragent@cursor.com>
81 lines
2.3 KiB
TypeScript
81 lines
2.3 KiB
TypeScript
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
import { create } from "zustand";
|
|
import { createJSONStorage, persist } from "zustand/middleware";
|
|
import type { Product } from "@/lib/data/products";
|
|
|
|
export type CartItem = {
|
|
productId: string;
|
|
slug: string;
|
|
name: string;
|
|
price: number;
|
|
image: string;
|
|
unit: string;
|
|
quantity: number;
|
|
requiresPrescription?: boolean;
|
|
};
|
|
|
|
type CartState = {
|
|
items: CartItem[];
|
|
voucherCode: string | null;
|
|
addProduct: (product: Product, qty?: number) => void;
|
|
removeItem: (productId: string) => void;
|
|
setQuantity: (productId: string, quantity: number) => void;
|
|
clear: () => void;
|
|
setVoucher: (code: string | null) => void;
|
|
totalItems: () => number;
|
|
subtotal: () => number;
|
|
};
|
|
|
|
export const useCartStore = create<CartState>()(
|
|
persist(
|
|
(set, get) => ({
|
|
items: [],
|
|
voucherCode: null,
|
|
addProduct: (product, qty = 1) => {
|
|
const items = [...get().items];
|
|
const idx = items.findIndex((i) => i.productId === product.id);
|
|
if (idx >= 0) {
|
|
items[idx] = {
|
|
...items[idx],
|
|
quantity: items[idx].quantity + qty,
|
|
};
|
|
} else {
|
|
items.push({
|
|
productId: product.id,
|
|
slug: product.slug,
|
|
name: product.name,
|
|
price: product.price,
|
|
image: product.image,
|
|
unit: product.unit,
|
|
quantity: qty,
|
|
requiresPrescription: product.requiresPrescription,
|
|
});
|
|
}
|
|
set({ items });
|
|
},
|
|
removeItem: (productId) =>
|
|
set({ items: get().items.filter((i) => i.productId !== productId) }),
|
|
setQuantity: (productId, quantity) => {
|
|
if (quantity <= 0) {
|
|
get().removeItem(productId);
|
|
return;
|
|
}
|
|
set({
|
|
items: get().items.map((i) =>
|
|
i.productId === productId ? { ...i, quantity } : i
|
|
),
|
|
});
|
|
},
|
|
clear: () => set({ items: [], voucherCode: null }),
|
|
setVoucher: (code) => set({ voucherCode: code }),
|
|
totalItems: () => get().items.reduce((n, i) => n + i.quantity, 0),
|
|
subtotal: () =>
|
|
get().items.reduce((n, i) => n + i.price * i.quantity, 0),
|
|
}),
|
|
{
|
|
name: "gishen-cart",
|
|
storage: createJSONStorage(() => AsyncStorage),
|
|
}
|
|
)
|
|
);
|