@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
JavaScript
;
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;