UNPKG

@open-tender/cloud

Version:

A library of hooks, reducers, utility functions, and types for use with Open Tender applications that utilize our cloud-based Order API.

330 lines (329 loc) 14.1 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.checkoutReducer = exports.selectDiscounts = exports.selectCompletedOrder = exports.selectCheck = exports.selectCheckout = exports.setRecaptchaToken = exports.updateCheckoutCustomer = exports.setSubmitting = exports.setGuest = exports.setCompletedOrder = exports.resetTip = exports.resetErrors = exports.resetCompletedOrder = exports.resetCheck = exports.resetCheckout = exports.submitOrderPay = exports.updateForm = exports.submitOrder = exports.validateOrder = exports.CheckoutActionType = void 0; const tslib_1 = require("tslib"); const toolkit_1 = require("@reduxjs/toolkit"); const utils_1 = require("@open-tender/utils"); const types_1 = require("./types"); const customer_1 = require("./customer"); const menu_1 = require("./menu"); const order_1 = require("./order"); const initialState = { check: null, form: { address: {}, customer: {}, details: {}, discounts: [], points: [], promoCodes: [], surcharges: [], tenders: [], tip: null, token: null }, submitting: false, isGuest: false, completedOrder: null, errors: {}, loading: 'idle' }; var CheckoutActionType; (function (CheckoutActionType) { CheckoutActionType["ValidateOrder"] = "checkout/validateOrder"; CheckoutActionType["SubmitOrder"] = "checkout/SubmitOrder"; CheckoutActionType["SubmitOrderPay"] = "checkout/SubmitOrderPay"; CheckoutActionType["UpdateForm"] = "checkout/updateForm"; })(CheckoutActionType = exports.CheckoutActionType || (exports.CheckoutActionType = {})); const assembleOrder = (orderData, save = false) => { const { order, checkout, groupOrder } = orderData; const { orderId, revenueCenter, serviceType, requestedAt, cart, deviceType, prepType, table } = order; const { revenue_center_id: revenueCenterId } = revenueCenter || {}; if (!revenueCenterId || !serviceType || !requestedAt || !cart) return null; const { form, check } = checkout; const { customer, address, details, surcharges, discounts, promoCodes, points, tenders, tip, token, kount_device_session_id } = form; const { deposit = null } = check || {}; // const defaultTip = check ? getDefaultTip(check.config) : null const hasTip = check === null || check === void 0 ? void 0 : check.config.gratuity.has_tip; const fullAddress = Object.assign(Object.assign({}, order.address), address); // eslint-disable-next-line @typescript-eslint/no-unused-vars const { customer_id } = customer, customerWithoutId = tslib_1.__rest(customer, ["customer_id"]); const data = { address: (0, utils_1.isEmpty)(fullAddress) ? null : fullAddress, cart: cart, cartId: groupOrder.cartId || null, customer: customerWithoutId, deposit, details, deviceType, discounts, orderId, points, prepType, promoCodes, requestedAt, revenueCenterId, serviceType, surcharges, table, tenders, tip: hasTip ? tip : null, save, token, kount_device_session_id }; return (0, utils_1.prepareOrder)(data); }; const refreshKeys = ['revenue_center_id', 'service_type', 'requested_at']; const makeRefreshArgs = (order) => ({ revenueCenterId: order.revenue_center_id, serviceType: order.service_type, requestedAt: order.requested_at }); const handleOrderErrors = (err, preparedOrder, dispatch) => { const errors = (0, utils_1.handleCheckoutError)(err); const keys = Object.keys(errors); const args = makeRefreshArgs(preparedOrder); if ((0, utils_1.contains)(keys, refreshKeys)) { dispatch((0, order_1.refreshRevenueCenter)(args)); return {}; } else if ((0, utils_1.contains)(keys, ['cart'])) { const cartError = errors.cart; if ((0, utils_1.isString)(cartError)) { dispatch((0, menu_1.fetchMenu)(args)); } else { const alert = { type: 'cartCounts', args: { errors: cartError } }; setTimeout(() => { dispatch((0, order_1.setAlert)(alert)); }, 500); } return {}; } else { return errors; } }; exports.validateOrder = (0, toolkit_1.createAsyncThunk)(CheckoutActionType.ValidateOrder, (order, { dispatch, getState, rejectWithValue }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { try { const { api } = getState().config; const token = (0, customer_1.selectToken)(getState()); if (!order) order = assembleOrder(getState()); const errors = {}; if (!order) { errors.form = 'Empty cart. Please return to menu.'; return { check: null, errors }; } const check = yield api.postOrderValidate(order, token); const checkError = (0, utils_1.makeCheckError)(check.errors); const errMessages = (0, utils_1.handleCheckoutError)(checkError); const keys = Object.keys(errMessages); const args = makeRefreshArgs(order); if ((0, utils_1.contains)(keys, refreshKeys)) { dispatch((0, order_1.refreshRevenueCenter)(args)); } else if ((0, utils_1.contains)(keys, ['cart'])) { const cartError = errMessages.cart; if ((0, utils_1.isString)(cartError)) { dispatch((0, menu_1.fetchMenu)(args)); } else { const alert = { type: 'cartCounts', args: { errors: cartError } }; dispatch((0, order_1.setAlert)(alert)); } } else if ((0, utils_1.contains)(keys, ['promo_codes'])) { errors['promo_codes'] = errMessages.promo_codes; } else if ((0, utils_1.contains)(keys, ['customer'])) { errors['customer'] = errMessages.customer; } return { check, errors }; } catch (err) { const errors = (0, utils_1.makeFormErrorsNested)(err); return rejectWithValue(errors); } })); exports.submitOrder = (0, toolkit_1.createAsyncThunk)(CheckoutActionType.SubmitOrder, (args, { dispatch, getState, rejectWithValue }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { const { api } = getState().config; if (!api) return; const token = (0, customer_1.selectToken)(getState()); const alert = { type: 'working', args: { text: 'Submitting your order...' } }; dispatch((0, order_1.setAlert)(alert)); const { save = false } = args || {}; const preparedOrder = assembleOrder(getState(), save); if (!preparedOrder) { return dispatch((0, order_1.setAlert)({ type: 'close' })); } try { const completedOrder = yield api.postOrder(preparedOrder, token); const auth = getState().customer.account.auth; const { email, password } = preparedOrder.customer || {}; if (password && !auth) { yield dispatch((0, customer_1.loginCustomer)({ email: email, password })); } dispatch((0, order_1.setAlert)({ type: 'close' })); return completedOrder; } catch (err) { dispatch((0, order_1.setAlert)({ type: 'close' })); const errors = handleOrderErrors(err, preparedOrder, dispatch); return rejectWithValue(errors); } })); exports.updateForm = (0, toolkit_1.createAsyncThunk)(CheckoutActionType.UpdateForm, (payload, { getState }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { var _b; const { checkout } = getState(); const errors = Object.assign({}, checkout.errors); const { tenders } = payload; const hasTip = (_b = checkout.check) === null || _b === void 0 ? void 0 : _b.config.gratuity.has_tip; if (tenders) delete errors.tenders; const form = Object.assign(Object.assign(Object.assign({}, checkout.form), payload), (!hasTip && { tip: null })); return { form, errors }; })); exports.submitOrderPay = (0, toolkit_1.createAsyncThunk)(CheckoutActionType.SubmitOrderPay, (showAlert = false, { dispatch, getState, rejectWithValue }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { const { api } = getState().config; if (!api) return; const token = (0, customer_1.selectToken)(getState()); dispatch((0, exports.setSubmitting)(true)); if (showAlert || false) { const alert = { type: 'working', args: { text: 'Submitting your order...' } }; dispatch((0, order_1.setAlert)(alert)); } const preparedOrder = assembleOrder(getState()); if (!preparedOrder) { return dispatch((0, order_1.setAlert)({ type: 'close' })); } try { const completedOrder = yield api.postOrder(preparedOrder, token); const auth = getState().customer.account.auth; const { email, password } = preparedOrder.customer || {}; if (password && !auth) { yield dispatch((0, customer_1.loginCustomer)({ email: email, password })); } dispatch((0, order_1.setAlert)({ type: 'close' })); return completedOrder; } catch (err) { dispatch((0, order_1.setAlert)({ type: 'close' })); const errors = handleOrderErrors(err, preparedOrder, dispatch); return rejectWithValue(errors); } })); const checkoutSlice = (0, toolkit_1.createSlice)({ name: types_1.ReducerType.Checkout, initialState, reducers: { resetCheckout: () => initialState, resetCheck: state => { state.check = null; }, resetTip: state => { state.form = Object.assign(Object.assign({}, state.form), { tip: null }); }, resetErrors: state => { state.errors = {}; }, resetCompletedOrder: state => { state.completedOrder = null; }, setCompletedOrder: (state, action) => { state.completedOrder = action.payload; }, setSubmitting: (state, action) => { state.submitting = action.payload; }, setGuest: (state, action) => { state.isGuest = action.payload; }, setRecaptchaToken: (state, action) => { state.form.token = action.payload; }, updateCheckoutCustomer: (state, action) => { const account = action.payload; const customer = Object.assign({}, state.form.customer); const customerId = customer ? customer.customer_id : null; let form = Object.assign({}, state.form); if (!account) { if (customerId) { form = Object.assign(Object.assign({}, form), { customer: {}, promoCodes: [], discounts: [], tenders: [] }); } else { form = Object.assign(Object.assign({}, form), { customer: {}, promoCodes: [] }); } } else if (customerId && account.customer_id !== customerId) { form = Object.assign(Object.assign({}, form), { customer, discounts: [], tenders: [] }); } else if (account && !customerId) { form = Object.assign(Object.assign({}, form), { customer: account, discounts: [], tenders: [] }); } state.form = Object.assign({}, form); } }, extraReducers: builder => { builder .addCase(exports.validateOrder.fulfilled, (state, action) => { return Object.assign(Object.assign(Object.assign({}, state), action.payload), { loading: 'idle', error: null }); }) .addCase(exports.validateOrder.pending, state => { state.loading = 'pending'; }) .addCase(exports.validateOrder.rejected, (state, action) => { state.errors = action.payload || {}; state.loading = 'idle'; }) .addCase(exports.updateForm.fulfilled, (state, action) => { return Object.assign(Object.assign({}, state), action.payload); }) .addCase(exports.submitOrder.fulfilled, (_, action) => { return Object.assign(Object.assign({}, initialState), { completedOrder: action.payload }); }) .addCase(exports.submitOrder.pending, state => { state.loading = 'pending'; }) .addCase(exports.submitOrder.rejected, (state, action) => { state.loading = 'idle'; state.submitting = false; state.errors = action.payload || {}; }) .addCase(exports.submitOrderPay.fulfilled, (_, action) => { return Object.assign(Object.assign({}, initialState), { completedOrder: action.payload }); }) .addCase(exports.submitOrderPay.pending, state => { state.loading = 'pending'; }) .addCase(exports.submitOrderPay.rejected, (state, action) => { state.loading = 'idle'; state.submitting = false; state.errors = action.payload || {}; }); } }); _a = checkoutSlice.actions, exports.resetCheckout = _a.resetCheckout, exports.resetCheck = _a.resetCheck, exports.resetCompletedOrder = _a.resetCompletedOrder, exports.resetErrors = _a.resetErrors, exports.resetTip = _a.resetTip, exports.setCompletedOrder = _a.setCompletedOrder, exports.setGuest = _a.setGuest, exports.setSubmitting = _a.setSubmitting, exports.updateCheckoutCustomer = _a.updateCheckoutCustomer, exports.setRecaptchaToken = _a.setRecaptchaToken; const selectCheckout = (state) => state.checkout; exports.selectCheckout = selectCheckout; const selectCheck = (state) => state.checkout.check; exports.selectCheck = selectCheck; const selectCompletedOrder = (state) => state.checkout.completedOrder; exports.selectCompletedOrder = selectCompletedOrder; const selectDiscounts = (state) => state.checkout.form.discounts; exports.selectDiscounts = selectDiscounts; exports.checkoutReducer = checkoutSlice.reducer;