Create BookingTimeInfo component

This commit is contained in:
Jenni Nurmi 2019-09-09 11:35:27 +03:00
parent cca0539c74
commit 4c97c19858
7 changed files with 277 additions and 0 deletions

View file

@ -0,0 +1,14 @@
@import '../../marketplace.css';
.root {
}
.bookingInfo {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.dateSection {
margin-right: 5px;
}

View file

@ -0,0 +1,141 @@
import BookingTimeInfo from './BookingTimeInfo';
import {
fakeIntl,
createBooking,
createTransaction,
createUser,
createListing,
} from '../../util/test-data';
import { LINE_ITEM_DAY, LINE_ITEM_NIGHT, LINE_ITEM_UNITS } from '../../util/types';
export const DateAndTimeSingleDay = {
component: BookingTimeInfo,
props: {
isOrder: true,
intl: fakeIntl,
tx: createTransaction({
customer: createUser('user1'),
provider: createUser('user2'),
listing: createListing('Listing'),
booking: createBooking('example-booking', {
displayStart: new Date(Date.UTC(2019, 8, 30, 3, 0)),
displayEnd: new Date(Date.UTC(2019, 8, 30, 4, 0)),
start: new Date(Date.UTC(2019, 8, 30, 3, 0)),
end: new Date(Date.UTC(2019, 8, 30, 4, 0)),
}),
}),
unitType: LINE_ITEM_UNITS,
dateType: 'datetime',
},
group: 'inbox',
};
export const DateAndTimeMultipleDays = {
component: BookingTimeInfo,
props: {
isOrder: true,
intl: fakeIntl,
tx: createTransaction({
customer: createUser('user1'),
provider: createUser('user2'),
listing: createListing('Listing'),
booking: createBooking('example-booking', {
displayStart: new Date(Date.UTC(2019, 8, 28, 3, 0)),
displayEnd: new Date(Date.UTC(2019, 8, 30, 5, 0)),
start: new Date(Date.UTC(2019, 8, 28, 3, 0)),
end: new Date(Date.UTC(2019, 8, 30, 5, 0)),
}),
}),
unitType: LINE_ITEM_UNITS,
dateType: 'datetime',
},
group: 'inbox',
};
export const OnlyDateSingleDay = {
component: BookingTimeInfo,
props: {
isOrder: true,
intl: fakeIntl,
tx: createTransaction({
customer: createUser('user1'),
provider: createUser('user2'),
listing: createListing('Listing'),
booking: createBooking('example-booking', {
displayStart: new Date(Date.UTC(2019, 8, 29, 3, 0)),
displayEnd: new Date(Date.UTC(2019, 8, 30, 4, 0)),
start: new Date(Date.UTC(2019, 8, 29, 3, 0)),
end: new Date(Date.UTC(2019, 8, 30, 4, 0)),
}),
}),
unitType: LINE_ITEM_DAY,
dateType: 'date',
},
group: 'inbox',
};
export const OnlyDateMultipleDays = {
component: BookingTimeInfo,
props: {
isOrder: true,
intl: fakeIntl,
tx: createTransaction({
customer: createUser('user1'),
provider: createUser('user2'),
listing: createListing('Listing'),
booking: createBooking('example-booking', {
displayStart: new Date(Date.UTC(2019, 8, 28, 3, 0)),
displayEnd: new Date(Date.UTC(2019, 8, 30, 5, 0)),
start: new Date(Date.UTC(2019, 8, 28, 3, 0)),
end: new Date(Date.UTC(2019, 8, 30, 5, 0)),
}),
}),
unitType: LINE_ITEM_DAY,
dateType: 'date',
},
group: 'inbox',
};
export const OnlyDateSingleNight = {
component: BookingTimeInfo,
props: {
isOrder: true,
intl: fakeIntl,
tx: createTransaction({
customer: createUser('user1'),
provider: createUser('user2'),
listing: createListing('Listing'),
booking: createBooking('example-booking', {
displayStart: new Date(Date.UTC(2019, 8, 29, 3, 0)),
displayEnd: new Date(Date.UTC(2019, 8, 30, 4, 0)),
start: new Date(Date.UTC(2019, 8, 29, 3, 0)),
end: new Date(Date.UTC(2019, 8, 30, 4, 0)),
}),
}),
unitType: LINE_ITEM_NIGHT,
dateType: 'date',
},
group: 'inbox',
};
export const OnlyDateMultipleNights = {
component: BookingTimeInfo,
props: {
isOrder: true,
intl: fakeIntl,
tx: createTransaction({
customer: createUser('user1'),
provider: createUser('user2'),
listing: createListing('Listing'),
booking: createBooking('example-booking', {
displayStart: new Date(Date.UTC(2019, 8, 28, 3, 0)),
displayEnd: new Date(Date.UTC(2019, 8, 30, 5, 0)),
start: new Date(Date.UTC(2019, 8, 28, 3, 0)),
end: new Date(Date.UTC(2019, 8, 30, 5, 0)),
}),
}),
unitType: LINE_ITEM_NIGHT,
dateType: 'date',
},
group: 'inbox',
};

View file

@ -0,0 +1,98 @@
import React from 'react';
import moment from 'moment';
import { bool, oneOf } from 'prop-types';
import classNames from 'classnames';
import { txIsEnquired } from '../../util/transaction';
import { dateFromAPIToLocalNoon, daysBetween, formatDateToText } from '../../util/dates';
import { injectIntl, intlShape } from '../../util/reactIntl';
import {
LINE_ITEM_DAY,
LINE_ITEM_NIGHT,
LINE_ITEM_UNITS,
DATE_TYPE_DATE,
DATE_TYPE_DATETIME,
propTypes,
} from '../../util/types';
import css from './BookingTimeInfo.css';
const bookingData = (unitType, tx, isOrder, intl) => {
// Attributes: displayStart and displayEnd can be used to differentiate shown time range
// from actual start and end times used for availability reservation. It can help in situations
// where there are preparation time needed between bookings.
// Read more: https://www.sharetribe.com/api-reference/#bookings
const { start, end, displayStart, displayEnd } = tx.booking.attributes;
const startDate = dateFromAPIToLocalNoon(displayStart || start);
const endDateRaw = dateFromAPIToLocalNoon(displayEnd || end);
const isDaily = unitType === LINE_ITEM_DAY;
const isNightly = unitType === LINE_ITEM_NIGHT;
const isUnits = unitType === LINE_ITEM_UNITS;
const isSingleDay = !isNightly && daysBetween(startDate, endDateRaw) <= 1;
const bookingStart = formatDateToText(intl, startDate);
// Shift the exclusive API end date with daily bookings
const endDate =
isDaily || isUnits
? moment(endDateRaw)
.subtract(1, 'days')
.toDate()
: endDateRaw;
const bookingEnd = formatDateToText(intl, endDate);
return { bookingStart, bookingEnd, isSingleDay };
};
const BookingTimeInfoComponent = props => {
const { bookingClassName, isOrder, intl, tx, unitType, dateType } = props;
const isEnquiry = txIsEnquired(tx);
if (isEnquiry) {
return null;
}
const bookingTimes = bookingData(unitType, tx, isOrder, intl);
const { bookingStart, bookingEnd, isSingleDay } = bookingTimes;
if (isSingleDay && dateType === DATE_TYPE_DATE) {
return (
<div className={classNames(css.bookingInfo, bookingClassName)}>
<span className={css.dateSection}>{`${bookingStart.date}`}</span>
</div>
);
} else if (dateType === DATE_TYPE_DATE) {
return (
<div className={classNames(css.bookingInfo, bookingClassName)}>
<span className={css.dateSection}>{`${bookingStart.date} -`}</span>
<span className={css.dateSection}>{`${bookingEnd.date}`}</span>
</div>
);
} else if (isSingleDay && dateType === DATE_TYPE_DATETIME) {
return (
<div className={classNames(css.bookingInfo, bookingClassName)}>
<span className={css.dateSection}>
{`${bookingStart.date}, ${bookingStart.time} - ${bookingEnd.time}`}
</span>
</div>
);
} else {
return (
<div className={classNames(css.bookingInfo, bookingClassName)}>
<span className={css.dateSection}>{`${bookingStart.dateAndTime} - `}</span>
<span className={css.dateSection}>{`${bookingEnd.dateAndTime}`}</span>
</div>
);
}
};
BookingTimeInfoComponent.defaultProps = { dateType: null };
BookingTimeInfoComponent.propTypes = {
intl: intlShape.isRequired,
isOrder: bool.isRequired,
tx: propTypes.transaction.isRequired,
unitType: propTypes.bookingUnitType.isRequired,
dateType: oneOf(DATE_TYPE_DATE, DATE_TYPE_DATETIME),
};
const BookingTimeInfo = injectIntl(BookingTimeInfoComponent);
export default BookingTimeInfo;

View file

@ -116,6 +116,7 @@ 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 BookingTimeInfo } from './BookingTimeInfo/BookingTimeInfo';
export { default as BookingPanel } from './BookingPanel/BookingPanel';
export { default as Discussion } from './Discussion/Discussion';
export { default as FilterPlain } from './FilterPlain/FilterPlain';

View file

@ -5,6 +5,7 @@ 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 BookingTimeInfo from './components/BookingTimeInfo/BookingTimeInfo.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';
@ -101,6 +102,7 @@ export {
BookingBreakdown,
BookingDateRangeFilter,
BookingDatesForm,
BookingTimeInfo,
BookingPanel,
Button,
Colors,

View file

@ -257,3 +257,20 @@ export const getExclusiveEndDate = dateString => {
.startOf('day')
.toDate();
};
export const formatDateToText = (intl, date) => {
return {
date: intl.formatDate(date, {
month: 'short',
day: 'numeric',
}),
time: intl.formatDate(date, {
hour: 'numeric',
minute: 'numeric',
}),
dateAndTime: intl.formatTime(date, {
month: 'short',
day: 'numeric',
}),
};
};

View file

@ -497,3 +497,7 @@ propTypes.error = shape({
});
export { propTypes };
// Options for showing just date or date and time on BookingTimeInfo and BookingBreakdown
export const DATE_TYPE_DATE = 'date';
export const DATE_TYPE_DATETIME = 'datetime';