Skip to content

Commit

Permalink
Stripe Cancel + UI (#1010)
Browse files Browse the repository at this point in the history
Co-authored-by: Aakaash Meduri <[email protected]>
  • Loading branch information
supraja-968 and acashmoney authored Aug 2, 2024
1 parent 5db00b2 commit b9a5b19
Show file tree
Hide file tree
Showing 14 changed files with 958 additions and 188 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export default function NewExperimentForm({ task }: { task: any }) {
}
} else if (userTier === 'Paid') {
if (isUserSubscribed) {
// Paid tier user with active subscription (including trial), directly create the experiment
// Paid tier user with active subscription, directly create the experiment
const response = await dispatch(addExperimentThunk(transformedPayload)).unwrap();
if (response && response.ID) {
console.log("Experiment created", response);
Expand All @@ -107,21 +107,9 @@ export default function NewExperimentForm({ task }: { task: any }) {
toast.error("Failed to start experiment");
}
} else {
// Paid tier user without active subscription, initiate checkout process
const result = await dispatch(addExperimentWithCheckoutThunk(transformedPayload)).unwrap();
if (result.checkout) {
// User needs to subscribe, redirect to checkout
window.location.href = result.checkout.url;
} else if (result && result.ID) {
// Experiment was created successfully (this case might not occur for non-subscribed users)
console.log("Experiment created", result);
router.push(`/experiments/${result.ID}`, { scroll: false });
dispatch(experimentListThunk(walletAddress));
toast.success("Experiment started successfully");
} else {
console.log("Something went wrong", result);
toast.error("Failed to start experiment");
}
// Paid tier user without active subscription, redirect to subscription page
console.log('Redirecting...');
router.push('/subscribe');
}
} else {
console.error("Invalid user tier");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,8 @@ export default function RerunExperimentForm() {
toast.error("Failed to add job to experiment");
}
} else if (userTier === 'Paid' && !isUserSubscribed) {
const checkoutResponse = await dispatch(addExperimentWithCheckoutThunk(transformedPayload)).unwrap();
if (checkoutResponse.checkout) {
window.location.href = checkoutResponse.checkout.url;
} else {
console.log("Something went wrong with checkout", checkoutResponse);
toast.error("Failed to initiate subscription process");
}
console.log('Redirecting...');
router.push('/subscribe');
} else {
console.error("Invalid user tier");
toast.error("Unable to process request due to invalid user tier");
Expand Down
129 changes: 129 additions & 0 deletions frontend/app/subscribe/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
"use client";

import { usePrivy } from "@privy-io/react-auth";
import React, { useEffect, useState } from "react";
import { Breadcrumbs } from "@/components/global/Breadcrumbs";
import { toast } from "sonner";
import { getAccessToken } from "@privy-io/react-auth";
import backendUrl from "lib/backendUrl";
import { useRouter } from "next/navigation";
import getPlanTemplate, { PlanDetail } from "lib/planTemplate";
import StripeCheckoutButton from "@/components/payment/StripeCheckoutButton";

interface PlanDetails {
plan_name: string;
plan_amount: number;
plan_currency: string;
plan_interval: string;
included_credits: number;
overage_charge: number;
}

export default function SubscribePage() {
const { user } = usePrivy();
const walletAddress = user?.wallet?.address;
const [loading, setLoading] = useState(true);
const [planDetails, setPlanDetails] = useState<PlanDetails | null>(null);
const router = useRouter();

useEffect(() => {
const fetchPlanDetails = async () => {
try {
const authToken = await getAccessToken();
const response = await fetch(`${backendUrl()}/stripe/plan-details`, {
headers: {
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
},
});

if (response.ok) {
const data: PlanDetails = await response.json();
setPlanDetails(data);
setLoading(false);
} else {
console.error("Failed to fetch plan details. Response not OK.");
setLoading(false);
}
} catch (error) {
console.error("Failed to fetch plan details:", error);
setLoading(false);
}
};

const checkSubscriptionStatus = async () => {
try {
const authToken = await getAccessToken();

const response = await fetch(`${backendUrl()}/stripe/subscription/check`, {
headers: {
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
},
});

if (response.ok) {
const data = await response.json();
if (data.isSubscribed) {
router.replace("/subscription/manage");
} else {
fetchPlanDetails();
}
} else {
console.error("Failed to check subscription status. Response not OK.");
setLoading(false);
}
} catch (error) {
console.error("Failed to check subscription status:", error);
setLoading(false);
}
};

if (walletAddress) {
checkSubscriptionStatus();
} else {
console.log("Waiting for wallet address...");
}
}, [router, walletAddress]);

if (loading || !walletAddress || !planDetails) {
return <div>Loading...</div>;
}

return (
<div className="relative flex flex-col h-screen max-w-full grow">
<Breadcrumbs
items={[
{ name: "Subscribe", href: "/subscribe" },
{ name: walletAddress, href: `/subscribe/${walletAddress}` },
]}
actions={null}
/>
<div className="flex flex-col items-center justify-between w-[706px] h-[400px] p-8 bg-white rounded-lg shadow-lg mx-auto my-6">
<h3 className="text-center font-heading" style={{ fontSize: '33px', fontWeight: 500, lineHeight: '43.2px', letterSpacing: '0.5px', color: '#000000'}}>
Become a lab.bio subscriber
</h3>
<div className="text-sm text-gray-600 space-y-4 font-mono" style={{ fontSize: '15px', lineHeight: '25px', letterSpacing: '0.3px', color: '#000000' }}>
{getPlanTemplate().details.map((detail: PlanDetail, index: number) => (
<div key={index} className="flex items-start">
<span className="mr-2 text-black"></span>
<span>{detail.description
.replace('{{includedCredits}}', planDetails.included_credits.toString())
.replace('{{numMolecules}}', (planDetails.included_credits / 10).toString()) // Example calculation
.replace('{{overageCharge}}', planDetails.overage_charge.toString())
}</span>
</div>
))}
</div>
<p className="mt-4 text-center font-heading" style={{ fontSize: '24px', lineHeight: '30px', letterSpacing: '0.14px', color: '#000000', fontWeight: '500' }}>
${planDetails.plan_amount} / month
</p>
<div className="px-2 py-2 w-full">
<StripeCheckoutButton color="primary" size="sm" className="w-full font-bold">
Start now
</StripeCheckoutButton>
</div>
</div>
</div>
);
}
Loading

0 comments on commit b9a5b19

Please sign in to comment.