occsn-checkout
Version:
Occasion checkout experience boilerplate component built using React-Redux and Mitragyna
193 lines (162 loc) • 6.1 kB
JSX
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import _ from 'underscore';
import { Row, Col } from 'reactstrap';
import { Resource } from 'mitragyna';
import * as appActions from '../actions/appActions';
import * as calendarActions from '../actions/calendarActions';
import occsn from '../libs/Occasion';
import TimeSlotsSelector from '../components/TimeSlotsSelector.jsx';
import Calendar from '../components/TimeSlots/Calendar.jsx';
import Paginator from '../components/TimeSlots/Paginator.jsx';
// Which part of the Redux global state does our component want to receive as props?
function stateToProps(state) {
return {
data: {
product: state.$$appStore.get('product'),
activeTimeSlotsCollection: state.$$calendarStore.get('activeTimeSlotsCollection'),
timeSlotsFromCalendar: state.$$calendarStore.get('timeSlotsFromCalendar'),
}
};
}
// Bind relevant action creators and map them to properties
function dispatchToProps(dispatch) {
return {
actions: {
loadProductCalendar: (product) => dispatch(calendarActions.loadProductCalendar(product)),
loadProductTimeSlots: (product) => dispatch(calendarActions.loadProductTimeSlots(product)),
saveOrder: (order) => dispatch(appActions.saveOrder(order)),
setOrder: (order) => dispatch(appActions.setOrder(order)),
setActiveTimeSlotsCollection: (timeSlots) => dispatch(calendarActions.setActiveTimeSlotsCollection(timeSlots)),
setTimeSlotsFromCalendar: (timeSlots) => dispatch(calendarActions.setTimeSlotsFromCalendar(timeSlots)),
}
};
}
export class TimeSlotsContainer extends React.Component {
static propTypes = {
actions: PropTypes.object.isRequired,
data: PropTypes.object.isRequired,
order: PropTypes.instanceOf(occsn.Order),
onSelect: PropTypes.func,
};
static contextTypes = {
callbackProps: PropTypes.object,
componentProps: PropTypes.object,
};
constructor() {
super();
_.bindAll(this,
'onDateSelect',
'onTimeSelect',
);
}
componentDidMount() {
const { actions, data, order } = this.props;
switch(data.product.timeSlotView) {
case 'calendar':
actions.loadProductCalendar(data.product);
break;
case 'list':
if(data.product.requiresTimeSlotSelection) actions.loadProductTimeSlots(data.product);
break;
}
if(data.product.sellsSessions) {
actions.setActiveTimeSlotsCollection(order.timeSlots().target().clone())
}
}
onDateSelect(timeSlotsFromCalendar) {
const { actions } = this.props;
const { callbackProps } = this.context;
if(callbackProps.onDateSelect) callbackProps.onDateSelect(timeSlotsFromCalendar);
actions.setTimeSlotsFromCalendar(timeSlotsFromCalendar);
}
onTimeSelect(order) {
const { actions } = this.props;
const { callbackProps } = this.context;
if(callbackProps.onTimeSelect) callbackProps.onTimeSelect(order);
actions.setOrder(order);
actions.saveOrder(order);
}
render() {
const { data } = this.props;
return <section className="time-slots">
{
data.activeTimeSlotsCollection.empty() ? (
this.renderLoadingScreen()
) : (
this.renderTimeSlotsScreen()
)
}
</section>;
}
renderLoadingScreen() {
const { componentProps } = this.context;
var loadingComponent;
if(componentProps.timeSlotsLoading) {
loadingComponent = React.createElement(componentProps.timeSlotsLoading);
}
return <section className="time-slots-loading">
{loadingComponent}
</section>;
}
renderTimeSlotsScreen() {
const { actions, data, order } = this.props;
switch(data.product.timeSlotView) {
case 'calendar':
return <section className="calendar-view">
<Row>
<Col xs="9">
<h3>{ data.activeTimeSlotsCollection.first().day.format('MMMM YYYY') }</h3>
</Col>
<Col xs="3">
<Paginator className="float-right" onChange={actions.setActiveTimeSlotsCollection} timeSlotsCollection={data.activeTimeSlotsCollection} />
</Col>
</Row>
<Calendar onDateSelect={this.onDateSelect} calendarTimeSlots={data.activeTimeSlotsCollection}/>
<a name="time-slots-selector" id="time-slots-selector-anchor"></a>
{
data.timeSlotsFromCalendar.first() ? (
<h3 className="calendar-date-selected">{data.timeSlotsFromCalendar.first().startsAt.format('dddd, MMMM Do')}</h3>
) : null
}
<TimeSlotsSelector
calendar={true}
onSelect={this.onTimeSelect}
showAvailability={data.product.showOccurrenceAvailability}
subject={order}
timeSlots={data.timeSlotsFromCalendar}
/>
</section>;
case 'list':
return <section className="list-view">
{
data.product.sellsSessions ? (
<p>Sessions are purchased together</p>
) : (null)
}
<a name="time-slots-selector" id="time-slots-selector-anchor"></a>
<TimeSlotsSelector
disabled={data.product.sellsSessions}
onSelect={this.onTimeSelect}
showAvailability={data.product.showOccurrenceAvailability}
subject={order}
timeSlots={data.activeTimeSlotsCollection}
/>
{
!data.product.sellsSessions ? (
<Row>
<Col xs={{ offset: "9" }}>
</Col>
<Col xs="3">
<Paginator className="float-right" onChange={actions.setActiveTimeSlotsCollection} timeSlotsCollection={data.activeTimeSlotsCollection} />
</Col>
</Row>
) : (null)
}
</section>;
}
}
}
// See https://github.com/reactjs/react-redux/blob/master/docs/api.md#examples
export default connect(stateToProps, dispatchToProps)(TimeSlotsContainer);