@caseparts-org/casecore 0.0.12 → 0.0.13
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/dist/cart/CartContext.d.ts +25 -0
- package/dist/cart/CartContext.js +93 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/cart/CreateCart.d.ts +0 -31
- package/dist/cart/CreateCart.js +0 -65
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Pricing } from './ClassPricing';
|
|
3
|
+
export interface BaseCartItem {
|
|
4
|
+
ItemKey: number | string;
|
|
5
|
+
Quantity: number;
|
|
6
|
+
Pricing?: Pricing | undefined;
|
|
7
|
+
[k: string]: any;
|
|
8
|
+
}
|
|
9
|
+
export interface CartContextValue {
|
|
10
|
+
items: BaseCartItem[];
|
|
11
|
+
initialized: boolean;
|
|
12
|
+
isMobile: boolean;
|
|
13
|
+
subtotal: number;
|
|
14
|
+
setItems: (_next: BaseCartItem[] | ((_prev: BaseCartItem[]) => BaseCartItem[])) => void;
|
|
15
|
+
addOrReplace: (_item: BaseCartItem) => void;
|
|
16
|
+
updateQuantity: (_key: number | string, _qty: number) => void;
|
|
17
|
+
removeItem: (_key: number | string) => void;
|
|
18
|
+
clear: () => void;
|
|
19
|
+
}
|
|
20
|
+
export interface CartProviderProps {
|
|
21
|
+
pricingResolver?: (_item: BaseCartItem) => number;
|
|
22
|
+
children: React.ReactNode;
|
|
23
|
+
}
|
|
24
|
+
export declare const CartProvider: React.FC<CartProviderProps>;
|
|
25
|
+
export declare function useCartContext(): CartContextValue;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useState, useCallback, useEffect, useMemo } from 'react';
|
|
3
|
+
const STORAGE_KEY = 'CPC.cart';
|
|
4
|
+
const CartContext = createContext(undefined);
|
|
5
|
+
export const CartProvider = ({ children, pricingResolver }) => {
|
|
6
|
+
const [items, _setItems] = useState([]);
|
|
7
|
+
const [initialized, setInitialized] = useState(false);
|
|
8
|
+
const [isMobile, setIsMobile] = useState(false);
|
|
9
|
+
// Load once
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
try {
|
|
12
|
+
const raw = typeof window !== 'undefined'
|
|
13
|
+
? window.localStorage.getItem(STORAGE_KEY)
|
|
14
|
+
: null;
|
|
15
|
+
if (raw) {
|
|
16
|
+
const parsed = JSON.parse(raw);
|
|
17
|
+
if (Array.isArray(parsed?.items)) {
|
|
18
|
+
_setItems(parsed.items);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch { /* ignore */ }
|
|
23
|
+
if (typeof navigator !== 'undefined') {
|
|
24
|
+
setIsMobile(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile|WPDesktop/i.test(navigator.userAgent));
|
|
25
|
+
}
|
|
26
|
+
setInitialized(true);
|
|
27
|
+
}, []);
|
|
28
|
+
const persist = useCallback((next) => {
|
|
29
|
+
try {
|
|
30
|
+
window.localStorage.setItem(STORAGE_KEY, JSON.stringify({ items: next }));
|
|
31
|
+
}
|
|
32
|
+
catch { /* ignore */ }
|
|
33
|
+
}, []);
|
|
34
|
+
const setItems = useCallback((next) => {
|
|
35
|
+
_setItems(prev => {
|
|
36
|
+
const resolvedArray = typeof next === 'function'
|
|
37
|
+
? next(prev)
|
|
38
|
+
: next;
|
|
39
|
+
const cloned = resolvedArray.map(i => ({ ...i })); // ensure new refs
|
|
40
|
+
persist(cloned);
|
|
41
|
+
return cloned;
|
|
42
|
+
});
|
|
43
|
+
}, [persist]);
|
|
44
|
+
const addOrReplace = useCallback((item) => {
|
|
45
|
+
setItems(prev => {
|
|
46
|
+
const idx = prev.findIndex(p => p.ItemKey === item.ItemKey);
|
|
47
|
+
if (idx === -1)
|
|
48
|
+
return [...prev, { ...item }];
|
|
49
|
+
const next = [...prev];
|
|
50
|
+
next[idx] = { ...item };
|
|
51
|
+
return next;
|
|
52
|
+
});
|
|
53
|
+
}, [setItems]);
|
|
54
|
+
const updateQuantity = useCallback((key, qty) => {
|
|
55
|
+
setItems(prev => {
|
|
56
|
+
if (qty <= 0)
|
|
57
|
+
return prev.filter(i => i.ItemKey !== key);
|
|
58
|
+
return prev.map(i => i.ItemKey === key ? { ...i, Quantity: qty } : i);
|
|
59
|
+
});
|
|
60
|
+
}, [setItems]);
|
|
61
|
+
const removeItem = useCallback((key) => {
|
|
62
|
+
setItems(prev => prev.filter(i => i.ItemKey !== key));
|
|
63
|
+
}, [setItems]);
|
|
64
|
+
const clear = useCallback(() => {
|
|
65
|
+
setItems([]);
|
|
66
|
+
}, [setItems]);
|
|
67
|
+
const subtotal = useMemo(() => {
|
|
68
|
+
if (!items.length)
|
|
69
|
+
return 0;
|
|
70
|
+
return items.reduce((sum, it) => {
|
|
71
|
+
const price = pricingResolver ? pricingResolver(it) : 0;
|
|
72
|
+
return sum + price * (it.Quantity ?? 1);
|
|
73
|
+
}, 0);
|
|
74
|
+
}, [items, pricingResolver]);
|
|
75
|
+
const value = useMemo(() => ({
|
|
76
|
+
items,
|
|
77
|
+
initialized,
|
|
78
|
+
isMobile,
|
|
79
|
+
subtotal,
|
|
80
|
+
setItems,
|
|
81
|
+
addOrReplace,
|
|
82
|
+
updateQuantity,
|
|
83
|
+
removeItem,
|
|
84
|
+
clear
|
|
85
|
+
}), [items, initialized, isMobile, subtotal, setItems, addOrReplace, updateQuantity, removeItem, clear]);
|
|
86
|
+
return (_jsx(CartContext.Provider, { value: value, children: children }));
|
|
87
|
+
};
|
|
88
|
+
export function useCartContext() {
|
|
89
|
+
const ctx = useContext(CartContext);
|
|
90
|
+
if (!ctx)
|
|
91
|
+
throw new Error('useCart must be used inside <CartProvider>');
|
|
92
|
+
return ctx;
|
|
93
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,5 +8,5 @@ export type { MicroFlexFieldSelectors, MicroFlexOptions, MicroFlexReturn } from
|
|
|
8
8
|
export { default as useMicroFlex } from './hooks/useMicroFlex';
|
|
9
9
|
export type { Pricing, CustomerClass } from './cart/ClassPricing';
|
|
10
10
|
export { getClassPricing } from './cart/ClassPricing';
|
|
11
|
-
export type { BaseCartItem,
|
|
12
|
-
export {
|
|
11
|
+
export type { BaseCartItem, CartContextValue, CartProviderProps, } from './cart/CartContext';
|
|
12
|
+
export { CartProvider, useCartContext } from './cart/CartContext';
|
package/dist/index.js
CHANGED
|
@@ -6,4 +6,4 @@ export { getSessionId } from './utils/SessionUtils';
|
|
|
6
6
|
export { buildClaimsFromPayload } from './utils/ClaimsUtils';
|
|
7
7
|
export { default as useMicroFlex } from './hooks/useMicroFlex';
|
|
8
8
|
export { getClassPricing } from './cart/ClassPricing';
|
|
9
|
-
export {
|
|
9
|
+
export { CartProvider, useCartContext } from './cart/CartContext';
|
package/package.json
CHANGED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Pricing } from './ClassPricing';
|
|
3
|
-
export type PricingResolver<T extends BaseCartItem> = (_item: T) => number;
|
|
4
|
-
export interface BaseCartItem {
|
|
5
|
-
ItemKey: number | string;
|
|
6
|
-
Quantity: number;
|
|
7
|
-
Pricing?: Pricing | undefined;
|
|
8
|
-
[k: string]: any;
|
|
9
|
-
}
|
|
10
|
-
export interface Cart<T extends BaseCartItem = BaseCartItem> {
|
|
11
|
-
items: T[];
|
|
12
|
-
}
|
|
13
|
-
export interface CartConfig<T extends BaseCartItem> {
|
|
14
|
-
storageKey?: string;
|
|
15
|
-
pricingResolver?: PricingResolver<T>;
|
|
16
|
-
}
|
|
17
|
-
export interface CartContextValue<T extends BaseCartItem> {
|
|
18
|
-
cart: Cart<T>;
|
|
19
|
-
updateCart: (_cart: Cart<T>) => void;
|
|
20
|
-
cartSubtotal: () => number;
|
|
21
|
-
initializedCart: boolean;
|
|
22
|
-
isMobile: boolean;
|
|
23
|
-
}
|
|
24
|
-
export type CartProviderProps<T extends BaseCartItem> = React.PropsWithChildren<{
|
|
25
|
-
pricingResolver?: PricingResolver<T>;
|
|
26
|
-
}>;
|
|
27
|
-
export interface CreateCartReturn<T extends BaseCartItem> {
|
|
28
|
-
CartProvider: React.FC<CartProviderProps<T>>;
|
|
29
|
-
useCartContext: () => CartContextValue<T>;
|
|
30
|
-
}
|
|
31
|
-
export declare function createCart<T extends BaseCartItem = BaseCartItem>(config?: CartConfig<T>): CreateCartReturn<T>;
|
package/dist/cart/CreateCart.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { createContext, useContext, useState, useCallback, useMemo, useEffect } from 'react';
|
|
3
|
-
export function createCart(config) {
|
|
4
|
-
const STORAGE_KEY = config?.storageKey ?? 'CPC.cart';
|
|
5
|
-
const CartContext = createContext(undefined);
|
|
6
|
-
const CartProvider = ({ children, pricingResolver }) => {
|
|
7
|
-
const [cart, setCart] = useState({ items: [] });
|
|
8
|
-
const [initialized, setInitialized] = useState(false);
|
|
9
|
-
const [isMobile, setIsMobile] = useState(false);
|
|
10
|
-
const resolver = pricingResolver ?? config?.pricingResolver;
|
|
11
|
-
// Initialize cart from local storage
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
try {
|
|
14
|
-
const rawCart = typeof window !== 'undefined' ? window.localStorage.getItem(STORAGE_KEY) : null;
|
|
15
|
-
if (rawCart) {
|
|
16
|
-
const parsed = JSON.parse(rawCart);
|
|
17
|
-
if (parsed?.items && Array.isArray(parsed.items)) {
|
|
18
|
-
setCart({ items: parsed.items });
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
23
|
-
/* ignore */
|
|
24
|
-
}
|
|
25
|
-
if (typeof navigator !== 'undefined') {
|
|
26
|
-
setIsMobile(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile|WPDesktop/i.test(navigator.userAgent));
|
|
27
|
-
}
|
|
28
|
-
setInitialized(true);
|
|
29
|
-
}, []);
|
|
30
|
-
const save = useCallback((c) => {
|
|
31
|
-
try {
|
|
32
|
-
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(c));
|
|
33
|
-
}
|
|
34
|
-
catch { /* suppress */ }
|
|
35
|
-
}, []);
|
|
36
|
-
const updateCart = useCallback((c) => {
|
|
37
|
-
setCart({ items: [...c.items] });
|
|
38
|
-
save(c);
|
|
39
|
-
}, [save]);
|
|
40
|
-
const cartSubtotal = useCallback(() => {
|
|
41
|
-
if (!cart.items.length)
|
|
42
|
-
return 0;
|
|
43
|
-
return cart.items.reduce((sum, item) => {
|
|
44
|
-
const price = resolver ? resolver(item) : 0;
|
|
45
|
-
const qty = item.Quantity ?? 1;
|
|
46
|
-
return sum + price * qty;
|
|
47
|
-
}, 0);
|
|
48
|
-
}, [cart.items, resolver]);
|
|
49
|
-
const value = useMemo(() => ({
|
|
50
|
-
cart,
|
|
51
|
-
updateCart,
|
|
52
|
-
cartSubtotal,
|
|
53
|
-
initializedCart: initialized,
|
|
54
|
-
isMobile
|
|
55
|
-
}), [cart, updateCart, cartSubtotal, initialized, isMobile]);
|
|
56
|
-
return _jsx(CartContext.Provider, { value: value, children: children });
|
|
57
|
-
};
|
|
58
|
-
const useCartContext = () => {
|
|
59
|
-
const cartContext = useContext(CartContext);
|
|
60
|
-
if (!cartContext)
|
|
61
|
-
throw new Error('useCartContext must be used inside CartProvider');
|
|
62
|
-
return cartContext;
|
|
63
|
-
};
|
|
64
|
-
return { CartProvider, useCartContext };
|
|
65
|
-
}
|