Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/src/packages/next/components/store/processing.tsx
Views: 791
/*1Page that you show user after they start a purchase and are waiting2for the payment to be completed and items to be allocated.3*/45import A from "components/misc/A";6import ShowError from "@cocalc/frontend/components/error";7import { Alert, Button, Divider, Spin, Table } from "antd";8import Loading from "components/share/loading";9import useIsMounted from "lib/hooks/mounted";10import { useEffect, useRef, useState } from "react";11import { Icon } from "@cocalc/frontend/components/icon";12import { type CheckoutParams } from "@cocalc/server/purchases/shopping-cart-checkout";13import Payments from "@cocalc/frontend/purchases/payments";14import { getColumns } from "./checkout";15import { getShoppingCartCheckoutParams } from "@cocalc/frontend/purchases/api";16import { SHOPPING_CART_CHECKOUT } from "@cocalc/util/db-schema/purchases";17import { useRouter } from "next/router";1819export default function Processing() {20const router = useRouter();21const [finished, setFinished] = useState<boolean>(false);22const [error, setError] = useState<string>("");23const [loading, setLoading] = useState<boolean>(false);24const [params, setParams] = useState<CheckoutParams | null>(null);25const refreshPaymentsRef = useRef<any>(null);26const numPaymentsRef = useRef<number | null>(null);27const updateParams = async () => {28try {29setError("");30setLoading(true);31// Get what has NOT been processed.32const params = await getShoppingCartCheckoutParams({33processing: true,34});35setParams(params);36} catch (err) {37setError(`${err}`);38} finally {39setLoading(false);40}41};4243useEffect(() => {44if (45params?.cart != null &&46params.cart.length == 0 &&47numPaymentsRef.current === 048) {49setFinished(true);50}51}, [params]);5253const lastRefreshRef = useRef<number>(0);54const refreshRef = useRef<Function>(() => {});55refreshRef.current = async () => {56const now = Date.now();57if (now - lastRefreshRef.current < 3000) {58return;59}60lastRefreshRef.current = now;61await updateParams();62await refreshPaymentsRef.current?.();63};6465// exponential backoff auto-refresh66const isMounted = useIsMounted();67const timeoutRef = useRef<any>(null);68useEffect(() => {69if (finished) {70// nothing left to do71return;72}73let delay = 5000;74const f = () => {75if (!isMounted.current) {76return;77}78delay = Math.min(5 * 60 * 1000, 1.3 * delay);79timeoutRef.current = setTimeout(f, delay);80refreshRef.current();81};82f();8384return () => {85if (timeoutRef.current) {86clearTimeout(timeoutRef.current);87timeoutRef.current = null;88}89};90}, [finished]);9192function renderBody() {93if (error) {94return <ShowError error={error} setError={setError} />;95}96if (finished) {97return (98<div>99<Alert100type="success"101showIcon102style={{ margin: "30px auto", maxWidth: "700px" }}103message="Success"104description=<>105Congratulations, all your purchases have been processed and are106ready to use!107<div style={{ textAlign: "center", marginTop: "30px" }}>108<Button109size="large"110type="primary"111onClick={() => {112router.push("/store/congrats");113}}114>115Congrats! View Your Items...116</Button>117</div>118</>119/>120121<Payments122unfinished123canceled124purpose={SHOPPING_CART_CHECKOUT}125refresh={() => {126refreshRef.current();127}}128numPaymentsRef={numPaymentsRef}129refreshPaymentsRef={refreshPaymentsRef}130/>131</div>132);133}134135if (params?.cart == null) {136return null;137}138139const done = !numPaymentsRef.current || params.cart.length == 0;140141return (142<>143{!done && (144<Alert145type="warning"146showIcon147style={{ margin: "30px auto", maxWidth: "700px" }}148message="Status"149description=<>150Your items will be added to your account when the outstanding151payment listed below goes through. You can update any payment152configuration or cancel an unfinished payment below.153</>154/>155)}156157{done && (158<Alert159type="success"160showIcon161style={{ margin: "30px auto", maxWidth: "700px" }}162message="Thank you"163description=<>164Your items should be allocated soon{" "}165<A href="/store/congrats">(check the Congrats tab)</A>, or in case166you canceled your payment, put back in your shopping cart.167</>168/>169)}170171<Payments172unfinished173canceled174purpose={SHOPPING_CART_CHECKOUT}175refresh={() => {176refreshRef.current();177}}178numPaymentsRef={numPaymentsRef}179refreshPaymentsRef={refreshPaymentsRef}180/>181182<Divider orientation="left" style={{ marginTop: "30px" }}>183Your Items184</Divider>185{params != null && (186<Table187showHeader={false}188columns={getColumns()}189dataSource={params?.cart}190rowKey={"id"}191pagination={{ hideOnSinglePage: true }}192/>193)}194</>195);196}197198return (199<div>200<Button201style={{ float: "right" }}202disabled={loading || finished}203onClick={() => {204refreshRef.current();205}}206>207Check Order Status {loading && <Spin />}208</Button>209<h3>210<Icon name="run" /> Order Processing211</h3>212{loading && <Loading large center />}213{renderBody()}214</div>215);216}217218219