Skip to content

Commit

Permalink
refactor: use form provider to refactor item name form (#1559)
Browse files Browse the repository at this point in the history
  • Loading branch information
pyphilia authored Nov 4, 2024
1 parent 114b7e3 commit 866fb4b
Show file tree
Hide file tree
Showing 8 changed files with 316 additions and 320 deletions.
125 changes: 68 additions & 57 deletions src/components/item/form/AppForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChangeEventHandler, useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { FormProvider, useForm } from 'react-hook-form';

import { ArrowBack } from '@mui/icons-material';
import {
Expand All @@ -22,7 +22,7 @@ import { useBuilderTranslation } from '../../../config/i18n';
import { hooks } from '../../../config/queryClient';
import { BUILDER } from '../../../langs/constants';
import addNewImage from '../../../resources/addNew.png';
import NameForm from './NameForm';
import { ItemNameField } from './ItemNameField';

type AppGridProps = {
currentUrl: string;
Expand Down Expand Up @@ -101,7 +101,8 @@ const AppForm = ({ onChange }: Props): JSX.Element => {

const [searchQuery, setSearchQuery] = useState<string>('');

const { register, setValue, watch, reset } = useForm<Inputs>();
const methods = useForm<Inputs>();
const { register, setValue, watch, reset } = methods;
const url = watch('url');
const name = watch('name');

Expand Down Expand Up @@ -143,66 +144,76 @@ const AppForm = ({ onChange }: Props): JSX.Element => {
if (isCustomApp) {
return (
<Stack direction="column" alignItems="start" mt={1} spacing={2}>
<Button
startIcon={<ArrowBack fontSize="small" />}
variant="text"
onClick={() => {
setIsCustomApp(false);
handleAppSelection(null);
}}
>
{translateBuilder(BUILDER.CREATE_NEW_APP_BACK_TO_APP_LIST_BUTTON)}
</Button>
<Typography>
{translateBuilder(BUILDER.CREATE_CUSTOM_APP_HELPER_TEXT)}
</Typography>
<TextField
id={CUSTOM_APP_URL_ID}
fullWidth
variant="standard"
autoFocus
label={translateBuilder(BUILDER.APP_URL)}
{...register('url', { validate: isUrlValid })}
/>
<NameForm nameForm={register('name')} autoFocus={false} />
<FormProvider {...methods}>
<Button
startIcon={<ArrowBack fontSize="small" />}
variant="text"
onClick={() => {
setIsCustomApp(false);
handleAppSelection(null);
}}
>
{translateBuilder(BUILDER.CREATE_NEW_APP_BACK_TO_APP_LIST_BUTTON)}
</Button>
<Typography>
{translateBuilder(BUILDER.CREATE_CUSTOM_APP_HELPER_TEXT)}
</Typography>
<TextField
id={CUSTOM_APP_URL_ID}
fullWidth
variant="standard"
autoFocus
label={translateBuilder(BUILDER.APP_URL)}
{...register('url', { validate: isUrlValid })}
/>
<ItemNameField required autoFocus={false} />
</FormProvider>
</Stack>
);
}
return (
<Stack direction="column" height="100%" spacing={2} minHeight="0px">
<TextField
fullWidth
placeholder={translateBuilder(BUILDER.CREATE_APP_SEARCH_FIELD_HELPER)}
variant="outlined"
autoFocus
size="small"
onChange={searchAnApp}
/>
<Box display="flex" flexGrow={1} minHeight="0px" overflow="scroll" p={1}>
<Grid
container
spacing={2}
height="max-content"
maxHeight={400}
alignItems="stretch"
<FormProvider {...methods}>
<TextField
fullWidth
placeholder={translateBuilder(BUILDER.CREATE_APP_SEARCH_FIELD_HELPER)}
variant="outlined"
autoFocus
size="small"
onChange={searchAnApp}
/>
<Box
display="flex"
flexGrow={1}
minHeight="0px"
overflow="scroll"
p={1}
>
<AppGrid
currentUrl={url}
handleSelection={handleAppSelection}
searchQuery={searchQuery}
/>
<AppCard
id={CUSTOM_APP_CYPRESS_ID}
name={translateBuilder(BUILDER.CREATE_CUSTOM_APP)}
description={translateBuilder(
BUILDER.CREATE_CUSTOM_APP_DESCRIPTION,
)}
image={addNewImage}
onClick={addCustomApp}
/>
</Grid>
</Box>
<NameForm nameForm={register('name')} autoFocus={false} />
<Grid
container
spacing={2}
height="max-content"
maxHeight={400}
alignItems="stretch"
>
<AppGrid
currentUrl={url}
handleSelection={handleAppSelection}
searchQuery={searchQuery}
/>
<AppCard
id={CUSTOM_APP_CYPRESS_ID}
name={translateBuilder(BUILDER.CREATE_CUSTOM_APP)}
description={translateBuilder(
BUILDER.CREATE_CUSTOM_APP_DESCRIPTION,
)}
image={addNewImage}
onClick={addCustomApp}
/>
</Grid>
</Box>
<ItemNameField required autoFocus={false} />
</FormProvider>
</Stack>
);
};
Expand Down
44 changes: 23 additions & 21 deletions src/components/item/form/BaseItemForm.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useEffect } from 'react';
import { useForm } from 'react-hook-form';
import { FormProvider, useForm } from 'react-hook-form';

import { Box } from '@mui/material';

import { DescriptionPlacementType, DiscriminatedItem } from '@graasp/sdk';

import { FOLDER_FORM_DESCRIPTION_ID } from '../../../config/selectors';
import DescriptionForm from './DescriptionForm';
import NameForm from './NameForm';
import { ItemNameField } from './ItemNameField';

type Inputs = {
name: string;
Expand All @@ -19,11 +19,11 @@ const BaseItemForm = ({
item,
setChanges,
}: {
item?: DiscriminatedItem;
item: DiscriminatedItem;
setChanges: (payload: Partial<DiscriminatedItem>) => void;
}): JSX.Element => {
const { register, watch, setValue } = useForm<Inputs>();

const methods = useForm<Inputs>({ defaultValues: { name: item.name } });
const { watch, setValue } = methods;
const name = watch('name');
const descriptionPlacement = watch('descriptionPlacement');
const description = watch('description');
Expand All @@ -40,23 +40,25 @@ const BaseItemForm = ({

return (
<Box overflow="auto">
<NameForm nameForm={register('name', { value: item?.name })} required />
<FormProvider {...methods}>
<ItemNameField required />

<Box sx={{ mt: 2 }}>
<DescriptionForm
id={FOLDER_FORM_DESCRIPTION_ID}
description={description ?? item?.description}
descriptionPlacement={
descriptionPlacement ?? item?.settings?.descriptionPlacement
}
onPlacementChange={(newValue) =>
setValue('descriptionPlacement', newValue)
}
onDescriptionChange={(newValue) => {
setValue('description', newValue);
}}
/>
</Box>
<Box sx={{ mt: 2 }}>
<DescriptionForm
id={FOLDER_FORM_DESCRIPTION_ID}
description={description ?? item?.description}
descriptionPlacement={
descriptionPlacement ?? item?.settings?.descriptionPlacement
}
onPlacementChange={(newValue) =>
setValue('descriptionPlacement', newValue)
}
onDescriptionChange={(newValue) => {
setValue('description', newValue);
}}
/>
</Box>
</FormProvider>
</Box>
);
};
Expand Down
109 changes: 53 additions & 56 deletions src/components/item/form/FileForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ReactNode } from 'react';
import { useForm } from 'react-hook-form';
import { FormProvider, useForm } from 'react-hook-form';

import {
Box,
Expand Down Expand Up @@ -32,7 +32,7 @@ import { getExtraFromPartial } from '@/utils/itemExtra';

import { BUILDER } from '../../../langs/constants';
import DescriptionForm from './DescriptionForm';
import NameForm from './NameForm';
import { ItemNameField } from './ItemNameField';

type Inputs = {
name: string;
Expand All @@ -50,14 +50,14 @@ const FileForm = ({
}): ReactNode => {
const { t: translateBuilder } = useBuilderTranslation();
const { t: translateCommon } = useCommonTranslation();
const methods = useForm<Inputs>({ defaultValues: { name: item.name } });
const {
register,
watch,
setValue,
handleSubmit,
reset,
formState: { errors, isValid },
} = useForm<Inputs>();
formState: { isValid },
} = methods;
const altText = watch('altText');
const description = watch('description');
const descriptionPlacement = watch('descriptionPlacement');
Expand Down Expand Up @@ -108,59 +108,56 @@ const FileForm = ({
}

return (
<Box component="form" onSubmit={handleSubmit(onSubmit)}>
<DialogContent
sx={{
display: 'flex',
flexDirection: 'column',
}}
>
<NameForm
nameForm={register('name', {
value: item.name,
required: true,
})}
error={errors.name}
showClearButton={Boolean(watch('name'))}
reset={() => reset({ name: '' })}
/>
{mimetype && MimeTypes.isImage(mimetype) && (
<TextField
variant="standard"
id={ITEM_FORM_IMAGE_ALT_TEXT_EDIT_FIELD_ID}
label={translateBuilder(BUILDER.EDIT_ITEM_IMAGE_ALT_TEXT_LABEL)}
// always shrink because setting name from defined app does not shrink automatically
slotProps={{ inputLabel: { shrink: true } }}
sx={{ width: '50%', my: 1 }}
multiline
{...register('altText', { value: previousAltText })}
/>
)}
<DescriptionForm
onPlacementChange={(newValue) =>
setValue('descriptionPlacement', newValue)
}
onDescriptionChange={(newValue) => {
setValue('description', newValue);
<FormProvider {...methods}>
<Box component="form" onSubmit={handleSubmit(onSubmit)}>
<DialogContent
sx={{
display: 'flex',
flexDirection: 'column',
}}
description={description ?? item?.description ?? ''}
descriptionPlacement={
descriptionPlacement ?? item?.settings?.descriptionPlacement
}
/>
</DialogContent>
<DialogActions>
<CancelButton id={EDIT_ITEM_MODAL_CANCEL_BUTTON_ID} onClick={onClose} />
<Button
variant="contained"
type="submit"
id={ITEM_FORM_CONFIRM_BUTTON_ID}
disabled={!isValid}
>
{translateCommon(COMMON.SAVE_BUTTON)}
</Button>
</DialogActions>
</Box>
<ItemNameField required showClearButton={Boolean(watch('name'))} />
{mimetype && MimeTypes.isImage(mimetype) && (
<TextField
variant="standard"
id={ITEM_FORM_IMAGE_ALT_TEXT_EDIT_FIELD_ID}
label={translateBuilder(BUILDER.EDIT_ITEM_IMAGE_ALT_TEXT_LABEL)}
// always shrink because setting name from defined app does not shrink automatically
slotProps={{ inputLabel: { shrink: true } }}
sx={{ width: '50%', my: 1 }}
multiline
{...register('altText', { value: previousAltText })}
/>
)}
<DescriptionForm
onPlacementChange={(newValue) =>
setValue('descriptionPlacement', newValue)
}
onDescriptionChange={(newValue) => {
setValue('description', newValue);
}}
description={description ?? item?.description ?? ''}
descriptionPlacement={
descriptionPlacement ?? item?.settings?.descriptionPlacement
}
/>
</DialogContent>
<DialogActions>
<CancelButton
id={EDIT_ITEM_MODAL_CANCEL_BUTTON_ID}
onClick={onClose}
/>
<Button
variant="contained"
type="submit"
id={ITEM_FORM_CONFIRM_BUTTON_ID}
disabled={!isValid}
>
{translateCommon(COMMON.SAVE_BUTTON)}
</Button>
</DialogActions>
</Box>
</FormProvider>
);
};

Expand Down
Loading

0 comments on commit 866fb4b

Please sign in to comment.