1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-27 21:54:27 +01:00

(ui) form-select: onChange cb

This commit is contained in:
Sylvain 2022-04-06 12:24:04 +02:00
parent c817094f90
commit 2baee48eaf
3 changed files with 80 additions and 27 deletions

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, { useState } from 'react';
import { useForm, SubmitHandler } from 'react-hook-form'; import { useForm, SubmitHandler } from 'react-hook-form';
import { react2angular } from 'react2angular'; import { react2angular } from 'react2angular';
import { AuthenticationProvider } from '../../models/authentication-provider'; import { AuthenticationProvider } from '../../models/authentication-provider';
@ -32,6 +32,7 @@ type selectProvidableTypeOption = { value: string, label: string };
*/ */
export const ProviderForm: React.FC<ProviderFormProps> = ({ action, provider, onError, onSuccess }) => { export const ProviderForm: React.FC<ProviderFormProps> = ({ action, provider, onError, onSuccess }) => {
const { handleSubmit, register, control } = useForm<AuthenticationProvider>({ defaultValues: { ...provider } }); const { handleSubmit, register, control } = useForm<AuthenticationProvider>({ defaultValues: { ...provider } });
const [providableType, setProvidableType] = useState<string>(provider?.providable_type);
const { t } = useTranslation('shared'); const { t } = useTranslation('shared');
/** /**
@ -54,11 +55,28 @@ export const ProviderForm: React.FC<ProviderFormProps> = ({ action, provider, on
}); });
}; };
/**
* Callback triggered when the providable type is changed.
* Changing the providable type will change the form to match the new type.
*/
const onProvidableTypeChange = (type: string) => {
setProvidableType(type);
};
return ( return (
<form className="provider-form" onSubmit={handleSubmit(onSubmit)}> <form className="provider-form" onSubmit={handleSubmit(onSubmit)}>
<FormInput id="name" register={register} readOnly={action === 'update'} rules={{ required: true }} label={t('app.shared.authentication.name')} /> <FormInput id="name"
<FormSelect id="providable_type" control={control} options={buildProvidableTypeOptions()} label={t('app.shared.authentication.authentication_type')} rules={{ required: true }} /> register={register}
{provider?.providable_type === 'OAuth2Provider' && <Oauth2Form register={register} />} readOnly={action === 'update'}
rules={{ required: true }}
label={t('app.shared.authentication.name')} />
<FormSelect id="providable_type"
control={control}
options={buildProvidableTypeOptions()}
label={t('app.shared.authentication.authentication_type')}
onChange={onProvidableTypeChange}
rules={{ required: true }} />
{providableType === 'OAuth2Provider' && <Oauth2Form register={register} />}
<input type={'submit'} /> <input type={'submit'} />
</form> </form>
); );

View File

@ -1,4 +1,4 @@
import React, { SelectHTMLAttributes } from 'react'; import React from 'react';
import Select from 'react-select'; import Select from 'react-select';
import { Controller, Path } from 'react-hook-form'; import { Controller, Path } from 'react-hook-form';
import { FieldValues } from 'react-hook-form/dist/types/fields'; import { FieldValues } from 'react-hook-form/dist/types/fields';
@ -6,11 +6,15 @@ import { FieldPath } from 'react-hook-form/dist/types/path';
import { FieldPathValue, UnpackNestedValue } from 'react-hook-form/dist/types'; import { FieldPathValue, UnpackNestedValue } from 'react-hook-form/dist/types';
import { FormControlledComponent } from '../../models/form-component'; import { FormControlledComponent } from '../../models/form-component';
interface FormSelectProps<TFieldValues, TContext extends object, TOptionValue> extends SelectHTMLAttributes<HTMLSelectElement>, FormControlledComponent<TFieldValues, TContext> { interface FormSelectProps<TFieldValues, TContext extends object, TOptionValue> extends FormControlledComponent<TFieldValues, TContext> {
id: string, id: string,
label?: string, label?: string,
options: Array<selectOption<TOptionValue>>, options: Array<selectOption<TOptionValue>>,
valuesDefault?: Array<TOptionValue>, valuesDefault?: Array<TOptionValue>,
onChange?: (values: Array<TOptionValue>) => void,
className?: string,
placeholder?: string,
disabled?: boolean,
} }
/** /**
@ -23,13 +27,23 @@ type selectOption<TOptionValue> = { value: TOptionValue, label: string };
* This component is a wrapper around react-select to use with react-hook-form. * This component is a wrapper around react-select to use with react-hook-form.
* It is a multi-select component. * It is a multi-select component.
*/ */
export const FormMultiSelect = <TFieldValues extends FieldValues, TContext extends object, TOptionValue>({ id, label, className, control, placeholder, options, valuesDefault, error, rules, disabled }: FormSelectProps<TFieldValues, TContext, TOptionValue>) => { export const FormMultiSelect = <TFieldValues extends FieldValues, TContext extends object, TOptionValue>({ id, label, className, control, placeholder, options, valuesDefault, error, rules, disabled, onChange }: FormSelectProps<TFieldValues, TContext, TOptionValue>) => {
const classNames = ` const classNames = `
form-item ${className || ''} form-item ${className || ''}
${error && error[id] ? 'is-incorrect' : ''} ${error && error[id] ? 'is-incorrect' : ''}
${rules && rules.required ? 'is-required' : ''} ${rules && rules.required ? 'is-required' : ''}
${disabled ? 'is-disabled' : ''}`; ${disabled ? 'is-disabled' : ''}`;
/**
* The following callback will trigger the onChange callback, if it was passed to this component,
* when the selected option changes.
*/
const onChangeCb = (newValues: Array<TOptionValue>): void => {
if (typeof onChange === 'function') {
onChange(newValues);
}
};
return ( return (
<label className={classNames}> <label className={classNames}>
{label && <div className="form-item-header"> {label && <div className="form-item-header">
@ -40,11 +54,15 @@ export const FormMultiSelect = <TFieldValues extends FieldValues, TContext exten
control={control} control={control}
defaultValue={valuesDefault as UnpackNestedValue<FieldPathValue<TFieldValues, Path<TFieldValues>>>} defaultValue={valuesDefault as UnpackNestedValue<FieldPathValue<TFieldValues, Path<TFieldValues>>>}
render={({ field: { onChange, value, ref } }) => render={({ field: { onChange, value, ref } }) =>
<Select inputRef={ref} <Select ref={ref}
classNamePrefix="rs" classNamePrefix="rs"
className="rs" className="rs"
value={options.filter(c => value?.includes(c.value))} value={options.filter(c => value?.includes(c.value))}
onChange={val => onChange(val.map(c => c.value))} onChange={val => {
const values = val?.map(c => c.value);
onChangeCb(values);
onChange(values);
}}
placeholder={placeholder} placeholder={placeholder}
options={options} options={options}
isMulti /> isMulti />

View File

@ -1,4 +1,4 @@
import React, { SelectHTMLAttributes } from 'react'; import React from 'react';
import Select from 'react-select'; import Select from 'react-select';
import { Controller, Path } from 'react-hook-form'; import { Controller, Path } from 'react-hook-form';
import { FieldValues } from 'react-hook-form/dist/types/fields'; import { FieldValues } from 'react-hook-form/dist/types/fields';
@ -6,11 +6,15 @@ import { FieldPath } from 'react-hook-form/dist/types/path';
import { FieldPathValue, UnpackNestedValue } from 'react-hook-form/dist/types'; import { FieldPathValue, UnpackNestedValue } from 'react-hook-form/dist/types';
import { FormControlledComponent } from '../../models/form-component'; import { FormControlledComponent } from '../../models/form-component';
interface FormSelectProps<TFieldValues, TContext extends object, TOptionValue> extends SelectHTMLAttributes<HTMLSelectElement>, FormControlledComponent<TFieldValues, TContext> { interface FormSelectProps<TFieldValues, TContext extends object, TOptionValue> extends FormControlledComponent<TFieldValues, TContext> {
id: string, id: string,
label?: string, label?: string,
options: Array<selectOption<TOptionValue>>, options: Array<selectOption<TOptionValue>>,
valueDefault?: TOptionValue, valueDefault?: TOptionValue,
onChange?: (value: TOptionValue) => void,
className?: string,
placeholder?: string,
disabled?: boolean,
} }
/** /**
@ -22,13 +26,23 @@ type selectOption<TOptionValue> = { value: TOptionValue, label: string };
/** /**
* This component is a wrapper for react-select to use with react-hook-form * 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, className, control, placeholder, options, valueDefault, error, rules, disabled }: FormSelectProps<TFieldValues, TContext, TOptionValue>) => { export const FormSelect = <TFieldValues extends FieldValues, TContext extends object, TOptionValue>({ id, label, className, control, placeholder, options, valueDefault, error, rules, disabled, onChange }: FormSelectProps<TFieldValues, TContext, TOptionValue>) => {
const classNames = ` const classNames = `
form-item ${className || ''} form-item ${className || ''}
${error && error[id] ? 'is-incorrect' : ''} ${error && error[id] ? 'is-incorrect' : ''}
${rules && rules.required ? 'is-required' : ''} ${rules && rules.required ? 'is-required' : ''}
${disabled ? 'is-disabled' : ''}`; ${disabled ? 'is-disabled' : ''}`;
/**
* The following callback will trigger the onChange callback, if it was passed to this component,
* when the selected option changes.
*/
const onChangeCb = (newValue: TOptionValue): void => {
if (typeof onChange === 'function') {
onChange(newValue);
}
};
return ( return (
<label className={classNames}> <label className={classNames}>
{label && <div className="form-item-header"> {label && <div className="form-item-header">
@ -39,11 +53,14 @@ export const FormSelect = <TFieldValues extends FieldValues, TContext extends ob
control={control} control={control}
defaultValue={valueDefault as UnpackNestedValue<FieldPathValue<TFieldValues, Path<TFieldValues>>>} defaultValue={valueDefault as UnpackNestedValue<FieldPathValue<TFieldValues, Path<TFieldValues>>>}
render={({ field: { onChange, value, ref } }) => render={({ field: { onChange, value, ref } }) =>
<Select inputRef={ref} <Select ref={ref}
classNamePrefix="rs" classNamePrefix="rs"
className="rs" className="rs"
value={options.find(c => c.value === value)} value={options.find(c => c.value === value)}
onChange={val => onChange(val.value)} onChange={val => {
onChangeCb(val.value);
onChange(val.value);
}}
placeholder={placeholder} placeholder={placeholder}
options={options} /> options={options} />
} /> } />