Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad1a5d4ba5 | ||
|
|
d75bcd4f00 | ||
|
|
f1670e105f |
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,3 +1,8 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
*/node_modules/
|
*/node_modules/
|
||||||
*/build/
|
*/build/
|
||||||
|
|
||||||
|
**/node_modules/
|
||||||
|
**/build/
|
||||||
|
.DS_Store
|
||||||
|
.env
|
||||||
File diff suppressed because one or more lines are too long
1
frontend/json/runtimeError.json
Normal file
1
frontend/json/runtimeError.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@ -50,6 +50,16 @@ const nextConfig = {
|
|||||||
source: '/about',
|
source: '/about',
|
||||||
destination: '/web_pages/about',
|
destination: '/web_pages/about',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
source: '/courses',
|
||||||
|
destination: '/web_pages/courses',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
source: '/courses/:id',
|
||||||
|
destination: '/web_pages/courses/:id',
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
41
frontend/src/components/Courses/CoursesPageCard.tsx
Normal file
41
frontend/src/components/Courses/CoursesPageCard.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
interface CoursesPageCardProps {
|
||||||
|
courses: Array<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CoursesPageCard: React.FC<CoursesPageCardProps> = ({ courses }) => {
|
||||||
|
return (
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{courses.map((course) => (
|
||||||
|
<div
|
||||||
|
key={course.id}
|
||||||
|
className="bg-white shadow-md rounded-lg overflow-hidden hover:shadow-lg transition-shadow duration-200"
|
||||||
|
>
|
||||||
|
{course.imageUrl && (
|
||||||
|
<img
|
||||||
|
src={course.imageUrl}
|
||||||
|
alt={course.title}
|
||||||
|
className="w-full h-48 object-cover"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<div className="p-4">
|
||||||
|
<h3 className="text-lg font-semibold mb-2">{course.title}</h3>
|
||||||
|
<p
|
||||||
|
className="text-gray-600 text-sm mb-4 overflow-hidden"
|
||||||
|
style={{ WebkitLineClamp: '2', display: '-webkit-box', WebkitBoxOrient: 'vertical' }}
|
||||||
|
>
|
||||||
|
{course.description}
|
||||||
|
</p>
|
||||||
|
<Link href={`/courses/${course.id}`} className="inline-block bg-indigo-600 text-white px-4 py-2 rounded hover:bg-indigo-700">
|
||||||
|
View Details
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CoursesPageCard;
|
||||||
@ -67,6 +67,11 @@ export const webPagesNavBar = [
|
|||||||
href: '/about',
|
href: '/about',
|
||||||
label: 'about',
|
label: 'about',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
href: '/courses',
|
||||||
|
label: 'courses',
|
||||||
|
},
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export default menuNavBar;
|
export default menuNavBar;
|
||||||
|
|||||||
47
frontend/src/pages/web_pages/courses.tsx
Normal file
47
frontend/src/pages/web_pages/courses.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import React, { ReactElement, useState, useEffect } from 'react';
|
||||||
|
import Head from 'next/head';
|
||||||
|
import LayoutGuest from '../../layouts/Guest';
|
||||||
|
import WebSiteHeader from '../../components/WebPageComponents/Header';
|
||||||
|
import WebSiteFooter from '../../components/WebPageComponents/Footer';
|
||||||
|
import axios from 'axios';
|
||||||
|
import CoursesPageCard from '../../components/Courses/CoursesPageCard';
|
||||||
|
|
||||||
|
export default function CoursesPage() {
|
||||||
|
const projectName = 'test i18';
|
||||||
|
|
||||||
|
const [courses, setCourses] = useState<any[]>([]);
|
||||||
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
axios
|
||||||
|
.get('courses')
|
||||||
|
.then((res) => setCourses(res.data.rows))
|
||||||
|
.catch((err) => console.error(err))
|
||||||
|
.finally(() => setLoading(false));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<title>Courses - {projectName}</title>
|
||||||
|
<meta name="description" content="Courses page." />
|
||||||
|
</Head>
|
||||||
|
|
||||||
|
<WebSiteHeader projectName={projectName} />
|
||||||
|
|
||||||
|
<main className="flex-grow p-8">
|
||||||
|
{loading ? (
|
||||||
|
<p>Loading courses...</p>
|
||||||
|
) : (
|
||||||
|
<CoursesPageCard courses={courses} />
|
||||||
|
)}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<WebSiteFooter projectName={projectName} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
CoursesPage.getLayout = function getLayout(page: ReactElement) {
|
||||||
|
return <LayoutGuest>{page}</LayoutGuest>;
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user