From 14bb8e572532993eb4f1dc2691a8e0b7aeeb3bc4 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 18:06:22 +0000 Subject: [PATCH 1/3] Changes Co-authored-by: domfelipe <53182096+domfelipe@users.noreply.github.com> --- .../mika/CancellationScheduledBanner.tsx | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/components/mika/CancellationScheduledBanner.tsx diff --git a/src/components/mika/CancellationScheduledBanner.tsx b/src/components/mika/CancellationScheduledBanner.tsx new file mode 100644 index 0000000..191fe6f --- /dev/null +++ b/src/components/mika/CancellationScheduledBanner.tsx @@ -0,0 +1,86 @@ +"use client"; + +import { useState } from "react"; +import { CalendarClock, Loader2, RotateCcw } from "lucide-react"; +import { format } from "date-fns"; +import { ptBR } from "date-fns/locale"; +import { toast } from "sonner"; +import { supabase } from "@/integrations/supabase/client"; +import { useSubscription } from "@/hooks/use-profile"; +import { Button } from "@/components/ui/button"; + +/** + * Discrete banner shown when the subscription is scheduled to be canceled + * at the end of the current period (cancel_at_period_end = true) but is + * still active. Tells the user until when access remains and offers a + * one-click way to reactivate via the Paddle customer portal. + */ +export function CancellationScheduledBanner() { + const { data: subscription } = useSubscription(); + const [loading, setLoading] = useState(false); + + const isActive = subscription?.status === "active" || subscription?.status === "trialing"; + const scheduled = !!subscription?.cancel_at_period_end && isActive; + + if (!scheduled) return null; + + const endsAt = subscription?.current_period_end + ? format(new Date(subscription.current_period_end), "d 'de' MMMM 'de' yyyy", { + locale: ptBR, + }) + : null; + + const openPortal = async () => { + setLoading(true); + try { + const { data, error } = await supabase.functions.invoke("create-portal-session"); + if (error || !data?.url) { + toast.error("Não foi possível abrir o portal. Tente novamente."); + return; + } + window.open(data.url, "_blank", "noopener,noreferrer"); + } finally { + setLoading(false); + } + }; + + return ( +
+ Sua assinatura foi cancelada + {endsAt ? ( + <> + {" "}e expira em{" "} + {endsAt}. + > + ) : ( + " e expirará no fim do período atual." + )}{" "} + Você ainda tem acesso até lá. +
+