mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-30 18:16:48 +10:00
Save CheckoutPage data to sessionStore
This commit is contained in:
parent
f899a51472
commit
cecae6b23e
1 changed files with 105 additions and 6 deletions
|
|
@ -3,6 +3,9 @@ import { compose } from 'redux';
|
|||
import { connect } from 'react-redux';
|
||||
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { reduce } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { types } from '../../util/sdkLoader';
|
||||
import { pathByRouteName } from '../../util/routes';
|
||||
import * as propTypes from '../../util/propTypes';
|
||||
import { withFlattenedRoutes } from '../../util/contextHelpers';
|
||||
|
|
@ -18,9 +21,102 @@ const ensureListingProperties = listing => {
|
|||
return { ...empty, ...listing };
|
||||
};
|
||||
|
||||
// Validate that given 'obj' has all the keys of defined by validPropTypes parameter
|
||||
// and values must pass related test-value-format function.
|
||||
const validateProperties = (obj, validPropTypes) => {
|
||||
return reduce(
|
||||
Object.entries(validPropTypes),
|
||||
(acc, [prop, fn]) => {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, prop) && fn(obj[prop])) {
|
||||
return acc;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
true
|
||||
);
|
||||
};
|
||||
|
||||
// Validate content of booking dates object received from SessionStore
|
||||
const isValidBookingDates = bookingDates => {
|
||||
const props = {
|
||||
bookingStart: d => d instanceof Date,
|
||||
bookingEnd: d => d instanceof Date,
|
||||
};
|
||||
return validateProperties(bookingDates, props);
|
||||
};
|
||||
|
||||
// Validate content of listing object received from SessionStore.
|
||||
// Currently only id & attributes.price are needed.
|
||||
const isValidListing = listing => {
|
||||
const props = {
|
||||
id: id => id instanceof types.UUID,
|
||||
attributes: v => {
|
||||
return typeof v === 'object' && v.price instanceof types.Money;
|
||||
},
|
||||
};
|
||||
return validateProperties(listing, props);
|
||||
};
|
||||
|
||||
// Stores given bookingDates and listing to sessionStorage
|
||||
const storeData = (bookingDates, listing) => {
|
||||
if (window && window.sessionStorage && listing && bookingDates) {
|
||||
// TODO: How should we deal with Dates when data is serialized?
|
||||
// Hard coded serializable date objects atm.
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
const data = {
|
||||
bookingDates: {
|
||||
bookingStart: { date: bookingDates.bookingStart, _serializedType: 'SerializableDate' },
|
||||
bookingEnd: { date: bookingDates.bookingEnd, _serializedType: 'SerializableDate' },
|
||||
},
|
||||
listing,
|
||||
storedAt: { date: new Date(), _serializedType: 'SerializableDate' },
|
||||
};
|
||||
/* eslint-enable no-underscore-dangle */
|
||||
|
||||
const storableData = JSON.stringify(data, types.replacer);
|
||||
window.sessionStorage.setItem('CheckoutPage', storableData);
|
||||
}
|
||||
};
|
||||
|
||||
// Get stored data
|
||||
const storedData = () => {
|
||||
if (window && window.sessionStorage) {
|
||||
const checkoutPageData = window.sessionStorage.getItem('CheckoutPage');
|
||||
|
||||
// TODO How should we deal with Dates when data is serialized?
|
||||
// Dates are expected to be in format: { date: new Date(), _serializedType: 'SerializableDate' }
|
||||
const reviver = (k, v) => {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
if (typeof v === 'object' && v._serializedType === 'SerializableDate') {
|
||||
return new Date(v.date);
|
||||
}
|
||||
return types.reviver(k, v);
|
||||
};
|
||||
|
||||
const { bookingDates, listing, storedAt } = checkoutPageData
|
||||
? JSON.parse(checkoutPageData, reviver)
|
||||
: {};
|
||||
|
||||
// If sessionStore contains freshly saved data (max 1 day old), use it
|
||||
const isFreshlySaved = storedAt
|
||||
? moment(storedAt).isAfter(moment().subtract(1, 'days'))
|
||||
: false;
|
||||
|
||||
if (isFreshlySaved && isValidBookingDates(bookingDates) && isValidListing(listing)) {
|
||||
return { bookingDates, listing };
|
||||
}
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
export class CheckoutPageComponent extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { bookingDates, listing } = props;
|
||||
|
||||
// Store received data
|
||||
storeData(bookingDates, listing);
|
||||
|
||||
this.state = { submitting: false };
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
}
|
||||
|
|
@ -48,20 +144,23 @@ export class CheckoutPageComponent extends Component {
|
|||
|
||||
render() {
|
||||
const { bookingDates, initiateOrderError, intl, listing, params, currentUser } = this.props;
|
||||
const { bookingStart, bookingEnd } = bookingDates || {};
|
||||
const currentListing = ensureListingProperties(listing);
|
||||
|
||||
// Get page data from passed-in props or from storage
|
||||
const pageData = bookingDates && listing ? { bookingDates, listing } : storedData();
|
||||
const { bookingStart, bookingEnd } = pageData.bookingDates || {};
|
||||
const currentListing = ensureListingProperties(pageData.listing);
|
||||
const price = currentListing.attributes.price;
|
||||
|
||||
const isOwnListing = listing &&
|
||||
const isOwnListing = currentListing &&
|
||||
currentUser &&
|
||||
listing.author &&
|
||||
listing.author.id.uuid === currentUser.id.uuid;
|
||||
currentListing.author &&
|
||||
currentListing.author.id.uuid === currentUser.id.uuid;
|
||||
|
||||
// Allow showing page when currentUser is still being downloaded,
|
||||
// but show payment form only when user info is loaded.
|
||||
const showPaymentForm = currentUser && !isOwnListing;
|
||||
|
||||
if (!listing || !price || isOwnListing) {
|
||||
if (!currentListing.id || !price || isOwnListing) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(
|
||||
'Listing, price, or user invalid for checkout, redirecting back to listing page.'
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue