add direct link to Stripe Customer Portal
This commit is contained in:
parent
71ceeb533f
commit
56c90d9c83
@ -10,6 +10,7 @@ import {
|
||||
} from "../ui/dropdown-menu";
|
||||
import { useStore } from "../../store/store";
|
||||
import { capitalize } from "./utils";
|
||||
import StripeCustomerPortalLink from "./StripeCustomerPortalLink";
|
||||
|
||||
export default function AvatarDropdown() {
|
||||
const { user, isLoaded, isSignedIn } = useUser();
|
||||
@ -55,12 +56,7 @@ export default function AvatarDropdown() {
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild={true}>
|
||||
<a
|
||||
href="https://billing.stripe.com/p/login/dR65nxfkLgvldyg9AA"
|
||||
target="_blank"
|
||||
>
|
||||
Cancel subscription
|
||||
</a>
|
||||
<StripeCustomerPortalLink label="Cancel subscription" />
|
||||
</DropdownMenuItem>
|
||||
</>
|
||||
)}
|
||||
|
||||
48
frontend/src/components/hosted/StripeCustomerPortalLink.tsx
Normal file
48
frontend/src/components/hosted/StripeCustomerPortalLink.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
import toast from "react-hot-toast";
|
||||
import { useAuthenticatedFetch } from "./useAuthenticatedFetch";
|
||||
import { addEvent } from "../../lib/analytics";
|
||||
import { SAAS_BACKEND_URL } from "../../config";
|
||||
import { PortalSessionResponse } from "./types";
|
||||
import { forwardRef, useState } from "react";
|
||||
import Spinner from "../custom-ui/Spinner";
|
||||
|
||||
interface Props {
|
||||
label: string;
|
||||
}
|
||||
|
||||
const StripeCustomerPortalLink = forwardRef<HTMLAnchorElement, Props>(
|
||||
({ label, ...props }, ref) => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const authenticatedFetch = useAuthenticatedFetch();
|
||||
|
||||
const redirectToBillingPortal = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const res: PortalSessionResponse = await authenticatedFetch(
|
||||
SAAS_BACKEND_URL + "/payments/create_portal_session",
|
||||
"POST"
|
||||
);
|
||||
window.location.href = res.url;
|
||||
} catch (e) {
|
||||
toast.error(
|
||||
"Error directing you to the billing portal. Please email support and we'll get it fixed right away."
|
||||
);
|
||||
addEvent("StripeBillingPortalError");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<a {...props} ref={ref} onClick={redirectToBillingPortal}>
|
||||
<div className="flex gap-x-2">
|
||||
{label} {isLoading && <Spinner />}
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
StripeCustomerPortalLink.displayName = "StripeCustomerPortalLink";
|
||||
|
||||
export default StripeCustomerPortalLink;
|
||||
@ -6,3 +6,7 @@ export interface UserResponse {
|
||||
subscriber_tier: string;
|
||||
stripe_customer_id: string;
|
||||
}
|
||||
|
||||
export interface PortalSessionResponse {
|
||||
url: string;
|
||||
}
|
||||
|
||||
@ -2,6 +2,9 @@ import { useAuth } from "@clerk/clerk-react";
|
||||
|
||||
type FetchMethod = "GET" | "POST" | "PUT" | "DELETE";
|
||||
|
||||
// Assumes that the backend is using JWTs for authentication
|
||||
// and assumes JSON responses
|
||||
// *If response code is not 200 OK or if there's any other error, throws an error
|
||||
export const useAuthenticatedFetch = () => {
|
||||
const { getToken } = useAuth();
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user