Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Website: Include site manifest files and fix on clean air forum sessions #2539

Merged
merged 10 commits into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/website2/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,21 @@ const nextConfig = {
destination: '/clean-air-forum/about',
permanent: true,
},
{
source: '/clean-air-network',
destination: '/clean-air-network/about',
permanent: true,
},
{
source: '/clean-air/about',
destination: '/clean-air-network/about',
permanent: true,
},
{
source: '/clean-air',
destination: '/clean-air-network/about',
permanent: true,
},
];
},
};
Expand Down
Binary file added src/website2/public/Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/website2/public/apple-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/website2/public/assets/icons/Icon1.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// components/icons/Icon1.tsx

import React from 'react';

interface IconProps {
Expand Down
2 changes: 1 addition & 1 deletion src/website2/public/assets/icons/Icon2.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// components/icons/Icon2.tsx

import React from 'react';

interface IconProps {
Expand Down
2 changes: 1 addition & 1 deletion src/website2/public/assets/icons/Icon3.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// components/icons/Icon3.tsx

import React from 'react';

interface IconProps {
Expand Down
2 changes: 1 addition & 1 deletion src/website2/public/assets/icons/Icon4.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// components/icons/Icon4.tsx

import React from 'react';

interface IconProps {
Expand Down
2 changes: 1 addition & 1 deletion src/website2/public/assets/icons/Icon5.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// components/icons/Icon5.tsx

import React from 'react';

interface IconProps {
Expand Down
2 changes: 1 addition & 1 deletion src/website2/public/assets/icons/Icon6.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// components/icons/Icon6.tsx

import React from 'react';

interface IconProps {
Expand Down
2 changes: 1 addition & 1 deletion src/website2/public/assets/icons/Icon7.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// components/icons/Icon6.tsx

import React from 'react';

interface IconProps {
Expand Down
2 changes: 1 addition & 1 deletion src/website2/public/assets/icons/Icon8.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// components/icons/Icon6.tsx

import React from 'react';

interface IconProps {
Expand Down
Binary file added src/website2/public/favicon.ico
Binary file not shown.
Binary file added src/website2/public/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/website2/public/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions src/website2/public/manifest.json
Original file line number Diff line number Diff line change
@@ -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"
}
Binary file added src/website2/public/web-app-manifest-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/website2/public/web-app-manifest-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 10 additions & 4 deletions src/website2/src/app/clean-air-forum/about/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import React from 'react';
import { Metadata } from 'next';

import AboutPage from '@/views/Forum/AboutPage';
import AboutPage from '@/views/cleanAirForum/about/AboutPage';

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix import path case sensitivity.

The import path is causing a build failure due to case sensitivity issues.

-import AboutPage from '@/views/cleanAirForum/about/AboutPage';
+import AboutPage from '@/views/cleanairforum/about/AboutPage';

The pipeline failure indicates that the module cannot be resolved. The actual directory path uses lowercase 'cleanairforum' rather than the camelCase 'cleanAirForum' in your import.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import AboutPage from '@/views/cleanAirForum/about/AboutPage';
import AboutPage from '@/views/cleanairforum/about/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 (
<div>
<AboutPage />
</div>
);
};

export default page;
export default Page;
120 changes: 10 additions & 110 deletions src/website2/src/app/clean-air-forum/glossary/page.tsx
Original file line number Diff line number Diff line change
@@ -1,115 +1,15 @@
'use client';
import { Metadata } from 'next';

import DOMPurify from 'dompurify';
import Link from 'next/link';
import React from 'react';
import GlossaryPage from '@/views/cleanAirForum/glossary/GlossaryPage';

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/Forum/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 <Loading />;
}

// 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 <NoData message="No events found" />;
}

// 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 (
<div className="px-4 lg:px-0 prose max-w-none flex flex-col gap-6">
<Divider className="bg-black p-0 m-0 h-[1px] w-full" />

{/* Clean Air Forum Events Section (Sidebar) */}
<div className="flex flex-col md:flex-row py-6 md:space-x-8">
{/* Left column: Heading */}
<div className="md:w-1/3 mb-4 md:mb-0">
<h1 className="text-2xl mt-4 font-semibold">
Clean Air Forum Events
</h1>
</div>
{/* Right column: List of event links */}
<div className="md:w-2/3">
<ul className="space-y-2">
{eventsList.map((event) => {
// Use the unique_title directly in the link.
const href = `/clean-air-forum/about?slug=${encodeURIComponent(
event.unique_title,
)}`;
return (
<li key={event.id}>
<Link
href={href}
target="_blank"
className="text-blue-600 hover:underline"
>
{event.title}
</Link>
</li>
);
})}
</ul>
</div>
</div>

{/* Clean Air Glossary Section */}
{showGlossaryMain && (
<>
<Divider className="bg-black p-0 m-0 h-[1px] w-full" />
<div className="flex flex-col py-6 md:flex-row md:space-x-8">
{/* Left column: Heading */}
<div className="md:w-1/3 mb-4 md:mb-0">
<h1 className="text-2xl mt-4 font-bold text-gray-900">
Clean Air Glossary
</h1>
</div>
{/* Right column: Glossary content */}
<div
className="md:w-2/3"
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(glossaryHTML),
}}
></div>
</div>
</>
)}
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.',
};

{/* Additional Glossary Sections (if any) */}
{glossarySections && glossarySections.length > 0 && (
<>
{glossarySections.map((section: any) => (
<SectionDisplay key={section.id} section={section} />
))}
</>
)}
</div>
);
const Page = () => {
return <GlossaryPage />;
};

export default GlossaryPage;
export default Page;
3 changes: 1 addition & 2 deletions src/website2/src/app/clean-air-forum/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// components/layouts/CleanAirLayout.tsx
'use client';

import { useSearchParams } from 'next/navigation';
Expand All @@ -12,7 +11,7 @@ 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/Forum/BannerSection';
import BannerSection from '@/views/cleanAirForum/BannerSection';

type CleanAirLayoutProps = {
children: ReactNode;
Expand Down
101 changes: 10 additions & 91 deletions src/website2/src/app/clean-air-forum/logistics/page.tsx
Original file line number Diff line number Diff line change
@@ -1,96 +1,15 @@
'use client';
import { Metadata } from 'next';

import DOMPurify from 'dompurify';
import React from 'react';
import LogisticsPage from '@/views/cleanAirForum/logistics/LogisticsPage';

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix the import path for LogisticsPage component.

The build pipeline is failing because it cannot find the LogisticsPage component. There appears to be a case sensitivity issue in the import path.

-import LogisticsPage from '@/views/cleanAirForum/logistics/LogisticsPage';
+import LogisticsPage from '@/views/cleanairforum/logistics/LogisticsPage';

Note: Ensure that the component actually exists at this path. If it doesn't, you'll need to create it first.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import LogisticsPage from '@/views/cleanAirForum/logistics/LogisticsPage';
import LogisticsPage from '@/views/cleanairforum/logistics/LogisticsPage';

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/Forum/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 <Loading />;
}

// 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 (
<div className="px-4 prose max-w-none lg:px-0">
{/* Render Vaccination Section if content exists */}
{showVaccination && (
<>
<Divider className="bg-black p-0 m-0 h-[1px] w-full" />
<div className="py-6">
<div className="flex flex-col md:flex-row md:space-x-8">
<div className="md:w-1/3 mb-4 md:mb-0">
<h1 className="text-2xl mt-4 font-bold text-gray-900">
Vaccination
</h1>
</div>
<div
className="md:w-2/3 space-y-4"
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(vaccinationHTML),
}}
/>
</div>
</div>
</>
)}

{/* Render Visa Invitation Letter Section if content exists */}
{showVisa && (
<>
<Divider className="bg-black p-0 m-0 h-[1px] w-full" />
<div className="py-6">
<div className="flex flex-col md:flex-row md:space-x-8">
<div className="md:w-1/3 mb-4 md:mb-0">
<h1 className="text-2xl mt-4 font-bold text-gray-900">
Visa invitation letter
</h1>
</div>
<div
className="md:w-2/3 space-y-4"
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(visaHTML),
}}
/>
</div>
</div>
</>
)}
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.',
};

{/* Render additional Logistics Sections, if any */}
{logisticsSections && logisticsSections.length > 0 && (
<>
{logisticsSections.map((section: any) => (
<SectionDisplay key={section.id} section={section} />
))}
</>
)}
</div>
);
const Page = () => {
return <LogisticsPage />;
};

export default LogisticsPage;
export default Page;
Loading
Loading