Skip to content

Commit

Permalink
Merge pull request #4233 from greenbone/refactor-dialog
Browse files Browse the repository at this point in the history
refactor: dialog and savedialog
  • Loading branch information
daniele-mng authored Dec 3, 2024
2 parents 4428e7f + b762f54 commit c3e9d28
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 182 deletions.
58 changes: 58 additions & 0 deletions src/web/components/dialog/SaveDialogFooter.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* SPDX-FileCopyrightText: 2024 Greenbone AG
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import MultiStepFooter from 'web/components/dialog/multistepfooter';
import DialogFooter from 'web/components/dialog/twobuttonfooter';
import PropTypes from 'web/utils/proptypes';

const SaveDialogFooter = ({
multiStep,
isLoading,
prevDisabled,
nextDisabled,
buttonTitle,
currentStep,
setCurrentStep,
onClose,
handleSaveClick,
}) => {
return multiStep > 0 ? (
<MultiStepFooter
loading={isLoading}
prevDisabled={prevDisabled}
nextDisabled={nextDisabled}
rightButtonTitle={buttonTitle}
onNextButtonClick={() =>
setCurrentStep(currentStep < multiStep ? currentStep + 1 : currentStep)
}
onLeftButtonClick={onClose}
onPreviousButtonClick={() =>
setCurrentStep(currentStep > 0 ? currentStep - 1 : currentStep)
}
onRightButtonClick={handleSaveClick}
/>
) : (
<DialogFooter
isLoading={isLoading}
rightButtonTitle={buttonTitle}
onLeftButtonClick={onClose}
onRightButtonClick={handleSaveClick}
/>
);
};

SaveDialogFooter.propTypes = {
multiStep: PropTypes.number.isRequired,
isLoading: PropTypes.bool.isRequired,
prevDisabled: PropTypes.bool.isRequired,
nextDisabled: PropTypes.bool.isRequired,
buttonTitle: PropTypes.string.isRequired,
currentStep: PropTypes.number.isRequired,
setCurrentStep: PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired,
handleSaveClick: PropTypes.func.isRequired,
};

export default SaveDialogFooter;
59 changes: 59 additions & 0 deletions src/web/components/dialog/__tests__/SaveDialogFooter.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* SPDX-FileCopyrightText: 2024 Greenbone AG
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import {describe, test, expect, testing} from '@gsa/testing';

import {render, fireEvent, screen} from 'web/utils/testing';
import SaveDialogFooter from '../SaveDialogFooter';

describe('SaveDialogFooter', () => {
const defaultProps = {
multiStep: 0,
isLoading: false,
prevDisabled: false,
nextDisabled: false,
buttonTitle: 'Save',
currentStep: 0,
setCurrentStep: testing.fn(),
onClose: testing.fn(),
handleSaveClick: testing.fn(),
};

test('renders DialogFooter when multiStep is 0', () => {
render(<SaveDialogFooter {...defaultProps} />);
expect(screen.getByText('Save')).toBeInTheDocument();
});

test('renders MultiStepFooter when multiStep is greater than 0', () => {
render(<SaveDialogFooter {...defaultProps} multiStep={3} />);
expect(screen.getByText('Save')).toBeInTheDocument();
});

test('calls setCurrentStep with incremented value on next button click in MultiStepFooter', () => {
render(<SaveDialogFooter {...defaultProps} multiStep={3} />);
fireEvent.click(screen.getByTestId('dialog-next-button'));
expect(defaultProps.setCurrentStep).toHaveBeenCalledWith(1);
});

test('calls setCurrentStep with decremented value on previous button click in MultiStepFooter', () => {
render(
<SaveDialogFooter {...defaultProps} multiStep={3} currentStep={2} />,
);
fireEvent.click(screen.getByTestId('dialog-previous-button'));
expect(defaultProps.setCurrentStep).toHaveBeenCalledWith(1);
});

test('calls onClose when left button is clicked', () => {
render(<SaveDialogFooter {...defaultProps} />);
fireEvent.click(screen.getByText('Cancel'));
expect(defaultProps.onClose).toHaveBeenCalled();
});

test('calls handleSaveClick when right button is clicked', () => {
render(<SaveDialogFooter {...defaultProps} />);
fireEvent.click(screen.getByText('Save'));
expect(defaultProps.handleSaveClick).toHaveBeenCalled();
});
});
60 changes: 13 additions & 47 deletions src/web/components/dialog/confirmationdialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import React, {useCallback} from 'react';

import PropTypes from 'web/utils/proptypes';

import Dialog from 'web/components/dialog/dialog';
import DialogContent from 'web/components/dialog/content';
import Dialog from 'web/components/dialog/dialog';
import DialogTwoButtonFooter, {
DELETE_ACTION,
} from 'web/components/dialog/twobuttonfooter';
Expand All @@ -17,43 +15,6 @@ import useTranslation from 'web/hooks/useTranslation';

const DEFAULT_DIALOG_WIDTH = '400px';

const ConfirmationDialogContent = ({
content,
close,
rightButtonTitle,
onResumeClick,
loading,
rightButtonAction,
}) => {
const handleResume = useCallback(() => {
if (onResumeClick) {
onResumeClick();
}
}, [onResumeClick]);

return (
<DialogContent>
{content}
<DialogTwoButtonFooter
rightButtonTitle={rightButtonTitle}
onLeftButtonClick={close}
onRightButtonClick={handleResume}
loading={loading}
rightButtonAction={rightButtonAction}
/>
</DialogContent>
);
};

ConfirmationDialogContent.propTypes = {
close: PropTypes.func.isRequired,
content: PropTypes.elementOrString,
rightButtonTitle: PropTypes.string,
onResumeClick: PropTypes.func.isRequired,
loading: PropTypes.bool,
rightButtonAction: PropTypes.oneOf([undefined, DELETE_ACTION]),
};

const ConfirmationDialog = ({
width = DEFAULT_DIALOG_WIDTH,
content,
Expand All @@ -67,18 +28,23 @@ const ConfirmationDialog = ({
const [_] = useTranslation();

rightButtonTitle = rightButtonTitle || _('OK');

return (
<Dialog width={width} onClose={onClose} title={title}>
{({close}) => (
<ConfirmationDialogContent
close={close}
content={content}
<Dialog
width={width}
onClose={onClose}
title={title}
footer={
<DialogTwoButtonFooter
rightButtonTitle={rightButtonTitle}
onResumeClick={onResumeClick}
onLeftButtonClick={onClose}
onRightButtonClick={onResumeClick}
loading={loading}
rightButtonAction={rightButtonAction}
/>
)}
}
>
<DialogContent>{content}</DialogContent>
</Dialog>
);
};
Expand Down
9 changes: 0 additions & 9 deletions src/web/components/dialog/content.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,4 @@ const DialogContent = styled.div`
gap: 20px;
`;

export const StickyFooter = styled.div`
position: sticky;
bottom: 0;
background-color: white;
padding: 20px 0;
z-index: 201;
margin-bottom: 20;
`;

export default DialogContent;
38 changes: 25 additions & 13 deletions src/web/components/dialog/dialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import {Modal} from '@greenbone/opensight-ui-components-mantinev7';
import {ScrollArea} from '@mantine/core';
import {isDefined, isFunction} from 'gmp/utils/identity';
import {useCallback, useEffect, useState} from 'react';
import styled from 'styled-components';
Expand All @@ -27,6 +28,10 @@ const DialogTitleButton = styled.button`
`;

const StyledModal = styled(Modal)`
position: relative;
left: ${({position}) => `${position.x}px`};
z-index: ${MODAL_Z_INDEX};
.mantine-Modal-content {
display: flex;
flex-direction: column;
Expand All @@ -42,27 +47,30 @@ const StyledModal = styled(Modal)`
flex: 1;
}
.mantine-Modal-body {
padding-bottom: 0px;
margin-bottom: 15px;
overflow-y: auto;
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.mantine-Modal-close {
width: 2rem;
height: 2rem;
}
`;

position: relative;
left: ${({position}) => `${position.x}px`};
z-index: ${MODAL_Z_INDEX};
resize: both;
const StyledScrollArea = styled(ScrollArea)`
flex: 1;
overflow-y: auto;
padding-right: 18px;
`;

const Dialog = ({
children,
title,
footer,
onClose,
height = MODAL_HEIGHT,
width = MODAL_WIDTH,
onClose,
}) => {
const [isResizing, setIsResizing] = useState(false);

Expand Down Expand Up @@ -150,17 +158,21 @@ const Dialog = ({
height={height}
position={position}
>
{isFunction(children)
? children({
close: handleClose,
})
: children}
<StyledScrollArea>
{isFunction(children)
? children({
close: handleClose,
})
: children}
</StyledScrollArea>
{footer}
</StyledModal>
);
};

Dialog.propTypes = {
children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
footer: PropTypes.node,
title: PropTypes.string,
width: PropTypes.string,
onClose: PropTypes.func,
Expand Down
Loading

0 comments on commit c3e9d28

Please sign in to comment.