From 61cba0e2126faf7e27ded27953e643192afca9d9 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Mon, 13 Jan 2025 16:57:12 +0300 Subject: [PATCH] add mobile config form --- client/src/components/ui/Guide/Guide.tsx | 2 +- .../components/ui/Guide/MobileConfigForm.tsx | 126 ++++++++++++------ client/src/helpers/validators.ts | 8 +- 3 files changed, 88 insertions(+), 48 deletions(-) diff --git a/client/src/components/ui/Guide/Guide.tsx b/client/src/components/ui/Guide/Guide.tsx index 672cc665..3b7c295b 100644 --- a/client/src/components/ui/Guide/Guide.tsx +++ b/client/src/components/ui/Guide/Guide.tsx @@ -7,7 +7,7 @@ import { MOBILE_CONFIG_LINKS } from '../../../helpers/constants'; import Tabs from '../Tabs'; -import MobileConfigForm from './MobileConfigForm'; +import { MobileConfigForm } from './MobileConfigForm'; import { RootState } from '../../../initialState'; interface renderLiProps { diff --git a/client/src/components/ui/Guide/MobileConfigForm.tsx b/client/src/components/ui/Guide/MobileConfigForm.tsx index cf64664b..d9a9a67c 100644 --- a/client/src/components/ui/Guide/MobileConfigForm.tsx +++ b/client/src/components/ui/Guide/MobileConfigForm.tsx @@ -1,27 +1,24 @@ import React from 'react'; import { Trans } from 'react-i18next'; -import { useSelector } from 'react-redux'; - -import { Field, reduxForm } from 'redux-form'; +import { useForm } from 'react-hook-form'; import i18next from 'i18next'; import cn from 'classnames'; import { getPathWithQueryString } from '../../../helpers/helpers'; -import { CLIENT_ID_LINK, FORM_NAME, MOBILE_CONFIG_LINKS, STANDARD_HTTPS_PORT } from '../../../helpers/constants'; -import { renderInputField, renderSelectField, toNumber } from '../../../helpers/form'; +import { CLIENT_ID_LINK, MOBILE_CONFIG_LINKS, STANDARD_HTTPS_PORT } from '../../../helpers/constants'; +import { toNumber } from '../../../helpers/form'; import { validateConfigClientId, validateServerName, validatePort, validateIsSafePort, } from '../../../helpers/validators'; -import { RootState } from '../../../initialState'; -const getDownloadLink = (host: any, clientId: any, protocol: any, invalid: any) => { +const getDownloadLink = (host: string, clientId: string, protocol: string, invalid: boolean) => { if (!host || invalid) { return ( ); } @@ -36,30 +33,49 @@ const getDownloadLink = (host: any, clientId: any, protocol: any, invalid: any) - download_mobileconfig + download + > + {i18next.t('download_mobileconfig')} ); }; -interface MobileConfigFormProps { - invalid: boolean; +const githubLink = ( + + text + +); + +type FormValues = { + host: string; + clientId: string; + protocol: string; + port?: number; } -const MobileConfigForm = ({ invalid }: MobileConfigFormProps) => { - const formValues = useSelector((state: RootState) => state.form[FORM_NAME.MOBILE_CONFIG]?.values); +type Props = { + initialValues?: FormValues; +} - if (!formValues) { - return null; - } +export const MobileConfigForm = ({ initialValues }: Props) => { + const { + register, + watch, + formState: { errors, isValid }, + } = useForm({ + mode: 'onChange', + defaultValues: { + host: initialValues?.host || '', + clientId: initialValues?.clientId || '', + protocol: initialValues?.protocol || MOBILE_CONFIG_LINKS.DOT, + port: initialValues?.port || undefined, + }, + }); - const { host, clientId, protocol, port } = formValues; - - const githubLink = ( - - text - - ); + const protocol = watch('protocol'); + const host = watch('host'); + const clientId = watch('clientId'); + const port = watch('port'); const getHostName = () => { if (port && port !== STANDARD_HTTPS_PORT && protocol === MOBILE_CONFIG_LINKS.DOH) { @@ -79,14 +95,20 @@ const MobileConfigForm = ({ invalid }: MobileConfigFormProps) => { {i18next.t('dhcp_table_hostname')} - + {errors.host && ( +
+ {errors.host.message} +
+ )} {protocol === MOBILE_CONFIG_LINKS.DOH && (
@@ -94,15 +116,25 @@ const MobileConfigForm = ({ invalid }: MobileConfigFormProps) => { {i18next.t('encryption_https')} - toNumber(val), + validate: { + range: (value) => validatePort(value) || true, + safety: (value) => validateIsSafePort(value) || true, + }, + })} /> + + {errors.port && ( +
+ {errors.port.message} +
+ )}
)} @@ -117,14 +149,21 @@ const MobileConfigForm = ({ invalid }: MobileConfigFormProps) => { client_id_desc - + + {errors.clientId && ( +
+ {errors.clientId.message} +
+ )}
@@ -132,17 +171,18 @@ const MobileConfigForm = ({ invalid }: MobileConfigFormProps) => { {i18next.t('protocol')} - +
- {getDownloadLink(getHostName(), clientId, protocol, invalid)} + {getDownloadLink(getHostName(), clientId, protocol, !isValid)} ); }; - -export default reduxForm({ form: FORM_NAME.MOBILE_CONFIG })(MobileConfigForm); diff --git a/client/src/helpers/validators.ts b/client/src/helpers/validators.ts index 87d441ee..3815339a 100644 --- a/client/src/helpers/validators.ts +++ b/client/src/helpers/validators.ts @@ -180,7 +180,7 @@ export const validateConfigClientId = (value: any) => { } const formattedValue = value.trim(); if (formattedValue && !R_CLIENT_ID.test(formattedValue)) { - return 'form_error_client_id_format'; + return i18next.t('form_error_client_id_format'); } return undefined; }; @@ -195,7 +195,7 @@ export const validateServerName = (value: any) => { } const formattedValue = value ? value.trim() : value; if (formattedValue && !R_DOMAIN.test(formattedValue)) { - return 'form_error_server_name'; + return i18next.t('form_error_server_name'); } return undefined; }; @@ -239,7 +239,7 @@ export const validateMac = (value: any) => { */ export const validatePort = (value: any) => { if ((value || value === 0) && (value < STANDARD_WEB_PORT || value > MAX_PORT)) { - return 'form_error_port_range'; + return i18next.t('form_error_port_range'); } return undefined; }; @@ -281,7 +281,7 @@ export const validatePortQuic = validatePortTLS; */ export const validateIsSafePort = (value: any) => { if (UNSAFE_PORTS.includes(value)) { - return 'form_error_port_unsafe'; + return i18next.t('form_error_port_unsafe'); } return undefined; };