From 46ca899c4374c6cbc6fb37db7bcf0717485a4add Mon Sep 17 00:00:00 2001 From: Belinda Marion Kobusingye <46527380+Codebmk@users.noreply.github.com> Date: Tue, 25 Feb 2025 18:25:30 +0300 Subject: [PATCH 01/20] fix redirect logic --- src/platform/src/core/utils/protectedRoute.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/platform/src/core/utils/protectedRoute.js b/src/platform/src/core/utils/protectedRoute.js index cc2bbf2469..332f57d931 100644 --- a/src/platform/src/core/utils/protectedRoute.js +++ b/src/platform/src/core/utils/protectedRoute.js @@ -14,6 +14,7 @@ import Spinner from '../../common/components/Spinner'; const MAX_RETRIES = 3; const RETRY_DELAY = 1000; +const LOGIN_ROUTE = '/account/login'; export default function withAuth(Component) { return function WithAuthComponent(props) { @@ -23,6 +24,7 @@ export default function withAuth(Component) { const [isRedirecting, setIsRedirecting] = React.useState( router.query.success === 'google', ); + const [redirectToLogin, setRedirectToLogin] = React.useState(false); const retryWithDelay = async (fn, retries = MAX_RETRIES) => { try { @@ -58,6 +60,7 @@ export default function withAuth(Component) { dispatch(setUserInfo(user)); dispatch(setSuccess(true)); + setIsRedirecting(false); }; useEffect(() => { @@ -73,18 +76,21 @@ export default function withAuth(Component) { .catch((error) => { console.error('Google auth error:', error); setIsRedirecting(false); - router.push('/account/login'); + setRedirectToLogin(true); + }) + .finally(() => { + if (!userCredentials.success) setRedirectToLogin(true); }); } else { setIsRedirecting(false); - router.push('/account/login'); + setRedirectToLogin(true); } return; // Exit early to prevent further checks until redirect is resolved } const storedUserGroup = localStorage.getItem('activeGroup'); if (!userCredentials.success) { - router.push('/account/login'); + setRedirectToLogin(true); } if (!storedUserGroup) { @@ -93,6 +99,13 @@ export default function withAuth(Component) { } }, [userCredentials, dispatch, router, retryWithDelay, isRedirecting]); + // Handle deferred redirect to /account/login + useEffect(() => { + if (redirectToLogin) { + router.push(LOGIN_ROUTE); + } + }, [redirectToLogin, router]); + // Block rendering until redirect is handled if (isRedirecting) { return ; From 26d1057cfcf0b4474e848918eba1413f72614158 Mon Sep 17 00:00:00 2001 From: Belinda Marion Kobusingye <46527380+Codebmk@users.noreply.github.com> Date: Tue, 25 Feb 2025 20:15:19 +0300 Subject: [PATCH 02/20] fix redirect --- src/platform/src/core/utils/protectedRoute.js | 79 ++++++++++++------- src/platform/src/pages/Home/index.jsx | 4 +- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/src/platform/src/core/utils/protectedRoute.js b/src/platform/src/core/utils/protectedRoute.js index 332f57d931..dd574f155f 100644 --- a/src/platform/src/core/utils/protectedRoute.js +++ b/src/platform/src/core/utils/protectedRoute.js @@ -1,12 +1,12 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { useRouter } from 'next/router'; import { useSelector, useDispatch } from 'react-redux'; -import LogoutUser from '@/core/utils/LogoutUser'; import Cookies from 'js-cookie'; import jwt_decode from 'jwt-decode'; import { setUserInfo, setSuccess, + resetStore, } from '@/lib/store/services/account/LoginSlice'; import { getIndividualUserPreferences } from '@/lib/store/services/account/UserDefaultsSlice'; import { getUserDetails } from '@/core/apis/Account'; @@ -21,10 +21,11 @@ export default function withAuth(Component) { const dispatch = useDispatch(); const router = useRouter(); const userCredentials = useSelector((state) => state.login); - const [isRedirecting, setIsRedirecting] = React.useState( + const [isRedirecting, setIsRedirecting] = useState( router.query.success === 'google', ); - const [redirectToLogin, setRedirectToLogin] = React.useState(false); + const [redirectToLogin, setRedirectToLogin] = useState(false); + const [isMounted, setIsMounted] = useState(false); const retryWithDelay = async (fn, retries = MAX_RETRIES) => { try { @@ -60,58 +61,78 @@ export default function withAuth(Component) { dispatch(setUserInfo(user)); dispatch(setSuccess(true)); - setIsRedirecting(false); + setIsRedirecting(false); // Clear redirecting state after success }; useEffect(() => { - if (typeof window !== 'undefined') { - // Handle Google redirect first + // Mark as mounted only once + if (!isMounted) { + setIsMounted(true); + } + + if (typeof window === 'undefined') return; + + const handleAuth = async () => { + // Handle Google redirect if (router.query.success === 'google') { - const token = Cookies.get('access_token'); - if (token) { + try { + const token = Cookies.get('temp_access_token'); + if (!token) { + throw new Error('No access_token cookie found'); + } + localStorage.setItem('token', token); const decoded = jwt_decode(token); - retryWithDelay(() => getUserDetails(decoded._id, token)) - .then((response) => setupUserSession(response.users[0])) - .catch((error) => { - console.error('Google auth error:', error); - setIsRedirecting(false); - setRedirectToLogin(true); - }) - .finally(() => { - if (!userCredentials.success) setRedirectToLogin(true); - }); - } else { + const response = await retryWithDelay(() => + getUserDetails(decoded._id, token), + ); + await setupUserSession(response.users[0]); + } catch (error) { + console.error('Google auth error:', error); setIsRedirecting(false); setRedirectToLogin(true); } - return; // Exit early to prevent further checks until redirect is resolved + return; } + // Handle authentication checks const storedUserGroup = localStorage.getItem('activeGroup'); if (!userCredentials.success) { setRedirectToLogin(true); + return; } if (!storedUserGroup) { - LogoutUser(dispatch, router); + dispatch(resetStore()); + if (typeof window !== 'undefined') { + localStorage.clear(); + } + const store = router.store || window.__NEXT_REDUX_STORE__; + if (store?.__persistor) { + await store.__persistor.purge(); + } + setRedirectToLogin(true); } - } - }, [userCredentials, dispatch, router, retryWithDelay, isRedirecting]); + }; + + handleAuth(); + }, [ + userCredentials.success, + dispatch, + router.query.success, + retryWithDelay, + ]); - // Handle deferred redirect to /account/login useEffect(() => { - if (redirectToLogin) { + if (isMounted && redirectToLogin) { router.push(LOGIN_ROUTE); } - }, [redirectToLogin, router]); + }, [isMounted, redirectToLogin, router]); - // Block rendering until redirect is handled if (isRedirecting) { return ; } - // Render the component if the user is authenticated return userCredentials.success ? : null; }; } diff --git a/src/platform/src/pages/Home/index.jsx b/src/platform/src/pages/Home/index.jsx index d2457eb2cf..d03f1abf6f 100644 --- a/src/platform/src/pages/Home/index.jsx +++ b/src/platform/src/pages/Home/index.jsx @@ -1,4 +1,4 @@ -// Import statements +import dynamic from 'next/dynamic'; import withAuth from '@/core/utils/protectedRoute'; import React, { useState, useEffect, useCallback, useMemo } from 'react'; import Layout from '@/components/Layout'; @@ -302,4 +302,4 @@ const Home = () => { ); }; -export default withAuth(Home); +export default dynamic(() => Promise.resolve(withAuth(Home)), { ssr: false }); From f7522e70e331773414c7f467c3c6f3fb771a97fe Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 25 Feb 2025 20:25:31 +0300 Subject: [PATCH 03/20] Update next platform staging image tag to stage-8dec5582-1740504113 --- k8s/platform/values-stage.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s/platform/values-stage.yaml b/k8s/platform/values-stage.yaml index 435920b26e..01dbfccbf1 100644 --- a/k8s/platform/values-stage.yaml +++ b/k8s/platform/values-stage.yaml @@ -2,7 +2,7 @@ replicaCount: 1 image: repository: eu.gcr.io/airqo-250220/airqo-stage-next-platform pullPolicy: Always - tag: stage-963fc29b-1740488187 + tag: stage-8dec5582-1740504113 imagePullSecrets: [] nameOverride: '' fullnameOverride: '' From b50213edd2e6f58dea3a6099c336b99582db5ca5 Mon Sep 17 00:00:00 2001 From: Belinda Marion Kobusingye <46527380+Codebmk@users.noreply.github.com> Date: Wed, 26 Feb 2025 10:59:23 +0300 Subject: [PATCH 04/20] undo file changes --- src/platform/src/core/utils/protectedRoute.js | 125 ++---------------- src/platform/src/pages/Home/index.jsx | 4 +- .../src/pages/account/login/index.jsx | 24 ---- 3 files changed, 10 insertions(+), 143 deletions(-) diff --git a/src/platform/src/core/utils/protectedRoute.js b/src/platform/src/core/utils/protectedRoute.js index dd574f155f..7df4e81298 100644 --- a/src/platform/src/core/utils/protectedRoute.js +++ b/src/platform/src/core/utils/protectedRoute.js @@ -1,138 +1,29 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect } from 'react'; import { useRouter } from 'next/router'; import { useSelector, useDispatch } from 'react-redux'; -import Cookies from 'js-cookie'; -import jwt_decode from 'jwt-decode'; -import { - setUserInfo, - setSuccess, - resetStore, -} from '@/lib/store/services/account/LoginSlice'; -import { getIndividualUserPreferences } from '@/lib/store/services/account/UserDefaultsSlice'; -import { getUserDetails } from '@/core/apis/Account'; -import Spinner from '../../common/components/Spinner'; - -const MAX_RETRIES = 3; -const RETRY_DELAY = 1000; -const LOGIN_ROUTE = '/account/login'; +import LogoutUser from '@/core/utils/LogoutUser'; export default function withAuth(Component) { return function WithAuthComponent(props) { const dispatch = useDispatch(); const router = useRouter(); const userCredentials = useSelector((state) => state.login); - const [isRedirecting, setIsRedirecting] = useState( - router.query.success === 'google', - ); - const [redirectToLogin, setRedirectToLogin] = useState(false); - const [isMounted, setIsMounted] = useState(false); - - const retryWithDelay = async (fn, retries = MAX_RETRIES) => { - try { - return await fn(); - } catch (error) { - if (retries > 0 && error.response?.status === 429) { - await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY)); - return retryWithDelay(fn, retries - 1); - } - throw error; - } - }; - - const setupUserSession = async (user) => { - if (!user.groups[0]?.grp_title) { - throw new Error( - 'Server error. Contact support to add you to the AirQo Organisation', - ); - } - - localStorage.setItem('loggedUser', JSON.stringify(user)); - - const preferencesResponse = await retryWithDelay(() => - dispatch(getIndividualUserPreferences({ identifier: user._id })), - ); - if (preferencesResponse.payload.success) { - const preferences = preferencesResponse.payload.preferences; - const activeGroup = preferences[0]?.group_id - ? user.groups.find((group) => group._id === preferences[0].group_id) - : user.groups.find((group) => group.grp_title === 'airqo'); - localStorage.setItem('activeGroup', JSON.stringify(activeGroup)); - } - - dispatch(setUserInfo(user)); - dispatch(setSuccess(true)); - setIsRedirecting(false); // Clear redirecting state after success - }; useEffect(() => { - // Mark as mounted only once - if (!isMounted) { - setIsMounted(true); - } - - if (typeof window === 'undefined') return; - - const handleAuth = async () => { - // Handle Google redirect - if (router.query.success === 'google') { - try { - const token = Cookies.get('temp_access_token'); - if (!token) { - throw new Error('No access_token cookie found'); - } - - localStorage.setItem('token', token); - const decoded = jwt_decode(token); - const response = await retryWithDelay(() => - getUserDetails(decoded._id, token), - ); - await setupUserSession(response.users[0]); - } catch (error) { - console.error('Google auth error:', error); - setIsRedirecting(false); - setRedirectToLogin(true); - } - return; - } - - // Handle authentication checks + if (typeof window !== 'undefined') { const storedUserGroup = localStorage.getItem('activeGroup'); + if (!userCredentials.success) { - setRedirectToLogin(true); - return; + router.push('/account/login'); } if (!storedUserGroup) { - dispatch(resetStore()); - if (typeof window !== 'undefined') { - localStorage.clear(); - } - const store = router.store || window.__NEXT_REDUX_STORE__; - if (store?.__persistor) { - await store.__persistor.purge(); - } - setRedirectToLogin(true); + LogoutUser(dispatch, router); } - }; - - handleAuth(); - }, [ - userCredentials.success, - dispatch, - router.query.success, - retryWithDelay, - ]); - - useEffect(() => { - if (isMounted && redirectToLogin) { - router.push(LOGIN_ROUTE); } - }, [isMounted, redirectToLogin, router]); - - if (isRedirecting) { - return ; - } + }, [userCredentials, dispatch, router]); + // Render the component if the user is authenticated return userCredentials.success ? : null; }; } diff --git a/src/platform/src/pages/Home/index.jsx b/src/platform/src/pages/Home/index.jsx index d03f1abf6f..d2457eb2cf 100644 --- a/src/platform/src/pages/Home/index.jsx +++ b/src/platform/src/pages/Home/index.jsx @@ -1,4 +1,4 @@ -import dynamic from 'next/dynamic'; +// Import statements import withAuth from '@/core/utils/protectedRoute'; import React, { useState, useEffect, useCallback, useMemo } from 'react'; import Layout from '@/components/Layout'; @@ -302,4 +302,4 @@ const Home = () => { ); }; -export default dynamic(() => Promise.resolve(withAuth(Home)), { ssr: false }); +export default withAuth(Home); diff --git a/src/platform/src/pages/account/login/index.jsx b/src/platform/src/pages/account/login/index.jsx index edbf1b764d..4a28bdac20 100644 --- a/src/platform/src/pages/account/login/index.jsx +++ b/src/platform/src/pages/account/login/index.jsx @@ -18,7 +18,6 @@ import { } from '@/lib/store/services/account/LoginSlice'; import { getIndividualUserPreferences } from '@/lib/store/services/account/UserDefaultsSlice'; import { postUserLoginDetails, getUserDetails } from '@/core/apis/Account'; -import { GOOGLE_AUTH_URL } from '@/core/urls/authentication'; const MAX_RETRIES = 3; const RETRY_DELAY = 1000; @@ -111,15 +110,6 @@ const UserLogin = () => { dispatch(setUserData({ key, value })); }; - const handleGoogleLogin = async () => { - try { - // Redirect to Google auth URL - window.location.href = GOOGLE_AUTH_URL; - } catch (error) { - console.error('Login error:', error); - } - }; - return ( { -
- -
From e4c8c8a770d4b4049123ed6e60d7e774b296a2b3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 26 Feb 2025 11:35:10 +0300 Subject: [PATCH 05/20] Update next platform staging image tag to stage-6fe6134a-1740558711 --- k8s/platform/values-stage.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s/platform/values-stage.yaml b/k8s/platform/values-stage.yaml index 01dbfccbf1..3e47349b6c 100644 --- a/k8s/platform/values-stage.yaml +++ b/k8s/platform/values-stage.yaml @@ -2,7 +2,7 @@ replicaCount: 1 image: repository: eu.gcr.io/airqo-250220/airqo-stage-next-platform pullPolicy: Always - tag: stage-8dec5582-1740504113 + tag: stage-6fe6134a-1740558711 imagePullSecrets: [] nameOverride: '' fullnameOverride: '' From 6108d1df3a04636ba028c6d349a21ad24998780d Mon Sep 17 00:00:00 2001 From: Ochieng Paul Date: Thu, 27 Feb 2025 12:02:33 +0300 Subject: [PATCH 06/20] updates --- .../components/dialogs/EngagementDialog.tsx | 12 ++++++++++++ src/website2/src/components/layouts/Navbar.tsx | 18 ++++++++++++++++-- .../src/components/layouts/NewsLetter.tsx | 7 +++++++ .../sections/footer/CountrySelectorDialog.tsx | 12 +++++++++++- .../src/views/home/HomePlayerSection.tsx | 5 +++++ 5 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/website2/src/components/dialogs/EngagementDialog.tsx b/src/website2/src/components/dialogs/EngagementDialog.tsx index b058037e42..1bfd87d414 100644 --- a/src/website2/src/components/dialogs/EngagementDialog.tsx +++ b/src/website2/src/components/dialogs/EngagementDialog.tsx @@ -10,6 +10,7 @@ import { useDispatch, useSelector } from '@/hooks'; import { postContactUs } from '@/services/externalService'; import { closeModal } from '@/store/slices/modalSlice'; +import { trackEvent } from '../GoogleAnalytics'; import { CustomButton } from '../ui'; interface EngagementOption { @@ -172,6 +173,17 @@ const EngagementDialog = () => { const res = await postContactUs(requestBody); if (res.success) { setSubmissionSuccess(true); + + // Fire the tracking event only on successful submission. + trackEvent({ + action: 'submit_form', + category: 'engagement_dialog', + label: selectedCategory + ? `engagement_dialog_submit_form_success_${selectedCategory}` + : 'engagement_dialog_submit_form_success', + }); + + // Reset form data after successful submission setFormData({ firstName: '', lastName: '', diff --git a/src/website2/src/components/layouts/Navbar.tsx b/src/website2/src/components/layouts/Navbar.tsx index 8d266dad70..584ae869dd 100644 --- a/src/website2/src/components/layouts/Navbar.tsx +++ b/src/website2/src/components/layouts/Navbar.tsx @@ -225,13 +225,27 @@ const Navbar: React.FC = () => { ))} dispatch(openModal())} + onClick={() => { + trackEvent({ + action: 'button_click', + category: 'engagement', + label: 'get_involved', + }); + dispatch(openModal()); + }} className="text-blue-600 bg-blue-50 transition rounded-none" > Get involved router.push('/explore-data')} + onClick={() => { + trackEvent({ + action: 'button_click', + category: 'navigation', + label: 'explore_data', + }); + router.push('/explore-data'); + }} className="rounded-none" > Explore data diff --git a/src/website2/src/components/layouts/NewsLetter.tsx b/src/website2/src/components/layouts/NewsLetter.tsx index 8c8f93706c..d523f797d3 100644 --- a/src/website2/src/components/layouts/NewsLetter.tsx +++ b/src/website2/src/components/layouts/NewsLetter.tsx @@ -5,6 +5,8 @@ import { CustomButton } from '@/components/ui'; import mainConfig from '@/configs/mainConfigs'; import { subscribeToNewsletter } from '@/services/externalService'; +import { trackEvent } from '../GoogleAnalytics'; + const NewsLetter: React.FC = () => { const [formStatus, setFormStatus] = useState<'idle' | 'success' | 'error'>( 'idle', @@ -32,6 +34,11 @@ const NewsLetter: React.FC = () => { const response = await subscribeToNewsletter(formData); if (response.success) { setFormStatus('success'); + trackEvent({ + action: 'submit_form', + category: 'newsletter', + label: 'newsletter_subscription', + }); } else { setFormStatus('error'); } diff --git a/src/website2/src/components/sections/footer/CountrySelectorDialog.tsx b/src/website2/src/components/sections/footer/CountrySelectorDialog.tsx index 2c7fa9e713..fd206c8dd9 100644 --- a/src/website2/src/components/sections/footer/CountrySelectorDialog.tsx +++ b/src/website2/src/components/sections/footer/CountrySelectorDialog.tsx @@ -5,6 +5,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { FiChevronDown } from 'react-icons/fi'; import { IoLocationSharp } from 'react-icons/io5'; +import { trackEvent } from '@/components/GoogleAnalytics'; import { CustomButton, Dialog, @@ -224,7 +225,16 @@ const CountrySelectorDialog: React.FC = () => { return ( - - -
- - {selectedEvent.forum_resources?.map( - (resource: any, resourceIndex: number) => ( -
-

- {resource.resource_title} -

- {resource.resource_sessions?.map( - (session: any, sessionIndex: number) => ( - - handleToggleAccordion(resourceIndex, sessionIndex) - } - /> - ), - )} - -
- ), - )} - - ); +const page = () => { + return ; }; -export default ResourcesPage; +export default page; diff --git a/src/website2/src/app/clean-air-forum/sessions/page.tsx b/src/website2/src/app/clean-air-forum/sessions/page.tsx index 010ab091cf..4ecbed5ff6 100644 --- a/src/website2/src/app/clean-air-forum/sessions/page.tsx +++ b/src/website2/src/app/clean-air-forum/sessions/page.tsx @@ -1,158 +1,7 @@ -'use client'; +import ProgramsPage from '@/views/cleanAirForum/sessions-programs/ProgramsPage'; -import { format } from 'date-fns'; -import DOMPurify from 'dompurify'; -import React, { useState } from 'react'; -import { FaChevronDown, FaChevronUp } from 'react-icons/fa'; - -import { Divider } from '@/components/ui'; -import { useForumData } from '@/context/ForumDataContext'; -import { isValidHTMLContent } from '@/utils/htmlValidator'; -import { renderContent } from '@/utils/quillUtils'; -import SectionDisplay from '@/views/Forum/SectionDisplay'; - -interface AccordionItemProps { - title: string; - subText: string; - sessions: any[]; - isOpen: boolean; - onToggle: () => void; -} - -const AccordionItem: React.FC = ({ - title, - subText, - sessions, - isOpen, - onToggle, -}) => { - const formatTime = (time: string) => { - try { - return format(new Date(`1970-01-01T${time}Z`), 'p'); - } catch (error) { - console.error(error); - return time; - } - }; - - return ( -
-
-
-

{title}

-
-
- {isOpen ? : } -
- {isOpen && ( -
- {sessions?.map((item: any, index: number) => ( -
- -
-
- {formatTime(item.start_time)} -
-
-

{item.session_title}

-
-
-
-
- ))} -
- )} -
- ); -}; - -const ProgramsPage: React.FC = () => { - const { selectedEvent } = useForumData(); - const [openAccordion, setOpenAccordion] = useState(null); - - if (!selectedEvent) { - return null; - } - - const scheduleHTML = renderContent(selectedEvent.schedule_details); - const showSchedule = isValidHTMLContent(scheduleHTML); - - const registrationHTML = renderContent(selectedEvent.registration_details); - const showRegistration = isValidHTMLContent(registrationHTML); - - const sessionSections = selectedEvent.sections?.filter((section: any) => { - if (!section.pages.includes('session')) return false; - const sectionHTML = renderContent(section.content); - return isValidHTMLContent(sectionHTML); - }); - - const handleToggle = (id: string) => { - setOpenAccordion(openAccordion === id ? null : id); - }; - - return ( -
- {showSchedule && ( -
-

Schedule

-
-
- )} - - {sessionSections && sessionSections.length > 0 && ( - <> - {sessionSections.map((section: any) => ( - - ))} - - )} - - <> - {selectedEvent.programs?.map((program: any) => ( - handleToggle(program.id)} - /> - ))} - - - {showRegistration && ( -
- -
-
-

Registration

-
-
-
-
- )} -
- ); +const page = () => { + return ; }; -export default ProgramsPage; +export default page; diff --git a/src/website2/src/app/clean-air-forum/speakers/page.tsx b/src/website2/src/app/clean-air-forum/speakers/page.tsx index af98135d6f..4b0ba9cf3f 100644 --- a/src/website2/src/app/clean-air-forum/speakers/page.tsx +++ b/src/website2/src/app/clean-air-forum/speakers/page.tsx @@ -1,147 +1,7 @@ -'use client'; +import SpeakersPage from '@/views/cleanAirForum/speakers/SpeakersPage'; -import DOMPurify from 'dompurify'; -import React, { useState } from 'react'; - -import { Divider, MemberCard, Pagination } from '@/components/ui/'; -import { useForumData } from '@/context/ForumDataContext'; -import { isValidHTMLContent } from '@/utils/htmlValidator'; -import { renderContent } from '@/utils/quillUtils'; -import SectionDisplay from '@/views/Forum/SectionDisplay'; - -const SpeakersPage: React.FC = () => { - // Now we use the selectedEvent from context - const { selectedEvent } = useForumData(); - const membersPerPage = 6; - const [currentKeyNotePage, setCurrentKeyNotePage] = useState(1); - const [currentSpeakersPage, setCurrentSpeakersPage] = useState(1); - - if (!selectedEvent) { - return null; - } - - // Filter keynote speakers and speakers from selectedEvent.persons. - // (Adjust your filtering logic as needed.) - const keyNoteSpeakers = - selectedEvent.persons?.filter( - (person: any) => - person.category === 'Key Note Speaker' || - person.category === 'Committee Member and Key Note Speaker', - ) || []; - const speakers = - selectedEvent.persons?.filter( - (person: any) => - person.category === 'Speaker' || - person.category === 'Speaker and Committee Member', - ) || []; - - // Pagination calculations for Keynote Speakers. - const totalKeyNotePages = Math.ceil(keyNoteSpeakers.length / membersPerPage); - const startKeyNoteIdx = (currentKeyNotePage - 1) * membersPerPage; - const displayedKeyNoteSpeakers = keyNoteSpeakers.slice( - startKeyNoteIdx, - startKeyNoteIdx + membersPerPage, - ); - - // Pagination calculations for Speakers. - const totalSpeakersPages = Math.ceil(speakers.length / membersPerPage); - const startSpeakersIdx = (currentSpeakersPage - 1) * membersPerPage; - const displayedSpeakers = speakers.slice( - startSpeakersIdx, - startSpeakersIdx + membersPerPage, - ); - - // Handlers for page changes. - const handleKeyNotePageChange = (newPage: number) => - setCurrentKeyNotePage(newPage); - const handleSpeakersPageChange = (newPage: number) => - setCurrentSpeakersPage(newPage); - - // Validate the main speakers text section. - const mainSpeakersHTML = renderContent(selectedEvent.speakers_text_section); - const showMainSpeakers = isValidHTMLContent(mainSpeakersHTML); - - // Filter extra sections assigned to the "speakers" page. - const speakersExtraSections = selectedEvent.sections?.filter( - (section: any) => { - if (!section.pages.includes('speakers')) return false; - const sectionHTML = renderContent(section.content); - return isValidHTMLContent(sectionHTML); - }, - ); - - return ( -
- - - {/* Speakers Text Section */} - {showMainSpeakers && ( -
-
-
- )} - - {/* Keynote Speakers Section */} -

Keynote Speakers

- -
- {displayedKeyNoteSpeakers.map((person: any) => ( - - ))} -
- {totalKeyNotePages > 1 && ( -
- -
- )} - - - - {/* Speakers Section */} -

Speakers

-
- {displayedSpeakers.map((person: any) => ( - - ))} -
- {totalSpeakersPages > 1 && ( -
- -
- )} - - {/* Extra Speakers Sections */} - {speakersExtraSections && speakersExtraSections.length > 0 && ( - <> - {speakersExtraSections.map((section: any) => ( - - ))} - - )} -
- ); +const page = () => { + return ; }; -export default SpeakersPage; +export default page; diff --git a/src/website2/src/app/clean-air-forum/sponsorships/page.tsx b/src/website2/src/app/clean-air-forum/sponsorships/page.tsx index 28e2a89534..eee73080f9 100644 --- a/src/website2/src/app/clean-air-forum/sponsorships/page.tsx +++ b/src/website2/src/app/clean-air-forum/sponsorships/page.tsx @@ -1,82 +1,7 @@ -'use client'; +import SponsorshipPage from '@/views/cleanAirForum/sponsorship/SponsorshipPage'; -import DOMPurify from 'dompurify'; -import React from 'react'; - -import { Divider } from '@/components/ui'; -import { useForumData } from '@/context/ForumDataContext'; -import { renderContent } from '@/utils/quillUtils'; -import PaginatedSection from '@/views/cleanairforum/PaginatedSection'; -import SectionDisplay from '@/views/Forum/SectionDisplay'; - -const SponsorshipPage: React.FC = () => { - const { selectedEvent } = useForumData(); - if (!selectedEvent) return null; - - const sponsorPartner = selectedEvent.partners - ?.filter((partner: any) => partner.category === 'Sponsor Partner') - .map((partner: any) => ({ - id: partner.id, - logoUrl: partner.partner_logo_url, - })); - - const sponsorshipSections = selectedEvent.sections?.filter((section: any) => { - if (!section.pages.includes('sponsorships')) return false; - const html = renderContent(section.content); - return html.trim().length > 0; - }); - - const mainSponsorshipHTML = renderContent( - selectedEvent.sponsorship_opportunities_partners, - ); - const showMainSponsorship = mainSponsorshipHTML.trim().length > 0; - - return ( -
- {showMainSponsorship && ( -
- -
-

Sponsorship opportunities

- -
-
-
- )} - - {sponsorshipSections && sponsorshipSections.length > 0 && ( - <> - {sponsorshipSections.map((section: any) => ( - - ))} - - )} - - {sponsorPartner && sponsorPartner.length > 0 && ( - <> - -
-
-
-

- Sponsors -

-
- -
-
- - )} -
- ); +const page = () => { + return ; }; -export default SponsorshipPage; +export default page; diff --git a/src/website2/src/app/clean-air-network/page.tsx b/src/website2/src/app/clean-air-network/about/page.tsx similarity index 61% rename from src/website2/src/app/clean-air-network/page.tsx rename to src/website2/src/app/clean-air-network/about/page.tsx index b7a801b61d..5cbb768215 100644 --- a/src/website2/src/app/clean-air-network/page.tsx +++ b/src/website2/src/app/clean-air-network/about/page.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import CleanAirPage from './CleanAirPage'; +import CleanAirPage from '@/views/cleanAirNetwork/about/CleanAirPage'; const page = () => { return ( diff --git a/src/website2/src/app/clean-air-network/events/[id]/page.tsx b/src/website2/src/app/clean-air-network/events/[id]/page.tsx index 6b46e523ca..a30542cae5 100644 --- a/src/website2/src/app/clean-air-network/events/[id]/page.tsx +++ b/src/website2/src/app/clean-air-network/events/[id]/page.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import SingleEvent from '@/views/cleanairforum/events/SingleEvent'; +import SingleEvent from '@/views/cleanAirNetwork/events/SingleEvent'; const page = ({ params }: { params: any }) => { return ( diff --git a/src/website2/src/app/clean-air-network/events/page.tsx b/src/website2/src/app/clean-air-network/events/page.tsx index 1033d25b12..71f1467baa 100644 --- a/src/website2/src/app/clean-air-network/events/page.tsx +++ b/src/website2/src/app/clean-air-network/events/page.tsx @@ -1,4 +1,4 @@ -import EventsPage from '@/views/cleanairforum/events/EventsPage'; +import EventsPage from '@/views/cleanAirNetwork/events/EventsPage'; const page = () => { return ( diff --git a/src/website2/src/app/clean-air-network/membership/page.tsx b/src/website2/src/app/clean-air-network/membership/page.tsx index ee1803b08d..f539b1fec5 100644 --- a/src/website2/src/app/clean-air-network/membership/page.tsx +++ b/src/website2/src/app/clean-air-network/membership/page.tsx @@ -1,4 +1,4 @@ -import MemberPage from '@/views/cleanairforum/membership/MemberPage'; +import MemberPage from '@/views/cleanAirNetwork/membership/MemberPage'; const page = () => { return ( diff --git a/src/website2/src/app/clean-air-network/resources/page.tsx b/src/website2/src/app/clean-air-network/resources/page.tsx index 805d6b0e40..ab4a307194 100644 --- a/src/website2/src/app/clean-air-network/resources/page.tsx +++ b/src/website2/src/app/clean-air-network/resources/page.tsx @@ -1,4 +1,4 @@ -import ResourcePage from '@/views/cleanairforum/resources/ResourcePage'; +import ResourcePage from '@/views/cleanAirNetwork/resources/ResourcePage'; const page = () => { return ( diff --git a/src/website2/src/components/layouts/Footer.tsx b/src/website2/src/components/layouts/Footer.tsx index 24c76d3f8e..d70f13fd4f 100644 --- a/src/website2/src/components/layouts/Footer.tsx +++ b/src/website2/src/components/layouts/Footer.tsx @@ -1,12 +1,8 @@ import Image from 'next/image'; import Link from 'next/link'; import React from 'react'; -import { - FaFacebookF, - FaLinkedinIn, - FaTwitter, - FaYoutube, -} from 'react-icons/fa'; +import { FaFacebookF, FaLinkedinIn, FaYoutube } from 'react-icons/fa'; +import { FaXTwitter } from 'react-icons/fa6'; import mainConfig from '@/configs/mainConfigs'; @@ -33,9 +29,9 @@ const Footer = () => { width={70} height={60} /> -

+

Clean air for all
African Cities. -

+

{ aria-label="Twitter" className="text-blue-600 bg-blue-50 rounded-full p-2 hover:bg-blue-200 transition-all" > - +
diff --git a/src/website2/src/components/layouts/Navbar.tsx b/src/website2/src/components/layouts/Navbar.tsx index 584ae869dd..fbb9938c36 100644 --- a/src/website2/src/components/layouts/Navbar.tsx +++ b/src/website2/src/components/layouts/Navbar.tsx @@ -20,7 +20,7 @@ import { import mainConfig from '@/configs/mainConfigs'; import { useDispatch } from '@/hooks'; import { openModal } from '@/store/slices/modalSlice'; -import TabNavigation from '@/views/cleanairforum/TabNavigation'; +import TabNavigation from '@/views/cleanAirNetwork/TabNavigation'; import { trackEvent } from '../GoogleAnalytics'; import NotificationBanner from './NotificationBanner'; diff --git a/src/website2/src/components/layouts/NewsLetter.tsx b/src/website2/src/components/layouts/NewsLetter.tsx index d523f797d3..da39b56ca9 100644 --- a/src/website2/src/components/layouts/NewsLetter.tsx +++ b/src/website2/src/components/layouts/NewsLetter.tsx @@ -78,7 +78,7 @@ const NewsLetter: React.FC = () => { // Split layout for idle state (header and form side-by-side on lg screens)
-

+

Subscribe to our Newsletter

diff --git a/src/website2/src/components/layouts/NotificationBanner.tsx b/src/website2/src/components/layouts/NotificationBanner.tsx index f80e02c09f..dd4348ad7d 100644 --- a/src/website2/src/components/layouts/NotificationBanner.tsx +++ b/src/website2/src/components/layouts/NotificationBanner.tsx @@ -10,7 +10,7 @@ import mainConfig from '@/configs/mainConfigs'; import { trackEvent } from '../GoogleAnalytics'; -const CLEAN_AIR_NETWORK_ROUTE = '/clean-air-network'; +const CLEAN_AIR_NETWORK_ROUTE = '/clean-air-network/about'; const NotificationBanner: React.FC = () => { const handleNetworkClick = (version: 'desktop' | 'mobile') => { @@ -52,7 +52,7 @@ const NotificationBanner: React.FC = () => {

{ - e.stopPropagation(); // Prevent double event firing + e.stopPropagation(); handleNetworkClick('mobile'); }} > diff --git a/src/website2/src/views/Forum/TabNavigation.tsx b/src/website2/src/views/Forum/TabNavigation.tsx deleted file mode 100644 index e34eeb07dc..0000000000 --- a/src/website2/src/views/Forum/TabNavigation.tsx +++ /dev/null @@ -1,63 +0,0 @@ -// components/layouts/TabNavigation.tsx -'use client'; - -import Link from 'next/link'; -import { usePathname, useSearchParams } from 'next/navigation'; -import React from 'react'; - -const TabNavigation: React.FC = () => { - const pathname = usePathname(); - const searchParams = useSearchParams(); - // Read the current slug, if it exists. - const currentSlug = searchParams.get('slug'); - - // Function to check if the tab is active based on the current pathname. - const isActiveTab = (path: string) => - pathname === path || pathname.startsWith(path); - - // Define the tabs list. - const tabs = [ - { href: '/clean-air-forum/about', text: 'About' }, - { href: '/clean-air-forum/program-committee', text: 'Programme Committee' }, - { href: '/clean-air-forum/sessions', text: 'Call for Sessions' }, - { href: '/clean-air-forum/speakers', text: 'Speakers' }, - { href: '/clean-air-forum/partners', text: 'Partners' }, - { href: '/clean-air-forum/sponsorships', text: 'Sponsorships' }, - { href: '/clean-air-forum/logistics', text: 'Travel Logistics' }, - { href: '/clean-air-forum/glossary', text: 'Glossary' }, - { href: '/clean-air-forum/resources', text: 'Resources' }, - ]; - - // If currentSlug exists, append it to the URL as a query parameter. - const buildHref = (href: string) => { - if (currentSlug) { - return `${href}?slug=${encodeURIComponent(currentSlug)}`; - } - return href; - }; - - return ( -
-
-
- {tabs.map((link, index) => ( - - {link.text} - {isActiveTab(link.href) && ( - - )} - - ))} -
-
-
- ); -}; - -export default TabNavigation; diff --git a/src/website2/src/views/about/AboutPage.tsx b/src/website2/src/views/about/AboutPage.tsx index 55da3ea15e..c6ffd06b9e 100644 --- a/src/website2/src/views/about/AboutPage.tsx +++ b/src/website2/src/views/about/AboutPage.tsx @@ -15,7 +15,7 @@ import { useTeamMembers, } from '@/hooks/useApiHooks'; import { openModal } from '@/store/slices/modalSlice'; -import PaginatedSection from '@/views/cleanairforum/PaginatedSection'; +import PaginatedSection from '@/views/cleanAirNetwork/PaginatedSection'; /** Skeleton Loader Component **/ diff --git a/src/website2/src/views/cleanairforum/ContentSection.tsx b/src/website2/src/views/cleanAirNetwork/ContentSection.tsx similarity index 100% rename from src/website2/src/views/cleanairforum/ContentSection.tsx rename to src/website2/src/views/cleanAirNetwork/ContentSection.tsx diff --git a/src/website2/src/views/cleanairforum/EventCard.tsx b/src/website2/src/views/cleanAirNetwork/EventCard.tsx similarity index 100% rename from src/website2/src/views/cleanairforum/EventCard.tsx rename to src/website2/src/views/cleanAirNetwork/EventCard.tsx diff --git a/src/website2/src/views/cleanairforum/EventSkeleton.tsx b/src/website2/src/views/cleanAirNetwork/EventSkeleton.tsx similarity index 100% rename from src/website2/src/views/cleanairforum/EventSkeleton.tsx rename to src/website2/src/views/cleanAirNetwork/EventSkeleton.tsx diff --git a/src/website2/src/views/cleanairforum/FeaturedEvent.tsx b/src/website2/src/views/cleanAirNetwork/FeaturedEvent.tsx similarity index 100% rename from src/website2/src/views/cleanairforum/FeaturedEvent.tsx rename to src/website2/src/views/cleanAirNetwork/FeaturedEvent.tsx diff --git a/src/website2/src/views/cleanairforum/PaginatedSection.tsx b/src/website2/src/views/cleanAirNetwork/PaginatedSection.tsx similarity index 100% rename from src/website2/src/views/cleanairforum/PaginatedSection.tsx rename to src/website2/src/views/cleanAirNetwork/PaginatedSection.tsx diff --git a/src/website2/src/views/cleanairforum/RegisterBanner.tsx b/src/website2/src/views/cleanAirNetwork/RegisterBanner.tsx similarity index 100% rename from src/website2/src/views/cleanairforum/RegisterBanner.tsx rename to src/website2/src/views/cleanAirNetwork/RegisterBanner.tsx diff --git a/src/website2/src/views/cleanAirNetwork/TabNavigation.tsx b/src/website2/src/views/cleanAirNetwork/TabNavigation.tsx new file mode 100644 index 0000000000..8733cdeac7 --- /dev/null +++ b/src/website2/src/views/cleanAirNetwork/TabNavigation.tsx @@ -0,0 +1,49 @@ +'use client'; + +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; +import type React from 'react'; + +import mainConfig from '@/configs/mainConfigs'; + +const tabs = [ + { label: 'About', value: '/clean-air-network/about' }, + { label: 'Membership', value: '/clean-air-network/membership' }, + { label: 'Events', value: '/clean-air-network/events' }, + { label: 'Resources', value: '/clean-air-network/resources' }, +]; + +const TabNavigation: React.FC = () => { + const pathname = usePathname(); + + const isActiveTab = (tabValue: string) => { + if (tabValue === '/clean-air-network/about') { + return pathname === tabValue; + } + return pathname.startsWith(tabValue); + }; + + return ( + + ); +}; + +export default TabNavigation; diff --git a/src/website2/src/app/clean-air-network/CleanAirPage.tsx b/src/website2/src/views/cleanAirNetwork/about/CleanAirPage.tsx similarity index 95% rename from src/website2/src/app/clean-air-network/CleanAirPage.tsx rename to src/website2/src/views/cleanAirNetwork/about/CleanAirPage.tsx index cd9601bc89..8b58f6e837 100644 --- a/src/website2/src/app/clean-air-network/CleanAirPage.tsx +++ b/src/website2/src/views/cleanAirNetwork/about/CleanAirPage.tsx @@ -2,8 +2,8 @@ import Image from 'next/image'; import React from 'react'; -import ContentSection from '@/views/cleanairforum/ContentSection'; -import FeaturedEvent from '@/views/cleanairforum/FeaturedEvent'; +import ContentSection from '@/views/cleanAirNetwork/ContentSection'; +import FeaturedEvent from '@/views/cleanAirNetwork/FeaturedEvent'; const CleanAirPage = () => { const goals = [ diff --git a/src/website2/src/views/cleanairforum/events/EventsPage.tsx b/src/website2/src/views/cleanAirNetwork/events/EventsPage.tsx similarity index 95% rename from src/website2/src/views/cleanairforum/events/EventsPage.tsx rename to src/website2/src/views/cleanAirNetwork/events/EventsPage.tsx index b0b0302d78..d3d5e434c7 100644 --- a/src/website2/src/views/cleanairforum/events/EventsPage.tsx +++ b/src/website2/src/views/cleanAirNetwork/events/EventsPage.tsx @@ -14,9 +14,9 @@ import { } from '@/components/ui'; import mainConfig from '@/configs/mainConfigs'; import { useCleanAirEvents } from '@/hooks/useApiHooks'; -import EventCard from '@/views/cleanairforum/EventCard'; -import EventSkeleton from '@/views/cleanairforum/EventSkeleton'; -import RegisterBanner from '@/views/cleanairforum/RegisterBanner'; +import EventCard from '@/views/cleanAirNetwork/EventCard'; +import EventSkeleton from '@/views/cleanAirNetwork/EventSkeleton'; +import RegisterBanner from '@/views/cleanAirNetwork/RegisterBanner'; const months = [ 'January', diff --git a/src/website2/src/views/cleanairforum/events/SingleEvent.tsx b/src/website2/src/views/cleanAirNetwork/events/SingleEvent.tsx similarity index 100% rename from src/website2/src/views/cleanairforum/events/SingleEvent.tsx rename to src/website2/src/views/cleanAirNetwork/events/SingleEvent.tsx diff --git a/src/website2/src/views/cleanairforum/membership/MemberPage.tsx b/src/website2/src/views/cleanAirNetwork/membership/MemberPage.tsx similarity index 95% rename from src/website2/src/views/cleanairforum/membership/MemberPage.tsx rename to src/website2/src/views/cleanAirNetwork/membership/MemberPage.tsx index 277bfb2a6e..8ee68149d2 100644 --- a/src/website2/src/views/cleanairforum/membership/MemberPage.tsx +++ b/src/website2/src/views/cleanAirNetwork/membership/MemberPage.tsx @@ -5,8 +5,8 @@ import React, { useMemo } from 'react'; import mainConfig from '@/configs/mainConfigs'; import { usePartners } from '@/hooks/useApiHooks'; -import PaginatedSection from '@/views/cleanairforum/PaginatedSection'; -import RegisterBanner from '@/views/cleanairforum/RegisterBanner'; +import PaginatedSection from '@/views/cleanAirNetwork/PaginatedSection'; +import RegisterBanner from '@/views/cleanAirNetwork/RegisterBanner'; const SkeletonPaginatedSection: React.FC = () => { return ( diff --git a/src/website2/src/views/cleanairforum/resources/ResourceCard.tsx b/src/website2/src/views/cleanAirNetwork/resources/ResourceCard.tsx similarity index 100% rename from src/website2/src/views/cleanairforum/resources/ResourceCard.tsx rename to src/website2/src/views/cleanAirNetwork/resources/ResourceCard.tsx diff --git a/src/website2/src/views/cleanairforum/resources/ResourcePage.tsx b/src/website2/src/views/cleanAirNetwork/resources/ResourcePage.tsx similarity index 100% rename from src/website2/src/views/cleanairforum/resources/ResourcePage.tsx rename to src/website2/src/views/cleanAirNetwork/resources/ResourcePage.tsx diff --git a/src/website2/src/views/Forum/AboutPage.tsx b/src/website2/src/views/cleanairforum/AboutPage.tsx similarity index 95% rename from src/website2/src/views/Forum/AboutPage.tsx rename to src/website2/src/views/cleanairforum/AboutPage.tsx index c0ec9f38b3..641c647774 100644 --- a/src/website2/src/views/Forum/AboutPage.tsx +++ b/src/website2/src/views/cleanairforum/AboutPage.tsx @@ -7,7 +7,7 @@ import { Divider, NoData } from '@/components/ui'; import { useForumData } from '@/context/ForumDataContext'; import { isValidHTMLContent } from '@/utils/htmlValidator'; import { renderContent } from '@/utils/quillUtils'; -import SectionDisplay from '@/views/Forum/SectionDisplay'; +import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; type SectionRowProps = { title: string; diff --git a/src/website2/src/views/Forum/BannerSection.tsx b/src/website2/src/views/cleanairforum/BannerSection.tsx similarity index 100% rename from src/website2/src/views/Forum/BannerSection.tsx rename to src/website2/src/views/cleanairforum/BannerSection.tsx diff --git a/src/website2/src/views/Forum/SectionDisplay.tsx b/src/website2/src/views/cleanairforum/SectionDisplay.tsx similarity index 100% rename from src/website2/src/views/Forum/SectionDisplay.tsx rename to src/website2/src/views/cleanairforum/SectionDisplay.tsx diff --git a/src/website2/src/views/cleanairforum/TabNavigation.tsx b/src/website2/src/views/cleanairforum/TabNavigation.tsx index 9fb60cf74e..e34eeb07dc 100644 --- a/src/website2/src/views/cleanairforum/TabNavigation.tsx +++ b/src/website2/src/views/cleanairforum/TabNavigation.tsx @@ -1,48 +1,62 @@ +// components/layouts/TabNavigation.tsx 'use client'; import Link from 'next/link'; -import { usePathname } from 'next/navigation'; -import type React from 'react'; - -import mainConfig from '@/configs/mainConfigs'; - -const tabs = [ - { label: 'About', value: '/clean-air-network' }, - { label: 'Membership', value: '/clean-air-network/membership' }, - { label: 'Events', value: '/clean-air-network/events' }, - { label: 'Resources', value: '/clean-air-network/resources' }, -]; +import { usePathname, useSearchParams } from 'next/navigation'; +import React from 'react'; const TabNavigation: React.FC = () => { const pathname = usePathname(); + const searchParams = useSearchParams(); + // Read the current slug, if it exists. + const currentSlug = searchParams.get('slug'); + + // Function to check if the tab is active based on the current pathname. + const isActiveTab = (path: string) => + pathname === path || pathname.startsWith(path); + + // Define the tabs list. + const tabs = [ + { href: '/clean-air-forum/about', text: 'About' }, + { href: '/clean-air-forum/program-committee', text: 'Programme Committee' }, + { href: '/clean-air-forum/sessions', text: 'Call for Sessions' }, + { href: '/clean-air-forum/speakers', text: 'Speakers' }, + { href: '/clean-air-forum/partners', text: 'Partners' }, + { href: '/clean-air-forum/sponsorships', text: 'Sponsorships' }, + { href: '/clean-air-forum/logistics', text: 'Travel Logistics' }, + { href: '/clean-air-forum/glossary', text: 'Glossary' }, + { href: '/clean-air-forum/resources', text: 'Resources' }, + ]; - const isActiveTab = (tabValue: string) => { - if (tabValue === '/clean-air-network') { - return pathname === tabValue; + // If currentSlug exists, append it to the URL as a query parameter. + const buildHref = (href: string) => { + if (currentSlug) { + return `${href}?slug=${encodeURIComponent(currentSlug)}`; } - return pathname.startsWith(tabValue); + return href; }; return ( - +
); }; diff --git a/src/website2/src/views/cleanairforum/glossary/GlossaryPage.tsx b/src/website2/src/views/cleanairforum/glossary/GlossaryPage.tsx new file mode 100644 index 0000000000..48f7003000 --- /dev/null +++ b/src/website2/src/views/cleanairforum/glossary/GlossaryPage.tsx @@ -0,0 +1,115 @@ +'use client'; + +import DOMPurify from 'dompurify'; +import Link from 'next/link'; +import React from 'react'; + +import Loading from '@/components/loading'; +import { Divider } from '@/components/ui'; +import { NoData } from '@/components/ui'; +import { useForumData } from '@/context/ForumDataContext'; +import { ForumEvent } from '@/types/forum'; +import { isValidGlossaryContent } from '@/utils/glossaryValidator'; +import { renderContent } from '@/utils/quillUtils'; +import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; + +const GlossaryPage: React.FC = () => { + // Access data from the context. + const { selectedEvent, eventTitles } = useForumData(); + + // If either is not available, show a loading state. + if (!selectedEvent || !eventTitles) { + return ; + } + + // Extract the events list from eventTitles. + // If eventTitles is an array, use it directly; otherwise, assume it's a ForumTitlesResponse. + const eventsList: ForumEvent[] = Array.isArray(eventTitles) + ? eventTitles + : eventTitles.forum_events; + + if (eventsList.length === 0) { + return ; + } + + // Render the main glossary content using the selected event. + const glossaryHTML = renderContent(selectedEvent.glossary_details); + const showGlossaryMain = isValidGlossaryContent(glossaryHTML); + + const glossarySections = selectedEvent.sections?.filter((section: any) => { + if (!section.pages.includes('glossary')) return false; + const html = renderContent(section.content); + return html.trim().length > 0; + }); + + return ( +
+ + + {/* Clean Air Forum Events Section (Sidebar) */} +
+ {/* Left column: Heading */} +
+

+ Clean Air Forum Events +

+
+ {/* Right column: List of event links */} +
+
    + {eventsList.map((event) => { + // Use the unique_title directly in the link. + const href = `/clean-air-forum/about?slug=${encodeURIComponent( + event.unique_title, + )}`; + return ( +
  • + + {event.title} + +
  • + ); + })} +
+
+
+ + {/* Clean Air Glossary Section */} + {showGlossaryMain && ( + <> + +
+ {/* Left column: Heading */} +
+

+ Clean Air Glossary +

+
+ {/* Right column: Glossary content */} +
+
+ + )} + + {/* Additional Glossary Sections (if any) */} + {glossarySections && glossarySections.length > 0 && ( + <> + {glossarySections.map((section: any) => ( + + ))} + + )} +
+ ); +}; + +export default GlossaryPage; diff --git a/src/website2/src/views/cleanairforum/logistics/LogisticsPage.tsx b/src/website2/src/views/cleanairforum/logistics/LogisticsPage.tsx new file mode 100644 index 0000000000..adb3800151 --- /dev/null +++ b/src/website2/src/views/cleanairforum/logistics/LogisticsPage.tsx @@ -0,0 +1,96 @@ +'use client'; + +import DOMPurify from 'dompurify'; +import React from 'react'; + +import Loading from '@/components/loading'; +import { Divider } from '@/components/ui'; +import { useForumData } from '@/context/ForumDataContext'; +import { isValidHTMLContent } from '@/utils/htmlValidator'; +import { renderContent } from '@/utils/quillUtils'; +import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; + +const LogisticsPage: React.FC = () => { + // Destructure the selected event from the context. + const { selectedEvent } = useForumData(); + + // If selectedEvent is not available, show a loading state. + if (!selectedEvent) { + return ; + } + + // Render static content from the event model. + const vaccinationHTML = renderContent( + selectedEvent.travel_logistics_vaccination_details, + ); + const visaHTML = renderContent(selectedEvent.travel_logistics_visa_details); + + const showVaccination = isValidHTMLContent(vaccinationHTML); + const showVisa = isValidHTMLContent(visaHTML); + + // Filter extra sections assigned to the "logistics" page. + const logisticsSections = selectedEvent.sections?.filter( + (section: any) => + section.pages.includes('logistics') && + isValidHTMLContent(renderContent(section.content)), + ); + + return ( +
+ {/* Render Vaccination Section if content exists */} + {showVaccination && ( + <> + +
+
+
+

+ Vaccination +

+
+
+
+
+ + )} + + {/* Render Visa Invitation Letter Section if content exists */} + {showVisa && ( + <> + +
+
+
+

+ Visa invitation letter +

+
+
+
+
+ + )} + + {/* Render additional Logistics Sections, if any */} + {logisticsSections && logisticsSections.length > 0 && ( + <> + {logisticsSections.map((section: any) => ( + + ))} + + )} +
+ ); +}; + +export default LogisticsPage; diff --git a/src/website2/src/views/cleanairforum/partners/PartnersPage.tsx b/src/website2/src/views/cleanairforum/partners/PartnersPage.tsx new file mode 100644 index 0000000000..e4810575ef --- /dev/null +++ b/src/website2/src/views/cleanairforum/partners/PartnersPage.tsx @@ -0,0 +1,148 @@ +'use client'; + +import DOMPurify from 'dompurify'; +import React from 'react'; + +import { Divider } from '@/components/ui'; +import { useForumData } from '@/context/ForumDataContext'; +import { isValidHTMLContent } from '@/utils/htmlValidator'; +import { renderContent } from '@/utils/quillUtils'; +import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; +import PaginatedSection from '@/views/cleanAirNetwork/PaginatedSection'; + +const PartnersPage: React.FC = () => { + const { selectedEvent } = useForumData(); + if (!selectedEvent) return null; + + const conveningPartners = selectedEvent.partners + ?.filter((partner: any) => partner.category === 'Co-Convening Partner') + .map((partner: any) => ({ + id: partner.id, + logoUrl: partner.partner_logo_url, + })); + + const hostPartners = selectedEvent.partners + ?.filter((partner: any) => partner.category === 'Host Partner') + .map((partner: any) => ({ + id: partner.id, + logoUrl: partner.partner_logo_url, + })); + + const programPartners = selectedEvent.partners + ?.filter((partner: any) => partner.category === 'Program Partner') + .map((partner: any) => ({ + id: partner.id, + logoUrl: partner.partner_logo_url, + })); + + const fundingPartners = selectedEvent.partners + ?.filter((partner: any) => partner.category === 'Funding Partner') + .map((partner: any) => ({ + id: partner.id, + logoUrl: partner.partner_logo_url, + })); + + const mainPartnersHTML = renderContent(selectedEvent.partners_text_section); + const showMainPartners = isValidHTMLContent(mainPartnersHTML); + + const partnersSections = selectedEvent.sections?.filter((section: any) => { + if (!section.pages.includes('partners')) return false; + const sectionHTML = renderContent(section.content); + return isValidHTMLContent(sectionHTML); + }); + + return ( +
+ {showMainPartners && ( +
+

Partners

+
+
+ )} + + {partnersSections && partnersSections.length > 0 && ( + <> + {partnersSections.map((section: any) => ( + + ))} + + )} + + {conveningPartners && conveningPartners.length > 0 && ( + <> + +
+
+

+ Convening partners and Collaborators +

+
+ +
+ + )} + + {hostPartners && hostPartners.length > 0 && ( + <> + +
+
+

+ Host partners +

+
+ +
+ + )} + + {programPartners && programPartners.length > 0 && ( + <> + +
+
+

Exhibitors

+
+ +
+ + )} + + {fundingPartners && fundingPartners.length > 0 && ( + <> + +
+
+

+ Funding Partners and Sponsors +

+
+ +
+ + )} +
+ ); +}; + +export default PartnersPage; diff --git a/src/website2/src/views/cleanairforum/program-committee/CommitteePage.tsx b/src/website2/src/views/cleanairforum/program-committee/CommitteePage.tsx new file mode 100644 index 0000000000..4066ec1be2 --- /dev/null +++ b/src/website2/src/views/cleanairforum/program-committee/CommitteePage.tsx @@ -0,0 +1,121 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +'use client'; + +import DOMPurify from 'dompurify'; +import React, { useMemo, useState } from 'react'; + +import { Divider, MemberCard, Pagination } from '@/components/ui/'; +import { useForumData } from '@/context/ForumDataContext'; +import { isValidHTMLContent } from '@/utils/htmlValidator'; +import { renderContent } from '@/utils/quillUtils'; +import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; + +const CommitteePage: React.FC = () => { + // Always call useForumData to get the selectedEvent. + const { selectedEvent } = useForumData(); + + // Instead of conditionally calling hooks based on selectedEvent, + // extract fallback values unconditionally. + const persons = selectedEvent?.persons || []; + const sections = selectedEvent?.sections || []; + const committeeText = selectedEvent?.committee_text_section || ''; + + // Local state for pagination. + const [currentPage, setCurrentPage] = useState(1); + const membersPerPage = 6; + + // Memoize committee members using a fallback empty array. + const committeeMembers = useMemo(() => { + return persons.filter( + (person: any) => + person.category === 'Committee Member' || + person.category === 'Committee Member and Key Note Speaker' || + person.category === 'Speaker and Committee Member', + ); + }, [persons]); + + // Calculate total pages. + const totalPages = useMemo(() => { + return Math.ceil(committeeMembers.length / membersPerPage); + }, [committeeMembers, membersPerPage]); + + // Get members for the current page. + const displayedMembers = useMemo(() => { + const startIdx = (currentPage - 1) * membersPerPage; + return committeeMembers.slice(startIdx, startIdx + membersPerPage); + }, [currentPage, committeeMembers, membersPerPage]); + + // Render main committee text. + const committeeHTML = renderContent(committeeText); + const showCommitteeMain = isValidHTMLContent(committeeHTML); + + // Filter extra sections assigned to the "committee" page. + const committeeSections = useMemo(() => { + return sections.filter((section: any) => { + if (!section.pages.includes('committee')) return false; + const sectionHTML = renderContent(section.content); + return isValidHTMLContent(sectionHTML); + }); + }, [sections]); + + const handlePageChange = (newPage: number) => setCurrentPage(newPage); + + // If selectedEvent is still not available, you might render a loading indicator. + if (!selectedEvent) { + return null; + } + + return ( +
+ + + {/* Program Committee Text Section */} +
+ {showCommitteeMain && ( + <> +

Program Committee

+
+ + )} +
+ + {/* Extra Committee Sections using SectionDisplay */} + {committeeSections.length > 0 && ( + <> + {committeeSections.map((section: any) => ( + + ))} + + )} + + {/* Member Cards Grid */} +
+ {displayedMembers.map((person: any) => ( + + ))} +
+ + {/* Pagination Component */} + {totalPages > 1 && ( +
+ +
+ )} +
+ ); +}; + +export default CommitteePage; diff --git a/src/website2/src/views/cleanairforum/resources/ResourcesPage.tsx b/src/website2/src/views/cleanairforum/resources/ResourcesPage.tsx new file mode 100644 index 0000000000..a107048955 --- /dev/null +++ b/src/website2/src/views/cleanairforum/resources/ResourcesPage.tsx @@ -0,0 +1,148 @@ +'use client'; + +import React, { useState } from 'react'; +import { FaChevronDown, FaChevronUp, FaFilePdf } from 'react-icons/fa'; + +import { Divider } from '@/components/ui'; +import { useForumData } from '@/context/ForumDataContext'; + +const getFileNameFromUrl = (url: string | null | undefined): string | null => { + if (!url || typeof url !== 'string') { + console.error('Invalid URL:', url); + return null; + } + const segments = url.split('/'); + return segments.pop() || null; +}; + +const AccordionItem = ({ session, isOpen, toggleAccordion }: any) => { + return ( +
+
+

+ {session.session_title} +

+ {isOpen ? : } +
+ {isOpen && ( +
+ {session?.resource_files?.map((file: any) => ( +
+
+
+

+ {file.resource_summary} +

+ + + {getFileNameFromUrl(file.file_url)} + +
+
+
+ ))} +
+ )} +
+ ); +}; + +const ResourcesPage: React.FC = () => { + const { selectedEvent } = useForumData(); + const [openAccordions, setOpenAccordions] = useState<{ + [resourceIndex: number]: { [sessionIndex: number]: boolean }; + }>({}); + const [allExpanded, setAllExpanded] = useState(false); + + if (!selectedEvent) { + return null; + } + + const handleToggleAccordion = ( + resourceIndex: number, + sessionIndex: number, + ) => { + setOpenAccordions((prevState) => ({ + ...prevState, + [resourceIndex]: { + ...prevState[resourceIndex], + [sessionIndex]: !prevState[resourceIndex]?.[sessionIndex], + }, + })); + }; + + const handleExpandAll = () => { + setAllExpanded(true); + const expandedAccordions: any = {}; + selectedEvent.forum_resources?.forEach( + (resource: any, resourceIndex: number) => { + expandedAccordions[resourceIndex] = {}; + resource.resource_sessions?.forEach((_: any, sessionIndex: number) => { + expandedAccordions[resourceIndex][sessionIndex] = true; + }); + }, + ); + setOpenAccordions(expandedAccordions); + }; + + const handleCollapseAll = () => { + setAllExpanded(false); + setOpenAccordions({}); + }; + + return ( +
+
+ + +
+ + {selectedEvent.forum_resources?.map( + (resource: any, resourceIndex: number) => ( +
+

+ {resource.resource_title} +

+ {resource.resource_sessions?.map( + (session: any, sessionIndex: number) => ( + + handleToggleAccordion(resourceIndex, sessionIndex) + } + /> + ), + )} + +
+ ), + )} +
+ ); +}; + +export default ResourcesPage; diff --git a/src/website2/src/views/cleanairforum/sessions-programs/ProgramsPage.tsx b/src/website2/src/views/cleanairforum/sessions-programs/ProgramsPage.tsx new file mode 100644 index 0000000000..265a8fb81d --- /dev/null +++ b/src/website2/src/views/cleanairforum/sessions-programs/ProgramsPage.tsx @@ -0,0 +1,158 @@ +'use client'; + +import { format } from 'date-fns'; +import DOMPurify from 'dompurify'; +import React, { useState } from 'react'; +import { FaChevronDown, FaChevronUp } from 'react-icons/fa'; + +import { Divider } from '@/components/ui'; +import { useForumData } from '@/context/ForumDataContext'; +import { isValidHTMLContent } from '@/utils/htmlValidator'; +import { renderContent } from '@/utils/quillUtils'; +import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; + +interface AccordionItemProps { + title: string; + subText: string; + sessions: any[]; + isOpen: boolean; + onToggle: () => void; +} + +const AccordionItem: React.FC = ({ + title, + subText, + sessions, + isOpen, + onToggle, +}) => { + const formatTime = (time: string) => { + try { + return format(new Date(`1970-01-01T${time}Z`), 'p'); + } catch (error) { + console.error(error); + return time; + } + }; + + return ( +
+
+
+

{title}

+
+
+ {isOpen ? : } +
+ {isOpen && ( +
+ {sessions?.map((item: any, index: number) => ( +
+ +
+
+ {formatTime(item.start_time)} +
+
+

{item.session_title}

+
+
+
+
+ ))} +
+ )} +
+ ); +}; + +const ProgramsPage: React.FC = () => { + const { selectedEvent } = useForumData(); + const [openAccordion, setOpenAccordion] = useState(null); + + if (!selectedEvent) { + return null; + } + + const scheduleHTML = renderContent(selectedEvent.schedule_details); + const showSchedule = isValidHTMLContent(scheduleHTML); + + const registrationHTML = renderContent(selectedEvent.registration_details); + const showRegistration = isValidHTMLContent(registrationHTML); + + const sessionSections = selectedEvent.sections?.filter((section: any) => { + if (!section.pages.includes('session')) return false; + const sectionHTML = renderContent(section.content); + return isValidHTMLContent(sectionHTML); + }); + + const handleToggle = (id: string) => { + setOpenAccordion(openAccordion === id ? null : id); + }; + + return ( +
+ {showSchedule && ( +
+

Schedule

+
+
+ )} + + {sessionSections && sessionSections.length > 0 && ( + <> + {sessionSections.map((section: any) => ( + + ))} + + )} + + <> + {selectedEvent.programs?.map((program: any) => ( + handleToggle(program.id)} + /> + ))} + + + {showRegistration && ( +
+ +
+
+

Registration

+
+
+
+
+ )} +
+ ); +}; + +export default ProgramsPage; diff --git a/src/website2/src/views/cleanairforum/speakers/SpeakersPage.tsx b/src/website2/src/views/cleanairforum/speakers/SpeakersPage.tsx new file mode 100644 index 0000000000..c9fb8f40c6 --- /dev/null +++ b/src/website2/src/views/cleanairforum/speakers/SpeakersPage.tsx @@ -0,0 +1,147 @@ +'use client'; + +import DOMPurify from 'dompurify'; +import React, { useState } from 'react'; + +import { Divider, MemberCard, Pagination } from '@/components/ui/'; +import { useForumData } from '@/context/ForumDataContext'; +import { isValidHTMLContent } from '@/utils/htmlValidator'; +import { renderContent } from '@/utils/quillUtils'; +import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; + +const SpeakersPage: React.FC = () => { + // Now we use the selectedEvent from context + const { selectedEvent } = useForumData(); + const membersPerPage = 6; + const [currentKeyNotePage, setCurrentKeyNotePage] = useState(1); + const [currentSpeakersPage, setCurrentSpeakersPage] = useState(1); + + if (!selectedEvent) { + return null; + } + + // Filter keynote speakers and speakers from selectedEvent.persons. + // (Adjust your filtering logic as needed.) + const keyNoteSpeakers = + selectedEvent.persons?.filter( + (person: any) => + person.category === 'Key Note Speaker' || + person.category === 'Committee Member and Key Note Speaker', + ) || []; + const speakers = + selectedEvent.persons?.filter( + (person: any) => + person.category === 'Speaker' || + person.category === 'Speaker and Committee Member', + ) || []; + + // Pagination calculations for Keynote Speakers. + const totalKeyNotePages = Math.ceil(keyNoteSpeakers.length / membersPerPage); + const startKeyNoteIdx = (currentKeyNotePage - 1) * membersPerPage; + const displayedKeyNoteSpeakers = keyNoteSpeakers.slice( + startKeyNoteIdx, + startKeyNoteIdx + membersPerPage, + ); + + // Pagination calculations for Speakers. + const totalSpeakersPages = Math.ceil(speakers.length / membersPerPage); + const startSpeakersIdx = (currentSpeakersPage - 1) * membersPerPage; + const displayedSpeakers = speakers.slice( + startSpeakersIdx, + startSpeakersIdx + membersPerPage, + ); + + // Handlers for page changes. + const handleKeyNotePageChange = (newPage: number) => + setCurrentKeyNotePage(newPage); + const handleSpeakersPageChange = (newPage: number) => + setCurrentSpeakersPage(newPage); + + // Validate the main speakers text section. + const mainSpeakersHTML = renderContent(selectedEvent.speakers_text_section); + const showMainSpeakers = isValidHTMLContent(mainSpeakersHTML); + + // Filter extra sections assigned to the "speakers" page. + const speakersExtraSections = selectedEvent.sections?.filter( + (section: any) => { + if (!section.pages.includes('speakers')) return false; + const sectionHTML = renderContent(section.content); + return isValidHTMLContent(sectionHTML); + }, + ); + + return ( +
+ + + {/* Speakers Text Section */} + {showMainSpeakers && ( +
+
+
+ )} + + {/* Keynote Speakers Section */} +

Keynote Speakers

+ +
+ {displayedKeyNoteSpeakers.map((person: any) => ( + + ))} +
+ {totalKeyNotePages > 1 && ( +
+ +
+ )} + + + + {/* Speakers Section */} +

Speakers

+
+ {displayedSpeakers.map((person: any) => ( + + ))} +
+ {totalSpeakersPages > 1 && ( +
+ +
+ )} + + {/* Extra Speakers Sections */} + {speakersExtraSections && speakersExtraSections.length > 0 && ( + <> + {speakersExtraSections.map((section: any) => ( + + ))} + + )} +
+ ); +}; + +export default SpeakersPage; diff --git a/src/website2/src/views/cleanairforum/sponsorship/SponsorshipPage.tsx b/src/website2/src/views/cleanairforum/sponsorship/SponsorshipPage.tsx new file mode 100644 index 0000000000..47257b1cee --- /dev/null +++ b/src/website2/src/views/cleanairforum/sponsorship/SponsorshipPage.tsx @@ -0,0 +1,82 @@ +'use client'; + +import DOMPurify from 'dompurify'; +import React from 'react'; + +import { Divider } from '@/components/ui'; +import { useForumData } from '@/context/ForumDataContext'; +import { renderContent } from '@/utils/quillUtils'; +import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; +import PaginatedSection from '@/views/cleanAirNetwork/PaginatedSection'; + +const SponsorshipPage: React.FC = () => { + const { selectedEvent } = useForumData(); + if (!selectedEvent) return null; + + const sponsorPartner = selectedEvent.partners + ?.filter((partner: any) => partner.category === 'Sponsor Partner') + .map((partner: any) => ({ + id: partner.id, + logoUrl: partner.partner_logo_url, + })); + + const sponsorshipSections = selectedEvent.sections?.filter((section: any) => { + if (!section.pages.includes('sponsorships')) return false; + const html = renderContent(section.content); + return html.trim().length > 0; + }); + + const mainSponsorshipHTML = renderContent( + selectedEvent.sponsorship_opportunities_partners, + ); + const showMainSponsorship = mainSponsorshipHTML.trim().length > 0; + + return ( +
+ {showMainSponsorship && ( +
+ +
+

Sponsorship opportunities

+ +
+
+
+ )} + + {sponsorshipSections && sponsorshipSections.length > 0 && ( + <> + {sponsorshipSections.map((section: any) => ( + + ))} + + )} + + {sponsorPartner && sponsorPartner.length > 0 && ( + <> + +
+
+
+

+ Sponsors +

+
+ +
+
+ + )} +
+ ); +}; + +export default SponsorshipPage; From 6d2b5a32098a3da6347bbd6da132c5b6d13caed6 Mon Sep 17 00:00:00 2001 From: Ochieng Paul Date: Fri, 28 Feb 2025 02:04:00 +0300 Subject: [PATCH 11/20] updates --- src/website2/public/assets/icons/Icon1.tsx | 2 +- src/website2/public/assets/icons/Icon2.tsx | 2 +- src/website2/public/assets/icons/Icon3.tsx | 2 +- src/website2/public/assets/icons/Icon4.tsx | 2 +- src/website2/public/assets/icons/Icon5.tsx | 2 +- src/website2/public/assets/icons/Icon6.tsx | 2 +- src/website2/public/assets/icons/Icon7.tsx | 2 +- src/website2/public/assets/icons/Icon8.tsx | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/website2/public/assets/icons/Icon1.tsx b/src/website2/public/assets/icons/Icon1.tsx index 76615bec02..be291f7323 100644 --- a/src/website2/public/assets/icons/Icon1.tsx +++ b/src/website2/public/assets/icons/Icon1.tsx @@ -1,4 +1,4 @@ -// components/icons/Icon1.tsx + import React from 'react'; interface IconProps { diff --git a/src/website2/public/assets/icons/Icon2.tsx b/src/website2/public/assets/icons/Icon2.tsx index dbd81a690d..3e6d88d384 100644 --- a/src/website2/public/assets/icons/Icon2.tsx +++ b/src/website2/public/assets/icons/Icon2.tsx @@ -1,4 +1,4 @@ -// components/icons/Icon2.tsx + import React from 'react'; interface IconProps { diff --git a/src/website2/public/assets/icons/Icon3.tsx b/src/website2/public/assets/icons/Icon3.tsx index 5812824619..71fa508107 100644 --- a/src/website2/public/assets/icons/Icon3.tsx +++ b/src/website2/public/assets/icons/Icon3.tsx @@ -1,4 +1,4 @@ -// components/icons/Icon3.tsx + import React from 'react'; interface IconProps { diff --git a/src/website2/public/assets/icons/Icon4.tsx b/src/website2/public/assets/icons/Icon4.tsx index 40c3fa8ba1..46f132ef6b 100644 --- a/src/website2/public/assets/icons/Icon4.tsx +++ b/src/website2/public/assets/icons/Icon4.tsx @@ -1,4 +1,4 @@ -// components/icons/Icon4.tsx + import React from 'react'; interface IconProps { diff --git a/src/website2/public/assets/icons/Icon5.tsx b/src/website2/public/assets/icons/Icon5.tsx index 7da0d0487b..5483e5940f 100644 --- a/src/website2/public/assets/icons/Icon5.tsx +++ b/src/website2/public/assets/icons/Icon5.tsx @@ -1,4 +1,4 @@ -// components/icons/Icon5.tsx + import React from 'react'; interface IconProps { diff --git a/src/website2/public/assets/icons/Icon6.tsx b/src/website2/public/assets/icons/Icon6.tsx index 3b62e3f341..26911b5ca2 100644 --- a/src/website2/public/assets/icons/Icon6.tsx +++ b/src/website2/public/assets/icons/Icon6.tsx @@ -1,4 +1,4 @@ -// components/icons/Icon6.tsx + import React from 'react'; interface IconProps { diff --git a/src/website2/public/assets/icons/Icon7.tsx b/src/website2/public/assets/icons/Icon7.tsx index 38af9fcba9..a8ebbde45c 100644 --- a/src/website2/public/assets/icons/Icon7.tsx +++ b/src/website2/public/assets/icons/Icon7.tsx @@ -1,4 +1,4 @@ -// components/icons/Icon6.tsx + import React from 'react'; interface IconProps { diff --git a/src/website2/public/assets/icons/Icon8.tsx b/src/website2/public/assets/icons/Icon8.tsx index 272fbb43a8..e7016fc1e5 100644 --- a/src/website2/public/assets/icons/Icon8.tsx +++ b/src/website2/public/assets/icons/Icon8.tsx @@ -1,4 +1,4 @@ -// components/icons/Icon6.tsx + import React from 'react'; interface IconProps { From 7d82e0a872383e7eae46eae041eee31dd2d0b320 Mon Sep 17 00:00:00 2001 From: Ochieng Paul Date: Fri, 28 Feb 2025 02:58:37 +0300 Subject: [PATCH 12/20] updates --- src/website2/public/Logo.png | Bin 0 -> 6048 bytes src/website2/public/apple-icon.png | Bin 0 -> 5275 bytes src/website2/public/favicon.ico | Bin 0 -> 15086 bytes src/website2/public/icon.png | Bin 0 -> 3112 bytes src/website2/public/icon.svg | 1 + src/website2/public/manifest.json | 21 ++++ .../public/web-app-manifest-192x192.png | Bin 0 -> 6719 bytes .../public/web-app-manifest-512x512.png | Bin 0 -> 24641 bytes src/website2/src/app/favicon.ico | Bin 4542 -> 15086 bytes src/website2/src/app/layout.tsx | 91 +++++++++++++++--- 10 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 src/website2/public/Logo.png create mode 100644 src/website2/public/apple-icon.png create mode 100644 src/website2/public/favicon.ico create mode 100644 src/website2/public/icon.png create mode 100644 src/website2/public/icon.svg create mode 100644 src/website2/public/manifest.json create mode 100644 src/website2/public/web-app-manifest-192x192.png create mode 100644 src/website2/public/web-app-manifest-512x512.png diff --git a/src/website2/public/Logo.png b/src/website2/public/Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bf64b5cbd5bd113c2781f3f2d9ac65c69c69e5c6 GIT binary patch literal 6048 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

r@Ba)L(y;2~L`e-;_`U6Q!EqwxDm3$^qBfsrO3 z^jlw)rH~dYU$#H2-2YDRaUn_Em)PWMe8T|1mZaNLRteI%jQ*_$hu+i0Rc`e!vm$0E z=!b$N+J?kbC;~?AY;*oRT?Bv&r`48gPIZ)hbE*$`QZ;%K_CV*$-tv({UbRmx4G0)) z$J)XHk7)>e^{GRAYnzKD>7hP=RMQUx`54Jf+~0)m-imvR(6>E6A@rom41;oh$MZ+H z9W}jchpCD9UHv{u=I+~Ej0NXBgcN9v(46G`$SU1=>qz)`5n|}Y_Sdr+J|_9IjNv_a zq2{w)PMx6fwBoAGh0FSyo1yz`n8#klM*#kC#3q-wasLOEOYZw*Csx%=sD-+uW~?%g z*ZRF8R>12ls8=Q_Jo~?s$%Qopt0B|Tu@PmBYkj=o;^*lPOdzeN{D&O&#hD}W;j4qL zV57LsOij&mBSjU2is+f6wz9aNOfL`V=-m(yXOe9dn5Pyezh|I+Ae5ci8BvL#C%TTd zKIt8Lt}5p}AE>mtg8!d~Mw<8ZW?SU3&1`PNe;H_$7r1kArA{*55fmpYd@b5k8{u-p zH@FJ3{(81X0#M3$bhxJO-0oGIr;Ft4?_b<`74+fYd3(!bT4$q2Ur6s_+!&M3?~UJT z675oc@63wd+PPK@-#F+5AZ>BJ6pz4Ldzszq={iIxi z60TuZ!8g%v%|BH_ke?T^L)@d4^mnt5r~$)(Nz;$=E-X)K`nIG(hVpfc|*3 zgg&ObI2<8Nrw>1t#LiU2AmcQ3)7TbI3i~qVjD`oQ{2Q`UCwx_Qx{!51|CyH>TnP6EhW4QY4wl4}$@nKnZ)Y|a>EFkVvUDgR zg}*IG7}hAueda!cwQLAVfDwVdsicd(WuP^E!(q6Y`gI@UT8fmp7RSYczW$aN3+3Xy zI(av8x$+MY^{x!HJPDFYMEZHtYtt#;t6C3=pPjCh4;ivAyv>}#=gE{JNjJy0&U>4O zQsLE|_N{Aq(V0)xtuWJwtX+t)#G`V}B)KC!4DZXfnL+2~^{6&?swh3T_OtG=uIzYL z4|SnxomHfb7TW|LjM^;sARc*7jlGg|{G4-3x_unI{?mW@Rk=Rq&YoP@(IW{@D@nPXW zIk6#~g2HE-*Aybjd#{O2K@9 zN$b|5vya4g9K-*qyNcwiUO7M!b_T|rS3ZOM%iFdj3pjeRsCKnL9SF3G{*e;%{|*0} c_HY3`RcLa^5KM5oavK5q+QwRC8qUxD0~aQ{BLDyZ literal 0 HcmV?d00001 diff --git a/src/website2/public/favicon.ico b/src/website2/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..80f940cae3b4eabceb7c974ff4a87f703cca4748 GIT binary patch literal 15086 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 literal 0 HcmV?d00001 diff --git a/src/website2/public/icon.png b/src/website2/public/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fd9cd302d843f26fb7e0ccbef498a07d221f8295 GIT binary patch literal 3112 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 literal 0 HcmV?d00001 diff --git a/src/website2/public/icon.svg b/src/website2/public/icon.svg new file mode 100644 index 0000000000..e925bedccd --- /dev/null +++ b/src/website2/public/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/website2/public/manifest.json b/src/website2/public/manifest.json new file mode 100644 index 0000000000..859342a095 --- /dev/null +++ b/src/website2/public/manifest.json @@ -0,0 +1,21 @@ +{ + "name": "AirQo Website", + "short_name": "AirQo", + "icons": [ + { + "src": "/web-app-manifest-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/web-app-manifest-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/src/website2/public/web-app-manifest-192x192.png b/src/website2/public/web-app-manifest-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..1f574466b54b18d9d9c7002f3fbef9c204ef60c5 GIT binary patch literal 6719 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 JQrj`=e*j48(Z&D( literal 0 HcmV?d00001 diff --git a/src/website2/public/web-app-manifest-512x512.png b/src/website2/public/web-app-manifest-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..9a57e19709775d03e3db84415d6843a5b01c2be6 GIT binary patch literal 24641 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 a0R5N)Uu}C^Fz`+QkfDKzex;uC}`^PG? zXO@^fUEetk-pD`}G7Ce<#d2e|9xz+G-0a%#n2qdjHslz!kCom=9&a}0WV2zP&cZ{y zk#X(WE)&`LA>@(SvGBo@_lT!tUYOJyxg)A{eXQ9`WFkBNdk8sjcKzRa&FnWPIY0PL`-$1=`HGVsL4&O`M`(6lq*+3=ONHOE+wAs>WdEnkZuqI|`P?$IWjCAE ze9h^w0omw~8}jGxOK)@^qsQ;Q>2ZndSDx|ThdwZSd$ZXszcAbPuGxK8oBex($8dND z=(+d5j=$x3vv=Q-Pd_x9G0bfCD8Js(WcI3f?t9N{>x*WWe#vd%{h~u|IFkF3o?It? zhj?Fcn^r19pEFv1(XgL-uGxpJx%D5a7#jW=vyE%ac1ph~!oTdxW-I5IeQ?nEy!nc3 z+hummS=K_G*uxyDpRO-!^+gHjL=!JTE`lW&BOU5?o?v;`d9{-fZ5LX7~|a%N3jW z|DLhZ>jcH^1!lS8=U|K36Z6c*p6>qNv(s$yIqu_Ce{?$DBeA_-J{b2cxAp#OT*ksW zmx*k2C>36N&c`46v!j+$vIN*l6m`)8D>x2ulPStaXM9VO|98gXZUZv5%>Pq z?C#55w*~SiV}Lk(@?OnRv;B9y;(Oeg&UcLb^6+#sVrE`VyY9@(#2B`g1Nembh53+p zgfH_R*SufmhzVz#z3`~n_(6KEdqY2-e6Btb$HIjsd@H~S^J^PV@qsSjBNN$`0QgM) zk?Rlt)P_!XkMa26U8O!NNyj_oEx(^Ms@F)-R=b(jn zvqt*M9lqYkrEB_q)+W#tUSAcGj_#}h$^&wu<+rrwk?H!TUXyEr3r+ce?wiVIBM#)! zd+eshmC1UQugbibl>nog5C``K92HYI}hVS?fpW4@m#HJ=li4^*gtq$J!7}_Y@m?QY__-nV@reuQ*~%cjvr>?5txo zUDtfq;=%W!E5C8bYOBxX)2*0i;z_PS&OzQp?nnMw&iWzb?;(#&Iz&GxiVo8Ei=y51AC00W`lF(#fxd5hU&nQyC<;B7|4&edF)8*naGhd* z6W8)f@Kf+x@MG|6@Uw{kzjIEjO6@GQQqE~9e)_6atJSM*Rclp?3*bTnEj(mVd=P$( zTC-ZE0A4kPG!Tw9eQaf=gl6Fb?_;v*!F{!tvd~oe7BVt)(7n#IJKctrsXov{-gj3+ zA|51^IIm=^#kB*OVT{G4sWe^~-yQic~nNspHHa7q3w#TQEKaSG4eGe#7f$ z9i?y;=9cy+)Wx?cMA{x!>fWgm*gZ<0)Wy-9wUGfHxlHt?SC7d)t6z!TnuVAor!yM5R9mY#puY{M!u&LHep zN;5%qMEtx)_OdTe-SF|de4l&ueX4c7Bb@IgasK3c$PEk3Mjh`w;av!b5%z{go!~l9 zd#9fI`=PSqtNw1OTVC~b-}}PO+442#5vb);A4eXw&gnzshvR$?7M_{$mtC8~hjk7} zK1PSsdJM7k;$ymZY`lGGXyE}bcoqZfiLJQR^$+{3i9J8@3)h8uY==jw`)lk&KRVOn z99u#wBo{pDpU{@Gm(4uLo-FfUqBbnPaby$g&_D~1asYb#M=ckd3dsitTxiObovJry zZEpQ#{@5cfZxar<@u4*qDz>!l_qm4mo9+khF%N+g-)>}YjU^u>YH7?N%;kxAkiFQ< z@9Qt{XW+yKWY@<>7bg6vajbpFY|%us#gqIu_llE^SY(p}bQdJn1``I~%|G{N;DGDkwESK%U1#(}$C+Br5wgDE4C3O6%9m#N z`AD9z)&MshSo?6kmi5O@vE}^ml4-ssV(rJ8g|ncnow%P4oCV_SD(fcBDv~!N|LQY! z-u2sB_kG2zPB}a}ay~X4_{Qzn=4Zw@U(GqaL|&-xFzYdLRL**Vlk0oPxf0e7oY&?1 z9dZeNhqKLv&YqBCuog<3`w|_r{N`Tv{6mJPL1L}DUh9Mll{XEM@ANzS8Ub2jpj3di tzgkNP44_GjBlRVZpD+mFrG`G4{?N@N1bf@YZ-c(nb$tSt_&qex{trly4G;hT literal 4542 zcmZQzU<5)%1qL9gz_3D)fkBLcfk6X^6@l0Rh(Y2Y&>+CTAj}QHU;!ZUKUQ@9|5%a# z1BRo8<44^94FAz^fTY3Ea2Pt_P-yu7KQ%DE@&{LX=#TsV|JB3)R0Cf>{Qut{i@hAg z=7u(Zs#%R;5H@#UbHnu`7+R?&a1CfSdc0tB1Jx|VVGuEH0L2}x0LW}&+;C_)tz7W` z|JqLC+>oyP|NrYp)OW{&%m4p_%qAurKxzt&sOt`ppFn1!+YjPnOOr5l)N%(t`w6)L zBu}Y32-#1J8$fER9smFT`jPbX0m=i_4%ovVWG)Qjiwl?<5KT_m+3JU|2iYuiHnDC1 z>6@8Dd{}_gqT7XwPl_8rW~}QX?2aW>#M=)tlTf$#vw*34FC)Ol%W6s diff --git a/src/website2/src/app/layout.tsx b/src/website2/src/app/layout.tsx index ebd32cf9c6..a6061ec024 100644 --- a/src/website2/src/app/layout.tsx +++ b/src/website2/src/app/layout.tsx @@ -39,6 +39,45 @@ export default async function RootLayout({ const description = 'AirQo is transforming air quality management in Africa by providing low-cost sensors, real-time data, and actionable insights to help communities and organizations improve air quality.'; + const keywords = [ + 'AirQo', + 'air quality monitoring', + 'air pollution', + 'PM1', + 'PM2.5', + 'PM10', + 'NO2', + 'SO2', + 'CO', + 'O3', + 'air quality index', + 'AQI', + 'real-time air quality data', + 'low-cost air sensors', + 'urban air pollution', + 'environmental monitoring', + 'climate change', + 'air quality management', + 'clean air solutions', + 'air quality in Africa', + 'environmental health', + 'ambient air monitoring', + 'particulate matter', + 'air quality forecasting', + 'air quality analytics', + 'pollution mitigation', + 'environmental data', + 'sustainable cities', + 'public health', + 'respiratory health', + 'environmental policy', + 'air quality research', + 'air quality standards', + 'air quality compliance', + 'air pollution control', + 'air quality education', + ].join(', '); + const maintenance = await checkMaintenance(); return ( @@ -47,24 +86,54 @@ export default async function RootLayout({ {/* Primary SEO */} {title} - + + + + {/* Real Favicon Generator / Favicon + App Icons */} + + + + + + + {/* Windows / MS Tiles */} + + + + {/* Manifest */} + + {/* Open Graph / Facebook */} + + + {/* Twitter */} + + + {/* Canonical URL */} + {/* GA snippet must appear in for Search Console verification */} From 981015a8269634968228a9c0e5254b75285e2e25 Mon Sep 17 00:00:00 2001 From: Ochieng Paul Date: Fri, 28 Feb 2025 03:19:33 +0300 Subject: [PATCH 13/20] updates --- src/website2/src/app/clean-air-forum/about/page.tsx | 12 +++++++++--- .../src/app/clean-air-forum/glossary/page.tsx | 12 ++++++++++-- src/website2/src/app/clean-air-forum/layout.tsx | 1 - .../src/app/clean-air-forum/logistics/page.tsx | 12 ++++++++++-- .../src/app/clean-air-forum/partners/page.tsx | 12 ++++++++++-- .../app/clean-air-forum/program-committee/page.tsx | 12 ++++++++++-- .../src/app/clean-air-forum/resources/page.tsx | 12 ++++++++++-- .../src/app/clean-air-forum/sessions/page.tsx | 12 ++++++++++-- .../src/app/clean-air-forum/speakers/page.tsx | 12 ++++++++++-- .../src/app/clean-air-forum/sponsorships/page.tsx | 12 ++++++++++-- .../src/app/clean-air-network/about/page.tsx | 12 +++++++++--- .../src/app/clean-air-network/events/page.tsx | 12 ++++++++++-- .../src/app/clean-air-network/membership/page.tsx | 12 ++++++++++-- .../src/app/clean-air-network/resources/page.tsx | 12 ++++++++++-- 14 files changed, 128 insertions(+), 29 deletions(-) diff --git a/src/website2/src/app/clean-air-forum/about/page.tsx b/src/website2/src/app/clean-air-forum/about/page.tsx index 50db675f9a..36e0d2d00b 100644 --- a/src/website2/src/app/clean-air-forum/about/page.tsx +++ b/src/website2/src/app/clean-air-forum/about/page.tsx @@ -1,8 +1,14 @@ -import React from 'react'; +import { Metadata } from 'next'; import AboutPage from '@/views/cleanAirForum/AboutPage'; -const page = () => { +export const metadata: Metadata = { + title: 'About Clean Air Forum | AirQo', + description: + 'Discover the Clean Air Forum – learn about our mission, vision, and how we foster collaboration to advance clean air solutions and improve air quality.', +}; + +const Page = () => { return (

@@ -10,4 +16,4 @@ const page = () => { ); }; -export default page; +export default Page; diff --git a/src/website2/src/app/clean-air-forum/glossary/page.tsx b/src/website2/src/app/clean-air-forum/glossary/page.tsx index 1ec56013d8..7e71c40c03 100644 --- a/src/website2/src/app/clean-air-forum/glossary/page.tsx +++ b/src/website2/src/app/clean-air-forum/glossary/page.tsx @@ -1,7 +1,15 @@ +import { Metadata } from 'next'; + import GlossaryPage from '@/views/cleanAirForum/glossary/GlossaryPage'; -const page = () => { +export const metadata: Metadata = { + title: 'Glossary | Clean Air Forum', + description: + 'Explore our glossary of key terms and pollutant types used at Clean Air Forum, providing clear definitions to help you better understand air quality management.', +}; + +const Page = () => { return ; }; -export default page; +export default Page; diff --git a/src/website2/src/app/clean-air-forum/layout.tsx b/src/website2/src/app/clean-air-forum/layout.tsx index d5c397f320..d727cb6bc7 100644 --- a/src/website2/src/app/clean-air-forum/layout.tsx +++ b/src/website2/src/app/clean-air-forum/layout.tsx @@ -1,4 +1,3 @@ -// components/layouts/CleanAirLayout.tsx 'use client'; import { useSearchParams } from 'next/navigation'; diff --git a/src/website2/src/app/clean-air-forum/logistics/page.tsx b/src/website2/src/app/clean-air-forum/logistics/page.tsx index 9830932ebf..21bc43015b 100644 --- a/src/website2/src/app/clean-air-forum/logistics/page.tsx +++ b/src/website2/src/app/clean-air-forum/logistics/page.tsx @@ -1,7 +1,15 @@ +import { Metadata } from 'next'; + import LogisticsPage from '@/views/cleanAirForum/logistics/LogisticsPage'; -const page = () => { +export const metadata: Metadata = { + title: 'Logistics | Clean Air Forum', + description: + 'Get all the essential logistics information for attending the Clean Air Forum, including travel, accommodation, event schedules, and practical tips for participants.', +}; + +const Page = () => { return ; }; -export default page; +export default Page; diff --git a/src/website2/src/app/clean-air-forum/partners/page.tsx b/src/website2/src/app/clean-air-forum/partners/page.tsx index 2be1d02a58..8aee8d68e9 100644 --- a/src/website2/src/app/clean-air-forum/partners/page.tsx +++ b/src/website2/src/app/clean-air-forum/partners/page.tsx @@ -1,7 +1,15 @@ +import { Metadata } from 'next'; + import PartnersPage from '@/views/cleanAirForum/partners/PartnersPage'; -const page = () => { +export const metadata: Metadata = { + title: 'Partners | Clean Air Forum | AirQo', + description: + 'Discover the partners collaborating with Clean Air Forum to advance clean air solutions and improve air quality through innovation and community engagement.', +}; + +const Page = () => { return ; }; -export default page; +export default Page; diff --git a/src/website2/src/app/clean-air-forum/program-committee/page.tsx b/src/website2/src/app/clean-air-forum/program-committee/page.tsx index 523fd1f3e6..c1dd8cfb3f 100644 --- a/src/website2/src/app/clean-air-forum/program-committee/page.tsx +++ b/src/website2/src/app/clean-air-forum/program-committee/page.tsx @@ -1,7 +1,15 @@ +import { Metadata } from 'next'; + import CommitteePage from '@/views/cleanAirForum/program-committee/CommitteePage'; -const page = () => { +export const metadata: Metadata = { + title: 'Program Committee | Clean Air Forum | AirQo', + description: + 'Meet the expert program committee of Clean Air Forum. Learn about the thought leaders and industry experts driving innovative strategies for better air quality.', +}; + +const Page = () => { return ; }; -export default page; +export default Page; diff --git a/src/website2/src/app/clean-air-forum/resources/page.tsx b/src/website2/src/app/clean-air-forum/resources/page.tsx index ddd69c5000..2a4a1b5831 100644 --- a/src/website2/src/app/clean-air-forum/resources/page.tsx +++ b/src/website2/src/app/clean-air-forum/resources/page.tsx @@ -1,7 +1,15 @@ +import { Metadata } from 'next'; + import ResourcesPage from '@/views/cleanAirForum/resources/ResourcesPage'; -const page = () => { +export const metadata: Metadata = { + title: 'Resources | Clean Air Forum | AirQo', + description: + 'Access comprehensive resources, presentations, and documents from Clean Air Forum to stay informed about the latest trends and innovations in air quality management.', +}; + +const Page = () => { return ; }; -export default page; +export default Page; diff --git a/src/website2/src/app/clean-air-forum/sessions/page.tsx b/src/website2/src/app/clean-air-forum/sessions/page.tsx index 4ecbed5ff6..24399efeff 100644 --- a/src/website2/src/app/clean-air-forum/sessions/page.tsx +++ b/src/website2/src/app/clean-air-forum/sessions/page.tsx @@ -1,7 +1,15 @@ +import { Metadata } from 'next'; + import ProgramsPage from '@/views/cleanAirForum/sessions-programs/ProgramsPage'; -const page = () => { +export const metadata: Metadata = { + title: 'Sessions & Programs | Clean Air Forum | AirQo', + description: + 'Explore the schedule and detailed program information for Clean Air Forum. Find out about the sessions, topics, and speakers shaping the future of air quality management.', +}; + +const Page = () => { return ; }; -export default page; +export default Page; diff --git a/src/website2/src/app/clean-air-forum/speakers/page.tsx b/src/website2/src/app/clean-air-forum/speakers/page.tsx index 4b0ba9cf3f..8f4891cb02 100644 --- a/src/website2/src/app/clean-air-forum/speakers/page.tsx +++ b/src/website2/src/app/clean-air-forum/speakers/page.tsx @@ -1,7 +1,15 @@ +import { Metadata } from 'next'; + import SpeakersPage from '@/views/cleanAirForum/speakers/SpeakersPage'; -const page = () => { +export const metadata: Metadata = { + title: 'Speakers | Clean Air Forum | AirQo', + description: + 'Meet the distinguished speakers at Clean Air Forum. Learn from industry leaders and experts who are driving change in air quality and environmental management.', +}; + +const Page = () => { return ; }; -export default page; +export default Page; diff --git a/src/website2/src/app/clean-air-forum/sponsorships/page.tsx b/src/website2/src/app/clean-air-forum/sponsorships/page.tsx index eee73080f9..600ae4b8da 100644 --- a/src/website2/src/app/clean-air-forum/sponsorships/page.tsx +++ b/src/website2/src/app/clean-air-forum/sponsorships/page.tsx @@ -1,7 +1,15 @@ +import { Metadata } from 'next'; + import SponsorshipPage from '@/views/cleanAirForum/sponsorship/SponsorshipPage'; -const page = () => { +export const metadata: Metadata = { + title: 'Sponsorship | Clean Air Forum | AirQo', + description: + 'Discover sponsorship opportunities for Clean Air Forum. Learn about tailored sponsorship packages designed to support innovation and community engagement in air quality management.', +}; + +const Page = () => { return ; }; -export default page; +export default Page; diff --git a/src/website2/src/app/clean-air-network/about/page.tsx b/src/website2/src/app/clean-air-network/about/page.tsx index 5cbb768215..b97864b717 100644 --- a/src/website2/src/app/clean-air-network/about/page.tsx +++ b/src/website2/src/app/clean-air-network/about/page.tsx @@ -1,8 +1,14 @@ -import React from 'react'; +import { Metadata } from 'next'; import CleanAirPage from '@/views/cleanAirNetwork/about/CleanAirPage'; -const page = () => { +export const metadata: Metadata = { + title: 'About Clean Air Network | AirQo', + description: + 'Discover Clean Air Network – our mission, vision, and the collaborative efforts we undertake to drive innovation and improve air quality through community and stakeholder engagement.', +}; + +const Page = () => { return (
@@ -10,4 +16,4 @@ const page = () => { ); }; -export default page; +export default Page; diff --git a/src/website2/src/app/clean-air-network/events/page.tsx b/src/website2/src/app/clean-air-network/events/page.tsx index 71f1467baa..e2b83ddc5e 100644 --- a/src/website2/src/app/clean-air-network/events/page.tsx +++ b/src/website2/src/app/clean-air-network/events/page.tsx @@ -1,6 +1,14 @@ +import { Metadata } from 'next'; + import EventsPage from '@/views/cleanAirNetwork/events/EventsPage'; -const page = () => { +export const metadata: Metadata = { + title: 'Events | Clean Air Network | AirQo', + description: + 'Explore upcoming and past events hosted by Clean Air Network. Stay informed about conferences, webinars, and networking opportunities designed to advance clean air initiatives.', +}; + +const Page = () => { return (
@@ -8,4 +16,4 @@ const page = () => { ); }; -export default page; +export default Page; diff --git a/src/website2/src/app/clean-air-network/membership/page.tsx b/src/website2/src/app/clean-air-network/membership/page.tsx index f539b1fec5..f57f069738 100644 --- a/src/website2/src/app/clean-air-network/membership/page.tsx +++ b/src/website2/src/app/clean-air-network/membership/page.tsx @@ -1,6 +1,14 @@ +import { Metadata } from 'next'; + import MemberPage from '@/views/cleanAirNetwork/membership/MemberPage'; -const page = () => { +export const metadata: Metadata = { + title: 'Membership | Clean Air Network | AirQo', + description: + 'Join Clean Air Network – connect with professionals dedicated to advancing air quality. Learn about membership benefits, exclusive resources, and opportunities for collaboration.', +}; + +const Page = () => { return (
@@ -8,4 +16,4 @@ const page = () => { ); }; -export default page; +export default Page; diff --git a/src/website2/src/app/clean-air-network/resources/page.tsx b/src/website2/src/app/clean-air-network/resources/page.tsx index ab4a307194..985d5abf52 100644 --- a/src/website2/src/app/clean-air-network/resources/page.tsx +++ b/src/website2/src/app/clean-air-network/resources/page.tsx @@ -1,6 +1,14 @@ +import { Metadata } from 'next'; + import ResourcePage from '@/views/cleanAirNetwork/resources/ResourcePage'; -const page = () => { +export const metadata: Metadata = { + title: 'Resources | Clean Air Network | AirQo', + description: + 'Access a wide range of resources and insights on air quality management from Clean Air Network. Explore reports, case studies, and research to stay ahead in clean air initiatives.', +}; + +const Page = () => { return (
@@ -8,4 +16,4 @@ const page = () => { ); }; -export default page; +export default Page; From c163d19dfb122a2bcaa40734afbff204a3a68ec1 Mon Sep 17 00:00:00 2001 From: Ochieng Paul Date: Fri, 28 Feb 2025 03:33:52 +0300 Subject: [PATCH 14/20] path issues --- src/website2/src/app/clean-air-forum/about/page.tsx | 2 +- src/website2/src/views/cleanairforum/{ => about}/AboutPage.tsx | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/website2/src/views/cleanairforum/{ => about}/AboutPage.tsx (100%) diff --git a/src/website2/src/app/clean-air-forum/about/page.tsx b/src/website2/src/app/clean-air-forum/about/page.tsx index 36e0d2d00b..28c7f03e7e 100644 --- a/src/website2/src/app/clean-air-forum/about/page.tsx +++ b/src/website2/src/app/clean-air-forum/about/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import AboutPage from '@/views/cleanAirForum/AboutPage'; +import AboutPage from '@/views/cleanAirForum/about/AboutPage'; export const metadata: Metadata = { title: 'About Clean Air Forum | AirQo', diff --git a/src/website2/src/views/cleanairforum/AboutPage.tsx b/src/website2/src/views/cleanairforum/about/AboutPage.tsx similarity index 100% rename from src/website2/src/views/cleanairforum/AboutPage.tsx rename to src/website2/src/views/cleanairforum/about/AboutPage.tsx From ac280ddcb0c3b1075763df241e1e2d8e3849f014 Mon Sep 17 00:00:00 2001 From: Ochieng Paul Date: Fri, 28 Feb 2025 03:53:27 +0300 Subject: [PATCH 15/20] removed react fc on components --- src/website2/src/views/cleanairforum/BannerSection.tsx | 6 +----- src/website2/src/views/cleanairforum/about/AboutPage.tsx | 2 +- .../src/views/cleanairforum/glossary/GlossaryPage.tsx | 2 +- .../src/views/cleanairforum/logistics/LogisticsPage.tsx | 2 +- .../src/views/cleanairforum/partners/PartnersPage.tsx | 2 +- .../views/cleanairforum/program-committee/CommitteePage.tsx | 2 +- .../src/views/cleanairforum/resources/ResourcesPage.tsx | 2 +- .../views/cleanairforum/sessions-programs/ProgramsPage.tsx | 2 +- .../src/views/cleanairforum/speakers/SpeakersPage.tsx | 2 +- .../src/views/cleanairforum/sponsorship/SponsorshipPage.tsx | 2 +- 10 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/website2/src/views/cleanairforum/BannerSection.tsx b/src/website2/src/views/cleanairforum/BannerSection.tsx index e7886bf2dc..c201a56a96 100644 --- a/src/website2/src/views/cleanairforum/BannerSection.tsx +++ b/src/website2/src/views/cleanairforum/BannerSection.tsx @@ -8,11 +8,7 @@ import { CustomButton } from '@/components/ui'; import TabNavigation from './TabNavigation'; -type BannerSectionProps = { - data: any; // Type it accordingly -}; - -const BannerSection: React.FC = ({ data }) => { +const BannerSection = ({ data }: { data: any }) => { if (!data) { return null; } diff --git a/src/website2/src/views/cleanairforum/about/AboutPage.tsx b/src/website2/src/views/cleanairforum/about/AboutPage.tsx index 641c647774..20741aef14 100644 --- a/src/website2/src/views/cleanairforum/about/AboutPage.tsx +++ b/src/website2/src/views/cleanairforum/about/AboutPage.tsx @@ -27,7 +27,7 @@ const SectionRow: React.FC = ({ title, children }) => ( ); -const AboutPage: React.FC = () => { +const AboutPage = () => { const { selectedEvent } = useForumData(); if (!selectedEvent) { diff --git a/src/website2/src/views/cleanairforum/glossary/GlossaryPage.tsx b/src/website2/src/views/cleanairforum/glossary/GlossaryPage.tsx index 48f7003000..3535cd32b2 100644 --- a/src/website2/src/views/cleanairforum/glossary/GlossaryPage.tsx +++ b/src/website2/src/views/cleanairforum/glossary/GlossaryPage.tsx @@ -13,7 +13,7 @@ import { isValidGlossaryContent } from '@/utils/glossaryValidator'; import { renderContent } from '@/utils/quillUtils'; import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; -const GlossaryPage: React.FC = () => { +const GlossaryPage = () => { // Access data from the context. const { selectedEvent, eventTitles } = useForumData(); diff --git a/src/website2/src/views/cleanairforum/logistics/LogisticsPage.tsx b/src/website2/src/views/cleanairforum/logistics/LogisticsPage.tsx index adb3800151..25c5f9ee1c 100644 --- a/src/website2/src/views/cleanairforum/logistics/LogisticsPage.tsx +++ b/src/website2/src/views/cleanairforum/logistics/LogisticsPage.tsx @@ -10,7 +10,7 @@ import { isValidHTMLContent } from '@/utils/htmlValidator'; import { renderContent } from '@/utils/quillUtils'; import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; -const LogisticsPage: React.FC = () => { +const LogisticsPage = () => { // Destructure the selected event from the context. const { selectedEvent } = useForumData(); diff --git a/src/website2/src/views/cleanairforum/partners/PartnersPage.tsx b/src/website2/src/views/cleanairforum/partners/PartnersPage.tsx index e4810575ef..0d09769ffe 100644 --- a/src/website2/src/views/cleanairforum/partners/PartnersPage.tsx +++ b/src/website2/src/views/cleanairforum/partners/PartnersPage.tsx @@ -10,7 +10,7 @@ import { renderContent } from '@/utils/quillUtils'; import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; import PaginatedSection from '@/views/cleanAirNetwork/PaginatedSection'; -const PartnersPage: React.FC = () => { +const PartnersPage = () => { const { selectedEvent } = useForumData(); if (!selectedEvent) return null; diff --git a/src/website2/src/views/cleanairforum/program-committee/CommitteePage.tsx b/src/website2/src/views/cleanairforum/program-committee/CommitteePage.tsx index 4066ec1be2..fbd4cf55b4 100644 --- a/src/website2/src/views/cleanairforum/program-committee/CommitteePage.tsx +++ b/src/website2/src/views/cleanairforum/program-committee/CommitteePage.tsx @@ -10,7 +10,7 @@ import { isValidHTMLContent } from '@/utils/htmlValidator'; import { renderContent } from '@/utils/quillUtils'; import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; -const CommitteePage: React.FC = () => { +const CommitteePage = () => { // Always call useForumData to get the selectedEvent. const { selectedEvent } = useForumData(); diff --git a/src/website2/src/views/cleanairforum/resources/ResourcesPage.tsx b/src/website2/src/views/cleanairforum/resources/ResourcesPage.tsx index a107048955..e07c787345 100644 --- a/src/website2/src/views/cleanairforum/resources/ResourcesPage.tsx +++ b/src/website2/src/views/cleanairforum/resources/ResourcesPage.tsx @@ -55,7 +55,7 @@ const AccordionItem = ({ session, isOpen, toggleAccordion }: any) => { ); }; -const ResourcesPage: React.FC = () => { +const ResourcesPage = () => { const { selectedEvent } = useForumData(); const [openAccordions, setOpenAccordions] = useState<{ [resourceIndex: number]: { [sessionIndex: number]: boolean }; diff --git a/src/website2/src/views/cleanairforum/sessions-programs/ProgramsPage.tsx b/src/website2/src/views/cleanairforum/sessions-programs/ProgramsPage.tsx index 265a8fb81d..e4e8c3b6fd 100644 --- a/src/website2/src/views/cleanairforum/sessions-programs/ProgramsPage.tsx +++ b/src/website2/src/views/cleanairforum/sessions-programs/ProgramsPage.tsx @@ -77,7 +77,7 @@ const AccordionItem: React.FC = ({ ); }; -const ProgramsPage: React.FC = () => { +const ProgramsPage = () => { const { selectedEvent } = useForumData(); const [openAccordion, setOpenAccordion] = useState(null); diff --git a/src/website2/src/views/cleanairforum/speakers/SpeakersPage.tsx b/src/website2/src/views/cleanairforum/speakers/SpeakersPage.tsx index c9fb8f40c6..049178a0fa 100644 --- a/src/website2/src/views/cleanairforum/speakers/SpeakersPage.tsx +++ b/src/website2/src/views/cleanairforum/speakers/SpeakersPage.tsx @@ -9,7 +9,7 @@ import { isValidHTMLContent } from '@/utils/htmlValidator'; import { renderContent } from '@/utils/quillUtils'; import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; -const SpeakersPage: React.FC = () => { +const SpeakersPage = () => { // Now we use the selectedEvent from context const { selectedEvent } = useForumData(); const membersPerPage = 6; diff --git a/src/website2/src/views/cleanairforum/sponsorship/SponsorshipPage.tsx b/src/website2/src/views/cleanairforum/sponsorship/SponsorshipPage.tsx index 47257b1cee..4f87ddef92 100644 --- a/src/website2/src/views/cleanairforum/sponsorship/SponsorshipPage.tsx +++ b/src/website2/src/views/cleanairforum/sponsorship/SponsorshipPage.tsx @@ -9,7 +9,7 @@ import { renderContent } from '@/utils/quillUtils'; import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; import PaginatedSection from '@/views/cleanAirNetwork/PaginatedSection'; -const SponsorshipPage: React.FC = () => { +const SponsorshipPage = () => { const { selectedEvent } = useForumData(); if (!selectedEvent) return null; From 53b9560fa188ec5f2832f50ae139d54bcdf4cd7f Mon Sep 17 00:00:00 2001 From: Ochieng Paul Date: Fri, 28 Feb 2025 03:59:12 +0300 Subject: [PATCH 16/20] updates --- src/website2/src/app/clean-air-forum/about/page.tsx | 2 +- src/website2/src/app/clean-air-forum/glossary/page.tsx | 2 +- src/website2/src/app/clean-air-forum/layout.tsx | 3 ++- src/website2/src/app/clean-air-forum/logistics/page.tsx | 2 +- src/website2/src/app/clean-air-forum/partners/page.tsx | 2 +- .../src/app/clean-air-forum/program-committee/page.tsx | 2 +- src/website2/src/app/clean-air-forum/resources/page.tsx | 2 +- src/website2/src/app/clean-air-forum/sessions/page.tsx | 2 +- src/website2/src/app/clean-air-forum/speakers/page.tsx | 2 +- src/website2/src/app/clean-air-forum/sponsorships/page.tsx | 2 +- 10 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/website2/src/app/clean-air-forum/about/page.tsx b/src/website2/src/app/clean-air-forum/about/page.tsx index 28c7f03e7e..02b75ed4b2 100644 --- a/src/website2/src/app/clean-air-forum/about/page.tsx +++ b/src/website2/src/app/clean-air-forum/about/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import AboutPage from '@/views/cleanAirForum/about/AboutPage'; +import AboutPage from '../../../views/cleanAirForum/about/AboutPage'; export const metadata: Metadata = { title: 'About Clean Air Forum | AirQo', diff --git a/src/website2/src/app/clean-air-forum/glossary/page.tsx b/src/website2/src/app/clean-air-forum/glossary/page.tsx index 7e71c40c03..82377b7b95 100644 --- a/src/website2/src/app/clean-air-forum/glossary/page.tsx +++ b/src/website2/src/app/clean-air-forum/glossary/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import GlossaryPage from '@/views/cleanAirForum/glossary/GlossaryPage'; +import GlossaryPage from '../../../views/cleanAirForum/glossary/GlossaryPage'; export const metadata: Metadata = { title: 'Glossary | Clean Air Forum', diff --git a/src/website2/src/app/clean-air-forum/layout.tsx b/src/website2/src/app/clean-air-forum/layout.tsx index d727cb6bc7..0a63fc3742 100644 --- a/src/website2/src/app/clean-air-forum/layout.tsx +++ b/src/website2/src/app/clean-air-forum/layout.tsx @@ -11,7 +11,8 @@ import { NoData } from '@/components/ui'; import mainConfig from '@/configs/mainConfigs'; import { ForumDataProvider } from '@/context/ForumDataContext'; import { useForumEventDetails, useForumEventTitles } from '@/hooks/useApiHooks'; -import BannerSection from '@/views/cleanAirForum/BannerSection'; + +import BannerSection from '../../views/cleanAirForum/BannerSection'; type CleanAirLayoutProps = { children: ReactNode; diff --git a/src/website2/src/app/clean-air-forum/logistics/page.tsx b/src/website2/src/app/clean-air-forum/logistics/page.tsx index 21bc43015b..784a6e5c2a 100644 --- a/src/website2/src/app/clean-air-forum/logistics/page.tsx +++ b/src/website2/src/app/clean-air-forum/logistics/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import LogisticsPage from '@/views/cleanAirForum/logistics/LogisticsPage'; +import LogisticsPage from '../../../views/cleanAirForum/logistics/LogisticsPage'; export const metadata: Metadata = { title: 'Logistics | Clean Air Forum', diff --git a/src/website2/src/app/clean-air-forum/partners/page.tsx b/src/website2/src/app/clean-air-forum/partners/page.tsx index 8aee8d68e9..104fa88b17 100644 --- a/src/website2/src/app/clean-air-forum/partners/page.tsx +++ b/src/website2/src/app/clean-air-forum/partners/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import PartnersPage from '@/views/cleanAirForum/partners/PartnersPage'; +import PartnersPage from '../../../views/cleanAirForum/partners/PartnersPage'; export const metadata: Metadata = { title: 'Partners | Clean Air Forum | AirQo', diff --git a/src/website2/src/app/clean-air-forum/program-committee/page.tsx b/src/website2/src/app/clean-air-forum/program-committee/page.tsx index c1dd8cfb3f..7ef680fa1c 100644 --- a/src/website2/src/app/clean-air-forum/program-committee/page.tsx +++ b/src/website2/src/app/clean-air-forum/program-committee/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import CommitteePage from '@/views/cleanAirForum/program-committee/CommitteePage'; +import CommitteePage from '../../../views/cleanAirForum/program-committee/CommitteePage'; export const metadata: Metadata = { title: 'Program Committee | Clean Air Forum | AirQo', diff --git a/src/website2/src/app/clean-air-forum/resources/page.tsx b/src/website2/src/app/clean-air-forum/resources/page.tsx index 2a4a1b5831..59c8df2a15 100644 --- a/src/website2/src/app/clean-air-forum/resources/page.tsx +++ b/src/website2/src/app/clean-air-forum/resources/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import ResourcesPage from '@/views/cleanAirForum/resources/ResourcesPage'; +import ResourcesPage from '../../../views/cleanAirForum/resources/ResourcesPage'; export const metadata: Metadata = { title: 'Resources | Clean Air Forum | AirQo', diff --git a/src/website2/src/app/clean-air-forum/sessions/page.tsx b/src/website2/src/app/clean-air-forum/sessions/page.tsx index 24399efeff..0b8e264000 100644 --- a/src/website2/src/app/clean-air-forum/sessions/page.tsx +++ b/src/website2/src/app/clean-air-forum/sessions/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import ProgramsPage from '@/views/cleanAirForum/sessions-programs/ProgramsPage'; +import ProgramsPage from '../../../views/cleanAirForum/sessions-programs/ProgramsPage'; export const metadata: Metadata = { title: 'Sessions & Programs | Clean Air Forum | AirQo', diff --git a/src/website2/src/app/clean-air-forum/speakers/page.tsx b/src/website2/src/app/clean-air-forum/speakers/page.tsx index 8f4891cb02..5caa198994 100644 --- a/src/website2/src/app/clean-air-forum/speakers/page.tsx +++ b/src/website2/src/app/clean-air-forum/speakers/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import SpeakersPage from '@/views/cleanAirForum/speakers/SpeakersPage'; +import SpeakersPage from '../../../views/cleanAirForum/speakers/SpeakersPage'; export const metadata: Metadata = { title: 'Speakers | Clean Air Forum | AirQo', diff --git a/src/website2/src/app/clean-air-forum/sponsorships/page.tsx b/src/website2/src/app/clean-air-forum/sponsorships/page.tsx index 600ae4b8da..6a50f50c3e 100644 --- a/src/website2/src/app/clean-air-forum/sponsorships/page.tsx +++ b/src/website2/src/app/clean-air-forum/sponsorships/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import SponsorshipPage from '@/views/cleanAirForum/sponsorship/SponsorshipPage'; +import SponsorshipPage from '../../../views/cleanAirForum/sponsorship/SponsorshipPage'; export const metadata: Metadata = { title: 'Sponsorship | Clean Air Forum | AirQo', From 9ebacc3aa1ef3e3547c9581a741d1a9ad7a83241 Mon Sep 17 00:00:00 2001 From: Ochieng Paul Date: Fri, 28 Feb 2025 04:05:27 +0300 Subject: [PATCH 17/20] path changes --- src/website2/src/app/clean-air-forum/about/page.tsx | 2 +- src/website2/src/app/clean-air-forum/glossary/page.tsx | 2 +- src/website2/src/app/clean-air-forum/layout.tsx | 2 +- src/website2/src/app/clean-air-forum/logistics/page.tsx | 2 +- src/website2/src/app/clean-air-forum/partners/page.tsx | 2 +- src/website2/src/app/clean-air-forum/program-committee/page.tsx | 2 +- src/website2/src/app/clean-air-forum/resources/page.tsx | 2 +- src/website2/src/app/clean-air-forum/sessions/page.tsx | 2 +- src/website2/src/app/clean-air-forum/speakers/page.tsx | 2 +- src/website2/src/app/clean-air-forum/sponsorships/page.tsx | 2 +- src/website2/src/views/cleanairforum/about/AboutPage.tsx | 2 +- src/website2/src/views/cleanairforum/glossary/GlossaryPage.tsx | 2 +- .../src/views/cleanairforum/logistics/LogisticsPage.tsx | 2 +- src/website2/src/views/cleanairforum/partners/PartnersPage.tsx | 2 +- .../src/views/cleanairforum/program-committee/CommitteePage.tsx | 2 +- .../src/views/cleanairforum/sessions-programs/ProgramsPage.tsx | 2 +- src/website2/src/views/cleanairforum/speakers/SpeakersPage.tsx | 2 +- .../src/views/cleanairforum/sponsorship/SponsorshipPage.tsx | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/website2/src/app/clean-air-forum/about/page.tsx b/src/website2/src/app/clean-air-forum/about/page.tsx index 02b75ed4b2..edb4bd14f0 100644 --- a/src/website2/src/app/clean-air-forum/about/page.tsx +++ b/src/website2/src/app/clean-air-forum/about/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import AboutPage from '../../../views/cleanAirForum/about/AboutPage'; +import AboutPage from '@/views/cleanairforum/about/AboutPage'; export const metadata: Metadata = { title: 'About Clean Air Forum | AirQo', diff --git a/src/website2/src/app/clean-air-forum/glossary/page.tsx b/src/website2/src/app/clean-air-forum/glossary/page.tsx index 82377b7b95..6ee00f95fc 100644 --- a/src/website2/src/app/clean-air-forum/glossary/page.tsx +++ b/src/website2/src/app/clean-air-forum/glossary/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import GlossaryPage from '../../../views/cleanAirForum/glossary/GlossaryPage'; +import GlossaryPage from '@/views/cleanairforum/glossary/GlossaryPage'; export const metadata: Metadata = { title: 'Glossary | Clean Air Forum', diff --git a/src/website2/src/app/clean-air-forum/layout.tsx b/src/website2/src/app/clean-air-forum/layout.tsx index 0a63fc3742..6b1604d5f7 100644 --- a/src/website2/src/app/clean-air-forum/layout.tsx +++ b/src/website2/src/app/clean-air-forum/layout.tsx @@ -12,7 +12,7 @@ import mainConfig from '@/configs/mainConfigs'; import { ForumDataProvider } from '@/context/ForumDataContext'; import { useForumEventDetails, useForumEventTitles } from '@/hooks/useApiHooks'; -import BannerSection from '../../views/cleanAirForum/BannerSection'; +import BannerSection from '../../views/cleanairforum/BannerSection'; type CleanAirLayoutProps = { children: ReactNode; diff --git a/src/website2/src/app/clean-air-forum/logistics/page.tsx b/src/website2/src/app/clean-air-forum/logistics/page.tsx index 784a6e5c2a..a358f9dc32 100644 --- a/src/website2/src/app/clean-air-forum/logistics/page.tsx +++ b/src/website2/src/app/clean-air-forum/logistics/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import LogisticsPage from '../../../views/cleanAirForum/logistics/LogisticsPage'; +import LogisticsPage from '@/views/cleanairforum/logistics/LogisticsPage'; export const metadata: Metadata = { title: 'Logistics | Clean Air Forum', diff --git a/src/website2/src/app/clean-air-forum/partners/page.tsx b/src/website2/src/app/clean-air-forum/partners/page.tsx index 104fa88b17..feffb94e35 100644 --- a/src/website2/src/app/clean-air-forum/partners/page.tsx +++ b/src/website2/src/app/clean-air-forum/partners/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import PartnersPage from '../../../views/cleanAirForum/partners/PartnersPage'; +import PartnersPage from '@/views/cleanairforum/partners/PartnersPage'; export const metadata: Metadata = { title: 'Partners | Clean Air Forum | AirQo', diff --git a/src/website2/src/app/clean-air-forum/program-committee/page.tsx b/src/website2/src/app/clean-air-forum/program-committee/page.tsx index 7ef680fa1c..b594c3c863 100644 --- a/src/website2/src/app/clean-air-forum/program-committee/page.tsx +++ b/src/website2/src/app/clean-air-forum/program-committee/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import CommitteePage from '../../../views/cleanAirForum/program-committee/CommitteePage'; +import CommitteePage from '@/views/cleanairforum/program-committee/CommitteePage'; export const metadata: Metadata = { title: 'Program Committee | Clean Air Forum | AirQo', diff --git a/src/website2/src/app/clean-air-forum/resources/page.tsx b/src/website2/src/app/clean-air-forum/resources/page.tsx index 59c8df2a15..7e848f67e6 100644 --- a/src/website2/src/app/clean-air-forum/resources/page.tsx +++ b/src/website2/src/app/clean-air-forum/resources/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import ResourcesPage from '../../../views/cleanAirForum/resources/ResourcesPage'; +import ResourcesPage from '@/views/cleanairforum/resources/ResourcesPage'; export const metadata: Metadata = { title: 'Resources | Clean Air Forum | AirQo', diff --git a/src/website2/src/app/clean-air-forum/sessions/page.tsx b/src/website2/src/app/clean-air-forum/sessions/page.tsx index 0b8e264000..ecb0a22762 100644 --- a/src/website2/src/app/clean-air-forum/sessions/page.tsx +++ b/src/website2/src/app/clean-air-forum/sessions/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import ProgramsPage from '../../../views/cleanAirForum/sessions-programs/ProgramsPage'; +import ProgramsPage from '@/views/cleanairforum/sessions-programs/ProgramsPage'; export const metadata: Metadata = { title: 'Sessions & Programs | Clean Air Forum | AirQo', diff --git a/src/website2/src/app/clean-air-forum/speakers/page.tsx b/src/website2/src/app/clean-air-forum/speakers/page.tsx index 5caa198994..155bca24e6 100644 --- a/src/website2/src/app/clean-air-forum/speakers/page.tsx +++ b/src/website2/src/app/clean-air-forum/speakers/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import SpeakersPage from '../../../views/cleanAirForum/speakers/SpeakersPage'; +import SpeakersPage from '@/views/cleanairforum/speakers/SpeakersPage'; export const metadata: Metadata = { title: 'Speakers | Clean Air Forum | AirQo', diff --git a/src/website2/src/app/clean-air-forum/sponsorships/page.tsx b/src/website2/src/app/clean-air-forum/sponsorships/page.tsx index 6a50f50c3e..7e3e96f2eb 100644 --- a/src/website2/src/app/clean-air-forum/sponsorships/page.tsx +++ b/src/website2/src/app/clean-air-forum/sponsorships/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; -import SponsorshipPage from '../../../views/cleanAirForum/sponsorship/SponsorshipPage'; +import SponsorshipPage from '@/views/cleanairforum/sponsorship/SponsorshipPage'; export const metadata: Metadata = { title: 'Sponsorship | Clean Air Forum | AirQo', diff --git a/src/website2/src/views/cleanairforum/about/AboutPage.tsx b/src/website2/src/views/cleanairforum/about/AboutPage.tsx index 20741aef14..a8112a636d 100644 --- a/src/website2/src/views/cleanairforum/about/AboutPage.tsx +++ b/src/website2/src/views/cleanairforum/about/AboutPage.tsx @@ -7,7 +7,7 @@ import { Divider, NoData } from '@/components/ui'; import { useForumData } from '@/context/ForumDataContext'; import { isValidHTMLContent } from '@/utils/htmlValidator'; import { renderContent } from '@/utils/quillUtils'; -import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; +import SectionDisplay from '@/views/cleanairforum/SectionDisplay'; type SectionRowProps = { title: string; diff --git a/src/website2/src/views/cleanairforum/glossary/GlossaryPage.tsx b/src/website2/src/views/cleanairforum/glossary/GlossaryPage.tsx index 3535cd32b2..e4a9f3d637 100644 --- a/src/website2/src/views/cleanairforum/glossary/GlossaryPage.tsx +++ b/src/website2/src/views/cleanairforum/glossary/GlossaryPage.tsx @@ -11,7 +11,7 @@ import { useForumData } from '@/context/ForumDataContext'; import { ForumEvent } from '@/types/forum'; import { isValidGlossaryContent } from '@/utils/glossaryValidator'; import { renderContent } from '@/utils/quillUtils'; -import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; +import SectionDisplay from '@/views/cleanairforum/SectionDisplay'; const GlossaryPage = () => { // Access data from the context. diff --git a/src/website2/src/views/cleanairforum/logistics/LogisticsPage.tsx b/src/website2/src/views/cleanairforum/logistics/LogisticsPage.tsx index 25c5f9ee1c..dacaa3a9e1 100644 --- a/src/website2/src/views/cleanairforum/logistics/LogisticsPage.tsx +++ b/src/website2/src/views/cleanairforum/logistics/LogisticsPage.tsx @@ -8,7 +8,7 @@ import { Divider } from '@/components/ui'; import { useForumData } from '@/context/ForumDataContext'; import { isValidHTMLContent } from '@/utils/htmlValidator'; import { renderContent } from '@/utils/quillUtils'; -import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; +import SectionDisplay from '@/views/cleanairforum/SectionDisplay'; const LogisticsPage = () => { // Destructure the selected event from the context. diff --git a/src/website2/src/views/cleanairforum/partners/PartnersPage.tsx b/src/website2/src/views/cleanairforum/partners/PartnersPage.tsx index 0d09769ffe..00a70287b6 100644 --- a/src/website2/src/views/cleanairforum/partners/PartnersPage.tsx +++ b/src/website2/src/views/cleanairforum/partners/PartnersPage.tsx @@ -7,7 +7,7 @@ import { Divider } from '@/components/ui'; import { useForumData } from '@/context/ForumDataContext'; import { isValidHTMLContent } from '@/utils/htmlValidator'; import { renderContent } from '@/utils/quillUtils'; -import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; +import SectionDisplay from '@/views/cleanairforum/SectionDisplay'; import PaginatedSection from '@/views/cleanAirNetwork/PaginatedSection'; const PartnersPage = () => { diff --git a/src/website2/src/views/cleanairforum/program-committee/CommitteePage.tsx b/src/website2/src/views/cleanairforum/program-committee/CommitteePage.tsx index fbd4cf55b4..dae9c51ee7 100644 --- a/src/website2/src/views/cleanairforum/program-committee/CommitteePage.tsx +++ b/src/website2/src/views/cleanairforum/program-committee/CommitteePage.tsx @@ -8,7 +8,7 @@ import { Divider, MemberCard, Pagination } from '@/components/ui/'; import { useForumData } from '@/context/ForumDataContext'; import { isValidHTMLContent } from '@/utils/htmlValidator'; import { renderContent } from '@/utils/quillUtils'; -import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; +import SectionDisplay from '@/views/cleanairforum/SectionDisplay'; const CommitteePage = () => { // Always call useForumData to get the selectedEvent. diff --git a/src/website2/src/views/cleanairforum/sessions-programs/ProgramsPage.tsx b/src/website2/src/views/cleanairforum/sessions-programs/ProgramsPage.tsx index e4e8c3b6fd..904e9cf4b3 100644 --- a/src/website2/src/views/cleanairforum/sessions-programs/ProgramsPage.tsx +++ b/src/website2/src/views/cleanairforum/sessions-programs/ProgramsPage.tsx @@ -9,7 +9,7 @@ import { Divider } from '@/components/ui'; import { useForumData } from '@/context/ForumDataContext'; import { isValidHTMLContent } from '@/utils/htmlValidator'; import { renderContent } from '@/utils/quillUtils'; -import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; +import SectionDisplay from '@/views/cleanairforum/SectionDisplay'; interface AccordionItemProps { title: string; diff --git a/src/website2/src/views/cleanairforum/speakers/SpeakersPage.tsx b/src/website2/src/views/cleanairforum/speakers/SpeakersPage.tsx index 049178a0fa..b39f1a042c 100644 --- a/src/website2/src/views/cleanairforum/speakers/SpeakersPage.tsx +++ b/src/website2/src/views/cleanairforum/speakers/SpeakersPage.tsx @@ -7,7 +7,7 @@ import { Divider, MemberCard, Pagination } from '@/components/ui/'; import { useForumData } from '@/context/ForumDataContext'; import { isValidHTMLContent } from '@/utils/htmlValidator'; import { renderContent } from '@/utils/quillUtils'; -import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; +import SectionDisplay from '@/views/cleanairforum/SectionDisplay'; const SpeakersPage = () => { // Now we use the selectedEvent from context diff --git a/src/website2/src/views/cleanairforum/sponsorship/SponsorshipPage.tsx b/src/website2/src/views/cleanairforum/sponsorship/SponsorshipPage.tsx index 4f87ddef92..397a6e3e79 100644 --- a/src/website2/src/views/cleanairforum/sponsorship/SponsorshipPage.tsx +++ b/src/website2/src/views/cleanairforum/sponsorship/SponsorshipPage.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { Divider } from '@/components/ui'; import { useForumData } from '@/context/ForumDataContext'; import { renderContent } from '@/utils/quillUtils'; -import SectionDisplay from '@/views/cleanAirForum/SectionDisplay'; +import SectionDisplay from '@/views/cleanairforum/SectionDisplay'; import PaginatedSection from '@/views/cleanAirNetwork/PaginatedSection'; const SponsorshipPage = () => { From 3ee5b16917c369ee21049a532d442898c3133ba4 Mon Sep 17 00:00:00 2001 From: Ochieng Paul Date: Fri, 28 Feb 2025 09:52:07 +0300 Subject: [PATCH 18/20] update organization step --- .../src/pages/account/creation/index.jsx | 93 ++++++++++--------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/src/platform/src/pages/account/creation/index.jsx b/src/platform/src/pages/account/creation/index.jsx index 94a428bfc2..51c184a39e 100644 --- a/src/platform/src/pages/account/creation/index.jsx +++ b/src/platform/src/pages/account/creation/index.jsx @@ -4,18 +4,26 @@ import GoogleLogo from '@/icons/Common/google_logo.svg'; import { getGoogleAuthDetails } from '@/core/apis/Account'; import CheckComponent from '@/components/Account/CheckComponent'; +const FORM_URL = 'https://forms.gle/VX5p2s65n8U51iBc8'; + const userRoles = [ { title: 'Individual', subText: 'Empower yourself with real-time Air Pollution Location Data for research and personal use. Stay informed, stay healthy. Join the clean air revolution today.', disabled: false, + // Internal route for individuals. + route: (router) => router.push(`/account/creation/individual/register`), }, { title: 'Organisation', subText: 'Beyond data, gain access to network management tools. Drive meaningful change, one location at a time. Shape a cleaner future for all.', - disabled: true, + disabled: false, + // External route for organisations. + route: () => { + window.location.href = FORM_URL; + }, }, ]; @@ -23,24 +31,27 @@ const UserDesignation = () => { const [clickedRole, setClickedRole] = useState(''); const router = useRouter(); - const routeToCreation = () => { - if (clickedRole) { - router.push(`/account/creation/${clickedRole.toLowerCase()}/register`); - } + const handleRoleClick = (roleTitle, disabled) => { + if (disabled) return; + setClickedRole((prevRole) => (prevRole === roleTitle ? '' : roleTitle)); }; - const handleRoleClick = (roleTitle) => { - setClickedRole((prevRole) => (prevRole === roleTitle ? '' : roleTitle)); + const routeToCreation = () => { + if (!clickedRole) return; + const selectedRole = userRoles.find((role) => role.title === clickedRole); + if (selectedRole && selectedRole.route) { + selectedRole.route(router); + } }; return (
-
+

How are you planning to use AirQo Analytics?

- We'll streamline your setup experience accordingly + We'll streamline your setup experience accordingly

@@ -48,24 +59,18 @@ const UserDesignation = () => {
{ - if (role.disabled) { - return; - } - handleRoleClick(role.title); - }} + role="button" + tabIndex={0} + onClick={() => handleRoleClick(role.title, role.disabled)} onKeyUp={(e) => { if (e.key === 'Enter' || e.key === ' ') { - if (role.disabled) { - return; - } - handleRoleClick(role.title); + handleRoleClick(role.title, role.disabled); } }} > { onClick={routeToCreation} className="mt-6 w-[262px] flex justify-center items-center px-4 py-2 bg-blue-600 text-white rounded-[12px]" > - Continue + {clickedRole === 'Organisation' ? 'Get started' : 'Continue'} )}
@@ -87,31 +92,27 @@ const UserDesignation = () => { ); }; -const GoogleAccountCreation = () => { - return ( -
-
- - Or - -
-
- -
+const GoogleAccountCreation = () => ( +
+
+ + Or +
- ); -}; +
+ +
+
+); export default UserDesignation; From 4482c190a72f8a3222a99d1affc2df5d754a1881 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2025 10:31:59 +0300 Subject: [PATCH 19/20] Update next platform staging image tag to stage-93a63a9e-1740727732 --- k8s/platform/values-stage.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s/platform/values-stage.yaml b/k8s/platform/values-stage.yaml index 3e47349b6c..be349674aa 100644 --- a/k8s/platform/values-stage.yaml +++ b/k8s/platform/values-stage.yaml @@ -2,7 +2,7 @@ replicaCount: 1 image: repository: eu.gcr.io/airqo-250220/airqo-stage-next-platform pullPolicy: Always - tag: stage-6fe6134a-1740558711 + tag: stage-93a63a9e-1740727732 imagePullSecrets: [] nameOverride: '' fullnameOverride: '' From 280275eaafc931ade0dcf35b67f41adc4b8f27e2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2025 10:33:59 +0300 Subject: [PATCH 20/20] Update analytics platform production image tag to prod-6a098ecd-1740727843 --- k8s/platform/values-prod.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s/platform/values-prod.yaml b/k8s/platform/values-prod.yaml index d70a342f35..6043bc5b08 100644 --- a/k8s/platform/values-prod.yaml +++ b/k8s/platform/values-prod.yaml @@ -2,7 +2,7 @@ replicaCount: 1 image: repository: eu.gcr.io/airqo-250220/airqo-next-platform pullPolicy: Always - tag: prod-16e65200-1739133930 + tag: prod-6a098ecd-1740727843 imagePullSecrets: [] nameOverride: '' fullnameOverride: ''