@weareconceptstudio/cart 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,350 @@
1
+ # @weareconceptstudio/cart
2
+
3
+ Simple and clean Zustand-based cart management for single and variant products.
4
+
5
+ ## Features
6
+
7
+ ✅ **Simple API** - Easy-to-use hooks for cart operations
8
+ ✅ **Variant Support** - Handle products with variants (color, size, etc.)
9
+ ✅ **Guest & Logged-in Users** - Cookie-based cart for guests, server-side for authenticated users
10
+ ✅ **TypeScript** - Full type safety
11
+ ✅ **Zustand** - Fast and minimal state management
12
+ ✅ **Clean Code** - Easy to read and maintain
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @weareconceptstudio/cart zustand
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ### 1. Initialize the cart store (in your app entry point)
23
+
24
+ ```typescript
25
+ import { initCartStore } from '@weareconceptstudio/cart';
26
+
27
+ // For simple products (no variants)
28
+ initCartStore(
29
+ { hasVariants: false },
30
+ isLoggedIn,
31
+ selectedLang
32
+ );
33
+
34
+ // For products with variants (color, size, etc.)
35
+ initCartStore(
36
+ { hasVariants: true },
37
+ isLoggedIn,
38
+ selectedLang
39
+ );
40
+ ```
41
+
42
+ ### 2. Use cart in your components
43
+
44
+ #### For Simple Products (No Variants)
45
+
46
+ ```typescript
47
+ import { useSimpleCart } from '@weareconceptstudio/cart';
48
+
49
+ function ProductCard({ productId }) {
50
+ const { addProduct, removeProduct, isInCart, getProductQty } = useSimpleCart();
51
+
52
+ return (
53
+ <div>
54
+ {isInCart(productId) ? (
55
+ <>
56
+ <span>Qty: {getProductQty(productId)}</span>
57
+ <button onClick={() => removeProduct(productId)}>Remove</button>
58
+ </>
59
+ ) : (
60
+ <button onClick={() => addProduct(productId, 1)}>Add to Cart</button>
61
+ )}
62
+ </div>
63
+ );
64
+ }
65
+ ```
66
+
67
+ #### For Products with Variants (Color, Size)
68
+
69
+ ```typescript
70
+ import { useVariantCart } from '@weareconceptstudio/cart';
71
+
72
+ function ProductWithVariants({ productId, variantId, optionId }) {
73
+ const { addVariantProduct, isVariantInCart, getVariantQty } = useVariantCart();
74
+
75
+ const inCart = isVariantInCart(productId, variantId, optionId);
76
+
77
+ return (
78
+ <div>
79
+ {inCart ? (
80
+ <span>Qty: {getVariantQty(productId, variantId, optionId)}</span>
81
+ ) : (
82
+ <button onClick={() => addVariantProduct(productId, variantId, optionId, 1)}>
83
+ Add to Cart
84
+ </button>
85
+ )}
86
+ </div>
87
+ );
88
+ }
89
+ ```
90
+
91
+ #### Cart Summary / Mini Cart
92
+
93
+ ```typescript
94
+ import { useCart } from '@weareconceptstudio/cart';
95
+
96
+ function MiniCart() {
97
+ const { items, itemsCount, total, currency, clearCart, loading } = useCart();
98
+
99
+ if (loading) return <div>Loading...</div>;
100
+
101
+ return (
102
+ <div>
103
+ <h3>Cart ({itemsCount} items)</h3>
104
+
105
+ {items.map((item) => (
106
+ <div key={item.product.id}>
107
+ <span>{item.product.name}</span>
108
+ <span>Qty: {item.qty}</span>
109
+ <span>{item.product.price} {currency}</span>
110
+ </div>
111
+ ))}
112
+
113
+ <div>Total: {total} {currency}</div>
114
+ <button onClick={clearCart}>Clear Cart</button>
115
+ </div>
116
+ );
117
+ }
118
+ ```
119
+
120
+ #### Checkout
121
+
122
+ ```typescript
123
+ import { useCheckout } from '@weareconceptstudio/cart';
124
+
125
+ function Checkout() {
126
+ const {
127
+ checkout,
128
+ setAddress,
129
+ setPaymentMethod,
130
+ setNote,
131
+ isReadyForCheckout,
132
+ total,
133
+ itemsCount,
134
+ } = useCheckout();
135
+
136
+ const handleCheckout = async () => {
137
+ if (!isReadyForCheckout()) {
138
+ alert('Cart is not ready for checkout');
139
+ return;
140
+ }
141
+
142
+ try {
143
+ const result = await checkout();
144
+
145
+ if (result.redirect_url) {
146
+ window.location.href = result.redirect_url;
147
+ }
148
+ } catch (error) {
149
+ console.error('Checkout error:', error);
150
+ }
151
+ };
152
+
153
+ return (
154
+ <div>
155
+ <h2>Checkout</h2>
156
+ <p>Items: {itemsCount}</p>
157
+ <p>Total: {total}</p>
158
+
159
+ <button onClick={() => setAddress(123)}>Select Address</button>
160
+ <button onClick={() => setPaymentMethod('cash_on_delivery')}>
161
+ Cash on Delivery
162
+ </button>
163
+ <textarea onChange={(e) => setNote(e.target.value)} placeholder="Add note" />
164
+
165
+ <button onClick={handleCheckout} disabled={!isReadyForCheckout()}>
166
+ Complete Order
167
+ </button>
168
+ </div>
169
+ );
170
+ }
171
+ ```
172
+
173
+ ## API Reference
174
+
175
+ ### Hooks
176
+
177
+ #### `useCart()`
178
+ Main hook with full cart state and operations.
179
+
180
+ **Returns:**
181
+ - `items` - Array of cart items with product details
182
+ - `itemsCount` - Total number of items
183
+ - `subtotal` - Cart subtotal
184
+ - `total` - Cart total
185
+ - `currency` - Currency code
186
+ - `loading` - Loading state
187
+ - `addItem()` - Add item to cart
188
+ - `removeItem()` - Remove item from cart
189
+ - `updateItem()` - Update item quantity
190
+ - `clearCart()` - Clear entire cart
191
+ - `getCart()` - Refresh cart from server
192
+
193
+ #### `useSimpleCart()`
194
+ Simplified hook for products without variants.
195
+
196
+ **Returns:**
197
+ - `addProduct(productId, qty)` - Add simple product
198
+ - `removeProduct(productId)` - Remove simple product
199
+ - `updateProductQty(productId, qty)` - Update quantity
200
+ - `isInCart(productId)` - Check if product is in cart
201
+ - `getProductQty(productId)` - Get product quantity
202
+ - `items`, `itemsCount`, `loading`
203
+
204
+ #### `useVariantCart()`
205
+ Hook for products with variants (color, size, etc.).
206
+
207
+ **Returns:**
208
+ - `addVariantProduct(productId, variantId, optionId, qty)` - Add variant product
209
+ - `removeVariantProduct(productId, variantId, optionId)` - Remove variant product
210
+ - `updateVariantProductQty(productId, variantId, optionId, qty)` - Update quantity
211
+ - `isVariantInCart(productId, variantId, optionId)` - Check if variant is in cart
212
+ - `getVariantQty(productId, variantId, optionId)` - Get variant quantity
213
+ - `items`, `itemsCount`, `loading`
214
+
215
+ #### `useCheckout()`
216
+ Hook for checkout operations.
217
+
218
+ **Returns:**
219
+ - `checkout()` - Complete checkout
220
+ - `setAddress(addressId)` - Set delivery address
221
+ - `setPaymentMethod(paymentType, cardId?)` - Set payment method
222
+ - `setNote(note)` - Add order note
223
+ - `applyPromoCode(code)` - Apply promotion code
224
+ - `isReadyForCheckout()` - Check if ready to checkout
225
+ - `checkoutData`, `total`, `subtotal`, `itemsCount`, `loading`
226
+
227
+ ### Store
228
+
229
+ #### `initCartStore(config, isLoggedIn, selectedLang)`
230
+ Initialize the cart store (call once at app start).
231
+
232
+ **Parameters:**
233
+ - `config.hasVariants` - Whether products have variants
234
+ - `isLoggedIn` - User authentication status
235
+ - `selectedLang` - Current language (default: 'en')
236
+
237
+ #### `useCartStore()`
238
+ Direct access to Zustand store (advanced usage).
239
+
240
+ ## Types
241
+
242
+ ### CartItem
243
+ ```typescript
244
+ // Simple product
245
+ interface BaseCartItem {
246
+ productId: number;
247
+ qty: number;
248
+ }
249
+
250
+ // Product with variants
251
+ interface VariantCartItem extends BaseCartItem {
252
+ variantId: number;
253
+ optionId: number;
254
+ itemId?: number;
255
+ }
256
+ ```
257
+
258
+ ### CartConfig
259
+ ```typescript
260
+ interface CartConfig {
261
+ hasVariants: boolean;
262
+ }
263
+ ```
264
+
265
+ ## Migration from Context API
266
+
267
+ If you're migrating from the old Context-based cart:
268
+
269
+ ### Before (Context API)
270
+ ```typescript
271
+ const { toggleCartItem, items } = useCart();
272
+
273
+ toggleCartItem({ productId: 123, qty: 1 });
274
+ ```
275
+
276
+ ### After (Zustand)
277
+ ```typescript
278
+ import { useSimpleCart } from '@weareconceptstudio/cart';
279
+
280
+ const { addProduct, items } = useSimpleCart();
281
+
282
+ addProduct(123, 1);
283
+ ```
284
+
285
+ ## Examples
286
+
287
+ ### Counter Component
288
+ ```typescript
289
+ import { useSimpleCart } from '@weareconceptstudio/cart';
290
+
291
+ function Counter({ productId }) {
292
+ const { getProductQty, updateProductQty } = useSimpleCart();
293
+ const qty = getProductQty(productId);
294
+
295
+ return (
296
+ <div>
297
+ <button onClick={() => updateProductQty(productId, qty - 1)}>-</button>
298
+ <span>{qty}</span>
299
+ <button onClick={() => updateProductQty(productId, qty + 1)}>+</button>
300
+ </div>
301
+ );
302
+ }
303
+ ```
304
+
305
+ ### Product with Variants
306
+ ```typescript
307
+ import { useVariantCart } from '@weareconceptstudio/cart';
308
+
309
+ function ProductPage({ product }) {
310
+ const { addVariantProduct } = useVariantCart();
311
+ const [selectedVariant, setSelectedVariant] = useState(product.variants[0]);
312
+ const [selectedOption, setSelectedOption] = useState(selectedVariant.options[0]);
313
+
314
+ const handleAddToCart = () => {
315
+ addVariantProduct(
316
+ product.id,
317
+ selectedVariant.id,
318
+ selectedOption.id,
319
+ 1
320
+ );
321
+ };
322
+
323
+ return (
324
+ <div>
325
+ <h1>{product.name}</h1>
326
+
327
+ {/* Color selection */}
328
+ {product.variants.map(variant => (
329
+ <button key={variant.id} onClick={() => setSelectedVariant(variant)}>
330
+ {variant.color.name}
331
+ </button>
332
+ ))}
333
+
334
+ {/* Size selection */}
335
+ {selectedVariant.options.map(option => (
336
+ <button key={option.id} onClick={() => setSelectedOption(option)}>
337
+ {option.size.name}
338
+ </button>
339
+ ))}
340
+
341
+ <button onClick={handleAddToCart}>Add to Cart</button>
342
+ </div>
343
+ );
344
+ }
345
+ ```
346
+
347
+ ## License
348
+
349
+ ISC © Concept Studio
350
+
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Cart Hooks
3
+ */
4
+ export { useCart, useSimpleCart, useVariantCart, useCheckout } from './useCart';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Cart Hooks
3
+ */
4
+ export { useCart, useSimpleCart, useVariantCart, useCheckout } from './useCart';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * useCart Hook
3
+ * Enhanced hook for cart operations with all features from old Context implementation
4
+ */
5
+ import { AddToCartParams, RemoveFromCartParams, UpdateCartItemParams } from '../types';
6
+ /**
7
+ * Main cart hook with backward compatibility
8
+ * Provides full API matching old Context-based cart
9
+ */
10
+ export declare function useCart(): {
11
+ items: import("../types").CartItemWithProduct[];
12
+ itemsCount: number;
13
+ formatted_subtotal: string | number;
14
+ subtotal: number;
15
+ total: number;
16
+ formatted_total: string | number;
17
+ currency: string;
18
+ shippingCost: string | number;
19
+ formatted_shippingCost: string;
20
+ loading: boolean;
21
+ discount: number;
22
+ formatted_discount: string;
23
+ appliedPromotions: any[];
24
+ remaining: number;
25
+ formatted_remaining: string;
26
+ shippingCostValue: number;
27
+ formatted_shippingCostValue: string;
28
+ shippingCityName: string;
29
+ hasFreeGift: true;
30
+ giftThresholdRemaining: number;
31
+ formatted_giftThresholdRemaining: string;
32
+ useBalance: string | number;
33
+ formatted_useBalance: string;
34
+ promotion_code: string;
35
+ promotion_error: string;
36
+ utensils: any[];
37
+ checkoutData: import("../types").CheckoutData;
38
+ setCheckoutData: (data: Partial<import("../types").CheckoutData>) => void;
39
+ addItem: (params: AddToCartParams) => Promise<void>;
40
+ removeItem: (params: RemoveFromCartParams) => Promise<void>;
41
+ updateItem: (params: UpdateCartItemParams) => Promise<void>;
42
+ clearCart: () => Promise<void>;
43
+ getCart: (params?: Record<string, any>) => Promise<void>;
44
+ mergeCart: () => Promise<void>;
45
+ syncCart: () => Promise<void>;
46
+ toggleCartItem: (params: {
47
+ productId: number;
48
+ qty: number;
49
+ variantId?: number;
50
+ optionId?: number;
51
+ itemId?: number;
52
+ update?: boolean;
53
+ }) => Promise<void>;
54
+ deleteCartItem: (params: {
55
+ productId: number;
56
+ variantId?: number;
57
+ optionId?: number;
58
+ }) => Promise<void>;
59
+ editCartItem: (params: any) => Promise<void>;
60
+ setGifts: ({ promotionId, qty, productId }: {
61
+ promotionId: number;
62
+ qty: number;
63
+ productId: number;
64
+ }) => void;
65
+ togglePromotion: ({ promotionId }: {
66
+ promotionId: number;
67
+ }) => void;
68
+ fillCheckoutData: (keyOrObject: Partial<import("../types").CheckoutData> | keyof import("../types").CheckoutData, value?: any) => void;
69
+ fillCart: (key: string, value: any) => void;
70
+ setCartState: (data: any) => void;
71
+ resetCart: () => void;
72
+ reorder: (orderId: number) => Promise<void>;
73
+ updateCheckoutData: (data: Partial<import("../types").CheckoutData>) => void;
74
+ checkout: () => Promise<any>;
75
+ handleCheckout: () => Promise<any>;
76
+ idramFormData: any;
77
+ setIdramForm: (form: any) => void;
78
+ submitIdramPayment: () => void;
79
+ checkoutBtnDisabled: any;
80
+ isCheckoutPage: boolean;
81
+ isCartPage: boolean;
82
+ isLoggedIn: boolean;
83
+ config: import("../types").CartConfig;
84
+ user: any;
85
+ setUser: (user: any) => void;
86
+ };
87
+ /**
88
+ * Hook for simple add to cart (without variants)
89
+ */
90
+ export declare function useSimpleCart(): {
91
+ addProduct: (productId: number, qty?: number) => Promise<void>;
92
+ removeProduct: (productId: number) => Promise<void>;
93
+ updateProductQty: (productId: number, qty: number) => Promise<void>;
94
+ isInCart: (productId: number) => boolean;
95
+ getProductQty: (productId: number) => number;
96
+ items: import("../types").CartItemWithProduct[];
97
+ itemsCount: number;
98
+ loading: boolean;
99
+ };
100
+ /**
101
+ * Hook for variant products (with color/size)
102
+ */
103
+ export declare function useVariantCart(): {
104
+ addVariantProduct: (productId: number, variantId: number, optionId: number, qty?: number) => Promise<void>;
105
+ removeVariantProduct: (productId: number, variantId: number, optionId: number) => Promise<void>;
106
+ updateVariantProductQty: (productId: number, variantId: number, optionId: number, qty: number) => Promise<void>;
107
+ isVariantInCart: (productId: number, variantId: number, optionId: number) => boolean;
108
+ getVariantQty: (productId: number, variantId: number, optionId: number) => number;
109
+ items: import("../types").CartItemWithProduct[];
110
+ itemsCount: number;
111
+ loading: boolean;
112
+ };
113
+ /**
114
+ * Hook for checkout operations
115
+ */
116
+ export declare function useCheckout(): {
117
+ checkoutData: import("../types").CheckoutData;
118
+ updateCheckoutData: (data: Partial<import("../types").CheckoutData>) => void;
119
+ checkout: () => Promise<any>;
120
+ setAddress: (addressId: number) => void;
121
+ setPaymentMethod: (paymentType: string, cardId?: number) => void;
122
+ setNote: (note: string) => void;
123
+ applyPromoCode: (code: string) => void;
124
+ isReadyForCheckout: () => boolean;
125
+ itemsCount: number;
126
+ total: number;
127
+ subtotal: number;
128
+ shippingCost: string | number;
129
+ loading: boolean;
130
+ };
131
+ //# sourceMappingURL=useCart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCart.d.ts","sourceRoot":"","sources":["../../src/hooks/useCart.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAGvF;;;GAGG;AACH,wBAAgB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAKgB;QACrC,SAAS,EAAE,MAAM,CAAC;QAClB,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,OAAO,CAAC;KACjB;6BAqBqC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE;2BAY9D,GAAG;;;;;;;;;;;yBAiBX,GAAG;;;;;;;;;;;;;;;;EAmG/B;AAED;;GAEG;AACH,wBAAgB,aAAa;4BAMS,MAAM,QAAO,MAAM;+BAOhB,MAAM;kCAOH,MAAM,OAAO,MAAM;0BAOjC,MAAM,KAAG,OAAO;+BAOX,MAAM,KAAG,MAAM;;;;EAejD;AAED;;GAEG;AACH,wBAAgB,cAAc;mCAMe,MAAM,aAAa,MAAM,YAAY,MAAM,QAAO,MAAM;sCAOrD,MAAM,aAAa,MAAM,YAAY,MAAM;yCAOxC,MAAM,aAAa,MAAM,YAAY,MAAM,OAAO,MAAM;iCAOtE,MAAM,aAAa,MAAM,YAAY,MAAM,KAAG,OAAO;+BASvD,MAAM,aAAa,MAAM,YAAY,MAAM,KAAG,MAAM;;;;EAiBtF;AAED;;GAEG;AACH,wBAAgB,WAAW;;;;4BAOK,MAAM;oCAOE,MAAM,WAAW,MAAM;oBAOvC,MAAM;2BAOC,MAAM;8BAOL,OAAO;;;;;;EAmBtC"}