kleckrelay/src/route-widgets/AliasDetailRoute/AliasPreferencesForm.tsx
2023-03-05 09:35:02 +01:00

211 lines
6.3 KiB
TypeScript

import * as yup from "yup"
import {ReactElement, useContext} from "react"
import {BsImage, BsShieldShaded} from "react-icons/bs"
import {useFormik} from "formik"
import {FaFile} from "react-icons/fa"
import {MdCheckCircle, MdTextSnippet} from "react-icons/md"
import {AxiosError} from "axios"
import {useTranslation} from "react-i18next"
import {LoadingButton} from "@mui/lab"
import {Box, Collapse, Grid, Typography} from "@mui/material"
import {QueryKey, useMutation} from "@tanstack/react-query"
import {Alias, DecryptedAlias, ImageProxyFormatType, ProxyUserAgentType} from "~/server-types"
import {UpdateAliasData, updateAlias} from "~/apis"
import {parseFastAPIError} from "~/utils"
import {
IMAGE_PROXY_FORMAT_TYPE_NAME_MAP,
PROXY_USER_AGENT_TYPE_NAME_MAP,
} from "~/constants/enum-mappings"
import {useErrorSuccessSnacks} from "~/hooks"
import {queryClient} from "~/constants/react-query"
import {AuthContext, FormikAutoLockNavigation} from "~/components"
import SelectField from "~/route-widgets/AliasDetailRoute/SelectField"
import decryptAliasNotes from "~/apis/helpers/decrypt-alias-notes"
export interface AliasPreferencesFormProps {
alias: Alias | DecryptedAlias
queryKey: QueryKey
}
interface Form {
removeTrackers: boolean | null
createMailReport: boolean | null
proxyImages: boolean | null
imageProxyFormat: ImageProxyFormatType | null
proxyUserAgent: ProxyUserAgentType | null
detail?: string
}
export default function AliasPreferencesForm({
alias,
queryKey,
}: AliasPreferencesFormProps): ReactElement {
const {t} = useTranslation(["aliases", "common"])
const {showSuccess, showError} = useErrorSuccessSnacks()
const {_decryptUsingMasterPassword} = useContext(AuthContext)
const schema = yup.object().shape({
removeTrackers: yup
.mixed<boolean | null>()
.oneOf([true, false, null])
.label(t("settings.fields.removeTrackers.label")),
createMailReport: yup
.mixed<boolean | null>()
.oneOf([true, false, null])
.label(t("settings.fields.createMailReport.label")),
proxyImages: yup
.mixed<boolean | null>()
.oneOf([true, false, null])
.label(t("settings.fields.proxyImages.label")),
imageProxyFormat: yup
.mixed<ImageProxyFormatType>()
.oneOf([null, ...Object.values(ImageProxyFormatType)])
.label(t("settings.fields.imageProxyFormat.label")),
proxyUserAgent: yup
.mixed<ProxyUserAgentType>()
.oneOf([null, ...Object.values(ProxyUserAgentType)])
.label(t("settings.fields.proxyUserAgent.label")),
expandUrlShorteners: yup
.mixed<boolean | null>()
.oneOf([true, false, null])
.label(t("settings.fields.expandUrlShorteners.label")),
})
const {mutateAsync} = useMutation<Alias, AxiosError, UpdateAliasData>(
data => updateAlias(alias.id, data),
{
onSuccess: async newAlias => {
showSuccess(t("messages.alias.updated", {ns: "common"}))
;(newAlias as any as DecryptedAlias).notes = decryptAliasNotes(
newAlias.encryptedNotes,
_decryptUsingMasterPassword,
)
await queryClient.cancelQueries(queryKey)
queryClient.setQueryData<DecryptedAlias>(
queryKey,
newAlias as any as DecryptedAlias,
)
},
onError: showError,
},
)
const formik = useFormik<Form>({
enableReinitialize: true,
initialValues: {
removeTrackers: alias.prefRemoveTrackers,
createMailReport: alias.prefCreateMailReport,
proxyImages: alias.prefProxyImages,
imageProxyFormat: alias.prefImageProxyFormat,
proxyUserAgent: alias.prefProxyUserAgent,
},
validationSchema: schema,
onSubmit: async (values, {setErrors}) => {
try {
await mutateAsync({
prefCreateMailReport: values.createMailReport,
prefRemoveTrackers: values.removeTrackers,
prefProxyImages: values.proxyImages,
prefImagProxyFormat: values.imageProxyFormat,
prefProxyUserAgent: values.proxyUserAgent,
})
} catch (error) {
setErrors(parseFastAPIError(error as AxiosError))
}
},
})
return (
<>
<form onSubmit={formik.handleSubmit}>
<Box marginTop={1}>
<Grid container spacing={4} flexDirection="column" alignItems="center">
<Grid item>
<Grid container spacing={4}>
<Grid item xs={12} sm={6}>
<SelectField
label={t("settings.fields.removeTrackers.label")}
formik={formik}
icon={<BsShieldShaded />}
name="removeTrackers"
/>
</Grid>
<Grid item xs={12} sm={6}>
<SelectField
label={t("settings.fields.createMailReport.label")}
formik={formik}
icon={<MdTextSnippet />}
name="createMailReport"
/>
</Grid>
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={12}>
<SelectField
label={t("settings.fields.proxyImages.label")}
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={t(
"settings.fields.imageProxyFormat.label",
)}
formik={formik}
icon={<FaFile />}
name="imageProxyFormat"
valueTextMap={
IMAGE_PROXY_FORMAT_TYPE_NAME_MAP
}
/>
</Grid>
<Grid item xs={12} sm={6}>
<SelectField
label={t(
"settings.fields.proxyUserAgent.label",
)}
formik={formik}
name="proxyUserAgent"
valueTextMap={
PROXY_USER_AGENT_TYPE_NAME_MAP
}
/>
</Grid>
</Grid>
</Collapse>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid item>
<LoadingButton
loading={formik.isSubmitting}
variant="contained"
type="submit"
startIcon={<MdCheckCircle />}
>
{t("settings.continueActionLabel")}
</LoadingButton>
</Grid>
<Grid item>
<Typography variant="body2">{t("settings.description")}</Typography>
</Grid>
</Grid>
</Box>
</form>
<FormikAutoLockNavigation formik={formik} />
</>
)
}