mirror of
https://github.com/Myzel394/kleckrelay-website.git
synced 2025-06-19 07:55:25 +02:00
created ReservedAliasesRoute.tsx
This commit is contained in:
parent
dead769e88
commit
dac14af539
@ -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": {
|
||||||
|
@ -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,
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
)
|
)
|
||||||
|
113
src/routes/ReservedAliasesRoute.tsx
Normal file
113
src/routes/ReservedAliasesRoute.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
@ -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<{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user