Skip to content

Commit

Permalink
feat: Validate create subform in nextrecommendedaction (#13966)
Browse files Browse the repository at this point in the history
  • Loading branch information
lassopicasso authored Nov 4, 2024
1 parent 5a3082b commit 0c25d8e
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React, { useState } from 'react';
import { StudioButton, StudioPopover, StudioTextfield } from '@studio/components';
import { PlusIcon } from '@studio/icons';
import { useAddLayoutSetMutation } from 'app-development/hooks/mutations/useAddLayoutSetMutation';
import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams';
import { useTranslation } from 'react-i18next';
import { useValidateLayoutSetName } from 'app-shared/hooks/useValidateLayoutSetName';
import type { LayoutSets } from 'app-shared/types/api/LayoutSetsResponse';
import classes from './CreateSubformWrapper.module.css';
import { useCreateSubform } from '@altinn/ux-editor/hooks/useCreateSubform';

type CreateSubformWrapperProps = {
layoutSets: LayoutSets;
Expand All @@ -22,20 +21,11 @@ export const CreateSubformWrapper = ({
const [nameError, setNameError] = useState('');
const { t } = useTranslation();
const { validateLayoutSetName } = useValidateLayoutSetName();
const { org, app } = useStudioEnvironmentParams();
const { mutate: addLayoutSet } = useAddLayoutSetMutation(org, app);
const { createSubform } = useCreateSubform();

const onCreateConfirmClick = () => {
setCreateNewOpen(false);

addLayoutSet({
layoutSetIdToUpdate: newSubformName,
layoutSetConfig: {
id: newSubformName,
type: 'subform',
},
});
onSubformCreated(newSubformName);
createSubform({ layoutSetName: newSubformName, onSubformCreated });
};

const onNameChange = (subformName: string) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,27 @@ describe('CreateNewSubformLayoutSet ', () => {
await waitFor(() => expect(onSubformCreatedMock).toHaveBeenCalledTimes(1));
expect(onSubformCreatedMock).toHaveBeenCalledWith('NewSubform');
});

it('disables the save button when input is invalid', async () => {
const user = userEvent.setup();
renderCreateNewSubformLayoutSet();

const saveButton = screen.getByRole('button', { name: textMock('general.close') });
expect(saveButton).toBeDisabled();

const input = screen.getByRole('textbox');

await user.type(input, 'æøå');
expect(saveButton).toBeDisabled();

await user.clear(input);
await user.type(input, 'e re a');
expect(saveButton).toBeDisabled();

await user.clear(input);
await user.type(input, 'NewSubform');
expect(saveButton).not.toBeDisabled();
});
});

const renderCreateNewSubformLayoutSet = (
Expand All @@ -60,7 +81,11 @@ const renderCreateNewSubformLayoutSet = (
queryClient.setQueryData([QueryKey.LayoutSets, org, app], layoutSetsMock);
return renderWithProviders(
<AppContext.Provider value={{ ...appContextMock }}>
<CreateNewSubformLayoutSet onSubformCreated={onSubformCreatedMock} {...componentProps} />
<CreateNewSubformLayoutSet
onSubformCreated={onSubformCreatedMock}
layoutSets={layoutSets}
{...componentProps}
/>
</AppContext.Provider>,
{ queryClient },
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,36 @@ import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { StudioButton, StudioCard, StudioTextfield } from '@studio/components';
import { ClipboardIcon, CheckmarkIcon } from '@studio/icons';
import { useAddLayoutSetMutation } from 'app-development/hooks/mutations/useAddLayoutSetMutation';
import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams';
import classes from './CreateNewSubformLayoutSet.module.css';
import { useValidateLayoutSetName } from 'app-shared/hooks/useValidateLayoutSetName';
import { useCreateSubform } from '@altinn/ux-editor/hooks/useCreateSubform';
import type { LayoutSets } from 'app-shared/types/api/LayoutSetsResponse';

type CreateNewSubformLayoutSetProps = {
onSubformCreated: (layoutSetName: string) => void;
layoutSets: LayoutSets;
};

export const CreateNewSubformLayoutSet = ({
onSubformCreated,
layoutSets,
}: CreateNewSubformLayoutSetProps): React.ReactElement => {
const { t } = useTranslation();
const [newSubform, setNewSubform] = useState('');
const { org, app } = useStudioEnvironmentParams();
const { mutate: addLayoutSet } = useAddLayoutSetMutation(org, app);

const createNewSubform = () => {
if (!newSubform) return;
addLayoutSet({
layoutSetIdToUpdate: newSubform,
layoutSetConfig: {
id: newSubform,
type: 'subform',
},
});
onSubformCreated(newSubform);
setNewSubform('');
};
const { validateLayoutSetName } = useValidateLayoutSetName();
const { createSubform } = useCreateSubform();
const [nameError, setNameError] = useState('');

function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
const subformNameValidation = validateLayoutSetName(e.target.value, layoutSets);
setNameError(subformNameValidation);
setNewSubform(e.target.value);
}

function handleCreateSubform() {
createSubform({ layoutSetName: newSubform, onSubformCreated });
}

return (
<StudioCard>
<StudioCard.Content>
Expand All @@ -46,12 +43,14 @@ export const CreateNewSubformLayoutSet = ({
value={newSubform}
size='sm'
onChange={handleChange}
error={nameError}
/>
<StudioButton
className={classes.savelayoutSetButton}
icon={<CheckmarkIcon />}
onClick={createNewSubform}
onClick={handleCreateSubform}
title={t('general.close')}
disabled={!newSubform || !!nameError}
variant='tertiary'
color='success'
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ import { StudioParagraph, StudioProperty, StudioRecommendedNextAction } from '@s
import { PlusIcon } from '@studio/icons';
import classes from './EditLayoutSet.module.css';
import { CreateNewSubformLayoutSet } from './CreateNewSubformLayoutSet';
import type { LayoutSets } from 'app-shared/types/api/LayoutSetsResponse';

type EditLayoutSetProps = {
existingLayoutSetForSubform: string;
onUpdateLayoutSet: (layoutSetId: string) => void;
onSubformCreated: (layoutSetName: string) => void;
layoutSets: LayoutSets;
};

export const EditLayoutSet = ({
existingLayoutSetForSubform,
onUpdateLayoutSet,
onSubformCreated,
layoutSets,
}: EditLayoutSetProps): React.ReactElement => {
const { t } = useTranslation();
const [isLayoutSetSelectorVisible, setIsLayoutSetSelectorVisible] = useState<boolean>(false);
Expand Down Expand Up @@ -62,7 +65,9 @@ export const EditLayoutSet = ({
onClick={handleClick}
/>
</StudioRecommendedNextAction>
{showCreateSubform && <CreateNewSubformLayoutSet onSubformCreated={onSubformCreated} />}
{showCreateSubform && (
<CreateNewSubformLayoutSet layoutSets={layoutSets} onSubformCreated={onSubformCreated} />
)}
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const EditLayoutSetForSubform = <T extends ComponentType>({
existingLayoutSetForSubform={component['layoutSet']}
onUpdateLayoutSet={handleUpdatedLayoutSet}
onSubformCreated={handleCreatedSubform}
layoutSets={layoutSets}
/>
);
};
32 changes: 32 additions & 0 deletions frontend/packages/ux-editor/src/hooks/useCreateSubform.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useCreateSubform } from './useCreateSubform';
import { renderHook } from '@testing-library/react';

const addLayoutSetMock = jest.fn();

jest.mock('app-development/hooks/mutations/useAddLayoutSetMutation', () => ({
useAddLayoutSetMutation: jest.fn(() => ({
mutate: addLayoutSetMock,
})),
}));

describe('useCreateSubform', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('should call addLayoutSet with correct parameters', () => {
const { createSubform } = renderHook(() => useCreateSubform()).result.current;
const subformName = 'underskjema';
const onSubformCreated = jest.fn();

createSubform({ layoutSetName: subformName, onSubformCreated });

expect(addLayoutSetMock).toHaveBeenCalledWith({
layoutSetIdToUpdate: subformName,
layoutSetConfig: {
id: subformName,
type: 'subform',
},
});
});
});
25 changes: 25 additions & 0 deletions frontend/packages/ux-editor/src/hooks/useCreateSubform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useAddLayoutSetMutation } from 'app-development/hooks/mutations/useAddLayoutSetMutation';
import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams';

type CreateSubformProps = {
layoutSetName: string;
onSubformCreated: (layoutSetName: string) => void;
};

export const useCreateSubform = () => {
const { org, app } = useStudioEnvironmentParams();
const { mutate: addLayoutSet } = useAddLayoutSetMutation(org, app);

const createSubform = ({ layoutSetName, onSubformCreated }: CreateSubformProps) => {
addLayoutSet({
layoutSetIdToUpdate: layoutSetName,
layoutSetConfig: {
id: layoutSetName,
type: 'subform',
},
});
onSubformCreated(layoutSetName);
};

return { createSubform };
};

0 comments on commit 0c25d8e

Please sign in to comment.