JS constants
This commit is contained in:
parent
ef8f7c9884
commit
259293f9b3
8 changed files with 77 additions and 44 deletions
|
@ -43,7 +43,6 @@ import (
|
||||||
- MEDIUM: Reservation (UI): Ask for confirmation when removing reservation (deadcade)
|
- MEDIUM: Reservation (UI): Ask for confirmation when removing reservation (deadcade)
|
||||||
- MEDIUM: Reservation table delete button: dialog "keep or delete messages?"
|
- MEDIUM: Reservation table delete button: dialog "keep or delete messages?"
|
||||||
- LOW: UI: Flickering upgrade banner when logging in
|
- LOW: UI: Flickering upgrade banner when logging in
|
||||||
- LOW: JS constants
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
import {
|
import {
|
||||||
|
accountBillingPortalUrl,
|
||||||
|
accountBillingSubscriptionUrl,
|
||||||
|
accountPasswordUrl,
|
||||||
accountReservationSingleUrl,
|
accountReservationSingleUrl,
|
||||||
accountReservationUrl,
|
accountReservationUrl,
|
||||||
accountPasswordUrl,
|
|
||||||
accountSettingsUrl,
|
accountSettingsUrl,
|
||||||
accountSubscriptionSingleUrl,
|
accountSubscriptionSingleUrl,
|
||||||
accountSubscriptionUrl,
|
accountSubscriptionUrl,
|
||||||
accountTokenUrl,
|
accountTokenUrl,
|
||||||
accountUrl, maybeWithAuth, topicUrl,
|
accountUrl,
|
||||||
|
tiersUrl,
|
||||||
withBasicAuth,
|
withBasicAuth,
|
||||||
withBearerAuth, accountBillingSubscriptionUrl, accountBillingPortalUrl, tiersUrl
|
withBearerAuth
|
||||||
} from "./utils";
|
} from "./utils";
|
||||||
import session from "./Session";
|
import session from "./Session";
|
||||||
import subscriptionManager from "./SubscriptionManager";
|
import subscriptionManager from "./SubscriptionManager";
|
||||||
import i18n from "i18next";
|
import i18n from "i18next";
|
||||||
import prefs from "./Prefs";
|
import prefs from "./Prefs";
|
||||||
import routes from "../components/routes";
|
import routes from "../components/routes";
|
||||||
import userManager from "./UserManager";
|
|
||||||
|
|
||||||
const delayMillis = 45000; // 45 seconds
|
const delayMillis = 45000; // 45 seconds
|
||||||
const intervalMillis = 900000; // 15 minutes
|
const intervalMillis = 900000; // 15 minutes
|
||||||
|
@ -441,6 +443,32 @@ class AccountApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Maps to user.Role in user/types.go
|
||||||
|
export const Role = {
|
||||||
|
ADMIN: "admin",
|
||||||
|
USER: "user"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Maps to server.visitorLimitBasis in server/visitor.go
|
||||||
|
export const LimitBasis = {
|
||||||
|
IP: "ip",
|
||||||
|
TIER: "tier"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Maps to stripe.SubscriptionStatus
|
||||||
|
export const SubscriptionStatus = {
|
||||||
|
ACTIVE: "active",
|
||||||
|
PAST_DUE: "past_due"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Maps to user.Permission in user/types.go
|
||||||
|
export const Permission = {
|
||||||
|
READ_WRITE: "read-write",
|
||||||
|
READ_ONLY: "read-only",
|
||||||
|
WRITE_ONLY: "write-only",
|
||||||
|
DENY_ALL: "deny-all"
|
||||||
|
};
|
||||||
|
|
||||||
export class UsernameTakenError extends Error {
|
export class UsernameTakenError extends Error {
|
||||||
constructor(username) {
|
constructor(username) {
|
||||||
super("Username taken");
|
super("Username taken");
|
||||||
|
|
|
@ -28,7 +28,13 @@ import TextField from "@mui/material/TextField";
|
||||||
import routes from "./routes";
|
import routes from "./routes";
|
||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import {formatBytes, formatShortDate, formatShortDateTime, openUrl, truncateString, validUrl} from "../app/utils";
|
import {formatBytes, formatShortDate, formatShortDateTime, openUrl, truncateString, validUrl} from "../app/utils";
|
||||||
import accountApi, {IncorrectPasswordError, UnauthorizedError} from "../app/AccountApi";
|
import accountApi, {
|
||||||
|
IncorrectPasswordError,
|
||||||
|
LimitBasis,
|
||||||
|
Role,
|
||||||
|
SubscriptionStatus,
|
||||||
|
UnauthorizedError
|
||||||
|
} from "../app/AccountApi";
|
||||||
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
|
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
|
||||||
import {Pref, PrefGroup} from "./Pref";
|
import {Pref, PrefGroup} from "./Pref";
|
||||||
import db from "../app/db";
|
import db from "../app/db";
|
||||||
|
@ -92,7 +98,7 @@ const Username = () => {
|
||||||
<Pref labelId={labelId} title={t("account_basics_username_title")} description={t("account_basics_username_description")}>
|
<Pref labelId={labelId} title={t("account_basics_username_title")} description={t("account_basics_username_description")}>
|
||||||
<div aria-labelledby={labelId}>
|
<div aria-labelledby={labelId}>
|
||||||
{session.username()}
|
{session.username()}
|
||||||
{account?.role === "admin"
|
{account?.role === Role.ADMIN
|
||||||
? <>{" "}<Tooltip title={t("account_basics_username_admin_tooltip")}><span style={{cursor: "default"}}>👑</span></Tooltip></>
|
? <>{" "}<Tooltip title={t("account_basics_username_admin_tooltip")}><span style={{cursor: "default"}}>👑</span></Tooltip></>
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
|
@ -237,7 +243,7 @@ const AccountType = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
let accountType;
|
let accountType;
|
||||||
if (account.role === "admin") {
|
if (account.role === Role.ADMIN) {
|
||||||
const tierSuffix = (account.tier) ? `(with ${account.tier.name} tier)` : `(no tier)`;
|
const tierSuffix = (account.tier) ? `(with ${account.tier.name} tier)` : `(no tier)`;
|
||||||
accountType = `${t("account_usage_tier_admin")} ${tierSuffix}`;
|
accountType = `${t("account_usage_tier_admin")} ${tierSuffix}`;
|
||||||
} else if (!account.tier) {
|
} else if (!account.tier) {
|
||||||
|
@ -248,7 +254,7 @@ const AccountType = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pref
|
<Pref
|
||||||
alignTop={account.billing?.status === "past_due" || account.billing?.cancel_at > 0}
|
alignTop={account.billing?.status === SubscriptionStatus.PAST_DUE || account.billing?.cancel_at > 0}
|
||||||
title={t("account_usage_tier_title")}
|
title={t("account_usage_tier_title")}
|
||||||
description={t("account_usage_tier_description")}
|
description={t("account_usage_tier_description")}
|
||||||
>
|
>
|
||||||
|
@ -259,7 +265,7 @@ const AccountType = () => {
|
||||||
<span><InfoIcon/></span>
|
<span><InfoIcon/></span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
{config.enable_payments && account.role === "user" && !account.billing?.subscription &&
|
{config.enable_payments && account.role === Role.USER && !account.billing?.subscription &&
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
size="small"
|
size="small"
|
||||||
|
@ -268,7 +274,7 @@ const AccountType = () => {
|
||||||
sx={{ml: 1}}
|
sx={{ml: 1}}
|
||||||
>{t("account_usage_tier_upgrade_button")}</Button>
|
>{t("account_usage_tier_upgrade_button")}</Button>
|
||||||
}
|
}
|
||||||
{config.enable_payments && account.role === "user" && account.billing?.subscription &&
|
{config.enable_payments && account.role === Role.USER && account.billing?.subscription &&
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
size="small"
|
size="small"
|
||||||
|
@ -276,7 +282,7 @@ const AccountType = () => {
|
||||||
sx={{ml: 1}}
|
sx={{ml: 1}}
|
||||||
>{t("account_usage_tier_change_button")}</Button>
|
>{t("account_usage_tier_change_button")}</Button>
|
||||||
}
|
}
|
||||||
{config.enable_payments && account.role === "user" && account.billing?.customer &&
|
{config.enable_payments && account.role === Role.USER && account.billing?.customer &&
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
size="small"
|
size="small"
|
||||||
|
@ -290,7 +296,7 @@ const AccountType = () => {
|
||||||
onCancel={() => setUpgradeDialogOpen(false)}
|
onCancel={() => setUpgradeDialogOpen(false)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{account.billing?.status === "past_due" &&
|
{account.billing?.status === SubscriptionStatus.PAST_DUE &&
|
||||||
<Alert severity="error" sx={{mt: 1}}>{t("account_usage_tier_payment_overdue")}</Alert>
|
<Alert severity="error" sx={{mt: 1}}>{t("account_usage_tier_payment_overdue")}</Alert>
|
||||||
}
|
}
|
||||||
{account.billing?.cancel_at > 0 &&
|
{account.billing?.cancel_at > 0 &&
|
||||||
|
@ -318,7 +324,7 @@ const Stats = () => {
|
||||||
{t("account_usage_title")}
|
{t("account_usage_title")}
|
||||||
</Typography>
|
</Typography>
|
||||||
<PrefGroup>
|
<PrefGroup>
|
||||||
{account.role !== "admin" &&
|
{account.role === Role.USER &&
|
||||||
<Pref title={t("account_usage_reservations_title")}>
|
<Pref title={t("account_usage_reservations_title")}>
|
||||||
{account.limits.reservations > 0 &&
|
{account.limits.reservations > 0 &&
|
||||||
<>
|
<>
|
||||||
|
@ -326,7 +332,7 @@ const Stats = () => {
|
||||||
<Typography variant="body2"
|
<Typography variant="body2"
|
||||||
sx={{float: "left"}}>{account.stats.reservations}</Typography>
|
sx={{float: "left"}}>{account.stats.reservations}</Typography>
|
||||||
<Typography variant="body2"
|
<Typography variant="body2"
|
||||||
sx={{float: "right"}}>{account.role === "user" ? t("account_usage_of_limit", {limit: account.limits.reservations}) : t("account_usage_unlimited")}</Typography>
|
sx={{float: "right"}}>{account.role === Role.USER ? t("account_usage_of_limit", {limit: account.limits.reservations}) : t("account_usage_unlimited")}</Typography>
|
||||||
</div>
|
</div>
|
||||||
<LinearProgress
|
<LinearProgress
|
||||||
variant="determinate"
|
variant="determinate"
|
||||||
|
@ -347,11 +353,11 @@ const Stats = () => {
|
||||||
}>
|
}>
|
||||||
<div>
|
<div>
|
||||||
<Typography variant="body2" sx={{float: "left"}}>{account.stats.messages}</Typography>
|
<Typography variant="body2" sx={{float: "left"}}>{account.stats.messages}</Typography>
|
||||||
<Typography variant="body2" sx={{float: "right"}}>{account.role === "user" ? t("account_usage_of_limit", { limit: account.limits.messages }) : t("account_usage_unlimited")}</Typography>
|
<Typography variant="body2" sx={{float: "right"}}>{account.role === Role.USER ? t("account_usage_of_limit", { limit: account.limits.messages }) : t("account_usage_unlimited")}</Typography>
|
||||||
</div>
|
</div>
|
||||||
<LinearProgress
|
<LinearProgress
|
||||||
variant="determinate"
|
variant="determinate"
|
||||||
value={account.role === "user" ? normalize(account.stats.messages, account.limits.messages) : 100}
|
value={account.role === Role.USER ? normalize(account.stats.messages, account.limits.messages) : 100}
|
||||||
/>
|
/>
|
||||||
</Pref>
|
</Pref>
|
||||||
<Pref title={
|
<Pref title={
|
||||||
|
@ -362,11 +368,11 @@ const Stats = () => {
|
||||||
}>
|
}>
|
||||||
<div>
|
<div>
|
||||||
<Typography variant="body2" sx={{float: "left"}}>{account.stats.emails}</Typography>
|
<Typography variant="body2" sx={{float: "left"}}>{account.stats.emails}</Typography>
|
||||||
<Typography variant="body2" sx={{float: "right"}}>{account.role === "user" ? t("account_usage_of_limit", { limit: account.limits.emails }) : t("account_usage_unlimited")}</Typography>
|
<Typography variant="body2" sx={{float: "right"}}>{account.role === Role.USER ? t("account_usage_of_limit", { limit: account.limits.emails }) : t("account_usage_unlimited")}</Typography>
|
||||||
</div>
|
</div>
|
||||||
<LinearProgress
|
<LinearProgress
|
||||||
variant="determinate"
|
variant="determinate"
|
||||||
value={account.role === "user" ? normalize(account.stats.emails, account.limits.emails) : 100}
|
value={account.role === Role.USER ? normalize(account.stats.emails, account.limits.emails) : 100}
|
||||||
/>
|
/>
|
||||||
</Pref>
|
</Pref>
|
||||||
<Pref
|
<Pref
|
||||||
|
@ -382,15 +388,15 @@ const Stats = () => {
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Typography variant="body2" sx={{float: "left"}}>{formatBytes(account.stats.attachment_total_size)}</Typography>
|
<Typography variant="body2" sx={{float: "left"}}>{formatBytes(account.stats.attachment_total_size)}</Typography>
|
||||||
<Typography variant="body2" sx={{float: "right"}}>{account.role === "user" ? t("account_usage_of_limit", { limit: formatBytes(account.limits.attachment_total_size) }) : t("account_usage_unlimited")}</Typography>
|
<Typography variant="body2" sx={{float: "right"}}>{account.role === Role.USER ? t("account_usage_of_limit", { limit: formatBytes(account.limits.attachment_total_size) }) : t("account_usage_unlimited")}</Typography>
|
||||||
</div>
|
</div>
|
||||||
<LinearProgress
|
<LinearProgress
|
||||||
variant="determinate"
|
variant="determinate"
|
||||||
value={account.role === "user" ? normalize(account.stats.attachment_total_size, account.limits.attachment_total_size) : 100}
|
value={account.role === Role.USER ? normalize(account.stats.attachment_total_size, account.limits.attachment_total_size) : 100}
|
||||||
/>
|
/>
|
||||||
</Pref>
|
</Pref>
|
||||||
</PrefGroup>
|
</PrefGroup>
|
||||||
{account.role === "user" && account.limits.basis === "ip" &&
|
{account.role === Role.USER && account.limits.basis === LimitBasis.IP &&
|
||||||
<Typography variant="body1">
|
<Typography variant="body1">
|
||||||
{t("account_usage_basis_ip_description")}
|
{t("account_usage_basis_ip_description")}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
|
@ -28,7 +28,7 @@ import config from "../app/config";
|
||||||
import ArticleIcon from '@mui/icons-material/Article';
|
import ArticleIcon from '@mui/icons-material/Article';
|
||||||
import {Trans, useTranslation} from "react-i18next";
|
import {Trans, useTranslation} from "react-i18next";
|
||||||
import session from "../app/Session";
|
import session from "../app/Session";
|
||||||
import accountApi from "../app/AccountApi";
|
import accountApi, {Permission, Role} from "../app/AccountApi";
|
||||||
import CelebrationIcon from '@mui/icons-material/Celebration';
|
import CelebrationIcon from '@mui/icons-material/Celebration';
|
||||||
import UpgradeDialog from "./UpgradeDialog";
|
import UpgradeDialog from "./UpgradeDialog";
|
||||||
import {AccountContext} from "./App";
|
import {AccountContext} from "./App";
|
||||||
|
@ -104,7 +104,7 @@ const NavList = (props) => {
|
||||||
navigate(routes.account);
|
navigate(routes.account);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isAdmin = account?.role === "admin";
|
const isAdmin = account?.role === Role.ADMIN;
|
||||||
const isPaid = account?.billing?.subscription;
|
const isPaid = account?.billing?.subscription;
|
||||||
const showUpgradeBanner = config.enable_payments && !isAdmin && !isPaid;
|
const showUpgradeBanner = config.enable_payments && !isAdmin && !isPaid;
|
||||||
const showSubscriptionsList = props.subscriptions?.length > 0;
|
const showSubscriptionsList = props.subscriptions?.length > 0;
|
||||||
|
@ -264,16 +264,16 @@ const SubscriptionItem = (props) => {
|
||||||
<ListItemText primary={displayName} primaryTypographyProps={{ style: { overflow: "hidden", textOverflow: "ellipsis" } }}/>
|
<ListItemText primary={displayName} primaryTypographyProps={{ style: { overflow: "hidden", textOverflow: "ellipsis" } }}/>
|
||||||
{subscription.reservation?.everyone &&
|
{subscription.reservation?.everyone &&
|
||||||
<ListItemIcon edge="end" sx={{ minWidth: "26px" }}>
|
<ListItemIcon edge="end" sx={{ minWidth: "26px" }}>
|
||||||
{subscription.reservation?.everyone === "read-write" &&
|
{subscription.reservation?.everyone === Permission.READ_WRITE &&
|
||||||
<Tooltip title={t("prefs_reservations_table_everyone_read_write")}><PermissionReadWrite size="small"/></Tooltip>
|
<Tooltip title={t("prefs_reservations_table_everyone_read_write")}><PermissionReadWrite size="small"/></Tooltip>
|
||||||
}
|
}
|
||||||
{subscription.reservation?.everyone === "read-only" &&
|
{subscription.reservation?.everyone === Permission.READ_ONLY &&
|
||||||
<Tooltip title={t("prefs_reservations_table_everyone_read_only")}><PermissionRead size="small"/></Tooltip>
|
<Tooltip title={t("prefs_reservations_table_everyone_read_only")}><PermissionRead size="small"/></Tooltip>
|
||||||
}
|
}
|
||||||
{subscription.reservation?.everyone === "write-only" &&
|
{subscription.reservation?.everyone === Permission.WRITE_ONLY &&
|
||||||
<Tooltip title={t("prefs_reservations_table_everyone_write_only")}><PermissionWrite size="small"/></Tooltip>
|
<Tooltip title={t("prefs_reservations_table_everyone_write_only")}><PermissionWrite size="small"/></Tooltip>
|
||||||
}
|
}
|
||||||
{subscription.reservation?.everyone === "deny-all" &&
|
{subscription.reservation?.everyone === Permission.DENY_ALL &&
|
||||||
<Tooltip title={t("prefs_reservations_table_everyone_deny_all")}><PermissionDenyAll size="small"/></Tooltip>
|
<Tooltip title={t("prefs_reservations_table_everyone_deny_all")}><PermissionDenyAll size="small"/></Tooltip>
|
||||||
}
|
}
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
|
|
|
@ -39,7 +39,7 @@ import {playSound, shuffle, sounds, validTopic, validUrl} from "../app/utils";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import session from "../app/Session";
|
import session from "../app/Session";
|
||||||
import routes from "./routes";
|
import routes from "./routes";
|
||||||
import accountApi, {UnauthorizedError} from "../app/AccountApi";
|
import accountApi, {Permission, Role, UnauthorizedError} from "../app/AccountApi";
|
||||||
import {Pref, PrefGroup} from "./Pref";
|
import {Pref, PrefGroup} from "./Pref";
|
||||||
import LockIcon from "@mui/icons-material/Lock";
|
import LockIcon from "@mui/icons-material/Lock";
|
||||||
import {Info, Public, PublicOff} from "@mui/icons-material";
|
import {Info, Public, PublicOff} from "@mui/icons-material";
|
||||||
|
@ -485,11 +485,11 @@ const Reservations = () => {
|
||||||
const [dialogKey, setDialogKey] = useState(0);
|
const [dialogKey, setDialogKey] = useState(0);
|
||||||
const [dialogOpen, setDialogOpen] = useState(false);
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
|
|
||||||
if (!config.enable_reservations || !session.exists() || !account || account.role === "admin") {
|
if (!config.enable_reservations || !session.exists() || !account || account.role === Role.ADMIN) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
const reservations = account.reservations || [];
|
const reservations = account.reservations || [];
|
||||||
const limitReached = account.role === "user" && account.stats.reservations_remaining === 0;
|
const limitReached = account.role === Role.USER && account.stats.reservations_remaining === 0;
|
||||||
|
|
||||||
const handleAddClick = () => {
|
const handleAddClick = () => {
|
||||||
setDialogKey(prev => prev+1);
|
setDialogKey(prev => prev+1);
|
||||||
|
@ -602,25 +602,25 @@ const ReservationsTable = (props) => {
|
||||||
{reservation.topic}
|
{reservation.topic}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell aria-label={t("prefs_reservations_table_access_header")}>
|
<TableCell aria-label={t("prefs_reservations_table_access_header")}>
|
||||||
{reservation.everyone === "read-write" &&
|
{reservation.everyone === Permission.READ_WRITE &&
|
||||||
<>
|
<>
|
||||||
<Public fontSize="small" sx={{color: "grey", verticalAlign: "bottom", mr: 0.5}}/>
|
<Public fontSize="small" sx={{color: "grey", verticalAlign: "bottom", mr: 0.5}}/>
|
||||||
{t("prefs_reservations_table_everyone_read_write")}
|
{t("prefs_reservations_table_everyone_read_write")}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
{reservation.everyone === "read-only" &&
|
{reservation.everyone === Permission.READ_ONLY &&
|
||||||
<>
|
<>
|
||||||
<PublicOff fontSize="small" sx={{color: "grey", verticalAlign: "bottom", mr: 0.5}}/>
|
<PublicOff fontSize="small" sx={{color: "grey", verticalAlign: "bottom", mr: 0.5}}/>
|
||||||
{t("prefs_reservations_table_everyone_read_only")}
|
{t("prefs_reservations_table_everyone_read_only")}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
{reservation.everyone === "write-only" &&
|
{reservation.everyone === Permission.WRITE_ONLY &&
|
||||||
<>
|
<>
|
||||||
<PublicOff fontSize="small" sx={{color: "grey", verticalAlign: "bottom", mr: 0.5}}/>
|
<PublicOff fontSize="small" sx={{color: "grey", verticalAlign: "bottom", mr: 0.5}}/>
|
||||||
{t("prefs_reservations_table_everyone_write_only")}
|
{t("prefs_reservations_table_everyone_write_only")}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
{reservation.everyone === "deny-all" &&
|
{reservation.everyone === Permission.DENY_ALL &&
|
||||||
<>
|
<>
|
||||||
<LockIcon fontSize="small" sx={{color: "grey", verticalAlign: "bottom", mr: 0.5}}/>
|
<LockIcon fontSize="small" sx={{color: "grey", verticalAlign: "bottom", mr: 0.5}}/>
|
||||||
{t("prefs_reservations_table_everyone_deny_all")}
|
{t("prefs_reservations_table_everyone_deny_all")}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import MenuItem from "@mui/material/MenuItem";
|
||||||
import ListItemIcon from "@mui/material/ListItemIcon";
|
import ListItemIcon from "@mui/material/ListItemIcon";
|
||||||
import ListItemText from "@mui/material/ListItemText";
|
import ListItemText from "@mui/material/ListItemText";
|
||||||
import {PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite} from "./ReserveIcons";
|
import {PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite} from "./ReserveIcons";
|
||||||
|
import {Permission} from "../app/AccountApi";
|
||||||
|
|
||||||
const ReserveTopicSelect = (props) => {
|
const ReserveTopicSelect = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -24,19 +25,19 @@ const ReserveTopicSelect = (props) => {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MenuItem value="deny-all">
|
<MenuItem value={Permission.DENY_ALL}>
|
||||||
<ListItemIcon><PermissionDenyAll/></ListItemIcon>
|
<ListItemIcon><PermissionDenyAll/></ListItemIcon>
|
||||||
<ListItemText primary={t("prefs_reservations_table_everyone_deny_all")}/>
|
<ListItemText primary={t("prefs_reservations_table_everyone_deny_all")}/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem value="read-only">
|
<MenuItem value={Permission.READ_ONLY}>
|
||||||
<ListItemIcon><PermissionRead/></ListItemIcon>
|
<ListItemIcon><PermissionRead/></ListItemIcon>
|
||||||
<ListItemText primary={t("prefs_reservations_table_everyone_read_only")}/>
|
<ListItemText primary={t("prefs_reservations_table_everyone_read_only")}/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem value="write-only">
|
<MenuItem value={Permission.WRITE_ONLY}>
|
||||||
<ListItemIcon><PermissionWrite/></ListItemIcon>
|
<ListItemIcon><PermissionWrite/></ListItemIcon>
|
||||||
<ListItemText primary={t("prefs_reservations_table_everyone_write_only")}/>
|
<ListItemText primary={t("prefs_reservations_table_everyone_write_only")}/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem value="read-write">
|
<MenuItem value={Permission.READ_WRITE}>
|
||||||
<ListItemIcon><PermissionReadWrite/></ListItemIcon>
|
<ListItemIcon><PermissionReadWrite/></ListItemIcon>
|
||||||
<ListItemText primary={t("prefs_reservations_table_everyone_read_write")}/>
|
<ListItemText primary={t("prefs_reservations_table_everyone_read_write")}/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
|
@ -17,7 +17,7 @@ import DialogFooter from "./DialogFooter";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import session from "../app/Session";
|
import session from "../app/Session";
|
||||||
import routes from "./routes";
|
import routes from "./routes";
|
||||||
import accountApi, {TopicReservedError, UnauthorizedError} from "../app/AccountApi";
|
import accountApi, {Role, TopicReservedError, UnauthorizedError} from "../app/AccountApi";
|
||||||
import ReserveTopicSelect from "./ReserveTopicSelect";
|
import ReserveTopicSelect from "./ReserveTopicSelect";
|
||||||
import {AccountContext} from "./App";
|
import {AccountContext} from "./App";
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ const SubscribePage = (props) => {
|
||||||
const existingBaseUrls = Array
|
const existingBaseUrls = Array
|
||||||
.from(new Set([publicBaseUrl, ...props.subscriptions.map(s => s.baseUrl)]))
|
.from(new Set([publicBaseUrl, ...props.subscriptions.map(s => s.baseUrl)]))
|
||||||
.filter(s => s !== config.base_url);
|
.filter(s => s !== config.base_url);
|
||||||
const reserveTopicEnabled = session.exists() && account?.role === "user" && (account?.stats.reservations_remaining || 0) > 0;
|
const reserveTopicEnabled = session.exists() && account?.role === Role.USER && (account?.stats.reservations_remaining || 0) > 0;
|
||||||
|
|
||||||
const handleSubscribe = async () => {
|
const handleSubscribe = async () => {
|
||||||
const user = await userManager.get(baseUrl); // May be undefined
|
const user = await userManager.get(baseUrl); // May be undefined
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import {useContext, useEffect, useState} from 'react';
|
||||||
import Dialog from '@mui/material/Dialog';
|
import Dialog from '@mui/material/Dialog';
|
||||||
import DialogContent from '@mui/material/DialogContent';
|
import DialogContent from '@mui/material/DialogContent';
|
||||||
import DialogTitle from '@mui/material/DialogTitle';
|
import DialogTitle from '@mui/material/DialogTitle';
|
||||||
|
@ -6,16 +7,14 @@ import {Alert, CardActionArea, CardContent, ListItem, useMediaQuery} from "@mui/
|
||||||
import theme from "./theme";
|
import theme from "./theme";
|
||||||
import DialogFooter from "./DialogFooter";
|
import DialogFooter from "./DialogFooter";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import accountApi, {TopicReservedError, UnauthorizedError} from "../app/AccountApi";
|
import accountApi, {UnauthorizedError} from "../app/AccountApi";
|
||||||
import session from "../app/Session";
|
import session from "../app/Session";
|
||||||
import routes from "./routes";
|
import routes from "./routes";
|
||||||
import {useContext, useEffect, useState} from "react";
|
|
||||||
import Card from "@mui/material/Card";
|
import Card from "@mui/material/Card";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import {AccountContext} from "./App";
|
import {AccountContext} from "./App";
|
||||||
import {formatBytes, formatNumber, formatShortDate} from "../app/utils";
|
import {formatBytes, formatNumber, formatShortDate} from "../app/utils";
|
||||||
import {Trans, useTranslation} from "react-i18next";
|
import {Trans, useTranslation} from "react-i18next";
|
||||||
import subscriptionManager from "../app/SubscriptionManager";
|
|
||||||
import List from "@mui/material/List";
|
import List from "@mui/material/List";
|
||||||
import {Check} from "@mui/icons-material";
|
import {Check} from "@mui/icons-material";
|
||||||
import ListItemIcon from "@mui/material/ListItemIcon";
|
import ListItemIcon from "@mui/material/ListItemIcon";
|
||||||
|
|
Loading…
Reference in a new issue