mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-26 06:47:17 +10:00
148 lines
4.8 KiB
JavaScript
148 lines
4.8 KiB
JavaScript
/**
|
|
* Booking breakdown estimation
|
|
*
|
|
* Transactions have payment information that can be shown with the
|
|
* BookingBreakdown component. However, when selecting booking
|
|
* details, there is no transaction object present and we have to
|
|
* estimate the breakdown of the transaction without data from the
|
|
* API.
|
|
*
|
|
* If the payment process of a customized marketplace is something
|
|
* else than simply daily or nightly bookings, the estimation will
|
|
* most likely need some changes.
|
|
*
|
|
* To customize the estimation, first change the BookingDatesForm to
|
|
* collect all booking information from the user (in addition to the
|
|
* default date pickers), and provide that data to the
|
|
* EstimatedBreakdownMaybe components. You can then make customization
|
|
* within this file to create a fake transaction object that
|
|
* calculates the breakdown information correctly according to the
|
|
* process.
|
|
*
|
|
* In the future, the optimal scenario would be to use the same
|
|
* transactions.initiateSpeculative API endpoint as the CheckoutPage
|
|
* is using to get the breakdown information from the API, but
|
|
* currently the API doesn't support that for logged out users, and we
|
|
* are forced to estimate the information here.
|
|
*/
|
|
import React from 'react';
|
|
import moment from 'moment';
|
|
import Decimal from 'decimal.js';
|
|
import { types as sdkTypes } from '../../util/sdkLoader';
|
|
import { dateFromLocalToAPI, nightsBetween, daysBetween } from '../../util/dates';
|
|
import {
|
|
LINE_ITEM_DAY,
|
|
LINE_ITEM_NIGHT,
|
|
LINE_ITEM_UNITS,
|
|
TRANSITION_REQUEST,
|
|
TX_TRANSITION_ACTOR_CUSTOMER,
|
|
} from '../../util/types';
|
|
import { unitDivisor, convertMoneyToNumber, convertUnitToSubUnit } from '../../util/currency';
|
|
import { BookingBreakdown } from '../../components';
|
|
|
|
import css from './BookingDatesForm.css';
|
|
|
|
const { Money, UUID } = sdkTypes;
|
|
|
|
const estimatedTotalPrice = (unitPrice, unitCount) => {
|
|
const numericPrice = convertMoneyToNumber(unitPrice);
|
|
const numericTotalPrice = new Decimal(numericPrice).times(unitCount).toNumber();
|
|
return new Money(
|
|
convertUnitToSubUnit(numericTotalPrice, unitDivisor(unitPrice.currency)),
|
|
unitPrice.currency
|
|
);
|
|
};
|
|
|
|
// When we cannot speculatively initiate a transaction (i.e. logged
|
|
// out), we must estimate the booking breakdown. This function creates
|
|
// an estimated transaction object for that use case.
|
|
const estimatedTransaction = (unitType, bookingStart, bookingEnd, unitPrice, quantity) => {
|
|
const now = new Date();
|
|
const isNightly = unitType === LINE_ITEM_NIGHT;
|
|
const isDaily = unitType === LINE_ITEM_DAY;
|
|
|
|
const unitCount = isNightly
|
|
? nightsBetween(bookingStart, bookingEnd)
|
|
: isDaily
|
|
? daysBetween(bookingStart, bookingEnd)
|
|
: quantity;
|
|
|
|
const totalPrice = estimatedTotalPrice(unitPrice, unitCount);
|
|
|
|
// bookingStart: "Fri Mar 30 2018 12:00:00 GMT-1100 (SST)" aka "Fri Mar 30 2018 23:00:00 GMT+0000 (UTC)"
|
|
// Server normalizes night/day bookings to start from 00:00 UTC aka "Thu Mar 29 2018 13:00:00 GMT-1100 (SST)"
|
|
// The result is: local timestamp.subtract(12h).add(timezoneoffset) (in eg. -23 h)
|
|
|
|
// local noon -> startOf('day') => 00:00 local => remove timezoneoffset => 00:00 API (UTC)
|
|
const serverDayStart = dateFromLocalToAPI(
|
|
moment(bookingStart)
|
|
.startOf('day')
|
|
.toDate()
|
|
);
|
|
const serverDayEnd = dateFromLocalToAPI(
|
|
moment(bookingEnd)
|
|
.startOf('day')
|
|
.toDate()
|
|
);
|
|
|
|
return {
|
|
id: new UUID('estimated-transaction'),
|
|
type: 'transaction',
|
|
attributes: {
|
|
createdAt: now,
|
|
lastTransitionedAt: now,
|
|
lastTransition: TRANSITION_REQUEST,
|
|
payinTotal: totalPrice,
|
|
payoutTotal: totalPrice,
|
|
lineItems: [
|
|
{
|
|
code: unitType,
|
|
includeFor: ['customer', 'provider'],
|
|
unitPrice: unitPrice,
|
|
quantity: new Decimal(unitCount),
|
|
lineTotal: totalPrice,
|
|
reversal: false,
|
|
},
|
|
],
|
|
transitions: [
|
|
{
|
|
createdAt: now,
|
|
by: TX_TRANSITION_ACTOR_CUSTOMER,
|
|
transition: TRANSITION_REQUEST,
|
|
},
|
|
],
|
|
},
|
|
booking: {
|
|
id: new UUID('estimated-booking'),
|
|
type: 'booking',
|
|
attributes: {
|
|
start: serverDayStart,
|
|
end: serverDayEnd,
|
|
},
|
|
},
|
|
};
|
|
};
|
|
|
|
const EstimatedBreakdownMaybe = props => {
|
|
const { unitType, unitPrice, startDate, endDate, quantity } = props.bookingData;
|
|
const isUnits = unitType === LINE_ITEM_UNITS;
|
|
const quantityIfUsingUnits = !isUnits || Number.isInteger(quantity);
|
|
const canEstimatePrice = startDate && endDate && unitPrice && quantityIfUsingUnits;
|
|
if (!canEstimatePrice) {
|
|
return null;
|
|
}
|
|
|
|
const tx = estimatedTransaction(unitType, startDate, endDate, unitPrice, quantity);
|
|
|
|
return (
|
|
<BookingBreakdown
|
|
className={css.receipt}
|
|
userRole="customer"
|
|
unitType={unitType}
|
|
transaction={tx}
|
|
booking={tx.booking}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export default EstimatedBreakdownMaybe;
|