Skip to content

Commit ae47967

Browse files
authored
Merge pull request #1588 from basedosdados/feat/trial-chatbot
Feat/trial chatbot
2 parents 622195e + d718774 commit ae47967

12 files changed

Lines changed: 270 additions & 97 deletions

File tree

next/components/organisms/PaymentSystem.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ export default function PaymentSystem({
9090
}) {
9191
const [clientSecret, setClientSecret] = useState("")
9292

93+
useEffect(() => {
94+
if (clientSecret === null) onSucess(true)
95+
}, [clientSecret])
96+
9397
const appearance = {
9498
theme: "stripe",
9599
variables: {
@@ -148,6 +152,14 @@ export default function PaymentSystem({
148152
}
149153

150154
const customerCreatPost = async (id, coupon) => {
155+
const trial = await fetch(`/api/stripe/startChatbotTrial?p=${btoa(id)}`, {method: "GET"})
156+
.then(res => res.json())
157+
158+
if (trial?.started) {
159+
setClientSecret(null)
160+
return isLoading(false)
161+
}
162+
151163
const clientSecret = await fetch(`/api/stripe/createSubscription?p=${btoa(id)}&c=${btoa(coupon)}`, {method: "GET"})
152164
.then(res => res.json())
153165

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

175-
if(!clientSecret) return (
187+
if(clientSecret === null) return null
188+
189+
if(clientSecret === "") return (
176190
<Stack flex={1}>
177191
<Stack width="100%" flexDirection="row" spacing={0} gap="8px" marginBottom="16px !important">
178192
<Stack width="100%" spacing={0} gap="8px">

next/components/organisms/componentsUserPage/PlansAndPayment.js

Lines changed: 139 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,36 @@ import BodyText from "../../atoms/Text/BodyText";
2323
import Toggle from "../../atoms/Toggle";
2424
import { SectionPrice } from "../../../pages/prices";
2525
import PaymentSystem from "../../organisms/PaymentSystem";
26-
import { triggerGAEvent, triggerGAEventWithData, hasBDProSubscription, hasChatbotSubscription, getChatbotStreamlitAppUrl } from "../../../utils";
26+
import { triggerGAEvent, triggerGAEventWithData, hasBDProSubscription, hasChatbotSubscription, getChatbotStreamlitAppUrl, getSubscriptionStatusKey, isSubscriptionTrialing } from "../../../utils";
27+
28+
const SubscriptionBadgeStyles = {
29+
active: { backgroundColor: "#D5E8DB", color: "#2B8C4D" },
30+
canceled: { backgroundColor: "#F6E3E3", color: "#BF3434" },
31+
trial: { backgroundColor: "#E8F2FC", color: "#0068C5" },
32+
}
33+
34+
function SubscriptionStatusBadge({ subscription, t, fallbackStatus = "active" }) {
35+
const statusKey = subscription ? getSubscriptionStatusKey(subscription) : fallbackStatus
36+
const badgeStyle = SubscriptionBadgeStyles[statusKey] || SubscriptionBadgeStyles.active;
37+
38+
return (
39+
<Badge
40+
width="fit-content"
41+
padding="2px 4px"
42+
textTransform="none"
43+
borderRadius="6px"
44+
backgroundColor={badgeStyle.backgroundColor}
45+
color={badgeStyle.color}
46+
fontSize="12px"
47+
lineHeight="18px"
48+
fontFamily="Roboto"
49+
fontWeight="500"
50+
letterSpacing="0.1px"
51+
>
52+
{t(`username.${statusKey}`)}
53+
</Badge>
54+
)
55+
}
2756

2857
import {
2958
TitleTextForm,
@@ -111,11 +140,15 @@ export default function PlansAndPayment ({ userData }) {
111140
const [isLoadingH, setIsLoadingH] = useState(false)
112141
const [isLoadingCanSub, setIsLoadingCanSub] = useState(false)
113142
const [isLoadingClientSecret, setIsLoadingClientSecret] = useState(true)
114-
const [hasSubscribed, setHasSubscribed] = useState(true)
143+
const [hasSubscribedBDPro, setHasSubscribedBDPro] = useState(true)
144+
const [hasSubscribedChatbot, setHasSubscribedChatbot] = useState(true)
145+
const [hasSubscribedLoaded, setHasSubscribedLoaded] = useState(false)
115146
const [plans, setPlans] = useState(null)
116147
const [toggleAnual, setToggleAnual] = useState(true)
117148
const [subscriptionToCancel, setSubscriptionToCancel] = useState("bd_pro")
118149
const [checkoutStep, setCheckoutStep] = useState("plan")
150+
const [isChatbotTrialSuccess, setIsChatbotTrialSuccess] = useState(false)
151+
const [isStartingChatbotTrial, setIsStartingChatbotTrial] = useState(false)
119152
const successCheckoutKindRef = useRef(null)
120153

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

131164
async function alreadySubscribed(id) {
132-
const result = await fetch(`/api/user/getAlreadySubscribed?p=${btoa(id)}`)
133-
.then(res => res.json())
134-
setHasSubscribed(result)
165+
try {
166+
const [bdPro, chatbot] = await Promise.all([
167+
fetch(`/api/user/getAlreadySubscribed?p=${btoa(id)}&type=bd_pro`).then(res => res.json()),
168+
fetch(`/api/user/getAlreadySubscribed?p=${btoa(id)}&type=chatbot`).then(res => res.json()),
169+
])
170+
setHasSubscribedBDPro(bdPro)
171+
setHasSubscribedChatbot(chatbot)
172+
} catch (error) {
173+
console.error(error)
174+
setHasSubscribedBDPro(false)
175+
setHasSubscribedChatbot(false)
176+
} finally {
177+
setHasSubscribedLoaded(true)
178+
}
135179
}
136180

137181
useEffect(() => {
138182
const reg = new RegExp("(?<=:).*")
139-
const [ id ] = reg.exec(userData.id)
183+
const match = reg.exec(userData.id)
184+
185+
if (!match) {
186+
setHasSubscribedLoaded(true)
187+
return
188+
}
140189

141-
alreadySubscribed(id)
190+
alreadySubscribed(match[0])
142191
}, [userData?.id])
143192

144193
useEffect(() => {
@@ -193,6 +242,7 @@ export default function PlansAndPayment ({ userData }) {
193242
useEffect(() => {
194243
if(plans === null) return
195244
if(plan === "") return
245+
if(!hasSubscribedLoaded) return
196246

197247
const value = Object.values(plans).find(elm => elm?._id === plan)
198248
if (!value) return
@@ -217,12 +267,16 @@ export default function PlansAndPayment ({ userData }) {
217267
const checkoutAlreadyVisible = PaymentModal.isOpen || EmailModal.isOpen
218268
if (!checkoutAlreadyVisible) {
219269
if (isChatbotType) {
220-
openCheckoutPlanStep()
270+
if (!hasSubscribedChatbot) {
271+
startChatbotTrialFlow()
272+
} else {
273+
openCheckoutPlanStep()
274+
}
221275
} else {
222276
EmailModal.onOpen()
223277
}
224278
}
225-
}, [plan, plans, userData, chatbotSubscriptionInfo])
279+
}, [plan, plans, userData, chatbotSubscriptionInfo, hasSubscribedLoaded, hasSubscribedChatbot])
226280

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

274328
const planActive = hasBDProSubscription(userData)
275329
const hasChatbotActiveSubscription = hasChatbotSubscription(userData)
330+
const isChatbotTrial = isSubscriptionTrialing(chatbotSubscriptionInfo)
276331
const isChatbotCheckout = checkoutInfos?.productName?.toLowerCase().includes("chatbot") || checkoutInfos?.productSlug?.toLowerCase().includes("chatbot")
332+
const hasSubscribed = isChatbotCheckout ? hasSubscribedChatbot : hasSubscribedBDPro
277333

278334
function getCheckoutStepLabel() {
279335
if (checkoutStep === "plan") {
@@ -297,6 +353,36 @@ export default function PlansAndPayment ({ userData }) {
297353
PaymentModal.onOpen()
298354
}
299355

356+
function openCheckoutPaymentStep() {
357+
setCheckoutStep("payment")
358+
setIsLoadingClientSecret(true)
359+
PaymentModal.onOpen()
360+
}
361+
362+
async function startChatbotTrialFlow() {
363+
setIsStartingChatbotTrial(true)
364+
365+
try {
366+
const trial = await fetch(`/api/stripe/startChatbotTrial?p=${btoa(plan)}`, {
367+
method: "GET",
368+
}).then((res) => res.json())
369+
370+
if (trial?.started) {
371+
successCheckoutKindRef.current = "chatbot"
372+
setIsChatbotTrialSuccess(true)
373+
SucessPaymentModal.onOpen()
374+
return
375+
}
376+
377+
openCheckoutPaymentStep()
378+
} catch (error) {
379+
console.error(error)
380+
openCheckoutPaymentStep()
381+
} finally {
382+
setIsStartingChatbotTrial(false)
383+
}
384+
}
385+
300386
function goBackFromPlanStep() {
301387
PaymentModal.onClose()
302388
if (isChatbotCheckout) {
@@ -391,7 +477,6 @@ export default function PlansAndPayment ({ userData }) {
391477

392478
const defaultResource = resources["BD Gratis"]
393479
const planResource = resources[userData?.proSubscription]
394-
const planCanceled = bdProSubscriptionInfo?.canceledAt
395480

396481
const controlResource = () => {
397482
if (!planActive || !planResource) return defaultResource
@@ -453,11 +538,12 @@ export default function PlansAndPayment ({ userData }) {
453538
)
454539
}
455540

456-
const openModalSucess = () => {
541+
const openModalSucess = (isTrial = false) => {
457542
const isChatbotPurchase =
458543
checkoutInfos?.productName?.toLowerCase().includes("chatbot") ||
459544
checkoutInfos?.productSlug?.toLowerCase().includes("chatbot")
460545
successCheckoutKindRef.current = isChatbotPurchase ? "chatbot" : "bd_pro"
546+
setIsChatbotTrialSuccess(isTrial)
461547
PaymentModal.onClose()
462548
SucessPaymentModal.onOpen()
463549
}
@@ -512,6 +598,7 @@ export default function PlansAndPayment ({ userData }) {
512598
}
513599

514600
successCheckoutKindRef.current = null
601+
setIsChatbotTrialSuccess(false)
515602

516603
if(isLoadingH === true) return window.open("/", "_self")
517604
window.open(`/user/${userData.username}?plans_and_payment`, "_self")
@@ -659,6 +746,7 @@ export default function PlansAndPayment ({ userData }) {
659746
useEffect(() => {
660747
const onPopState = () => {
661748
successCheckoutKindRef.current = null
749+
setIsChatbotTrialSuccess(false)
662750
setIsLoading(false)
663751
setIsLoadingH(false)
664752
SucessPaymentModal.onClose()
@@ -670,7 +758,7 @@ export default function PlansAndPayment ({ userData }) {
670758
return (
671759
<Stack spacing={0}>
672760
<Box
673-
display={isLoading || isLoadingH ? "flex" : "none"}
761+
display={isLoading || isLoadingH || isStartingChatbotTrial ? "flex" : "none"}
674762
position="fixed"
675763
top="0"
676764
left="0"
@@ -949,7 +1037,7 @@ export default function PlansAndPayment ({ userData }) {
9491037
userData={userData}
9501038
plan={plan}
9511039
coupon={coupon}
952-
onSucess={() => openModalSucess()}
1040+
onSucess={(isTrial) => openModalSucess(isTrial)}
9531041
onErro={() => openModalErro()}
9541042
isLoading={(e) => setIsLoadingClientSecret(e)}
9551043
/>
@@ -1107,27 +1195,35 @@ export default function PlansAndPayment ({ userData }) {
11071195
<SuccessIcon width="90px" height="64px" fill="#34A15A" />
11081196
<TitleText>
11091197
{isChatbotCheckout
1110-
? t("username.chatbotSubscriptionSuccessTitle")
1198+
? isChatbotTrialSuccess
1199+
? t("username.chatbotTrialSuccessTitle")
1200+
: t("username.chatbotSubscriptionSuccessTitle")
11111201
: t("username.congratulations")}
11121202
</TitleText>
11131203
{isChatbotCheckout ? (
1114-
<BodyText color="#464A51">
1115-
<Trans
1116-
t={t}
1117-
i18nKey="username.chatbotSubscriptionSuccessDescription"
1118-
components={{
1119-
1: (
1120-
<Text
1121-
as="a"
1122-
href="/contact"
1123-
target="_self"
1124-
color="#0068C5"
1125-
_hover={{ color: "#0057A4" }}
1126-
/>
1127-
),
1128-
}}
1129-
/>
1130-
</BodyText>
1204+
isChatbotTrialSuccess ? (
1205+
<BodyText color="#464A51">
1206+
{t("username.chatbotTrialSuccessDescription")}
1207+
</BodyText>
1208+
) : (
1209+
<BodyText color="#464A51">
1210+
<Trans
1211+
t={t}
1212+
i18nKey="username.chatbotSubscriptionSuccessDescription"
1213+
components={{
1214+
1: (
1215+
<Text
1216+
as="a"
1217+
href="/contact"
1218+
target="_self"
1219+
color="#0068C5"
1220+
_hover={{ color: "#0057A4" }}
1221+
/>
1222+
),
1223+
}}
1224+
/>
1225+
</BodyText>
1226+
)
11311227
) : (
11321228
<BodyText color="#464A51">
11331229
{t("username.BQEmailDescription4")}{" "}
@@ -1173,6 +1269,7 @@ export default function PlansAndPayment ({ userData }) {
11731269
width={{ base: "100%", lg: "50%" }}
11741270
onClick={() => {
11751271
successCheckoutKindRef.current = null;
1272+
setIsChatbotTrialSuccess(false);
11761273
setIsLoading(false);
11771274
setIsLoadingH(false);
11781275
SucessPaymentModal.onClose();
@@ -1428,29 +1525,12 @@ export default function PlansAndPayment ({ userData }) {
14281525
justifyContent="space-between"
14291526
>
14301527
<Stack spacing="8px" marginBottom={{ base: "16px", lg: "0" }}>
1431-
<Badge
1432-
width="fit-content"
1433-
padding="2px 4px"
1434-
textTransform="none"
1435-
borderRadius="6px"
1436-
backgroundColor={
1437-
planActive ? (planCanceled ? "#F6E3E3" : "#D5E8DB") : "#D5E8DB"
1438-
}
1439-
color={
1440-
planActive ? (planCanceled ? "#BF3434" : "#2B8C4D") : "#2B8C4D"
1441-
}
1442-
fontSize="12px"
1443-
lineHeight="18px"
1444-
fontFamily="Roboto"
1445-
fontWeight="500"
1446-
letterSpacing="0.1px"
1447-
>
1448-
{planActive
1449-
? planCanceled
1450-
? t("username.canceled")
1451-
: t("username.active")
1452-
: t("username.active")}
1453-
</Badge>
1528+
{planActive && (
1529+
<SubscriptionStatusBadge
1530+
subscription={bdProSubscriptionInfo}
1531+
t={t}
1532+
/>
1533+
)}
14541534

14551535
<Box
14561536
display="flex"
@@ -1614,27 +1694,10 @@ export default function PlansAndPayment ({ userData }) {
16141694
marginTop="8px"
16151695
>
16161696
{hasChatbotActiveSubscription && (
1617-
<Badge
1618-
width="fit-content"
1619-
padding="2px 4px"
1620-
textTransform="none"
1621-
borderRadius="6px"
1622-
backgroundColor={
1623-
chatbotSubscriptionInfo?.canceledAt ? "#F6E3E3" : "#D5E8DB"
1624-
}
1625-
color={
1626-
chatbotSubscriptionInfo?.canceledAt ? "#BF3434" : "#2B8C4D"
1627-
}
1628-
fontSize="12px"
1629-
lineHeight="18px"
1630-
fontFamily="Roboto"
1631-
fontWeight="500"
1632-
letterSpacing="0.1px"
1633-
>
1634-
{chatbotSubscriptionInfo?.canceledAt
1635-
? t("username.canceled")
1636-
: t("username.active")}
1637-
</Badge>
1697+
<SubscriptionStatusBadge
1698+
subscription={chatbotSubscriptionInfo}
1699+
t={t}
1700+
/>
16381701
)}
16391702
<Box
16401703
display="flex"
@@ -1661,7 +1724,7 @@ export default function PlansAndPayment ({ userData }) {
16611724
>
16621725
{t("username.chatbotNewBadge")}
16631726
</Badge>
1664-
{chatbotSubscriptionInfo?.planInterval && (
1727+
{chatbotSubscriptionInfo?.planInterval && !isChatbotTrial && (
16651728
<LabelText typography="x-small" color="#71757A">
16661729
{formattedPlanInterval(
16671730
chatbotSubscriptionInfo?.planInterval,

0 commit comments

Comments
 (0)