Skip to content

Commit

Permalink
Merge pull request #2460 from airqo-platform/website-clean-air
Browse files Browse the repository at this point in the history
updates UI website
  • Loading branch information
Baalmart authored Feb 13, 2025
2 parents 7e9561c + b01336f commit ea9d158
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 61 deletions.
16 changes: 6 additions & 10 deletions website2/src/app/clean-air-forum/glossary/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React from 'react';

import { Divider } from '@/components/ui';
import { useSelector } from '@/hooks/reduxHooks';
import { isValidGlossaryContent } from '@/utils/glossaryValidator';
import { renderContent } from '@/utils/quillUtils';
import SectionDisplay from '@/views/Forum/SectionDisplay';

Expand All @@ -23,20 +24,15 @@ const Page: React.FC = () => {
return title.split(',')[0].trim().toLowerCase().replace(/\s+/g, '-');
};

// Define what you consider a default "empty" message.
const defaultMessage = 'No details available yet.';

// Render the main glossary content.
const glossaryHTML = renderContent(selectedEvent.glossary_details);
const showGlossaryMain =
glossaryHTML.trim() !== '' && !glossaryHTML.includes(defaultMessage);
const showGlossaryMain = isValidGlossaryContent(glossaryHTML);

// Filter extra sections assigned to the "glossary" page
// and filter out those with no meaningful content.
// Filter extra sections assigned to the "glossary" page.
const glossarySections = selectedEvent.sections?.filter((section: any) => {
if (!section.pages.includes('glossary')) return false;
const sectionHTML = renderContent(section.content);
return sectionHTML.trim() !== '' && !sectionHTML.includes(defaultMessage);
return isValidGlossaryContent(sectionHTML);
});

return (
Expand Down Expand Up @@ -78,15 +74,15 @@ const Page: React.FC = () => {
</div>
</div>

{/* Clear Air Glossary Section */}
{/* Clean Air Glossary Section */}
{showGlossaryMain && (
<>
<Divider className="bg-black p-0 m-0 h-[1px] w-full" />
<div className="flex flex-col md:flex-row md:space-x-8">
{/* Left column: Heading */}
<div className="md:w-1/3 mb-4 md:mb-0">
<h2 className="text-2xl font-bold text-gray-900">
Clear Air Glossary
Clean Air Glossary
</h2>
</div>
{/* Right column: Glossary content */}
Expand Down
17 changes: 8 additions & 9 deletions website2/src/app/clean-air-forum/logistics/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ 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/Forum/SectionDisplay';

Expand All @@ -14,22 +15,20 @@ const LogisticsPage = () => {
return null;
}

// Render static content from the event model
// Render static content from the event model.
const vaccinationHTML = renderContent(
data.travel_logistics_vaccination_details,
);
const visaHTML = renderContent(data.travel_logistics_visa_details);

// Define a default text string that indicates no content.
const defaultMessage = 'No details available yet.';

const showVaccination =
vaccinationHTML.trim() !== '' && !vaccinationHTML.includes(defaultMessage);
const showVisa = visaHTML.trim() !== '' && !visaHTML.includes(defaultMessage);
const showVaccination = isValidHTMLContent(vaccinationHTML);
const showVisa = isValidHTMLContent(visaHTML);

// Filter extra sections assigned to the "logistics" page.
const logisticsSections = data.sections?.filter((section: any) =>
section.pages.includes('logistics'),
const logisticsSections = data.sections?.filter(
(section: any) =>
section.pages.includes('logistics') &&
isValidHTMLContent(renderContent(section.content)),
);

return (
Expand Down
8 changes: 3 additions & 5 deletions website2/src/app/clean-air-forum/partners/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ 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 PaginatedSection from '@/views/cleanairforum/PaginatedSection';
import SectionDisplay from '@/views/Forum/SectionDisplay';

const Page: React.FC = () => {
const data = useForumData();
const defaultMessage = 'No details available yet.';

if (!data) {
return null;
Expand Down Expand Up @@ -47,15 +47,13 @@ const Page: React.FC = () => {

// Check the main partners text section.
const mainPartnersHTML = renderContent(data.partners_text_section);
const showMainPartners =
mainPartnersHTML.trim() !== '' &&
!mainPartnersHTML.includes(defaultMessage);
const showMainPartners = isValidHTMLContent(mainPartnersHTML);

// Filter extra sections assigned to the "partners" page.
const partnersSections = data.sections?.filter((section: any) => {
if (!section.pages.includes('partners')) return false;
const sectionHTML = renderContent(section.content);
return sectionHTML.trim() !== '' && !sectionHTML.includes(defaultMessage);
return isValidHTMLContent(sectionHTML);
});

return (
Expand Down
9 changes: 3 additions & 6 deletions website2/src/app/clean-air-forum/program-committee/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ 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/Forum/SectionDisplay';

const Page: React.FC = () => {
const data = useForumData();
const [currentPage, setCurrentPage] = useState<number>(1);
const membersPerPage = 6;
const defaultMessage = 'No details available yet.';

// Memoize committee members.
const committeeMembers = useMemo(
Expand Down Expand Up @@ -40,18 +40,15 @@ const Page: React.FC = () => {

// Render main committee text.
const committeeHTML = renderContent(data?.committee_text_section || '');
const showCommitteeMain =
committeeHTML.trim() !== '' && !committeeHTML.includes(defaultMessage);
const showCommitteeMain = isValidHTMLContent(committeeHTML);

// Filter extra sections assigned to the "committee" page.
const committeeSections = useMemo(() => {
return (
data?.sections?.filter((section: any) => {
if (!section.pages.includes('committee')) return false;
const sectionHTML = renderContent(section.content);
return (
sectionHTML.trim() !== '' && !sectionHTML.includes(defaultMessage)
);
return isValidHTMLContent(sectionHTML);
}) || []
);
}, [data?.sections]);
Expand Down
32 changes: 17 additions & 15 deletions website2/src/app/clean-air-forum/sessions/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,19 @@ 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';

const AccordionItem: React.FC<any> = ({
interface AccordionItemProps {
title: string;
subText: string;
sessions: any[];
isOpen: boolean;
onToggle: () => void;
}

const AccordionItem: React.FC<AccordionItemProps> = ({
title,
subText,
sessions,
Expand Down Expand Up @@ -71,29 +80,23 @@ const Page: React.FC = () => {
const data = useForumData();
const [openAccordion, setOpenAccordion] = useState<string | null>(null);

// Define a default placeholder text.
const defaultMessage = 'No details available yet.';

if (!data) {
return null;
}

// Render and check schedule_details.
// Render and validate schedule_details.
const scheduleHTML = renderContent(data.schedule_details);
const showSchedule =
scheduleHTML.trim() !== '' && !scheduleHTML.includes(defaultMessage);
const showSchedule = isValidHTMLContent(scheduleHTML);

// Render and check registration_details.
// Render and validate registration_details.
const registrationHTML = renderContent(data.registration_details);
const showRegistration =
registrationHTML.trim() !== '' &&
!registrationHTML.includes(defaultMessage);
const showRegistration = isValidHTMLContent(registrationHTML);

// Filter extra sections assigned to the "session" page.
// Filter extra sections assigned to the "session" page and validate content.
const sessionSections = data?.sections?.filter((section: any) => {
if (!section.pages.includes('session')) return false;
const sectionHTML = renderContent(section.content);
return sectionHTML.trim() !== '' && !sectionHTML.includes(defaultMessage);
return isValidHTMLContent(sectionHTML);
});

const handleToggle = (id: string) => {
Expand Down Expand Up @@ -126,7 +129,6 @@ const Page: React.FC = () => {

{/* Programs Accordion */}
<>
<Divider className="bg-black p-0 m-0 h-[1px] w-full" />
{data.programs?.map((program: any) => (
<AccordionItem
key={program.id}
Expand All @@ -142,7 +144,7 @@ const Page: React.FC = () => {
{/* Registration Section */}
{showRegistration && (
<div>
<Divider className="bg-black p-0 m-0 h-[1px] w-full" />
<Divider className="bg-black p-0 mb-4 h-[1px] w-full" />
<div className="flex flex-col md:flex-row md:space-x-8">
<div className="md:w-1/3 mb-4 md:mb-0">
<h2 className="text-2xl font-bold">Registration</h2>
Expand Down
16 changes: 7 additions & 9 deletions website2/src/app/clean-air-forum/speakers/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ 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 Page: React.FC = () => {
const data = useForumData();
const membersPerPage = 6;
const defaultMessage = 'No details available yet.';

// Separate pagination states for Keynote Speakers and Speakers
// Separate pagination states for Keynote Speakers and Speakers.
const [currentKeyNotePage, setCurrentKeyNotePage] = useState(1);
const [currentSpeakersPage, setCurrentSpeakersPage] = useState(1);

Expand All @@ -33,7 +33,7 @@ const Page: React.FC = () => {
person.category === 'Speaker and Committee Member',
);

// Pagination calculations for keynote speakers.
// Pagination calculations for Keynote Speakers.
const totalKeyNotePages = Math.ceil(KeyNoteSpeakers?.length / membersPerPage);
const startKeyNoteIdx = (currentKeyNotePage - 1) * membersPerPage;
const endKeyNoteIdx = startKeyNoteIdx + membersPerPage;
Expand All @@ -42,7 +42,7 @@ const Page: React.FC = () => {
endKeyNoteIdx,
);

// Pagination calculations for speakers.
// Pagination calculations for Speakers.
const totalSpeakersPages = Math.ceil(Speakers?.length / membersPerPage);
const startSpeakersIdx = (currentSpeakersPage - 1) * membersPerPage;
const endSpeakersIdx = startSpeakersIdx + membersPerPage;
Expand All @@ -54,17 +54,15 @@ const Page: React.FC = () => {
const handleSpeakersPageChange = (newPage: number) =>
setCurrentSpeakersPage(newPage);

// Check main speakers text section.
// Validate the main speakers text section.
const mainSpeakersHTML = renderContent(data.speakers_text_section);
const showMainSpeakers =
mainSpeakersHTML.trim() !== '' &&
!mainSpeakersHTML.includes(defaultMessage);
const showMainSpeakers = isValidHTMLContent(mainSpeakersHTML);

// Filter extra sections assigned to the "speakers" page.
const speakersExtraSections = data?.sections?.filter((section: any) => {
if (!section.pages.includes('speakers')) return false;
const sectionHTML = renderContent(section.content);
return sectionHTML.trim() !== '' && !sectionHTML.includes(defaultMessage);
return isValidHTMLContent(sectionHTML);
});

return (
Expand Down
11 changes: 4 additions & 7 deletions website2/src/app/clean-air-forum/sponsorships/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
'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 PaginatedSection from '@/views/cleanairforum/PaginatedSection';
import SectionDisplay from '@/views/Forum/SectionDisplay';

const SponsorshipPage = () => {
const data = useForumData();
const defaultMessage = 'No details available yet.';

if (!data) {
return null;
Expand All @@ -29,16 +28,14 @@ const SponsorshipPage = () => {
const sponsorshipSections = data.sections?.filter((section: any) => {
if (!section.pages.includes('sponsorships')) return false;
const html = renderContent(section.content);
return html.trim() !== '' && !html.includes(defaultMessage);
return isValidHTMLContent(html);
});

// Check main text section
// Check main text section.
const mainSponsorshipHTML = renderContent(
data.sponsorship_opportunities_partners,
);
const showMainSponsorship =
mainSponsorshipHTML.trim() !== '' &&
!mainSponsorshipHTML.includes(defaultMessage);
const showMainSponsorship = isValidHTMLContent(mainSponsorshipHTML);

return (
<div className="px-4 lg:px-0 flex flex-col gap-6">
Expand Down
31 changes: 31 additions & 0 deletions website2/src/utils/glossaryValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// src/utils/glossaryValidator.ts

/**
* Checks if the provided glossary HTML content is valid for display.
* It removes any empty paragraphs (e.g., <p><br/></p>) and then checks
* if the cleaned content contains any invalid snippets.
*
* @param html The HTML content to validate.
* @returns {boolean} True if valid, false otherwise.
*/
export function isValidGlossaryContent(html: string): boolean {
if (!html) return false;

// Remove empty paragraphs. This regex will remove <p><br/></p> or similar variants.
const cleanedHTML = html.replace(/<p>\s*<br\s*\/?>\s*<\/p>/gi, '').trim();

const invalidSnippets = [
'<p><br/></p>',
'No details available yet.',
'Details coming soon.',
];

// Check if the cleaned HTML contains any of the invalid snippets.
for (const snippet of invalidSnippets) {
if (cleanedHTML === snippet || cleanedHTML.includes(snippet)) {
return false;
}
}

return cleanedHTML.length > 0;
}
30 changes: 30 additions & 0 deletions website2/src/utils/htmlValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// src/utils/htmlValidator.ts

/**
* Checks if the provided HTML content is valid for display.
* It will return false if the content is empty or if it contains any
* unwanted placeholders like '<p><br/></p>', 'No details available yet.', or 'Details coming soon.'.
*
* @param html The HTML content to validate.
* @returns {boolean} True if the content is valid, false otherwise.
*/
export function isValidHTMLContent(html: string): boolean {
const invalidSnippets = [
'<p><br/></p>',
'No details available yet.',
'Details coming soon.',
];

// Trim the HTML to ensure we don't have just whitespace.
const trimmedHTML = html.trim();

if (!trimmedHTML) return false;

// Check if any invalid snippet exists in the HTML.
for (const snippet of invalidSnippets) {
if (trimmedHTML.includes(snippet)) {
return false;
}
}
return true;
}

0 comments on commit ea9d158

Please sign in to comment.