Skip to content

Commit

Permalink
fix: add alert to ReferenceTab.tsx (#14307)
Browse files Browse the repository at this point in the history
  • Loading branch information
Konrad-Simso authored Jan 3, 2025
1 parent 1b719b9 commit 20b4540
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 27 deletions.
7 changes: 4 additions & 3 deletions frontend/language/src/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -1752,16 +1752,17 @@
"ux_editor.no_text": "Ingen tekst",
"ux_editor.open_preview": "Åpne forhåndsvisning",
"ux_editor.options.code_list_only": "Denne komponenten støtter bare oppsett med forhåndsdefinerte kodelister.",
"ux_editor.options.code_list_referenceId.description": "Her kan du legge til en referanse-ID til en dynamisk kodeliste som er satt opp i koden.",
"ux_editor.options.code_list_referenceId.description_details": "Du bruker dynamiske kodelister for å tilpasse alternativer for brukerne. Det kan for eksempel være tilpasninger ut fra geografisk plassering, eller valg brukeren gjør tidligere i skjemaet.",
"ux_editor.options.code_list_reference_id.description": "Her kan du legge til en referanse-ID til en dynamisk kodeliste som er satt opp i koden.",
"ux_editor.options.code_list_reference_id.description_details": "Du bruker dynamiske kodelister for å tilpasse alternativer for brukerne. Det kan for eksempel være tilpasninger ut fra geografisk plassering, eller valg brukeren gjør tidligere i skjemaet.",
"ux_editor.options.multiple": "{{value}} alternativer",
"ux_editor.options.option_edit_text": "Rediger kodeliste",
"ux_editor.options.option_remove_text": "Fjern valgt kodeliste",
"ux_editor.options.section_heading": "Valg for kodelister",
"ux_editor.options.single": "{{value}} alternativ",
"ux_editor.options.tab_code_list": "Velg kodeliste",
"ux_editor.options.tab_manual": "Sett opp egne alternativer",
"ux_editor.options.tab_referenceId": "Angi referanse-ID",
"ux_editor.options.tab_reference_id": "Angi referanse-ID",
"ux_editor.options.tab_reference_id_alert_title": "Du har allerede referert til en kodeliste. Skriver du inn en ID, vil referansen bli slettet.",
"ux_editor.options.upload_title": "Last opp egen kodeliste",
"ux_editor.page": "Side",
"ux_editor.page_config_pdf_abort_converting_page_to_pdf": "Avbryt å gjøre om siden til PDF",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ describe('TextTab', () => {
},
});
const addReferenceTab = await screen.findByRole('tab', {
name: textMock('ux_editor.options.tab_referenceId'),
name: textMock('ux_editor.options.tab_reference_id'),
});
await waitFor(() => user.click(addReferenceTab));
const enterReferenceField = screen.getByRole('textbox', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe('EditOptions', () => {

expect(
screen.getByRole('tab', {
name: textMock('ux_editor.options.tab_referenceId'),
name: textMock('ux_editor.options.tab_reference_id'),
}),
).toBeInTheDocument();
});
Expand Down Expand Up @@ -103,13 +103,13 @@ describe('EditOptions', () => {
});

const referenceIdElement = screen.getByRole('tab', {
name: textMock('ux_editor.options.tab_referenceId'),
name: textMock('ux_editor.options.tab_reference_id'),
});
await user.click(referenceIdElement);

expect(
screen.getByRole('tab', {
name: textMock('ux_editor.options.tab_referenceId'),
name: textMock('ux_editor.options.tab_reference_id'),
}),
).toBeInTheDocument();
});
Expand Down Expand Up @@ -138,13 +138,13 @@ describe('EditOptions', () => {
});

const referenceIdElement = screen.getByRole('tab', {
name: textMock('ux_editor.options.tab_referenceId'),
name: textMock('ux_editor.options.tab_reference_id'),
});
await user.click(referenceIdElement);

expect(
screen.getByRole('tab', {
name: textMock('ux_editor.options.tab_referenceId'),
name: textMock('ux_editor.options.tab_reference_id'),
}),
).toBeInTheDocument();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ function OptionTabsMergedTabs({
{t('ux_editor.options.tab_code_list')}
</StudioTabs.Tab>
<StudioTabs.Tab value={SelectedOptionsType.ReferenceId}>
{t('ux_editor.options.tab_referenceId')}
{t('ux_editor.options.tab_reference_id')}
</StudioTabs.Tab>
</StudioTabs.List>
<StudioTabs.Content className={classes.tabContent} value={SelectedOptionsType.CodeList}>
Expand Down Expand Up @@ -122,7 +122,7 @@ function OptionTabsSplitTabs({ component, handleComponentChange, optionListIds }
{t('ux_editor.options.tab_manual')}
</StudioTabs.Tab>
<StudioTabs.Tab value={SelectedOptionsType.ReferenceId}>
{t('ux_editor.options.tab_referenceId')}
{t('ux_editor.options.tab_reference_id')}
</StudioTabs.Tab>
</StudioTabs.List>
<StudioTabs.Content className={classes.tabContent} value={SelectedOptionsType.CodeList}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.container {
padding-inline: var(--fds-spacing-5);
}

.alert {
margin-top: var(--fds-spacing-2);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,28 @@ import { textMock } from '@studio/testing/mocks/i18nMock';
import userEvent from '@testing-library/user-event';
import { componentMocks } from '../../../../../../testing/componentMocks';

// Test data:
const mockComponent = componentMocks[ComponentType.Dropdown];
const mockOptionsId1 = 'test1';
const mockOptionsId2 = 'test2';
const getOptionListIds = jest
.fn()
.mockImplementation(() => Promise.resolve<string[]>([mockOptionsId1, mockOptionsId2]));
const handleComponentChange = jest.fn();

describe('ReferenceTab', () => {
it('should render', () => {
afterEach(() => jest.clearAllMocks());

it('should render a spinner', () => {
renderReferenceTab();
expect(screen.getByText(textMock('ux_editor.modal_properties_loading'))).toBeInTheDocument();
});

it('should render the component', () => {
renderReferenceTab();

expect(
screen.getByText(textMock('ux_editor.options.code_list_referenceId.description')),
screen.getByText(textMock('ux_editor.options.code_list_reference_id.description')),
).toBeInTheDocument();
});

Expand All @@ -24,14 +39,24 @@ describe('ReferenceTab', () => {
optionsId: 'some-id',
},
});
expect(screen.getByDisplayValue('some-id')).toBeInTheDocument();

expect(getInputElement()).toHaveValue('some-id');
});

it('should render no value if optionsId is a codeList from the library', () => {
renderReferenceTab({
componentProps: {
optionsId: mockOptionsId1,
},
});

expect(getInputElement()).toHaveValue('');
});

it('should call handleComponentChange when input value changes', async () => {
const handleComponentChange = jest.fn();
renderReferenceTab({ handleComponentChange });
const user = userEvent.setup();
const inputElement = screen.getByRole('textbox');
renderReferenceTab();
const inputElement = getInputElement();
await user.type(inputElement, 'new-id');
expect(handleComponentChange).toHaveBeenCalledWith({
...mockComponent,
Expand All @@ -40,9 +65,8 @@ describe('ReferenceTab', () => {
});

it('should call remove options property (if it exists) when input value changes', async () => {
const handleComponentChange = jest.fn();
const user = userEvent.setup();
renderReferenceTab({
handleComponentChange,
componentProps: {
options: [
{
Expand All @@ -52,8 +76,7 @@ describe('ReferenceTab', () => {
],
},
});
const user = userEvent.setup();
const inputElement = screen.getByRole('textbox');
const inputElement = getInputElement();
await user.type(inputElement, 'new-id');
expect(handleComponentChange).toHaveBeenCalledWith({
...mockComponent,
Expand All @@ -62,8 +85,13 @@ describe('ReferenceTab', () => {
});
});

function getInputElement() {
return screen.getByRole('textbox', {
name: textMock('ux_editor.modal_properties_custom_code_list_id'),
});
}

const renderReferenceTab = ({
handleComponentChange = jest.fn(),
componentProps = {},
}: {
handleComponentChange?: () => void;
Expand All @@ -79,5 +107,6 @@ const renderReferenceTab = ({
...componentProps,
}}
/>,
{ queries: { getOptionListIds } },
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ import React from 'react';
import type { IGenericEditComponent } from '../../../../componentConfig';
import { useTranslation, Trans } from 'react-i18next';
import { altinnDocsUrl } from 'app-shared/ext-urls';
import { StudioParagraph, StudioTextfield } from '@studio/components';
import { StudioAlert, StudioParagraph, StudioSpinner, StudioTextfield } from '@studio/components';
import type { SelectionComponentType } from '../../../../../../types/FormComponent';
import { useOptionListIdsQuery } from '../../../../../../hooks/queries/useOptionListIdsQuery';
import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams';
import classes from './ReferenceTab.module.css';

export function ReferenceTab({
component,
handleComponentChange,
}: IGenericEditComponent<SelectionComponentType>) {
const { t } = useTranslation();
const { org, app } = useStudioEnvironmentParams();
const { data: optionListIds, isPending } = useOptionListIdsQuery(org, app);

const handleOptionsIdChange = (optionsId: string) => {
if (component.options) {
Expand All @@ -22,22 +26,42 @@ export function ReferenceTab({
});
};

if (isPending) {
return (
<StudioSpinner
showSpinnerTitle={false}
spinnerTitle={t('ux_editor.modal_properties_loading')}
/>
);
}

const isOptionsIdInLibrary = optionListIds?.some(
(optionId: string): boolean => optionId == component.optionsId,
);
const isOptionsIdInLibraryOrComponent = isOptionsIdInLibrary || !!component.options;
const referenceIdValue = isOptionsIdInLibrary ? undefined : component.optionsId;

return (
<div className={classes.container}>
<StudioParagraph spacing size='small'>
{t('ux_editor.options.code_list_referenceId.description')}
{t('ux_editor.options.code_list_reference_id.description')}
</StudioParagraph>
<StudioParagraph spacing size='small'>
{t('ux_editor.options.code_list_referenceId.description_details')}
{t('ux_editor.options.code_list_reference_id.description_details')}
</StudioParagraph>
<StudioTextfield
type='text'
label={t('ux_editor.modal_properties_custom_code_list_id')}
onChange={(event) => handleOptionsIdChange(event.target.value)}
value={component.optionsId}
value={referenceIdValue}
size='small'
/>
<p style={{ marginBottom: 0 }}>
{isOptionsIdInLibraryOrComponent && (
<StudioAlert className={classes.alert} severity={'info'} size='sm'>
{t('ux_editor.options.tab_reference_id_alert_title')}
</StudioAlert>
)}
<p>
<Trans i18nKey={'ux_editor.modal_properties_code_list_read_more'}>
<a
href={altinnDocsUrl({ relativeUrl: 'altinn-studio/guides/options/dynamic-codelists/' })}
Expand Down

0 comments on commit 20b4540

Please sign in to comment.