Payment stuff, cont'd
This commit is contained in:
parent
f7f7f469ad
commit
c06bfb989e
11 changed files with 457 additions and 309 deletions
|
@ -1,6 +1,6 @@
|
|||
import * as React from 'react';
|
||||
import {useContext, useState} from 'react';
|
||||
import {LinearProgress, Stack, useMediaQuery} from "@mui/material";
|
||||
import {Alert, LinearProgress, Stack, useMediaQuery} from "@mui/material";
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import Typography from "@mui/material/Typography";
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
|
@ -18,7 +18,7 @@ import TextField from "@mui/material/TextField";
|
|||
import DialogActions from "@mui/material/DialogActions";
|
||||
import routes from "./routes";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import {formatBytes} from "../app/utils";
|
||||
import {formatBytes, formatShortDateTime} from "../app/utils";
|
||||
import accountApi, {UnauthorizedError} from "../app/AccountApi";
|
||||
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
|
||||
import {Pref, PrefGroup} from "./Pref";
|
||||
|
@ -28,6 +28,7 @@ import humanizeDuration from "humanize-duration";
|
|||
import UpgradeDialog from "./UpgradeDialog";
|
||||
import CelebrationIcon from "@mui/icons-material/Celebration";
|
||||
import {AccountContext} from "./App";
|
||||
import {Warning, WarningAmber} from "@mui/icons-material";
|
||||
|
||||
const Account = () => {
|
||||
if (!session.exists()) {
|
||||
|
@ -183,7 +184,7 @@ const Stats = () => {
|
|||
const handleManageBilling = async () => {
|
||||
try {
|
||||
const response = await accountApi.createBillingPortalSession();
|
||||
window.location.href = response.redirect_url;
|
||||
window.open(response.redirect_url, "billing_portal");
|
||||
} catch (e) {
|
||||
console.log(`[Account] Error changing password`, e);
|
||||
if ((e instanceof UnauthorizedError)) {
|
||||
|
@ -199,7 +200,10 @@ const Stats = () => {
|
|||
{t("account_usage_title")}
|
||||
</Typography>
|
||||
<PrefGroup>
|
||||
<Pref title={t("account_usage_tier_title")}>
|
||||
<Pref
|
||||
alignTop={account.billing?.status === "past_due"}
|
||||
title={t("account_usage_tier_title")}
|
||||
>
|
||||
<div>
|
||||
{account.role === "admin" &&
|
||||
<>
|
||||
|
@ -219,26 +223,29 @@ const Stats = () => {
|
|||
>{t("account_usage_tier_upgrade_button")}</Button>
|
||||
}
|
||||
{config.enable_payments && account.role === "user" && account.tier?.paid &&
|
||||
<>
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
onClick={() => setUpgradeDialogOpen(true)}
|
||||
sx={{ml: 1}}
|
||||
>{t("account_usage_tier_change_button")}</Button>
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
onClick={handleManageBilling}
|
||||
sx={{ml: 1}}
|
||||
>Manage billing</Button>
|
||||
</>
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
onClick={() => setUpgradeDialogOpen(true)}
|
||||
sx={{ml: 1}}
|
||||
>{t("account_usage_tier_change_button")}</Button>
|
||||
}
|
||||
{config.enable_payments && account.role === "user" && account.billing?.customer &&
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
onClick={handleManageBilling}
|
||||
sx={{ml: 1}}
|
||||
>{t("account_usage_manage_billing_button")}</Button>
|
||||
}
|
||||
<UpgradeDialog
|
||||
open={upgradeDialogOpen}
|
||||
onCancel={() => setUpgradeDialogOpen(false)}
|
||||
/>
|
||||
</div>
|
||||
{account.billing?.status === "past_due" &&
|
||||
<Alert severity="error" sx={{mt: 1}}>{t("account_usage_tier_payment_overdue")}</Alert>
|
||||
}
|
||||
</Pref>
|
||||
{account.role !== "admin" &&
|
||||
<Pref title={t("account_usage_reservations_title")}>
|
||||
|
|
|
@ -17,16 +17,20 @@ import {AccountContext} from "./App";
|
|||
const UpgradeDialog = (props) => {
|
||||
const { account } = useContext(AccountContext);
|
||||
const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
||||
const [selected, setSelected] = useState(account?.tier?.code || null);
|
||||
const [newTier, setNewTier] = useState(account?.tier?.code || null);
|
||||
const [errorText, setErrorText] = useState("");
|
||||
|
||||
const handleCheckout = async () => {
|
||||
try {
|
||||
const response = await accountApi.createCheckoutSession(selected);
|
||||
if (response.redirect_url) {
|
||||
window.location.href = response.redirect_url;
|
||||
if (newTier == null) {
|
||||
await accountApi.deleteBillingSubscription();
|
||||
} else {
|
||||
await accountApi.sync();
|
||||
const response = await accountApi.updateBillingSubscription(newTier);
|
||||
if (response.redirect_url) {
|
||||
window.location.href = response.redirect_url;
|
||||
} else {
|
||||
await accountApi.sync();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
|
@ -46,10 +50,10 @@ const UpgradeDialog = (props) => {
|
|||
display: "flex",
|
||||
flexDirection: "row"
|
||||
}}>
|
||||
<TierCard code={null} name={"Free"} selected={selected === null} onClick={() => setSelected(null)}/>
|
||||
<TierCard code="starter" name={"Starter"} selected={selected === "starter"} onClick={() => setSelected("starter")}/>
|
||||
<TierCard code="pro" name={"Pro"} selected={selected === "pro"} onClick={() => setSelected("pro")}/>
|
||||
<TierCard code="business" name={"Business"} selected={selected === "business"} onClick={() => setSelected("business")}/>
|
||||
<TierCard code={null} name={"Free"} selected={newTier === null} onClick={() => setNewTier(null)}/>
|
||||
<TierCard code="starter" name={"Starter"} selected={newTier === "starter"} onClick={() => setNewTier("starter")}/>
|
||||
<TierCard code="pro" name={"Pro"} selected={newTier === "pro"} onClick={() => setNewTier("pro")}/>
|
||||
<TierCard code="business" name={"Business"} selected={newTier === "business"} onClick={() => setNewTier("business")}/>
|
||||
</div>
|
||||
</DialogContent>
|
||||
<DialogFooter status={errorText}>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue