Skip to content

Commit

Permalink
feat(datepicker): datepicker based on ant design
Browse files Browse the repository at this point in the history
- Add AntdPicker component as a new component for DatePicker, based on ant design library.
- Update DatePicker and FormControl to use the new component and support some props from old datepicker component to keep compatibility between them.
- Update old tests and add new ones for new component.
  • Loading branch information
luisval11 committed Jul 14, 2022
1 parent 880489e commit cdc0277
Show file tree
Hide file tree
Showing 10 changed files with 1,176 additions and 72 deletions.
278 changes: 278 additions & 0 deletions src/components/AntdPicker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
/* eslint-disable camelcase */
import React, { useEffect, useState } from 'react';
import { ConfigProvider } from 'antd';
import ca_ES from 'antd/lib/locale/ca_ES';
import de_DE from 'antd/lib/locale/de_DE';
import en_US from 'antd/lib/locale/en_US';
import es_ES from 'antd/lib/locale/es_ES';
// import eu_ES from 'antd/lib/locale/eu_ES'; There's no such translation on antd
import fr_FR from 'antd/lib/locale/fr_FR';
import it_IT from 'antd/lib/locale/it_IT';
import pt_PT from 'antd/lib/locale/pt_PT';
import tr_TR from 'antd/lib/locale/tr_TR';
import { omit } from 'lodash';
import moment from 'moment';
import PropTypes from 'prop-types';
import { withTheme } from 'styled-components';
// import pt_BR from 'antd/lib/locale/pt_BR';
import el_GR from 'antd/lib/locale/el_GR';
import nl_NL from 'antd/lib/locale/nl_NL';
// import nl_BE from 'antd/lib/locale/nl_BE';
import pl_PL from 'antd/lib/locale/pl_PL';
import bg_BG from 'antd/lib/locale/bg_BG';
import da_DK from 'antd/lib/locale/da_DK';
import fi_FI from 'antd/lib/locale/fi_FI';
// import no_NO from 'antd/lib/locale/no_NO'; There's no such translation on antd
import sl_SI from 'antd/lib/locale/sl_SI';
import sv_SE from 'antd/lib/locale/sv_SE';
import zh_CN from 'antd/lib/locale/zh_CN';
import {
DropdownDatePickerStyles,
StyledAntdDatePicker,
StyledAntdRangePicker,
} from '../styles/components/StyledAntdPicker';
import defaultTheme from '../styles/theme';
import {
currentMonth,
DATE_RANGE,
last28Days,
last7Days,
lastMonth,
previousYear,
today,
yearToDate,
yesterday,
} from '../utils/dates';
import Icon from './Icon';

// i18n
const getLocale = language => {
switch (language) {
case 'ca':
return ca_ES;
case 'de':
return de_DE;
case 'es':
return es_ES;
case 'fr':
return fr_FR;
case 'it':
return it_IT;
case 'pt':
return pt_PT;
case 'tr':
return tr_TR;
case 'el':
return el_GR;
case 'nl':
return nl_NL;
case 'pl':
return pl_PL;
case 'bg':
return bg_BG;
case 'da':
return da_DK;
case 'fi':
return fi_FI;
case 'sl':
return sl_SI;
case 'sv':
return sv_SE;
case 'zh':
return zh_CN;
case 'en':
default:
return en_US;
}
};

// Ranges
export const withDatePickerFormat = (start, end) => [start, end];
const custom = () => withDatePickerFormat(null, null);
export const datePickerRange = (range, parser = date => date) => {
if (range === DATE_RANGE.TODAY) return today(parser);
if (range === DATE_RANGE.YESTERDAY) return yesterday(parser);
if (range === DATE_RANGE.LAST_7_DAYS) return last7Days(parser);
if (range === DATE_RANGE.LAST_28_DAYS) return last28Days(parser);
if (range === DATE_RANGE.CURRENET_MONTH) return currentMonth(parser);
if (range === DATE_RANGE.LAST_MONTH) return lastMonth(parser);
if (range === DATE_RANGE.YEAR_TO_DATE) return yearToDate(parser);
if (range === DATE_RANGE.PREVIOUS_YEAR) return previousYear(parser);
if (range === DATE_RANGE.CUSTOM) return custom();
return null;
};
const DATEPICKER_PICKER = [null, 'week', 'month', 'year'];
const TYPE_PICKER = ['date', 'range'];

const AntdDatePicker = props => {
const { dataId } = props;

return (
<StyledAntdDatePicker
data-id={dataId}
nextIcon={<Icon name="chevron_right_l" size={10} color="gray600" />}
prevIcon={<Icon name="chevron_left_l" size={10} color="gray600" />}
suffixIcon={<Icon name="calendar_blank" size={18} color="gray600" />}
{...props}
/>
);
};

const AntdRangePicker = props => {
const [rangesValue, setRangesValue] = useState({});
const { autoFocus, dataId, defaultValue, placeholder, ranges } = props; // Antd Props

const {
// stateDateWrapper, // Unused --> If changes to date wants to be applied, use custom onChange function or format prop
periodOptions,
startDatePlaceholderText,
endDatePlaceholderText,
// periodDefault, // Unused --> There's no select element anymore
// periodLabel, // Unused --> There's no select element anymore
initialStartDate,
initialEndDate,
onDatesChange,
} = props; // Legacy Props

const antdRangePickerProps = omit(props, [
'autoFocusEndDate',
'startDatePlaceholderText',
'endDatePlaceholderText',
'periodOptions',
'periodDefault',
'initialStartDate',
'initialEndDate',
'onDatesChange',
]);

// Load ranges and parse old presets to ranges
useEffect(() => {
if (ranges !== undefined && ranges !== null) {
setRangesValue(ranges);
} else if (periodOptions !== undefined && periodOptions !== null) {
const rangesParsed = {};
periodOptions.forEach(option => {
const label = option.label;
rangesParsed[label] = datePickerRange(
option.value,
withDatePickerFormat
);
});
setRangesValue(rangesParsed);
}
}, [ranges, periodOptions]);

// Populate initial date periods to defaultPeriod
const defaultValuePeriod =
initialStartDate || initialEndDate
? [initialStartDate, initialEndDate]
: defaultValue;

return (
<StyledAntdRangePicker
autoFocus={autoFocus}
defaultValue={defaultValuePeriod}
ranges={rangesValue}
onChange={onDatesChange}
placeholder={
startDatePlaceholderText || endDatePlaceholderText
? [startDatePlaceholderText, endDatePlaceholderText]
: placeholder
}
data-id={dataId}
separator={<Icon name="arrow_right" size={18} color="gray600" />}
suffixIcon={<Icon name="calendar_range" size={18} color="gray600" />}
{...antdRangePickerProps}
/>
);
};

const AntdPicker = props => {
const antdPickerProps = omit(props, ['type']);
const antdDatePickerProps = omit(antdPickerProps, [
'language',
'autoFocusEndDate',
'periodOptions',
'periodDefault',
'initialStartDate',
'initialEndDate',
'onDatesChange',
]);
const { theme, type, language, locale } = props;

useEffect(() => {
moment.locale(language);
}, [language]);

return (
<>
<ConfigProvider
locale={
(String(language).length === 2 && getLocale(language)) || locale
}
>
<DropdownDatePickerStyles theme={theme} />
{type === 'range' ||
props.autoFocusEndDate ||
props.periodOptions ||
props.periodDefault ||
props.initialStartDate ||
props.initialEndDate ||
props.onDatesChange ? (
<AntdRangePicker data-testid="antd-range-picker" {...props} />
) : (
<AntdDatePicker
data-testid="antd-date-picker"
{...antdDatePickerProps}
/>
)}
</ConfigProvider>
</>
);
};

const defaultProps = {
type: 'date',
theme: defaultTheme,
dataId: 'datepicker',
};
AntdPicker.propTypes = {
/**
* data-id attribute to identfy the element in DOM
*/
dataId: PropTypes.string,
/**
* Format the date of the input
*/
format: PropTypes.string,
/**
* Allowed pickers of AntdPicker
*/
picker: PropTypes.oneOf(DATEPICKER_PICKER),
/**
* JSON object that applies styles to the component
*/
theme: PropTypes.shape({}),
/**
* Allowed types of AntdPicker
*/
type: PropTypes.oneOf(TYPE_PICKER),
/**
* Legacy props from old DatePicker
*/
/**
* The period option default selected, we use a select so please check the <a href="https://dexma.github.io/ui-components/?path=/docs/select--select">Select section</a>
*/
periodOptions: PropTypes.arrayOf(PropTypes.shape({})),
/**
* The period option default selected, we use a select so please check the <a href="https://dexma.github.io/ui-components/?path=/docs/select--select">Select section</a>
*/
periodDefault: PropTypes.objectOf(PropTypes.string),
/**
* The period label we use on the select
*/
periodLabel: PropTypes.string,
};
AntdPicker.defaultProps = defaultProps;

export default withTheme(AntdPicker);
Loading

0 comments on commit cdc0277

Please sign in to comment.