UNPKG

@heymantle/react

Version:

Mantle's React component library

1 lines 41 kB
{"version":3,"file":"index.mjs","sources":["../src/utils/constants.ts","../src/components/core/MantleProvider/MantleProvider.tsx","../src/utils/features.ts","../src/utils/money.ts","../src/utils/plans.ts","../src/utils/views.ts"],"sourcesContent":["export const PlanAvailability = {\n Public: \"public\",\n CustomerTag: \"customerTag\",\n ShopifyPlan: \"shopifyPlan\",\n Customer: \"customer\",\n Hidden: \"hidden\",\n} as const;\n\nexport const Labels = {\n AmountPerInterval: \"{{ amount }} per {{ interval }}\",\n Back: \"Back\",\n Cancel: \"Cancel\",\n CancelConfirmation: \"Are you sure you want to cancel your subscription?\",\n CancelPlan: \"Cancel plan\",\n ChangePlan: \"Change plan\",\n CurrentPlan: \"Current plan\",\n CustomPlans: \"Custom plans\",\n CustomPlansDescription: \"Plans tailored to your specific needs\",\n DiscountAmount: \"{{ amount }} discount\",\n DiscountAmountExpired: \"{{ amount }} discount expired\",\n FreeTrialLength: \"{{ trialDays }}-day free trial\",\n Features: \"Features\",\n Month: \"month\",\n MonthShort: \"mo\",\n Monthly: \"Monthly\",\n NextBillingDate: \"Next billing date\",\n NotSubscribed: \"You're not subscribed to a plan yet.\",\n Year: \"year\",\n YearShort: \"yr\",\n Yearly: \"Yearly\",\n MostPopular: \"Most popular\",\n Per: \"/\",\n Plans: \"Plans\",\n Price: \"Price\",\n SelectPlan: \"Select plan\",\n SubscribeSuccessTitle: \"Subscription successful\",\n SubscribeSuccessBody: \"Thanks for subscribing to our app!\",\n Subscription: \"Subscription\",\n SubscriptionCancelled: \"Subscription cancelled\",\n UsageCharges: \"Usage charges\",\n\n // Common\n loading: \"Loading...\",\n error: \"An error occurred\",\n retry: \"Retry\",\n cancel: \"Cancel\",\n continue: \"Continue\",\n \n // Subscription\n subscribe: \"Subscribe\",\n subscribeNow: \"Subscribe Now\",\n upgradeNow: \"Upgrade Now\",\n manageSubscription: \"Manage Subscription\",\n cancelSubscription: \"Cancel Subscription\",\n \n // Payment\n addPaymentMethod: \"Add Payment Method\",\n updatePaymentMethod: \"Update Payment Method\",\n \n // Features\n featureNotAvailable: \"This feature is not available on your current plan\",\n upgradeRequired: \"Upgrade Required\",\n limitReached: \"Limit Reached\",\n} as const;\n","import type {\n Customer,\n Feature,\n HostedSession,\n MantleError,\n Notify,\n Plan,\n ProrationBehaviorOptions,\n RequirePaymentMethodOptions,\n SetupIntent,\n Subscription,\n OneTimeCharge,\n SuccessResponse,\n UsageEvent,\n UsageMetricReport,\n GetAppInstallationsResponse,\n} from \"@heymantle/client\";\nimport { MantleClient } from \"@heymantle/client\";\nimport React, { createContext, useContext, useEffect, useState } from \"react\";\nimport { Labels } from \"../../../utils/constants\";\n\n/** The main context interface that encapsulates functionality exposed by MantleProvider */\nexport interface TMantleContext {\n /** The MantleClient instance */\n client: MantleClient;\n /** The current customer */\n customer: Customer | null;\n /** The current subscription */\n subscription: Subscription | null;\n /** The available plans */\n plans: Plan[];\n /** Whether the current customer is loading */\n loading: boolean;\n /** Internationalization labels */\n i18n: typeof Labels;\n /** Refetch the current customer */\n refetch: () => Promise<void>;\n /** Send a new usage event to Mantle */\n sendUsageEvent: SendUsageEventCallback;\n /** Get a usage report for a usage metric */\n getUsageReport: GetUsageReportCallback;\n /** Subscribe to a new plan */\n subscribe: SubscribeCallback;\n /** Cancel the current subscription */\n cancelSubscription: CancelSubscriptionCallback;\n /** Create a one-time charge */\n createOneTimeCharge: CreateOneTimeChargeCallback;\n /** Start the process of adding a new payment method */\n addPaymentMethod: AddPaymentMethodCallback;\n /** Check if a feature is enabled */\n isFeatureEnabled: FeatureEnabledCallback;\n /** Get the limit for a feature */\n limitForFeature: FeatureLimitCallback;\n /** Create a hosted session */\n createHostedSession: HostedSessionCallback;\n /** Get a notifications */\n listNotifications: ListNotificationsCallback;\n /** Trigger a notification CTA */\n triggerNotificationCta: TriggerNotificationCtaCallback;\n /** Update a notification */\n updateNotification: UpdateNotificationCallback;\n /** Get the active checklist */\n getChecklist: GetChecklistCallback;\n /** Get all checklists */\n getChecklists: GetChecklistsCallback;\n /** Complete a checklist step */\n completeChecklistStep: CompleteChecklistStepCallback;\n /** Skip a checklist step */\n skipChecklistStep: SkipChecklistStepCallback;\n /** Mark a checklist as shown */\n showChecklist: ShowChecklistCallback;\n /** Get app installations */\n getAppInstallations: GetAppInstallationsCallback;\n}\n\n/** Callback to send a new usage event to Mantle */\nexport type SendUsageEventCallback = (\n usageEvent: UsageEvent\n) => Promise<SuccessResponse>;\n\n/** Callback to get a usage report for a usage metric */\nexport type GetUsageReportCallback = (params: {\n /** The ID of the usage metric to get a report for */\n usageId: string;\n /** The period to get the usage report for */\n period: string;\n}) => Promise<{ report: UsageMetricReport } | MantleError>;\n\n/** Callback to get the checklist */\nexport type GetChecklistCallback = (handle: string) => Promise<any>;\n\n/** Callback to show a checklist */\nexport type ShowChecklistCallback = (params: {\n /** The ID of the checklist to show */\n idOrHandle: string;\n}) => Promise<any>;\n\n/** Callback to get app installations */\nexport type GetAppInstallationsCallback = (params?: {\n /** The customer ID / Shopify domain, api token. Only required if using the API key for authentication instead of the customer API token */\n customerId?: string;\n}) => Promise<GetAppInstallationsResponse | MantleError>;\n\n/** Callback to get all checklists */\nexport type GetChecklistsCallback = (\n handles?: string[]\n) => Promise<any[] | MantleError>;\n\n/** Callback to complete a checklist step */\nexport type CompleteChecklistStepCallback = (params: {\n /** The ID of the checklist */\n idOrHandle: string;\n /** The ID of the checklist step to complete */\n stepIdOrHandle: string;\n}) => Promise<any>;\n\n/** Callback to skip a checklist step */\nexport type SkipChecklistStepCallback = (params: {\n idOrHandle: string;\n stepIdOrHandle: string;\n}) => Promise<any>;\n\n/** Common subscription parameters without the plan selection */\nexport type BaseSubscribeParams = {\n /** The ID of the discount to apply */\n discountId?: string;\n /** The billing provider to use */\n billingProvider?: string;\n /** The URL to return to after subscribing */\n returnUrl?: string;\n /** Whether to use the saved payment method for the customer. Defaults to true. */\n useSavedPaymentMethod?: boolean;\n /** The number of trial days to offer */\n trialDays?: number;\n /** (Stripe only) Whether to use Stripe checkout for the subscription. Not applicable for Shopify subscriptions as they are always hosted */\n hosted?: boolean;\n /** (Stripe only) The collection method to use for the subscription */\n collectionMethod?: string;\n /** (Stripe only) The number of days until the subscription is due */\n daysUntilDue?: number;\n /** (Stripe only) The payment method types to use for the subscription */\n paymentMethodTypes?: string[];\n /** (Stripe only) When to require a payment method for the subscription */\n requirePaymentMethod?: RequirePaymentMethodOptions;\n /** (Stripe only) Whether to automatically calculate tax for the subscription. Defaults to false. */\n automaticTax?: boolean;\n /** (Stripe only) The `proration_behavior` to use for the subscription */\n prorationBehavior?: ProrationBehaviorOptions;\n /** (Stripe checkout only) Tell the Stripe Checkout Session to require a billing address */\n requireBillingAddress?: boolean;\n /** (Stripe checkout only) Prefill the Stripe customer's email address */\n email?: string;\n /** (Stripe checkout only) Key-value pairs of metadata to attach to the subscription */\n metadata?: Record<string, string>;\n};\n\n/** Parameters for subscribing to a single plan */\nexport type SinglePlanSubscribe = BaseSubscribeParams & {\n /** The ID of the plan to subscribe to */\n planId: string;\n /** Not allowed when using planId */\n planIds?: never;\n};\n\n/** Parameters for subscribing to multiple plans */\nexport type MultiPlanSubscribe = BaseSubscribeParams & {\n /** Not allowed when using planIds */\n planId?: never;\n /** The IDs of the plans to subscribe to */\n planIds: string[];\n};\n\n/** Callback to subscribe to a new plan or plans */\nexport type SubscribeCallback = (\n params: SinglePlanSubscribe | MultiPlanSubscribe\n) => Promise<Subscription | MantleError>;\n\n/** Callback to cancel the current subscription */\nexport type CancelSubscriptionCallback = (params?: {\n /** The reason for canceling the subscription */\n cancelReason?: string;\n}) => Promise<Subscription | MantleError>;\n\n/** Callback to create a one-time charge */\nexport type CreateOneTimeChargeCallback = (params: {\n /** The amount to charge */\n amount: number;\n /** The name of the charge */\n name: string;\n /** The currency to charge in, defaults to USD */\n currencyCode?: string;\n /** The URL to return to after the charge, defaults to app root */\n returnUrl?: string;\n /** Whether to test the charge, defaults to false */\n test?: boolean;\n}) => Promise<OneTimeCharge | MantleError>;\n\n/** Callback to start the process of adding a new payment method */\nexport type AddPaymentMethodCallback = (params: {\n /** The URL to return to after connecting a new PaymentMethod */\n returnUrl: string;\n /** Whether to update payment methods that are already attached to existing subscriptions */\n updateExistingPaymentMethods?: boolean;\n}) => Promise<SetupIntent | MantleError>;\n\n/** Callback to check if a feature is enabled */\nexport type FeatureEnabledCallback = (params: {\n /** The key of the feature to evaluate */\n featureKey: string;\n /** The count to evaluate against the feature limit if there is one */\n count?: number;\n}) => boolean;\n\n/** Callback to get the limit for a feature */\nexport type FeatureLimitCallback = (params: {\n /** The key of the feature to evaluate */\n featureKey: string;\n}) => number;\n\n/** Callback to create a hosted session */\nexport type HostedSessionCallback = (params: {\n /** The type of hosted session to create */\n type: string;\n /** The configuration for the hosted session */\n config: Record<string, any>;\n}) => Promise<HostedSession | MantleError>;\n\n/** Callback to list notifications */\nexport type ListNotificationsCallback = (params?: {\n email?: string;\n}) => Promise<\n | {\n notifies: Notify[];\n hasMore: boolean;\n }\n | MantleError\n>;\n\n/** Callback to trigger a notification CTA */\nexport type TriggerNotificationCtaCallback = (params: {\n id: string;\n}) => Promise<SuccessResponse | MantleError>;\n\n/** Callback to update a notification */\nexport type UpdateNotificationCallback = (params: {\n id: string;\n readAt?: Date;\n dismissedAt?: Date;\n}) => Promise<SuccessResponse | MantleError>;\n\n/** Props for the MantleProvider component */\nexport interface MantleProviderProps {\n /** The Mantle App ID provided by Mantle */\n appId: string;\n /** The Mantle Customer API Token returned by the identify endpoint */\n customerApiToken: string;\n /** The Mantle API URL to use */\n apiUrl?: string;\n /** The children to render */\n children: React.ReactNode;\n /** The i18n object to use for labels */\n i18n?: typeof Labels;\n /** Whether to wait for the customer to be fetched */\n waitForCustomer?: boolean;\n /** The component to render while waiting for the customer to be fetched */\n loadingComponent?: React.ReactNode;\n /** Whether to throw an error if an error occurs */\n throwOnError?: boolean;\n}\n\n/** React Context for providing Mantle functionality throughout the app */\nconst MantleContext = createContext<TMantleContext | undefined>(undefined);\n\n/**\n * Evaluates whether a feature is enabled based on its type and value\n * @param feature - The feature to evaluate\n * @param count - The count to evaluate against if the feature is a limit type\n * @returns Whether the feature is considered enabled\n */\nconst evaluateFeature = ({\n feature,\n count = 0,\n}: {\n feature: Feature;\n count?: number;\n}): boolean => {\n if (feature?.type === \"boolean\") {\n return feature.value;\n } else if (feature?.type === \"limit\") {\n return count < feature.value || feature.value === -1;\n }\n return false;\n};\n\n/**\n * MantleProvider uses the React Context API to provide a MantleClient instance and\n * the current customer to its children, which can be accessed using the useMantle hook.\n *\n * @example\n * ```tsx\n * function App() {\n * return (\n * <MantleProvider\n * appId=\"your-app-id\"\n * customerApiToken=\"customer-token\"\n * >\n * <YourApp />\n * </MantleProvider>\n * );\n * }\n * ```\n */\nexport const MantleProvider: React.FC<MantleProviderProps> = ({\n appId,\n customerApiToken,\n apiUrl = \"https://appapi.heymantle.com/v1\",\n children,\n i18n = Labels,\n waitForCustomer = false,\n loadingComponent = null,\n throwOnError = false,\n}) => {\n const mantleClient = new MantleClient({ appId, customerApiToken, apiUrl });\n\n const [customer, setCustomer] = useState<Customer | null>(null);\n const [loading, setLoading] = useState(true);\n\n /**\n * Fetches the current customer from Mantle's API\n * Updates the customer state and handles loading states\n */\n const fetchCustomer = async () => {\n try {\n setLoading(true);\n const result = await mantleClient.getCustomer();\n if (result && \"error\" in result) {\n throw new Error(result.error);\n }\n setCustomer(result as Customer);\n } catch (error) {\n if (throwOnError) {\n throw error;\n } else {\n console.error(\"[MantleProvider] Error fetching customer: \", error);\n }\n } finally {\n setLoading(false);\n }\n };\n\n /**\n * Sends a usage event to Mantle\n * @param usageEvent - The usage event to send\n */\n const sendUsageEvent: SendUsageEventCallback = async (usageEvent) => {\n const result = await mantleClient.sendUsageEvent(usageEvent);\n if (\"error\" in result) {\n if (throwOnError) {\n throw new Error(result.error);\n }\n return {\n success: false,\n };\n }\n return result;\n };\n\n /**\n * Gets a usage report for a specific metric and period\n * @param params.usageId - The ID of the usage metric\n * @param params.period - The period to get the report for\n * @returns The usage report data\n */\n const getUsageReport: GetUsageReportCallback = async ({\n usageId,\n period,\n }) => {\n const result = await mantleClient.getUsageMetricReport({\n id: usageId,\n period,\n });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Subscribes to one or more plans\n * @param params - Either SinglePlanSubscribe or MultiPlanSubscribe parameters\n * @returns The created subscription\n */\n const subscribe: SubscribeCallback = async (params) => {\n const result = await mantleClient.subscribe(params);\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result as Subscription;\n };\n\n /**\n * Cancels the current subscription\n * @param params.cancelReason - Optional reason for cancellation\n * @returns The cancelled subscription\n */\n const cancelSubscription: CancelSubscriptionCallback = async ({\n cancelReason,\n } = {}) => {\n const result = await mantleClient.cancelSubscription({\n ...(cancelReason && { cancelReason }),\n });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Create a one-time charge\n * @param params.amount - The amount to charge\n * @param params.name - The name of the charge\n * @param params.currency - The currency to charge in\n * @returns The created charge\n */\n const createOneTimeCharge: CreateOneTimeChargeCallback = async ({\n amount,\n name,\n currencyCode,\n returnUrl,\n test,\n }) => {\n const result = await mantleClient.createOneTimeCharge({\n amount,\n name,\n currencyCode,\n returnUrl,\n test,\n });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Initiates the process of adding a new payment method\n * @param params.returnUrl - The URL to return to after adding the payment method\n * @param params.updateExistingPaymentMethods - Whether to update payment methods that are already attached to existing subscriptions\n * @returns A SetupIntent for completing the payment method addition\n * @throws Error if returnUrl is not provided\n */\n const addPaymentMethod: AddPaymentMethodCallback = async ({\n returnUrl,\n updateExistingPaymentMethods,\n }) => {\n if (!returnUrl) {\n throw new Error(\"returnUrl is required\");\n }\n const result = await mantleClient.addPaymentMethod({\n returnUrl,\n updateExistingPaymentMethods,\n });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Creates a hosted session for various checkout flows\n * @param params.type - The type of hosted session to create\n * @param params.config - Configuration options for the hosted session\n * @returns The created hosted session\n * @throws Error if type is not provided\n */\n const createHostedSession: HostedSessionCallback = async ({\n type,\n config,\n }) => {\n if (!type) {\n throw new Error(\"type is required\");\n }\n const searchParams = new URL(document.location.toString()).searchParams;\n const locale = searchParams.get(\"locale\");\n const result = await mantleClient.createHostedSession({\n type,\n config: {\n ...(locale ? { locale } : {}),\n ...(config || {}),\n },\n });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n const listNotifications: ListNotificationsCallback = async (params) => {\n const result = await mantleClient.listNotifications(params);\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n const triggerNotificationCta: TriggerNotificationCtaCallback = async ({\n id,\n }) => {\n const result = await mantleClient.triggerNotificationCta({ id });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n const updateNotification: UpdateNotificationCallback = async ({\n id,\n readAt,\n dismissedAt,\n }) => {\n const result = await mantleClient.updateNotification({\n id,\n readAt,\n dismissedAt,\n });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Gets the checklist for the current customer\n * @returns The checklist data\n */\n const getChecklist: GetChecklistCallback = async (handle) => {\n const result = await mantleClient.getChecklist(handle);\n if (result && \"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Gets all checklists for the current customer\n * @param handle - An optional handle filter for checklist(s) to get, can be a CSV list of handles.\n * @returns The checklist data\n */\n const getChecklists: GetChecklistsCallback = async (handle) => {\n const result = await mantleClient.getChecklists(handle);\n if (result && \"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Shows a checklist for the current customer\n * @param params.checklistId - The ID of the checklist to mark as shown\n * @returns The show result\n */\n const showChecklist: ShowChecklistCallback = async ({ idOrHandle }) => {\n const result = await mantleClient.showChecklist({ idOrHandle });\n if (result && \"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Skips a checklist step for the current customer\n * @param params.idOrHandle - The ID of the checklist\n * @param params.stepIdOrHandle - The ID of the checklist step to skip\n * @returns The skip result\n */\n const skipChecklistStep: SkipChecklistStepCallback = async ({\n idOrHandle,\n stepIdOrHandle,\n }) => {\n const result = await mantleClient.skipChecklistStep({\n idOrHandle,\n stepIdOrHandle,\n });\n if (result && \"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Completes a specific checklist step\n * @param params.idOrHandle - The ID of the checklist\n * @param params.stepIdOrHandle - The ID of the checklist step to complete\n * @returns The completion result\n */\n const completeChecklistStep: CompleteChecklistStepCallback = async ({\n idOrHandle,\n stepIdOrHandle,\n }) => {\n const result = await mantleClient.completeChecklistStep({\n idOrHandle,\n stepIdOrHandle,\n });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n /**\n * Get the list of app installations for the customer\n * @param params.customerId - The customer ID / Shopify domain, api token. Only required if using the API key for authentication instead of the customer API token\n * @returns The list of app installations\n */\n const getAppInstallations: GetAppInstallationsCallback = async ({\n customerId,\n } = {}) => {\n const result = await mantleClient.getAppInstallations({\n ...(customerId && { customerId }),\n });\n if (\"error\" in result && throwOnError) {\n throw new Error(result.error);\n }\n return result;\n };\n\n // Fetch customer when the token changes\n useEffect(() => {\n if (customerApiToken) {\n fetchCustomer();\n }\n }, [customerApiToken]);\n\n const plans = customer?.plans || [];\n const subscription = customer?.subscription || null;\n\n if (waitForCustomer && loading) {\n return loadingComponent || null;\n }\n\n return (\n <MantleContext.Provider\n value={{\n client: mantleClient,\n customer,\n subscription,\n plans,\n loading,\n i18n: { ...Labels, ...i18n },\n sendUsageEvent,\n getUsageReport,\n subscribe,\n cancelSubscription,\n createOneTimeCharge,\n addPaymentMethod,\n createHostedSession,\n listNotifications,\n triggerNotificationCta,\n updateNotification,\n getChecklist,\n getChecklists,\n completeChecklistStep,\n showChecklist,\n skipChecklistStep,\n getAppInstallations,\n isFeatureEnabled: ({ featureKey, count = 0 }) => {\n if (customer?.features[featureKey]) {\n return evaluateFeature({\n feature: customer.features[featureKey],\n count,\n });\n }\n return false;\n },\n limitForFeature: ({ featureKey }) => {\n if (\n customer?.features[featureKey] &&\n customer.features[featureKey].type === \"limit\"\n ) {\n return customer.features[featureKey].value;\n }\n return -1;\n },\n refetch: async () => {\n await fetchCustomer();\n },\n }}\n >\n {children}\n </MantleContext.Provider>\n );\n};\n\n/**\n * React hook to access the Mantle context\n * Must be used within a MantleProvider component\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { customer, subscription } = useMantle();\n * return <div>Hello {customer?.name}</div>;\n * }\n * ```\n *\n * @returns The Mantle context containing all Mantle functionality\n * @throws Error if used outside of a MantleProvider\n */\nexport const useMantle = (): TMantleContext => {\n const context = useContext(MantleContext);\n\n if (context === undefined) {\n throw new Error(\"useMantle must be used within a MantleProvider\");\n }\n\n return context;\n};\n","import type { Feature } from '@heymantle/client';\n\n/**\n * Determines if a feature is enabled based on its type and value\n * @param feature - The feature to check\n * @returns true if the feature is enabled\n */\nexport const featureEnabled = (feature: Feature): boolean => {\n return (\n (feature.type === \"boolean\" && feature.value === true) ||\n (feature.type === \"limit\" && feature.value !== 0)\n );\n};\n\n/**\n * Sorts features by enabled status (enabled first) and then by name\n * @param a - First feature to compare\n * @param b - Second feature to compare\n * @returns Sort order (-1, 0, or 1)\n */\nexport const featureSort = (a: Feature, b: Feature): number =>\n (Number(featureEnabled(b)) - Number(featureEnabled(a))) || a.name.localeCompare(b.name); ","/**\n * Creates a number formatter for the specified currency\n * @param currencyCode - The currency code to format for\n * @returns An Intl.NumberFormat instance configured for the currency\n */\nconst moneyFormatter = (currencyCode: string = \"USD\"): Intl.NumberFormat =>\n new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: currencyCode,\n notation: \"standard\",\n });\n\n/**\n * Formats the given amount of money based on the specified currency code\n * @param amount - The amount of money to format\n * @param currencyCode - The currency code to use for formatting\n * @param removeCents - Whether to remove the cents from the formatted result\n * @returns The formatted money string\n * \n * @example\n * ```ts\n * money(1234.56) // \"$1,234.56\"\n * money(1234.56, \"USD\", true) // \"$1,234\"\n * money(1234.56, \"EUR\") // \"€1,234.56\"\n * ```\n */\nexport const money = (\n amount: number,\n currencyCode: string = \"USD\",\n removeCents: boolean = true\n): string => {\n let result = moneyFormatter(currencyCode).format(amount);\n if (removeCents) {\n result = result.replace(/\\.00$/, '');\n }\n return result;\n}; ","import type { Discount, Plan } from \"@heymantle/client\";\nimport { Labels } from \"./constants\";\n\nexport enum PlanInterval {\n Annual = \"ANNUAL\",\n Every30Days = \"EVERY_30_DAYS\",\n}\n\ntype IntervalLabelType = \"year\" | \"month\";\ntype IntervalLabelShortType = \"yr\" | \"mo\";\n\n/**\n * Generate a long label for the given interval\n * @param interval - The interval to generate a label for\n * @returns The long label for the interval\n */\nexport const intervalLabelLong = (interval: PlanInterval = PlanInterval.Every30Days): IntervalLabelType => {\n switch (interval) {\n case PlanInterval.Annual:\n return \"year\";\n case PlanInterval.Every30Days:\n default:\n return \"month\";\n }\n};\n\n/**\n * Generate a short label for the given interval\n * @param interval - The interval to generate a label for\n * @returns The short label for the interval\n */\nexport const intervalLabelShort = (interval: PlanInterval = PlanInterval.Every30Days): IntervalLabelShortType => {\n switch (interval) {\n case PlanInterval.Annual:\n return \"yr\";\n case PlanInterval.Every30Days:\n default:\n return \"mo\";\n }\n};\n\ninterface IntervalLabelParams {\n interval?: PlanInterval;\n useShortFormPlanIntervals?: boolean;\n}\n\n/**\n * Generate a label for the given interval and format\n * @param params.interval - The interval to generate a label for\n * @param params.useShortFormPlanIntervals - Whether to use short form plan intervals\n * @returns The label for the interval\n */\nexport const intervalLabel = ({\n interval = PlanInterval.Every30Days,\n useShortFormPlanIntervals = true,\n}: IntervalLabelParams): IntervalLabelType | IntervalLabelShortType => {\n return useShortFormPlanIntervals ? intervalLabelShort(interval) : intervalLabelLong(interval);\n};\n\ninterface PlanParams {\n plan: Plan;\n customFieldKey?: string;\n}\n\n/**\n * Check if the plan is recommended by using custom fields\n * @param params.plan - The Mantle plan to check\n * @param params.customFieldKey - The key to check for the recommended status\n * @returns Whether the plan is recommended\n */\nexport const isRecommendedPlan = ({ \n plan, \n customFieldKey = \"recommended\" \n}: PlanParams): boolean => {\n return !!plan.customFields?.[customFieldKey];\n};\n\n/**\n * Get the custom button label for the plan, or the default label\n * @param params.plan - The Mantle plan to check\n * @param params.customFieldKey - The key to check for the button label\n * @returns The custom button label or the default label\n */\nexport const customButtonLabel = ({ \n plan, \n customFieldKey = \"buttonLabel\" \n}: PlanParams): string => {\n return plan.customFields?.[customFieldKey] || Labels.subscribe;\n};\n\n/**\n * Get the best discount for the plan\n * @param params.plan - The Mantle plan to check for a discount\n * @returns The highest discount for the plan, or undefined if none found\n */\nexport const highestDiscount = ({ plan }: { plan: Plan }): Discount | undefined => {\n return plan.discounts?.length > 0\n ? plan.discounts.reduce((prev, current) =>\n prev.discountedAmount < current.discountedAmount ? prev : current\n )\n : undefined;\n}; ","interface ColumnSpans {\n xs: number;\n sm: number;\n md: number;\n lg: number;\n xl: number;\n}\n\n/**\n * Get the column span for the grid layout\n * @param count - The number of columns\n * @returns The column span for each screen size\n * \n * @example\n * ```ts\n * columnSpan(4) // { xs: 6, sm: 6, md: 2, lg: 3, xl: 3 }\n * columnSpan(3) // { xs: 6, sm: 6, md: 2, lg: 4, xl: 4 }\n * ```\n */\nexport const columnSpan = (count: number = 4): ColumnSpans => {\n if (count % 4 === 0) return { xs: 6, sm: 6, md: 2, lg: 3, xl: 3 };\n if (count % 3 === 0) return { xs: 6, sm: 6, md: 2, lg: 4, xl: 4 };\n if (count % 2 === 0) return { xs: 6, sm: 6, md: 3, lg: 6, xl: 6 };\n if (count === 1) return { xs: 6, sm: 6, md: 6, lg: 12, xl: 12 };\n return { xs: 6, sm: 6, md: 2, lg: 4, xl: 4 };\n};\n\n/**\n * Get the column count for the grid layout\n * @param size - The number of items\n * @returns The number of columns\n * \n * @example\n * ```ts\n * columnCount(4) // 4\n * columnCount(3) // 3\n * columnCount(2) // 2\n * ```\n */\nexport const columnCount = (size: number = 4): number => {\n if (size % 4 === 0) return 4;\n if (size % 3 === 0) return 3;\n if (size % 2 === 0) return 2;\n if (size === 1) return 1;\n return 4;\n}; "],"names":["PlanAvailability","Labels","MantleContext","createContext","evaluateFeature","feature","count","MantleProvider","appId","customerApiToken","apiUrl","children","i18n","waitForCustomer","loadingComponent","throwOnError","mantleClient","MantleClient","customer","setCustomer","useState","loading","setLoading","fetchCustomer","result","error","sendUsageEvent","usageEvent","getUsageReport","usageId","period","subscribe","params","cancelSubscription","cancelReason","createOneTimeCharge","amount","name","currencyCode","returnUrl","test","addPaymentMethod","updateExistingPaymentMethods","createHostedSession","type","config","locale","listNotifications","triggerNotificationCta","id","updateNotification","readAt","dismissedAt","getChecklist","handle","getChecklists","showChecklist","idOrHandle","skipChecklistStep","stepIdOrHandle","completeChecklistStep","getAppInstallations","customerId","useEffect","plans","subscription","jsx","featureKey","useMantle","context","useContext","featureEnabled","featureSort","a","b","moneyFormatter","money","removeCents","PlanInterval","intervalLabelLong","interval","intervalLabelShort","intervalLabel","useShortFormPlanIntervals","isRecommendedPlan","plan","customFieldKey","_a","customButtonLabel","highestDiscount","prev","current","columnSpan","columnCount","size"],"mappings":"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"}