diff --git a/web/public/static/langs/en.json b/web/public/static/langs/en.json index a34c734a..b9d261a3 100644 --- a/web/public/static/langs/en.json +++ b/web/public/static/langs/en.json @@ -183,7 +183,7 @@ "account_usage_plan_code_business_plus": "Business Plus", "account_usage_messages_title": "Published messages", "account_usage_emails_title": "Emails sent", - "account_usage_topics_title": "Topics reserved", + "account_usage_topics_title": "Reserved topics", "account_usage_attachment_storage_title": "Attachment storage", "account_usage_attachment_storage_subtitle": "{{filesize}} per file", "account_usage_basis_ip_description": "Usage stats and limits for this account are based on your IP address, so they may be shared with other users.", @@ -239,6 +239,17 @@ "prefs_users_dialog_button_save": "Save", "prefs_appearance_title": "Appearance", "prefs_appearance_language_title": "Language", + "prefs_access_title": "Reserved topics", + "prefs_access_description": "You may reserve topic names for personal use here, and define access to a topic for other users.", + "prefs_access_add_button": "Add reserved topic", + "prefs_access_edit_button": "Edit topic access", + "prefs_access_delete_button": "Reset topic access", + "prefs_access_table": "Reserved topics table", + "prefs_access_table_topic_header": "Topic", + "prefs_access_table_access_header": "Access", + "prefs_access_table_perms_private": "Only I can publish and subscribe", + "prefs_access_table_perms_public_read": "I can publish, everyone can subscribe", + "prefs_access_table_perms_public": "Everyone can publish and subscribe", "priority_min": "min", "priority_low": "low", "priority_default": "default", diff --git a/web/src/components/Preferences.js b/web/src/components/Preferences.js index 3024e63f..54628fcd 100644 --- a/web/src/components/Preferences.js +++ b/web/src/components/Preferences.js @@ -10,7 +10,8 @@ import { TableBody, TableCell, TableHead, - TableRow, Tooltip, + TableRow, + Tooltip, useMediaQuery } from "@mui/material"; import Typography from "@mui/material/Typography"; @@ -32,22 +33,23 @@ import DialogTitle from "@mui/material/DialogTitle"; import DialogContent from "@mui/material/DialogContent"; import DialogActions from "@mui/material/DialogActions"; import userManager from "../app/UserManager"; -import {playSound, shuffle, sounds, validTopic, validUrl} from "../app/utils"; +import {playSound, shuffle, sounds, validUrl} from "../app/utils"; import {useTranslation} from "react-i18next"; import session from "../app/Session"; import routes from "./routes"; import accountApi, {UnauthorizedError} from "../app/AccountApi"; import {Pref, PrefGroup} from "./Pref"; -import InfoIcon from '@mui/icons-material/Info'; -import {useNavigate} from "react-router-dom"; +import {useOutletContext} from "react-router-dom"; +import LockIcon from "@mui/icons-material/Lock"; const Preferences = () => { return ( - + + ); @@ -471,6 +473,129 @@ const Language = () => { ) }; +const Access = () => { + const { t } = useTranslation(); + const { account } = useOutletContext(); + const [dialogKey, setDialogKey] = useState(0); + const [dialogOpen, setDialogOpen] = useState(false); + + const handleAddClick = () => { + setDialogKey(prev => prev+1); + setDialogOpen(true); + }; + + const handleDialogCancel = () => { + setDialogOpen(false); + }; + + const handleDialogSubmit = async (entry) => { + setDialogOpen(false); + try { + await accountApi.addAccessEntry(); + console.debug(`[Preferences] Added entry ${entry.topic}`); + } catch (e) { + console.log(`[Preferences] Error adding access entry.`, e); + } + }; + + if (!session.exists() || !account) { + return <>; + } + + return ( + + + + {t("prefs_access_title")} + + + {t("prefs_access_description")} + + {account.access.length > 0 && } + + + + {/**/} + + + ); +}; + +const AccessTable = (props) => { + const { t } = useTranslation(); + const [dialogKey, setDialogKey] = useState(0); + const [dialogOpen, setDialogOpen] = useState(false); + const [dialogUser, setDialogUser] = useState(null); + + const handleEditClick = (user) => { + setDialogKey(prev => prev+1); + setDialogUser(user); + setDialogOpen(true); + }; + + const handleDialogCancel = () => { + setDialogOpen(false); + }; + + const handleDialogSubmit = async (user) => { + setDialogOpen(false); + // FIXME + }; + + const handleDeleteClick = async (user) => { + // FIXME + }; + + return ( + + + + {t("prefs_access_table_topic_header")} + {t("prefs_access_table_access_header")} + + + + + {props.entries.map(entry => ( + + {entry.topic} + + + {t("prefs_access_table_perms_private")} + + + handleEditClick(entry)} aria-label={t("prefs_access_edit_button")}> + + + handleDeleteClick(entry)} aria-label={t("prefs_access_delete_button")}> + + + + + ))} + + {/**/} +
+ ); +}; + const maybeUpdateAccountSettings = async (payload) => { if (!session.exists()) { return;