"use client"; import type { SessionContextValue } from "next-auth/react"; import { CheckIcon, CopyIcon } from "lucide-react"; import { useSession } from "next-auth/react"; import { useCallback, useState } from "react"; import { Controller, useForm } from "react-hook-form"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; import type { Ensure } from "@calcom/types/utils"; import { showToast } from "@calcom/ui/components/toast"; import { UserPermissionRole } from "@calcom/prisma/enums"; import { Alert, AlertDescription } from "@coss/ui/components/alert"; import { Button } from "@coss/ui/components/button"; import { Card, CardFrame, CardFrameDescription, CardFrameFooter, CardFrameHeader, CardFrameTitle, CardPanel, } from "@coss/ui/components/card"; import { Dialog, DialogClose, DialogDescription, DialogFooter, DialogHeader, DialogPanel, DialogPopup, DialogTitle, DialogTrigger, } from "@coss/ui/components/dialog"; import { Field, FieldLabel } from "@coss/ui/components/field"; import { Form } from "@coss/ui/components/form"; import { Input } from "@coss/ui/components/input"; import { Select, SelectItem, SelectPopup, SelectTrigger, SelectValue, } from "@coss/ui/components/select"; import { ToggleGroup, Toggle } from "@coss/ui/components/toggle-group"; function CopyButton({ value }: { value: string }) { const [copied, setCopied] = useState(false); const handleCopy = useCallback(() => { navigator.clipboard.writeText(value); setCopied(true); setTimeout(() => setCopied(false), 2000); }, [value]); return ( ); } export const CreateANewLicenseKeyForm = () => { const session = useSession(); if (session.data?.user.role !== "ADMIN") { return null; } // @ts-expect-error session can't be null due to the early return return ; }; enum BillingType { PER_BOOKING = "PER_BOOKING", PER_USER = "PER_USER", } enum BillingPeriod { MONTHLY = "MONTHLY", ANNUALLY = "ANNUALLY", } interface LicenseFormValues { billingType: BillingType; entityCount: number; entityPrice: number; billingPeriod: BillingPeriod; overages: number; billingEmail: string; } interface CouponFormValues { couponName: string; billingEmail: string; code: string; discountType: "percent" | "fixed"; discountAmount: number; duration: "once" | "repeating" | "forever"; durationInMonths: number; } const CreateANewLicenseKeyFormChild = ({ session, }: { session: Ensure; }) => { const { t } = useLocale(); const [serverErrorMessage, setServerErrorMessage] = useState( null ); const [stripeCheckoutUrl, setStripeCheckoutUrl] = useState( null ); const [couponCode, setCouponCode] = useState(null); const isAdmin = session.data.user.role === UserPermissionRole.ADMIN; const licenseForm = useForm({ defaultValues: { billingType: BillingType.PER_BOOKING, billingPeriod: BillingPeriod.MONTHLY, entityCount: 500, overages: 99, entityPrice: 50, billingEmail: undefined, }, }); const licenseMutation = trpc.viewer.admin.createSelfHostedLicense.useMutation( { onSuccess: async (values) => { showToast( "Success: We have created a stripe payment URL for this billing email", "success" ); setStripeCheckoutUrl(values.stripeCheckoutUrl); }, onError: async (err) => { setServerErrorMessage(err.message); }, } ); const watchedBillingPeriod = licenseForm.watch("billingPeriod"); const watchedBillingEmail = licenseForm.watch("billingEmail"); const watchedEntityCount = licenseForm.watch("entityCount"); const watchedEntityPrice = licenseForm.watch("entityPrice"); function calculateMonthlyPrice() { const occurrence = watchedBillingPeriod === "MONTHLY" ? 1 : 12; const sum = watchedEntityCount * watchedEntityPrice; return `$ ${sum / 100} / ${occurrence} months`; } return ( Create License Key Configure pricing and generate a Stripe checkout URL for the customer. {!stripeCheckoutUrl ? (
{ event.preventDefault(); licenseForm.handleSubmit((values) => { licenseMutation.mutate(values); })(event); }} > {serverErrorMessage && ( {serverErrorMessage} )} ( Billing Period { if (newValue.length > 0) onChange(newValue[0]); }} > Monthly Annually )} /> ( Billing Email for Customer )} /> ( Booking Type { if (newValue.length > 0) onChange(newValue[0]); }} > Per Booking Per User )} />
( Total entities included onChange(+event.target.value)} /> )} /> ( Fixed price per entity ($) onChange(+event.target.value * 100) } /> )} />
( Overages ($) onChange(+event.target.value * 100) } autoComplete="off" /> )} />
) : (
Checkout URL
{couponCode && ( Coupon Code
)}
)}

Need a coupon for this customer?{" "} setCouponCode(code)} />

); }; function CreateCouponDialog({ billingEmail, onCouponCreated, }: { billingEmail: string; onCouponCreated: (code: string) => void; }) { const [couponResult, setCouponResult] = useState<{ promotionCode: string; couponId: string; } | null>(null); const [couponError, setCouponError] = useState(null); const [open, setOpen] = useState(false); const couponForm = useForm({ defaultValues: { couponName: "", billingEmail: "", code: "", discountType: "percent", discountAmount: 10, duration: "once", durationInMonths: 3, }, }); const couponMutation = trpc.viewer.admin.createCoupon.useMutation({ onSuccess: (data) => { showToast("Coupon created successfully", "success"); setCouponResult(data); setCouponError(null); onCouponCreated(data.promotionCode); }, onError: (err) => { setCouponError(err.message); setCouponResult(null); }, }); const watchedDuration = couponForm.watch("duration"); function handleOpenChange(isOpen: boolean) { setOpen(isOpen); if (isOpen) { couponForm.setValue("billingEmail", billingEmail); } if (!isOpen) { couponForm.reset(); setCouponResult(null); setCouponError(null); } } return ( } > Create a coupon
{ event.preventDefault(); couponForm.handleSubmit((values) => { setCouponError(null); setCouponResult(null); couponMutation.mutate(values); })(event); }} > Create Coupon Create a Stripe coupon with a promotion code restricted to a specific customer. {couponError && ( {couponError} )} {couponResult && (
Promo Code: {couponResult.promotionCode} Coupon ID: {couponResult.couponId}
)} ( Coupon Name (optional) )} /> ( Billing Email )} /> ( Promo Code )} /> ( Discount Type { if (newValue.length > 0) onChange(newValue[0]); }} > Percentage Fixed Amount )} /> ( Discount Amount{" "} {couponForm.watch("discountType") === "percent" ? "(%)" : "(cents)"} { const raw = event.target.value; onChange(raw === "" ? "" : +raw); }} required /> )} /> ( Duration )} /> {watchedDuration === "repeating" && ( ( Duration in Months onChange(+event.target.value)} required /> )} /> )}
}> Cancel
); }