diff --git a/cmd/serve.go b/cmd/serve.go
index cbfb141e..8847f2c0 100644
--- a/cmd/serve.go
+++ b/cmd/serve.go
@@ -79,7 +79,7 @@ var flagsServe = append(
 	altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-signup", Aliases: []string{"enable_signup"}, EnvVars: []string{"NTFY_ENABLE_SIGNUP"}, Value: false, Usage: "xxx"}),
 	altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-login", Aliases: []string{"enable_login"}, EnvVars: []string{"NTFY_ENABLE_LOGIN"}, Value: false, Usage: "xxx"}),
 	altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-payments", Aliases: []string{"enable_payments"}, EnvVars: []string{"NTFY_ENABLE_PAYMENTS"}, Value: false, Usage: "xxx"}),
-	altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-reserve-topics", Aliases: []string{"enable_reserve_topics"}, EnvVars: []string{"NTFY_ENABLE_RESERVE_TOPICS"}, Value: false, Usage: "xxx"}),
+	altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-reservations", Aliases: []string{"enable_reservations"}, EnvVars: []string{"NTFY_ENABLE_RESERVATIONS"}, Value: false, Usage: "xxx"}),
 )
 
 var cmdServe = &cli.Command{
@@ -151,7 +151,7 @@ func execServe(c *cli.Context) error {
 	enableSignup := c.Bool("enable-signup")
 	enableLogin := c.Bool("enable-login")
 	enablePayments := c.Bool("enable-payments")
-	enableReserveTopics := c.Bool("enable-reserve-topics")
+	enableReservations := c.Bool("enable-reservations")
 
 	// Check values
 	if firebaseKeyFile != "" && !util.FileExists(firebaseKeyFile) {
@@ -188,7 +188,7 @@ func execServe(c *cli.Context) error {
 		return errors.New("if upstream-base-url is set, base-url must also be set")
 	} else if upstreamBaseURL != "" && baseURL != "" && baseURL == upstreamBaseURL {
 		return errors.New("base-url and upstream-base-url cannot be identical, you'll likely want to set upstream-base-url to https://ntfy.sh, see https://ntfy.sh/docs/config/#ios-instant-notifications")
-	} else if authFile == "" && (enableSignup || enableLogin || enableReserveTopics || enablePayments) {
+	} else if authFile == "" && (enableSignup || enableLogin || enableReservations || enablePayments) {
 		return errors.New("cannot set enable-signup, enable-login, enable-reserve-topics, or enable-payments if auth-file is not set")
 	}
 
@@ -284,7 +284,7 @@ func execServe(c *cli.Context) error {
 	conf.EnableSignup = enableSignup
 	conf.EnableLogin = enableLogin
 	conf.EnablePayments = enablePayments
-	conf.EnableReserveTopics = enableReserveTopics
+	conf.EnableReservations = enableReservations
 	conf.Version = c.App.Version
 
 	// Set up hot-reloading of config
diff --git a/go.sum b/go.sum
index 12ffac06..0ad00577 100644
--- a/go.sum
+++ b/go.sum
@@ -35,8 +35,6 @@ github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead h1:fI1Jck0vUrXT8b
 github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
 github.com/emersion/go-smtp v0.15.0 h1:3+hMGMGrqP/lqd7qoxZc1hTU8LY8gHV9RFGWlqSDmP8=
 github.com/emersion/go-smtp v0.15.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
-github.com/emersion/go-smtp v0.16.0 h1:eB9CY9527WdEZSs5sWisTmilDX7gG+Q/2IdRcmubpa8=
-github.com/emersion/go-smtp v0.16.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -172,8 +170,6 @@ google.golang.org/appengine/v2 v2.0.2/go.mod h1:PkgRUWz4o1XOvbqtWTkBtCitEJ5Tp4Ho
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20221207170731-23e4bf6bdc37 h1:jmIfw8+gSvXcZSgaFAGyInDXeWzUhvYH57G/5GKMn70=
-google.golang.org/genproto v0.0.0-20221207170731-23e4bf6bdc37/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
 google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY=
 google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
diff --git a/server/config.go b/server/config.go
index 98796506..20374032 100644
--- a/server/config.go
+++ b/server/config.go
@@ -110,7 +110,7 @@ type Config struct {
 	EnableEmailConfirm                   bool
 	EnablePasswordReset                  bool
 	EnablePayments                       bool
-	EnableReserveTopics                  bool   // Allow users with role "user" to own/reserve topics
+	EnableReservations                   bool   // Allow users with role "user" to own/reserve topics
 	Version                              string // injected by App
 }
 
diff --git a/server/server.go b/server/server.go
index 57760805..bc267379 100644
--- a/server/server.go
+++ b/server/server.go
@@ -44,7 +44,6 @@ import (
 		UI:
 		- flicker of upgrade banner
 		- JS constants
-		- useContext for account
 		Sync:
 			- "account topic" sync mechanism
 			- "mute" setting
@@ -58,9 +57,7 @@ import (
 		Refactor:
 		- rename /access -> /reservation
 		Later:
-		- Password reset
 		- Pricing
-		- change email
 */
 
 // Server is the main server, providing the UI and API for ntfy
@@ -457,10 +454,10 @@ func (s *Server) handleWebConfig(w http.ResponseWriter, _ *http.Request, _ *visi
 		EnableSignup:        s.config.EnableSignup,
 		EnablePasswordReset: s.config.EnablePasswordReset,
 		EnablePayments:      s.config.EnablePayments,
-		EnableReserveTopics: s.config.EnableReserveTopics,
+		EnableReservations:  s.config.EnableReservations,
 		DisallowedTopics:    disallowedTopics,
 	}
-	b, err := json.Marshal(response)
+	b, err := json.MarshalIndent(response, "", "  ")
 	if err != nil {
 		return err
 	}
diff --git a/server/types.go b/server/types.go
index e766171e..21022f39 100644
--- a/server/types.go
+++ b/server/types.go
@@ -292,6 +292,6 @@ type apiConfigResponse struct {
 	EnableSignup        bool     `json:"enable_signup"`
 	EnablePasswordReset bool     `json:"enable_password_reset"`
 	EnablePayments      bool     `json:"enable_payments"`
-	EnableReserveTopics bool     `json:"enable_reserve_topics"`
+	EnableReservations  bool     `json:"enable_reservations"`
 	DisallowedTopics    []string `json:"disallowed_topics"`
 }
diff --git a/web/public/config.js b/web/public/config.js
index df73585e..ffcc383e 100644
--- a/web/public/config.js
+++ b/web/public/config.js
@@ -12,6 +12,6 @@ var config = {
     enable_signup: true,
     enable_password_reset: false,
     enable_payments: true,
-    enable_reserve_topics: true,
+    enable_reservations: true,
     disallowed_topics: ["docs", "static", "file", "app", "account", "settings", "pricing", "signup", "login", "reset-password"]
 };
diff --git a/web/public/static/langs/en.json b/web/public/static/langs/en.json
index 8f41fa7a..0efc0a1c 100644
--- a/web/public/static/langs/en.json
+++ b/web/public/static/langs/en.json
@@ -243,6 +243,7 @@
   "prefs_appearance_language_title": "Language",
   "prefs_reservations_title": "Reserved topics",
   "prefs_reservations_description": "You can reserve topic names for personal use here. Reserving a topic gives you ownership over the topic, and allows you to define access permissions for other users over the topic.",
+  "prefs_reservations_limit_reached": "You reached your reserved topics limit.",
   "prefs_reservations_add_button": "Add reserved topic",
   "prefs_reservations_edit_button": "Edit topic access",
   "prefs_reservations_delete_button": "Reset topic access",
diff --git a/web/src/components/Account.js b/web/src/components/Account.js
index c08e0d39..734577f0 100644
--- a/web/src/components/Account.js
+++ b/web/src/components/Account.js
@@ -1,6 +1,6 @@
 import * as React from 'react';
-import {useState} from 'react';
-import {LinearProgress, Link, Stack, useMediaQuery} from "@mui/material";
+import {useContext, useState} from 'react';
+import {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,6 @@ import TextField from "@mui/material/TextField";
 import DialogActions from "@mui/material/DialogActions";
 import routes from "./routes";
 import IconButton from "@mui/material/IconButton";
-import {useOutletContext} from "react-router-dom";
 import {formatBytes} from "../app/utils";
 import accountApi, {UnauthorizedError} from "../app/AccountApi";
 import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
@@ -28,6 +27,7 @@ import i18n from "i18next";
 import humanizeDuration from "humanize-duration";
 import UpgradeDialog from "./UpgradeDialog";
 import CelebrationIcon from "@mui/icons-material/Celebration";
+import {AccountContext} from "./App";
 
 const Account = () => {
     if (!session.exists()) {
@@ -62,7 +62,7 @@ const Basics = () => {
 
 const Username = () => {
     const { t } = useTranslation();
-    const { account } = useOutletContext();
+    const { account } = useContext(AccountContext);
     const labelId = "prefUsername";
 
     return (
@@ -169,23 +169,12 @@ const ChangePasswordDialog = (props) => {
 
 const Stats = () => {
     const { t } = useTranslation();
-    const { account } = useOutletContext();
+    const { account } = useContext(AccountContext);
     const [upgradeDialogOpen, setUpgradeDialogOpen] = useState(false);
-
     if (!account) {
         return <></>;
     }
-
     const normalize = (value, max) => Math.min(value / max * 100, 100);
-    const barColor = (remaining, limit) => {
-        if (account.role === "admin") {
-            return "primary";
-        } else if (limit > 0 && remaining === 0) {
-            return "error";
-        }
-        return "primary";
-    };
-
     return (
         <Card sx={{p: 3}} aria-label={t("account_usage_title")}>
             <Typography variant="h5" sx={{marginBottom: 2}}>
@@ -238,7 +227,6 @@ const Stats = () => {
                                 <LinearProgress
                                     variant="determinate"
                                     value={account.limits.reservations > 0 ? normalize(account.stats.reservations, account.limits.reservations) : 100}
-                                    color={barColor(account.stats.reservations_remaining, account.limits.reservations)}
                                 />
                             </>
                         }
@@ -260,7 +248,6 @@ const Stats = () => {
                     <LinearProgress
                         variant="determinate"
                         value={account.role === "user" ? normalize(account.stats.messages, account.limits.messages) : 100}
-                        color={account.role === "user" && account.stats.messages_remaining === 0 ? 'error' : 'primary'}
                     />
                 </Pref>
                 <Pref title={
@@ -271,12 +258,11 @@ const Stats = () => {
                 }>
                     <div>
                         <Typography variant="body2" sx={{float: "left"}}>{account.stats.emails}</Typography>
-                        <Typography variant="body2" sx={{float: "right"}}>{account.limits.emails > 0 ? t("account_usage_of_limit", { limit: account.limits.emails }) : t("account_usage_unlimited")}</Typography>
+                        <Typography variant="body2" sx={{float: "right"}}>{account.role === "user" ? t("account_usage_of_limit", { limit: account.limits.emails }) : t("account_usage_unlimited")}</Typography>
                     </div>
                     <LinearProgress
                         variant="determinate"
-                        value={account.limits.emails > 0 ? normalize(account.stats.emails, account.limits.emails) : 100}
-                        color={account?.role !== "admin" && account.stats.emails_remaining === 0 ? 'error' : 'primary'}
+                        value={account.role === "user" ? normalize(account.stats.emails, account.limits.emails) : 100}
                     />
                 </Pref>
                 <Pref
@@ -292,16 +278,15 @@ const Stats = () => {
                 >
                     <div>
                         <Typography variant="body2" sx={{float: "left"}}>{formatBytes(account.stats.attachment_total_size)}</Typography>
-                        <Typography variant="body2" sx={{float: "right"}}>{account.limits.attachment_total_size > 0 ? 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 === "user" ? t("account_usage_of_limit", { limit: formatBytes(account.limits.attachment_total_size) }) : t("account_usage_unlimited")}</Typography>
                     </div>
                     <LinearProgress
                         variant="determinate"
-                        value={account.limits.attachment_total_size > 0 ? normalize(account.stats.attachment_total_size, account.limits.attachment_total_size) : 100}
-                        color={account.role !== "admin" && account.stats.attachment_total_size_remaining === 0 ? 'error' : 'primary'}
+                        value={account.role === "user" ? normalize(account.stats.attachment_total_size, account.limits.attachment_total_size) : 100}
                     />
                 </Pref>
             </PrefGroup>
-            {account.limits.basis === "ip" &&
+            {account.role === "user" && account.limits.basis === "ip" &&
                 <Typography variant="body1">
                     {t("account_usage_basis_ip_description")}
                 </Typography>
diff --git a/web/src/components/App.js b/web/src/components/App.js
index 047a461d..7bb36958 100644
--- a/web/src/components/App.js
+++ b/web/src/components/App.js
@@ -1,10 +1,10 @@
 import * as React from 'react';
-import {Suspense, useEffect, useState} from 'react';
+import {createContext, Suspense, useContext, useEffect, useState} from 'react';
 import Box from '@mui/material/Box';
 import {ThemeProvider} from '@mui/material/styles';
 import CssBaseline from '@mui/material/CssBaseline';
 import Toolbar from '@mui/material/Toolbar';
-import Notifications from "./Notifications";
+import {AllSubscriptions, SingleSubscription} from "./Notifications";
 import theme from "./theme";
 import Navigation from "./Navigation";
 import ActionBar from "./ActionBar";
@@ -13,11 +13,11 @@ import Preferences from "./Preferences";
 import {useLiveQuery} from "dexie-react-hooks";
 import subscriptionManager from "../app/SubscriptionManager";
 import userManager from "../app/UserManager";
-import {BrowserRouter, Outlet, Route, Routes, useOutletContext, useParams} from "react-router-dom";
+import {BrowserRouter, Outlet, Route, Routes, useParams} from "react-router-dom";
 import {expandUrl} from "../app/utils";
 import ErrorBoundary from "./ErrorBoundary";
 import routes from "./routes";
-import {useAccountListener, useAutoSubscribe, useBackgroundProcesses, useConnectionListeners} from "./hooks";
+import {useAccountListener, useBackgroundProcesses, useConnectionListeners} from "./hooks";
 import PublishDialog from "./PublishDialog";
 import Messaging from "./Messaging";
 import "./i18n"; // Translations!
@@ -27,53 +27,45 @@ import Login from "./Login";
 import Pricing from "./Pricing";
 import Signup from "./Signup";
 import Account from "./Account";
-import ResetPassword from "./ResetPassword";
+
+export const AccountContext = createContext(null);
 
 const App = () => {
+    const [account, setAccount] = useState(null);
     return (
         <Suspense fallback={<Loader />}>
             <BrowserRouter>
                 <ThemeProvider theme={theme}>
-                    <CssBaseline/>
-                    <ErrorBoundary>
-                        <Routes>
-                            <Route path={routes.home} element={<Home/>}/>
-                            <Route path={routes.pricing} element={<Pricing/>}/>
-                            <Route path={routes.login} element={<Login/>}/>
-                            <Route path={routes.signup} element={<Signup/>}/>
-                            <Route path={routes.resetPassword} element={<ResetPassword/>}/>
-                            <Route element={<Layout/>}>
-                                <Route path={routes.app} element={<AllSubscriptions/>}/>
-                                <Route path={routes.account} element={<Account/>}/>
-                                <Route path={routes.settings} element={<Preferences/>}/>
-                                <Route path={routes.subscription} element={<SingleSubscription/>}/>
-                                <Route path={routes.subscriptionExternal} element={<SingleSubscription/>}/>
-                            </Route>
-                        </Routes>
-                    </ErrorBoundary>
+                    <AccountContext.Provider value={{ account, setAccount }}>
+                        <CssBaseline/>
+                        <ErrorBoundary>
+                            <Routes>
+                                <Route path={routes.home} element={<Home/>}/>
+                                <Route path={routes.pricing} element={<Pricing/>}/>
+                                <Route path={routes.login} element={<Login/>}/>
+                                <Route path={routes.signup} element={<Signup/>}/>
+                                <Route element={<Layout/>}>
+                                    <Route path={routes.app} element={<AllSubscriptions/>}/>
+                                    <Route path={routes.account} element={<Account/>}/>
+                                    <Route path={routes.settings} element={<Preferences/>}/>
+                                    <Route path={routes.subscription} element={<SingleSubscription/>}/>
+                                    <Route path={routes.subscriptionExternal} element={<SingleSubscription/>}/>
+                                </Route>
+                            </Routes>
+                        </ErrorBoundary>
+                    </AccountContext.Provider>
                 </ThemeProvider>
             </BrowserRouter>
         </Suspense>
     );
 }
 
-const AllSubscriptions = () => {
-    const { subscriptions } = useOutletContext();
-    return <Notifications mode="all" subscriptions={subscriptions}/>;
-};
-
-const SingleSubscription = () => {
-    const { subscriptions, selected } = useOutletContext();
-    useAutoSubscribe(subscriptions, selected);
-    return <Notifications mode="one" subscription={selected}/>;
-};
-
 const Layout = () => {
     const params = useParams();
+    const { account, setAccount } = useContext(AccountContext);
     const [mobileDrawerOpen, setMobileDrawerOpen] = useState(false);
     const [notificationsGranted, setNotificationsGranted] = useState(notifier.granted());
     const [sendDialogOpenMode, setSendDialogOpenMode] = useState("");
-    const [account, setAccount] = useState(null);
     const users = useLiveQuery(() => userManager.all());
     const subscriptions = useLiveQuery(() => subscriptionManager.all());
     const newNotificationsCount = subscriptions?.reduce((prev, cur) => prev + cur.new, 0) || 0;
@@ -94,7 +86,6 @@ const Layout = () => {
                 onMobileDrawerToggle={() => setMobileDrawerOpen(!mobileDrawerOpen)}
             />
             <Navigation
-                account={account}
                 subscriptions={subscriptions}
                 selectedSubscription={selected}
                 notificationsGranted={notificationsGranted}
@@ -105,7 +96,7 @@ const Layout = () => {
             />
             <Main>
                 <Toolbar/>
-                <Outlet context={{ account, subscriptions, selected }}/>
+                <Outlet context={{ subscriptions, selected }}/>
             </Main>
             <Messaging
                 selected={selected}
diff --git a/web/src/components/Navigation.js b/web/src/components/Navigation.js
index 07004662..cd80fd6a 100644
--- a/web/src/components/Navigation.js
+++ b/web/src/components/Navigation.js
@@ -1,6 +1,6 @@
 import Drawer from "@mui/material/Drawer";
 import * as React from "react";
-import {useState} from "react";
+import {useContext, useState} from "react";
 import ListItemButton from "@mui/material/ListItemButton";
 import ListItemIcon from "@mui/material/ListItemIcon";
 import ChatBubbleOutlineIcon from "@mui/icons-material/ChatBubbleOutline";
@@ -30,6 +30,7 @@ import session from "../app/Session";
 import accountApi from "../app/AccountApi";
 import CelebrationIcon from '@mui/icons-material/Celebration';
 import UpgradeDialog from "./UpgradeDialog";
+import {AccountContext} from "./App";
 
 const navWidth = 280;
 
@@ -76,6 +77,7 @@ const NavList = (props) => {
     const { t } = useTranslation();
     const navigate = useNavigate();
     const location = useLocation();
+    const { account } = useContext(AccountContext);
     const [subscribeDialogKey, setSubscribeDialogKey] = useState(0);
     const [subscribeDialogOpen, setSubscribeDialogOpen] = useState(false);
 
@@ -100,8 +102,8 @@ const NavList = (props) => {
         navigate(routes.account);
     };
 
-    const isAdmin = props.account?.role === "admin";
-    const isPaid = props.account?.tier?.paid;
+    const isAdmin = account?.role === "admin";
+    const isPaid = account?.tier?.paid;
     const showUpgradeBanner = config.enable_payments && !isAdmin && !isPaid;// && (!props.account || !props.account.tier || !props.account.tier.paid || props.account);
     const showSubscriptionsList = props.subscriptions?.length > 0;
     const showNotificationBrowserNotSupportedBox = !notifier.browserSupported();
diff --git a/web/src/components/Notifications.js b/web/src/components/Notifications.js
index b4804022..10bcad81 100644
--- a/web/src/components/Notifications.js
+++ b/web/src/components/Notifications.js
@@ -19,7 +19,8 @@ import {
     formatBytes,
     formatMessage,
     formatShortDateTime,
-    formatTitle, maybeAppendActionErrors,
+    formatTitle,
+    maybeAppendActionErrors,
     openUrl,
     shortUrl,
     topicShortUrl,
@@ -41,15 +42,27 @@ import priority5 from "../img/priority-5.svg";
 import logoOutline from "../img/ntfy-outline.svg";
 import AttachmentIcon from "./AttachmentIcon";
 import {Trans, useTranslation} from "react-i18next";
+import {useOutletContext} from "react-router-dom";
+import {useAutoSubscribe} from "./hooks";
 
-const Notifications = (props) => {
-    if (props.mode === "all") {
-        return (props.subscriptions) ? <AllSubscriptions subscriptions={props.subscriptions}/> : <Loading/>;
+export const AllSubscriptions = () => {
+    const { subscriptions } = useOutletContext();
+    if (!subscriptions) {
+        return <Loading/>;
     }
-    return (props.subscription) ? <SingleSubscription subscription={props.subscription}/> : <Loading/>;
-}
+    return <AllSubscriptionsList subscriptions={subscriptions}/>;
+};
 
-const AllSubscriptions = (props) => {
+export const SingleSubscription = () => {
+    const { subscriptions, selected } = useOutletContext();
+    useAutoSubscribe(subscriptions, selected);
+    if (!selected) {
+        return <Loading/>;
+    }
+    return <SingleSubscriptionList subscription={selected}/>;
+};
+
+const AllSubscriptionsList = (props) => {
     const subscriptions = props.subscriptions;
     const notifications = useLiveQuery(() => subscriptionManager.getAllNotifications(), []);
     if (notifications === null || notifications === undefined) {
@@ -62,7 +75,7 @@ const AllSubscriptions = (props) => {
     return <NotificationList key="all" notifications={notifications} messageBar={false}/>;
 }
 
-const SingleSubscription = (props) => {
+const SingleSubscriptionList = (props) => {
     const subscription = props.subscription;
     const notifications = useLiveQuery(() => subscriptionManager.getNotifications(subscription.id), [subscription]);
     if (notifications === null || notifications === undefined) {
@@ -533,5 +546,3 @@ const Loading = () => {
         </VerticallyCenteredContainer>
     );
 };
-
-export default Notifications;
diff --git a/web/src/components/Preferences.js b/web/src/components/Preferences.js
index e1777e28..fa26a866 100644
--- a/web/src/components/Preferences.js
+++ b/web/src/components/Preferences.js
@@ -1,5 +1,5 @@
 import * as React from 'react';
-import {useEffect, useState} from 'react';
+import {useContext, useEffect, useState} from 'react';
 import {
     Alert,
     CardActions,
@@ -40,13 +40,11 @@ import session from "../app/Session";
 import routes from "./routes";
 import accountApi, {UnauthorizedError} from "../app/AccountApi";
 import {Pref, PrefGroup} from "./Pref";
-import {useOutletContext} from "react-router-dom";
 import LockIcon from "@mui/icons-material/Lock";
 import {Public, PublicOff} from "@mui/icons-material";
-import ListItemIcon from "@mui/material/ListItemIcon";
-import ListItemText from "@mui/material/ListItemText";
 import DialogContentText from "@mui/material/DialogContentText";
 import ReserveTopicSelect from "./ReserveTopicSelect";
+import {AccountContext} from "./App";
 
 const Preferences = () => {
     return (
@@ -481,11 +479,11 @@ const Language = () => {
 
 const Reservations = () => {
     const { t } = useTranslation();
-    const { account } = useOutletContext();
+    const { account } = useContext(AccountContext);
     const [dialogKey, setDialogKey] = useState(0);
     const [dialogOpen, setDialogOpen] = useState(false);
 
-    if (!config.enable_reserve_topics || !session.exists() || !account || account.role === "admin") {
+    if (!config.enable_reservations || !session.exists() || !account || account.role === "admin") {
         return <></>;
     }
     const reservations = account.reservations || [];
@@ -522,14 +520,7 @@ const Reservations = () => {
                     {t("prefs_reservations_description")}
                 </Paragraph>
                 {reservations.length > 0 && <ReservationsTable reservations={reservations}/>}
-                {limitReached &&
-                    <Alert severity="info">
-                        You reached your reserved topics limit.
-                        {config.enable_payments &&
-                            <>{" "}<b>Upgrade</b></>
-                        }
-                    </Alert>
-                }
+                {limitReached && <Alert severity="info">{t("prefs_reservations_limit_reached")}</Alert>}
             </CardContent>
             <CardActions>
                 <Button onClick={handleAddClick} disabled={limitReached}>{t("prefs_reservations_add_button")}</Button>
diff --git a/web/src/components/ResetPassword.js b/web/src/components/ResetPassword.js
deleted file mode 100644
index bcf635eb..00000000
--- a/web/src/components/ResetPassword.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import * as React from 'react';
-import TextField from "@mui/material/TextField";
-import Button from "@mui/material/Button";
-import Box from "@mui/material/Box";
-import routes from "./routes";
-import Typography from "@mui/material/Typography";
-import {NavLink} from "react-router-dom";
-import AvatarBox from "./AvatarBox";
-
-const ResetPassword = () => {
-    const handleSubmit = async (event) => {
-        //
-    };
-
-    return (
-        <AvatarBox>
-            <Typography sx={{ typography: 'h6' }}>
-                Reset password
-            </Typography>
-            <Box component="form" onSubmit={handleSubmit} noValidate sx={{mt: 1, maxWidth: 400}}>
-                <TextField
-                    margin="dense"
-                    required
-                    fullWidth
-                    id="email"
-                    label="Email"
-                    name="email"
-                    autoFocus
-                />
-                <Button
-                    type="submit"
-                    fullWidth
-                    variant="contained"
-                    sx={{mt: 2, mb: 2}}
-                >
-                    Reset password
-                </Button>
-            </Box>
-            <Typography sx={{mb: 4}}>
-                <NavLink to={routes.login} variant="body1">
-                    &lt; Return to sign in
-                </NavLink>
-            </Typography>
-        </AvatarBox>
-    );
-}
-
-export default ResetPassword;
diff --git a/web/src/components/SubscribeDialog.js b/web/src/components/SubscribeDialog.js
index 783d00ec..460ee5df 100644
--- a/web/src/components/SubscribeDialog.js
+++ b/web/src/components/SubscribeDialog.js
@@ -1,5 +1,5 @@
 import * as React from 'react';
-import {useState} from 'react';
+import {useContext, useState} from 'react';
 import Button from '@mui/material/Button';
 import TextField from '@mui/material/TextField';
 import Dialog from '@mui/material/Dialog';
@@ -19,7 +19,7 @@ import session from "../app/Session";
 import routes from "./routes";
 import accountApi, {TopicReservedError, UnauthorizedError} from "../app/AccountApi";
 import ReserveTopicSelect from "./ReserveTopicSelect";
-import {useOutletContext} from "react-router-dom";
+import {AccountContext} from "./App";
 
 const publicBaseUrl = "https://ntfy.sh";
 
@@ -76,7 +76,7 @@ const SubscribeDialog = (props) => {
 
 const SubscribePage = (props) => {
     const { t } = useTranslation();
-    //const { account } = useOutletContext();
+    const { account } = useContext(AccountContext);
     const [reserveTopicVisible, setReserveTopicVisible] = useState(false);
     const [anotherServerVisible, setAnotherServerVisible] = useState(false);
     const [errorText, setErrorText] = useState("");
@@ -87,7 +87,7 @@ const SubscribePage = (props) => {
     const existingBaseUrls = Array
         .from(new Set([publicBaseUrl, ...props.subscriptions.map(s => s.baseUrl)]))
         .filter(s => s !== config.base_url);
-    //const reserveTopicEnabled = session.exists() && (account?.stats.reservations_remaining || 0) > 0;
+    const reserveTopicEnabled = session.exists() && account?.role === "user" && (account?.stats.reservations_remaining || 0) > 0;
 
     const handleSubscribe = async () => {
         const user = await userManager.get(baseUrl); // May be undefined
@@ -177,14 +177,14 @@ const SubscribePage = (props) => {
                         {t("subscribe_dialog_subscribe_button_generate_topic_name")}
                     </Button>
                 </div>
-                {config.enable_reserve_topics && session.exists() && !anotherServerVisible &&
+                {config.enable_reservations && session.exists() && !anotherServerVisible &&
                     <FormGroup>
                         <FormControlLabel
                             variant="standard"
                             control={
                                 <Checkbox
                                     fullWidth
-                                    // disabled={account.stats.reservations_remaining}
+                                    disabled={!reserveTopicEnabled}
                                     checked={reserveTopicVisible}
                                     onChange={(ev) => setReserveTopicVisible(ev.target.checked)}
                                     inputProps={{
diff --git a/web/src/components/SubscriptionSettingsDialog.js b/web/src/components/SubscriptionSettingsDialog.js
index 128dccad..85d77c7c 100644
--- a/web/src/components/SubscriptionSettingsDialog.js
+++ b/web/src/components/SubscriptionSettingsDialog.js
@@ -78,7 +78,7 @@ const SubscriptionSettingsDialog = (props) => {
                         "aria-label": t("subscription_settings_dialog_display_name_placeholder")
                     }}
                 />
-                {config.enable_reserve_topics && session.exists() &&
+                {config.enable_reservations && session.exists() &&
                     <>
                         <FormControlLabel
                             fullWidth
diff --git a/web/src/components/UpgradeDialog.js b/web/src/components/UpgradeDialog.js
index 392f8752..1a44c97d 100644
--- a/web/src/components/UpgradeDialog.js
+++ b/web/src/components/UpgradeDialog.js
@@ -1,25 +1,10 @@
 import * as React from 'react';
-import {useState} from 'react';
-import Button from '@mui/material/Button';
-import TextField from '@mui/material/TextField';
 import Dialog from '@mui/material/Dialog';
 import DialogContent from '@mui/material/DialogContent';
-import DialogContentText from '@mui/material/DialogContentText';
 import DialogTitle from '@mui/material/DialogTitle';
-import {Autocomplete, Checkbox, FormControlLabel, FormGroup, useMediaQuery} from "@mui/material";
+import {useMediaQuery} from "@mui/material";
 import theme from "./theme";
-import api from "../app/Api";
-import {randomAlphanumericString, topicUrl, validTopic, validUrl} from "../app/utils";
-import userManager from "../app/UserManager";
-import subscriptionManager from "../app/SubscriptionManager";
-import poller from "../app/Poller";
 import DialogFooter from "./DialogFooter";
-import {useTranslation} from "react-i18next";
-import session from "../app/Session";
-import routes from "./routes";
-import accountApi, {TopicReservedError, UnauthorizedError} from "../app/AccountApi";
-import ReserveTopicSelect from "./ReserveTopicSelect";
-import {useOutletContext} from "react-router-dom";
 
 const UpgradeDialog = (props) => {
     const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
diff --git a/web/src/components/routes.js b/web/src/components/routes.js
index 7f6589a2..a7a2e762 100644
--- a/web/src/components/routes.js
+++ b/web/src/components/routes.js
@@ -8,7 +8,7 @@ const routes = {
     pricing: "/pricing",
     login: "/login",
     signup: "/signup",
-    resetPassword: "/reset-password",
+    resetPassword: "/reset-password", // Not used (yet)
     app: config.app_root,
     account: "/account",
     settings: "/settings",