import React, {useState, useEffect, useRef} from "react";
import {Text} from "components/elementsThemed";
import {withErrorBoundary} from "components/hocs";
import {useMutationObserver} from "hooks";
import Axios from "axios";
import {constants} from "utils";
import Lbc from "@lunchboxinc/lunchbox-components";
import Fallback from "./Fallback";
import css from "./beamImpact.module.scss";
const {BEAM_BASE_URL} = constants;
const {Row} = Lbc.Grid;
const POST_TRANSACTION_URL = `${BEAM_BASE_URL}/api/v1/nonprofits/transaction/`;
const Step = {
POST_CHECKOUT: "post-checkout",
PRE_CHECKOUT: "pre-checkout",
};
/**
* Helper method for postTransaction
*
* @param {string} widgetId
* @param {object} data
*/
const POST_BEAM_TRANSACTION = (widgetId, data) => {
return Axios.post(POST_TRANSACTION_URL, data, {
headers: {
"X-WIDGET-ID": widgetId,
},
}).then(
(response) => response,
(error) => console.error(error),
);
};
/**
* Post method for posting Beam transaction data
*
* @param {object} beam
* @param
* @param selectedNonprofit
*/
const postTransaction = async (beam, selectedNonprofit) => {
const {store, cart_total, user, nonprofit} = beam?.widget?.transactionData;
const {widgetId} = beam?.widget?.options;
let data;
if (nonprofit) {
data = {
cart_total,
nonprofit,
store,
user,
};
} else {
data = {
cart_total,
nonprofit: selectedNonprofit,
store,
user,
};
}
if (nonprofit || selectedNonprofit)
await POST_BEAM_TRANSACTION(widgetId, data);
};
/**
* Component for Beam Nonprofit widget
*
* @author Htin Linn Aung
* @memberof Fragments.Fragments/Beam
* @param {object} props
* @param {object} props.style - From theme file & withTemplate HOC
* @param {string} props.widgetColors - From BeamImpact component
* @param {string} props.widgetId - Provided by Beam. It is in config
* @param {string} props.patronEmail - From BeamImpact component
* @param {number} props.cartTotal - From BeamImpact component
* @param {string} props.step - Checkout Step
* @param {object} props.beam - State in pages/Cart/routes.jsx
* @param {Function} props.setBeam - Setter method for state in pages/Cart/routes.jsx
* @param {Fuction} props.onSkipBeamSelection - Alternate Func to bring the user to Routes.PURCHASE_COMPLETE - from home.jsx
* @returns {React.Element} - Component for Beam Nonprofit widget
*/
const BeamNonProfit = ({
style,
widgetColors,
widgetId,
patronEmail,
cartTotal,
step,
beam,
setBeam,
onSkipBeamSelection,
}) => {
const {labels} = style;
const {
explainerTextColor,
defaultExplainerTextColor,
descriptionTextColor,
impactProgressBarColor,
baseWarningTextColor,
} = widgetColors;
const explainerColor = explainerTextColor || defaultExplainerTextColor;
const [beamAppsLoading, setBeamAppsLoading] = useState(false);
const [widgetLoading, setWidgetLoading] = useState(false);
const isPreCheckout = step === Step.PRE_CHECKOUT;
const beamWidget = useRef(null);
const getArgs = () => ({
cartTotal,
user: patronEmail,
});
useEffect(() => {
if (!widgetId) {
console.error("[Beam Impact] Widget ID is required.");
return;
}
setBeamAppsLoading(true);
setWidgetLoading(true);
const initializeWidget = async () => {
// Need to add mechanism to handle duplicate instantiation
const widget = new window.beamApps.NonprofitWidget({
containerId: "beam-widget-container",
forceMobileView: "true",
isPreCheckout,
loadingScreenContent: "",
textColor: explainerColor,
themeConfig: {
changeButtonColor: baseWarningTextColor,
descriptionBackgroundColor: explainerColor,
descriptionTextColor,
goalTextColor: explainerColor,
id: "lunchbox-nonprofit",
progressBarColors: [
{
color: impactProgressBarColor,
offset: "100%",
},
],
selectedNonprofitCallback: (nonprofit) => {
if (step === Step.PRE_CHECKOUT) widget.render(getArgs());
else {
postTransaction(beam, nonprofit?.id);
onSkipBeamSelection();
}
},
textColor: explainerColor,
},
widgetId,
});
await widget.render(getArgs());
beamWidget.current = widget;
await setBeam({
postTransaction,
widget,
});
};
if (window.beamApps) {
setBeamAppsLoading(false);
initializeWidget();
}
}, [beamAppsLoading, window.beamApps]);
useMutationObserver(() => setWidgetLoading(false), {
attributes: true,
selector: "#beam-widget-container",
});
switch (step) {
case Step.PRE_CHECKOUT:
return <div id="beam-widget-container" />;
default:
return (
<>
<div id="beam-widget-container">
{widgetLoading && (
<div className={css.content}>
<Row spacing={10}>
<Text type={labels.primary}>Thank you for your order!</Text>
</Row>
</div>
)}
</div>
</>
);
}
};
export default withErrorBoundary(BeamNonProfit, Fallback);