From 225d90e70c9c63c4055debafd13ab10f38afa3aa Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 15 Jan 2026 16:39:33 +0000 Subject: [PATCH] v2 --- .../db/seeders/20231127130745-sample-data.js | 99 ++++++++++++++++++- backend/src/index.js | 2 + backend/src/routes/public.js | 17 ++++ .../components/Courses/PublicCourseCard.tsx | 24 +++++ .../components/Courses/PublicCourseList.tsx | 35 +++++++ frontend/src/pages/index.tsx | 7 ++ 6 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 backend/src/routes/public.js create mode 100644 frontend/src/components/Courses/PublicCourseCard.tsx create mode 100644 frontend/src/components/Courses/PublicCourseList.tsx diff --git a/backend/src/db/seeders/20231127130745-sample-data.js b/backend/src/db/seeders/20231127130745-sample-data.js index 5edbaf1..0e5a8db 100644 --- a/backend/src/db/seeders/20231127130745-sample-data.js +++ b/backend/src/db/seeders/20231127130745-sample-data.js @@ -129,97 +129,188 @@ const CoursesData = [ + + + + "description": "Deep dive into hooks, context, performance optimization, and patterns.", + + + + + + - "status": "archived", + + "status": "published", + + + + + + + // type code here for "relation_one" field + + + + + + + "category": "Web Development", + + + + + + + "price": 79.99, + + + + + + + "duration": 360, + + + + + + + // type code here for "images" field + + + + + + + "published_at": new Date('2025-12-05T09:00:00Z'), + + + + + + + "enrollment_count": 64, + + + + }, + + { + + + + + "title": "UX for Developers", + + + + + + + "description": "Design thinking and practical UX techniques for building better interfaces.", + + + + + + - "status": "archived", + + "status": "published", + + + + + + - // type code here for "relation_one" field - + + // type code here for "relation_one" field diff --git a/backend/src/index.js b/backend/src/index.js index d0a4630..2d51171 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -15,6 +15,7 @@ const authRoutes = require('./routes/auth'); const fileRoutes = require('./routes/file'); const searchRoutes = require('./routes/search'); const pexelsRoutes = require('./routes/pexels'); +const publicRoutes = require('./routes/public'); const openaiRoutes = require('./routes/openai'); @@ -87,6 +88,7 @@ require('./auth/auth'); app.use(bodyParser.json()); app.use('/api/auth', authRoutes); +app.use('/api/public', publicRoutes); app.use('/api/file', fileRoutes); app.use('/api/pexels', pexelsRoutes); app.enable('trust proxy'); diff --git a/backend/src/routes/public.js b/backend/src/routes/public.js new file mode 100644 index 0000000..e256399 --- /dev/null +++ b/backend/src/routes/public.js @@ -0,0 +1,17 @@ +const express = require('express'); +const router = express.Router(); +const CoursesDBApi = require('../db/api/courses'); + +router.get('/courses', async (req, res) => { + try { + const publishedCourses = await CoursesDBApi.findAll({ + where: { status: 'published' }, + }); + res.json(publishedCourses); + } catch (error) { + console.error(error); + res.status(500).send('Internal Server Error'); + } +}); + +module.exports = router; \ No newline at end of file diff --git a/frontend/src/components/Courses/PublicCourseCard.tsx b/frontend/src/components/Courses/PublicCourseCard.tsx new file mode 100644 index 0000000..4a7c493 --- /dev/null +++ b/frontend/src/components/Courses/PublicCourseCard.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import ImageField from '../ImageField'; +import Link from 'next/link'; + +type Props = { + course: any; +}; + +const PublicCourseCard = ({ course }: Props) => { + return ( +
  • + + +

    {course.title}

    + +
  • + ); +}; + +export default PublicCourseCard; diff --git a/frontend/src/components/Courses/PublicCourseList.tsx b/frontend/src/components/Courses/PublicCourseList.tsx new file mode 100644 index 0000000..d3afec0 --- /dev/null +++ b/frontend/src/components/Courses/PublicCourseList.tsx @@ -0,0 +1,35 @@ +import React, { useEffect, useState } from 'react'; +import axios from 'axios'; +import PublicCourseCard from './PublicCourseCard'; +import LoadingSpinner from '../LoadingSpinner'; + +const PublicCourseList = () => { + const [courses, setCourses] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + axios + .get('/public/courses') + .then((res) => { + setCourses(res.data.rows); + setLoading(false); + }) + .catch((err) => { + console.error(err); + setLoading(false); + }); + }, []); + + return ( +
    +

    Our Courses

    + {loading && } +
      + {!loading && + courses.map((course) => )} +
    +
    + ); +}; + +export default PublicCourseList; diff --git a/frontend/src/pages/index.tsx b/frontend/src/pages/index.tsx index 36ff6fb..6ada819 100644 --- a/frontend/src/pages/index.tsx +++ b/frontend/src/pages/index.tsx @@ -16,6 +16,7 @@ import { mdiLinkedin, } from '@mdi/js' import BaseIcon from '../components/BaseIcon' +import PublicCourseList from '../components/Courses/PublicCourseList' export default function Landing() { const textColor = useAppSelector((state) => state.style.linkColor) @@ -94,6 +95,12 @@ export default function Landing() { +
    +
    + +
    +
    +