@blocklet/payment-react
Version:
Reusable react components for payment kit v2
169 lines (168 loc) • 5.45 kB
JavaScript
import { jsx } from "react/jsx-runtime";
import { Alert } from "@mui/material";
import { useLocalStorageState, useRequest } from "ahooks";
import { createContext, useContext, useEffect, useState } from "react";
import axios from "axios";
import { joinURL } from "ufo";
import api from "../libs/api.js";
import { getPrefix, PAYMENT_KIT_DID } from "../libs/util.js";
import { CachedRequest } from "../libs/cached-request.js";
const formatData = (data) => {
if (!data) {
return {
paymentMethods: [],
baseCurrency: {}
};
}
return {
...data,
paymentMethods: data.paymentMethods || [],
baseCurrency: data.baseCurrency || {}
};
};
const PaymentContext = createContext({ api });
const { Provider, Consumer } = PaymentContext;
const getSettings = (forceRefresh = false) => {
const livemode = localStorage.getItem("livemode") !== "false";
const cacheKey = `payment-settings-${window.location.pathname}-${livemode}`;
const cachedRequest = new CachedRequest(cacheKey, () => api.get("/api/settings", { params: { livemode } }));
return cachedRequest.fetch(forceRefresh);
};
const getCurrency = (currencyId, methods) => {
const currencies = methods.reduce((acc, x) => acc.concat(x.payment_currencies), []);
return currencies.find((x) => x.id === currencyId);
};
const getMethod = (methodId, methods) => {
return methods.find((x) => x.id === methodId);
};
const syncToSpaceRequest = (userDid, spaceDid) => {
const cacheKey = `sync-space-${userDid}-${spaceDid}`;
const cachedRequest = new CachedRequest(cacheKey, () => api.post("/api/customers/sync-to-space"), {
ttl: 1e3 * 60 * 60
// 1 hour
});
return cachedRequest.fetch(false).then((res) => {
if (!res.success) {
cachedRequest.clearCache();
}
return res;
});
};
function PaymentProvider({
session,
connect,
children,
baseUrl = void 0,
authToken = void 0
}) {
const [crossOriginLoading, setCrossOriginLoading] = useState(false);
if (authToken) {
window.__PAYMENT_KIT_AUTH_TOKEN = authToken;
} else {
window.__PAYMENT_KIT_AUTH_TOKEN = "";
}
useEffect(() => {
const fetchCrossOriginBlockletInfo = async () => {
if (!baseUrl) {
window.__PAYMENT_KIT_BASE_URL = "";
setCrossOriginLoading(false);
return;
}
const tmp = new URL(baseUrl);
if (tmp.origin === window.location.origin) {
window.__PAYMENT_KIT_BASE_URL = "";
setCrossOriginLoading(false);
return;
}
setCrossOriginLoading(true);
try {
const scriptUrl = joinURL(tmp.origin, "__blocklet__.js?type=json");
const cacheKey = `cross-origin-blocklet-${tmp.origin}`;
const cachedRequest = new CachedRequest(
cacheKey,
() => axios.get(scriptUrl).then((res) => ({ data: res.data })),
{
strategy: "session",
ttl: 10 * 60 * 1e3
// 10 minutes TTL
}
);
const blockletInfo = await cachedRequest.fetch();
const componentId = (blockletInfo?.componentId || "").split("/").pop();
if (componentId === PAYMENT_KIT_DID) {
window.__PAYMENT_KIT_BASE_URL = joinURL(tmp.origin, blockletInfo.prefix || "/");
} else {
const component = (blockletInfo?.componentMountPoints || []).find((x) => x?.did === PAYMENT_KIT_DID);
window.__PAYMENT_KIT_BASE_URL = component ? joinURL(tmp.origin, component.mountPoint) : baseUrl;
}
} catch (err) {
console.warn(`Failed to fetch blocklet json from ${baseUrl}:`, err);
window.__PAYMENT_KIT_BASE_URL = baseUrl;
} finally {
setCrossOriginLoading(false);
}
};
fetchCrossOriginBlockletInfo();
}, [baseUrl]);
const [livemode, setLivemode] = useLocalStorageState("livemode", { defaultValue: true });
const {
data = {
paymentMethods: [],
baseCurrency: {}
},
error,
run,
loading
} = useRequest(getSettings, {
refreshDeps: [livemode]
});
useEffect(() => {
const didSpace = session?.user?.didSpace;
const userDid = session?.user?.did;
if (userDid && didSpace && didSpace.endpoint && didSpace.did) {
syncToSpaceRequest(userDid, didSpace.did);
}
}, [session?.user]);
const prefix = getPrefix();
const [payable, setPayable] = useState(true);
const [paymentState, setPaymentState] = useState({
paying: false,
stripePaying: false
});
const updatePaymentState = (state) => {
setPaymentState((prev) => ({ ...prev, ...state }));
};
if (error) {
return /* @__PURE__ */ jsx(Alert, { severity: "error", children: error.message });
}
if (loading || crossOriginLoading) {
return null;
}
return /* @__PURE__ */ jsx(
Provider,
{
value: {
session,
connect,
prefix,
livemode: !!livemode,
settings: formatData(data),
getCurrency: (currencyId) => getCurrency(currencyId, data?.paymentMethods || []),
getMethod: (methodId) => getMethod(methodId, data?.paymentMethods || []),
refresh: run,
setLivemode,
api,
payable,
setPayable,
paymentState,
setPaymentState: updatePaymentState
},
children
}
);
}
function usePaymentContext() {
const context = useContext(PaymentContext);
return context;
}
export { PaymentContext, PaymentProvider, Consumer as SettingsConsumer, usePaymentContext };