@@ -23,7 +23,36 @@ import BodyText from "../../atoms/Text/BodyText";
2323import Toggle from "../../atoms/Toggle" ;
2424import { SectionPrice } from "../../../pages/prices" ;
2525import 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
2857import {
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