Upgrade dialog looks nice now
This commit is contained in:
parent
695c1349e8
commit
4092f7fd51
9 changed files with 160 additions and 85 deletions
|
@ -202,8 +202,17 @@
|
|||
"account_delete_dialog_button_cancel": "Cancel",
|
||||
"account_delete_dialog_button_submit": "Permanently delete account",
|
||||
"account_upgrade_dialog_title": "Change account tier",
|
||||
"account_upgrade_dialog_cancel_warning": "This will cancel your subscription, and downgrade your account on {{date}}. On that date, topic reservations as well as messages cached on the server will be deleted.",
|
||||
"account_upgrade_dialog_proration_info": "When switching between paid plans, the price difference will be charged or refunded in the next invoice.",
|
||||
"account_upgrade_dialog_cancel_warning": "This will <strong>cancel your subscription</strong>, and downgrade your account on {{date}}. On that date, topic reservations as well as messages cached on the server <strong>will be deleted</strong>.",
|
||||
"account_upgrade_dialog_proration_info": "<strong>Proration</strong>: When switching between paid plans, the price difference will be charged or refunded in the next invoice. You will not receive another invoice until the end of the next billing period.",
|
||||
"account_upgrade_dialog_tier_features_reservations": "{{reservations}} reserved topics",
|
||||
"account_upgrade_dialog_tier_features_messages": "{{messages}} daily messages",
|
||||
"account_upgrade_dialog_tier_features_emails": "{{emails}} daily emails",
|
||||
"account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} per file",
|
||||
"account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} total storage",
|
||||
"account_upgrade_dialog_tier_selected_label": "Selected",
|
||||
"account_upgrade_dialog_button_pay_now": "Pay now and subscribe",
|
||||
"account_upgrade_dialog_button_cancel_subscription": "Cancel subscription",
|
||||
"account_upgrade_dialog_button_update_subscription": "Update subscription",
|
||||
"prefs_notifications_title": "Notifications",
|
||||
"prefs_notifications_sound_title": "Notification sound",
|
||||
"prefs_notifications_sound_description_none": "Notifications do not play any sound when they arrive",
|
||||
|
|
|
@ -199,6 +199,13 @@ export const formatBytes = (bytes, decimals = 2) => {
|
|||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
export const formatNumber = (n) => {
|
||||
if (n % 1000 === 0) {
|
||||
return `${n/1000}k`;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
export const openUrl = (url) => {
|
||||
window.open(url, "_blank", "noopener,noreferrer");
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as React from 'react';
|
|||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import {Alert, CardActionArea, CardContent, useMediaQuery} from "@mui/material";
|
||||
import {Alert, CardActionArea, CardContent, ListItem, useMediaQuery} from "@mui/material";
|
||||
import theme from "./theme";
|
||||
import DialogFooter from "./DialogFooter";
|
||||
import Button from "@mui/material/Button";
|
||||
|
@ -13,16 +13,20 @@ import {useContext, useEffect, useState} from "react";
|
|||
import Card from "@mui/material/Card";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import {AccountContext} from "./App";
|
||||
import {formatShortDate} from "../app/utils";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {formatBytes, formatNumber, formatShortDate} from "../app/utils";
|
||||
import {Trans, useTranslation} from "react-i18next";
|
||||
import subscriptionManager from "../app/SubscriptionManager";
|
||||
import List from "@mui/material/List";
|
||||
import {Check} from "@mui/icons-material";
|
||||
import ListItemIcon from "@mui/material/ListItemIcon";
|
||||
import ListItemText from "@mui/material/ListItemText";
|
||||
|
||||
const UpgradeDialog = (props) => {
|
||||
const { t } = useTranslation();
|
||||
const { account } = useContext(AccountContext);
|
||||
const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
||||
const [tiers, setTiers] = useState(null);
|
||||
const [newTier, setNewTier] = useState(account?.tier?.code || null);
|
||||
const [newTier, setNewTier] = useState(account?.tier?.code); // May be undefined
|
||||
const [errorText, setErrorText] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -35,22 +39,22 @@ const UpgradeDialog = (props) => {
|
|||
return <></>;
|
||||
}
|
||||
|
||||
const currentTier = account.tier?.code || null;
|
||||
const currentTier = account.tier?.code; // May be undefined
|
||||
let action, submitButtonLabel, submitButtonEnabled;
|
||||
if (currentTier === newTier) {
|
||||
submitButtonLabel = "Update subscription";
|
||||
submitButtonLabel = t("account_upgrade_dialog_button_update_subscription");
|
||||
submitButtonEnabled = false;
|
||||
action = null;
|
||||
} else if (currentTier === null) {
|
||||
submitButtonLabel = "Pay $5 now and subscribe";
|
||||
} else if (!currentTier) {
|
||||
submitButtonLabel = t("account_upgrade_dialog_button_pay_now");
|
||||
submitButtonEnabled = true;
|
||||
action = Action.CREATE;
|
||||
} else if (newTier === null) {
|
||||
submitButtonLabel = "Cancel subscription";
|
||||
} else if (!newTier) {
|
||||
submitButtonLabel = t("account_upgrade_dialog_button_cancel_subscription");
|
||||
submitButtonEnabled = true;
|
||||
action = Action.CANCEL;
|
||||
} else {
|
||||
submitButtonLabel = "Update subscription";
|
||||
submitButtonLabel = t("account_upgrade_dialog_button_update_subscription");
|
||||
submitButtonEnabled = true;
|
||||
action = Action.UPDATE;
|
||||
}
|
||||
|
@ -76,7 +80,13 @@ const UpgradeDialog = (props) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<Dialog open={props.open} onClose={props.onCancel} maxWidth="md" fullScreen={fullScreen}>
|
||||
<Dialog
|
||||
open={props.open}
|
||||
onClose={props.onCancel}
|
||||
maxWidth="md"
|
||||
fullWidth
|
||||
fullScreen={fullScreen}
|
||||
>
|
||||
<DialogTitle>{t("account_upgrade_dialog_title")}</DialogTitle>
|
||||
<DialogContent>
|
||||
<div style={{
|
||||
|
@ -85,33 +95,25 @@ const UpgradeDialog = (props) => {
|
|||
marginBottom: "8px",
|
||||
width: "100%"
|
||||
}}>
|
||||
<TierCard
|
||||
code={null}
|
||||
name={t("account_usage_tier_free")}
|
||||
price={null}
|
||||
selected={newTier === null}
|
||||
onClick={() => setNewTier(null)}
|
||||
/>
|
||||
{tiers.map(tier =>
|
||||
<TierCard
|
||||
key={`tierCard${tier.code}`}
|
||||
code={tier.code}
|
||||
name={tier.name}
|
||||
price={tier.price}
|
||||
features={tier.features}
|
||||
selected={newTier === tier.code}
|
||||
onClick={() => setNewTier(tier.code)}
|
||||
key={`tierCard${tier.code || '_free'}`}
|
||||
tier={tier}
|
||||
selected={newTier === tier.code} // tier.code may be undefined!
|
||||
onClick={() => setNewTier(tier.code)} // tier.code may be undefined!
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{action === Action.CANCEL &&
|
||||
<Alert severity="warning">
|
||||
{t("account_upgrade_dialog_cancel_warning", { date: formatShortDate(account.billing.paid_until) })}
|
||||
<Trans
|
||||
i18nKey="account_upgrade_dialog_cancel_warning"
|
||||
values={{ date: formatShortDate(account.billing.paid_until) }} />
|
||||
</Alert>
|
||||
}
|
||||
{action === Action.UPDATE &&
|
||||
{currentTier && (!action || action === Action.UPDATE) &&
|
||||
<Alert severity="info">
|
||||
{t("account_upgrade_dialog_proration_info")}
|
||||
<Trans i18nKey="account_upgrade_dialog_proration_info" />
|
||||
</Alert>
|
||||
}
|
||||
</DialogContent>
|
||||
|
@ -124,12 +126,18 @@ const UpgradeDialog = (props) => {
|
|||
};
|
||||
|
||||
const TierCard = (props) => {
|
||||
const cardStyle = (props.selected) ? { background: "#eee", border: "2px solid #338574" } : {};
|
||||
const { t } = useTranslation();
|
||||
const cardStyle = (props.selected) ? { background: "#eee", border: "2px solid #338574" } : { border: "2px solid transparent" };
|
||||
const tier = props.tier;
|
||||
|
||||
return (
|
||||
<Card sx={{
|
||||
m: 1,
|
||||
minWidth: "190px",
|
||||
maxWidth: "250px",
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
flexBasis: 0,
|
||||
"&:first-child": { ml: 0 },
|
||||
"&:last-child": { mr: 0 },
|
||||
...cardStyle
|
||||
|
@ -145,19 +153,21 @@ const TierCard = (props) => {
|
|||
background: "#338574",
|
||||
color: "white",
|
||||
borderRadius: "3px",
|
||||
}}>Selected</div>
|
||||
}}>{t("account_upgrade_dialog_tier_selected_label")}</div>
|
||||
}
|
||||
<Typography gutterBottom variant="h5" component="div">
|
||||
{props.name}
|
||||
<Typography variant="h5" component="div">
|
||||
{tier.name || t("account_usage_tier_free")}
|
||||
</Typography>
|
||||
{props.features &&
|
||||
<Typography variant="body2" color="text.secondary" sx={{whiteSpace: "pre-wrap"}}>
|
||||
{props.features}
|
||||
</Typography>
|
||||
}
|
||||
{props.price &&
|
||||
<Typography variant="subtitle1" sx={{mt: 1}}>
|
||||
{props.price} / month
|
||||
<List dense>
|
||||
{tier.limits.reservations > 0 && <FeatureItem>{t("account_upgrade_dialog_tier_features_reservations", { reservations: tier.limits.reservations })}</FeatureItem>}
|
||||
<FeatureItem>{t("account_upgrade_dialog_tier_features_messages", { messages: formatNumber(tier.limits.messages) })}</FeatureItem>
|
||||
<FeatureItem>{t("account_upgrade_dialog_tier_features_emails", { emails: formatNumber(tier.limits.emails) })}</FeatureItem>
|
||||
<FeatureItem>{t("account_upgrade_dialog_tier_features_attachment_file_size", { filesize: formatBytes(tier.limits.attachment_file_size, 0) })}</FeatureItem>
|
||||
<FeatureItem>{t("account_upgrade_dialog_tier_features_attachment_total_size", { totalsize: formatBytes(tier.limits.attachment_total_size, 0) })}</FeatureItem>
|
||||
</List>
|
||||
{tier.price &&
|
||||
<Typography variant="subtitle1" sx={{fontWeight: 500}}>
|
||||
{tier.price} / month
|
||||
</Typography>
|
||||
}
|
||||
</CardContent>
|
||||
|
@ -166,6 +176,25 @@ const TierCard = (props) => {
|
|||
);
|
||||
}
|
||||
|
||||
const FeatureItem = (props) => {
|
||||
return (
|
||||
<ListItem disableGutters sx={{m: 0, p: 0}}>
|
||||
<ListItemIcon sx={{minWidth: "24px"}}>
|
||||
<Check fontSize="small" sx={{ color: "#338574" }}/>
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
sx={{mt: "2px", mb: "2px"}}
|
||||
primary={
|
||||
<Typography variant="body2">
|
||||
{props.children}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
const Action = {
|
||||
CREATE: 1,
|
||||
UPDATE: 2,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue