mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-29 05:00:43 +10:00
Create BookingDateRangeFilter component
This commit is contained in:
parent
0870f01b13
commit
69631bf5fc
8 changed files with 335 additions and 0 deletions
|
|
@ -0,0 +1,5 @@
|
|||
@import '../../marketplace.css';
|
||||
|
||||
.popupSize {
|
||||
padding: 0 10px 7px 10px;
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
import React from 'react';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { stringify, parse } from '../../util/urlHelpers';
|
||||
import { parseDateFromISO8601, stringifyDateToISO8601 } from '../../util/dates';
|
||||
import BookingDateRangeFilter from './BookingDateRangeFilter';
|
||||
|
||||
const URL_PARAM = 'dates';
|
||||
|
||||
const handleSubmit = (urlParam, values, history) => {
|
||||
const hasDates = values && values.dates;
|
||||
const { startDate, endDate } = hasDates ? values.dates : {};
|
||||
|
||||
const start = startDate ? stringifyDateToISO8601(startDate) : null;
|
||||
const end = endDate ? stringifyDateToISO8601(endDate) : null;
|
||||
|
||||
const queryParams =
|
||||
start != null && end != null ? `?${stringify({ [urlParam]: [start, end].join(',') })}` : '';
|
||||
history.push(`${window.location.pathname}${queryParams}`);
|
||||
};
|
||||
|
||||
const BookingDateRangeFilterWrapper = withRouter(props => {
|
||||
const { history, location } = props;
|
||||
|
||||
const params = parse(location.search);
|
||||
const dates = params[URL_PARAM];
|
||||
const rawValuesFromParams = !!dates ? dates.split(',') : [];
|
||||
const valuesFromParams = rawValuesFromParams.map(v => parseDateFromISO8601(v));
|
||||
const initialValues =
|
||||
!!dates && valuesFromParams.length === 2
|
||||
? {
|
||||
dates: { startDate: valuesFromParams[0], endDate: valuesFromParams[1] },
|
||||
}
|
||||
: { dates: null };
|
||||
|
||||
return (
|
||||
<BookingDateRangeFilter
|
||||
{...props}
|
||||
initialValues={initialValues}
|
||||
onSubmit={(urlParam, values) => {
|
||||
console.log('Submit BookingDateRangeFilter with (unformatted) values:', values);
|
||||
handleSubmit(urlParam, values, history);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export const BookingDateRangeFilterPopup = {
|
||||
component: BookingDateRangeFilterWrapper,
|
||||
props: {
|
||||
id: 'BookingDateRangeFilterPopupExample',
|
||||
urlParam: URL_PARAM,
|
||||
liveEdit: false,
|
||||
showAsPopup: true,
|
||||
contentPlacementOffset: -14,
|
||||
// initialValues: handled inside wrapper
|
||||
// onSubmit: handled inside wrapper
|
||||
},
|
||||
group: 'misc',
|
||||
};
|
||||
|
||||
export const BookingDateRangeFilterPlain = {
|
||||
component: BookingDateRangeFilterWrapper,
|
||||
props: {
|
||||
id: 'BookingDateRangeFilterPlainExample',
|
||||
urlParam: URL_PARAM,
|
||||
liveEdit: true,
|
||||
showAsPopup: false,
|
||||
contentPlacementOffset: -14,
|
||||
// initialValues: handled inside wrapper
|
||||
// onSubmit: handled inside wrapper
|
||||
},
|
||||
group: 'misc',
|
||||
};
|
||||
153
src/components/BookingDateRangeFilter/BookingDateRangeFilter.js
Normal file
153
src/components/BookingDateRangeFilter/BookingDateRangeFilter.js
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
import React, { Component } from 'react';
|
||||
import { bool, func, number, object, string } from 'prop-types';
|
||||
import { injectIntl, intlShape } from 'react-intl';
|
||||
|
||||
import { FieldDateRangeController, FilterPopup, FilterPlain } from '../../components';
|
||||
import css from './BookingDateRangeFilter.css';
|
||||
|
||||
export class BookingDateRangeFilterComponent extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.popupControllerRef = null;
|
||||
this.plainControllerRef = null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
rootClassName,
|
||||
showAsPopup,
|
||||
initialValues: initialValuesRaw,
|
||||
id,
|
||||
contentPlacementOffset,
|
||||
onSubmit,
|
||||
urlParam,
|
||||
intl,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
const isSelected = !!initialValuesRaw && !!initialValuesRaw.dates;
|
||||
const initialValues = isSelected ? initialValuesRaw : { dates: null };
|
||||
|
||||
const startDate = isSelected ? initialValues.dates.startDate : null;
|
||||
const endDate = isSelected ? initialValues.dates.endDate : null;
|
||||
|
||||
const format = {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
};
|
||||
|
||||
const formattedStartDate = isSelected ? intl.formatDate(startDate, format) : null;
|
||||
const formattedEndDate = isSelected ? intl.formatDate(endDate, format) : null;
|
||||
|
||||
const labelForPlain = isSelected
|
||||
? intl.formatMessage(
|
||||
{ id: 'BookingDateRangeFilter.labelSelectedPlain' },
|
||||
{
|
||||
dates: `${formattedStartDate} - ${formattedEndDate}`,
|
||||
}
|
||||
)
|
||||
: intl.formatMessage({ id: 'BookingDateRangeFilter.labelPlain' });
|
||||
|
||||
const labelForPopup = isSelected
|
||||
? intl.formatMessage(
|
||||
{ id: 'BookingDateRangeFilter.labelSelectedPopup' },
|
||||
{
|
||||
dates: `${formattedStartDate} - ${formattedEndDate}`,
|
||||
}
|
||||
)
|
||||
: intl.formatMessage({ id: 'BookingDateRangeFilter.labelPopup' });
|
||||
|
||||
const onClearPopupMaybe =
|
||||
this.popupControllerRef && this.popupControllerRef.onReset
|
||||
? { onClear: () => this.popupControllerRef.onReset(null, null) }
|
||||
: {};
|
||||
|
||||
const onCancelPopupMaybe =
|
||||
this.popupControllerRef && this.popupControllerRef.onReset
|
||||
? { onCancel: () => this.popupControllerRef.onReset(startDate, endDate) }
|
||||
: {};
|
||||
|
||||
const onClearPlainMaybe =
|
||||
this.plainControllerRef && this.plainControllerRef.onReset
|
||||
? { onClear: () => this.plainControllerRef.onReset(null, null) }
|
||||
: {};
|
||||
|
||||
return showAsPopup ? (
|
||||
<FilterPopup
|
||||
className={className}
|
||||
rootClassName={rootClassName}
|
||||
popupClassName={css.popupSize}
|
||||
label={labelForPopup}
|
||||
isSelected={isSelected}
|
||||
id={`${id}.popup`}
|
||||
showAsPopup
|
||||
contentPlacementOffset={contentPlacementOffset}
|
||||
onSubmit={onSubmit}
|
||||
{...onClearPopupMaybe}
|
||||
{...onCancelPopupMaybe}
|
||||
initialValues={initialValues}
|
||||
urlParam={urlParam}
|
||||
{...rest}
|
||||
>
|
||||
<FieldDateRangeController
|
||||
name="dates"
|
||||
controllerRef={node => {
|
||||
this.popupControllerRef = node;
|
||||
}}
|
||||
/>
|
||||
</FilterPopup>
|
||||
) : (
|
||||
<FilterPlain
|
||||
className={className}
|
||||
rootClassName={rootClassName}
|
||||
label={labelForPlain}
|
||||
isSelected={isSelected}
|
||||
id={`${id}.plain`}
|
||||
liveEdit
|
||||
contentPlacementOffset={contentPlacementOffset}
|
||||
onSubmit={onSubmit}
|
||||
{...onClearPlainMaybe}
|
||||
initialValues={initialValues}
|
||||
urlParam={urlParam}
|
||||
{...rest}
|
||||
>
|
||||
<FieldDateRangeController
|
||||
name="dates"
|
||||
controllerRef={node => {
|
||||
this.plainControllerRef = node;
|
||||
}}
|
||||
/>
|
||||
</FilterPlain>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
BookingDateRangeFilterComponent.defaultProps = {
|
||||
rootClassName: null,
|
||||
className: null,
|
||||
showAsPopup: true,
|
||||
liveEdit: false,
|
||||
initialValues: null,
|
||||
contentPlacementOffset: 0,
|
||||
};
|
||||
|
||||
BookingDateRangeFilterComponent.propTypes = {
|
||||
rootClassName: string,
|
||||
className: string,
|
||||
id: string.isRequired,
|
||||
showAsPopup: bool,
|
||||
liveEdit: bool,
|
||||
urlParam: string.isRequired,
|
||||
onSubmit: func.isRequired,
|
||||
initialValues: object,
|
||||
contentPlacementOffset: number,
|
||||
|
||||
// form injectIntl
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
const BookingDateRangeFilter = injectIntl(BookingDateRangeFilterComponent);
|
||||
|
||||
export default BookingDateRangeFilter;
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
import React from 'react';
|
||||
|
||||
// react-dates needs to be initialized before using any react-dates component
|
||||
// Since this is currently only component using react-dates we can do it here
|
||||
// https://github.com/airbnb/react-dates#initialize
|
||||
import 'react-dates/initialize';
|
||||
import { renderShallow } from '../../util/test-helpers';
|
||||
import { fakeIntl } from '../../util/test-data';
|
||||
import { BookingDateRangeFilterComponent } from './BookingDateRangeFilter';
|
||||
|
||||
describe('BookingDateRangeFilter', () => {
|
||||
it('matches popup snapshot', () => {
|
||||
const tree = renderShallow(
|
||||
<BookingDateRangeFilterComponent
|
||||
id="BookingDateRangeFilter"
|
||||
urlParam="dates"
|
||||
liveEdit={false}
|
||||
showAsPopup={true}
|
||||
contentPlacementOffset={-14}
|
||||
initialValues={{}}
|
||||
onSubmit={() => null}
|
||||
intl={fakeIntl}
|
||||
/>
|
||||
);
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('matches plain snapshot', () => {
|
||||
const tree = renderShallow(
|
||||
<BookingDateRangeFilterComponent
|
||||
id="BookingDateRangeFilter"
|
||||
urlParam="dates"
|
||||
liveEdit={true}
|
||||
showAsPopup={false}
|
||||
contentPlacementOffset={-14}
|
||||
initialValues={{}}
|
||||
onSubmit={() => null}
|
||||
intl={fakeIntl}
|
||||
/>
|
||||
);
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`BookingDateRangeFilter matches plain snapshot 1`] = `
|
||||
<InjectIntl(FilterPlainComponent)
|
||||
className={null}
|
||||
contentPlacementOffset={-14}
|
||||
id="BookingDateRangeFilter.plain"
|
||||
initialValues={
|
||||
Object {
|
||||
"dates": null,
|
||||
}
|
||||
}
|
||||
isSelected={false}
|
||||
label="BookingDateRangeFilter.labelPlain"
|
||||
liveEdit={true}
|
||||
onSubmit={[Function]}
|
||||
rootClassName={null}
|
||||
urlParam="dates"
|
||||
>
|
||||
<FieldDateRangeController
|
||||
className={null}
|
||||
controllerRef={[Function]}
|
||||
name="dates"
|
||||
rootClassName={null}
|
||||
/>
|
||||
</InjectIntl(FilterPlainComponent)>
|
||||
`;
|
||||
|
||||
exports[`BookingDateRangeFilter matches popup snapshot 1`] = `
|
||||
<InjectIntl(FilterPopup)
|
||||
className={null}
|
||||
contentPlacementOffset={-14}
|
||||
id="BookingDateRangeFilter.popup"
|
||||
initialValues={
|
||||
Object {
|
||||
"dates": null,
|
||||
}
|
||||
}
|
||||
isSelected={false}
|
||||
label="BookingDateRangeFilter.labelPopup"
|
||||
liveEdit={false}
|
||||
onSubmit={[Function]}
|
||||
rootClassName={null}
|
||||
showAsPopup={true}
|
||||
urlParam="dates"
|
||||
>
|
||||
<FieldDateRangeController
|
||||
className={null}
|
||||
controllerRef={[Function]}
|
||||
name="dates"
|
||||
rootClassName={null}
|
||||
/>
|
||||
</InjectIntl(FilterPopup)>
|
||||
`;
|
||||
|
|
@ -2,6 +2,7 @@ export { default as ActivityFeed } from './ActivityFeed/ActivityFeed';
|
|||
export { default as AddImages } from './AddImages/AddImages';
|
||||
export { default as Avatar, AvatarMedium, AvatarLarge } from './Avatar/Avatar';
|
||||
export { default as BookingBreakdown } from './BookingBreakdown/BookingBreakdown';
|
||||
export { default as BookingDateRangeFilter } from './BookingDateRangeFilter/BookingDateRangeFilter';
|
||||
export { default as Button, PrimaryButton, SecondaryButton, InlineTextButton } from './Button/Button';
|
||||
export { default as BookingPanel } from './BookingPanel/BookingPanel';
|
||||
export { default as CookieConsent } from './CookieConsent/CookieConsent';
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import * as AddImages from './components/AddImages/AddImages.example';
|
|||
import * as Avatar from './components/Avatar/Avatar.example';
|
||||
import * as BookingBreakdown from './components/BookingBreakdown/BookingBreakdown.example';
|
||||
import * as BookingPanel from './components/BookingPanel/BookingPanel.example';
|
||||
import * as BookingDateRangeFilter from './components/BookingDateRangeFilter/BookingDateRangeFilter.example';
|
||||
import * as Button from './components/Button/Button.example';
|
||||
import * as ExpandingTextarea from './components/ExpandingTextarea/ExpandingTextarea.example';
|
||||
import * as FieldBirthdayInput from './components/FieldBirthdayInput/FieldBirthdayInput.example';
|
||||
|
|
@ -94,6 +95,7 @@ export {
|
|||
AddImages,
|
||||
Avatar,
|
||||
BookingBreakdown,
|
||||
BookingDateRangeFilter,
|
||||
BookingDatesForm,
|
||||
BookingPanel,
|
||||
Button,
|
||||
|
|
|
|||
|
|
@ -67,6 +67,10 @@
|
|||
"BookingDatesForm.requiredDate": "Oops, make sure your date is correct!",
|
||||
"BookingDatesForm.timeSlotsError": "Loading listing availability failed. Please refresh the page.",
|
||||
"BookingDatesForm.youWontBeChargedInfo": "You won't be charged yet",
|
||||
"BookingDateRangeFilter.labelPlain": "Dates",
|
||||
"BookingDateRangeFilter.labelPopup": "Dates",
|
||||
"BookingDateRangeFilter.labelSelectedPlain": "{dates}",
|
||||
"BookingDateRangeFilter.labelSelectedPopup": "{dates}",
|
||||
"BookingPanel.closedListingButtonText": "Sorry, this listing has been closed.",
|
||||
"BookingPanel.ctaButtonMessage": "Request to book",
|
||||
"BookingPanel.hostedBy": "Hosted by {name}",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue