created ReservedAliasesRoute.tsx

This commit is contained in:
Myzel394 2023-02-04 14:36:26 +01:00
parent dead769e88
commit dac14af539
6 changed files with 152 additions and 12 deletions

View File

@ -280,6 +280,22 @@
"title": "Log out", "title": "Log out",
"description": "We are logging you out..." "description": "We are logging you out..."
}, },
"ReservedAliasesRoute": {
"title": "Reserved Aliases",
"pageActions": {
"search": {
"label": "Search",
"placeholder": "Search for aliases"
}
},
"actions": {
"create": {
"label": "Create new Reserved Alias"
}
},
"userAmount_one": "Forwards to one user",
"userAmount_other": "Forwards to {{count}} users"
},
"AdminRoute": { "AdminRoute": {
"title": "Site configuration", "title": "Site configuration",
"forms": { "forms": {

View File

@ -21,6 +21,7 @@ import LogoutRoute from "~/routes/LogoutRoute"
import OverviewRoute from "~/routes/OverviewRoute" import OverviewRoute from "~/routes/OverviewRoute"
import ReportDetailRoute from "~/routes/ReportDetailRoute" import ReportDetailRoute from "~/routes/ReportDetailRoute"
import ReportsRoute from "~/routes/ReportsRoute" import ReportsRoute from "~/routes/ReportsRoute"
import ReservedAliasesRoute from "~/routes/ReservedAliasesRoute"
import RootRoute from "~/routes/Root" import RootRoute from "~/routes/Root"
import SettingsRoute from "~/routes/SettingsRoute" import SettingsRoute from "~/routes/SettingsRoute"
import SignupRoute from "~/routes/SignupRoute" import SignupRoute from "~/routes/SignupRoute"
@ -99,6 +100,10 @@ const router = createBrowserRouter([
loader: getServerSettings, loader: getServerSettings,
element: <EnterDecryptionPassword />, element: <EnterDecryptionPassword />,
}, },
{
path: "/admin/reserved-aliases",
element: <ReservedAliasesRoute />,
},
{ {
path: "/admin/reserved-aliases/create", path: "/admin/reserved-aliases/create",
loader: getServerSettings, loader: getServerSettings,

View File

@ -4,7 +4,7 @@ import {MdMail} from "react-icons/md"
import {useLoaderData} from "react-router" import {useLoaderData} from "react-router"
import {ServerSettings} from "~/server-types" import {ServerSettings} from "~/server-types"
import {useTranslation} from "react-i18next" import {useTranslation} from "react-i18next"
import {BsArrowDown} from "react-icons/bs" import {BsArrowRight} from "react-icons/bs"
import {FaMask} from "react-icons/fa" import {FaMask} from "react-icons/fa"
import {HiUsers} from "react-icons/hi" import {HiUsers} from "react-icons/hi"
@ -21,13 +21,14 @@ export default function AliasExplanation({local, emails}: AliasExplanationProps)
return ( return (
<Grid <Grid
container container
direction="column" direction="row"
padding={4} padding={4}
gap={4} gap={4}
borderRadius={theme.shape.borderRadius} borderRadius={theme.shape.borderRadius}
border={1} border={1}
borderColor={theme.palette.text.disabled} borderColor={theme.palette.text.disabled}
bgcolor={theme.palette.background.default} bgcolor={theme.palette.background.default}
flexWrap="nowrap"
> >
<Grid item> <Grid item>
<Grid container direction="column" spacing={1} alignItems="center"> <Grid container direction="column" spacing={1} alignItems="center">
@ -35,7 +36,7 @@ export default function AliasExplanation({local, emails}: AliasExplanationProps)
<MdMail size={24} /> <MdMail size={24} />
</Grid> </Grid>
<Grid item> <Grid item>
<Typography variant="caption" align="center"> <Typography variant="caption" textAlign="center">
{t("routes.AdminRoute.forms.reservedAliases.explanation.step1")} {t("routes.AdminRoute.forms.reservedAliases.explanation.step1")}
</Typography> </Typography>
</Grid> </Grid>
@ -44,10 +45,10 @@ export default function AliasExplanation({local, emails}: AliasExplanationProps)
<Grid item> <Grid item>
<Grid container direction="column" spacing={1} alignItems="center"> <Grid container direction="column" spacing={1} alignItems="center">
<Grid item> <Grid item>
<BsArrowDown size={24} /> <BsArrowRight size={24} />
</Grid> </Grid>
<Grid item> <Grid item>
<Typography variant="caption" align="center"> <Typography variant="caption" textAlign="center">
{t("routes.AdminRoute.forms.reservedAliases.explanation.step2")} {t("routes.AdminRoute.forms.reservedAliases.explanation.step2")}
</Typography> </Typography>
</Grid> </Grid>
@ -59,9 +60,11 @@ export default function AliasExplanation({local, emails}: AliasExplanationProps)
<FaMask size={24} /> <FaMask size={24} />
</Grid> </Grid>
<Grid item> <Grid item>
<Typography variant="body1" align="center"> <Typography variant="body1" textAlign="center">
<span style={{display: "block"}}>{local}</span> <span style={{display: "block"}}>{local}</span>
<span style={{opacity: 0.4}}>@{serverSettings.mailDomain}</span> <span style={{opacity: 0.4, wordBreak: "break-word"}}>
@{serverSettings.mailDomain}
</span>
</Typography> </Typography>
</Grid> </Grid>
</Grid> </Grid>
@ -69,10 +72,10 @@ export default function AliasExplanation({local, emails}: AliasExplanationProps)
<Grid item> <Grid item>
<Grid container direction="column" spacing={1} alignItems="center"> <Grid container direction="column" spacing={1} alignItems="center">
<Grid item> <Grid item>
<BsArrowDown size={24} /> <BsArrowRight size={24} />
</Grid> </Grid>
<Grid item> <Grid item>
<Typography variant="caption" align="center"> <Typography variant="caption" textAlign="center">
{t("routes.AdminRoute.forms.reservedAliases.explanation.step4")} {t("routes.AdminRoute.forms.reservedAliases.explanation.step4")}
</Typography> </Typography>
</Grid> </Grid>

View File

@ -77,14 +77,13 @@ export default function CreateReservedAliasRoute(): ReactElement {
})), })),
}) })
} catch (error) { } catch (error) {
console.log(parseFastAPIError(error as AxiosError))
setErrors(parseFastAPIError(error as AxiosError)) setErrors(parseFastAPIError(error as AxiosError))
} }
}, },
}) })
return ( return (
<Grid container spacing={4} flexDirection="column" alignItems="center"> <Grid container spacing={2} flexDirection="column" alignItems="center">
<Grid item> <Grid item>
<form onSubmit={formik.handleSubmit}> <form onSubmit={formik.handleSubmit}>
<SimpleForm <SimpleForm
@ -133,7 +132,10 @@ export default function CreateReservedAliasRoute(): ReactElement {
</form> </form>
</Grid> </Grid>
<Grid item> <Grid item>
<AliasExplanation local={formik.values.local} emails={[]} /> <AliasExplanation
local={formik.values.local}
emails={formik.values.users.map(user => user.email.address)}
/>
</Grid> </Grid>
</Grid> </Grid>
) )

View File

@ -0,0 +1,113 @@
import {ReactElement, useState, useTransition} from "react"
import {AxiosError} from "axios"
import {useTranslation} from "react-i18next"
import {MdAdd, MdSearch} from "react-icons/md"
import {Link} from "react-router-dom"
import {
Button,
InputAdornment,
List,
ListItemButton,
ListItemSecondaryAction,
ListItemText,
Switch,
TextField,
} from "@mui/material"
import {useQuery} from "@tanstack/react-query"
import {PaginationResult, ReservedAlias} from "~/server-types"
import {getReservedAliases} from "~/apis"
import {QueryResult, SimplePage} from "~/components"
export default function ReservedAliasesRoute(): ReactElement {
const {t} = useTranslation()
const [showSearch, setShowSearch] = useState<boolean>(false)
const [searchValue, setSearchValue] = useState<string>("")
const [queryValue, setQueryValue] = useState<string>("")
const [, startTransition] = useTransition()
const query = useQuery<PaginationResult<ReservedAlias>, AxiosError>(
["getReservedAliases", {queryValue}],
() =>
getReservedAliases({
query: queryValue,
}),
{
onSuccess: () => {
setShowSearch(true)
},
},
)
return (
<SimplePage
title={t("routes.ReservedAliasesRoute.title")}
pageOptionsActions={
showSearch && (
<TextField
key="search"
fullWidth
value={searchValue}
onChange={event => {
setSearchValue(event.target.value)
startTransition(() => {
setQueryValue(event.target.value)
})
}}
label={t("routes.ReservedAliasesRoute.pageActions.search.label")}
placeholder={t(
"routes.ReservedAliasesRoute.pageActions.search.placeholder",
)}
id="search"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<MdSearch />
</InputAdornment>
),
}}
/>
)
}
actions={
<Button
component={Link}
startIcon={<MdAdd />}
to="/admin/reserved-aliases/create"
variant="contained"
>
{t("routes.ReservedAliasesRoute.actions.create.label")}
</Button>
}
>
<QueryResult<PaginationResult<ReservedAlias>, AxiosError> query={query}>
{({items: aliases}) => (
<List>
{aliases.map(alias => (
<ListItemButton
to={`/admin/reserved-aliases/${alias.id}`}
component={Link}
key={alias.id}
>
<ListItemText
primary={
<>
<span>{alias.local}</span>
<span style={{opacity: 0.4}}>@{alias.domain}</span>
</>
}
secondary={t("routes.ReservedAliasesRoute.userAmount", {
count: alias.users.length,
})}
/>
<ListItemSecondaryAction>
<Switch checked={alias.isActive} />
</ListItemSecondaryAction>
</ListItemButton>
))}
</List>
)}
</QueryResult>
</SimplePage>
)
}

View File

@ -103,6 +103,7 @@ export interface Alias {
export interface ReservedAlias { export interface ReservedAlias {
id: string id: string
isActive: boolean
domain: string domain: string
local: string local: string
users: Array<{ users: Array<{