{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cancel-subscription-card",
  "title": "Cancel Subscription Card",
  "description": "A cancel subscription card component",
  "dependencies": ["lucide-react"],
  "registryDependencies": ["button", "badge", "card", "utils"],
  "files": [
    {
      "path": "src/registry/billingsdk/cancel-subscription-card.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { Button } from \"@/components/ui/button\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Card, CardContent } from \"@/components/ui/card\";\nimport { type Plan } from \"@/lib/billingsdk-config\";\nimport { cn } from \"@/lib/utils\";\nimport { Circle } from \"lucide-react\";\n\nexport interface CancelSubscriptionCardProps {\n  title: string;\n  description: string;\n  plan: Plan;\n  leftPanelImageUrl?: string;\n  warningTitle?: string;\n  warningText?: string;\n  keepButtonText?: string;\n  continueButtonText?: string;\n  finalTitle?: string;\n  finalSubtitle?: string;\n  finalWarningText?: string;\n  goBackButtonText?: string;\n  confirmButtonText?: string;\n  onCancel: (planId: string) => Promise<void> | void;\n  onKeepSubscription?: (planId: string) => Promise<void> | void;\n  className?: string;\n}\n\nexport function CancelSubscriptionCard({\n  title,\n  description,\n  plan,\n  leftPanelImageUrl,\n  warningTitle,\n  warningText,\n  keepButtonText,\n  continueButtonText,\n  finalTitle,\n  finalSubtitle,\n  finalWarningText,\n  goBackButtonText,\n  confirmButtonText,\n  onCancel,\n  onKeepSubscription,\n  className,\n}: CancelSubscriptionCardProps) {\n  const [showConfirmation, setShowConfirmation] = useState(false);\n  const [isLoading, setIsLoading] = useState(false);\n  const [error, setError] = useState<string | null>(null);\n\n  const handleContinueCancellation = () => {\n    setShowConfirmation(true);\n    setError(null);\n  };\n\n  const handleConfirmCancellation = async () => {\n    try {\n      setIsLoading(true);\n      setError(null);\n      await onCancel(plan.id);\n    } catch (err) {\n      setError(\n        err instanceof Error ? err.message : \"Failed to cancel subscription\",\n      );\n    } finally {\n      setIsLoading(false);\n    }\n  };\n\n  const handleKeepSubscription = async () => {\n    try {\n      setIsLoading(true);\n      setError(null);\n      if (onKeepSubscription) {\n        await onKeepSubscription(plan.id);\n      }\n    } catch (err) {\n      setError(\n        err instanceof Error ? err.message : \"Failed to keep subscription\",\n      );\n    } finally {\n      setIsLoading(false);\n    }\n  };\n\n  const handleGoBack = () => {\n    setShowConfirmation(false);\n    setError(null);\n  };\n\n  return (\n    <Card\n      className={cn(\n        \"flex w-full flex-col overflow-hidden p-0 sm:max-w-[1000px] md:flex-row\",\n        leftPanelImageUrl ? \"\" : \"sm:max-w-[500px]\",\n        className,\n      )}\n    >\n      {leftPanelImageUrl && (\n        <div className=\"relative hidden min-h-[500px] w-full overflow-hidden md:block md:w-1/2\">\n          {/* eslint-disable-next-line @next/next/no-img-element */}\n          <img\n            src={leftPanelImageUrl}\n            alt=\"Cancel Subscription\"\n            className=\"absolute inset-0 h-full w-full object-cover\"\n          />\n          <div className=\"via-background/30 to-background/90 absolute inset-0 hidden bg-gradient-to-r from-transparent dark:block\"></div>\n          <div className=\"from-background/80 to-background/20 absolute inset-0 hidden bg-gradient-to-t via-transparent dark:block\"></div>\n        </div>\n      )}\n      <CardContent\n        className={cn(\n          \"flex flex-col gap-4 px-4 py-6\",\n          leftPanelImageUrl ? \"w-full md:w-1/2\" : \"w-full\",\n        )}\n      >\n        <div className=\"flex flex-col gap-2 text-center md:text-left\">\n          <h2 className=\"text-xl font-semibold md:text-2xl\">{title}</h2>\n          <p className=\"text-muted-foreground text-xs md:text-sm\">\n            {description}\n          </p>\n          {error && (\n            <div className=\"bg-destructive/10 border-destructive/20 rounded-md border p-3\">\n              <p className=\"text-destructive text-sm\">{error}</p>\n            </div>\n          )}\n        </div>\n\n        {/* Plan Details */}\n        {!showConfirmation && (\n          <div className=\"bg-muted/50 flex flex-col gap-4 rounded-lg p-4\">\n            <div className=\"flex items-center justify-between\">\n              <div className=\"flex flex-col gap-1\">\n                <span className=\"text-lg font-semibold\">{plan.title} Plan</span>\n                <span className=\"text-muted-foreground text-sm\">\n                  Current subscription\n                </span>\n              </div>\n              <Badge variant=\"secondary\">\n                {parseFloat(plan.monthlyPrice) >= 0\n                  ? `${plan.currency}${plan.monthlyPrice}/monthly`\n                  : `${plan.monthlyPrice}/monthly`}\n              </Badge>\n            </div>\n            <div className=\"flex flex-col gap-2\">\n              {plan.features.slice(0, 4).map((feature, index) => (\n                <div key={index} className=\"flex items-center gap-2\">\n                  <Circle className=\"fill-primary text-primary h-2 w-2\" />\n                  <span className=\"text-muted-foreground text-sm\">\n                    {feature.name}\n                  </span>\n                </div>\n              ))}\n            </div>\n          </div>\n        )}\n\n        {/* Warning Section */}\n        {!showConfirmation && (warningTitle || warningText) && (\n          <div className=\"bg-muted/30 border-border rounded-lg border p-4\">\n            {warningTitle && (\n              <h3 className=\"text-foreground mb-2 font-semibold\">\n                {warningTitle}\n              </h3>\n            )}\n            {warningText && (\n              <p className=\"text-muted-foreground text-sm\">{warningText}</p>\n            )}\n          </div>\n        )}\n        {/* Action Buttons */}\n        {!showConfirmation ? (\n          <div className=\"mt-auto flex flex-col gap-3 lg:flex-row\">\n            <Button\n              className=\"flex-1\"\n              onClick={handleKeepSubscription}\n              disabled={isLoading}\n            >\n              {isLoading\n                ? \"Processing...\"\n                : keepButtonText || \"Keep My Subscription\"}\n            </Button>\n            <Button\n              variant=\"destructive\"\n              className=\"flex-1\"\n              onClick={handleContinueCancellation}\n              disabled={isLoading}\n            >\n              {continueButtonText || \"Continue Cancellation\"}\n            </Button>\n          </div>\n        ) : (\n          <div className=\"mt-auto flex flex-col gap-4\">\n            <div className=\"bg-muted/50 rounded-lg p-4 text-center\">\n              <h3 className=\"text-foreground mb-2 font-semibold\">\n                {finalTitle || \"Final Confirmation\"}\n              </h3>\n              <p className=\"text-muted-foreground mb-2 text-sm\">\n                {finalSubtitle ||\n                  \"Are you sure you want to cancel your subscription?\"}\n              </p>\n              <p className=\"text-destructive text-sm\">\n                {finalWarningText ||\n                  \"This action cannot be undone and you'll lose access to all premium features.\"}\n              </p>\n            </div>\n            <div className=\"flex flex-col gap-3 lg:flex-row\">\n              <Button\n                variant=\"outline\"\n                className=\"flex-1\"\n                onClick={handleGoBack}\n                disabled={isLoading}\n              >\n                {goBackButtonText || \"Go Back\"}\n              </Button>\n              <Button\n                variant=\"destructive\"\n                className=\"flex-1\"\n                onClick={handleConfirmCancellation}\n                disabled={isLoading}\n              >\n                {isLoading\n                  ? \"Cancelling...\"\n                  : confirmButtonText || \"Yes, Cancel Subscription\"}\n              </Button>\n            </div>\n          </div>\n        )}\n      </CardContent>\n    </Card>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/billingsdk/cancel-subscription-card.tsx"
    },
    {
      "path": "src/registry/billingsdk/demo/cancel-subscription-card-demo.tsx",
      "content": "\"use client\";\n\nimport { CancelSubscriptionCard } from \"@/components/billingsdk/cancel-subscription-card\";\nimport { plans } from \"@/lib/billingsdk-config\";\n\nexport function CancelSubscriptionCardDemo() {\n  return (\n    <div className=\"flex w-full flex-col\">\n      <CancelSubscriptionCard\n        title=\"We're sorry to see you go...\"\n        description={`Before you cancel, we hope you'll consider upgrading to a ${plans[1].title} plan again.`}\n        plan={plans[1]}\n        leftPanelImageUrl=\"https://framerusercontent.com/images/GWE8vop9hubsuh3uWWn0vyuxEg.webp\"\n        warningTitle=\"You will lose access to your account\"\n        warningText=\"If you cancel your subscription, you will lose access to your account and all your data will be deleted.\"\n        keepButtonText={`Keep My ${plans[1].title} Plan`}\n        continueButtonText=\"Continue with Cancellation\"\n        finalTitle=\"Final Step - Confirm Cancellation\"\n        finalSubtitle=\"This action will immediately cancel your subscription\"\n        finalWarningText=\"You'll lose access to all Pro features and your data will be permanently deleted after 30 days.\"\n        goBackButtonText=\"Wait, Go Back\"\n        confirmButtonText=\"Yes, Cancel My Subscription\"\n        onCancel={async (planId) => {\n          console.log(\"Cancelling subscription for plan:\", planId);\n          return new Promise((resolve) => {\n            setTimeout(() => {\n              resolve(void 0);\n            }, 1000);\n          });\n        }}\n        onKeepSubscription={async (planId) => {\n          console.log(\"Keeping subscription for plan:\", planId);\n        }}\n        className=\"max-w-4xl\"\n      />\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/cancel-subscription-card-demo.tsx"
    },
    {
      "path": "src/registry/lib/billingsdk-config.ts",
      "content": "export interface Plan {\n  id: string;\n  title: string;\n  description: string;\n  highlight?: boolean;\n  type?: \"monthly\" | \"yearly\";\n  currency?: string;\n  monthlyPrice: string;\n  yearlyPrice: string;\n  buttonText: string;\n  badge?: string;\n  features: {\n    name: string;\n    icon: string;\n    iconColor?: string;\n  }[];\n}\n\nexport interface CurrentPlan {\n  plan: Plan;\n  type: \"monthly\" | \"yearly\" | \"custom\";\n  price?: string;\n  nextBillingDate: string;\n  paymentMethod: string;\n  status: \"active\" | \"inactive\" | \"past_due\" | \"cancelled\";\n}\n\nexport const plans: Plan[] = [\n  {\n    id: \"starter\",\n    title: \"Starter\",\n    description: \"For developers testing out Liveblocks locally.\",\n    currency: \"$\",\n    monthlyPrice: \"0\",\n    yearlyPrice: \"0\",\n    buttonText: \"Start today for free\",\n    features: [\n      {\n        name: \"Presence\",\n        icon: \"check\",\n        iconColor: \"text-green-500\",\n      },\n      {\n        name: \"Comments\",\n        icon: \"check\",\n        iconColor: \"text-orange-500\",\n      },\n      {\n        name: \"Notifications\",\n        icon: \"check\",\n        iconColor: \"text-teal-500\",\n      },\n      {\n        name: \"Text Editor\",\n        icon: \"check\",\n        iconColor: \"text-blue-500\",\n      },\n      {\n        name: \"Sync Datastore\",\n        icon: \"check\",\n        iconColor: \"text-zinc-500\",\n      },\n    ],\n  },\n  {\n    id: \"pro\",\n    title: \"Pro\",\n    description: \"For companies adding collaboration in production.\",\n    currency: \"$\",\n    monthlyPrice: \"20\",\n    yearlyPrice: \"199\",\n    buttonText: \"Sign up\",\n    badge: \"Most popular\",\n    highlight: true,\n    features: [\n      {\n        name: \"Presence\",\n        icon: \"check\",\n        iconColor: \"text-green-500\",\n      },\n      {\n        name: \"Comments\",\n        icon: \"check\",\n        iconColor: \"text-orange-500\",\n      },\n      {\n        name: \"Notifications\",\n        icon: \"check\",\n        iconColor: \"text-teal-500\",\n      },\n      {\n        name: \"Text Editor\",\n        icon: \"check\",\n        iconColor: \"text-blue-500\",\n      },\n      {\n        name: \"Sync Datastore\",\n        icon: \"check\",\n        iconColor: \"text-zinc-500\",\n      },\n    ],\n  },\n  {\n    id: \"enterprise\",\n    title: \"Enterprise\",\n    description:\n      \"For organizations that need more support and compliance features.\",\n    currency: \"$\",\n    monthlyPrice: \"Custom\",\n    yearlyPrice: \"Custom\",\n    buttonText: \"Contact sales\",\n    features: [\n      {\n        name: \"Presence\",\n        icon: \"check\",\n        iconColor: \"text-green-500\",\n      },\n      {\n        name: \"Comments\",\n        icon: \"check\",\n        iconColor: \"text-orange-500\",\n      },\n      {\n        name: \"Notifications\",\n        icon: \"check\",\n        iconColor: \"text-teal-500\",\n      },\n      {\n        name: \"Text Editor\",\n        icon: \"check\",\n        iconColor: \"text-blue-500\",\n      },\n      {\n        name: \"Sync Datastore\",\n        icon: \"check\",\n        iconColor: \"text-zinc-500\",\n      },\n    ],\n  },\n];\n",
      "type": "registry:lib",
      "target": "lib/billingsdk-config.ts"
    }
  ],
  "type": "registry:block"
}
