Skip to content

Commit

Permalink
Merge pull request #1194 from sharetribe/show-time-on-inboxpage
Browse files Browse the repository at this point in the history
Show booking  date and time correctly on InboxPage
  • Loading branch information
OtterleyW authored Sep 10, 2019
2 parents cca0539 + 697003d commit a707c4b
Show file tree
Hide file tree
Showing 11 changed files with 330 additions and 61 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ way to update this template, but currently, we follow a pattern:

## Upcoming version 2019-XX-XX

- [change] Move `BookingTimeInfo` to separate component from `InboxPage`. Add options to show only
booking dates or booking dates and times.
[#1194](https://github.com/sharetribe/flex-template-web/pull/1194)
- [add] Add new Spanish translations related to storing payment card.
[#1193](https://github.com/sharetribe/flex-template-web/pull/1193)
- [fix] Update yarn.lock (there was Lodash version resolution missing)
Expand Down
14 changes: 14 additions & 0 deletions src/components/BookingTimeInfo/BookingTimeInfo.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@import '../../marketplace.css';

.root {
}

.bookingInfo {
display: flex;
align-items: center;
flex-wrap: wrap;
}

.dateSection {
margin-right: 5px;
}
141 changes: 141 additions & 0 deletions src/components/BookingTimeInfo/BookingTimeInfo.example.js
Original file line number Diff line number Diff line change
@@ -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',
};
98 changes: 98 additions & 0 deletions src/components/BookingTimeInfo/BookingTimeInfo.js
Original file line number Diff line number Diff line change
@@ -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;
1 change: 1 addition & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
22 changes: 8 additions & 14 deletions src/containers/InboxPage/InboxPage.css
Original file line number Diff line number Diff line change
Expand Up @@ -273,29 +273,23 @@
}
}

.bookingInfo {
.bookingInfoWrapper {
display: flex;
align-items: center;
flex-wrap: wrap;

font-size: 14px;
line-height: 14px;
margin-top: 3px;
margin-top: 2px;
padding-top: 2px;

@media (--viewportMedium) {
padding-top: 0px;
margin-top: 8px;
line-height: 16px;
}
}

.itemTimestamp {
/* Font */
@apply --marketplaceH5FontStyles;

margin-top: 0px;
margin-bottom: 0px;
@media (--viewportMedium) {
margin-top: 4px;
margin-bottom: 0;
}
}

.itemPrice {
&::before {
font-size: 10px;
Expand Down
Loading

0 comments on commit a707c4b

Please sign in to comment.