shellphone.app/app/settings/hooks/use-subscription.ts

118 lines
3.0 KiB
TypeScript
Raw Normal View History

import { useEffect, useRef, useState } from "react";
import { useQuery, useMutation, useSession } from "blitz";
2021-09-26 22:44:26 +00:00
2021-09-30 22:18:03 +00:00
import type { Subscription } from "db";
import { SubscriptionStatus } from "db";
2021-09-26 22:44:26 +00:00
import getSubscription from "../queries/get-subscription";
import usePaddle from "./use-paddle";
import useCurrentUser from "../../core/hooks/use-current-user";
import updateSubscription from "../mutations/update-subscription";
2021-09-30 22:18:03 +00:00
type Params = {
initialData?: Subscription;
};
export default function useSubscription({ initialData }: Params = {}) {
2021-09-26 22:44:26 +00:00
const session = useSession();
const { user } = useCurrentUser();
const [isWaitingForSubChange, setIsWaitingForSubChange] = useState(false);
const [subscription] = useQuery(getSubscription, null, {
initialData,
refetchInterval: isWaitingForSubChange ? 1500 : false,
});
2021-09-26 22:44:26 +00:00
const [updateSubscriptionMutation] = useMutation(updateSubscription);
const resolve = useRef<() => void>();
const promise = useRef<Promise<void>>();
const { Paddle } = usePaddle({
eventCallback(data) {
if (["Checkout.Close", "Checkout.Complete"].includes(data.event)) {
resolve.current!();
promise.current = new Promise((r) => (resolve.current = r));
}
},
});
// cancel subscription polling when we get a new subscription
useEffect(() => setIsWaitingForSubChange(false), [subscription?.paddleSubscriptionId, subscription?.status]);
2021-09-26 22:44:26 +00:00
useEffect(() => {
promise.current = new Promise((r) => (resolve.current = r));
}, []);
type BuyParams = {
planId: number;
2021-09-26 22:44:26 +00:00
coupon?: string;
};
async function subscribe(params: BuyParams) {
if (!user || !session.orgId) {
return;
}
const { planId, coupon } = params;
const checkoutOpenParams = {
email: user.email,
product: planId,
allowQuantity: false,
2021-09-30 22:59:35 +00:00
passthrough: JSON.stringify({ organizationId: session.orgId }),
2021-09-26 22:44:26 +00:00
coupon: "",
};
if (coupon) {
checkoutOpenParams.coupon = coupon;
}
Paddle.Checkout.open(checkoutOpenParams);
setIsWaitingForSubChange(true);
2021-09-26 22:44:26 +00:00
return promise.current;
}
async function updatePaymentMethod({ updateUrl }: { updateUrl: string }) {
const checkoutOpenParams = { override: updateUrl };
Paddle.Checkout.open(checkoutOpenParams);
setIsWaitingForSubChange(true);
2021-09-26 22:44:26 +00:00
return promise.current;
}
async function cancelSubscription({ cancelUrl }: { cancelUrl: string }) {
const checkoutOpenParams = { override: cancelUrl };
Paddle.Checkout.open(checkoutOpenParams);
setIsWaitingForSubChange(true);
2021-09-26 22:44:26 +00:00
return promise.current;
}
type ChangePlanParams = {
planId: number;
2021-09-26 22:44:26 +00:00
};
async function changePlan({ planId }: ChangePlanParams) {
if (planId === -1) {
return cancelSubscription({ cancelUrl: subscription!.cancelUrl });
}
2021-09-26 22:44:26 +00:00
try {
await updateSubscriptionMutation({ planId });
} catch (error) {
console.log("error", error);
}
}
const hasActiveSubscription = Boolean(subscription && subscription?.status !== SubscriptionStatus.deleted);
2021-09-26 22:44:26 +00:00
return {
subscription,
hasActiveSubscription,
2021-09-26 22:44:26 +00:00
subscribe,
updatePaymentMethod,
cancelSubscription,
changePlan,
};
}