From 557850800b663948958a367a73a05c5cb8301ee5 Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Tue, 20 Aug 2024 11:45:21 -0300 Subject: [PATCH 01/11] feat: wip plan active infos --- next/components/organisms/PaymentSystem.js | 42 +++++++++++++++------- next/pages/api/user/getUser.js | 10 ++++++ next/pages/user/[username].js | 4 +-- next/pages/user/survey.js | 2 ++ next/styles/paymentSystem.module.css | 8 ++--- 5 files changed, 47 insertions(+), 19 deletions(-) diff --git a/next/components/organisms/PaymentSystem.js b/next/components/organisms/PaymentSystem.js index beb8ac3c9..64f6bc98c 100644 --- a/next/components/organisms/PaymentSystem.js +++ b/next/components/organisms/PaymentSystem.js @@ -2,13 +2,13 @@ import { Stack, VStack, Skeleton, + Spinner, } from "@chakra-ui/react" import { useState, useEffect } from 'react'; import { loadStripe } from '@stripe/stripe-js'; import { Elements, PaymentElement, - AddressElement, useElements, useStripe, } from "@stripe/react-stripe-js"; @@ -18,10 +18,12 @@ import styles from "../../styles/paymentSystem.module.css"; const stripePromise = loadStripe(process.env.NEXT_PUBLIC_KEY_STRIPE) const PaymentForm = ({ onSucess, onErro, clientSecret}) => { + const [isLoading, setIsLoading] = useState(false) const stripe = useStripe() const elements = useElements() const handlerSubmit = async (e) => { + setIsLoading(true) e.preventDefault() const isSetupIntent = clientSecret.startsWith('seti_'); @@ -57,11 +59,25 @@ const PaymentForm = ({ onSucess, onErro, clientSecret}) => { className={styles.content} onSubmit={handlerSubmit} > - - - + ) @@ -121,15 +137,17 @@ export default function PaymentSystem({ userData, plan, onSucess, onErro }) { if(!clientSecret) return ( - - - - - + + + + + + + + + + - - - diff --git a/next/pages/api/user/getUser.js b/next/pages/api/user/getUser.js index a89fb0e1b..17cc4db99 100644 --- a/next/pages/api/user/getUser.js +++ b/next/pages/api/user/getUser.js @@ -35,6 +35,16 @@ async function getUser(id, token) { proSubscriptionStatus workDataTool availableForResearch + internalSubscription (isActive: true) { + edges { + node { + canceledAt + createdAt + isActive + stripeSubscription + } + } + } } } } diff --git a/next/pages/user/[username].js b/next/pages/user/[username].js index 1c6244371..0f327aaef 100644 --- a/next/pages/user/[username].js +++ b/next/pages/user/[username].js @@ -1671,7 +1671,7 @@ const PlansAndPayment = ({ userData }) => { propsModalContent={{ minWidth: "fit-content", maxWidth: "fit-content", - maxHeight: isMobileMod() ? "fit-content" : "700px", + maxHeight: "fit-content", margin: "24px 0" }} > @@ -1692,8 +1692,6 @@ const PlansAndPayment = ({ userData }) => { flexDirection="column" justifyContent="center" justifyItems="center" - width="fit-content" - minWidth="292px" gap="20px" spacing={0} > diff --git a/next/pages/user/survey.js b/next/pages/user/survey.js index fb2e9b0d4..adc5339b7 100644 --- a/next/pages/user/survey.js +++ b/next/pages/user/survey.js @@ -313,6 +313,8 @@ export default function Survey() { height="100%" fontSize="20px" lineHeight="30px" + fontFamily="Roboto" + fontWeight="500" pointerEvents={isLoading ? "none" : "default"} color={elm.style ? "#0D99FC" : "#FFFFFF"} backgroundColor={elm.style ? "#FFF" : "#0D99FC"} diff --git a/next/styles/paymentSystem.module.css b/next/styles/paymentSystem.module.css index 83b8f3389..ed2f31bca 100644 --- a/next/styles/paymentSystem.module.css +++ b/next/styles/paymentSystem.module.css @@ -2,19 +2,19 @@ display: flex; flex-direction: column; gap: 14px; - padding: 0 5px; + width: 100%; } .modal { - overflow-y: auto; - width: 306px; + width: 400px; + height: 100%; scroll-margin-left: 20px; } @media (max-width: 600px) { .modal { overflow-y: initial; - width: 300px; + width: 400px; } } From 5531f94d67daf43e29a45a70abfb60fc21e9ea4b Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Tue, 20 Aug 2024 17:17:50 -0300 Subject: [PATCH 02/11] chore: code R spaces --- next/components/molecules/DataInformationQuery.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/next/components/molecules/DataInformationQuery.js b/next/components/molecules/DataInformationQuery.js index 4f19cfb78..7fc633eaf 100644 --- a/next/components/molecules/DataInformationQuery.js +++ b/next/components/molecules/DataInformationQuery.js @@ -910,8 +910,8 @@ bd.read_sql(query = query, billing_project_id = billing_id)`} isLoaded={!isLoadingCode} > {` - # Defina o seu projeto no Google Cloud - set_billing_id("") +# Defina o seu projeto no Google Cloud +set_billing_id("") # Para carregar o dado direto no R query <- " From 843df2dfd9cb1f969a5fb8eea4d6b2aff1191a62 Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Tue, 27 Aug 2024 22:20:36 -0300 Subject: [PATCH 03/11] feat: wip feature internalSubscription canceledAt --- next/components/molecules/ColumnsTable.js | 2 +- .../molecules/DataInformationQuery.js | 2 +- next/pages/api/stripe/userGetSubscription.js | 44 ------ next/pages/api/user/getUser.js | 4 - next/pages/precos.js | 6 +- next/pages/user/[username].js | 149 ++++++++++++------ 6 files changed, 104 insertions(+), 103 deletions(-) delete mode 100644 next/pages/api/stripe/userGetSubscription.js diff --git a/next/components/molecules/ColumnsTable.js b/next/components/molecules/ColumnsTable.js index 73f82c860..cbe2e726e 100644 --- a/next/components/molecules/ColumnsTable.js +++ b/next/components/molecules/ColumnsTable.js @@ -111,7 +111,7 @@ export default function ColumnsTable({ let user if(cookies.get("userBD")) user = JSON.parse(cookies.get("userBD")) - if(user?.proSubscriptionStatus === "active") return true + if(user?.internalSubscription?.edges?.[0]?.node?.isActive === true) return true return false } diff --git a/next/components/molecules/DataInformationQuery.js b/next/components/molecules/DataInformationQuery.js index 74aefb636..510f49857 100644 --- a/next/components/molecules/DataInformationQuery.js +++ b/next/components/molecules/DataInformationQuery.js @@ -196,7 +196,7 @@ export default function DataInformationQuery({ resource }) { let user if(cookies.get("userBD")) user = JSON.parse(cookies.get("userBD")) - if(user?.proSubscriptionStatus === "active") return true + if(user?.internalSubscription?.edges?.[0]?.node?.isActive === true) return true return false } diff --git a/next/pages/api/stripe/userGetSubscription.js b/next/pages/api/stripe/userGetSubscription.js deleted file mode 100644 index 218f1e960..000000000 --- a/next/pages/api/stripe/userGetSubscription.js +++ /dev/null @@ -1,44 +0,0 @@ -import axios from "axios"; - -const API_URL= `${process.env.NEXT_PUBLIC_API_URL}/api/v1/graphql` - -async function userGetSubscription(id, token) { - try { - const res = await axios({ - url: API_URL, - method: "POST", - headers: { - Authorization: `Bearer ${token}` - }, - data: { - query: ` - query { - allAccount (id: "${id}"){ - edges { - node { - email - proSubscriptionStatus - } - } - } - } - ` - } - }) - const data = res.data - return data - } catch (error) { - console.error(error) - return "err" - } -} - -export default async function handler(req, res) { - const token = req.cookies.token - const result = await userGetSubscription(atob(req.query.p), token) - - if(result.errors) return res.status(500).json({error: result.errors}) - if(result === "err") return res.status(500).json({error: "err"}) - - res.status(200).json(result?.data?.allAccount?.edges[0]?.node) -} diff --git a/next/pages/api/user/getUser.js b/next/pages/api/user/getUser.js index 17cc4db99..1ac877964 100644 --- a/next/pages/api/user/getUser.js +++ b/next/pages/api/user/getUser.js @@ -29,10 +29,6 @@ async function getUser(id, token) { github twitter linkedin - proSubscription - proSubscriptionRole - proSubscriptionSlots - proSubscriptionStatus workDataTool availableForResearch internalSubscription (isActive: true) { diff --git a/next/pages/precos.js b/next/pages/precos.js index 9f9dbfd32..e4a840e5e 100644 --- a/next/pages/precos.js +++ b/next/pages/precos.js @@ -286,10 +286,12 @@ export function SectionPrice() { let user = null if(cookies.get("userBD")) user = JSON.parse(cookies.get("userBD")) + const stripeSubscription = user?.internalSubscription?.edges?.[0]?.node?.stripeSubscription + if(user != null) { setUsername(user?.username) - setIsBDPro(user?.proSubscription === "bd_pro") - setIsBDEmp(user?.proSubscription === "bd_pro_empresas") + setIsBDPro(stripeSubscription === "bd_pro") + setIsBDEmp(stripeSubscription === "bd_pro_empresas") } async function fecthPlans() { diff --git a/next/pages/user/[username].js b/next/pages/user/[username].js index 0f327aaef..ea70888a7 100644 --- a/next/pages/user/[username].js +++ b/next/pages/user/[username].js @@ -1454,6 +1454,8 @@ const PlansAndPayment = ({ userData }) => { const [plans, setPlans] = useState(null) const [toggleAnual, setToggleAnual] = useState(false) + const subscriptionInfo = userData?.internalSubscription?.edges?.[0]?.node + useEffect(() => { if(PlansModal.isOpen === false) return @@ -1492,7 +1494,7 @@ const PlansAndPayment = ({ userData }) => { useEffect(() => { if(query.i) { - if(userData.proSubscriptionStatus === "active") return AlertChangePlanModal.onOpen() + if(subscriptionInfo?.isActive === true) return AlertChangePlanModal.onOpen() setPlan({id: query.i}) PaymentModal.onOpen() } @@ -1501,7 +1503,10 @@ const PlansAndPayment = ({ userData }) => { const resources={ "BD Gratis" : { title: "BD Grátis", - buttons: [{text:"Comparar planos", onClick: () => PlansModal.onOpen()}], + buttons: [{ + text:"Comparar planos", + onClick: () => PlansModal.onOpen()} + ], resources : [{name: "Tabelas tratadas"}, {name: "Dados integrados", tooltip: "Nossa metodologia de padronização e compatibilização de dados permite que você cruze tabelas de diferentes instituições e temas de maneira simplificada."}, {name: "Acesso em nuvem"}, @@ -1510,19 +1515,36 @@ const PlansAndPayment = ({ userData }) => { }, "bd_pro" : { title: "BD Pro", - buttons : [{text:"Cancelar plano", onClick: () => CancelModalPlan.onOpen()}], + buttons : [{ + text:"Cancelar plano", + onClick: () => CancelModalPlan.onOpen(), + props: { + borderColor: subscriptionInfo?.canceledAt ? "#ACAEB1" : "#42B0FF", + color: subscriptionInfo?.canceledAt ? "#ACAEB1" : "#42B0FF", + pointerEvents: subscriptionInfo?.canceledAt ? "none" : "default" + } + }], resources : [{name: "Dezenas de bases de alta frequência atualizadas"}] }, "bd_pro_empresas" : { title: "BD Empresas", - buttons : [{text:"Cancelar plano", onClick: () => CancelModalPlan.onOpen()}], + buttons : [{ + text:"Cancelar plano", + onClick: () => CancelModalPlan.onOpen(), + props: { + borderColor: subscriptionInfo?.canceledAt ? "#ACAEB1" : "#42B0FF", + color: subscriptionInfo?.canceledAt ? "#ACAEB1" : "#42B0FF", + pointerEvents: subscriptionInfo?.canceledAt ? "none" : "default" + } + }], resources : [{name: "Acesso para 10 contas"}, {name: "Suporte prioritário via email e Discord"}]} } - const planActive = userData?.proSubscriptionStatus === "active" + const planActive = subscriptionInfo?.isActive === true const defaultResource = resources["BD Gratis"] - const planResource = resources[userData?.proSubscription] + const planResource = resources[subscriptionInfo?.stripeSubscription] + const planCanceled = subscriptionInfo?.canceledAt const controlResource = () => { return planActive ? planResource : defaultResource @@ -1618,15 +1640,6 @@ const PlansAndPayment = ({ userData }) => { setIsLoadingCanSub(false) } - // do { - // const statusSub = await fetch(`/api/stripe/userGetSubscription?p=${btoa(id)}`, {method: "GET"}) - // .then(res => res.json()) - // if(statusSub?.proSubscriptionStatus !== "active") { - // break - // } - // await new Promise (resolve => setTimeout(resolve ,1000)) - // } while (true) - const user = await fetch(`/api/user/getUser?p=${btoa(id)}`, {method: "GET"}) .then(res => res.json()) cookies.set('userBD', JSON.stringify(user)) @@ -1637,15 +1650,6 @@ const PlansAndPayment = ({ userData }) => { const reg = new RegExp("(?<=:).*") const [ id ] = reg.exec(userData.id) - do { - const statusSub = await fetch(`/api/stripe/userGetSubscription?p=${btoa(id)}`, {method: "GET"}) - .then(res => res.json()) - if(statusSub?.proSubscriptionStatus === "active") { - break - } - await new Promise (resolve => setTimeout(resolve ,1000)) - } while (true) - const user = await fetch(`/api/user/getUser?p=${btoa(id)}`, {method: "GET"}) .then(res => res.json()) cookies.set('userBD', JSON.stringify(user)) @@ -1992,13 +1996,13 @@ const PlansAndPayment = ({ userData }) => { {name: "Download direto até 1GB (80% das tabelas da plataforma)", tooltip: "Tabelas maiores que 1 GB não estão disponíveis para download parcial ou completo. Esse limite não se aplica ao acesso via SQL, Python e R."} ]} button={{ - text: `${userData?.proSubscription === "bd_pro" ? "Plano atual" : "Assinar"}`, - onClick: userData?.proSubscription === "bd_pro" ? () => {} : () => { + text: `${subscriptionInfo?.stripeSubscription === "bd_pro" ? "Plano atual" : "Assinar"}`, + onClick: subscriptionInfo?.stripeSubscription === "bd_pro" ? () => {} : () => { setPlan({id: plans?.[`bd_pro_${toggleAnual ? "year" : "month"}`]._id}) PlansModal.onClose() PaymentModal.onOpen() }, - isCurrentPlan: userData?.proSubscription === "bd_pro" ? true : false, + isCurrentPlan: subscriptionInfo?.stripeSubscription === "bd_pro" ? true : false, }} /> @@ -2013,13 +2017,13 @@ const PlansAndPayment = ({ userData }) => { {name: "Suporte prioritário via email e Discord"} ]} button={{ - text: `${userData?.proSubscription === "bd_pro_empresas" ? "Plano atual" : "Assinar"}`, - onClick: userData?.proSubscription === "bd_pro_empresas" ? () => {} : () => { + text: `${subscriptionInfo?.stripeSubscription === "bd_pro_empresas" ? "Plano atual" : "Assinar"}`, + onClick: subscriptionInfo?.stripeSubscription === "bd_pro_empresas" ? () => {} : () => { setPlan({id: plans?.[`bd_empresas_${toggleAnual ? "year" : "month"}`]._id}) PlansModal.onClose() PaymentModal.onOpen() }, - isCurrentPlan: userData?.proSubscription === "bd_pro_empresas" ? true : false, + isCurrentPlan: subscriptionInfo?.stripeSubscription === "bd_pro_empresas" ? true : false, }} /> @@ -2138,26 +2142,68 @@ const PlansAndPayment = ({ userData }) => { flexDirection={isMobileMod() ? "column" : "row"} justifyContent="space-between" > - + Plano atual - {controlResource().title} + letterSpacing="0.1px" + > + {planActive ? planCanceled ? "Cancelado" : "Ativo" : "Ativo"} + + + + {controlResource().title} + + (Mensal) + + + + + + Próxima data de renovação automática: + 08 de agosto de 2024 + + + {/* Acesso ao plano disponível até: */} + { width={isMobileMod() ? "100%" : "fit-content"} _hover={{transform: "none", opacity: 0.8}} onClick={() => controlResource().buttons[0].onClick()} + {...controlResource()?.buttons?.[0]?.props} >{controlResource().buttons[0].text} @@ -2196,12 +2243,12 @@ const PlansAndPayment = ({ userData }) => { {defaultResource.resources.map((elm, index) => { return })} - {userData?.proSubscription === "bd_pro" && + {subscriptionInfo?.stripeSubscription === "bd_pro" && planResource.resources.map((elm, index) => { return }) } - {userData?.proSubscription === "bd_pro_empresas" && + {subscriptionInfo?.stripeSubscription === "bd_pro_empresas" && <> {resources["bd_pro"].resources.map((elm, index) => { return @@ -2212,7 +2259,7 @@ const PlansAndPayment = ({ userData }) => { } - {userData?.proSubscriptionStatus !== "active" && + {!subscriptionInfo?.isActive && { - {userData?.proSubscription !== "bd_pro_empresas" && + {subscriptionInfo?.stripeSubscription !== "bd_pro_empresas" && { } - {userData?.proSubscription === "bd_pro" && + {subscriptionInfo?.stripeSubscription === "bd_pro" && resources["bd_pro_empresas"].resources.map((elm, index) => { return }) } - {userData?.proSubscriptionStatus !== "active" && + {!subscriptionInfo?.isActive && Date: Mon, 2 Sep 2024 12:19:51 -0300 Subject: [PATCH 04/11] feat: new layout applied to registration --- .../molecules/DataInformationQuery.js | 10 +++--- next/pages/api/tables/downloadTable.js | 35 ++++++++++++------- next/pages/api/user/getUser.js | 2 ++ next/pages/user/[username].js | 22 ++++++++---- 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/next/components/molecules/DataInformationQuery.js b/next/components/molecules/DataInformationQuery.js index 510f49857..7fc633eaf 100644 --- a/next/components/molecules/DataInformationQuery.js +++ b/next/components/molecules/DataInformationQuery.js @@ -196,7 +196,7 @@ export default function DataInformationQuery({ resource }) { let user if(cookies.get("userBD")) user = JSON.parse(cookies.get("userBD")) - if(user?.internalSubscription?.edges?.[0]?.node?.isActive === true) return true + if(user?.proSubscriptionStatus === "active") return true return false } @@ -598,10 +598,10 @@ export default function DataInformationQuery({ resource }) { { - if(downloadWarning === "100mbBetween1gb") return plansModal.onOpen() + if(downloadWarning !== "free" && isUserPro() === false) return plansModal.onOpen() + window.open(`/api/tables/downloadTable?p=${btoa(gcpDatasetID)}&q=${btoa(gcpTableId)}&d=${btoa(downloadPermitted)}&s=${btoa(downloadWarning)}`, "_blank") triggerGAEvent("download_da_tabela",`{ gcp: ${gcpProjectID+"."+gcpDatasetID+"."+gcpTableId}, tamanho: ${formatBytes(resource.uncompressedFileSize) || ""}, @@ -910,8 +910,8 @@ bd.read_sql(query = query, billing_project_id = billing_id)`} isLoaded={!isLoadingCode} > {` - # Defina o seu projeto no Google Cloud - set_billing_id("") +# Defina o seu projeto no Google Cloud +set_billing_id("") # Para carregar o dado direto no R query <- " diff --git a/next/pages/api/tables/downloadTable.js b/next/pages/api/tables/downloadTable.js index 40b6d384a..39931c8bc 100644 --- a/next/pages/api/tables/downloadTable.js +++ b/next/pages/api/tables/downloadTable.js @@ -20,24 +20,22 @@ async function validateToken(token) { async function downloadTable(url, datasetID, tableId, token, res) { let payloadToken - if(url !== "free") { - if(token !== null) payloadToken = await validateToken(token) - } + if(token !== null) payloadToken = await validateToken(token) const urlDownloadOpen = process.env.URL_DOWNLOAD_OPEN.replace("gs://", "") const urlDownloadClosed = process.env.URL_DOWNLOAD_CLOSED.replace("gs://", "") const prefixUrl = "https://storage.googleapis.com/" - try { - let fileUrl = "" + let fileUrl = "" - if(url === "free") { - fileUrl =`${prefixUrl}${urlDownloadOpen}${datasetID}/${tableId}/${tableId}.csv.gz` - }else if(payloadToken?.pro_subscription_status === "active") { - fileUrl = `${prefixUrl}${urlDownloadClosed}${datasetID}/${tableId}/${tableId}_bdpro.csv.gz` - } + if(payloadToken?.is_subscription_active === true) { + fileUrl = `${prefixUrl}${urlDownloadClosed}${datasetID}/${tableId}/${tableId}_bdpro.csv.gz` + }else if(url === "free") { + fileUrl =`${prefixUrl}${urlDownloadOpen}${datasetID}/${tableId}/${tableId}.csv.gz` + } + try { const response = await axios({ url: fileUrl, method: 'GET', @@ -49,8 +47,21 @@ async function downloadTable(url, datasetID, tableId, token, res) { response.data.pipe(res) } catch (error) { - console.error(error) - res.status(500).json({ message: 'Error downloading the file' }) + try { + const response = await axios({ + url: `${prefixUrl}${urlDownloadOpen}${datasetID}/${tableId}/${tableId}.csv.gz`, + method: 'GET', + responseType: 'stream' + }) + + res.setHeader('Content-Disposition', `attachment; filename=${datasetID}_${tableId}.csv.gz`) + res.setHeader('Content-Type', 'application/gzip') + + response.data.pipe(res) + } catch (error) { + console.error(error) + res.status(500).json({ message: 'Error downloading the file' }) + } } } diff --git a/next/pages/api/user/getUser.js b/next/pages/api/user/getUser.js index 1ac877964..d9749b807 100644 --- a/next/pages/api/user/getUser.js +++ b/next/pages/api/user/getUser.js @@ -38,6 +38,8 @@ async function getUser(id, token) { createdAt isActive stripeSubscription + planInterval + nextBillingCycle } } } diff --git a/next/pages/user/[username].js b/next/pages/user/[username].js index ea70888a7..335b4fdf5 100644 --- a/next/pages/user/[username].js +++ b/next/pages/user/[username].js @@ -1549,7 +1549,6 @@ const PlansAndPayment = ({ userData }) => { const controlResource = () => { return planActive ? planResource : defaultResource } - const IncludesFeature = ({ elm, index }) => { return ( @@ -1658,6 +1657,18 @@ const PlansAndPayment = ({ userData }) => { window.open(`/user/${userData.username}?plans_and_payment`, "_self") } + function formatTimeStamp (value) { + const date = new Date(value) + const options = { day: '2-digit', month: 'long', year: 'numeric' } + const formattedDate = date.toLocaleDateString('pt-BR', options) + return formattedDate + } + + function formattedPlanInterval (value) { + if(value === "month") return "(Mensal)" + if(value === "year") return "(Anual)" + } + useEffect(() => { if(isLoading === true || isLoadingH === true) closeModalSucess() if(isLoadingCanSub === true) cancelSubscripetion() @@ -2183,11 +2194,11 @@ const PlansAndPayment = ({ userData }) => { letterSpacing="0.1px" color="#71757A" > - (Mensal) + {formattedPlanInterval(subscriptionInfo?.planInterval)} - + { lineHeight="22px" color="#252A32" > - Próxima data de renovação automática: - 08 de agosto de 2024 + {formatTimeStamp(subscriptionInfo?.canceledAt ? subscriptionInfo?.canceledAt : subscriptionInfo?.nextBillingCycle)} - {/* Acesso ao plano disponível até: */} From e2745f6d69399e7b3f0870ab7f77c5d9ad852afd Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Mon, 2 Sep 2024 23:45:18 -0300 Subject: [PATCH 05/11] fix: ajust toggle plan year --- next/pages/user/[username].js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/next/pages/user/[username].js b/next/pages/user/[username].js index 335b4fdf5..01033fdee 100644 --- a/next/pages/user/[username].js +++ b/next/pages/user/[username].js @@ -1891,7 +1891,10 @@ const PlansAndPayment = ({ userData }) => { { + PlansModal.onClose() + setToggleAnual(false) + }} propsModal={{ scrollBehavior: isMobileMod() ? "outside" : "inside", }} From 3de57bcc2b16cc095baea95d2d2909373318ccd2 Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Tue, 3 Sep 2024 15:33:11 -0300 Subject: [PATCH 06/11] feat: system to identify already subscribed plan --- next/pages/api/user/getAlreadySubscribed.js | 59 +++++++++++++++++++++ next/pages/precos.js | 19 ++++++- next/pages/user/[username].js | 18 ++++++- 3 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 next/pages/api/user/getAlreadySubscribed.js diff --git a/next/pages/api/user/getAlreadySubscribed.js b/next/pages/api/user/getAlreadySubscribed.js new file mode 100644 index 000000000..c01dcb846 --- /dev/null +++ b/next/pages/api/user/getAlreadySubscribed.js @@ -0,0 +1,59 @@ +import axios from "axios"; + +const API_URL= `${process.env.NEXT_PUBLIC_API_URL}/api/v1/graphql` + +async function getAlreadySubscribed(id, token) { + try { + const res = await axios({ + url: API_URL, + method: "POST", + headers: { + Authorization: `Bearer ${token}` + }, + data: { + query: ` + query { + allAccount (id: "${id}"){ + edges { + node { + id + internalSubscription { + edges { + node { + canceledAt + createdAt + isActive + stripeSubscription + planInterval + nextBillingCycle + } + } + } + } + } + } + } + ` + } + }) + const data = res.data + return data + } catch (error) { + console.error(error) + return "err" + } +} + +export default async function handler(req, res) { + const token = () => { + if(req.query.q) return atob(req.query.q) + return req.cookies.token + } + + const result = await getAlreadySubscribed(atob(req.query.p), token()) + + if(result.errors) return res.status(500).json({error: result.errors}) + if(result === "err") return res.status(500).json({error: "err"}) + + res.status(200).json(result?.data?.allAccount?.edges[0]?.node?.internalSubscription) +} diff --git a/next/pages/precos.js b/next/pages/precos.js index e4a840e5e..0634811db 100644 --- a/next/pages/precos.js +++ b/next/pages/precos.js @@ -281,11 +281,26 @@ export function SectionPrice() { const [username, setUsername] = useState(null) const [isBDPro, setIsBDPro] = useState(false) const [isBDEmp, setIsBDEmp] = useState(false) + const [hasSubscribed, setHasSubscribed] = useState(true) + + async function alreadySubscribed(id) { + const result = await fetch(`/api/user/getAlreadySubscribed?p=${btoa(id)}`) + .then(res => res.json()) + setHasSubscribed(result?.edges.length > 0) + } useEffect(() => { let user = null if(cookies.get("userBD")) user = JSON.parse(cookies.get("userBD")) + if(user) { + const reg = new RegExp("(?<=:).*") + const [ id ] = reg.exec(user.id) + alreadySubscribed(id) + } else { + setHasSubscribed(false) + } + const stripeSubscription = user?.internalSubscription?.edges?.[0]?.node?.stripeSubscription if(user != null) { @@ -412,7 +427,7 @@ export function SectionPrice() { {name: "Download direto até 1GB (80% das tabelas da plataforma)", tooltip: "Tabelas maiores que 1 GB não estão disponíveis para download parcial ou completo. Esse limite não se aplica ao acesso via SQL, Python e R."} ]} button={{ - text: isBDPro ? "Plano atual" : `Iniciar teste grátis`, + text: isBDPro ? "Plano atual" : hasSubscribed ? "Assinar" : "Iniciar teste grátis", href: username === null ? `/user/login?q=pro&i=${plans?.[`bd_pro_${toggleAnual ? "year" : "month"}`]._id}` :`/user/${username}?plans_and_payment&q=pro&i=${plans?.[`bd_pro_${toggleAnual ? "year" : "month"}`]._id}`, isCurrentPlan: isBDPro, }} @@ -429,7 +444,7 @@ export function SectionPrice() { {name: "Suporte prioritário via email e Discord"} ]} button={{ - text: isBDEmp ? "Plano atual" : "Iniciar teste grátis", + text: isBDEmp ? "Plano atual" : hasSubscribed ? "Assinar" : "Iniciar teste grátis", href: username === null ? `/user/login?q=empresas&i=${plans?.[`bd_empresas_${toggleAnual ? "year" : "month"}`]._id}` :`/user/${username}?plans_and_payment&q=empresas&i=${plans?.[`bd_empresas_${toggleAnual ? "year" : "month"}`]._id}`, isCurrentPlan: isBDEmp, }} diff --git a/next/pages/user/[username].js b/next/pages/user/[username].js index 01033fdee..2ac9d5746 100644 --- a/next/pages/user/[username].js +++ b/next/pages/user/[username].js @@ -1450,12 +1450,26 @@ const PlansAndPayment = ({ userData }) => { const [isLoading, setIsLoading] = useState(false) const [isLoadingH, setIsLoadingH] = useState(false) const [isLoadingCanSub, setIsLoadingCanSub] = useState(false) + const [hasSubscribed, setHasSubscribed] = useState(true) const [plans, setPlans] = useState(null) const [toggleAnual, setToggleAnual] = useState(false) const subscriptionInfo = userData?.internalSubscription?.edges?.[0]?.node + async function alreadySubscribed(id) { + const result = await fetch(`/api/user/getAlreadySubscribed?p=${btoa(id)}`) + .then(res => res.json()) + setHasSubscribed(result?.edges.length > 0) + } + + useEffect(() => { + const reg = new RegExp("(?<=:).*") + const [ id ] = reg.exec(userData.id) + + alreadySubscribed(id) + }, [userData?.id]) + useEffect(() => { if(PlansModal.isOpen === false) return @@ -2010,7 +2024,7 @@ const PlansAndPayment = ({ userData }) => { {name: "Download direto até 1GB (80% das tabelas da plataforma)", tooltip: "Tabelas maiores que 1 GB não estão disponíveis para download parcial ou completo. Esse limite não se aplica ao acesso via SQL, Python e R."} ]} button={{ - text: `${subscriptionInfo?.stripeSubscription === "bd_pro" ? "Plano atual" : "Assinar"}`, + text: `${subscriptionInfo?.stripeSubscription === "bd_pro" ? "Plano atual" : hasSubscribed ? "Assinar" : "Iniciar teste grátis"}`, onClick: subscriptionInfo?.stripeSubscription === "bd_pro" ? () => {} : () => { setPlan({id: plans?.[`bd_pro_${toggleAnual ? "year" : "month"}`]._id}) PlansModal.onClose() @@ -2031,7 +2045,7 @@ const PlansAndPayment = ({ userData }) => { {name: "Suporte prioritário via email e Discord"} ]} button={{ - text: `${subscriptionInfo?.stripeSubscription === "bd_pro_empresas" ? "Plano atual" : "Assinar"}`, + text: `${subscriptionInfo?.stripeSubscription === "bd_pro_empresas" ? "Plano atual" : hasSubscribed ? "Assinar" : "Iniciar teste grátis"}`, onClick: subscriptionInfo?.stripeSubscription === "bd_pro_empresas" ? () => {} : () => { setPlan({id: plans?.[`bd_empresas_${toggleAnual ? "year" : "month"}`]._id}) PlansModal.onClose() From 13d5f0ff958eccc939f0f12aed15235a7f962396 Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Wed, 4 Sep 2024 11:34:41 -0300 Subject: [PATCH 07/11] feat: ajust modal price in user page --- next/pages/user/[username].js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/next/pages/user/[username].js b/next/pages/user/[username].js index 2ac9d5746..824275875 100644 --- a/next/pages/user/[username].js +++ b/next/pages/user/[username].js @@ -1914,6 +1914,8 @@ const PlansAndPayment = ({ userData }) => { }} propsModalContent={{ maxWidth: "fit-content", + minWidth: "fit-content", + maxHeight: "fit-content", margin: isMobileMod() ? "0" : "24px", borderRadius: isMobileMod() ? "0" : "20px", }} @@ -1988,6 +1990,7 @@ const PlansAndPayment = ({ userData }) => { gridTemplateColumns="repeat(3, 320px)" gridTemplateRows="1fr" alignItems={isMobileMod() ? "center" : {base: "center", lg: "inherit"}} + padding="0 20px 10px" justifyContent="center" justifyItems="center" gap="20px" From 4261e4a462bf44e34a39a2d59dbbebc405664567 Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Wed, 4 Sep 2024 18:21:54 -0300 Subject: [PATCH 08/11] feat: removed STATA mentions and adjustments to plan presentations --- .../molecules/DataInformationQuery.js | 4 +- next/content/FAQ.js | 14 ++--- next/content/caseStudies.js | 2 +- next/content/serviceTerms.js | 2 +- next/pages/_app.js | 4 +- next/pages/perguntas-frequentes.js | 2 +- next/pages/precos.js | 29 ++++----- next/pages/user/[username].js | 62 +++++++++++++------ 8 files changed, 71 insertions(+), 48 deletions(-) diff --git a/next/components/molecules/DataInformationQuery.js b/next/components/molecules/DataInformationQuery.js index 7fc633eaf..ae5cbbc8e 100644 --- a/next/components/molecules/DataInformationQuery.js +++ b/next/components/molecules/DataInformationQuery.js @@ -586,13 +586,13 @@ export default function DataInformationQuery({ resource }) { color="#0068C5" _hover={{color: "#0057A4"}} >assinantes dos nossos planos pagos - . No entanto, você pode acessar a tabela gratuitamente utilizando SQL, Python, R ou Stata. Considere atualizar para um plano pago para fazer o download. + . No entanto, você pode acessar a tabela gratuitamente utilizando SQL, Python ou R. Considere atualizar para um plano pago para fazer o download. } {downloadWarning === "biggest1gb" && } diff --git a/next/content/FAQ.js b/next/content/FAQ.js index 5a176d21f..30432df37 100644 --- a/next/content/FAQ.js +++ b/next/content/FAQ.js @@ -48,7 +48,7 @@ export const QuestionFAQ = [

Sim, você pode baixar o arquivo CSV completo das tabelas tratadas direto na plataforma. - No entanto, tabelas com mais de 200.000 linhas só podem ser acessados através do nosso data lake no BigQuery ou dos nossos pacotes em Python, R e Stata. + No entanto, tabelas com mais de 200.000 linhas só podem ser acessados através do nosso data lake no BigQuery ou dos nossos pacotes em Python e R.

) @@ -64,7 +64,7 @@ export const QuestionFAQ = [

O limite para download dos dados na nossa plataforma é de 200.000 linhas. - Para acessar tabelas que ultrapassam esse limite, utilize nosso datalake no BigQuery ou nossos pacotes em Python, R e Stata. + Para acessar tabelas que ultrapassam esse limite, utilize nosso datalake no BigQuery ou nossos pacotes em Python e R.

) @@ -94,7 +94,7 @@ export const QuestionFAQ = [ return (

- São tabelas prontas para análise, disponíveis via SQL, Python, R ou Stata. + São tabelas prontas para análise, disponíveis via SQL, Python e R. O processo de tratamento das tabelas envolve a padronização de nomes de variáveis e compatibilização de códigos, o que permite que o cruzamento de tabelas de diferentes instituições e temas seja tão simples quanto qualquer outra consulta.

@@ -147,13 +147,13 @@ export const QuestionFAQ = [

Você pode consultar as tabelas tratadas BD+ de diferentes maneiras. Além de fazer o download direto na plataforma, - é possível explorar os dados com SQL através do BigQuery ou com os pacotes em Python, R e Stata. + é possível explorar os dados com SQL através do BigQuery ou com os pacotes em Python e R.

) }, categories: ["Dados"], - keywords: "acesso, consulta, tratada, tratado, BD+, download, baixar, pacote, SQL, BigQuery, Python, R, Stata", + keywords: "acesso, consulta, tratada, tratado, BD+, download, baixar, pacote, SQL, BigQuery, Python, R", id: "access-tables" }, { @@ -231,7 +231,7 @@ export const QuestionFAQ = [

Nossos pacotes permitem o acesso ao datalake público direto do seu computador ou ambiente de desenvolvimento. - Para começar a explorar nossos dados em Python, R ou Stata, + Para começar a explorar nossos dados em Python ou R, siga os tutoriais de instalação dos pacotes presentes na nossa documentação.

@@ -239,7 +239,7 @@ export const QuestionFAQ = [ ) }, categories: ["Dados"], - keywords: "pacote, Python, R, Stata, instalação, documentação", + keywords: "pacote, Python, R, instalação, documentação", id: "packages" }, { diff --git a/next/content/caseStudies.js b/next/content/caseStudies.js index 49b1ef5cf..59572cd20 100644 --- a/next/content/caseStudies.js +++ b/next/content/caseStudies.js @@ -325,7 +325,7 @@ export const CaseStudiesContent = [

A BD também disponibiliza em sua plataforma os dados atualizados de receitas e despesas, possibilitando o download das tabelas tratadas ou o acesso por ferramentas de análise de dados, - como SQL, Python, R e Stata. + como SQL, Python e R.

diff --git a/next/content/serviceTerms.js b/next/content/serviceTerms.js index 5ab5af2ef..a4e774bcd 100644 --- a/next/content/serviceTerms.js +++ b/next/content/serviceTerms.js @@ -60,7 +60,7 @@ export default function ServiceTerms() { gap="8px" > 2. Descrição do Serviço - 2.1. Nossos serviços consistem em uma assinatura mensal que concede aos seus assinantes o acesso a diversos dados exclusivos, harmonizados e atualizados na plataforma da Base dos Dados. O acesso se dá via os pacotes Python, R ou Stata da Base dos Dados, ou via BigQuery, serviço de armazenamento de dados de baixo custo e totalmente gerenciado do Google para análises. + 2.1. Nossos serviços consistem em uma assinatura mensal que concede aos seus assinantes o acesso a diversos dados exclusivos, harmonizados e atualizados na plataforma da Base dos Dados. O acesso se dá via os pacotes Python ou R da Base dos Dados, ou via BigQuery, serviço de armazenamento de dados de baixo custo e totalmente gerenciado do Google para análises. Base dos Dados