"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
/*
 *  This file is part of CoCalc: Copyright © 2022 Sagemath, Inc.
 *  License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details
 */
/*
Shopping cart.

The UX is similar to Amazon.com, since that's probably the single most popular
shopping cart experience, so most likely to feel familiar to users and easy
to use.
*/
const icon_1 = require("@cocalc/frontend/components/icon");
const describe_quota_1 = require("@cocalc/util/licenses/describe-quota");
const utils_1 = require("@cocalc/util/licenses/purchase/utils");
const misc_1 = require("@cocalc/util/misc");
const antd_1 = require("antd");
const A_1 = __importDefault(require("components/misc/A"));
const loading_1 = __importDefault(require("components/share/loading"));
const site_name_1 = __importDefault(require("components/share/site-name"));
const post_1 = __importDefault(require("lib/api/post"));
const api_1 = __importDefault(require("lib/hooks/api"));
const mounted_1 = __importDefault(require("lib/hooks/mounted"));
const router_1 = require("next/router");
const react_1 = require("react");
const compute_cost_1 = require("./compute-cost");
const other_items_1 = __importDefault(require("./other-items"));
const run_limit_1 = require("./run-limit");
const site_license_cost_1 = require("./site-license-cost");
function ShoppingCart() {
    const isMounted = (0, mounted_1.default)();
    const [updating, setUpdating] = (0, react_1.useState)(false);
    const [subTotal, setSubTotal] = (0, react_1.useState)(0);
    const router = (0, router_1.useRouter)();
    // most likely, user will checkout next
    (0, react_1.useEffect)(() => {
        router.prefetch("/store/checkout");
    }, []);
    const cart = (0, api_1.default)("/shopping/cart/get");
    const items = (0, react_1.useMemo)(() => {
        if (!cart.result)
            return undefined;
        // TODO deal with errors returned by useAPI
        if (cart.result.error != null)
            return undefined;
        const x = [];
        let subTotal = 0;
        for (const item of cart.result) {
            try {
                item.cost = (0, compute_cost_1.computeCost)(item.description);
            }
            catch (err) {
                // sadly computeCost is buggy, or rather - it crashes because of other bugs.
                // It's much better to
                // have something not in the cart and an error than to make the cart and
                // store just be 100% broken
                // forever for a user!
                // That said, I've fixed every bug I could find and tested things, so hopefully
                // this doesn't come up.
                console.warn("Invalid item in cart -- not showing", item);
                continue;
            }
            if (item.checked) {
                subTotal += item.cost.discounted_cost;
            }
            x.push(item);
        }
        setSubTotal(subTotal);
        return x;
    }, [cart.result]);
    if (cart.error) {
        return (0, jsx_runtime_1.jsx)(antd_1.Alert, { type: "error", message: cart.error });
    }
    if (!items) {
        return (0, jsx_runtime_1.jsx)(loading_1.default, { center: true });
    }
    async function reload() {
        if (!isMounted.current)
            return;
        setUpdating(true);
        try {
            await cart.call();
        }
        finally {
            if (isMounted.current) {
                setUpdating(false);
            }
        }
    }
    const columns = [
        {
            responsive: ["xs"],
            render: ({ id, checked, cost, description, type, project_id }) => {
                return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(CheckboxColumn, { ...{ id, checked, updating, setUpdating, isMounted, reload } }), (0, jsx_runtime_1.jsx)(DescriptionColumn, { ...{
                                id,
                                cost,
                                description,
                                updating,
                                setUpdating,
                                isMounted,
                                reload,
                                type,
                                project_id,
                            }, compact: true }), (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("b", { style: { fontSize: "11pt" }, children: (0, jsx_runtime_1.jsx)(site_license_cost_1.DisplayCost, { cost: cost, simple: true, oneLine: true }) }) })] }));
            },
        },
        {
            responsive: ["sm"],
            title: "",
            render: (_, { id, checked }) => ((0, jsx_runtime_1.jsx)(CheckboxColumn, { ...{ id, checked, updating, setUpdating, isMounted, reload } })),
        },
        {
            responsive: ["sm"],
            title: "Product",
            align: "center",
            render: () => ((0, jsx_runtime_1.jsxs)("div", { style: { color: "darkblue" }, children: [(0, jsx_runtime_1.jsx)(icon_1.Icon, { name: "key", style: { fontSize: "24px" } }), (0, jsx_runtime_1.jsx)("div", { style: { fontSize: "10pt" }, children: "Site License" })] })),
        },
        {
            responsive: ["sm"],
            width: "60%",
            render: (_, { id, cost, description, type, project_id }) => ((0, jsx_runtime_1.jsx)(DescriptionColumn, { ...{
                    id,
                    cost,
                    description,
                    updating,
                    setUpdating,
                    isMounted,
                    reload,
                    type,
                    project_id,
                }, compact: false })),
        },
        {
            responsive: ["sm"],
            title: "Price",
            align: "right",
            render: (_, { cost }) => ((0, jsx_runtime_1.jsx)("b", { style: { fontSize: "11pt" }, children: (0, jsx_runtime_1.jsx)(site_license_cost_1.DisplayCost, { cost: cost, simple: true }) })),
        },
    ];
    function noItems() {
        return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("h3", { children: [(0, jsx_runtime_1.jsx)(icon_1.Icon, { name: "shopping-cart", style: { marginRight: "5px" } }), " Your", " ", (0, jsx_runtime_1.jsx)(site_name_1.default, {}), " Shopping Cart is Empty"] }), (0, jsx_runtime_1.jsx)(A_1.default, { href: "/store/site-license", children: "Buy a License" })] }));
    }
    function renderItems() {
        return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { style: { float: "right", marginBottom: "15px" }, children: [(0, jsx_runtime_1.jsx)("span", { style: { fontSize: "13pt" }, children: (0, jsx_runtime_1.jsx)(TotalCost, { items: items }) }), (0, jsx_runtime_1.jsx)(A_1.default, { href: "/store/checkout", children: (0, jsx_runtime_1.jsx)(antd_1.Button, { disabled: subTotal == 0 || updating, style: { marginLeft: "15px" }, size: "large", type: "primary", children: "Proceed to Checkout" }) })] }), (0, jsx_runtime_1.jsxs)("h3", { children: [(0, jsx_runtime_1.jsx)(icon_1.Icon, { name: "shopping-cart", style: { marginRight: "5px" } }), " ", "Shopping Cart"] }), (0, jsx_runtime_1.jsx)("div", { style: { marginTop: "-10px", marginBottom: "5px" }, children: (0, jsx_runtime_1.jsx)(SelectAllItems, { items: items, onChange: reload }) }), (0, jsx_runtime_1.jsx)("div", { style: { border: "1px solid #eee" }, children: (0, jsx_runtime_1.jsx)(antd_1.Table, { showHeader: false, columns: columns, dataSource: items, rowKey: "id", pagination: { hideOnSinglePage: true } }) }), (0, jsx_runtime_1.jsxs)("div", { style: {
                        float: "right",
                        fontSize: "12pt",
                        margin: "15px 15px 0 0",
                    }, children: [(0, jsx_runtime_1.jsx)("div", { style: { float: "right" }, children: (0, jsx_runtime_1.jsx)(TotalCost, { items: cart.result }) }), (0, jsx_runtime_1.jsx)("br", {})] })] }));
    }
    return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [items.length == 0 && noItems(), items.length > 0 && renderItems(), (0, jsx_runtime_1.jsx)("div", { style: {
                    marginTop: "60px",
                    border: "1px solid #eee",
                }, children: (0, jsx_runtime_1.jsx)(other_items_1.default, { onChange: reload, cart: cart }) })] }));
}
exports.default = ShoppingCart;
function TotalCost({ items }) {
    let discounted_cost = 0;
    let n = 0;
    for (const { cost, checked } of items) {
        if (checked && cost != null) {
            discounted_cost += cost.discounted_cost;
            n += 1;
        }
    }
    if (n == 0) {
        return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: "No items selected" });
    }
    return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["Subtotal (", n, " items): ", (0, jsx_runtime_1.jsx)("b", { children: (0, utils_1.money)(discounted_cost) })] }));
}
function SelectAllItems({ items, onChange }) {
    const numSelected = (0, react_1.useMemo)(() => {
        let n = 0;
        if (items == null)
            return n;
        for (const item of items) {
            if (item.checked)
                n += 1;
        }
        return n;
    }, [items]);
    if (items == null)
        return null;
    async function doSelectAll(checked) {
        await (0, post_1.default)("/shopping/cart/checked", { checked });
        onChange();
    }
    if (numSelected == 0) {
        return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["No items selected.", " ", (0, jsx_runtime_1.jsx)("a", { onClick: () => doSelectAll(true), children: "Select all items" })] }));
    }
    if (numSelected < items.length) {
        return (0, jsx_runtime_1.jsx)("a", { onClick: () => doSelectAll(true), children: "Select all items" });
    }
    return (0, jsx_runtime_1.jsx)("a", { onClick: () => doSelectAll(false), children: "Deselect all items" });
}
function CheckboxColumn({ id, checked, updating, setUpdating, isMounted, reload, }) {
    return ((0, jsx_runtime_1.jsx)(antd_1.Checkbox, { disabled: updating, checked: checked, onChange: async (e) => {
            setUpdating(true);
            try {
                await (0, post_1.default)("/shopping/cart/checked", {
                    id,
                    checked: e.target.checked,
                });
                if (!isMounted.current)
                    return;
                await reload();
            }
            finally {
                if (!isMounted.current)
                    return;
                setUpdating(false);
            }
        }, children: (0, jsx_runtime_1.jsx)("span", { className: "sr-only", children: "Select" }) }));
}
function DescriptionColumn(props) {
    const { id, cost, description, updating, setUpdating, isMounted, reload, compact, project_id, } = props;
    const router = (0, router_1.useRouter)();
    const { input } = cost;
    const [editRunLimit, setEditRunLimit] = (0, react_1.useState)(false);
    const [runLimit, setRunLimit] = (0, react_1.useState)(description.run_limit);
    const showRunLimitEditor = description.type !== "disk" && description.type !== "vm";
    function renderEditRunLimit() {
        if (!editRunLimit)
            return null;
        return ((0, jsx_runtime_1.jsxs)("div", { style: {
                border: "1px solid #eee",
                padding: "15px",
                margin: "15px 0",
                background: "white",
            }, children: [(0, jsx_runtime_1.jsx)(icon_1.Icon, { name: "times", style: { float: "right" }, onClick: () => {
                        setEditRunLimit(false);
                    } }), (0, jsx_runtime_1.jsx)(run_limit_1.EditRunLimit, { value: runLimit, onChange: setRunLimit }), (0, jsx_runtime_1.jsx)(antd_1.Button, { type: "primary", style: { marginTop: "15px" }, onClick: async () => {
                        setEditRunLimit(false);
                        await (0, post_1.default)("/shopping/cart/edit", {
                            id,
                            description: { ...description, run_limit: runLimit },
                        });
                        await reload();
                    }, children: "Save" })] }));
    }
    function renderProjectID() {
        if (!project_id || !(0, misc_1.isValidUUID)(project_id))
            return null;
        return ((0, jsx_runtime_1.jsx)(antd_1.Alert, { type: "info", banner: true, message: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["For project: ", (0, jsx_runtime_1.jsx)("code", { children: project_id })] }) }));
    }
    function editableQuota() {
        return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, describe_quota_1.describeQuotaFromInfo)(input), showRunLimitEditor && !editRunLimit && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("br", {}), (0, jsx_runtime_1.jsxs)(antd_1.Button, { onClick: () => setEditRunLimit(true), disabled: updating, style: { marginBottom: "5px" }, children: [runLimit, " simultaneous running ", (0, misc_1.plural)(runLimit, "project")] })] }))] }), renderEditRunLimit(), renderProjectID()] }));
    }
    // this could rely an the "type" field, but we rather check the data directly
    function editPage() {
        if (input.type === "disk" || input.type === "vm") {
            return "dedicated";
        }
        else if (input.boost) {
            return "boost";
        }
        return "site-license";
    }
    return ((0, jsx_runtime_1.jsxs)("div", { style: { fontSize: "12pt" }, children: [description.title && ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("b", { children: description.title }) })), description.description && (0, jsx_runtime_1.jsx)("div", { children: description.description }), (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("b", { children: input.subscription == "no"
                        ? (0, site_license_cost_1.describePeriod)({ quota: input })
                        : (0, misc_1.capitalize)(input.subscription) + " subscription" }) }), (0, jsx_runtime_1.jsxs)("div", { style: {
                    border: "1px solid lightblue",
                    background: "white",
                    padding: "15px 15px 5px 15px",
                    margin: "5px 0 10px 0",
                    borderRadius: "5px",
                }, children: [compact ? (0, site_license_cost_1.describeItem)({ info: input }) : editableQuota(), " "] }), (0, jsx_runtime_1.jsxs)(antd_1.Button, { style: { marginRight: "5px" }, onClick: () => {
                    const page = editPage();
                    router.push(`/store/${page}?id=${id}`);
                }, children: [(0, jsx_runtime_1.jsx)(icon_1.Icon, { name: "pencil" }), " Edit"] }), (0, jsx_runtime_1.jsxs)(antd_1.Button, { style: { margin: "0 5px 5px 0" }, disabled: updating, onClick: async () => {
                    setUpdating(true);
                    try {
                        await (0, post_1.default)("/shopping/cart/remove", { id });
                        if (!isMounted.current)
                            return;
                        await reload();
                    }
                    finally {
                        if (!isMounted.current)
                            return;
                        setUpdating(false);
                    }
                }, children: [(0, jsx_runtime_1.jsx)(icon_1.Icon, { name: "save" }), " Save for later"] }), (0, jsx_runtime_1.jsx)(antd_1.Popconfirm, { title: "Are you sure you want to delete this item?", onConfirm: async () => {
                    setUpdating(true);
                    try {
                        await (0, post_1.default)("/shopping/cart/delete", { id });
                        if (!isMounted.current)
                            return;
                        await reload();
                    }
                    finally {
                        if (!isMounted.current)
                            return;
                        setUpdating(false);
                    }
                }, okText: "Yes, delete this item", cancelText: "Cancel", children: (0, jsx_runtime_1.jsxs)(antd_1.Button, { disabled: updating, type: "dashed", children: [(0, jsx_runtime_1.jsx)(icon_1.Icon, { name: "trash" }), " Delete"] }) })] }));
}
//# sourceMappingURL=cart.js.map