diff --git a/frontend/packages/ux-editor/src/components/Elements/Subform/CreateSubformWrapper.tsx b/frontend/packages/ux-editor/src/components/Elements/Subform/CreateSubformWrapper.tsx
index 0ce957979c2..44ff25007ef 100644
--- a/frontend/packages/ux-editor/src/components/Elements/Subform/CreateSubformWrapper.tsx
+++ b/frontend/packages/ux-editor/src/components/Elements/Subform/CreateSubformWrapper.tsx
@@ -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;
@@ -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) => {
diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSet/CreateNewSubformLayoutSet/CreateNewSubformLayoutSet.test.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSet/CreateNewSubformLayoutSet/CreateNewSubformLayoutSet.test.tsx
index 8a918996a9a..47bcb935ae0 100644
--- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSet/CreateNewSubformLayoutSet/CreateNewSubformLayoutSet.test.tsx
+++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSet/CreateNewSubformLayoutSet/CreateNewSubformLayoutSet.test.tsx
@@ -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 = (
@@ -60,7 +81,11 @@ const renderCreateNewSubformLayoutSet = (
queryClient.setQueryData([QueryKey.LayoutSets, org, app], layoutSetsMock);
return renderWithProviders(
-
+
,
{ queryClient },
);
diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSet/CreateNewSubformLayoutSet/CreateNewSubformLayoutSet.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSet/CreateNewSubformLayoutSet/CreateNewSubformLayoutSet.tsx
index acaf206ce24..fd041cdd149 100644
--- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSet/CreateNewSubformLayoutSet/CreateNewSubformLayoutSet.tsx
+++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSet/CreateNewSubformLayoutSet/CreateNewSubformLayoutSet.tsx
@@ -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) {
+ const subformNameValidation = validateLayoutSetName(e.target.value, layoutSets);
+ setNameError(subformNameValidation);
setNewSubform(e.target.value);
}
+ function handleCreateSubform() {
+ createSubform({ layoutSetName: newSubform, onSubformCreated });
+ }
+
return (
@@ -46,12 +43,14 @@ export const CreateNewSubformLayoutSet = ({
value={newSubform}
size='sm'
onChange={handleChange}
+ error={nameError}
/>
}
- onClick={createNewSubform}
+ onClick={handleCreateSubform}
title={t('general.close')}
+ disabled={!newSubform || !!nameError}
variant='tertiary'
color='success'
/>
diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSet/EditLayoutSet.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSet/EditLayoutSet.tsx
index 8a8c957978e..9f1c6baae8e 100644
--- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSet/EditLayoutSet.tsx
+++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSet/EditLayoutSet.tsx
@@ -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(false);
@@ -62,7 +65,9 @@ export const EditLayoutSet = ({
onClick={handleClick}
/>
- {showCreateSubform && }
+ {showCreateSubform && (
+
+ )}
>
);
}
diff --git a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSetForSubform.tsx b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSetForSubform.tsx
index 12954ba971e..70ee13ca973 100644
--- a/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSetForSubform.tsx
+++ b/frontend/packages/ux-editor/src/components/Properties/PropertiesHeader/EditLayoutSetForSubform/EditLayoutSetForSubform.tsx
@@ -37,6 +37,7 @@ export const EditLayoutSetForSubform = ({
existingLayoutSetForSubform={component['layoutSet']}
onUpdateLayoutSet={handleUpdatedLayoutSet}
onSubformCreated={handleCreatedSubform}
+ layoutSets={layoutSets}
/>
);
};
diff --git a/frontend/packages/ux-editor/src/hooks/useCreateSubform.test.ts b/frontend/packages/ux-editor/src/hooks/useCreateSubform.test.ts
new file mode 100644
index 00000000000..ece8a38b609
--- /dev/null
+++ b/frontend/packages/ux-editor/src/hooks/useCreateSubform.test.ts
@@ -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',
+ },
+ });
+ });
+});
diff --git a/frontend/packages/ux-editor/src/hooks/useCreateSubform.ts b/frontend/packages/ux-editor/src/hooks/useCreateSubform.ts
new file mode 100644
index 00000000000..b96c3ca1aeb
--- /dev/null
+++ b/frontend/packages/ux-editor/src/hooks/useCreateSubform.ts
@@ -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 };
+};