diff --git a/actions/reactivateSubscription.ts b/actions/reactivateSubscription.ts new file mode 100644 index 00000000..fab67d04 --- /dev/null +++ b/actions/reactivateSubscription.ts @@ -0,0 +1,40 @@ +"use server"; + +import { getIdentityData } from "./getIdentityData"; +import { getStripe } from "stripe/client"; +import { supabaseServerClient } from "supabase/serverClient"; +import { Ok, Err, type Result } from "src/result"; + +export async function reactivateSubscription(): Promise< + Result<{ renewsAt: string }, string> +> { + const identity = await getIdentityData(); + if (!identity) { + return Err("Not authenticated"); + } + + const { data: sub } = await supabaseServerClient + .from("user_subscriptions") + .select("stripe_subscription_id, current_period_end") + .eq("identity_id", identity.id) + .single(); + + if (!sub?.stripe_subscription_id) { + return Err("No active subscription found"); + } + + await getStripe().subscriptions.update(sub.stripe_subscription_id, { + cancel_at_period_end: false, + }); + + // Optimistic update + await supabaseServerClient + .from("user_subscriptions") + .update({ + status: "active", + updated_at: new Date().toISOString(), + }) + .eq("identity_id", identity.id); + + return Ok({ renewsAt: sub.current_period_end || "" }); +} diff --git a/app/lish/[did]/[publication]/dashboard/settings/ManageProSubscription.tsx b/app/lish/[did]/[publication]/dashboard/settings/ManageProSubscription.tsx index e5a220a6..2723baa2 100644 --- a/app/lish/[did]/[publication]/dashboard/settings/ManageProSubscription.tsx +++ b/app/lish/[did]/[publication]/dashboard/settings/ManageProSubscription.tsx @@ -2,6 +2,7 @@ import { useState } from "react"; import { ButtonPrimary } from "components/Buttons"; import { PubSettingsHeader } from "./PublicationSettings"; import { cancelSubscription } from "actions/cancelSubscription"; +import { reactivateSubscription } from "actions/reactivateSubscription"; import { useIdentityData } from "components/IdentityProvider"; import { DotLoader } from "components/utils/DotLoader"; import { useLocalizedDate } from "src/hooks/useLocalizedDate"; @@ -17,7 +18,7 @@ export const ManageProSubscription = (props: { backToMenu: () => void }) => { const subscription = identity?.subscription; const renewalDate = useLocalizedDate( subscription?.current_period_end || new Date().toISOString(), - { month: "long", day: "numeric" }, + { month: "long", day: "numeric", year: "numeric" }, ); async function handleCancel() { @@ -33,6 +34,18 @@ export const ManageProSubscription = (props: { backToMenu: () => void }) => { setLoading(false); } + async function handleReactivate() { + setLoading(true); + setError(null); + let result = await reactivateSubscription(); + if (result.ok) { + mutate(); + } else { + setError(result.error); + } + setLoading(false); + } + return (