UNPKG

@coursebuilder/commerce-next

Version:

Commerce Functionality for Course Builder with Next.js

99 lines (98 loc) 6.18 kB
'use client'; import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import * as React from 'react'; import { Slot } from '@radix-ui/react-slot'; import { Clipboard } from 'lucide-react'; import pluralize from 'pluralize'; import { useCopyToClipboard } from 'react-use'; import { Alert, Button, Input } from '@coursebuilder/ui'; import { useToast } from '@coursebuilder/ui/primitives/use-toast'; import { cn } from '@coursebuilder/ui/utils/cn'; import { handleSelfRedeem } from '../utils/handle-self-redeem'; export default function InviteTeam(props) { return (_jsxs(Root, { ...props, children: [_jsx(SeatsAvailable, { className: "[&_span]:font-semibold" }), _jsx("p", { children: "Send the following invite link to your colleagues to get started:" }), _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(InviteLink, {}), _jsx(CopyInviteLinkButton, {})] }), _jsx(SelfRedeemButton, {})] })); } const InviteTeamContext = React.createContext(undefined); export const InviteTeamProvider = ({ children, ...props }) => { return (_jsx(InviteTeamContext.Provider, { value: props, children: children })); }; export const useInviteTeam = () => { const context = React.use(InviteTeamContext); if (context === undefined) { throw new Error('useInviteTeam must be used within an InviteTeamProvider'); } return context; }; const Root = ({ children, className, ...props }) => { const code = props.purchase?.bulkCoupon?.id; const inviteLink = `${process.env.NEXT_PUBLIC_URL}?code=${code}`; return (_jsx(InviteTeamProvider, { ...props, inviteLink: inviteLink, children: _jsx("section", { className: cn('w-full', className), children: children }) })); }; const SeatsAvailable = ({ children, asChild, className }) => { const { purchase } = useInviteTeam(); const Comp = asChild ? Slot : 'p'; const numberOfRedemptionsLeft = Number(purchase?.bulkCoupon?.maxUses) - Number(purchase?.bulkCoupon?.usedCount); return (_jsxs(Comp, { className: cn('', className), children: ["You have", ' ', _jsxs("span", { children: [numberOfRedemptionsLeft, " team", ' ', pluralize('seat', numberOfRedemptionsLeft), " available."] })] })); }; const InviteLink = ({ children, asChild, className, ...props }) => { const Comp = asChild ? Slot : Input; const { purchase, disabled = false, inviteLink } = useInviteTeam(); return (_jsx(Comp, { className: cn('', className), readOnly: true, disabled: disabled, id: "inviteLink", onClick: (e) => { if (disabled) return; e.currentTarget.select(); }, value: disabled ? 'Buy more seats' : inviteLink, ...props })); }; const CopyInviteLinkButton = ({ children = _jsx(Clipboard, { className: "h-4 w-4", "aria-label": "Copy to clipboard" }), asChild, className, ...props }) => { const Comp = asChild ? Slot : Button; const { purchase, disabled = false, inviteLink } = useInviteTeam(); const [_, setCopied] = useCopyToClipboard(); const { toast } = useToast(); return (_jsx(Comp, { variant: "outline", size: "icon", type: "button", "aria-label": "Copy to clipboard", disabled: disabled, onClick: () => { setCopied(inviteLink); toast({ title: 'Link copied to clipboard' }); }, ...props, children: children })); }; const SelfRedeemButton = ({ children = 'Claim 1 seat for yourself', asChild, className, ...props }) => { const Comp = asChild ? Slot : Button; const { purchase, disabled = false, userEmail, existingPurchase, } = useInviteTeam(); const [isLoading, setIsLoading] = React.useState(false); const { toast } = useToast(); const [errorMessage, setErrorMessage] = React.useState(null); const canRedeem = !existingPurchase; return canRedeem ? (_jsxs(_Fragment, { children: [_jsx(Comp, { variant: "outline", className: cn('text-primary w-full', className), type: "button", disabled: isLoading || disabled || !userEmail || !canRedeem, onClick: () => { if (userEmail) { setIsLoading(true); handleSelfRedeem(userEmail, purchase.bulkCoupon?.id, purchase.productId, (params) => { if (params.status === 'success') { console.log('redeemedPurchase', params.redeemedPurchase); toast({ title: 'Success! You have successfully redeemed a seat for yourself.', }); setIsLoading(false); } else { setIsLoading(false); // TODO: report to sentry or support? console.debug(params.error); if (params.error.startsWith('already-purchased-')) { const message = 'You have already redeemed a seat for yourself. Please contact support if you are having trouble accessing it.'; setErrorMessage(message); toast({ title: message, }); } else { const message = 'We were unable to redeem a seat for this account. If the issue persists, please reach out to support.'; setErrorMessage(message); toast({ title: 'We were unable to redeem a seat for this account. If the issue persists, please reach out to support.', }); } } }); } }, ...props, children: isLoading ? 'Claiming a seat...' : children }), errorMessage && _jsx(Alert, { children: errorMessage })] })) : null; }; export { Root, SeatsAvailable, InviteLink, CopyInviteLinkButton, SelfRedeemButton, };