rewrite form

This commit is contained in:
Ildar Kamalov 2024-12-12 17:01:30 +03:00
parent 77420d8c96
commit 8e2dea267c
7 changed files with 76 additions and 63 deletions

View file

@ -44,7 +44,7 @@ const Check = ({ onSubmit }: Props) => {
type="text" type="text"
className="form-control" className="form-control"
placeholder={t('form_enter_host') ?? ''} placeholder={t('form_enter_host') ?? ''}
{...register('name', { required: true })} {...register('name', { required: t('form_error_required') })}
/> />
<span className="input-group-append"> <span className="input-group-append">
<button <button

View file

@ -1,50 +1,71 @@
import React from 'react'; import React from 'react';
import { useForm } from 'react-hook-form';
import { Trans, useTranslation } from 'react-i18next';
import { Field, reduxForm } from 'redux-form'; import { validateAnswer, validateDomain } from '../../../helpers/validators';
import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow';
import { renderInputField } from '../../../helpers/form'; interface FormValues {
import { validateAnswer, validateDomain, validateRequiredValue } from '../../../helpers/validators'; domain: string;
import { FORM_NAME } from '../../../helpers/constants'; answer: string;
interface FormProps {
pristine: boolean;
handleSubmit: (...args: unknown[]) => string;
reset: (...args: unknown[]) => string;
toggleRewritesModal: (...args: unknown[]) => unknown;
submitting: boolean;
processingAdd: boolean;
t: (...args: unknown[]) => string;
initialValues?: object;
} }
const Form = (props: FormProps) => { type Props = {
const { t, handleSubmit, reset, pristine, submitting, toggleRewritesModal, processingAdd } = props; processingAdd: boolean;
currentRewrite?: { answer: string, domain: string; };
toggleRewritesModal: () => void;
onSubmit?: (data: FormValues) => Promise<void> | void;
}
const Form = ({ processingAdd, currentRewrite, toggleRewritesModal, onSubmit }: Props) => {
const { t } = useTranslation();
const {
register,
handleSubmit,
reset,
formState: { isDirty, isSubmitting, errors },
} = useForm<FormValues>({
mode: 'onChange',
defaultValues: {
domain: currentRewrite?.domain || '',
answer: currentRewrite?.answer || '',
},
});
const handleFormSubmit = async (data: FormValues) => {
if (onSubmit) {
await onSubmit(data);
}
};
return ( return (
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit(handleFormSubmit)}>
<div className="modal-body"> <div className="modal-body">
<div className="form__desc form__desc--top"> <div className="form__desc form__desc--top">
<Trans>domain_desc</Trans> <Trans>domain_desc</Trans>
</div> </div>
<div className="form__group"> <div className="form__group">
<Field <input
id="domain" id="domain"
name="domain"
component={renderInputField}
type="text" type="text"
className="form-control" className="form-control"
placeholder={t('form_domain')} placeholder={t('form_domain')}
validate={[validateRequiredValue, validateDomain]} {...register('domain', {
validate: validateDomain,
required: t('form_error_required'),
})}
/> />
{errors.domain && (
<div className="form__message form__message--error">
{errors.domain.message}
</div>
)}
</div> </div>
<Trans>examples_title</Trans>: <Trans>examples_title</Trans>:
<ol className="leading-loose"> <ol className="leading-loose">
<li> <li>
<code>example.org</code> <Trans>example_rewrite_domain</Trans> <code>example.org</code> <Trans>example_rewrite_domain</Trans>
</li> </li>
<li> <li>
<code>*.example.org</code> &nbsp; <code>*.example.org</code> &nbsp;
<span> <span>
@ -53,15 +74,21 @@ const Form = (props: FormProps) => {
</li> </li>
</ol> </ol>
<div className="form__group"> <div className="form__group">
<Field <input
id="answer" id="answer"
name="answer"
component={renderInputField}
type="text" type="text"
className="form-control" className="form-control"
placeholder={t('form_answer')} placeholder={t('form_answer') ?? ''}
validate={[validateRequiredValue, validateAnswer]} {...register('answer', {
validate: validateAnswer,
required: t('form_error_required'),
})}
/> />
{errors.answer && (
<div className="form__message form__message--error">
{errors.answer.message}
</div>
)}
</div> </div>
</div> </div>
@ -78,18 +105,20 @@ const Form = (props: FormProps) => {
<button <button
type="button" type="button"
className="btn btn-secondary btn-standard" className="btn btn-secondary btn-standard"
disabled={submitting || processingAdd} disabled={isSubmitting || processingAdd}
onClick={() => { onClick={() => {
reset(); reset();
toggleRewritesModal(); toggleRewritesModal();
}}> }}
>
<Trans>cancel_btn</Trans> <Trans>cancel_btn</Trans>
</button> </button>
<button <button
type="submit" type="submit"
className="btn btn-success btn-standard" className="btn btn-success btn-standard"
disabled={submitting || pristine || processingAdd}> disabled={isSubmitting || !isDirty || processingAdd}
>
<Trans>save_btn</Trans> <Trans>save_btn</Trans>
</button> </button>
</div> </div>
@ -98,10 +127,4 @@ const Form = (props: FormProps) => {
); );
}; };
export default flow([ export default Form;
withTranslation(),
reduxForm({
form: FORM_NAME.REWRITES,
enableReinitialize: true,
}),
])(Form);

View file

@ -14,7 +14,7 @@ interface ModalProps {
processingAdd: boolean; processingAdd: boolean;
processingDelete: boolean; processingDelete: boolean;
modalType: string; modalType: string;
currentRewrite?: object; currentRewrite?: { answer: string, domain: string; };
} }
const Modal = (props: ModalProps) => { const Modal = (props: ModalProps) => {
@ -23,7 +23,6 @@ const Modal = (props: ModalProps) => {
handleSubmit, handleSubmit,
toggleRewritesModal, toggleRewritesModal,
processingAdd, processingAdd,
processingDelete,
modalType, modalType,
currentRewrite, currentRewrite,
} = props; } = props;
@ -50,11 +49,10 @@ const Modal = (props: ModalProps) => {
</div> </div>
<Form <Form
initialValues={{ ...currentRewrite }}
onSubmit={handleSubmit} onSubmit={handleSubmit}
toggleRewritesModal={toggleRewritesModal} toggleRewritesModal={toggleRewritesModal}
processingAdd={processingAdd} processingAdd={processingAdd}
processingDelete={processingDelete} currentRewrite={currentRewrite}
/> />
</div> </div>
</ReactModal> </ReactModal>

View file

@ -63,6 +63,7 @@
} }
.form__message { .form__message {
margin-top: 4px;
font-size: 11px; font-size: 11px;
} }

View file

@ -292,7 +292,7 @@ export const validateIsSafePort = (value: any) => {
*/ */
export const validateDomain = (value: any) => { export const validateDomain = (value: any) => {
if (value && !R_HOST.test(value)) { if (value && !R_HOST.test(value)) {
return 'form_error_domain_format'; return i18next.t('form_error_domain_format');
} }
return undefined; return undefined;
}; };
@ -303,7 +303,7 @@ export const validateDomain = (value: any) => {
*/ */
export const validateAnswer = (value: any) => { export const validateAnswer = (value: any) => {
if (value && !R_IPV4.test(value) && !R_IPV6.test(value) && !R_HOST.test(value)) { if (value && !R_IPV4.test(value) && !R_IPV6.test(value) && !R_HOST.test(value)) {
return 'form_error_answer_format'; return i18next.t('form_error_answer_format');
} }
return undefined; return undefined;
}; };

View file

@ -55,17 +55,14 @@ const Auth = (props: Props) => {
<Trans>install_auth_username</Trans> <Trans>install_auth_username</Trans>
</label> </label>
<input <input
{...register('username', { required: { {...register('username', { required: t('form_error_required') })}
value: true,
message: i18n.t('form_error_required'),
}})}
type="text" type="text"
className={cn('form-control', { 'is-invalid': errors.username })} className={cn('form-control', { 'is-invalid': errors.username })}
placeholder={t('install_auth_username_enter')} placeholder={t('install_auth_username_enter')}
autoComplete="username" autoComplete="username"
/> />
{errors.username && ( {errors.username && (
<div className="invalid-feedback"> <div className="form__message form__message--error">
{errors.username.message} {errors.username.message}
</div> </div>
)} )}
@ -77,10 +74,7 @@ const Auth = (props: Props) => {
</label> </label>
<input <input
{...register('password', { {...register('password', {
required: { required: t('form_error_required'),
value: true,
message: i18n.t('form_error_required'),
},
validate: validatePasswordLength, validate: validatePasswordLength,
})} })}
type="password" type="password"
@ -89,8 +83,8 @@ const Auth = (props: Props) => {
autoComplete="new-password" autoComplete="new-password"
/> />
{errors.password && ( {errors.password && (
<div className="invalid-feedback"> <div className="form__message form__message--error">
{errors.password.message || i18n.t('form_error_password_length')} {errors.password.message}
</div> </div>
)} )}
</div> </div>
@ -101,10 +95,7 @@ const Auth = (props: Props) => {
</label> </label>
<input <input
{...register('confirm_password', { {...register('confirm_password', {
required: { required: t('form_error_required'),
value: true,
message: i18n.t('form_error_required'),
},
validate: validateConfirmPassword, validate: validateConfirmPassword,
})} })}
type="password" type="password"

View file

@ -276,7 +276,7 @@ const Settings: React.FC<Props> = ({
)} )}
/> />
{errors.web?.port && ( {errors.web?.port && (
<div className="text-danger"> <div className="form__message form__message--error">
{errors.web.port.message} {errors.web.port.message}
</div> </div>
)} )}
@ -376,7 +376,7 @@ const Settings: React.FC<Props> = ({
)} )}
/> />
{errors.dns?.port.message && ( {errors.dns?.port.message && (
<div className="text-danger"> <div className="form__message form__message--error">
{t(errors.dns.port.message)} {t(errors.dns.port.message)}
</div> </div>
)} )}