Files
ontime/apps/client/src/features/app-settings/panel/project-settings-panel/CustomFieldForm.tsx
T
2024-03-02 23:08:08 +01:00

100 lines
3.0 KiB
TypeScript

import { useEffect } from 'react';
import { useForm } from 'react-hook-form';
import { Button, Input } from '@chakra-ui/react';
import { CustomField } from 'ontime-types';
import { isAlphanumeric } from 'ontime-utils';
import { maybeAxiosError } from '../../../../common/api/utils';
import SwatchSelect from '../../../../common/components/input/colour-input/SwatchSelect';
import * as Panel from '../PanelUtils';
import style from './ProjectSettingsPanel.module.scss';
interface CustomFieldsFormProps {
onSubmit: (field: CustomField) => Promise<void>;
onCancel: () => void;
initialColour?: string;
initialLabel?: string;
}
export default function CustomFieldForm(props: CustomFieldsFormProps) {
const { onSubmit, onCancel, initialColour, initialLabel } = props;
const {
handleSubmit,
register,
setFocus,
setError,
setValue,
getValues,
formState: { errors, isSubmitting, isValid, isDirty },
} = useForm({
defaultValues: { label: initialLabel || '', colour: initialColour || '' },
resetOptions: {
keepDirtyValues: true,
},
});
const setupSubmit = async (values: { label: string; colour: string }) => {
const { label, colour } = values;
const newField: CustomField = {
type: 'string', // type is not user definable yet
colour,
label,
};
try {
await onSubmit(newField);
} catch (error) {
setError('root', { type: 'custom', message: maybeAxiosError(error) });
}
};
// give initial focus to the label
useEffect(() => {
setFocus('label');
}, [setFocus]);
const handleSelectColour = (colour: string) => {
setValue('colour', colour, { shouldDirty: true });
};
const colour = getValues('colour');
const canSubmit = isDirty && isValid;
return (
<form onSubmit={handleSubmit(setupSubmit)} className={style.fieldForm}>
<div className={style.column}>
<Panel.Description>Label</Panel.Description>
{errors.label && <Panel.Error>{errors.label.message}</Panel.Error>}
<Input
{...register('label', {
required: { value: true, message: 'Required field' },
validate: (value) => {
if (value.trim().length === 0) return 'Required field';
if (!isAlphanumeric(value)) return 'Only alphanumeric characters are allowed';
return true;
},
})}
size='sm'
variant='ontime-filled'
autoComplete='off'
/>
</div>
<div>
<Panel.Description>Colour</Panel.Description>
<SwatchSelect name='colour' value={colour} handleChange={(_field, value) => handleSelectColour(value)} />
</div>
{errors.root && <Panel.Error>{errors.root.message}</Panel.Error>}
<div className={style.buttonRow}>
<Button size='sm' variant='ontime-ghosted' onClick={onCancel}>
Cancel
</Button>
<Button size='sm' type='submit' variant='ontime-filled' isDisabled={!canSubmit} isLoading={isSubmitting}>
Save
</Button>
</div>
</form>
);
}