@blocklet/payment-react
Version:
Reusable react components for payment kit v2
1,298 lines (1,297 loc) • 42 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PAYMENT_KIT_DID = void 0;
exports.findCurrency = findCurrency;
exports.flattenPaymentMethods = void 0;
exports.formatAmount = formatAmount;
exports.formatAmountPrecisionLimit = formatAmountPrecisionLimit;
exports.formatBNStr = formatBNStr;
exports.formatCheckoutHeadlines = formatCheckoutHeadlines;
exports.formatCouponTerms = void 0;
exports.formatDateTime = formatDateTime;
exports.formatError = void 0;
exports.formatLineItemPricing = formatLineItemPricing;
exports.formatLinkWithLocale = formatLinkWithLocale;
exports.formatLocale = void 0;
exports.formatMeteredThen = formatMeteredThen;
exports.formatNumber = formatNumber;
exports.formatPriceAmount = exports.formatPrice = exports.formatPrettyMsLocale = void 0;
exports.formatPriceDisplay = formatPriceDisplay;
exports.formatQuantityInventory = formatQuantityInventory;
exports.formatRecurring = formatRecurring;
exports.formatSubscriptionProduct = formatSubscriptionProduct;
exports.formatSubscriptionStatus = formatSubscriptionStatus;
exports.formatTime = formatTime;
exports.formatToDate = formatToDate;
exports.formatToDatetime = formatToDatetime;
exports.formatTotalPrice = formatTotalPrice;
exports.formatUpsellSaving = formatUpsellSaving;
exports.getCheckoutAmount = getCheckoutAmount;
exports.getCustomerAvatar = getCustomerAvatar;
exports.getFreeTrialTime = getFreeTrialTime;
exports.getInvoiceDescriptionAndReason = getInvoiceDescriptionAndReason;
exports.getInvoiceStatusColor = getInvoiceStatusColor;
exports.getLineTimeInfo = void 0;
exports.getPaymentIntentStatusColor = getPaymentIntentStatusColor;
exports.getPaymentKitComponent = getPaymentKitComponent;
exports.getPayoutStatusColor = getPayoutStatusColor;
exports.getPrefix = void 0;
exports.getPriceCurrencyOptions = getPriceCurrencyOptions;
exports.getPriceUintAmountByCurrency = getPriceUintAmountByCurrency;
exports.getQueryParams = getQueryParams;
exports.getRecurringPeriod = getRecurringPeriod;
exports.getRefundStatusColor = getRefundStatusColor;
exports.getStatementDescriptor = getStatementDescriptor;
exports.getSubscriptionAction = void 0;
exports.getSubscriptionStatusColor = getSubscriptionStatusColor;
exports.getSubscriptionTimeSummary = void 0;
exports.getTokenBalanceLink = getTokenBalanceLink;
exports.getTxLink = void 0;
exports.getUserProfileLink = getUserProfileLink;
exports.getWebhookStatusColor = getWebhookStatusColor;
exports.getWordBreakStyle = getWordBreakStyle;
exports.hasDelegateTxHash = hasDelegateTxHash;
exports.hasMultipleRecurringIntervals = hasMultipleRecurringIntervals;
exports.isCreditMetered = isCreditMetered;
exports.isCrossOrigin = isCrossOrigin;
exports.isMobileSafari = isMobileSafari;
exports.isPaymentKitMounted = void 0;
exports.isValidCountry = isValidCountry;
exports.lazyLoad = lazyLoad;
exports.mergeExtraParams = void 0;
exports.openDonationSettings = openDonationSettings;
exports.parseMarkedText = parseMarkedText;
exports.showStaking = showStaking;
exports.sleep = sleep;
exports.stopEvent = stopEvent;
exports.truncateText = truncateText;
var _util = require("@ocap/util");
var _omit = _interopRequireDefault(require("lodash/omit"));
var _trimEnd = _interopRequireDefault(require("lodash/trimEnd"));
var _numbro = _interopRequireDefault(require("numbro"));
var _stringWidth = _interopRequireDefault(require("string-width"));
var _reactInternationalPhone = require("react-international-phone");
var _ufo = require("ufo");
var _locales = require("../locales");
var _dayjs = _interopRequireDefault(require("./dayjs"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const PAYMENT_KIT_DID = exports.PAYMENT_KIT_DID = "z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk";
const formatCouponTerms = (coupon, currency, locale = "en") => {
let couponOff = "";
if (coupon.percent_off && coupon.percent_off > 0) {
couponOff = (0, _locales.t)("payment.checkout.coupon.percentage", locale, {
percent: coupon.percent_off
});
}
if (coupon.amount_off && coupon.amount_off !== "0") {
const {
symbol
} = currency;
couponOff = coupon.currency_id === currency.id ? coupon.amount_off || "" : coupon.currency_options?.[currency.id]?.amount_off || "";
if (couponOff) {
couponOff = (0, _locales.t)("payment.checkout.coupon.fixedAmount", locale, {
amount: formatAmount(couponOff, currency.decimal),
symbol
});
}
}
if (!couponOff) {
return (0, _locales.t)("payment.checkout.coupon.noDiscount");
}
return (0, _locales.t)(`payment.checkout.coupon.terms.${coupon.duration}`, locale, {
couponOff,
months: coupon.duration_in_months || 0
});
};
exports.formatCouponTerms = formatCouponTerms;
const isPaymentKitMounted = () => {
return (window.blocklet?.componentMountPoints || []).some(x => x.did === PAYMENT_KIT_DID);
};
exports.isPaymentKitMounted = isPaymentKitMounted;
const getPrefix = () => {
const prefix = window.blocklet?.prefix || "/";
const baseUrl = window.location?.origin;
if (window.__PAYMENT_KIT_BASE_URL) {
try {
const tmp = new URL(window.__PAYMENT_KIT_BASE_URL);
if (tmp.origin !== window.location.origin) {
return window.__PAYMENT_KIT_BASE_URL;
}
} catch (err) {
console.warn("Invalid baseUrl for PaymentProvider", window.__PAYMENT_KIT_BASE_URL);
}
}
const componentId = (window.blocklet?.componentId || "").split("/").pop();
if (componentId === PAYMENT_KIT_DID) {
return (0, _ufo.joinURL)(baseUrl, prefix);
}
const component = (window.blocklet?.componentMountPoints || []).find(x => x?.did === PAYMENT_KIT_DID);
if (component) {
return (0, _ufo.joinURL)(baseUrl, component.mountPoint);
}
return (0, _ufo.joinURL)(baseUrl, prefix);
};
exports.getPrefix = getPrefix;
function isCrossOrigin() {
try {
const prefix = getPrefix();
const prefixOrigin = new URL(prefix).origin;
const currentOrigin = window.location.origin;
return prefixOrigin !== currentOrigin;
} catch (error) {
return false;
}
}
function formatToDate(date, locale = "en", format = "YYYY-MM-DD HH:mm:ss") {
if (!date) {
return "-";
}
return (0, _dayjs.default)(date).locale(formatLocale(locale)).format(format);
}
function formatToDatetime(date, locale = "en") {
if (!date) {
return "-";
}
return (0, _dayjs.default)(date).locale(formatLocale(locale)).format("lll");
}
function formatTime(date, format = "YYYY-MM-DD HH:mm:ss", locale = "en") {
if (!date) {
return "-";
}
return (0, _dayjs.default)(date).locale(formatLocale(locale)).format(format);
}
function formatDateTime(date, locale = "en") {
return (0, _dayjs.default)(date).locale(formatLocale(locale)).format("YYYY-MM-DD HH:mm");
}
const formatLocale = (locale = "en") => {
if (locale === "tw") {
return "zh";
}
return locale;
};
exports.formatLocale = formatLocale;
const formatPrettyMsLocale = locale => locale === "zh" ? "zh_CN" : "en_US";
exports.formatPrettyMsLocale = formatPrettyMsLocale;
const formatError = err => {
if (!err) {
return "Unknown error";
}
const {
details,
errors,
response
} = err;
if (Array.isArray(errors)) {
return errors.map(x => x.message).join("\n");
}
if (Array.isArray(details)) {
const formatted = details.map(e => {
const errorMessage = e.message.replace(/["]/g, "'");
const errorPath = e.path.join(".");
return `${errorPath}: ${errorMessage}`;
});
return `Validate failed: ${formatted.join(";")}`;
}
if (response) {
return response.data?.error || `${err.message}: ${JSON.stringify(response.data)}`;
}
return err.message;
};
exports.formatError = formatError;
function formatBNStr(str = "", decimals = 18, precision = 6, trim = true, thousandSeparated = true) {
if (!str) {
return "0";
}
return formatNumber((0, _util.fromUnitToToken)(str, decimals), precision, trim, thousandSeparated);
}
function formatNumber(n, precision = 6, trim = true, thousandSeparated = true) {
if (!n || n === "0") {
return "0";
}
const num = (0, _numbro.default)(n);
const options = {
thousandSeparated,
...((precision || precision === 0) && {
mantissa: precision
})
};
const result = num.format(options);
if (!trim) {
return result;
}
const [left, right] = result.split(".");
return right ? [left, (0, _trimEnd.default)(right, "0")].filter(Boolean).join(".") : left;
}
const formatPrice = (price, currency, unit_label, quantity = 1, bn = true, locale = "en") => {
if (!currency) {
return "";
}
if (price.custom_unit_amount) {
return `Custom (${currency.symbol})`;
}
const unit = getPriceUintAmountByCurrency(price, currency);
const amount = bn ? (0, _util.fromUnitToToken)(new _util.BN(unit).mul(new _util.BN(quantity)), currency.decimal).toString() : +unit * quantity;
if (price?.type === "recurring" && price.recurring) {
const recurring = formatRecurring(price.recurring, false, "slash", locale);
if (unit_label) {
return `${amount} ${currency.symbol} / ${unit_label} ${recurring}`;
}
if (price.recurring.usage_type === "metered") {
return `${amount} ${currency.symbol} / unit ${recurring}`;
}
return `${amount} ${currency.symbol} ${recurring}`;
}
return `${amount} ${currency.symbol}`;
};
exports.formatPrice = formatPrice;
const formatPriceAmount = (price, currency, unit_label, quantity = 1, bn = true) => {
if (!currency) {
return "";
}
const unit = getPriceUintAmountByCurrency(price, currency);
const amount = bn ? (0, _util.fromUnitToToken)(new _util.BN(unit).mul(new _util.BN(quantity)), currency.decimal).toString() : +unit * quantity;
if (price?.type === "recurring" && price.recurring) {
if (unit_label) {
return `${amount} ${currency.symbol} / ${unit_label}`;
}
if (price.recurring.usage_type === "metered") {
return `${amount} ${currency.symbol} / unit`;
}
return `${amount} ${currency.symbol}`;
}
return `${amount} ${currency.symbol}`;
};
exports.formatPriceAmount = formatPriceAmount;
function getStatementDescriptor(items) {
for (const item of items) {
if (item.price?.product?.statement_descriptor) {
return item.price?.product?.statement_descriptor;
}
}
return window.blocklet?.appName;
}
function formatRecurring(recurring, translate = true, separator = "per", locale = "en") {
const intervals = {
hour: "hourly",
day: "daily",
week: "weekly",
month: "monthly",
year: "yearly"
};
if (!recurring) {
return "";
}
if (+recurring.interval_count === 1) {
const interval = (0, _locales.t)(`common.${recurring.interval}`, locale);
return translate ? (0, _locales.t)(`common.${intervals[recurring.interval]}`, locale) : separator ? (0, _locales.t)(`common.${separator}`, locale, {
interval
}) : interval;
}
if (recurring.interval === "month") {
if (recurring.interval_count === 3) {
return (0, _locales.t)("common.month3", locale);
}
if (recurring.interval_count === 6) {
return (0, _locales.t)("common.month6", locale);
}
}
return (0, _locales.t)("common.recurring", locale, {
count: recurring.interval_count,
interval: (0, _locales.t)(`common.${recurring.interval}s`, locale)
});
}
function getPriceUintAmountByCurrency(price, currency) {
const options = getPriceCurrencyOptions(price);
const option = options.find(x => x.currency_id === currency?.id);
if (option) {
if (option.custom_unit_amount) {
return option.custom_unit_amount.preset || option.custom_unit_amount.presets[0];
}
return option.unit_amount;
}
if (price.currency_id === currency?.id) {
if (price.custom_unit_amount) {
return price.custom_unit_amount.preset || price.custom_unit_amount.presets[0];
}
return price.unit_amount;
}
console.warn(`Currency ${currency?.id} not configured for price`, price);
return "0";
}
function getPriceCurrencyOptions(price) {
if (Array.isArray(price.currency_options)) {
return price.currency_options;
}
return [{
currency_id: price.currency_id,
unit_amount: price.unit_amount,
custom_unit_amount: price.custom_unit_amount || null,
tiers: null
}];
}
function formatLineItemPricing(item, currency, {
trialEnd,
trialInDays
}, locale = "en") {
if (!currency) {
return {
primary: "",
secondary: "",
quantity: ""
};
}
const price = item.upsell_price || item.price;
let quantity = (0, _locales.t)("common.qty", locale, {
count: item.quantity
});
if (price.recurring?.usage_type === "metered" || +item.quantity === 1) {
quantity = "";
}
const unitValue = new _util.BN(getPriceUintAmountByCurrency(price, currency));
const total = `${(0, _util.fromUnitToToken)(unitValue.mul(new _util.BN(item.quantity)), currency.decimal)} ${currency.symbol}`;
const unit = `${(0, _util.fromUnitToToken)(unitValue, currency.decimal)} ${currency.symbol}`;
const trialResult = getFreeTrialTime({
trialInDays,
trialEnd
}, locale);
const appendUnit = (v, alt) => {
if (price.product.unit_label) {
return `${v}/${price.product.unit_label}`;
}
if (price.recurring?.usage_type === "metered" || item.quantity === 1) {
return alt;
}
return quantity ? (0, _locales.t)("common.each", locale, {
unit
}) : "";
};
if (price.type === "recurring" && price.recurring) {
if (trialResult.count > 0) {
return {
primary: (0, _locales.t)("common.trial", locale, {
count: trialResult.count,
interval: trialResult.interval
}),
secondary: `${appendUnit(total, total)} ${formatRecurring(price.recurring, false, "slash", locale)}`,
quantity
};
}
return {
primary: total,
secondary: appendUnit(total, ""),
quantity
};
}
return {
primary: total,
secondary: appendUnit(total, ""),
quantity
};
}
function getSubscriptionStatusColor(status) {
switch (status) {
case "active":
return "success";
case "trialing":
return "primary";
case "incomplete":
case "incomplete_expired":
case "paused":
return "warning";
case "past_due":
case "unpaid":
return "error";
case "canceled":
default:
return "default";
}
}
function getPaymentIntentStatusColor(status) {
switch (status) {
case "succeeded":
return "success";
case "requires_payment_method":
case "requires_confirmation":
case "requires_action":
case "requires_capture":
return "warning";
case "canceled":
case "processing":
default:
return "default";
}
}
function getRefundStatusColor(status) {
switch (status) {
case "succeeded":
return "success";
case "requires_action":
return "warning";
case "canceled":
case "pending":
default:
return "default";
}
}
function getPayoutStatusColor(status) {
switch (status) {
case "paid":
return "success";
case "deferred":
return "warning";
case "failed":
return "warning";
case "canceled":
case "pending":
case "in_transit":
default:
return "default";
}
}
function getInvoiceStatusColor(status) {
switch (status) {
case "paid":
return "success";
case "open":
return "secondary";
case "uncollectible":
return "warning";
case "draft":
case "void":
default:
return "default";
}
}
function getWebhookStatusColor(status) {
switch (status) {
case "enabled":
return "success";
case "disabled":
default:
return "default";
}
}
function getCheckoutAmount(items, currency, trialing = false, upsell = true) {
if (items.find(x => (x.upsell_price || x.price).custom_unit_amount) && items.length > 1) {
throw new Error("Multiple items with custom unit amount are not supported");
}
let renew = new _util.BN(0);
const total = items.filter(x => {
const price = upsell ? x.upsell_price || x.price : x.price;
return price != null;
}).reduce((acc, x) => {
if (x.custom_amount) {
return acc.add(new _util.BN(x.custom_amount));
}
const price = upsell ? x.upsell_price || x.price : x.price;
const unitPrice = getPriceUintAmountByCurrency(price, currency);
if (price.custom_unit_amount) {
if (unitPrice) {
return acc.add(new _util.BN(unitPrice).mul(new _util.BN(x.quantity)));
}
}
if (price?.type === "recurring") {
renew = renew.add(new _util.BN(unitPrice).mul(new _util.BN(x.quantity)));
if (trialing) {
return acc;
}
if (price.recurring?.usage_type === "metered") {
return acc;
}
}
return acc.add(new _util.BN(unitPrice).mul(new _util.BN(x.quantity)));
}, new _util.BN(0)).toString();
return {
subtotal: total,
total,
renew: renew.toString(),
discount: "0",
shipping: "0",
tax: "0"
};
}
function getRecurringPeriod(recurring) {
const {
interval
} = recurring;
const count = +recurring.interval_count || 1;
const dayInMs = 24 * 60 * 60 * 1e3;
switch (interval) {
case "hour":
return 60 * 60 * 1e3;
case "day":
return count * dayInMs;
case "week":
return count * 7 * dayInMs;
case "month":
return count * 30 * dayInMs;
case "year":
return count * 365 * dayInMs;
default:
throw new Error(`Unsupported recurring interval: ${interval}`);
}
}
function formatUpsellSaving(items, currency) {
if (items[0]?.upsell_price_id) {
return "0";
}
if (!items[0]?.price.upsell?.upsells_to) {
return "0";
}
const from = getCheckoutAmount(items, currency, false, false);
const to = getCheckoutAmount(items.map(x => ({
...x,
upsell_price_id: x.price.upsell?.upsells_to_id,
upsell_price: x.price.upsell?.upsells_to
})), currency, false, true);
const fromRecurring = items[0].price?.recurring;
const toRecurring = items[0].price?.upsell?.upsells_to?.recurring;
if (!fromRecurring || !toRecurring) {
return "0";
}
const factor = Math.floor(getRecurringPeriod(toRecurring) / getRecurringPeriod(fromRecurring));
const before = new _util.BN(from.total).mul(new _util.BN(factor));
const after = new _util.BN(to.total);
return Number(before.sub(after).mul(new _util.BN(100)).div(before).toString()).toFixed(0);
}
function formatMeteredThen(subscription, recurring, hasMetered, locale = "en") {
if (hasMetered) {
return (0, _locales.t)("payment.checkout.meteredThen", locale, {
subscription,
recurring
});
}
return (0, _locales.t)("payment.checkout.then", locale, {
subscription,
recurring
});
}
function formatPriceDisplay({
amount,
then,
actualAmount,
showThen
}, recurring, hasMetered, locale = "en") {
if (Number(actualAmount) === 0 && hasMetered) {
return (0, _locales.t)("payment.checkout.metered", locale, {
recurring
});
}
if (showThen) {
return [amount, then].filter(Boolean).join(", ");
}
return [amount, then].filter(Boolean).join(" ");
}
function hasMultipleRecurringIntervals(items) {
const intervals = /* @__PURE__ */new Set();
for (const item of items) {
if (item.price?.recurring?.interval && item.price?.type === "recurring") {
intervals.add(`${item.price.recurring.interval}-${item.price.recurring.interval_count}`);
if (intervals.size > 1) {
return true;
}
}
}
return false;
}
function getFreeTrialTime({
trialInDays,
trialEnd
}, locale = "en") {
const now = (0, _dayjs.default)().unix();
if (trialEnd > 0 && trialEnd > now) {
if (trialEnd - now < 3600) {
return {
count: Math.ceil((trialEnd - now) / 60),
interval: (0, _locales.t)("common.minute", locale)
};
}
if (trialEnd - now < 86400) {
return {
count: Math.ceil((trialEnd - now) / 3600),
interval: (0, _locales.t)("common.hour", locale)
};
}
return {
count: Math.ceil((trialEnd - now) / 86400),
interval: (0, _locales.t)("common.day", locale)
};
}
if (trialInDays > 0) {
return {
count: trialInDays,
interval: (0, _locales.t)("common.day", locale)
};
}
return {
count: 0,
interval: (0, _locales.t)("common.day", locale)
};
}
function formatCheckoutHeadlines(items, currency, {
trialInDays,
trialEnd
}, locale = "en") {
const brand = getStatementDescriptor(items);
const {
total
} = getCheckoutAmount(items, currency, trialInDays > 0);
const actualAmount = (0, _util.fromUnitToToken)(total, currency.decimal);
const amount = `${(0, _util.fromUnitToToken)(total, currency.decimal)} ${currency.symbol}`;
const trialResult = getFreeTrialTime({
trialInDays,
trialEnd
}, locale);
if (items.length === 0) {
return {
action: (0, _locales.t)("payment.checkout.empty", locale),
amount: "0",
then: "",
actualAmount: "0",
priceDisplay: "0"
};
}
const {
name
} = items[0]?.price.product || {
name: ""
};
if (items.every(x => x.price.type === "one_time")) {
const action = (0, _locales.t)("payment.checkout.pay", locale, {
payee: brand
});
if (items.length > 1) {
return {
action,
amount,
actualAmount,
priceDisplay: amount
};
}
return {
action,
amount,
then: "",
actualAmount,
priceDisplay: amount
};
}
const item = items.find(x => x.price.type === "recurring");
const recurring = formatRecurring((item?.upsell_price || item?.price)?.recurring, false, "per", locale);
const hasMetered = items.some(x => x.price.type === "recurring" && x.price.recurring?.usage_type === "metered");
const differentRecurring = hasMultipleRecurringIntervals(items);
if (items.every(x => x.price.type === "recurring")) {
const subscription2 = [hasMetered ? (0, _locales.t)("payment.checkout.least", locale) : "", (0, _util.fromUnitToToken)(items.reduce((acc, x) => {
if (x.price.recurring?.usage_type === "metered") {
return acc;
}
return acc.add(new _util.BN(getPriceUintAmountByCurrency(x.upsell_price || x.price, currency)).mul(new _util.BN(x.quantity)));
}, new _util.BN(0)), currency.decimal), currency.symbol].filter(Boolean).join(" ");
if (items.length > 1) {
if (trialResult.count > 0) {
const result4 = {
action: (0, _locales.t)("payment.checkout.try2", locale, {
name,
count: items.length - 1
}),
amount: (0, _locales.t)("payment.checkout.free", locale, {
count: trialResult.count,
interval: trialResult.interval
}),
then: formatMeteredThen(subscription2, recurring, hasMetered && Number(subscription2) === 0, locale),
showThen: true,
actualAmount: "0"
};
return {
...result4,
priceDisplay: formatPriceDisplay(result4, recurring, hasMetered, locale)
};
}
const result3 = {
action: (0, _locales.t)("payment.checkout.sub2", locale, {
name,
count: items.length - 1
}),
amount,
then: hasMetered ? (0, _locales.t)("payment.checkout.meteredThen", locale, {
recurring
}) : recurring,
showThen: hasMetered,
actualAmount
};
return {
...result3,
priceDisplay: formatPriceDisplay(result3, recurring, hasMetered, locale)
};
}
if (trialResult.count > 0) {
const result3 = {
action: (0, _locales.t)("payment.checkout.try1", locale, {
name
}),
amount: (0, _locales.t)("payment.checkout.free", locale, {
count: trialResult.count,
interval: trialResult.interval
}),
then: formatMeteredThen(subscription2, recurring, hasMetered && Number(subscription2) === 0, locale),
showThen: true,
actualAmount: "0"
};
return {
...result3,
priceDisplay: formatPriceDisplay(result3, recurring, hasMetered, locale)
};
}
const result2 = {
action: (0, _locales.t)("payment.checkout.sub1", locale, {
name
}),
amount,
then: hasMetered ? (0, _locales.t)("payment.checkout.meteredThen", locale, {
recurring
}) : recurring,
showThen: hasMetered && !differentRecurring,
actualAmount
};
return {
...result2,
priceDisplay: formatPriceDisplay(result2, recurring, hasMetered, locale)
};
}
const subscription = (0, _util.fromUnitToToken)(items.filter(x => x.price.type === "recurring").reduce((acc, x) => {
if (x.price.recurring?.usage_type === "metered") {
return acc;
}
return acc.add(new _util.BN(getPriceUintAmountByCurrency(x.price, currency)).mul(new _util.BN(x.quantity)));
}, new _util.BN(0)), currency.decimal);
const result = {
action: (0, _locales.t)("payment.checkout.pay", locale, {
payee: brand
}),
amount,
then: formatMeteredThen(`${subscription} ${currency.symbol}`, recurring, hasMetered && Number(subscription) === 0, locale),
showThen: !differentRecurring,
actualAmount
};
return {
...result,
priceDisplay: formatPriceDisplay(result, recurring, hasMetered, locale)
};
}
function formatAmount(amount, decimals) {
return (0, _util.fromUnitToToken)(amount, decimals);
}
function findCurrency(methods, currencyId) {
for (const method of methods) {
for (const currency of method.payment_currencies) {
if (currency.id === currencyId) {
return {
object: "payment_currency",
...currency,
paymentMethod: (0, _omit.default)(method, ["payment_currencies"])
};
}
}
}
return null;
}
function isValidCountry(code) {
return _reactInternationalPhone.defaultCountries.some(x => x[1] === code);
}
function stopEvent(e) {
try {
e.stopPropagation();
e.preventDefault();
} catch {}
}
function sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
function formatSubscriptionProduct(items, maxLength = 2) {
const names = items.map(x => x.price?.product?.name).filter(Boolean);
return names.slice(0, maxLength).join(", ") + (names.length > maxLength ? ` and ${names.length - maxLength} more` : "");
}
const getLineTimeInfo = (time, locale = "en") => {
const isToday = (0, _dayjs.default)().isSame((0, _dayjs.default)(time), "day");
const timeFormat = isToday ? "HH:mm:ss" : "YYYY-MM-DD";
return {
time: formatToDate(time, locale, timeFormat),
isToday
};
};
exports.getLineTimeInfo = getLineTimeInfo;
const getSubscriptionTimeSummary = (subscription, locale = "en") => {
if (subscription.status === "active" || subscription.status === "trialing") {
if (subscription.cancel_at) {
const endTime = subscription.cancel_at * 1e3;
const {
time: time2,
isToday: isToday2
} = getLineTimeInfo(endTime, locale);
return {
action: endTime > Date.now() ? "willEnd" : "ended",
time: time2,
isToday: isToday2
};
}
if (subscription.cancel_at_period_end) {
const endTime = subscription.current_period_end * 1e3;
const {
time: time2,
isToday: isToday2
} = getLineTimeInfo(endTime, locale);
return {
action: "willEnd",
time: time2,
isToday: isToday2
};
}
const {
time,
isToday
} = getLineTimeInfo(subscription.current_period_end * 1e3, locale);
return {
action: "renew",
time,
isToday
};
}
if (subscription.status === "past_due") {
const endTime = (subscription.cancel_at || subscription.current_period_end) * 1e3;
const {
time,
isToday
} = getLineTimeInfo(endTime, locale);
return {
action: endTime > Date.now() ? "willEnd" : "ended",
time,
isToday
};
}
if (subscription.status === "canceled") {
const {
time,
isToday
} = getLineTimeInfo(subscription.canceled_at * 1e3, locale);
return {
action: "ended",
time,
isToday
};
}
return null;
};
exports.getSubscriptionTimeSummary = getSubscriptionTimeSummary;
const getSubscriptionAction = (subscription, actionProps) => {
if (subscription.status === "active" || subscription.status === "trialing") {
if (subscription.cancel_at_period_end) {
if (subscription.cancelation_details?.reason === "payment_failed") {
return null;
}
return {
action: "recover",
variant: "contained",
color: "primary",
canRenew: false,
...actionProps?.recover
};
}
if (subscription.cancel_at && subscription.cancel_at !== subscription.current_period_end) {
return null;
}
return {
action: "cancel",
variant: "outlined",
color: "inherit",
canRenew: false,
...actionProps?.cancel
};
}
if (subscription.status === "past_due") {
const canRenew = subscription.cancel_at && subscription.cancel_at !== subscription.current_period_end;
return {
action: "pastDue",
variant: "contained",
color: "primary",
canRenew,
...actionProps?.pastDue
};
}
if (subscription.status !== "canceled" && subscription.cancel_at_period_end) {
return {
action: "recover",
variant: "contained",
color: "primary",
canRenew: false,
...actionProps?.recover
};
}
return null;
};
exports.getSubscriptionAction = getSubscriptionAction;
const mergeExtraParams = (extra = {}) => {
const params = new URLSearchParams(window.location.search);
Object.keys(extra).forEach(key => {
params.set(key, extra[key]);
});
return params.toString();
};
exports.mergeExtraParams = mergeExtraParams;
const flattenPaymentMethods = (methods = []) => {
const out = [];
methods.forEach(method => {
const currencies = method.paymentCurrencies || method.payment_currencies || [];
currencies.forEach(currency => {
out.push({
...currency,
method
});
});
});
return out;
};
exports.flattenPaymentMethods = flattenPaymentMethods;
const getTxLink = (method, details) => {
if (!details) {
return {
text: "N/A",
link: "",
gas: ""
};
}
if (method.type === "arcblock" && details.arcblock?.tx_hash) {
return {
link: (0, _ufo.joinURL)(method.settings.arcblock?.explorer_host, "/txs", details.arcblock?.tx_hash),
text: details.arcblock?.tx_hash,
gas: ""
};
}
if (method.type === "bitcoin" && details.bitcoin?.tx_hash) {
return {
link: (0, _ufo.joinURL)(method.settings.bitcoin?.explorer_host, "/tx", details.bitcoin?.tx_hash),
text: details.bitcoin?.tx_hash,
gas: ""
};
}
if (method.type === "ethereum" && details.ethereum?.tx_hash) {
return {
link: (0, _ufo.joinURL)(method.settings.ethereum?.explorer_host, "/tx", details.ethereum?.tx_hash),
text: (details.ethereum?.tx_hash).toUpperCase(),
gas: new _util.BN(details.ethereum.gas_price).mul(new _util.BN(details.ethereum.gas_used)).toString()
};
}
if (method.type === "base" && details.base?.tx_hash) {
return {
link: (0, _ufo.joinURL)(method.settings.base?.explorer_host, "/tx", details.base?.tx_hash),
text: (details.base?.tx_hash).toUpperCase(),
gas: ""
};
}
if (method.type === "stripe") {
const dashboard = method.livemode ? "https://dashboard.stripe.com" : "https://dashboard.stripe.com/test";
return {
link: (0, _ufo.joinURL)(method.settings.stripe?.dashboard || dashboard, "payments", details.stripe?.payment_intent_id),
text: details.stripe?.payment_intent_id,
gas: ""
};
}
return {
text: "N/A",
link: "",
gas: ""
};
};
exports.getTxLink = getTxLink;
function getQueryParams(url) {
const queryParams = {};
const urlObj = new URL(url);
urlObj.searchParams.forEach((value, key) => {
queryParams[key] = value;
});
return queryParams;
}
function lazyLoad(lazyRun) {
if ("requestIdleCallback" in window) {
window.requestIdleCallback(() => {
lazyRun();
});
return;
}
if (document.readyState === "complete") {
lazyRun();
return;
}
if ("onload" in window) {
window.onload = () => {
lazyRun();
};
return;
}
setTimeout(() => {
lazyRun();
}, 0);
}
function formatTotalPrice({
product,
quantity = 1,
priceId,
locale = "en"
}) {
const {
prices = [],
default_price_id: defaultPriceId
} = product ?? {
prices: [],
default_price_id: ""
};
const price = prices?.find(x => x.id === (priceId || defaultPriceId));
if (!price || !product) {
return {
totalPrice: "0",
unitPrice: "",
quantity: (0, _locales.t)("common.qty", locale, {
count: quantity
}),
totalAmount: "0"
};
}
const currency = price?.currency ?? {};
const unitValue = new _util.BN(getPriceUintAmountByCurrency(price, currency));
const total = `${(0, _util.fromUnitToToken)(unitValue.mul(new _util.BN(quantity)), currency.decimal)} ${currency.symbol} `;
const unit = `${(0, _util.fromUnitToToken)(unitValue, currency.decimal)} ${currency.symbol} `;
const appendUnit = (v, alt) => {
if (product.unit_label) {
return `${v}/${price.product.unit_label}`;
}
if (price.recurring?.usage_type === "metered" || quantity === 1) {
return alt;
}
return quantity ? (0, _locales.t)("common.each", locale, {
unit
}) : "";
};
return {
totalPrice: total,
unitPrice: appendUnit(total, ""),
quantity: (0, _locales.t)("common.qty", locale, {
count: quantity
}),
totalAmount: unitValue.mul(new _util.BN(quantity)).toString()
};
}
function formatQuantityInventory(price, quantity, locale = "en") {
const q = Number(quantity);
const {
quantity_available: quantityAvailable = 0,
quantity_sold: quantitySold = 0,
quantity_limit_per_checkout: quantityLimitPerCheckout = 0
} = price || {};
if (quantityAvailable > 0 && quantitySold + q > quantityAvailable) {
return (0, _locales.t)("common.quantityNotEnough", locale);
}
if (quantityLimitPerCheckout > 0 && quantityLimitPerCheckout < q) {
return (0, _locales.t)("common.quantityLimitPerCheckout", locale);
}
return "";
}
function formatSubscriptionStatus(status) {
if (status === "canceled") {
return "Ended";
}
return status;
}
function formatAmountPrecisionLimit(amount, locale = "en", precision = 6) {
if (!amount) {
return "";
}
const [, decimal] = String(amount).split(".");
if (decimal && decimal.length > precision) {
return (0, _locales.t)("common.amountPrecisionLimit", locale, {
precision
});
}
return "";
}
function getWordBreakStyle(value) {
if (typeof value === "string" && /\s/.test(value)) {
return "break-word";
}
return "break-all";
}
function isMobileSafari() {
const ua = navigator.userAgent.toLowerCase();
const isSafari = ua.indexOf("safari") > -1 && ua.indexOf("chrome") === -1;
const isMobile = ua.indexOf("mobile") > -1 || /iphone|ipad|ipod/.test(ua);
const isIOS = /iphone|ipad|ipod/.test(ua);
return isSafari && isMobile && isIOS;
}
function truncateText(text, maxLength, useWidth = false) {
if (!text || !maxLength) {
return text;
}
if (!useWidth) {
if (text.length <= maxLength) {
return text;
}
return `${text.substring(0, maxLength)}...`;
}
let width = 0;
let truncated = "";
for (let i = 0; i < text.length; i++) {
const charWidth = (0, _stringWidth.default)(text.charAt(i));
if (width + charWidth > maxLength) {
break;
}
truncated += text.charAt(i);
width += charWidth;
}
if (truncated === text) {
return truncated;
}
return `${truncated}...`;
}
function getCustomerAvatar(did, updated_at, imageSize = 48) {
const updated = typeof updated_at === "number" ? updated_at : (0, _dayjs.default)(updated_at).unix();
return `/.well-known/service/user/avatar/${did}?imageFilter=resize&w=${imageSize}&h=${imageSize}&updateAt=${updated || (0, _dayjs.default)().unix()}`;
}
function hasDelegateTxHash(details, paymentMethod) {
return paymentMethod?.type && ["arcblock", "ethereum", "base"].includes(paymentMethod?.type) &&
// @ts-ignore
details?.[paymentMethod?.type]?.tx_hash;
}
function getInvoiceDescriptionAndReason(invoice, locale = "en") {
const {
billing_reason: reason,
description
} = invoice;
const reasonMap = {
subscription_create: (0, _locales.t)("payment.invoice.reason.creation", locale),
subscription_cycle: (0, _locales.t)("payment.invoice.reason.cycle", locale),
subscription_update: (0, _locales.t)("payment.invoice.reason.update", locale),
subscription_recover: (0, _locales.t)("payment.invoice.reason.recover", locale),
subscription_threshold: (0, _locales.t)("payment.invoice.reason.threshold", locale),
subscription_cancel: (0, _locales.t)("payment.invoice.reason.cancel", locale),
manual: (0, _locales.t)("payment.invoice.reason.manual", locale),
upcoming: (0, _locales.t)("payment.invoice.reason.upcoming", locale),
slash_stake: (0, _locales.t)("payment.invoice.reason.slashStake", locale),
stake: (0, _locales.t)("payment.invoice.reason.stake", locale),
return_stake: (0, _locales.t)("payment.invoice.reason.returnStake", locale),
recharge: (0, _locales.t)("payment.invoice.reason.recharge", locale),
stake_overdraft_protection: (0, _locales.t)("payment.invoice.reason.stake", locale),
overdraft_protection: (0, _locales.t)("payment.invoice.reason.fee", locale),
auto_recharge: (0, _locales.t)("payment.invoice.reason.recharge", locale)
};
let invoiceType = (0, _locales.t)("payment.invoice.reason.payment", locale);
if (reason.includes("stake") || reason.includes("recharge") || reason === "overdraft_protection") {
invoiceType = reasonMap[reason];
}
if (description?.startsWith("Subscription ") || description?.startsWith("Slash stake")) {
return {
description: reasonMap[reason],
reason: reasonMap[reason],
type: invoiceType
};
}
const descMap = {
"Stake for subscription plan change": (0, _locales.t)("payment.invoice.reason.stakeForChangePlan", locale),
"Stake for subscription payment change": (0, _locales.t)("payment.invoice.reason.stakeForChangePayment", locale),
"Stake for subscription": (0, _locales.t)("payment.invoice.reason.staking", locale),
"Return Subscription staking": (0, _locales.t)("payment.invoice.reason.returnStake", locale),
"Recharge for subscription": (0, _locales.t)("payment.invoice.reason.rechargeForSubscription", locale),
"Add funds for subscription": (0, _locales.t)("payment.invoice.reason.rechargeForSubscription", locale),
"Overdraft protection": (0, _locales.t)("payment.invoice.reason.overdraftProtection", locale),
"Stake for subscription overdraft protection": (0, _locales.t)("payment.invoice.reason.stakeForSubscriptionOverdraftProtection", locale),
"Re-stake to resume subscription": (0, _locales.t)("payment.invoice.reason.reStakeToResumeSubscription", locale)
};
return {
description: descMap[description] || description,
reason: reasonMap[reason] || reason,
type: invoiceType
};
}
function getPaymentKitComponent() {
const paymentKit = window.blocklet?.componentMountPoints?.find(c => c.did === PAYMENT_KIT_DID);
return paymentKit || null;
}
function openDonationSettings(openInNewTab = false) {
const paymentKit = getPaymentKitComponent();
if (paymentKit) {
const mountPoint = paymentKit.mountPoint.endsWith("/") ? paymentKit.mountPoint.slice(0, -1) : paymentKit.mountPoint;
window.open(`${window.location.origin}${mountPoint}/integrations/donations`, openInNewTab ? "_blank" : "_self");
}
}
function getUserProfileLink(userDid, locale = "en") {
return (0, _ufo.joinURL)(window.location.origin, (0, _ufo.withQuery)(".well-known/service/user", {
locale,
did: userDid
}));
}
function parseMarkedText(text) {
if (!text) return [];
const parts = text.split(/(#([^#]*)#)/);
const result = [];
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
if (!part) continue;
if (i % 3 === 0) {
result.push({
type: "text",
content: part
});
} else if (i % 3 === 1 && part.startsWith("#") && part.endsWith("#")) {
const content = part.slice(1, -1);
if (content.length >= 0) {
result.push({
type: "marked",
content
});
}
}
}
return result.filter(p => p.content !== "");
}
function getTokenBalanceLink(method, address) {
if (!method || !address) {
return "";
}
const explorerHost = method?.settings?.[method?.type]?.explorer_host || "";
if (method.type === "arcblock" && address) {
return (0, _ufo.joinURL)(explorerHost, "accounts", address, "tokens");
}
if (["ethereum", "base"].includes(method.type) && address) {
return (0, _ufo.joinURL)(explorerHost, "address", address);
}
return "";
}
function isCreditMetered(price) {
return !!(price.type === "recurring" && price.recurring?.usage_type === "metered" && price.recurring?.meter_id);
}
function showStaking(method, currency, noStake) {
if (noStake) {
return false;
}
if (method.type === "arcblock") {
return currency.type !== "credit";
}
return false;
}
function formatLinkWithLocale(url, locale) {
if (!locale || !url) {
return url;
}
try {
const urlObj = new URL(url);
urlObj.searchParams.set("locale", locale);
return urlObj.toString();
} catch (error) {
if (/[?&]locale=[^&]*/.test(url)) {
return url.replace(/([?&])locale=[^&]*/, `$1locale=${locale}`);
}
const separator = url.includes("?") ? "&" : "?";
return `${url}${separator}locale=${locale}`;
}
}