mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-26 06:47:17 +10:00
309 lines
9.7 KiB
JavaScript
309 lines
9.7 KiB
JavaScript
import pick from 'lodash/pick';
|
|
import config from '../../config';
|
|
import { denormalisedResponseEntities } from '../../util/data';
|
|
import { storableError } from '../../util/errors';
|
|
import {
|
|
TRANSITION_REQUEST_PAYMENT,
|
|
TRANSITION_REQUEST_PAYMENT_AFTER_ENQUIRY,
|
|
TRANSITION_CONFIRM_PAYMENT,
|
|
} from '../../util/transaction';
|
|
import * as log from '../../util/log';
|
|
import { fetchCurrentUserHasOrdersSuccess, fetchCurrentUser } from '../../ducks/user.duck';
|
|
|
|
// ================ Action types ================ //
|
|
|
|
export const SET_INITAL_VALUES = 'app/CheckoutPage/SET_INITIAL_VALUES';
|
|
|
|
export const INITIATE_ORDER_REQUEST = 'app/CheckoutPage/INITIATE_ORDER_REQUEST';
|
|
export const INITIATE_ORDER_SUCCESS = 'app/CheckoutPage/INITIATE_ORDER_SUCCESS';
|
|
export const INITIATE_ORDER_ERROR = 'app/CheckoutPage/INITIATE_ORDER_ERROR';
|
|
|
|
export const CONFIRM_PAYMENT_REQUEST = 'app/CheckoutPage/CONFIRM_PAYMENT_REQUEST';
|
|
export const CONFIRM_PAYMENT_SUCCESS = 'app/CheckoutPage/CONFIRM_PAYMENT_SUCCESS';
|
|
export const CONFIRM_PAYMENT_ERROR = 'app/CheckoutPage/CONFIRM_PAYMENT_ERROR';
|
|
|
|
export const SPECULATE_TRANSACTION_REQUEST = 'app/ListingPage/SPECULATE_TRANSACTION_REQUEST';
|
|
export const SPECULATE_TRANSACTION_SUCCESS = 'app/ListingPage/SPECULATE_TRANSACTION_SUCCESS';
|
|
export const SPECULATE_TRANSACTION_ERROR = 'app/ListingPage/SPECULATE_TRANSACTION_ERROR';
|
|
|
|
export const STRIPE_CUSTOMER_REQUEST = 'app/CheckoutPage/STRIPE_CUSTOMER_REQUEST';
|
|
export const STRIPE_CUSTOMER_SUCCESS = 'app/CheckoutPage/STRIPE_CUSTOMER_SUCCESS';
|
|
export const STRIPE_CUSTOMER_ERROR = 'app/CheckoutPage/STRIPE_CUSTOMER_ERROR';
|
|
|
|
// ================ Reducer ================ //
|
|
|
|
const initialState = {
|
|
listing: null,
|
|
bookingData: null,
|
|
bookingDates: null,
|
|
speculateTransactionInProgress: false,
|
|
speculateTransactionError: null,
|
|
speculatedTransaction: null,
|
|
transaction: null,
|
|
initiateOrderError: null,
|
|
confirmPaymentError: null,
|
|
stripeCustomerFetched: false,
|
|
};
|
|
|
|
export default function checkoutPageReducer(state = initialState, action = {}) {
|
|
const { type, payload } = action;
|
|
switch (type) {
|
|
case SET_INITAL_VALUES:
|
|
return { ...initialState, ...payload };
|
|
|
|
case SPECULATE_TRANSACTION_REQUEST:
|
|
return {
|
|
...state,
|
|
speculateTransactionInProgress: true,
|
|
speculateTransactionError: null,
|
|
speculatedTransaction: null,
|
|
};
|
|
case SPECULATE_TRANSACTION_SUCCESS:
|
|
return {
|
|
...state,
|
|
speculateTransactionInProgress: false,
|
|
speculatedTransaction: payload.transaction,
|
|
};
|
|
case SPECULATE_TRANSACTION_ERROR:
|
|
console.error(payload); // eslint-disable-line no-console
|
|
return {
|
|
...state,
|
|
speculateTransactionInProgress: false,
|
|
speculateTransactionError: payload,
|
|
};
|
|
|
|
case INITIATE_ORDER_REQUEST:
|
|
return { ...state, initiateOrderError: null };
|
|
case INITIATE_ORDER_SUCCESS:
|
|
return { ...state, transaction: payload };
|
|
case INITIATE_ORDER_ERROR:
|
|
console.error(payload); // eslint-disable-line no-console
|
|
return { ...state, initiateOrderError: payload };
|
|
|
|
case CONFIRM_PAYMENT_REQUEST:
|
|
return { ...state, confirmPaymentError: null };
|
|
case CONFIRM_PAYMENT_SUCCESS:
|
|
return state;
|
|
case CONFIRM_PAYMENT_ERROR:
|
|
console.error(payload); // eslint-disable-line no-console
|
|
return { ...state, confirmPaymentError: payload };
|
|
|
|
case STRIPE_CUSTOMER_REQUEST:
|
|
return { ...state, stripeCustomerFetched: false };
|
|
case STRIPE_CUSTOMER_SUCCESS:
|
|
return { ...state, stripeCustomerFetched: true };
|
|
case STRIPE_CUSTOMER_ERROR:
|
|
console.error(payload); // eslint-disable-line no-console
|
|
return { ...state, stripeCustomerFetchError: payload };
|
|
|
|
default:
|
|
return state;
|
|
}
|
|
}
|
|
|
|
// ================ Selectors ================ //
|
|
|
|
// ================ Action creators ================ //
|
|
|
|
export const setInitialValues = initialValues => ({
|
|
type: SET_INITAL_VALUES,
|
|
payload: pick(initialValues, Object.keys(initialState)),
|
|
});
|
|
|
|
const initiateOrderRequest = () => ({ type: INITIATE_ORDER_REQUEST });
|
|
|
|
const initiateOrderSuccess = order => ({
|
|
type: INITIATE_ORDER_SUCCESS,
|
|
payload: order,
|
|
});
|
|
|
|
const initiateOrderError = e => ({
|
|
type: INITIATE_ORDER_ERROR,
|
|
error: true,
|
|
payload: e,
|
|
});
|
|
|
|
const confirmPaymentRequest = () => ({ type: CONFIRM_PAYMENT_REQUEST });
|
|
|
|
const confirmPaymentSuccess = orderId => ({
|
|
type: CONFIRM_PAYMENT_SUCCESS,
|
|
payload: orderId,
|
|
});
|
|
|
|
const confirmPaymentError = e => ({
|
|
type: CONFIRM_PAYMENT_ERROR,
|
|
error: true,
|
|
payload: e,
|
|
});
|
|
|
|
export const speculateTransactionRequest = () => ({ type: SPECULATE_TRANSACTION_REQUEST });
|
|
|
|
export const speculateTransactionSuccess = transaction => ({
|
|
type: SPECULATE_TRANSACTION_SUCCESS,
|
|
payload: { transaction },
|
|
});
|
|
|
|
export const speculateTransactionError = e => ({
|
|
type: SPECULATE_TRANSACTION_ERROR,
|
|
error: true,
|
|
payload: e,
|
|
});
|
|
|
|
export const stripeCustomerRequest = () => ({ type: STRIPE_CUSTOMER_REQUEST });
|
|
export const stripeCustomerSuccess = () => ({ type: STRIPE_CUSTOMER_SUCCESS });
|
|
export const stripeCustomerError = e => ({
|
|
type: STRIPE_CUSTOMER_ERROR,
|
|
error: true,
|
|
payload: e,
|
|
});
|
|
|
|
/* ================ Thunks ================ */
|
|
|
|
export const initiateOrder = (orderParams, transactionId) => (dispatch, getState, sdk) => {
|
|
dispatch(initiateOrderRequest());
|
|
const bodyParams = transactionId
|
|
? {
|
|
id: transactionId,
|
|
transition: TRANSITION_REQUEST_PAYMENT_AFTER_ENQUIRY,
|
|
params: orderParams,
|
|
}
|
|
: {
|
|
processAlias: config.bookingProcessAlias,
|
|
transition: TRANSITION_REQUEST_PAYMENT,
|
|
params: orderParams,
|
|
};
|
|
const queryParams = {
|
|
include: ['booking', 'provider'],
|
|
expand: true,
|
|
};
|
|
|
|
const createOrder = transactionId ? sdk.transactions.transition : sdk.transactions.initiate;
|
|
|
|
return createOrder(bodyParams, queryParams)
|
|
.then(response => {
|
|
const entities = denormalisedResponseEntities(response);
|
|
const order = entities[0];
|
|
dispatch(initiateOrderSuccess(order));
|
|
dispatch(fetchCurrentUserHasOrdersSuccess(true));
|
|
return order;
|
|
})
|
|
.catch(e => {
|
|
dispatch(initiateOrderError(storableError(e)));
|
|
const transactionIdMaybe = transactionId ? { transactionId: transactionId.uuid } : {};
|
|
log.error(e, 'initiate-order-failed', {
|
|
...transactionIdMaybe,
|
|
listingId: orderParams.listingId.uuid,
|
|
bookingStart: orderParams.bookingStart,
|
|
bookingEnd: orderParams.bookingEnd,
|
|
});
|
|
throw e;
|
|
});
|
|
};
|
|
|
|
export const confirmPayment = orderParams => (dispatch, getState, sdk) => {
|
|
dispatch(confirmPaymentRequest());
|
|
|
|
const bodyParams = {
|
|
id: orderParams.transactionId,
|
|
transition: TRANSITION_CONFIRM_PAYMENT,
|
|
params: {},
|
|
};
|
|
|
|
return sdk.transactions
|
|
.transition(bodyParams)
|
|
.then(response => {
|
|
const order = response.data.data;
|
|
dispatch(confirmPaymentSuccess(order.id));
|
|
return order;
|
|
})
|
|
.catch(e => {
|
|
dispatch(confirmPaymentError(storableError(e)));
|
|
const transactionIdMaybe = orderParams.transactionId
|
|
? { transactionId: orderParams.transactionId.uuid }
|
|
: {};
|
|
log.error(e, 'initiate-order-failed', {
|
|
...transactionIdMaybe,
|
|
});
|
|
throw e;
|
|
});
|
|
};
|
|
|
|
export const sendMessage = params => (dispatch, getState, sdk) => {
|
|
const message = params.message;
|
|
const orderId = params.id;
|
|
|
|
if (message) {
|
|
return sdk.messages
|
|
.send({ transactionId: orderId, content: message })
|
|
.then(() => {
|
|
return { orderId, messageSuccess: true };
|
|
})
|
|
.catch(e => {
|
|
log.error(e, 'initial-message-send-failed', { txId: orderId });
|
|
return { orderId, messageSuccess: false };
|
|
});
|
|
} else {
|
|
return Promise.resolve({ orderId, messageSuccess: true });
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Initiate the speculative transaction with the given booking details
|
|
*
|
|
* The API allows us to do speculative transaction initiation and
|
|
* transitions. This way we can create a test transaction and get the
|
|
* actual pricing information as if the transaction had been started,
|
|
* without affecting the actual data.
|
|
*
|
|
* We store this speculative transaction in the page store and use the
|
|
* pricing info for the booking breakdown to get a proper estimate for
|
|
* the price with the chosen information.
|
|
*/
|
|
export const speculateTransaction = params => (dispatch, getState, sdk) => {
|
|
dispatch(speculateTransactionRequest());
|
|
const bodyParams = {
|
|
transition: TRANSITION_REQUEST_PAYMENT,
|
|
processAlias: config.bookingProcessAlias,
|
|
params: {
|
|
...params,
|
|
cardToken: 'CheckoutPage_speculative_card_token',
|
|
},
|
|
};
|
|
const queryParams = {
|
|
include: ['booking', 'provider'],
|
|
expand: true,
|
|
};
|
|
return sdk.transactions
|
|
.initiateSpeculative(bodyParams, queryParams)
|
|
.then(response => {
|
|
const entities = denormalisedResponseEntities(response);
|
|
if (entities.length !== 1) {
|
|
throw new Error('Expected a resource in the sdk.transactions.initiateSpeculative response');
|
|
}
|
|
const tx = entities[0];
|
|
dispatch(speculateTransactionSuccess(tx));
|
|
})
|
|
.catch(e => {
|
|
const { listingId, bookingStart, bookingEnd } = params;
|
|
log.error(e, 'speculate-transaction-failed', {
|
|
listingId: listingId.uuid,
|
|
bookingStart,
|
|
bookingEnd,
|
|
});
|
|
return dispatch(speculateTransactionError(storableError(e)));
|
|
});
|
|
};
|
|
|
|
// StripeCustomer is a relantionship to currentUser
|
|
// We need to fetch currentUser with correct params to include relationship
|
|
export const stripeCustomer = () => (dispatch, getState, sdk) => {
|
|
dispatch(stripeCustomerRequest());
|
|
|
|
return dispatch(fetchCurrentUser({ include: ['stripeCustomer.defaultPaymentMethod'] }))
|
|
.then(response => {
|
|
dispatch(stripeCustomerSuccess());
|
|
})
|
|
.catch(e => {
|
|
dispatch(stripeCustomerError(storableError(e)));
|
|
});
|
|
};
|