mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-03-15 12:29:16 +01:00
(ui) allow form inputs to be disabled, possibly with a callback
This commit is contained in:
parent
2f0a8064c2
commit
1f2d3867aa
@ -96,7 +96,7 @@ export const ProviderForm: React.FC<ProviderFormProps> = ({ action, provider, on
|
||||
<form className="provider-form" onSubmit={handleSubmit(onSubmit)}>
|
||||
<FormInput id="name"
|
||||
register={register}
|
||||
readOnly={action === 'update'}
|
||||
disabled={action === 'update'}
|
||||
rules={{ required: true }}
|
||||
label={t('app.admin.authentication.provider_form.name')} />
|
||||
<FormSelect id="providable_type"
|
||||
@ -104,7 +104,7 @@ export const ProviderForm: React.FC<ProviderFormProps> = ({ action, provider, on
|
||||
options={buildProvidableTypeOptions()}
|
||||
label={t('app.admin.authentication.provider_form.authentication_type')}
|
||||
onChange={onProvidableTypeChange}
|
||||
readOnly={action === 'update'}
|
||||
disabled={action === 'update'}
|
||||
rules={{ required: true }} />
|
||||
{providableType === 'DatabaseProvider' && <DatabaseForm register={register} />}
|
||||
{providableType === 'OAuth2Provider' && <Oauth2Form register={register} strategyName={strategyName} />}
|
||||
|
@ -20,7 +20,8 @@ interface FabTextEditorProps {
|
||||
image?: boolean,
|
||||
onChange?: (content: string) => void,
|
||||
placeholder?: string,
|
||||
error?: string
|
||||
error?: string,
|
||||
readOnly?: boolean,
|
||||
}
|
||||
|
||||
export interface FabTextEditorRef {
|
||||
@ -30,7 +31,7 @@ export interface FabTextEditorRef {
|
||||
/**
|
||||
* This component is a WYSIWYG text editor
|
||||
*/
|
||||
export const FabTextEditor: React.ForwardRefRenderFunction<FabTextEditorRef, FabTextEditorProps> = ({ label, paragraphTools, content, limit = 400, video, image, onChange, placeholder, error }, ref: RefObject<FabTextEditorRef>) => {
|
||||
export const FabTextEditor: React.ForwardRefRenderFunction<FabTextEditorRef, FabTextEditorProps> = ({ label, paragraphTools, content, limit = 400, video, image, onChange, placeholder, error, readOnly = false }, ref: RefObject<FabTextEditorRef>) => {
|
||||
const { t } = useTranslation('shared');
|
||||
const placeholderText = placeholder || t('app.shared.text_editor.text_placeholder');
|
||||
// TODO: Add ctrl+click on link to visit
|
||||
@ -70,6 +71,7 @@ export const FabTextEditor: React.ForwardRefRenderFunction<FabTextEditorRef, Fab
|
||||
}
|
||||
})
|
||||
],
|
||||
editable: readOnly,
|
||||
content,
|
||||
onUpdate: ({ editor }) => {
|
||||
onChange(editor.getHTML());
|
||||
|
@ -8,7 +8,7 @@ export interface AbstractFormItemProps<TFieldValues> extends PropsWithChildren<A
|
||||
label?: string,
|
||||
tooltip?: ReactNode,
|
||||
className?: string,
|
||||
disabled?: boolean,
|
||||
disabled?: boolean|((id: string) => boolean),
|
||||
readOnly?: boolean
|
||||
onLabelClick?: (event: React.MouseEvent<HTMLLabelElement, MouseEvent>) => void,
|
||||
}
|
||||
@ -18,8 +18,9 @@ export interface AbstractFormItemProps<TFieldValues> extends PropsWithChildren<A
|
||||
* Other forms components that are intended to be used with react-hook-form must extend this component.
|
||||
*/
|
||||
export const AbstractFormItem = <TFieldValues extends FieldValues>({ id, label, tooltip, className, disabled, readOnly, error, warning, rules, formState, onLabelClick, children }: AbstractFormItemProps<TFieldValues>) => {
|
||||
const [isDirty, setIsDirty] = useState(false);
|
||||
const [fieldError, setFieldError] = useState(error);
|
||||
const [isDirty, setIsDirty] = useState<boolean>(false);
|
||||
const [fieldError, setFieldError] = useState<{ message: string }>(error);
|
||||
const [isDisabled, setIsDisabled] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsDirty(_get(formState?.dirtyFields, id));
|
||||
@ -30,6 +31,14 @@ export const AbstractFormItem = <TFieldValues extends FieldValues>({ id, label,
|
||||
setFieldError(error);
|
||||
}, [error]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof disabled === 'function') {
|
||||
setIsDisabled(disabled(id));
|
||||
} else {
|
||||
setIsDisabled(disabled);
|
||||
}
|
||||
}, [disabled]);
|
||||
|
||||
// Compose classnames from props
|
||||
const classNames = [
|
||||
'form-item',
|
||||
@ -38,7 +47,7 @@ export const AbstractFormItem = <TFieldValues extends FieldValues>({ id, label,
|
||||
`${isDirty && warning ? 'is-warned' : ''}`,
|
||||
`${rules && rules.required ? 'is-required' : ''}`,
|
||||
`${readOnly ? 'is-readonly' : ''}`,
|
||||
`${disabled ? 'is-disabled' : ''}`
|
||||
`${isDisabled ? 'is-disabled' : ''}`
|
||||
].join(' ');
|
||||
|
||||
/**
|
||||
|
@ -64,7 +64,7 @@ export const FormInput = <TFieldValues extends FieldValues, TInputType>({ id, re
|
||||
})}
|
||||
type={type}
|
||||
step={step}
|
||||
disabled={disabled}
|
||||
disabled={typeof disabled === 'function' ? disabled(id) : disabled}
|
||||
readOnly={readOnly}
|
||||
placeholder={placeholder}
|
||||
accept={accept} />
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import Select from 'react-select';
|
||||
import { Controller, Path } from 'react-hook-form';
|
||||
import { FieldValues } from 'react-hook-form/dist/types/fields';
|
||||
@ -26,6 +26,16 @@ type selectOption<TOptionValue> = { value: TOptionValue, label: string };
|
||||
* It is a multi-select component.
|
||||
*/
|
||||
export const FormMultiSelect = <TFieldValues extends FieldValues, TContext extends object, TOptionValue>({ id, label, tooltip, className, control, placeholder, options, valuesDefault, error, rules, disabled, onChange, formState, readOnly, warning, expectedResult }: FormSelectProps<TFieldValues, TContext, TOptionValue>) => {
|
||||
const [isDisabled, setIsDisabled] = React.useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof disabled === 'function') {
|
||||
setIsDisabled(disabled(id) || readOnly);
|
||||
} else {
|
||||
setIsDisabled(disabled || readOnly);
|
||||
}
|
||||
}, [disabled]);
|
||||
|
||||
/**
|
||||
* The following callback will trigger the onChange callback, if it was passed to this component,
|
||||
* when the selected option changes.
|
||||
@ -74,6 +84,7 @@ export const FormMultiSelect = <TFieldValues extends FieldValues, TContext exten
|
||||
}}
|
||||
placeholder={placeholder}
|
||||
options={options}
|
||||
isDisabled={isDisabled}
|
||||
isMulti />
|
||||
} />
|
||||
</AbstractFormItem>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { FormControlledComponent } from '../../models/form-component';
|
||||
import { AbstractFormItem, AbstractFormItemProps } from './abstract-form-item';
|
||||
import { FieldValues } from 'react-hook-form/dist/types/fields';
|
||||
@ -18,8 +18,17 @@ interface FormRichTextProps<TFieldValues, TContext extends object> extends FormC
|
||||
/**
|
||||
* This component is a rich-text editor to use with react-hook-form.
|
||||
*/
|
||||
export const FormRichText = <TFieldValues extends FieldValues, TContext extends object>({ id, label, tooltip, className, control, valueDefault, error, warning, rules, disabled, formState, limit, paragraphTools, video, image }: FormRichTextProps<TFieldValues, TContext>) => {
|
||||
export const FormRichText = <TFieldValues extends FieldValues, TContext extends object>({ id, label, tooltip, className, control, valueDefault, error, warning, rules, disabled, readOnly, formState, limit, paragraphTools, video, image }: FormRichTextProps<TFieldValues, TContext>) => {
|
||||
const textEditorRef = React.useRef<FabTextEditorRef>();
|
||||
const [isDisabled, setIsDisabled] = React.useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof disabled === 'function') {
|
||||
setIsDisabled(disabled(id) || readOnly);
|
||||
} else {
|
||||
setIsDisabled(disabled || readOnly);
|
||||
}
|
||||
}, [disabled]);
|
||||
|
||||
/**
|
||||
* Callback triggered when the user clicks to get the focus on the editor.
|
||||
@ -40,7 +49,14 @@ export const FormRichText = <TFieldValues extends FieldValues, TContext extends
|
||||
control={control}
|
||||
defaultValue={valueDefault as UnpackNestedValue<FieldPathValue<TFieldValues, Path<TFieldValues>>>}
|
||||
render={({ field: { onChange, value } }) =>
|
||||
<FabTextEditor onChange={onChange} content={value} limit={limit} paragraphTools={paragraphTools} video={video} image={image} ref={textEditorRef} />
|
||||
<FabTextEditor onChange={onChange}
|
||||
content={value}
|
||||
limit={limit}
|
||||
paragraphTools={paragraphTools}
|
||||
video={video}
|
||||
image={image}
|
||||
readOnly={isDisabled}
|
||||
ref={textEditorRef} />
|
||||
} />
|
||||
</AbstractFormItem>
|
||||
);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import Select from 'react-select';
|
||||
import { Controller, Path } from 'react-hook-form';
|
||||
import { FieldValues } from 'react-hook-form/dist/types/fields';
|
||||
@ -25,6 +25,16 @@ type selectOption<TOptionValue> = { value: TOptionValue, label: string };
|
||||
* This component is a wrapper for react-select to use with react-hook-form
|
||||
*/
|
||||
export const FormSelect = <TFieldValues extends FieldValues, TContext extends object, TOptionValue>({ id, label, tooltip, className, control, placeholder, options, valueDefault, error, warning, rules, disabled, onChange, readOnly, clearable, formState }: FormSelectProps<TFieldValues, TContext, TOptionValue>) => {
|
||||
const [isDisabled, setIsDisabled] = React.useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof disabled === 'function') {
|
||||
setIsDisabled(disabled(id) || readOnly);
|
||||
} else {
|
||||
setIsDisabled(disabled || readOnly);
|
||||
}
|
||||
}, [disabled]);
|
||||
|
||||
/**
|
||||
* The following callback will trigger the onChange callback, if it was passed to this component,
|
||||
* when the selected option changes.
|
||||
@ -53,7 +63,7 @@ export const FormSelect = <TFieldValues extends FieldValues, TContext extends ob
|
||||
onChange(val.value);
|
||||
}}
|
||||
placeholder={placeholder}
|
||||
isDisabled={readOnly}
|
||||
isDisabled={isDisabled}
|
||||
isClearable={clearable}
|
||||
options={options} />
|
||||
} />
|
||||
|
@ -42,7 +42,7 @@ export const FormSwitch = <TFieldValues, TContext extends object>({ id, label, t
|
||||
height={19}
|
||||
width={40}
|
||||
ref={ref}
|
||||
disabled={disabled}
|
||||
disabled={typeof disabled === 'function' ? disabled(id) : disabled}
|
||||
readOnly={readOnly} />
|
||||
} />
|
||||
</AbstractFormItem>
|
||||
|
@ -18,6 +18,7 @@ import { PaymentScheduleSummary } from '../payment-schedule/payment-schedule-sum
|
||||
import { PaymentSchedule } from '../../models/payment-schedule';
|
||||
import { LocalPaymentModal } from '../payment/local-payment/local-payment-modal';
|
||||
import { User } from '../../models/user';
|
||||
import { TDateISO } from '../../typings/date-iso';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
@ -83,7 +84,7 @@ const RenewModal: React.FC<RenewModalProps> = ({ isOpen, toggleModal, subscripti
|
||||
/**
|
||||
* Return the formatted localized date for the given date
|
||||
*/
|
||||
const formatDateTime = (date: Date): string => {
|
||||
const formatDateTime = (date: Date|TDateISO): string => {
|
||||
return t('app.admin.free_extend_modal.DATE_TIME', { DATE: FormatLib.date(date), TIME: FormatLib.time(date) });
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user