Skip to content

Commit acc0754

Browse files
aleksandernsilvaMartinSchoeler
authored andcommitted
refactor: GenericUpsellModal to use GenericModal (#36347)
1 parent 43bfd7a commit acc0754

File tree

6 files changed

+599
-93
lines changed

6 files changed

+599
-93
lines changed

apps/meteor/client/components/GenericModal/GenericModal.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type { RequiredModalProps } from './withDoNotAskAgain';
99
import { withDoNotAskAgain } from './withDoNotAskAgain';
1010
import { modalStore } from '../../providers/ModalProvider/ModalStore';
1111

12-
type VariantType = 'danger' | 'warning' | 'info' | 'success';
12+
type VariantType = 'danger' | 'warning' | 'info' | 'success' | 'upsell';
1313

1414
type GenericModalProps = RequiredModalProps & {
1515
variant?: VariantType;
@@ -38,6 +38,7 @@ const getButtonProps = (variant: VariantType): ComponentProps<typeof Button> =>
3838
case 'danger':
3939
return { danger: true };
4040
case 'warning':
41+
case 'upsell':
4142
return { primary: true };
4243
default:
4344
return {};
@@ -83,6 +84,8 @@ const GenericModal = ({
8384

8485
const dismissedRef = useRef(true);
8586

87+
const taglineColor = variant === 'upsell' ? 'annotation' : undefined;
88+
8689
const handleConfirm = useEffectEvent(() => {
8790
dismissedRef.current = false;
8891
onConfirm?.();
@@ -118,7 +121,7 @@ const GenericModal = ({
118121
<Modal.Header>
119122
{renderIcon(icon, variant)}
120123
<Modal.HeaderText>
121-
{tagline && <Modal.Tagline>{tagline}</Modal.Tagline>}
124+
{tagline && <Modal.Tagline color={taglineColor}>{tagline}</Modal.Tagline>}
122125
<Modal.Title id={`${genericModalId}-title`}>{title ?? t('Are_you_sure')}</Modal.Title>
123126
</Modal.HeaderText>
124127
{onClose && <Modal.Close aria-label={t('Close')} onClick={handleCloseButtonClick} />}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/* eslint-disable @typescript-eslint/naming-convention */
2+
import { mockAppRoot } from '@rocket.chat/mock-providers';
3+
import { composeStories } from '@storybook/react';
4+
import { render, screen } from '@testing-library/react';
5+
import { axe } from 'jest-axe';
6+
7+
import GenericUpsellModal from './GenericUpsellModal';
8+
import * as stories from './GenericUpsellModal.stories';
9+
10+
const appRoot = mockAppRoot()
11+
.withTranslations('en', 'core', {
12+
Premium_capability: 'Premium capability',
13+
Cancel: 'Cancel',
14+
Upgrade: 'Upgrade',
15+
})
16+
.build();
17+
18+
describe('GenericUpsellModal', () => {
19+
const defaultProps = {
20+
title: 'Test Title',
21+
img: 'test-image.png',
22+
onClose: jest.fn(),
23+
};
24+
25+
afterEach(() => {
26+
jest.clearAllMocks();
27+
});
28+
29+
const testCases = Object.values(composeStories(stories)).map((Story) => [Story.storyName || 'Story', Story]);
30+
31+
test.each(testCases)(`renders %s without crashing`, async (_storyname, Story) => {
32+
const { baseElement } = render(<Story />);
33+
expect(baseElement).toMatchSnapshot();
34+
});
35+
36+
test.each(testCases)('%s should have no a11y violations', async (_storyname, Story) => {
37+
const { container } = render(<Story />);
38+
39+
const results = await axe(container);
40+
expect(results).toHaveNoViolations();
41+
});
42+
43+
it('should render basic properties', () => {
44+
const props = {
45+
...defaultProps,
46+
subtitle: 'Test Subtitle',
47+
description: 'Test Description',
48+
onCancel: jest.fn(),
49+
onConfirm: jest.fn(),
50+
};
51+
render(<GenericUpsellModal {...props} />, { wrapper: appRoot });
52+
53+
expect(screen.getByText('Test Title')).toBeInTheDocument();
54+
expect(screen.getByText('Test Subtitle')).toBeInTheDocument();
55+
expect(screen.getByText('Test Description')).toBeInTheDocument();
56+
});
57+
58+
it('should render with default confirm and cancel buttons', () => {
59+
render(<GenericUpsellModal {...defaultProps} onCancel={jest.fn()} onConfirm={jest.fn()} />, { wrapper: appRoot });
60+
61+
expect(screen.getByRole('button', { name: 'Cancel' })).toBeInTheDocument();
62+
expect(screen.getByRole('button', { name: 'Upgrade' })).toBeInTheDocument();
63+
});
64+
65+
it('should render with default tagline', () => {
66+
render(<GenericUpsellModal {...defaultProps} />, { wrapper: appRoot });
67+
68+
expect(screen.getByText('Premium capability')).toBeInTheDocument();
69+
});
70+
});
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { action } from '@storybook/addon-actions';
2+
import type { Meta, StoryObj } from '@storybook/react';
3+
4+
import GenericUpsellModal from '.';
5+
6+
const meta = {
7+
title: 'Components/GenericUpsellModal',
8+
component: GenericUpsellModal,
9+
args: {
10+
onClose: action('onClose'),
11+
img: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAoACgDASIAAhEBAxEB/8QAGwAAAgIDAQAAAAAAAAAAAAAAAAcEBgIDBQj/xAAuEAACAQQAAwcEAQUAAAAAAAABAgMABAUREiExBhMUIkFRYQcWcYGhFTJSgpH/xAAYAQADAQEAAAAAAAAAAAAAAAACAwQBAP/EAB4RAAIBBQEBAQAAAAAAAAAAAAABAgMREiExE0HR/9oADAMBAAIRAxEAPwBuXuIkhBuMe5ib/AHQP49q4L3mLitryTLTSpOiHQI5k/HzXa/qbFOEudVTu1dumWvcTaNCZYZ7vU6g6LxqjOU/24dfs1Ouh9FnkMpd3Reeyx83hAxZZEhkdV9/MBrX71WGPvJcqrJBGveKATtuXXqNU0pu02bTHXD/AGvJAluyxxRd6F4x00o+NdKoVrjbzJdvVe1t5cVLc2ck8qjnohgpPtz2v7G6JtPQ2VJwjlcw+37mchpnK6GtIuv5NFWeTsLNPvxWTvpfjvOEfwKKzEVkSct2vscS/BIzSN0YRkeX81UpPqO8masJETu7OOccY4dswYFQeftv096XV5knuJGdm2T1+agvMXj8jEaHX905QihabvcbuS7X566mLWLwSY8PuRnk/u4eZ0deTl71Ef6hY+0yM88TzeNZY4luYwpVYyduOfrvhPTnr0pXSX9y5mCsyJMdyxxvwq599em+taItqCSNc90ChvZRUruUcT0JiO18Elpk7t8v41LWzacxkBSuvjQ/FFJayjDWrCTepAQ2vUH0oo/Jk3ovpwJJeVCP5CN+lFFaaMqy+nAyuChvrTI2kN9JAsi2ZOy4IBHMnkSCP+iqBexSWdxLazoUljJVlPUH2oorkV10pRc7b1zXb/hZOzuJvM86QWEXeELxOzHSIPcmiiiunVlF2RNTpRkrs//Z',
12+
},
13+
parameters: {
14+
layout: 'centered',
15+
},
16+
} satisfies Meta<typeof GenericUpsellModal>;
17+
18+
export default meta;
19+
type Story = StoryObj<typeof meta>;
20+
21+
export const Default: Story = {
22+
args: {
23+
title: 'This is the title',
24+
subtitle: 'This is a subtitle',
25+
description:
26+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
27+
onCancel: action('onCancel'),
28+
onConfirm: action('onConfirm'),
29+
},
30+
};
31+
32+
export const WithCustomTagLine: Story = {
33+
args: {
34+
...Default.args,
35+
tagline: 'Exclusive',
36+
},
37+
};
38+
39+
export const WithCustomButtons: Story = {
40+
args: {
41+
...Default.args,
42+
cancelText: 'Learn More',
43+
confirmText: 'Contact Sales',
44+
},
45+
};
46+
47+
export const WithAnnotation: Story = {
48+
args: {
49+
...Default.args,
50+
annotation: 'This is an annotation.',
51+
},
52+
};

apps/meteor/client/components/GenericUpsellModal/GenericUpsellModal.tsx

Lines changed: 26 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,40 @@
1-
import { Box, Button, Modal } from '@rocket.chat/fuselage';
2-
import type { Keys as IconName } from '@rocket.chat/icons';
3-
import type { ReactNode, ReactElement, ComponentProps } from 'react';
1+
import { Box, Modal } from '@rocket.chat/fuselage';
2+
import type { ReactElement, ComponentProps } from 'react';
43
import { useTranslation } from 'react-i18next';
54

6-
type GenericUpsellModalProps = {
7-
children?: ReactNode;
8-
tagline?: ReactNode;
9-
cancelText?: ReactNode;
10-
confirmText?: ReactNode;
11-
title: string | ReactElement;
5+
import GenericModal from '../GenericModal';
6+
7+
type GenericUpsellModalProps = Omit<ComponentProps<typeof GenericModal>, 'variant' | 'children' | 'onClose' | 'onDismiss'> & {
128
subtitle?: string | ReactElement;
139
description?: string | ReactElement;
14-
icon?: IconName;
1510
img: ComponentProps<typeof Modal.HeroImage>['src'];
16-
onCancel?: () => void;
1711
onClose: () => void;
1812
onConfirm?: () => void;
19-
annotation?: ReactNode;
20-
} & ComponentProps<typeof Modal>;
13+
};
2114

22-
const GenericUpsellModal = ({
23-
tagline,
24-
title,
25-
subtitle,
26-
img,
27-
cancelText,
28-
confirmText,
29-
icon,
30-
description,
31-
onClose,
32-
onCancel,
33-
onConfirm,
34-
annotation,
35-
...props
36-
}: GenericUpsellModalProps) => {
15+
const GenericUpsellModal = ({ tagline, subtitle, img, description, confirmText, icon = null, ...props }: GenericUpsellModalProps) => {
3716
const { t } = useTranslation();
3817

3918
return (
40-
<Modal {...props}>
41-
<Modal.Header>
42-
{icon && <Modal.Icon name={icon} />}
43-
<Modal.HeaderText>
44-
<Modal.Tagline color='font-annotation'>{tagline ?? t('Premium_capability')}</Modal.Tagline>
45-
<Modal.Title>{title}</Modal.Title>
46-
</Modal.HeaderText>
47-
<Modal.Close aria-label={t('Close')} onClick={onClose} />
48-
</Modal.Header>
49-
<Modal.Content>
50-
<Modal.HeroImage src={img} alt='' />
51-
{subtitle && (
52-
<Box is='h3' fontScale='h3'>
53-
{subtitle}
54-
</Box>
55-
)}
56-
{description && (
57-
<Box style={{ whiteSpace: 'break-spaces' }} fontScale='p2' mbs={16}>
58-
{description}
59-
</Box>
60-
)}
61-
</Modal.Content>
62-
<Modal.Footer justifyContent={annotation ? 'space-between' : 'flex-end'}>
63-
{annotation && <Modal.FooterAnnotation>{annotation}</Modal.FooterAnnotation>}
64-
{(onCancel || onConfirm) && (
65-
<Modal.FooterControllers>
66-
{onCancel && (
67-
<Button secondary onClick={onCancel}>
68-
{cancelText ?? t('Cancel')}
69-
</Button>
70-
)}
71-
{onConfirm && (
72-
<Button primary onClick={onConfirm}>
73-
{confirmText ?? t('Upgrade')}
74-
</Button>
75-
)}
76-
</Modal.FooterControllers>
77-
)}
78-
</Modal.Footer>
79-
</Modal>
19+
<GenericModal
20+
{...props}
21+
icon={icon}
22+
tagline={tagline ?? t('Premium_capability')}
23+
variant='upsell'
24+
confirmText={confirmText ?? t('Upgrade')}
25+
>
26+
<Modal.HeroImage src={img} alt='' />
27+
{subtitle && (
28+
<Box is='h3' fontScale='h3'>
29+
{subtitle}
30+
</Box>
31+
)}
32+
{description && (
33+
<Box style={{ whiteSpace: 'break-spaces' }} fontScale='p2' mbs={16}>
34+
{description}
35+
</Box>
36+
)}
37+
</GenericModal>
8038
);
8139
};
8240

0 commit comments

Comments
 (0)