adding AliasDetailRoute.tsx

This commit is contained in:
Myzel394 2022-10-23 21:13:10 +02:00
parent 044c98f348
commit 7225dcc98c
13 changed files with 341 additions and 32 deletions

2
README.md Normal file
View File

@ -0,0 +1,2 @@
* Make `Page` component
* TextInput -> Select

View File

@ -7,6 +7,7 @@ import {CssBaseline, ThemeProvider} from "@mui/material"
import {queryClient} from "~/constants/react-query" import {queryClient} from "~/constants/react-query"
import {lightTheme} from "~/constants/themes" import {lightTheme} from "~/constants/themes"
import {getServerSettings} from "~/apis" import {getServerSettings} from "~/apis"
import AliasDetailRoute from "~/routes/AliasDetailRoute"
import AliasesRoute from "~/routes/AliasesRoute" import AliasesRoute from "~/routes/AliasesRoute"
import AuthContextProvider from "~/AuthContext/AuthContextProvider" import AuthContextProvider from "~/AuthContext/AuthContextProvider"
import AuthenticateRoute from "~/routes/AuthenticateRoute" import AuthenticateRoute from "~/routes/AuthenticateRoute"
@ -60,6 +61,10 @@ const router = createBrowserRouter([
path: "/aliases", path: "/aliases",
element: <AliasesRoute />, element: <AliasesRoute />,
}, },
{
path: "/aliases/:addressInBase64",
element: <AliasDetailRoute />,
},
{ {
path: "/settings", path: "/settings",
element: <SettingsRoute />, element: <SettingsRoute />,

View File

@ -9,11 +9,12 @@ import {client} from "~/constants/axios-client"
interface CreateAliasDataOther { interface CreateAliasDataOther {
isActive?: boolean isActive?: boolean
encryptedNotes?: string encryptedNotes?: string
removeTrackers?: boolean
createMailReport?: boolean prefRemoveTrackers?: boolean
proxyImages?: boolean prefCreateMailReport?: boolean
imageProxyFormat?: ImageProxyFormatType prefProxyImages?: boolean
imageProxyUserAgent?: ProxyUserAgentType prefImageProxyFormat?: ImageProxyFormatType
prefImageProxyUserAgent?: ProxyUserAgentType
} }
interface CreateAliasDataBase extends CreateAliasDataOther { interface CreateAliasDataBase extends CreateAliasDataOther {

13
src/apis/get-alias.ts Normal file
View File

@ -0,0 +1,13 @@
import {client} from "~/constants/axios-client"
import {Alias} from "~/server-types"
export default async function getAlias(address: string): Promise<Alias> {
const {data} = await client.get(
`${import.meta.env.VITE_SERVER_BASE_URL}/alias/${address}`,
{
withCredentials: true,
},
)
return data
}

View File

@ -1,7 +1,9 @@
import {Alias, PaginationResult} from "~/server-types" import {AliasList, PaginationResult} from "~/server-types"
import {client} from "~/constants/axios-client" import {client} from "~/constants/axios-client"
export default async function getAliases(): Promise<PaginationResult<Alias>> { export default async function getAliases(): Promise<
PaginationResult<AliasList>
> {
const {data} = await client.get( const {data} = await client.get(
`${import.meta.env.VITE_SERVER_BASE_URL}/alias`, `${import.meta.env.VITE_SERVER_BASE_URL}/alias`,
{ {

View File

@ -30,3 +30,5 @@ export * from "./get-reports"
export {default as getReports} from "./get-reports" export {default as getReports} from "./get-reports"
export * from "./get-report" export * from "./get-report"
export {default as getReport} from "./get-report" export {default as getReport} from "./get-report"
export * from "./get-alias"
export {default as getAlias} from "./get-alias"

View File

@ -0,0 +1,22 @@
import {ImageProxyFormatType, ProxyUserAgentType} from "~/server-types"
export const IMAGE_PROXY_FORMAT_TYPE_NAME_MAP: Record<
ImageProxyFormatType,
string
> = {
[ImageProxyFormatType.JPEG]: "JPEG",
[ImageProxyFormatType.PNG]: "PNG",
[ImageProxyFormatType.WEBP]: "WebP",
}
export const IMAGE_PROXY_USER_AGENT_TYPE_NAME_MAP: Record<
ProxyUserAgentType,
string
> = {
[ProxyUserAgentType.APPLE_MAIL]: "Apple Mail",
[ProxyUserAgentType.GOOGLE_MAIL]: "Google Mail",
[ProxyUserAgentType.CHROME]: "Chrome Browser",
[ProxyUserAgentType.FIREFOX]: "Firefox Browser",
[ProxyUserAgentType.OUTLOOK_MACOS]: "Outlook / MacOS",
[ProxyUserAgentType.OUTLOOK_WINDOWS]: "Outlook / Windows",
}

View File

@ -0,0 +1,140 @@
import * as yup from "yup"
import {ReactElement} from "react"
import {BsImage, BsShieldShaded} from "react-icons/bs"
import {useFormik} from "formik"
import {FaFile} from "react-icons/fa"
import {Collapse, Grid} from "@mui/material"
import {mdiTextBoxMultiple} from "@mdi/js/commonjs/mdi"
import Icon from "@mdi/react"
import {Alias, ImageProxyFormatType, ProxyUserAgentType} from "~/server-types"
import {LoadingButton} from "@mui/lab"
import {MdCheckCircle} from "react-icons/md"
import SelectField from "~/route-widgets/SettingsRoute/SelectField"
export interface AliasPreferencesFormProps {
alias: Alias
}
interface Form {
removeTrackers: boolean
createMailReport: boolean
proxyImages: boolean
imageProxyFormat: ImageProxyFormatType
imageProxyUserAgent: ProxyUserAgentType
detail?: string
}
const SCHEMA = yup.object().shape({
removeTrackers: yup.boolean(),
createMailReport: yup.boolean(),
proxyImages: yup.boolean(),
imageProxyFormat: yup
.mixed<ImageProxyFormatType>()
.oneOf(Object.values(ImageProxyFormatType))
.required(),
imageProxyUserAgent: yup
.mixed<ProxyUserAgentType>()
.oneOf(Object.values(ProxyUserAgentType))
.required(),
})
export default function AliasPreferencesForm({
alias,
}: AliasPreferencesFormProps): ReactElement {
const formik = useFormik<Form>({
initialValues: {
removeTrackers: alias.prefRemoveTrackers,
createMailReport: alias.prefCreateMailReport,
proxyImages: alias.prefProxyImages,
imageProxyFormat: alias.prefImageProxyFormat,
imageProxyUserAgent: alias.prefImageProxyUserAgent,
},
validationSchema: SCHEMA,
onSubmit: () => null,
})
return (
<form onSubmit={formik.handleSubmit}>
<Grid
container
spacing={4}
flexDirection="column"
alignItems="center"
>
<Grid item>
<Grid container spacing={4}>
<Grid item xs={12} sm={6}>
<SelectField
label="Remove Trackers"
formik={formik}
icon={<BsShieldShaded />}
name="removeTrackers"
/>
</Grid>
<Grid item xs={12} sm={6}>
<SelectField
label="Create Reports"
formik={formik}
icon={
<Icon
path={mdiTextBoxMultiple}
size={0.8}
/>
}
name="createMailReport"
/>
</Grid>
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={12}>
<SelectField
label="Proxy Images"
formik={formik}
icon={<BsImage />}
name="proxyImages"
/>
</Grid>
<Grid item xs={12}>
<Collapse
in={formik.values.proxyImages !== false}
>
<Grid container spacing={4}>
<Grid item xs={12} sm={6}>
<SelectField
label="Image File Type"
formik={formik}
icon={<FaFile />}
name="imageProxyFormat"
/>
</Grid>
<Grid item xs={12} sm={6}>
<SelectField
label="Image Proxy User Agent"
formik={formik}
name="imageProxyUserAgent"
/>
</Grid>
</Grid>
</Collapse>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid item>
<LoadingButton
loading={formik.isSubmitting}
variant="contained"
type="submit"
startIcon={<MdCheckCircle />}
>
Save Settings
</LoadingButton>
</Grid>
</Grid>
</form>
)
}

View File

@ -3,7 +3,7 @@ import {MdOutlineMoreVert} from "react-icons/md"
import { import {
IconButton, IconButton,
ListItem, ListItemButton,
ListItemSecondaryAction, ListItemSecondaryAction,
ListItemText, ListItemText,
} from "@mui/material" } from "@mui/material"
@ -17,14 +17,16 @@ export interface AliasListItemProps {
export default function AliasListItem({ export default function AliasListItem({
alias, alias,
}: AliasListItemProps): ReactElement { }: AliasListItemProps): ReactElement {
const address = `${alias.local}@${alias.domain}`
return ( return (
<ListItem> <ListItemButton href={`/aliases/${btoa(address)}`}>
<ListItemText primary={`${alias.local}@${alias.domain}`} /> <ListItemText primary={address} />
<ListItemSecondaryAction> <ListItemSecondaryAction>
<IconButton edge="end"> <IconButton edge="end">
<MdOutlineMoreVert /> <MdOutlineMoreVert />
</IconButton> </IconButton>
</ListItemSecondaryAction> </ListItemSecondaryAction>
</ListItem> </ListItemButton>
) )
} }

View File

@ -30,6 +30,10 @@ import {UpdatePreferencesData, updatePreferences} from "~/apis"
import {useUser} from "~/hooks" import {useUser} from "~/hooks"
import {parseFastAPIError} from "~/utils" import {parseFastAPIError} from "~/utils"
import {SuccessSnack} from "~/components" import {SuccessSnack} from "~/components"
import {
IMAGE_PROXY_FORMAT_TYPE_NAME_MAP,
IMAGE_PROXY_USER_AGENT_TYPE_NAME_MAP,
} from "~/constants/enum_mappings"
import AuthContext from "~/AuthContext/AuthContext" import AuthContext from "~/AuthContext/AuthContext"
import ErrorSnack from "~/components/ErrorSnack" import ErrorSnack from "~/components/ErrorSnack"
@ -57,22 +61,6 @@ const SCHEMA = yup.object().shape({
.required(), .required(),
}) })
const IMAGE_PROXY_FORMAT_TYPE_NAME_MAP: Record<ImageProxyFormatType, string> = {
[ImageProxyFormatType.JPEG]: "JPEG",
[ImageProxyFormatType.PNG]: "PNG",
[ImageProxyFormatType.WEBP]: "WebP",
}
const IMAGE_PROXY_USER_AGENT_TYPE_NAME_MAP: Record<ProxyUserAgentType, string> =
{
[ProxyUserAgentType.APPLE_MAIL]: "Apple Mail",
[ProxyUserAgentType.GOOGLE_MAIL]: "Google Mail",
[ProxyUserAgentType.CHROME]: "Chrome Browser",
[ProxyUserAgentType.FIREFOX]: "Firefox Browser",
[ProxyUserAgentType.OUTLOOK_MACOS]: "Outlook / MacOS",
[ProxyUserAgentType.OUTLOOK_WINDOWS]: "Outlook / Windows",
}
export default function AliasesPreferencesForm(): ReactElement { export default function AliasesPreferencesForm(): ReactElement {
const {_updateUser} = useContext(AuthContext) const {_updateUser} = useContext(AuthContext)
const user = useUser() const user = useUser()

View File

@ -0,0 +1,64 @@
import {ReactElement, ReactNode} from "react"
import {
FormControl,
FormHelperText,
InputAdornment,
InputLabel,
MenuItem,
Select,
} from "@mui/material"
export interface SelectFieldProps {
label: string
formik: any
name: string
icon?: ReactElement
children?: ReactNode
}
export default function SelectField({
label,
formik,
icon,
name,
children,
}: SelectFieldProps): ReactElement {
const labelId = `${name}-label`
return (
<FormControl fullWidth>
<InputLabel id={labelId}>{label}</InputLabel>
<Select
fullWidth
name={name}
id={name}
label={label}
labelId={labelId}
startAdornment={
icon ? (
<InputAdornment position="start">{icon}</InputAdornment>
) : undefined
}
value={(formik.values[name] ?? "null").toString()}
onChange={formik.handleChange}
disabled={formik.isSubmitting}
error={Boolean(formik.touched[name] && formik.errors[name])}
>
{children ?? (
<MenuItem value="null">
<i>{"<Default>"}</i>
</MenuItem>
)}
{children ?? <MenuItem value="true">Yes</MenuItem>}
{children ?? <MenuItem value="false">No</MenuItem>}
</Select>
<FormHelperText
error={Boolean(formik.touched[name] && formik.errors[name])}
>
{formik.touched[name] && formik.errors[name]}
</FormHelperText>
</FormControl>
)
}

View File

@ -0,0 +1,60 @@
import {ReactElement} from "react"
import {useParams} from "react-router-dom"
import {AxiosError} from "axios"
import {useQuery} from "@tanstack/react-query"
import {Grid, Typography} from "@mui/material"
import {getAlias} from "~/apis"
import {Alias} from "~/server-types"
import AliasPreferencesForm from "~/route-widgets/AliasDetailRoute/AliasPreferencesForm"
import QueryResult from "~/components/QueryResult"
export default function AliasDetailRoute(): ReactElement {
const params = useParams()
const address = atob(params.addressInBase64 as string)
const query = useQuery<Alias, AxiosError>(
["get_alias", params.addressInBase64],
() => getAlias(address),
)
return (
<QueryResult<Alias> query={query}>
{alias => (
<Grid container spacing={4}>
<Grid item xs={12}>
<Typography variant="h4" component="h1">
Alias Details
</Typography>
</Grid>
<Grid item>
<Typography variant="subtitle1">{address}</Typography>
</Grid>
<Grid item>
<Grid container spacing={4}>
<Grid item>
<Typography variant="h6">Settings</Typography>
</Grid>
<Grid item>
<Typography variant="body1">
These settings apply to this alias only. You
can either set a value manually or refer to
your defaults settings. Note that this does
change in behavior. When you set a value to
refer to your default setting, the alias
will always use the latest value. So when
you change your default setting, the alias
will automatically use the new value.
</Typography>
</Grid>
<Grid item>
<AliasPreferencesForm alias={alias} />
</Grid>
</Grid>
</Grid>
</Grid>
)}
</QueryResult>
)
}

View File

@ -82,11 +82,19 @@ export interface Alias {
local: string local: string
isActive: boolean isActive: boolean
encryptedNotes: string encryptedNotes: string
removeTrackers: boolean
createMailReport: boolean prefRemoveTrackers: boolean
proxyImages: boolean prefCreateMailReport: boolean
imageProxyFormat: ImageProxyFormatType prefProxyImages: boolean
imageProxyUserAgent: ProxyUserAgentType prefImageProxyFormat: ImageProxyFormatType
prefImageProxyUserAgent: ProxyUserAgentType
}
export interface AliasList {
id: string
domain: string
local: string
isActive: boolean
} }
export interface Report { export interface Report {