1
0
Fork 0
mirror of https://github.com/binwiederhier/ntfy.git synced 2024-11-04 19:04:15 +01:00

Fix UI bugs

This commit is contained in:
binwiederhier 2023-02-10 21:19:44 -05:00
parent 79f9e78c37
commit 5724bdf436
5 changed files with 54 additions and 28 deletions

View file

@ -34,6 +34,7 @@ import (
/* /*
- MEDIUM fail2ban to work with ntfy log not nginx log
- HIGH Docs - HIGH Docs
- tiers - tiers
- api - api

View file

@ -26,7 +26,7 @@ import {Logout, Person, Settings} from "@mui/icons-material";
import ListItemIcon from "@mui/material/ListItemIcon"; import ListItemIcon from "@mui/material/ListItemIcon";
import accountApi from "../app/AccountApi"; import accountApi from "../app/AccountApi";
import PopupMenu from "./PopupMenu"; import PopupMenu from "./PopupMenu";
import SubscriptionPopup from "./SubscriptionPopup"; import { SubscriptionPopup } from "./SubscriptionPopup";
const ActionBar = (props) => { const ActionBar = (props) => {
const { t } = useTranslation(); const { t } = useTranslation();

View file

@ -11,9 +11,8 @@ import Divider from "@mui/material/Divider";
import List from "@mui/material/List"; import List from "@mui/material/List";
import SettingsIcon from "@mui/icons-material/Settings"; import SettingsIcon from "@mui/icons-material/Settings";
import AddIcon from "@mui/icons-material/Add"; import AddIcon from "@mui/icons-material/Add";
import VisibilityIcon from '@mui/icons-material/Visibility';
import SubscribeDialog from "./SubscribeDialog"; import SubscribeDialog from "./SubscribeDialog";
import {Alert, AlertTitle, Badge, CircularProgress, Link, ListSubheader, Menu, Portal, Tooltip} from "@mui/material"; import {Alert, AlertTitle, Badge, CircularProgress, Link, ListSubheader, Portal, Tooltip} from "@mui/material";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import {openUrl, topicDisplayName, topicUrl} from "../app/utils"; import {openUrl, topicDisplayName, topicUrl} from "../app/utils";
@ -21,16 +20,7 @@ import routes from "./routes";
import {ConnectionState} from "../app/Connection"; import {ConnectionState} from "../app/Connection";
import {useLocation, useNavigate} from "react-router-dom"; import {useLocation, useNavigate} from "react-router-dom";
import subscriptionManager from "../app/SubscriptionManager"; import subscriptionManager from "../app/SubscriptionManager";
import { import {ChatBubble, MoreVert, NotificationsOffOutlined, Send} from "@mui/icons-material";
ChatBubble,
Lock, Logout,
MoreHoriz, MoreVert,
NotificationsOffOutlined,
Public,
PublicOff,
Send,
Settings
} from "@mui/icons-material";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
import notifier from "../app/Notifier"; import notifier from "../app/Notifier";
import config from "../app/config"; import config from "../app/config";
@ -43,9 +33,7 @@ import UpgradeDialog from "./UpgradeDialog";
import {AccountContext} from "./App"; import {AccountContext} from "./App";
import {PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite} from "./ReserveIcons"; import {PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite} from "./ReserveIcons";
import IconButton from "@mui/material/IconButton"; import IconButton from "@mui/material/IconButton";
import MenuItem from "@mui/material/MenuItem"; import { SubscriptionPopup } from "./SubscriptionPopup";
import PopupMenu from "./PopupMenu";
import SubscriptionPopup from "./SubscriptionPopup";
const navWidth = 280; const navWidth = 280;

View file

@ -6,7 +6,7 @@ import Dialog from '@mui/material/Dialog';
import DialogContent from '@mui/material/DialogContent'; import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText'; import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle'; import DialogTitle from '@mui/material/DialogTitle';
import {Autocomplete, Checkbox, Chip, FormControlLabel, FormGroup, useMediaQuery} from "@mui/material"; import {Autocomplete, Checkbox, FormControlLabel, FormGroup, useMediaQuery} from "@mui/material";
import theme from "./theme"; import theme from "./theme";
import api from "../app/Api"; import api from "../app/Api";
import {randomAlphanumericString, topicUrl, validTopic, validUrl} from "../app/utils"; import {randomAlphanumericString, topicUrl, validTopic, validUrl} from "../app/utils";
@ -21,6 +21,7 @@ import accountApi, {Role} from "../app/AccountApi";
import ReserveTopicSelect from "./ReserveTopicSelect"; import ReserveTopicSelect from "./ReserveTopicSelect";
import {AccountContext} from "./App"; import {AccountContext} from "./App";
import {TopicReservedError, UnauthorizedError} from "../app/errors"; import {TopicReservedError, UnauthorizedError} from "../app/errors";
import {ReserveLimitChip} from "./SubscriptionPopup";
const publicBaseUrl = "https://ntfy.sh"; const publicBaseUrl = "https://ntfy.sh";
@ -33,7 +34,7 @@ const SubscribeDialog = (props) => {
const handleSuccess = async () => { const handleSuccess = async () => {
console.log(`[SubscribeDialog] Subscribing to topic ${topic}`); console.log(`[SubscribeDialog] Subscribing to topic ${topic}`);
const actualBaseUrl = (baseUrl) ? baseUrl : config.base_url; const actualBaseUrl = (baseUrl) ? baseUrl : config.base_url;
const subscription = subscribeTopic(actualBaseUrl, topic); const subscription = await subscribeTopic(actualBaseUrl, topic);
poller.pollInBackground(subscription); // Dangle! poller.pollInBackground(subscription); // Dangle!
props.onSuccess(subscription); props.onSuccess(subscription);
} }
@ -73,6 +74,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 showReserveTopicCheckbox = config.enable_reservations && session.exists() && !anotherServerVisible;
const reserveTopicEnabled = session.exists() && account?.role === 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 () => {
@ -163,7 +165,7 @@ const SubscribePage = (props) => {
{t("subscribe_dialog_subscribe_button_generate_topic_name")} {t("subscribe_dialog_subscribe_button_generate_topic_name")}
</Button> </Button>
</div> </div>
{config.enable_reservations && session.exists() && !anotherServerVisible && {showReserveTopicCheckbox &&
<FormGroup> <FormGroup>
<FormControlLabel <FormControlLabel
variant="standard" variant="standard"
@ -181,7 +183,7 @@ const SubscribePage = (props) => {
label={ label={
<> <>
{t("reserve_dialog_checkbox_label")} {t("reserve_dialog_checkbox_label")}
<Chip label={t("action_bar_reservation_limit_reached")} variant="outlined" color="primary" sx={{ opacity: 0.8, borderWidth: "2px", height: "24px", marginLeft: "5px" }}/> <ReserveLimitChip/>
</> </>
} }
/> />

View file

@ -24,9 +24,8 @@ import {Clear} from "@mui/icons-material";
import {AccountContext} from "./App"; import {AccountContext} from "./App";
import {ReserveAddDialog, ReserveDeleteDialog, ReserveEditDialog} from "./ReserveDialogs"; import {ReserveAddDialog, ReserveDeleteDialog, ReserveEditDialog} from "./ReserveDialogs";
import {UnauthorizedError} from "../app/errors"; import {UnauthorizedError} from "../app/errors";
import Box from "@mui/material/Box";
const SubscriptionPopup = (props) => { export const SubscriptionPopup = (props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { account } = useContext(AccountContext); const { account } = useContext(AccountContext);
const navigate = useNavigate(); const navigate = useNavigate();
@ -39,10 +38,10 @@ const SubscriptionPopup = (props) => {
const placement = props.placement ?? "left"; const placement = props.placement ?? "left";
const reservations = account?.reservations || []; const reservations = account?.reservations || [];
const showReservationAdd = !subscription?.reservation && account?.stats.reservations_remaining > 0; const showReservationAdd = config.enable_reservations && !subscription?.reservation && account?.stats.reservations_remaining > 0;
const showReservationAddDisabled = !subscription?.reservation && account?.stats.reservations_remaining === 0; const showReservationAddDisabled = config.enable_reservations && !subscription?.reservation && (config.enable_payments || account?.stats.reservations_remaining === 0);
const showReservationEdit = !!subscription?.reservation; const showReservationEdit = config.enable_reservations && !!subscription?.reservation;
const showReservationDelete = !!subscription?.reservation; const showReservationDelete = config.enable_reservations && !!subscription?.reservation;
const handleChangeDisplayName = async () => { const handleChangeDisplayName = async () => {
setDisplayNameDialogOpen(true); setDisplayNameDialogOpen(true);
@ -141,7 +140,7 @@ const SubscriptionPopup = (props) => {
{showReservationAddDisabled && {showReservationAddDisabled &&
<MenuItem sx={{ cursor: "default" }}> <MenuItem sx={{ cursor: "default" }}>
<span style={{ opacity: 0.3 }}>{t("action_bar_reservation_add")}</span> <span style={{ opacity: 0.3 }}>{t("action_bar_reservation_add")}</span>
<Chip label={t("action_bar_reservation_limit_reached")} variant="outlined" color="primary" sx={{ opacity: 0.8, borderWidth: "2px", height: "24px", marginLeft: "5px" }}/> <ReserveLimitChip/>
</MenuItem> </MenuItem>
} }
{showReservationEdit && <MenuItem onClick={handleReserveEdit}>{t("action_bar_reservation_edit")}</MenuItem>} {showReservationEdit && <MenuItem onClick={handleReserveEdit}>{t("action_bar_reservation_edit")}</MenuItem>}
@ -254,4 +253,40 @@ const DisplayNameDialog = (props) => {
); );
}; };
export default SubscriptionPopup; export const ReserveLimitChip = () => {
const { account } = useContext(AccountContext);
if (account?.stats.reservations_remaining > 0) {
return <></>;
} else if (config.enable_payments) {
return <ProChip/>;
} else if (account) {
return <LimitReachedChip/>;
}
return <></>;
};
const LimitReachedChip = () => {
const { t } = useTranslation();
return (
<Chip
label={t("action_bar_reservation_limit_reached")}
variant="outlined"
color="primary"
sx={{ opacity: 0.8, borderWidth: "2px", height: "24px", marginLeft: "5px" }}
/>
);
};
const ProChip = () => {
const { t } = useTranslation();
return (
<Chip
label={"ntfy Pro"}
variant="outlined"
color="primary"
sx={{ opacity: 0.8, borderWidth: "2px", height: "24px", marginLeft: "5px" }}
/>
);
};