{"version":3,"sources":["FC_CartCounter.tsx"],"sourcesContent":["/*\n * Framer Commerce\n * Confidential and Proprietary - All Rights Reserved\n * Unauthorized use, reproduction, distribution, or disclosure of this\n * source code or any related information is strictly prohibited.\n *\n * This software is the exclusive property of Framer Commerce (\"Company\").\n * It is considered highly confidential and proprietary information.\n *\n * Any use, copying, modification, distribution, or sharing of this software,\n * in whole or in part, without the express written permission of the Company\n * is strictly prohibited and may result in legal action.\n *\n * DISCLAIMER: This software does not provide any express or\n * implied warranties, including, but not limited to, the implied warranties\n * of merchantability and fitness for a particular purpose. In no event shall\n * Framer Commerce be liable for any direct, indirect, incidental, special,\n * exemplary, or consequential damages (including, but not limited to, procurement\n * of substitute goods or services; loss of use, data, or profits; or business\n * interruption) however caused and on any theory of liability, whether in\n * contract, strict liability, or tort (including negligence or otherwise)\n * arising in any way out of the use of this software, even if advised of\n * the possibility of such damage.\n *\n * Any unauthorized possession, use, copying, distribution, or dissemination\n * of this software will be considered a breach of confidentiality and may\n * result in legal action.\n *\n * For inquiries, contact:\n * Framer Commerce\n * Email: hello@framercommerce.com\n *\n * © 2025 Butter Supply Inc. All Rights Reserved.\n */\n\nimport { useEffect, useRef, useState, useCallback } from \"react\"\nimport { addPropertyControls, ControlType, RenderTarget } from \"framer\"\nimport { throttle } from \"lodash-es\"\n\n/**\n * @framerDisableUnlink\n */\n\nexport default function FC_CartCounter(props) {\n    if (RenderTarget.current() === RenderTarget.canvas) {\n        return (\n            <div\n                style={{\n                    display: \"inline-flex\",\n                    alignItems: \"center\",\n                    justifyContent: \"center\",\n                }}\n            >\n                <p\n                    style={{\n                        ...props.font,\n                        color: props.color,\n                        backgroundColor: props.backgroundColor,\n                        ...props.border,\n                        borderRadius: props.radius,\n                        padding: props.padding,\n                        display: \"flex\",\n                        alignItems: \"center\",\n                        margin: 0,\n                        height: props.fixedHeight\n                            ? `${props.heightPx}px`\n                            : \"auto\",\n                    }}\n                >\n                    0\n                </p>\n            </div>\n        )\n    } else {\n        const [isBrowser, setIsBrowser] = useState(false)\n        const [cartItemCount, setCartItemCount] = useState(0)\n        const isFetching = useRef(false)\n\n        // Set isBrowser to true once component mounts\n        useEffect(() => {\n            setIsBrowser(true)\n        }, [])\n\n        // Helper function to wait until a condition is true\n        const waitForCondition = useCallback(\n            (conditionFn, checkInterval = 100, timeout = 10000) => {\n                return new Promise((resolve, reject) => {\n                    const startTime = Date.now()\n                    const checkCondition = () => {\n                        if (conditionFn()) {\n                            resolve()\n                        } else if (Date.now() - startTime >= timeout) {\n                            reject(\n                                new Error(\"Condition not met within timeout\")\n                            )\n                        } else {\n                            setTimeout(checkCondition, checkInterval)\n                        }\n                    }\n                    checkCondition()\n                })\n            },\n            []\n        )\n\n        const fetchCartAndUpdateCount = useCallback(\n            async (cartId) => {\n                if (isFetching.current) {\n                    return\n                }\n                isFetching.current = true\n                try {\n                    await waitForCondition(\n                        () => window.shopXtools && window.shopXtools.fetchCart\n                    )\n\n                    const cartData = await window.shopXtools.fetchCart(cartId)\n                    if (cartData) {\n                        if (cartData.lines && cartData.lines.edges) {\n                            const itemCount = cartData.lines.edges.reduce(\n                                (total, edge) =>\n                                    total + (edge.node.quantity || 0),\n                                0\n                            )\n                            setCartItemCount(itemCount)\n                        } else {\n                            setCartItemCount(0)\n                        }\n                    } else {\n                        setCartItemCount(0)\n                    }\n                } catch (error) {\n                    setCartItemCount(0)\n                } finally {\n                    isFetching.current = false\n                }\n            },\n            [waitForCondition]\n        )\n\n        const handleCartUpdate = useCallback(\n            throttle(async () => {\n                if (!isBrowser) return // Don't run on server-side\n\n                let cartId = window[\"shopXtools\"]?.cart?.id\n\n                if (!cartId) {\n                    try {\n                        cartId = localStorage.getItem(\"shopX_cart_id\")\n                    } catch (error) {\n                        // Error accessing localStorage\n                    }\n                }\n\n                if (cartId) {\n                    await fetchCartAndUpdateCount(cartId)\n                } else {\n                    setCartItemCount(0)\n                }\n            }, 1000),\n            [fetchCartAndUpdateCount, isBrowser]\n        )\n\n        useEffect(() => {\n            if (!isBrowser) return // Don't run on server-side\n\n            window.addEventListener(\"shopXtools-cart-update\", handleCartUpdate)\n            handleCartUpdate()\n\n            return () => {\n                window.removeEventListener(\n                    \"shopXtools-cart-update\",\n                    handleCartUpdate\n                )\n            }\n        }, [handleCartUpdate, isBrowser])\n\n        if (props.hideIf0 && cartItemCount === 0) {\n            return null\n        }\n\n        return (\n            <div\n                style={{\n                    display: \"inline-flex\",\n                    alignItems: \"center\",\n                    justifyContent: \"center\",\n                }}\n            >\n                <p\n                    style={{\n                        ...props.font,\n                        color: props.color,\n                        backgroundColor: props.backgroundColor,\n                        ...props.border,\n                        borderRadius: props.radius,\n                        padding: props.padding,\n                        display: \"flex\",\n                        alignItems: \"center\",\n                        margin: 0,\n                        height: props.fixedHeight\n                            ? `${props.heightPx}px`\n                            : \"auto\",\n                    }}\n                >\n                    {isBrowser ? cartItemCount.toString() : \"0\"}\n                </p>\n            </div>\n        )\n    }\n}\n\nFC_CartCounter.defaultProps = {\n    hideIf0: false,\n    font: undefined,\n    color: \"#000\",\n    backgroundColor: \"#FFFFFF\",\n    border: {\n        borderTopWidth: 0,\n        borderRightWidth: 0,\n        borderBottomWidth: 0,\n        borderLeftWidth: 0,\n        borderStyle: \"solid\",\n        borderColor: \"rgba(0, 0, 0, 0.5)\",\n    },\n    radius: 0,\n    padding: 0,\n    fixedHeight: false,\n    heightPx: 40,\n}\n\naddPropertyControls(FC_CartCounter, {\n    hideIf0: {\n        type: ControlType.Boolean,\n        title: \"Hide If 0\",\n        defaultValue: false,\n    },\n    font: {\n        type: ControlType.Font,\n        controls: \"extended\",\n        title: \"Font\",\n    },\n    color: {\n        type: ControlType.Color,\n        defaultValue: \"#000\",\n        title: \"Color\",\n    },\n    backgroundColor: {\n        type: ControlType.Color,\n        title: \"BG\",\n        defaultValue: \"#FFFFFF\",\n    },\n    border: {\n        type: ControlType.Border,\n        title: \"Border\",\n        defaultValue: {\n            borderTopWidth: 0,\n            borderRightWidth: 0,\n            borderBottomWidth: 0,\n            borderLeftWidth: 0,\n            borderStyle: \"solid\",\n            borderColor: \"rgba(0, 0, 0, 0.5)\",\n        },\n    },\n    fixedHeight: {\n        type: ControlType.Boolean,\n        title: \"Height\",\n        defaultValue: false,\n        enabledTitle: \"Fixed\",\n        disabledTitle: \"Fit\",\n    },\n    heightPx: {\n        type: ControlType.Number,\n        title: \"Height\",\n        defaultValue: 40,\n        min: 0,\n        hidden: ({ fixedHeight }) => !fixedHeight,\n    },\n    padding: {\n        type: ControlType.FusedNumber,\n        title: \"Padding\",\n        defaultValue: 0,\n        toggleKey: \"paddingPerSide\",\n        toggleTitles: [\"All\", \"Sides\"],\n        valueKeys: [\n            \"paddingTop\",\n            \"paddingRight\",\n            \"paddingBottom\",\n            \"paddingLeft\",\n        ],\n        valueLabels: [\"T\", \"R\", \"B\", \"L\"],\n        min: 0,\n    },\n    radius: {\n        type: ControlType.FusedNumber,\n        title: \"Radius\",\n        defaultValue: 0,\n        toggleKey: \"radiusPerCorner\",\n        toggleTitles: [\"All\", \"Corners\"],\n        valueKeys: [\"topLeft\", \"topRight\", \"bottomRight\", \"bottomLeft\"],\n        valueLabels: [\"TL\", \"TR\", \"BR\", \"BL\"],\n        min: 0,\n    },\n})\n"],"names":[],"mappings":"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"}