Skip to content

Commit

Permalink
Implement delete-warning-popover for repeating-groups (#498)
Browse files Browse the repository at this point in the history
* add functional warning popup

* add languages, fix z-index issue

* implement delete-warning repeating groups mobile

* Update src/altinn-app-frontend/src/features/form/containers/RepeatingGroupTable.tsx

Co-authored-by: Håkon <2082481+haakemon@users.noreply.github.com>

* Part 2 of restructuring calls

* Copying config from the frontend project part, making shared tests work

* Fixing unit test (the component did not check this optional passed function before calling it)

* extract popover component, apply css suggestion

* move DeleteWarningPopover to altinn-shared

* remove empty testfile

* add test for checking popover-warning open and close

* extract layout into function to reuse

* add cypress test for groups popover warning

* update with correct button references

* change nested group test to work with openByDefault

* typo

* update query textfield in table

Co-authored-by: Ole Martin Handeland <github@olemartin.org>
Co-authored-by: Håkon <2082481+haakemon@users.noreply.github.com>
Co-authored-by: Ole Martin Handeland <git@olemartin.org>
  • Loading branch information
4 people authored Oct 20, 2022
1 parent 9d04196 commit dd5b9ef
Show file tree
Hide file tree
Showing 13 changed files with 359 additions and 55 deletions.
1 change: 1 addition & 0 deletions src/altinn-app-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"react-styleguidist": "12.0.0",
"redux-mock-store": "1.5.4",
"redux-saga-test-plan": "4.0.6",
"resize-observer-polyfill": "1.5.1",
"rimraf": "3.0.2",
"source-map-loader": "4.0.0",
"style-loader": "3.3.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback } from 'react';
import React, { useState } from 'react';

import {
createTheme,
Expand Down Expand Up @@ -48,6 +48,7 @@ import {
AltinnTableHeader,
AltinnTableRow,
} from 'altinn-shared/components';
import { DeleteWarningPopover } from 'altinn-shared/components/molecules/DeleteWarningPopover';
import altinnAppTheme from 'altinn-shared/theme/altinnAppTheme';
import { getLanguageFromKey, getTextResourceByKey } from 'altinn-shared/utils';
import type { IMobileTableItem } from 'altinn-shared/components/molecules/AltinnMobileTableItem';
Expand Down Expand Up @@ -190,6 +191,10 @@ const useStyles = makeStyles({
clipPath: 'inset(50%)',
whiteSpace: 'nowrap',
},
popoverCurrentCell: {
zIndex: 1,
position: 'relative',
},
});

function getEditButtonText(
Expand Down Expand Up @@ -271,6 +276,8 @@ export function RepeatingGroupTable({

const showTableHeader =
repeatingGroupIndex > -1 && !(repeatingGroupIndex == 0 && editIndex == 0);
const [popoverPanelIndex, setPopoverPanelIndex] = useState(-1);
const [popoverOpen, setPopoverOpen] = useState(false);

const getFormDataForComponent = (
component: ILayoutComponent | ILayoutGroup,
Expand All @@ -288,6 +295,30 @@ export function RepeatingGroupTable({
);
};

const onOpenChange = (index: number) => {
if (index == popoverPanelIndex && popoverOpen) {
setPopoverPanelIndex(-1);
} else {
setPopoverPanelIndex(index);
}
};

const handlePopoverDeleteClick = (index: number) => {
return () => {
onClickRemove(index);
onOpenChange(index);
setPopoverOpen(false);
};
};

const handleDeleteClick = (index: number) => {
if (container.edit?.alertOnDelete) {
onOpenChange(index);
} else {
onClickRemove(index);
}
};

const handleEditClick = (groupIndex: number) => {
if (groupIndex === editIndex) {
setEditIndex(-1);
Expand Down Expand Up @@ -345,15 +376,6 @@ export function RepeatingGroupTable({
);
};

const removeClicked = useCallback(
(index: number) => {
return async () => {
onClickRemove(index);
};
},
[onClickRemove],
);

const renderRepeatingGroupsEditContainer = () => {
return (
editIndex >= 0 && (
Expand Down Expand Up @@ -506,16 +528,40 @@ export function RepeatingGroupTable({
align='center'
style={{ width: '80px', padding: 0 }}
key={`delete-${index}`}
className={cn({
[classes.popoverCurrentCell]:
index == popoverPanelIndex,
})}
>
<IconButton
className={classes.deleteButton}
disabled={deleting}
onClick={removeClicked(index)}
aria-label={`${deleteButtonText}-${firstCellData}`}
>
<i className='ai ai-trash' />
{deleteButtonText}
</IconButton>
<DeleteWarningPopover
trigger={
<IconButton
className={classes.deleteButton}
disabled={deleting}
onClick={() => handleDeleteClick(index)}
aria-label={`${deleteButtonText}-${firstCellData}`}
>
<i className='ai ai-trash' />
{deleteButtonText}
</IconButton>
}
side='left'
language={language}
deleteButtonText={getLanguageFromKey(
'group.row_popover_delete_button_confirm',
language,
)}
messageText={getLanguageFromKey(
'group.row_popover_delete_message',
language,
)}
open={popoverPanelIndex == index && popoverOpen}
setPopoverOpen={setPopoverOpen}
onCancelClick={() => onOpenChange(index)}
onPopoverDeleteClick={handlePopoverDeleteClick(
index,
)}
/>
</TableCell>
)}
</AltinnTableRow>
Expand Down Expand Up @@ -575,7 +621,7 @@ export function RepeatingGroupTable({
valid={!rowHasErrors}
editIndex={editIndex}
onEditClick={() => handleEditClick(index)}
onDeleteClick={() => onClickRemove(index)}
onDeleteClick={() => handleDeleteClick(index)}
editButtonText={
rowHasErrors
? getLanguageFromKey(
Expand Down Expand Up @@ -605,6 +651,12 @@ export function RepeatingGroupTable({
deleteIconNode={
!hideDeleteButton && <i className={'ai ai-trash'} />
}
popoverPanelIndex={popoverPanelIndex}
popoverOpen={popoverOpen}
setPopoverOpen={setPopoverOpen}
language={language}
onPopoverDeleteClick={handlePopoverDeleteClick}
onOpenChange={onOpenChange}
/>
{editIndex === index &&
renderRepeatingGroupsEditContainer()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as React from 'react';
import { getFormLayoutGroupMock } from '__mocks__/mocks';
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import * as ResizeObserverModule from 'resize-observer-polyfill';
import { mockMediaQuery, renderWithProviders } from 'testUtils';

import { RepeatingGroupTable } from 'src/features/form/containers/RepeatingGroupTable';
Expand All @@ -20,14 +21,49 @@ import type { IOption, ITextResource } from 'src/types';

import type { ILanguage } from 'altinn-shared/types';

(global as any).ResizeObserver = ResizeObserverModule.default;

const user = userEvent.setup();

const getLayout = (group: ILayoutGroup, components: ILayoutComponent[]) => {
const layout: ILayoutState = {
layouts: {
FormLayout: [].concat(group).concat(components),
},
uiConfig: {
hiddenFields: [],
repeatingGroups: {
'mock-container-id': {
index: 3,
},
},
autoSave: false,
currentView: 'FormLayout',
focus: undefined,
tracks: {
order: ['FormLayout'],
hidden: [],
hiddenExpr: {},
},
},
error: null,
layoutsets: null,
};

return layout;
};

describe('RepeatingGroupTable', () => {
const group: ILayoutGroup = getFormLayoutGroupMock({});
const language: ILanguage = {
general: {
delete: 'Delete',
edit_alt: 'Edit',
cancel: 'Cancel',
},
group: {
row_popover_delete_message: 'Are you sure you want to delete this row?',
row_popover_delete_button_confirm: 'Yes, delete the row',
},
};
const textResources: ITextResource[] = [
Expand Down Expand Up @@ -90,29 +126,7 @@ describe('RepeatingGroupTable', () => {
options: options,
} as ISelectionComponentProps,
];
const layout: ILayoutState = {
layouts: {
FormLayout: [].concat(group).concat(components),
},
uiConfig: {
hiddenFields: [],
repeatingGroups: {
'mock-container-id': {
index: 3,
},
},
autoSave: false,
currentView: 'FormLayout',
focus: undefined,
tracks: {
order: ['FormLayout'],
hidden: [],
hiddenExpr: {},
},
},
error: null,
layoutsets: null,
};
const layout: ILayoutState = getLayout(group, components);
const currentView = 'FormLayout';
const data: IFormData = {
'some-group[1].checkboxBinding': 'option.value',
Expand Down Expand Up @@ -146,6 +160,43 @@ describe('RepeatingGroupTable', () => {
expect(tableHeader).not.toBeInTheDocument();
});

describe('popOver warning', () => {
beforeEach(() => {
const group: ILayoutGroup = getFormLayoutGroupMock({
edit: { alertOnDelete: true },
});
const layout: ILayoutState = getLayout(group, components);
const repeatingGroupDeepCopyComponents: Array<
Array<ILayoutComponent | ILayoutGroup>
> = createRepeatingGroupComponents(
group,
components,
repeatingGroupIndex,
textResources,
);

render({
container: group,
repeatingGroupDeepCopyComponents: repeatingGroupDeepCopyComponents,
layout: layout.layouts[currentView],
});
});

it('should open and close delete-warning on delete click when alertOnDelete is active', async () => {
await user.click(screen.getAllByRole('button', { name: /delete/i })[0]);

expect(
screen.queryByText('Are you sure you want to delete this row?'),
).toBeInTheDocument();

await user.click(screen.getAllByRole('button', { name: /delete/i })[0]);

expect(
screen.queryByText('Are you sure you want to delete this row?'),
).not.toBeInTheDocument();
});
});

describe('desktop view', () => {
const { setScreenWidth } = mockMediaQuery(992);
beforeEach(() => {
Expand Down
1 change: 1 addition & 0 deletions src/altinn-app-frontend/src/features/form/layout/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ export interface IGroupEditProperties {
deleteButton?: boolean;
multiPage?: boolean;
openByDefault?: boolean | 'first' | 'last';
alertOnDelete?: boolean;
saveAndNextButton?: boolean;
}

Expand Down
8 changes: 6 additions & 2 deletions src/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
},
"jest": {
"transform": {
".(ts|tsx)": "ts-jest"
".(ts|tsx)": "ts-jest",
"\\.js$": "ts-jest"
},
"reporters": [
"default",
Expand All @@ -64,7 +65,10 @@
"!__tests__/**/*",
"src/**/*.{ts,tsx}"
],
"testEnvironment": "jsdom"
"testEnvironment": "jsdom",
"transformIgnorePatterns": [
"node_modules/(?!react-leaflet)/"
]
},
"browserslist": {
"production": [
Expand Down
Loading

0 comments on commit dd5b9ef

Please sign in to comment.