Created SimpleCard component to reduce duplicated code when rendering cards

This commit is contained in:
Alejandro Celaya 2020-12-08 19:10:29 +01:00
parent e60d241fcf
commit 2017ee7456
4 changed files with 126 additions and 93 deletions

View file

@ -1,6 +1,7 @@
import { Card, CardBody, CardHeader, FormGroup, Input } from 'reactstrap';
import { FormGroup, Input } from 'reactstrap';
import classNames from 'classnames';
import ToggleSwitch from '../utils/ToggleSwitch';
import { SimpleCard } from '../utils/SimpleCard';
import { Settings } from './reducers/settings';
interface RealTimeUpdatesProps {
@ -14,9 +15,7 @@ const intervalValue = (interval?: number) => !interval ? '' : `${interval}`;
const RealTimeUpdates = (
{ settings: { realTimeUpdates }, toggleRealTimeUpdates, setRealTimeUpdatesInterval }: RealTimeUpdatesProps,
) => (
<Card>
<CardHeader>Real-time updates</CardHeader>
<CardBody>
<SimpleCard title="Real-time updates">
<FormGroup>
<ToggleSwitch checked={realTimeUpdates.enabled} onChange={toggleRealTimeUpdates}>
Enable or disable real-time updates, when using Shlink v2.2.0 or newer.
@ -45,8 +44,7 @@ const RealTimeUpdates = (
</small>
)}
</FormGroup>
</CardBody>
</Card>
</SimpleCard>
);
export default RealTimeUpdates;

View file

@ -1,6 +1,6 @@
import { isEmpty, pipe, replace, trim } from 'ramda';
import { FC, useState } from 'react';
import { Button, Card, CardBody, CardHeader, FormGroup, Input } from 'reactstrap';
import { Button, FormGroup, Input } from 'reactstrap';
import { InputType } from 'reactstrap/lib/Input';
import * as m from 'moment';
import DateInput, { DateInputProps } from '../utils/DateInput';
@ -11,6 +11,7 @@ import { isReachableServer, SelectedServer } from '../servers/data';
import { formatIsoDate } from '../utils/helpers/date';
import { TagsSelectorProps } from '../tags/helpers/TagsSelector';
import { DomainSelectorProps } from '../domains/DomainSelector';
import { SimpleCard } from '../utils/SimpleCard';
import { ShortUrlData } from './data';
import { ShortUrlCreation } from './reducers/shortUrlCreation';
import UseExistingIfFoundInfoIcon from './UseExistingIfFoundInfoIcon';
@ -121,9 +122,7 @@ const CreateShortUrl = (
<>
<div className="row">
<div className="col-sm-6 mb-3">
<Card>
<CardHeader>Customize the short URL</CardHeader>
<CardBody>
<SimpleCard title="Customize the short URL">
<p>
Use a custom slug for your marketing campaigns, change the domain or set a specific length for
the auto-generated short code.
@ -150,26 +149,21 @@ const CreateShortUrl = (
/>
</FormGroup>
)}
</CardBody>
</Card>
</SimpleCard>
</div>
<div className="col-sm-6 mb-3">
<Card>
<CardHeader>Limit access to the short URL</CardHeader>
<CardBody>
<SimpleCard title="Limit access to the short URL">
<p>Determine when and how many times your short URL can be accessed.</p>
{renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
{renderDateInput('validSince', 'Enabled since...', { maxDate: shortUrlCreation.validUntil as m.Moment | undefined })}
{renderDateInput('validUntil', 'Enabled until...', { minDate: shortUrlCreation.validSince as m.Moment | undefined })}
</CardBody>
</Card>
</SimpleCard>
</div>
</div>
<Card className="mb-3">
<CardHeader>Extra validations</CardHeader>
<CardBody>
<ForServerVersion minVersion="1.16.0">
<SimpleCard title="Extra validations" className="mb-3">
<p>
Make sure the long URL is valid, or ensure an existing short URL is returned if it matches all
provided data.
@ -185,7 +179,6 @@ const CreateShortUrl = (
</Checkbox>
</p>
</ForServerVersion>
<ForServerVersion minVersion="1.16.0">
<p>
<Checkbox
inline
@ -197,9 +190,8 @@ const CreateShortUrl = (
</Checkbox>
<UseExistingIfFoundInfoIcon />
</p>
</SimpleCard>
</ForServerVersion>
</CardBody>
</Card>
</>
)}

13
src/utils/SimpleCard.tsx Normal file
View file

@ -0,0 +1,13 @@
import { CardProps } from 'reactstrap/lib/Card';
import { Card, CardBody, CardHeader } from 'reactstrap';
interface SimpleCardProps extends CardProps {
title?: string;
}
export const SimpleCard = ({ title, children, ...rest }: SimpleCardProps) => (
<Card {...rest}>
{title && <CardHeader>{title}</CardHeader>}
<CardBody>{children}</CardBody>
</Card>
);

View file

@ -0,0 +1,30 @@
import { shallow } from 'enzyme';
import { Card, CardBody, CardHeader } from 'reactstrap';
import { SimpleCard } from '../../src/utils/SimpleCard';
describe('<SimpleCard />', () => {
it.each([
[{}, 0 ],
[{ title: 'Cool title' }, 1 ],
])('renders header only if title is provided', (props, expectedAmountOfHeaders) => {
const wrapper = shallow(<SimpleCard {...props} />);
expect(wrapper.find(CardHeader)).toHaveLength(expectedAmountOfHeaders);
});
it('renders children inside body', () => {
const wrapper = shallow(<SimpleCard>Hello world</SimpleCard>);
const body = wrapper.find(CardBody);
expect(body).toHaveLength(1);
expect(body.html()).toContain('Hello world');
});
it('passes extra props to nested card', () => {
const wrapper = shallow(<SimpleCard className="foo" color="primary">Hello world</SimpleCard>);
const card = wrapper.find(Card);
expect(card.prop('className')).toEqual('foo');
expect(card.prop('color')).toEqual('primary');
});
});