From c86655a57dd6b830c83805b3c22d6b5bf3e5d2f2 Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Wed, 25 Sep 2024 19:17:36 -0300 Subject: [PATCH 1/9] =?UTF-8?q?feat:=20For=20subscribers,=20no=20more=20?= =?UTF-8?q?=E2=80=9Cfor=20subscribers=E2=80=9D=20messages/conditions=20wil?= =?UTF-8?q?l=20appear?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../molecules/TemporalCoverageDisplay.js | 62 +++++++++++++------ next/pages/dataset/index.js | 12 +++- next/pages/precos.js | 1 + next/pages/user/[username].js | 2 + 4 files changed, 58 insertions(+), 19 deletions(-) diff --git a/next/components/molecules/TemporalCoverageDisplay.js b/next/components/molecules/TemporalCoverageDisplay.js index f534fcfec..81fa877ff 100644 --- a/next/components/molecules/TemporalCoverageDisplay.js +++ b/next/components/molecules/TemporalCoverageDisplay.js @@ -9,10 +9,12 @@ import { ModalCloseButton } from "@chakra-ui/react"; import { useState, useEffect } from "react"; +import cookies from "js-cookie"; import { CalendarComunIcon } from "../../public/img/icons/calendarIcon"; import { SectionPrice } from "../../pages/precos"; import { ModalGeneral } from "./uiUserPage"; import RedirectIcon from "../../public/img/icons/redirectIcon"; +import CheckIcon from "../../public/img/icons/checkIcon"; export function TemporalCoverage ({ value, @@ -132,6 +134,14 @@ export function TemporalCoverageBar ({ value }) { const [values, setValues] = useState({}) const plansModal = useDisclosure() + const isUserPro = () => { + let user + if(cookies.get("userBD")) user = JSON.parse(cookies.get("userBD")) + + if(user?.internalSubscription?.edges?.[0]?.node?.isActive === true) return true + return false + } + const TextData = ({ string, ...style }) => { return ( - + plansModal.onOpen()} + onClick={() => { + if(isUserPro()) return + plansModal.onOpen()} + } > PAGO - + {isUserPro() ? + + : + + } @@ -388,13 +414,13 @@ export function TemporalCoverageBar ({ value }) { display="flex" alignItems="center" flexDirection="column" - right={0} top="-3px" + right="-4px" > { + let user + if(cookies.get("userBD")) user = JSON.parse(cookies.get("userBD")) + + if(user?.internalSubscription?.edges?.[0]?.node?.isActive === true) return true + return false + } + function flattenArray(arr) { let result = [] @@ -584,6 +593,7 @@ export default function SearchDatasetPage() { - + { }} ], resources : [ + {name: "Bases de baixa frequência atualizadas"}, {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"}, @@ -2370,6 +2371,7 @@ const PlansAndPayment = ({ userData }) => { price={"0"} textResource="Recursos:" resources={[ + {name: "Bases de baixa frequência atualizadas"}, {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"}, From 0440e5606fe6c36ff39ce5ab06c3d03a6f012ae9 Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Wed, 25 Sep 2024 22:20:16 -0300 Subject: [PATCH 2/9] feat: adding new element for signature recognition --- next/components/molecules/Menu.js | 161 +++++++++++++++++++----------- 1 file changed, 104 insertions(+), 57 deletions(-) diff --git a/next/components/molecules/Menu.js b/next/components/molecules/Menu.js index f848b2a12..3b5060d7b 100644 --- a/next/components/molecules/Menu.js +++ b/next/components/molecules/Menu.js @@ -194,7 +194,7 @@ function MenuDrawer({ userData, isOpen, onClose, links }) { ); } -function MenuDrawerUser({ userData, isOpen, onClose}) { +function MenuDrawerUser({ userData, isOpen, onClose, isUserPro}) { const router = useRouter() const links = [ @@ -236,35 +236,50 @@ function MenuDrawerUser({ userData, isOpen, onClose}) { color="#252A32" fontFamily="Roboto" letterSpacing="0.1px" - fontSize="14px" - fontWeight="400" - lineHeight="27px" + fontSize="12px" + fontWeight="500" + lineHeight="18px" >{userData?.username || ""} {userData?.email || ""} + + + {isUserPro ? "Pro" : "Grátis"} + - - + + Configurações @@ -272,30 +287,31 @@ function MenuDrawerUser({ userData, isOpen, onClose}) { - - {links.map((elm, index) => { - return ( - { - onClose() - router.push({pathname: `/user/${userData.username}`, query: elm.value})} - } - >{elm.name} - ) - })} - + + + {links.map((elm, index) => { + return ( + { + onClose() + router.push({pathname: `/user/${userData.username}`, query: elm.value})} + } + >{elm.name} + ) + })} + @@ -306,7 +322,7 @@ function MenuDrawerUser({ userData, isOpen, onClose}) { cursor="pointer" spacing={0} flexDirection="row" - padding="16px 0" + padding="14px 0" alignItems="center" color="#252A32" fill="#D0D0D0" @@ -322,10 +338,9 @@ function MenuDrawerUser({ userData, isOpen, onClose}) { Sair @@ -336,7 +351,7 @@ function MenuDrawerUser({ userData, isOpen, onClose}) { ) } -function MenuUser ({ userData, onOpen, onClose }) { +function MenuUser ({ userData, onOpen, onClose, isUserPro }) { const timerRef = useRef() const [isOpenMenu, setIsOpenMenu] = useState(false) @@ -440,21 +455,37 @@ function MenuUser ({ userData, onOpen, onClose }) { fontFamily="Roboto" letterSpacing="0.1px" fontSize="12px" - fontWeight="400" - lineHeight="16px" + fontWeight="500" + lineHeight="18px" > {userData?.username ? userData?.username : ""} {userData?.email ? userData?.email : ""} + + + {isUserPro ? "Pro" : "Grátis"} + Configurações @@ -496,10 +526,9 @@ function MenuUser ({ userData, onOpen, onClose }) { Sair @@ -618,7 +647,14 @@ function SearchInputUser ({ user }) { ) } -function DesktopLinks({ userData, links, position = false, path, userTemplate = false }) { +function DesktopLinks({ + userData, + links, + position = false, + path, + userTemplate = false, + isUserPro +}) { function LinkMenuDropDown ({ url, text, icon }) { const [flag, setFlag] = useBoolean() @@ -765,7 +801,7 @@ function DesktopLinks({ userData, links, position = false, path, userTemplate = {userData ? ( - + ) : ( <> @@ -840,6 +876,14 @@ export default function MenuNav({ simpleTemplate = false, userTemplate = false } const [lastScrollY, setLastScrollY] = useState(0) const [menuVisible, setMenuVisible] = useState(true) + const isUserPro = () => { + let user + if(cookies.get("userBD")) user = JSON.parse(cookies.get("userBD")) + + if(user?.internalSubscription?.edges?.[0]?.node?.isActive === true) return true + return false + } + const handleScroll = () => { const currentScrollY = window.scrollY if (currentScrollY > lastScrollY) { @@ -991,6 +1035,7 @@ export default function MenuNav({ simpleTemplate = false, userTemplate = false } position={isScrollDown} path={route} userTemplate={userTemplate} + isUserPro={isUserPro()} /> } @@ -1005,12 +1050,14 @@ export default function MenuNav({ simpleTemplate = false, userTemplate = false } userData={userData} onOpen={menuUserMobile.onOpen} onClose={menuUserMobile.onClose} + isUserPro={isUserPro()} /> } From 6a30c22403c10dc9493cf10ed89781e7aa20cf41 Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Thu, 26 Sep 2024 18:50:34 -0300 Subject: [PATCH 3/9] feat: added a call counter for signup success --- next/pages/user/[username].js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/next/pages/user/[username].js b/next/pages/user/[username].js index ce3e952f4..edcdd16bc 100644 --- a/next/pages/user/[username].js +++ b/next/pages/user/[username].js @@ -1692,9 +1692,23 @@ const PlansAndPayment = ({ userData }) => { const reg = new RegExp("(?<=:).*") const [ id ] = reg.exec(userData.id) - const user = await fetch(`/api/user/getUser?p=${btoa(id)}`, {method: "GET"}) - .then(res => res.json()) - cookies.set('userBD', JSON.stringify(user)) + let user + let attempts = 0 + const maxAttempts = 10 + const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) + + while (!user?.internalSubscription?.edges?.[0]?.node && attempts < maxAttempts) { + user = await fetch(`/api/user/getUser?p=${btoa(id)}`, { method: "GET" }) + .then((res) => res.json()) + + if (user?.internalSubscription?.edges?.[0]?.node) { + cookies.set("userBD", JSON.stringify(user)) + break + } + + attempts++ + await delay(10000) + } if(isLoadingH === true) return window.open("/", "_self") window.open(`/user/${userData.username}?plans_and_payment`, "_self") From b2225522f1e5e71a8d2c1cdfd797fee20aa9ac94 Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Tue, 1 Oct 2024 18:05:43 -0300 Subject: [PATCH 4/9] feat: add new design in user page for modal email gcp --- next/components/molecules/uiUserPage.js | 2 +- next/pages/api/user/changeUserGcpEmail.js | 44 ++ next/pages/api/user/getUser.js | 1 + next/pages/api/user/isEmailInGoogleGroup.js | 44 ++ next/pages/user/[username].js | 421 ++++++++++++++++++-- next/public/img/icons/penIcon.js | 4 +- 6 files changed, 475 insertions(+), 41 deletions(-) create mode 100644 next/pages/api/user/changeUserGcpEmail.js create mode 100644 next/pages/api/user/isEmailInGoogleGroup.js diff --git a/next/components/molecules/uiUserPage.js b/next/components/molecules/uiUserPage.js index 782f758f2..e59a4291b 100644 --- a/next/components/molecules/uiUserPage.js +++ b/next/components/molecules/uiUserPage.js @@ -94,7 +94,7 @@ export function ModalGeneral ({ minWidth={isMobileMod() ? "auto" : "536px"} boxSizing="content-box" padding="32px" - borderRadius="20px" + borderRadius="16px" {...propsModalContent} > diff --git a/next/pages/api/user/changeUserGcpEmail.js b/next/pages/api/user/changeUserGcpEmail.js new file mode 100644 index 000000000..4a247fd2f --- /dev/null +++ b/next/pages/api/user/changeUserGcpEmail.js @@ -0,0 +1,44 @@ +import axios from "axios"; + +const API_URL= `${process.env.NEXT_PUBLIC_API_URL}/api/v1/graphql` + +async function changeUserGcpEmail(email, token) { + try { + const res = await axios({ + url: API_URL, + method: "POST", + headers: { + Authorization: `Bearer ${token}` + }, + data: { + query: ` + mutation { + changeUserGcpEmail (email: "${email}"){ + ok + errors + } + } + ` + } + }) + const data = res.data?.data?.changeUserGcpEmail + 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 changeUserGcpEmail(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) +} diff --git a/next/pages/api/user/getUser.js b/next/pages/api/user/getUser.js index d9749b807..b38d3de83 100644 --- a/next/pages/api/user/getUser.js +++ b/next/pages/api/user/getUser.js @@ -20,6 +20,7 @@ async function getUser(id, token) { isAdmin isActive isEmailVisible + gcpEmail picture username firstName diff --git a/next/pages/api/user/isEmailInGoogleGroup.js b/next/pages/api/user/isEmailInGoogleGroup.js new file mode 100644 index 000000000..31472609a --- /dev/null +++ b/next/pages/api/user/isEmailInGoogleGroup.js @@ -0,0 +1,44 @@ +import axios from "axios"; + +const API_URL= `${process.env.NEXT_PUBLIC_API_URL}/api/v1/graphql` + +async function isEmailInGoogleGroup(email, token) { + try { + const res = await axios({ + url: API_URL, + method: "POST", + headers: { + Authorization: `Bearer ${token}` + }, + data: { + query: ` + query { + isEmailInGoogleGroup (email: "${email}"){ + ok + errors + } + } + ` + } + }) + const data = res.data?.data?.isEmailInGoogleGroup + 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 isEmailInGoogleGroup(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) +} diff --git a/next/pages/user/[username].js b/next/pages/user/[username].js index edcdd16bc..d263aa29e 100644 --- a/next/pages/user/[username].js +++ b/next/pages/user/[username].js @@ -733,7 +733,7 @@ const Account = ({ userInfo }) => { fontSize="14px" top="24px" right="26px" - _hover={{backgroundColor: "transparent", color:"#42B0FF"}} + _hover={{backgroundColor: "transparent", opacity: 0.7}} onClick={() => { setEmailSent(false) emailModal.onClose() @@ -749,7 +749,7 @@ const Account = ({ userInfo }) => { fontSize="14px" top="34px" right="26px" - _hover={{backgroundColor: "transparent", color:"#42B0FF"}} + _hover={{backgroundColor: "transparent", opacity: 0.7}} /> } @@ -888,7 +888,7 @@ instruções enviadas no e-mail para completar a alteração. @@ -1190,7 +1190,7 @@ const NewPassword = ({ userInfo }) => { fontSize="14px" top="34px" right="26px" - _hover={{backgroundColor: "transparent", color:"#42B0FF"}} + _hover={{backgroundColor: "transparent", opacity: 0.7}} /> @@ -1448,7 +1448,11 @@ const PlansAndPayment = ({ userData }) => { const [couponInfos, setCouponInfos] = useState({}) const [couponInputFocus, setCouponInputFocus] = useState(false) const [coupon, setCoupon] = useState("") + const [emailGCP, setEmailGCP] = useState(userData?.gcpEmail || userData?.email) + const [emailGCPFocus, setEmailGCPFocus] = useState(false) + const [errEmailGCP, setErrEmailGCP] = useState(false) const PaymentModal = useDisclosure() + const EmailModal = useDisclosure() const SucessPaymentModal = useDisclosure() const ErroPaymentModal = useDisclosure() const PlansModal = useDisclosure() @@ -1518,7 +1522,7 @@ const PlansAndPayment = ({ userData }) => { const value = Object.values(plans).find(elm => elm._id === plan) if(value?.interval === "month") setToggleAnual(false) setCheckoutInfos(value) - PaymentModal.onOpen() + EmailModal.onOpen() }, [plan, plans]) useEffect(() => { @@ -1800,6 +1804,22 @@ const PlansAndPayment = ({ userData }) => { ) } + async function handlerEmailGcp() { + setErrEmailGCP(false) + + function isValidEmail(email) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ + return emailRegex.test(email) + } + if(!isValidEmail(emailGCP)) return setErrEmailGCP(true) + + const response = await fetch(`/api/user/changeUserGcpEmail?p=${btoa(emailGCP)}`) + .then(res => res.json()) + + EmailModal.onClose() + PaymentModal.onOpen() + } + useEffect(() => { if(valueCoupon === "") { setCoupon("") @@ -1834,6 +1854,16 @@ const PlansAndPayment = ({ userData }) => { isCentered={isMobileMod() ? false : true} > + + Passo 2 de 2 + { fontSize="14px" top="34px" right="26px" - _hover={{backgroundColor: "transparent", color:"#42B0FF"}} + _hover={{backgroundColor: "transparent", opacity: 0.7}} /> @@ -2090,6 +2120,37 @@ const PlansAndPayment = ({ userData }) => { A partir do {couponInfos?.duration === "once" && 2} {couponInfos?.duration === "repeating" && couponInfos?.durationInMonths + 1}º {formattedPlanInterval(checkoutInfos?.interval, true)} {!hasSubscribed && "e 7º dia"}, o total a pagar será de {checkoutInfos?.amount?.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL', minimumFractionDigits: 2 })}/{formattedPlanInterval(checkoutInfos?.interval, true)}. } + + { + PaymentModal.onClose() + EmailModal.onOpen() + }} + > + Voltar + @@ -2113,9 +2174,188 @@ const PlansAndPayment = ({ userData }) => { + {/* email gcp */} + { + setEmailGCP(userData?.gcpEmail || userData?.email) + setErrEmailGCP(false) + EmailModal.onClose() + }} + propsModalContent={{ + width: "100%", + maxWidth:"1008px", + margin: "24px" + }} + isCentered={isMobileMod() ? false : true} + > + + + Passo 1 de 2 + + + + + + + E-mail de acesso ao BigQuery + + + + Utilizaremos o seu e-mail para garantir acesso exclusivo aos dados pelo BigQuery. Já preenchemos com o e-mail que você usou ao criar sua conta na nossa plataforma. Caso prefira usar outro e-mail para acessar o BigQuery, basta editá-lo abaixo. + + + + E-mail de acesso + + + + + + + {errEmailGCP && + + Por favor, insira um e-mail válido. + + } + + + + { + setEmailGCP(userData?.gcpEmail || userData?.email) + setErrEmailGCP(false) + EmailModal.onClose() + }} + > + Cancelar + + + handlerEmailGcp()} + > + Próximo + + + + {/* success */} setIsLoading(true)} > @@ -2124,7 +2364,7 @@ const PlansAndPayment = ({ userData }) => { fontSize="14px" top="28px" right="26px" - _hover={{backgroundColor: "transparent", color:"#42B0FF"}} + _hover={{backgroundColor: "transparent", opacity: 0.7}} /> @@ -2145,24 +2385,23 @@ const PlansAndPayment = ({ userData }) => { fill="#34A15A" /> - Parabéns! + Assinatura efetuada com sucesso! - Seu pagamento foi efetuado com sucesso e seu plano foi atualizado. + O acesso aos dados foi concedido para o e-mail {emailGCP}. Se precisar alterar o e-mail de acesso, você pode fazer isso na seção “BigQuery” das configurações da sua conta. + Em caso de dúvida, entre em contato com nosso suporte. @@ -2172,26 +2411,61 @@ const PlansAndPayment = ({ userData }) => { gap="24px" width="100%" > - setIsLoading(true)} + color="#2B8C4D" + borderColor="#2B8C4D" + _hover={{ + borderColor: "#22703E", + color: "#22703E" + }} + fontFamily="Roboto" + fontWeight="500" + fontSize="14px" + lineHeight="20px" + onClick={() => window.open(`/user/${userData?.username}?big_query`, "_self")} > {isLoading ? : - "Continuar nas configurações" + "Alterar e-mail de acesso" } - + - setIsLoadingH(true)} > {isLoadingH ? @@ -2199,7 +2473,7 @@ const PlansAndPayment = ({ userData }) => { : "Ir para a página inicial" } - + @@ -2214,7 +2488,7 @@ const PlansAndPayment = ({ userData }) => { fontSize="14px" top="28px" right="26px" - _hover={{backgroundColor: "transparent", color:"#42B0FF"}} + _hover={{backgroundColor: "transparent", opacity: 0.7}} /> @@ -2318,7 +2592,7 @@ const PlansAndPayment = ({ userData }) => { fontSize="14px" top="34px" right="26px" - _hover={{backgroundColor: "transparent", color:"#42B0FF"}} + _hover={{backgroundColor: "transparent", opacity: 0.7}} /> @@ -2416,7 +2690,7 @@ const PlansAndPayment = ({ userData }) => { onClick: subscriptionInfo?.stripeSubscription === "bd_pro" ? () => {} : () => { setPlan(plans?.[`bd_pro_${toggleAnual ? "year" : "month"}`]._id) PlansModal.onClose() - PaymentModal.onOpen() + EmailModal.onOpen() }, isCurrentPlan: subscriptionInfo?.stripeSubscription === "bd_pro" ? true : false, }} @@ -2437,7 +2711,7 @@ const PlansAndPayment = ({ userData }) => { onClick: subscriptionInfo?.stripeSubscription === "bd_pro_empresas" ? () => {} : () => { setPlan(plans?.[`bd_empresas_${toggleAnual ? "year" : "month"}`]._id) PlansModal.onClose() - PaymentModal.onOpen() + EmailModal.onOpen() }, isCurrentPlan: subscriptionInfo?.stripeSubscription === "bd_pro_empresas" ? true : false, }} @@ -2464,7 +2738,7 @@ const PlansAndPayment = ({ userData }) => { fontSize="14px" top="34px" right="26px" - _hover={{backgroundColor: "transparent", color:"#42B0FF"}} + _hover={{backgroundColor: "transparent", opacity: 0.7}} /> @@ -2514,7 +2788,7 @@ const PlansAndPayment = ({ userData }) => { fontSize="14px" top="34px" right="26px" - _hover={{backgroundColor: "transparent", color:"#42B0FF"}} + _hover={{backgroundColor: "transparent", opacity: 0.7}} /> @@ -2864,7 +3138,76 @@ const Accesses = ({ userInfo }) => { ) } -// Sections Of User Page + +const BigQuery = ({ userInfo }) => { + const [emailGcp, setEmailGcp] = useState(userInfo?.emailgcp || userInfo?.email) + const [errors, setErrors] = useState({}) + const [isLoading, setIsLoading] = useState(false) + + async function handleUpdateEmailGcp() { + + } + + return ( + + + E-mail de acesso ao BigQuery + + + + O seu e-mail é utilizado para garantir acesso exclusivo aos dados pelo BigQuery. + + + + setEmailGcp(e)} + placeholder="Insira o e-mail que deseja utilizar para acessar o BigQuery" + fontFamily="ubuntu" + maxWidth="480px" + height="40px" + fontSize="14px" + borderRadius="16px" + _invalid={{boxShadow:"0 0 0 2px #D93B3B"}} + /> + + {errors.emailGcp} + + + + handleUpdateEmailGcp()} + isDisabled={isLoading} + > + {isLoading ? + + : + "Atualizar e-mail" + } + + + ) +} export default function UserPage({ getUser }) { const router = useRouter() @@ -2881,6 +3224,7 @@ export default function UserPage({ getUser }) { {bar: "Conta", title: "Conta", value: "account", index: 1}, {bar: "Senha", title: "Alterar senha", value: "new_password", index: 2}, {bar: "Planos e pagamento", title: "Planos e pagamento", value: "plans_and_payment", index: 3}, + {bar: "BigQuery", title: "BigQuery", value: "big_query", index: 4}, ] // {bar: "Acessos", title: "Gerenciar acessos", value: "accesses", index: 4}, @@ -2961,6 +3305,7 @@ export default function UserPage({ getUser }) { {sectionSelected === 1 && } {sectionSelected === 2 && } {sectionSelected === 3 && } + {sectionSelected === 4 && } {/* {sectionSelected === 4 && } */} diff --git a/next/public/img/icons/penIcon.js b/next/public/img/icons/penIcon.js index 64f6af984..bd061b1fa 100644 --- a/next/public/img/icons/penIcon.js +++ b/next/public/img/icons/penIcon.js @@ -2,11 +2,11 @@ import { createIcon } from '@chakra-ui/icons'; const PenIcon = createIcon({ displayName: "pen", - viewBox: "0 0 22 22", + viewBox: "0 0 32 32", path: ( ) }) From de6180df6ae225a8c426125ba3ebbd5792142810 Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Thu, 3 Oct 2024 07:03:34 -0300 Subject: [PATCH 5/9] feat: wip visual and functional ajust --- next/pages/user/[username].js | 193 ++++++++++++++++++++++------------ 1 file changed, 127 insertions(+), 66 deletions(-) diff --git a/next/pages/user/[username].js b/next/pages/user/[username].js index d263aa29e..7c3553be9 100644 --- a/next/pages/user/[username].js +++ b/next/pages/user/[username].js @@ -1451,6 +1451,7 @@ const PlansAndPayment = ({ userData }) => { const [emailGCP, setEmailGCP] = useState(userData?.gcpEmail || userData?.email) const [emailGCPFocus, setEmailGCPFocus] = useState(false) const [errEmailGCP, setErrEmailGCP] = useState(false) + const PaymentModal = useDisclosure() const EmailModal = useDisclosure() const SucessPaymentModal = useDisclosure() @@ -1458,6 +1459,7 @@ const PlansAndPayment = ({ userData }) => { const PlansModal = useDisclosure() const CancelModalPlan = useDisclosure() const AlertChangePlanModal = useDisclosure() + const [isLoading, setIsLoading] = useState(false) const [isLoadingH, setIsLoadingH] = useState(false) const [isLoadingCanSub, setIsLoadingCanSub] = useState(false) @@ -1814,7 +1816,7 @@ const PlansAndPayment = ({ userData }) => { if(!isValidEmail(emailGCP)) return setErrEmailGCP(true) const response = await fetch(`/api/user/changeUserGcpEmail?p=${btoa(emailGCP)}`) - .then(res => res.json()) + .then(res => res.json()) EmailModal.onClose() PaymentModal.onOpen() @@ -1933,29 +1935,36 @@ const PlansAndPayment = ({ userData }) => { - {toggleAnual ? - changeIntervalPlanCheckout()} - /> - : - changeIntervalPlanCheckout()} - /> - } - Desconto anual + + {toggleAnual ? + changeIntervalPlanCheckout()} + /> + : + changeIntervalPlanCheckout()} + /> + } + Desconto anual + { } - { - PaymentModal.onClose() - EmailModal.onOpen() - }} - > - Voltar + + { + PaymentModal.onClose() + EmailModal.onOpen() + }} + > + Voltar + @@ -2185,7 +2196,7 @@ const PlansAndPayment = ({ userData }) => { propsModalContent={{ width: "100%", maxWidth:"1008px", - margin: "24px" + margin: "24px", }} isCentered={isMobileMod() ? false : true} > @@ -2208,7 +2219,7 @@ const PlansAndPayment = ({ userData }) => { /> - + { lineHeight="24px" marginBottom="32px !important" > - Utilizaremos o seu e-mail para garantir acesso exclusivo aos dados pelo BigQuery. Já preenchemos com o e-mail que você usou ao criar sua conta na nossa plataforma. Caso prefira usar outro e-mail para acessar o BigQuery, basta editá-lo abaixo. + O seu e-mail precisa ser uma Conta Google para garantir acesso exclusivo aos dados pelo BigQuery. Já preenchemos com o e-mail que você usou ao criar sua conta na nossa plataforma. Caso necessite usar outro e-mail para acessar o BigQuery, basta editá-lo abaixo. { { } - + { setEmailGCP(userData?.gcpEmail || userData?.email) setErrEmailGCP(false) EmailModal.onClose() + }} > Cancelar @@ -2325,7 +2343,7 @@ const PlansAndPayment = ({ userData }) => { display="flex" alignItems="center" justifyContent="center" - width="fit-content" + width={{base: "100%", lg:"fit-content"}} height="40px" borderRadius="8px" padding="10px 34px" @@ -2416,7 +2434,7 @@ const PlansAndPayment = ({ userData }) => { display="flex" alignItems="center" justifyContent="center" - width="50%" + width={{base:"100%", lg: "50%"}} height="40px" borderRadius="8px" padding="10px 34px" @@ -2448,7 +2466,7 @@ const PlansAndPayment = ({ userData }) => { display="flex" alignItems="center" justifyContent="center" - width="50%" + width={{base:"100%", lg: "50%"}} height="40px" borderRadius="8px" padding="10px 34px" @@ -3140,16 +3158,53 @@ const Accesses = ({ userInfo }) => { } const BigQuery = ({ userInfo }) => { - const [emailGcp, setEmailGcp] = useState(userInfo?.emailgcp || userInfo?.email) + const [emailGcp, setEmailGcp] = useState(userInfo?.gcpEmail || userInfo?.email) const [errors, setErrors] = useState({}) const [isLoading, setIsLoading] = useState(false) async function handleUpdateEmailGcp() { - + setErrors({}) + setIsLoading(true) + + function isValidEmail(email) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ + return emailRegex.test(email) + } + + if(!isValidEmail(emailGcp)) { + setErrors({emailGcp: "Por favor, insira um e-mail válido."}) + } else { + const reg = new RegExp("(?<=:).*") + const [ id ] = reg.exec(userInfo.id) + + let user + let attempts = 0 + const maxAttempts = 10 + const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) + + const response = await fetch(`/api/user/changeUserGcpEmail?p=${btoa(emailGcp)}`) + .then(res => res.json()) + + while (!user?.gcpEmail && attempts < maxAttempts) { + user = await fetch(`/api/user/getUser?p=${btoa(id)}`, { method: "GET" }) + .then((res) => res.json()) + + if (user?.gcpEmail) { + cookies.set("userBD", JSON.stringify(user)) + break + } + + attempts++ + await delay(10000) + } + } + setIsLoading(false) } return ( + + { letterSpacing="0.3px" color="#7D7D7D" > - O seu e-mail é utilizado para garantir acesso exclusivo aos dados pelo BigQuery. + O seu e-mail precisa ser uma Conta Google para garantir acesso exclusivo aos dados pelo BigQuery. @@ -3177,9 +3232,10 @@ const BigQuery = ({ userInfo }) => { id="emailgcp" name="emailgcp" value={emailGcp} - onChange={(e) => setEmailGcp(e)} + onChange={(e) => setEmailGcp(e.target.value)} placeholder="Insira o e-mail que deseja utilizar para acessar o BigQuery" fontFamily="ubuntu" + maxWidth="480px" height="40px" fontSize="14px" @@ -3219,12 +3275,17 @@ export default function UserPage({ getUser }) { setUserInfo(getUser) }, [getUser]) + const isUserPro = () => { + if(getUser?.internalSubscription?.edges?.[0]?.node?.isActive === true) return true + return false + } + const choices = [ {bar: "Perfil público", title: "Perfil público", value: "profile", index: 0}, {bar: "Conta", title: "Conta", value: "account", index: 1}, {bar: "Senha", title: "Alterar senha", value: "new_password", index: 2}, {bar: "Planos e pagamento", title: "Planos e pagamento", value: "plans_and_payment", index: 3}, - {bar: "BigQuery", title: "BigQuery", value: "big_query", index: 4}, + isUserPro() && {bar: "BigQuery", title: "BigQuery", value: "big_query", index: 4}, ] // {bar: "Acessos", title: "Gerenciar acessos", value: "accesses", index: 4}, @@ -3305,7 +3366,7 @@ export default function UserPage({ getUser }) { {sectionSelected === 1 && } {sectionSelected === 2 && } {sectionSelected === 3 && } - {sectionSelected === 4 && } + {sectionSelected === 4 && isUserPro() && } {/* {sectionSelected === 4 && } */} From 2da285a58346d118727ec6560601413edb79906b Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Thu, 3 Oct 2024 08:41:57 -0300 Subject: [PATCH 6/9] fix: bug open modal for change toggle disount --- next/pages/user/[username].js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/next/pages/user/[username].js b/next/pages/user/[username].js index 7c3553be9..48596d165 100644 --- a/next/pages/user/[username].js +++ b/next/pages/user/[username].js @@ -1448,6 +1448,7 @@ const PlansAndPayment = ({ userData }) => { const [couponInfos, setCouponInfos] = useState({}) const [couponInputFocus, setCouponInputFocus] = useState(false) const [coupon, setCoupon] = useState("") + const [hasOpenEmailModal, setHasOpenEmailModal] = useState(false) const [emailGCP, setEmailGCP] = useState(userData?.gcpEmail || userData?.email) const [emailGCPFocus, setEmailGCPFocus] = useState(false) const [errEmailGCP, setErrEmailGCP] = useState(false) @@ -1524,7 +1525,10 @@ const PlansAndPayment = ({ userData }) => { const value = Object.values(plans).find(elm => elm._id === plan) if(value?.interval === "month") setToggleAnual(false) setCheckoutInfos(value) - EmailModal.onOpen() + if(!hasOpenEmailModal) { + EmailModal.onOpen() + setHasOpenEmailModal(true) + } }, [plan, plans]) useEffect(() => { From a49b7d1c44a0f9532515b8cf06e64f7f39c5ba61 Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Fri, 4 Oct 2024 10:33:18 -0300 Subject: [PATCH 7/9] feat: ajust mobile visual modal emailGcp --- next/pages/user/[username].js | 51 ++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/next/pages/user/[username].js b/next/pages/user/[username].js index 48596d165..fcf883dac 100644 --- a/next/pages/user/[username].js +++ b/next/pages/user/[username].js @@ -1452,7 +1452,8 @@ const PlansAndPayment = ({ userData }) => { const [emailGCP, setEmailGCP] = useState(userData?.gcpEmail || userData?.email) const [emailGCPFocus, setEmailGCPFocus] = useState(false) const [errEmailGCP, setErrEmailGCP] = useState(false) - + const [isLoadingEmailChange, setIsLoadingEmailChange] = useState(false) + const PaymentModal = useDisclosure() const EmailModal = useDisclosure() const SucessPaymentModal = useDisclosure() @@ -1812,6 +1813,7 @@ const PlansAndPayment = ({ userData }) => { async function handlerEmailGcp() { setErrEmailGCP(false) + setIsLoadingEmailChange(true) function isValidEmail(email) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ @@ -1822,6 +1824,7 @@ const PlansAndPayment = ({ userData }) => { const response = await fetch(`/api/user/changeUserGcpEmail?p=${btoa(emailGCP)}`) .then(res => res.json()) + setIsLoadingEmailChange(false) EmailModal.onClose() PaymentModal.onOpen() } @@ -2000,7 +2003,7 @@ const PlansAndPayment = ({ userData }) => { @@ -2042,7 +2045,7 @@ const PlansAndPayment = ({ userData }) => { display="flex" alignItems="center" justifyContent="center" - width="fit-content" + width={{base: "100%", lg: "fit-content"}} height="44px" borderRadius="8px" padding="10px 34px" @@ -2134,7 +2137,7 @@ const PlansAndPayment = ({ userData }) => { } - + { onSucess={() => openModalSucess()} onErro={() => openModalErro()} /> + + + { + PaymentModal.onClose() + EmailModal.onOpen() + }} + > + Voltar + + @@ -2308,7 +2343,7 @@ const PlansAndPayment = ({ userData }) => { spacing={0} gap="16px" justifyContent="end" - flexDirection={{base: "column", lg:"row"}} + flexDirection={{base: "column-reverse", lg:"row"}} > { lineHeight="20px" onClick={() => handlerEmailGcp()} > - Próximo + {isLoadingEmailChange ? + + : + "Próximo" + } From 5b668f63222bafcf05ec12bfd3aee79d30a58fbc Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Mon, 7 Oct 2024 09:26:31 -0300 Subject: [PATCH 8/9] fix: get response change emailgcp fix --- next/pages/user/[username].js | 36 +++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/next/pages/user/[username].js b/next/pages/user/[username].js index fcf883dac..2555fbe24 100644 --- a/next/pages/user/[username].js +++ b/next/pages/user/[username].js @@ -1824,9 +1824,13 @@ const PlansAndPayment = ({ userData }) => { const response = await fetch(`/api/user/changeUserGcpEmail?p=${btoa(emailGCP)}`) .then(res => res.json()) - setIsLoadingEmailChange(false) - EmailModal.onClose() - PaymentModal.onOpen() + if(response.ok) { + setIsLoadingEmailChange(false) + EmailModal.onClose() + PaymentModal.onOpen() + } else { + setErrEmailGCP(true) + } } useEffect(() => { @@ -3227,18 +3231,22 @@ const BigQuery = ({ userInfo }) => { const response = await fetch(`/api/user/changeUserGcpEmail?p=${btoa(emailGcp)}`) .then(res => res.json()) - - while (!user?.gcpEmail && attempts < maxAttempts) { - user = await fetch(`/api/user/getUser?p=${btoa(id)}`, { method: "GET" }) - .then((res) => res.json()) - - if (user?.gcpEmail) { - cookies.set("userBD", JSON.stringify(user)) - break + + if(response.ok) { + while (!user?.gcpEmail && attempts < maxAttempts) { + user = await fetch(`/api/user/getUser?p=${btoa(id)}`, { method: "GET" }) + .then((res) => res.json()) + + if (user?.gcpEmail) { + cookies.set("userBD", JSON.stringify(user)) + break + } + + attempts++ + await delay(10000) } - - attempts++ - await delay(10000) + } else { + setErrors({emailGcp: "Por favor, insira um e-mail válido."}) } } setIsLoading(false) From 29513ebdc2b2a78025c861fa35d31d6834ef9478 Mon Sep 17 00:00:00 2001 From: aldemirLucas Date: Tue, 8 Oct 2024 07:54:54 -0300 Subject: [PATCH 9/9] feat: add trigger emailgcp in GA --- next/pages/user/[username].js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/next/pages/user/[username].js b/next/pages/user/[username].js index 2555fbe24..729e24df8 100644 --- a/next/pages/user/[username].js +++ b/next/pages/user/[username].js @@ -44,7 +44,7 @@ import Toggle from "../../components/atoms/Toggle"; import { CardPrice } from "../precos"; import PaymentSystem from "../../components/organisms/PaymentSystem"; import ImageCrop from "../../components/molecules/ImgCrop"; -import { cleanString } from "../../utils"; +import { cleanString, triggerGAEvent } from "../../utils"; import { LabelTextForm, @@ -1824,7 +1824,12 @@ const PlansAndPayment = ({ userData }) => { const response = await fetch(`/api/user/changeUserGcpEmail?p=${btoa(emailGCP)}`) .then(res => res.json()) - if(response.ok) { + if(response.ok) { + if(emailGCP !== userData?.email) { + if(emailGCP !== userData?.gcpEmail) { + triggerGAEvent("troca_do_email_gcp",`checkout_de_pagamento`) + } + } setIsLoadingEmailChange(false) EmailModal.onClose() PaymentModal.onOpen() @@ -3233,6 +3238,12 @@ const BigQuery = ({ userInfo }) => { .then(res => res.json()) if(response.ok) { + if(emailGcp !== userInfo?.email) { + if(emailGcp !== userInfo?.gcpEmail) { + triggerGAEvent("troca_do_email_gcp",`section_bigquery`) + } + } + while (!user?.gcpEmail && attempts < maxAttempts) { user = await fetch(`/api/user/getUser?p=${btoa(id)}`, { method: "GET" }) .then((res) => res.json())