Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚀 feat(PlanCard): Make ListItem clickable #670

Merged
merged 2 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 43 additions & 22 deletions packages/yoga/src/Card/web/PlanCard/List.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { string, node, shape, oneOfType, func } from 'prop-types';

import Text from '../../../Text';
import theme from '../../../Theme/helpers/themeReader';
import Box from '../../../Box';

const { card, cardweb } = theme.components;

Expand Down Expand Up @@ -31,11 +32,20 @@ const Item = styled.li`
}
`;

const Wrapper = styled.div`
const Wrapper = styled(Box)`
display: flex;
min-width: 0;
align-items: center;

${props =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clicks can also be a link, Should we add that option? Example:
If the component receives a href prop, we can assume element should be a <a> tag..

WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, beware that button should have the "type" attribute. (Maybe we can assume always type="button").

A helpful article: https://www.builder.io/blog/buttons

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clicks can also be a link, Should we add that option? Example: If the component receives a href prop, we can assume element should be a <a> tag..

WDYT?

I have discussed with the team, and for now, links are out of scope, at least within the context of Gympass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, beware that button should have the "type" attribute. (Maybe we can assume always type="button").

A helpful article: https://www.builder.io/blog/buttons

Nice article! I completely agree. I added the button type in this commit: 5845523.

@MicaelRodrigues could you review it again please?

props.as === 'button' &&
css`
border: none;
padding: 0;
background: transparent;
cursor: pointer;
`}

svg {
flex-shrink: 0;
}
Expand Down Expand Up @@ -77,45 +87,56 @@ const Button = styled.button`
`;

const ListItem = withTheme(
({ text, icon: Icon, buttonProps, theme: yogaTheme }) => (
<Item>
<Wrapper>
{Icon && (
<IconWrapper>
{isValidElement(Icon) ? (
Icon
) : (
<Icon
width={16}
height={16}
fill={yogaTheme.yoga.colors.text.primary}
/>
)}
</IconWrapper>
({ text, icon: Icon, buttonProps, theme: yogaTheme, onClick }) => {
const wrapperProps = onClick
? { as: 'button', type: 'button', onClick }
: {};

return (
<Item>
<Wrapper {...wrapperProps}>
{Icon && (
<IconWrapper>
{isValidElement(Icon) ? (
Icon
) : (
<Icon
width={16}
height={16}
fill={yogaTheme.yoga.colors.text.primary}
/>
)}
</IconWrapper>
)}
<ItemText as="span">{text}</ItemText>
</Wrapper>
{Boolean(Object.keys(buttonProps).length) && (
<Button {...buttonProps} />
)}
<ItemText as="span">{text}</ItemText>
</Wrapper>
{Boolean(Object.keys(buttonProps).length) && <Button {...buttonProps} />}
</Item>
),
</Item>
);
},
);

List.displayName = 'PlanCard.List';
ListItem.displayName = 'PlanCard.ListItem';
Button.displayName = 'PlanCard.ListButton';

ListItem.propTypes = {
text: string.isRequired,
text: oneOfType([string, node]).isRequired,
/** an icon to be displayed on the begin of the item */
icon: oneOfType([node, func]),
/** if provided displays a button below the item text. It accepts all button
* element props */
buttonProps: shape({}),
/** if provided makes the item clickable */
onClick: func,
};

ListItem.defaultProps = {
icon: undefined,
buttonProps: {},
onClick: undefined,
};

export { List, ListItem };
41 changes: 40 additions & 1 deletion packages/yoga/src/Card/web/PlanCard/PlanCard.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import PlanCard from '.';
describe('<PlanCard />', () => {
const buttonOnClickMock = jest.fn();

const renderPlan = () =>
const renderPlan = ({ clickableItems } = {}) =>
render(
<ThemeProvider>
<PlanCard>
Expand All @@ -31,6 +31,7 @@ describe('<PlanCard />', () => {
/>
}
text="gyms and studios"
onClick={clickableItems && jest.fn()}
/>
<PlanCard.ListItem
icon={Star}
Expand All @@ -40,6 +41,7 @@ describe('<PlanCard />', () => {
as: 'a',
onClick: buttonOnClickMock,
}}
onClick={clickableItems && jest.fn()}
/>
</PlanCard.List>
</PlanCard.Content>
Expand All @@ -58,6 +60,37 @@ describe('<PlanCard />', () => {

expect(buttonOnClickMock).toHaveBeenCalled();
});

it('should make list item clickable', () => {
const itemClickMock = jest.fn();

const { getByRole } = render(
<ThemeProvider>
<PlanCard variant="energy">
<PlanCard.Content title="Basic">
<PlanCard.List>
<PlanCard.ListItem
icon={
<Icon
as={MapPin}
height="small"
width="small"
stroke="medium"
/>
}
text="gyms and studios"
onClick={itemClickMock}
/>
</PlanCard.List>
</PlanCard.Content>
</PlanCard>
</ThemeProvider>,
);

fireEvent.click(getByRole('button', { label: 'gyms and studios' }));

expect(itemClickMock).toHaveBeenCalled();
});
});

describe('Snapshots', () => {
Expand Down Expand Up @@ -151,5 +184,11 @@ describe('<PlanCard />', () => {

expect(container).toMatchSnapshot();
});

it('should render list item content as button', () => {
const { container } = renderPlan({ clickableItems: true });

expect(container).toMatchSnapshot();
});
});
});
Loading