Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion next/components/organisms/PaymentSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ export default function PaymentSystem({
}) {
const [clientSecret, setClientSecret] = useState("")

useEffect(() => {
if (clientSecret === null) onSucess(true)
}, [clientSecret])

const appearance = {
theme: "stripe",
variables: {
Expand Down Expand Up @@ -148,6 +152,14 @@ export default function PaymentSystem({
}

const customerCreatPost = async (id, coupon) => {
const trial = await fetch(`/api/stripe/startChatbotTrial?p=${btoa(id)}`, {method: "GET"})
.then(res => res.json())

if (trial?.started) {
setClientSecret(null)
return isLoading(false)
}

const clientSecret = await fetch(`/api/stripe/createSubscription?p=${btoa(id)}&c=${btoa(coupon)}`, {method: "GET"})
.then(res => res.json())

Expand All @@ -172,7 +184,9 @@ export default function PaymentSystem({
if(type === "bnt") return <Skeleton height="40px" borderRadius="12px" startColor="#F0F0F0" endColor="#F3F3F3" {...props}/>
}

if(!clientSecret) return (
if(clientSecret === null) return null

if(clientSecret === "") return (
<Stack flex={1}>
<Stack width="100%" flexDirection="row" spacing={0} gap="8px" marginBottom="16px !important">
<Stack width="100%" spacing={0} gap="8px">
Expand Down
215 changes: 139 additions & 76 deletions next/components/organisms/componentsUserPage/PlansAndPayment.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,36 @@ import BodyText from "../../atoms/Text/BodyText";
import Toggle from "../../atoms/Toggle";
import { SectionPrice } from "../../../pages/prices";
import PaymentSystem from "../../organisms/PaymentSystem";
import { triggerGAEvent, triggerGAEventWithData, hasBDProSubscription, hasChatbotSubscription, getChatbotStreamlitAppUrl } from "../../../utils";
import { triggerGAEvent, triggerGAEventWithData, hasBDProSubscription, hasChatbotSubscription, getChatbotStreamlitAppUrl, getSubscriptionStatusKey, isSubscriptionTrialing } from "../../../utils";

const SubscriptionBadgeStyles = {
active: { backgroundColor: "#D5E8DB", color: "#2B8C4D" },
canceled: { backgroundColor: "#F6E3E3", color: "#BF3434" },
trial: { backgroundColor: "#E8F2FC", color: "#0068C5" },
}

function SubscriptionStatusBadge({ subscription, t, fallbackStatus = "active" }) {
const statusKey = subscription ? getSubscriptionStatusKey(subscription) : fallbackStatus
const badgeStyle = SubscriptionBadgeStyles[statusKey] || SubscriptionBadgeStyles.active;

return (
<Badge
width="fit-content"
padding="2px 4px"
textTransform="none"
borderRadius="6px"
backgroundColor={badgeStyle.backgroundColor}
color={badgeStyle.color}
fontSize="12px"
lineHeight="18px"
fontFamily="Roboto"
fontWeight="500"
letterSpacing="0.1px"
>
{t(`username.${statusKey}`)}
</Badge>
)
}

import {
TitleTextForm,
Expand Down Expand Up @@ -111,11 +140,15 @@ export default function PlansAndPayment ({ userData }) {
const [isLoadingH, setIsLoadingH] = useState(false)
const [isLoadingCanSub, setIsLoadingCanSub] = useState(false)
const [isLoadingClientSecret, setIsLoadingClientSecret] = useState(true)
const [hasSubscribed, setHasSubscribed] = useState(true)
const [hasSubscribedBDPro, setHasSubscribedBDPro] = useState(true)
const [hasSubscribedChatbot, setHasSubscribedChatbot] = useState(true)
const [hasSubscribedLoaded, setHasSubscribedLoaded] = useState(false)
const [plans, setPlans] = useState(null)
const [toggleAnual, setToggleAnual] = useState(true)
const [subscriptionToCancel, setSubscriptionToCancel] = useState("bd_pro")
const [checkoutStep, setCheckoutStep] = useState("plan")
const [isChatbotTrialSuccess, setIsChatbotTrialSuccess] = useState(false)
const [isStartingChatbotTrial, setIsStartingChatbotTrial] = useState(false)
const successCheckoutKindRef = useRef(null)

const internalSubscriptions = userData?.internalSubscription?.edges?.map((edge) => edge?.node) || []
Expand All @@ -129,16 +162,32 @@ export default function PlansAndPayment ({ userData }) {
}) || null

async function alreadySubscribed(id) {
const result = await fetch(`/api/user/getAlreadySubscribed?p=${btoa(id)}`)
.then(res => res.json())
setHasSubscribed(result)
try {
const [bdPro, chatbot] = await Promise.all([
fetch(`/api/user/getAlreadySubscribed?p=${btoa(id)}&type=bd_pro`).then(res => res.json()),
fetch(`/api/user/getAlreadySubscribed?p=${btoa(id)}&type=chatbot`).then(res => res.json()),
])
setHasSubscribedBDPro(bdPro)
setHasSubscribedChatbot(chatbot)
} catch (error) {
console.error(error)
setHasSubscribedBDPro(false)
setHasSubscribedChatbot(false)
} finally {
setHasSubscribedLoaded(true)
}
}

useEffect(() => {
const reg = new RegExp("(?<=:).*")
const [ id ] = reg.exec(userData.id)
const match = reg.exec(userData.id)

if (!match) {
setHasSubscribedLoaded(true)
return
}

alreadySubscribed(id)
alreadySubscribed(match[0])
}, [userData?.id])

useEffect(() => {
Expand Down Expand Up @@ -193,6 +242,7 @@ export default function PlansAndPayment ({ userData }) {
useEffect(() => {
if(plans === null) return
if(plan === "") return
if(!hasSubscribedLoaded) return

const value = Object.values(plans).find(elm => elm?._id === plan)
if (!value) return
Expand All @@ -217,12 +267,16 @@ export default function PlansAndPayment ({ userData }) {
const checkoutAlreadyVisible = PaymentModal.isOpen || EmailModal.isOpen
if (!checkoutAlreadyVisible) {
if (isChatbotType) {
openCheckoutPlanStep()
if (!hasSubscribedChatbot) {
startChatbotTrialFlow()
} else {
openCheckoutPlanStep()
}
} else {
EmailModal.onOpen()
}
}
}, [plan, plans, userData, chatbotSubscriptionInfo])
}, [plan, plans, userData, chatbotSubscriptionInfo, hasSubscribedLoaded, hasSubscribedChatbot])

useEffect(() => {
if (!plans || plan !== "") return
Expand Down Expand Up @@ -273,7 +327,9 @@ export default function PlansAndPayment ({ userData }) {

const planActive = hasBDProSubscription(userData)
const hasChatbotActiveSubscription = hasChatbotSubscription(userData)
const isChatbotTrial = isSubscriptionTrialing(chatbotSubscriptionInfo)
const isChatbotCheckout = checkoutInfos?.productName?.toLowerCase().includes("chatbot") || checkoutInfos?.productSlug?.toLowerCase().includes("chatbot")
const hasSubscribed = isChatbotCheckout ? hasSubscribedChatbot : hasSubscribedBDPro

function getCheckoutStepLabel() {
if (checkoutStep === "plan") {
Expand All @@ -297,6 +353,36 @@ export default function PlansAndPayment ({ userData }) {
PaymentModal.onOpen()
}

function openCheckoutPaymentStep() {
setCheckoutStep("payment")
setIsLoadingClientSecret(true)
PaymentModal.onOpen()
}

async function startChatbotTrialFlow() {
setIsStartingChatbotTrial(true)

try {
const trial = await fetch(`/api/stripe/startChatbotTrial?p=${btoa(plan)}`, {
method: "GET",
}).then((res) => res.json())

if (trial?.started) {
successCheckoutKindRef.current = "chatbot"
setIsChatbotTrialSuccess(true)
SucessPaymentModal.onOpen()
return
}

openCheckoutPaymentStep()
} catch (error) {
console.error(error)
openCheckoutPaymentStep()
} finally {
setIsStartingChatbotTrial(false)
}
}

function goBackFromPlanStep() {
PaymentModal.onClose()
if (isChatbotCheckout) {
Expand Down Expand Up @@ -391,7 +477,6 @@ export default function PlansAndPayment ({ userData }) {

const defaultResource = resources["BD Gratis"]
const planResource = resources[userData?.proSubscription]
const planCanceled = bdProSubscriptionInfo?.canceledAt

const controlResource = () => {
if (!planActive || !planResource) return defaultResource
Expand Down Expand Up @@ -453,11 +538,12 @@ export default function PlansAndPayment ({ userData }) {
)
}

const openModalSucess = () => {
const openModalSucess = (isTrial = false) => {
const isChatbotPurchase =
checkoutInfos?.productName?.toLowerCase().includes("chatbot") ||
checkoutInfos?.productSlug?.toLowerCase().includes("chatbot")
successCheckoutKindRef.current = isChatbotPurchase ? "chatbot" : "bd_pro"
setIsChatbotTrialSuccess(isTrial)
PaymentModal.onClose()
SucessPaymentModal.onOpen()
}
Expand Down Expand Up @@ -512,6 +598,7 @@ export default function PlansAndPayment ({ userData }) {
}

successCheckoutKindRef.current = null
setIsChatbotTrialSuccess(false)

if(isLoadingH === true) return window.open("/", "_self")
window.open(`/user/${userData.username}?plans_and_payment`, "_self")
Expand Down Expand Up @@ -659,6 +746,7 @@ export default function PlansAndPayment ({ userData }) {
useEffect(() => {
const onPopState = () => {
successCheckoutKindRef.current = null
setIsChatbotTrialSuccess(false)
setIsLoading(false)
setIsLoadingH(false)
SucessPaymentModal.onClose()
Expand All @@ -670,7 +758,7 @@ export default function PlansAndPayment ({ userData }) {
return (
<Stack spacing={0}>
<Box
display={isLoading || isLoadingH ? "flex" : "none"}
display={isLoading || isLoadingH || isStartingChatbotTrial ? "flex" : "none"}
position="fixed"
top="0"
left="0"
Expand Down Expand Up @@ -949,7 +1037,7 @@ export default function PlansAndPayment ({ userData }) {
userData={userData}
plan={plan}
coupon={coupon}
onSucess={() => openModalSucess()}
onSucess={(isTrial) => openModalSucess(isTrial)}
onErro={() => openModalErro()}
isLoading={(e) => setIsLoadingClientSecret(e)}
/>
Expand Down Expand Up @@ -1107,27 +1195,35 @@ export default function PlansAndPayment ({ userData }) {
<SuccessIcon width="90px" height="64px" fill="#34A15A" />
<TitleText>
{isChatbotCheckout
? t("username.chatbotSubscriptionSuccessTitle")
? isChatbotTrialSuccess
? t("username.chatbotTrialSuccessTitle")
: t("username.chatbotSubscriptionSuccessTitle")
: t("username.congratulations")}
</TitleText>
{isChatbotCheckout ? (
<BodyText color="#464A51">
<Trans
t={t}
i18nKey="username.chatbotSubscriptionSuccessDescription"
components={{
1: (
<Text
as="a"
href="/contact"
target="_self"
color="#0068C5"
_hover={{ color: "#0057A4" }}
/>
),
}}
/>
</BodyText>
isChatbotTrialSuccess ? (
<BodyText color="#464A51">
{t("username.chatbotTrialSuccessDescription")}
</BodyText>
) : (
<BodyText color="#464A51">
<Trans
t={t}
i18nKey="username.chatbotSubscriptionSuccessDescription"
components={{
1: (
<Text
as="a"
href="/contact"
target="_self"
color="#0068C5"
_hover={{ color: "#0057A4" }}
/>
),
}}
/>
</BodyText>
)
) : (
<BodyText color="#464A51">
{t("username.BQEmailDescription4")}{" "}
Expand Down Expand Up @@ -1173,6 +1269,7 @@ export default function PlansAndPayment ({ userData }) {
width={{ base: "100%", lg: "50%" }}
onClick={() => {
successCheckoutKindRef.current = null;
setIsChatbotTrialSuccess(false);
setIsLoading(false);
setIsLoadingH(false);
SucessPaymentModal.onClose();
Expand Down Expand Up @@ -1428,29 +1525,12 @@ export default function PlansAndPayment ({ userData }) {
justifyContent="space-between"
>
<Stack spacing="8px" marginBottom={{ base: "16px", lg: "0" }}>
<Badge
width="fit-content"
padding="2px 4px"
textTransform="none"
borderRadius="6px"
backgroundColor={
planActive ? (planCanceled ? "#F6E3E3" : "#D5E8DB") : "#D5E8DB"
}
color={
planActive ? (planCanceled ? "#BF3434" : "#2B8C4D") : "#2B8C4D"
}
fontSize="12px"
lineHeight="18px"
fontFamily="Roboto"
fontWeight="500"
letterSpacing="0.1px"
>
{planActive
? planCanceled
? t("username.canceled")
: t("username.active")
: t("username.active")}
</Badge>
{planActive && (
<SubscriptionStatusBadge
subscription={bdProSubscriptionInfo}
t={t}
/>
)}

<Box
display="flex"
Expand Down Expand Up @@ -1614,27 +1694,10 @@ export default function PlansAndPayment ({ userData }) {
marginTop="8px"
>
{hasChatbotActiveSubscription && (
<Badge
width="fit-content"
padding="2px 4px"
textTransform="none"
borderRadius="6px"
backgroundColor={
chatbotSubscriptionInfo?.canceledAt ? "#F6E3E3" : "#D5E8DB"
}
color={
chatbotSubscriptionInfo?.canceledAt ? "#BF3434" : "#2B8C4D"
}
fontSize="12px"
lineHeight="18px"
fontFamily="Roboto"
fontWeight="500"
letterSpacing="0.1px"
>
{chatbotSubscriptionInfo?.canceledAt
? t("username.canceled")
: t("username.active")}
</Badge>
<SubscriptionStatusBadge
subscription={chatbotSubscriptionInfo}
t={t}
/>
)}
<Box
display="flex"
Expand All @@ -1661,7 +1724,7 @@ export default function PlansAndPayment ({ userData }) {
>
{t("username.chatbotNewBadge")}
</Badge>
{chatbotSubscriptionInfo?.planInterval && (
{chatbotSubscriptionInfo?.planInterval && !isChatbotTrial && (
<LabelText typography="x-small" color="#71757A">
{formattedPlanInterval(
chatbotSubscriptionInfo?.planInterval,
Expand Down
Loading