From b5ebadbb93fa222b1dbe08c2ae8ed941d6f9966c Mon Sep 17 00:00:00 2001 From: Gustavo Date: Mon, 12 May 2025 16:46:31 +0200 Subject: [PATCH 1/7] add conutry code when fetching the courses on the bootcamp page --- src/pages/bootcamp/[course_slug].jsx | 95 ++++------------------------ src/services/breathecode.js | 1 + 2 files changed, 12 insertions(+), 84 deletions(-) diff --git a/src/pages/bootcamp/[course_slug].jsx b/src/pages/bootcamp/[course_slug].jsx index 1de63a98e..7f9d82e6d 100644 --- a/src/pages/bootcamp/[course_slug].jsx +++ b/src/pages/bootcamp/[course_slug].jsx @@ -1,14 +1,12 @@ /* eslint-disable camelcase */ /* eslint-disable no-unused-vars */ -import axios from 'axios'; -import PropTypes from 'prop-types'; import { Box, Button, Flex, Image, SkeletonText, Badge } from '@chakra-ui/react'; import { useEffect, useState, useRef } from 'react'; import useTranslation from 'next-translate/useTranslation'; import { useRouter } from 'next/router'; import Head from 'next/head'; import { parseQuerys } from '../../utils/url'; -import { BREATHECODE_HOST, ORIGIN_HOST, WHITE_LABEL_ACADEMY, BASE_COURSE } from '../../utils/variables'; +import { BREATHECODE_HOST, ORIGIN_HOST, BASE_COURSE } from '../../utils/variables'; import Icon from '../../components/Icon'; import Text from '../../components/Text'; import GridContainer from '../../components/GridContainer'; @@ -48,75 +46,10 @@ import useCustomToast from '../../hooks/useCustomToast'; import { usePlanPrice } from '../../utils/getPriceWithDiscount'; import useSession from '../../hooks/useSession'; -export async function getStaticPaths({ locales }) { - const mktQueryString = parseQuerys({ - featured: true, - academy: WHITE_LABEL_ACADEMY, - }); - - const getAllCourses = await Promise.all(locales.map(async (locale) => { - const resp = await axios.get(`${BREATHECODE_HOST}/v1/marketing/course${mktQueryString}&lang=${locale}`); - return resp?.data; - })); - - const filterByTranslations = getAllCourses.flat().filter((item) => item?.course_translation !== null); - const paths = filterByTranslations.flatMap((course) => { - const locale = course?.course_translation?.lang?.split('-')[0]; - return course?.slug && ({ - params: { - course_slug: course?.slug, - }, - locale, - }); - }); - - return { - fallback: false, - paths, - }; -} -export async function getStaticProps({ locale, locales, params }) { - const { course_slug: courseSlug } = params; - - const endpoint = `/v1/marketing/course/${courseSlug}?lang=${locale}`; - const resp = await axios.get(`${BREATHECODE_HOST}${endpoint}`); - const data = resp?.data; - - if (resp?.status >= 400) { - console.error(`ERROR with /bootcamp/course/${courseSlug}: something went wrong fetching "${endpoint}"`); - return { - notFound: true, - }; - } - - const syllabusSlug = data.syllabus[0]?.slug; - - const respSyll = await axios.get(`${BREATHECODE_HOST}/v1/admissions/syllabus/version?slug=${syllabusSlug}`); - const syllabus = respSyll?.data[0]; - - return { - props: { - seo: { - title: data.course_translation.title, - description: data.course_translation.description, - image: data?.course_translation?.preview_url || `${ORIGIN_HOST}/static/images/4geeks.png`, - locales, - locale, - disableStaticCanonical: true, - disableHreflangs: true, - url: `/bootcamp/${data.slug}`, - pathConnector: '/bootcamp', - card: 'default', - }, - data, - syllabus, - }, - }; -} - -function CoursePage({ data, syllabus }) { +function CoursePage() { const { state, getPriceWithDiscount, getSelfAppliedCoupon, applyDiscountCouponsToPlans } = useSignup(); const [coupon] = usePersistentBySession('coupon', ''); + const [data, setData] = useState({}); const { selfAppliedCoupon } = state; const showBottomCTA = useRef(null); const [isCtaVisible, setIsCtaVisible] = useState(false); @@ -146,6 +79,7 @@ function CoursePage({ data, syllabus }) { const cohortId = data?.cohort?.id; const isVisibilityPublic = data.visibility === 'PUBLIC'; const courseColor = data?.color; + const { course_slug: courseSlug } = router.query; const structuredData = data?.course_translation ? { '@context': 'https://schema.org', @@ -204,7 +138,7 @@ function CoursePage({ data, syllabus }) { const country_code = location?.countryShort; useEffect(() => { - if (isRigoInitialized && data.course_translation && !initialDataIsFetching && planData?.slug) { + if (isRigoInitialized && data?.course_translation && !initialDataIsFetching && planData?.slug) { // const context = document.body.innerText; const plans = applyDiscountCouponsToPlans(planData.planList, selfAppliedCoupon); @@ -216,8 +150,8 @@ function CoursePage({ data, syllabus }) { period: ${plan.period_label} ${plan.lastPrice ? `original price: ${isSpain && plan.type !== 'FREE' ? '199.99€' : plan.lastPrice}\n discount: ${discount}\n` : ''} `); - const syllabusContext = syllabus?.json - ? syllabus.json.days + const syllabusContext = cohortData?.cohortSyllabus?.syllabus?.json + ? cohortData.cohortSyllabus.syllabus.json.days .map(({ label, description }) => `- Title: ${typeof label === 'object' ? (label[lang] || label.us) : label}, Description: ${typeof description === 'object' ? (description[lang] || description.us) : description}`) : ''; @@ -356,7 +290,10 @@ function CoursePage({ data, syllabus }) { const getInitialData = async () => { setInitialDataIsFetching(true); - const cohortSyllabus = await generateCohortSyllabusModules(cohortId); + const { data: courseData } = await bc.marketing({ lang, country_code }).getCourse(courseSlug); + setData(courseData); + + const cohortSyllabus = await generateCohortSyllabusModules(courseData?.cohort?.id); const getModulesInfo = async () => { try { @@ -1094,14 +1031,4 @@ function CoursePage({ data, syllabus }) { ); } -CoursePage.propTypes = { - data: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array])), - syllabus: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.any])), -}; - -CoursePage.defaultProps = { - data: {}, - syllabus: null, -}; - export default CoursePage; diff --git a/src/services/breathecode.js b/src/services/breathecode.js index 79068d884..0d365dd91 100644 --- a/src/services/breathecode.js +++ b/src/services/breathecode.js @@ -321,6 +321,7 @@ const breathecode = { return { lead: (data) => axios.post(`${url}/lead${qs}`, data), courses: () => axios.get(`${url}/course${qs}`), + getCourse: (courseSlug) => axios.get(`${url}/course/${courseSlug}${qs}`), }; }, From b4464156f848969dba0bf6ea7b77daca51e90134 Mon Sep 17 00:00:00 2001 From: Gustavo Date: Mon, 12 May 2025 16:54:46 +0200 Subject: [PATCH 2/7] add country code to marketing courses endpoints --- src/components/Navbar/index.jsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/Navbar/index.jsx b/src/components/Navbar/index.jsx index 5f712d093..0888670c0 100644 --- a/src/components/Navbar/index.jsx +++ b/src/components/Navbar/index.jsx @@ -34,7 +34,7 @@ import { getAllMySubscriptions } from '../../handlers/subscriptions'; function Navbar({ translations, pageProps }) { const [uniqueLanguages, setUniqueLanguages] = useState([]); - const { userSession, location } = useSession(); + const { userSession, location, isLoadingLocation } = useSession(); const isUtmMediumAcademy = userSession?.utm_medium === 'academy'; const { isAuthenticated, isLoading, user, logout, cohorts } = useAuth(); const [navbarItems, setNavbarItems] = useState([]); @@ -141,8 +141,10 @@ function Navbar({ translations, pageProps }) { }; useEffect(() => { - fetchMktCourses(); - }, [locale]); + if (!isLoadingLocation) { + fetchMktCourses(); + } + }, [locale, isLoadingLocation]); useEffect(() => { if (pageProps?.existsWhiteLabel) { From 11c4bb3196af0d1fb8f23bc3cb49911646b9619d Mon Sep 17 00:00:00 2001 From: lumi-tip Date: Mon, 12 May 2025 14:27:21 -0400 Subject: [PATCH 3/7] small change on oneColumn picture --- src/components/MktOneColumnSection/ImageOnTopVariation.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/MktOneColumnSection/ImageOnTopVariation.jsx b/src/components/MktOneColumnSection/ImageOnTopVariation.jsx index 23985acf8..1ba568982 100644 --- a/src/components/MktOneColumnSection/ImageOnTopVariation.jsx +++ b/src/components/MktOneColumnSection/ImageOnTopVariation.jsx @@ -77,6 +77,7 @@ function ImageOnTopVariation({ src={image.url} alt={image.alt || title || 'Section image'} objectFit="cover" + objectPosition="50% 10%" width="100%" height={{ base: '271px', md: '365px' }} /> From 053705933ae524e255666afda091f7fbce12a0f8 Mon Sep 17 00:00:00 2001 From: lumi-tip Date: Mon, 12 May 2025 14:41:29 -0400 Subject: [PATCH 4/7] small change on oneColumn picture --- src/pages/bootcamp/[course_slug].jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/bootcamp/[course_slug].jsx b/src/pages/bootcamp/[course_slug].jsx index f8824d895..fe1ff0798 100644 --- a/src/pages/bootcamp/[course_slug].jsx +++ b/src/pages/bootcamp/[course_slug].jsx @@ -383,15 +383,15 @@ function CoursePage({ data, syllabus }) { }); let combinedFeaturedAssets = [ - ...filterAssets(exercises, true), ...filterAssets(projects, true), + ...filterAssets(exercises, true), ]; if (combinedFeaturedAssets.length < 3) { const remainingNeeded = 3 - combinedFeaturedAssets.length; const additionalItems = [ - ...filterAssets(exercises, false), ...filterAssets(projects, false), + ...filterAssets(exercises, false), ].slice(-remainingNeeded); combinedFeaturedAssets = [...combinedFeaturedAssets, ...additionalItems]; From 5b59b71099c7b4481a90183fcc7dffd005da5749 Mon Sep 17 00:00:00 2001 From: lumi-tip Date: Wed, 14 May 2025 18:43:40 -0400 Subject: [PATCH 5/7] allow aprender on for spaniars --- src/components/Navbar/index.jsx | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/components/Navbar/index.jsx b/src/components/Navbar/index.jsx index d831bd8c0..52a968efb 100644 --- a/src/components/Navbar/index.jsx +++ b/src/components/Navbar/index.jsx @@ -35,8 +35,7 @@ import { getAllMySubscriptions } from '../../handlers/subscriptions'; function Navbar({ translations, pageProps }) { const [uniqueLanguages, setUniqueLanguages] = useState([]); - const { userSession, location } = useSession(); - const isUtmMediumAcademy = userSession?.utm_medium === 'academy'; + const { location } = useSession(); const { isAuthenticated, isLoading, user, logout, cohorts } = useAuth(); const [navbarItems, setNavbarItems] = useState([]); const [mktCourses, setMktCourses] = useState([]); @@ -142,15 +141,10 @@ function Navbar({ translations, pageProps }) { useEffect(() => { if (pageProps?.existsWhiteLabel) { setNavbarItems(whiteLabelitems); + } else if (!isLoading && user?.id) { + setNavbarItems(preDefinedItems.filter((item) => (item.disabled !== true && item.hide_on_auth !== true))); } else { - const preFilteredItems = preDefinedItems.filter( - (item) => (isUtmMediumAcademy ? item.id !== 'bootcamps' : true) && (item.id === 'bootcamps' ? location?.countryShort !== 'ES' : true), - ); - if (!isLoading && user?.id) { - setNavbarItems(preFilteredItems.filter((item) => (item.disabled !== true && item.hide_on_auth !== true))); - } else { - setNavbarItems(preFilteredItems.filter((item) => item.disabled !== true)); - } + setNavbarItems(preDefinedItems.filter((item) => item.disabled !== true)); } }, [user, cohorts, isLoading, cohortSession, mktCourses, router.locale, location]); From 941584960bccd497eb6b92a4f6cf28befe1235fa Mon Sep 17 00:00:00 2001 From: lumi-tip Date: Wed, 14 May 2025 18:55:44 -0400 Subject: [PATCH 6/7] small change to redeploy --- src/components/Navbar/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Navbar/index.jsx b/src/components/Navbar/index.jsx index 52a968efb..8ecb147e8 100644 --- a/src/components/Navbar/index.jsx +++ b/src/components/Navbar/index.jsx @@ -130,7 +130,7 @@ function Navbar({ translations, pageProps }) { setMktCourses(coursesStruct || []); } catch (error) { - console.error(error); + console.error(`Error fetching mkt courses: ${error}`); } }; From 28532d7fe510d28099f8d2711b93138eca74fa8e Mon Sep 17 00:00:00 2001 From: Gustavo Date: Thu, 15 May 2025 10:44:16 +0200 Subject: [PATCH 7/7] add academy parameter to card post --- src/components/Checkout/PaymentInfo.jsx | 2 +- src/components/Checkout/ServiceSummary.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Checkout/PaymentInfo.jsx b/src/components/Checkout/PaymentInfo.jsx index aec9b79a4..8d6e5749c 100644 --- a/src/components/Checkout/PaymentInfo.jsx +++ b/src/components/Checkout/PaymentInfo.jsx @@ -270,7 +270,7 @@ function PaymentInfo({ setShowPaymentDetails }) { }; const handleSubmit = async (actions, values) => { - const resp = await bc.payment().addCard(values); + const resp = await bc.payment().addCard({ ...values, academy: selectedPlanCheckoutData.owner.id }); const data = await resp.json(); setIsSubmittingCard(false); diff --git a/src/components/Checkout/ServiceSummary.jsx b/src/components/Checkout/ServiceSummary.jsx index 67af5bc30..11b84dfce 100644 --- a/src/components/Checkout/ServiceSummary.jsx +++ b/src/components/Checkout/ServiceSummary.jsx @@ -166,7 +166,7 @@ function ServiceSummary({ service }) { }, }); } - const resp = await bc.payment().addCard(values); + const resp = await bc.payment().addCard({ ...values, academy: service.academy.id }); const data = await resp.json(); setIsSubmittingCard(false); if (resp.ok) {