-
-
Notifications
You must be signed in to change notification settings - Fork 171
Course landing page #1077
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
Course landing page #1077
Changes from 4 commits
af4e914
80532a8
fd5aa0e
98e9e3f
f619a8f
dc4d730
b720297
78c0cb8
1b77104
d2e2f81
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,24 +1,20 @@ | ||
| "use client"; | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This file was meant to be kept as an example. I don't think I was clear enough in the issue so that's my fault. But it is meant to be in |
||
| import { type Session } from "next-auth"; | ||
| import { notFound } from "next/navigation"; | ||
| import { isFlagEnabled, FEATURE_FLAGS } from "@/utils/flags"; | ||
| import CoursesLanding from "@/components/Course"; | ||
|
|
||
| const Content = ({ session }: { session: Session | null }) => { | ||
| const flagEnabled = isFlagEnabled(FEATURE_FLAGS.FEATURE_FLAG_TEST); | ||
| const flagEnabled = isFlagEnabled(FEATURE_FLAGS.COURSES_LANDING); // Adjust to the correct flag | ||
|
|
||
| if (!flagEnabled) { | ||
| notFound(); | ||
| notFound(); // Show 404 page if the feature flag is not enabled | ||
| } | ||
|
|
||
| return ( | ||
| <div className="mx-auto max-w-2xl"> | ||
| <h1 className="text-lg"> | ||
| This page is behind a feature flag. It will work in development or when | ||
| the flag is turned on. | ||
| </h1> | ||
| <p className="mt-8 text-sm"> | ||
| {session ? "User is logged in" : "User is not logged in"} | ||
| </p> | ||
| <div className="mx-auto max-w-6xl"> | ||
| <CoursesLanding session={session} /> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,11 +2,11 @@ import Content from "./_client"; | |
| import { getServerAuthSession } from "@/server/auth"; | ||
|
|
||
| export const metadata = { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again this should be in the /courses path |
||
| title: "This is a feature flag example", | ||
| title: "Courses Landing Page", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inconsistency between page title and file path The metadata title has been updated to "Courses Landing Page", which aligns with the PR objectives. However, the file is still located in the Consider moving this file to a more appropriate location, such as |
||
| }; | ||
|
|
||
| export default async function Page() { | ||
| // Example of grabbing session in case it is needed | ||
| export default async function CoursesPage() { | ||
| // Get session if needed for authentication purposes | ||
| const session = await getServerAuthSession(); | ||
|
|
||
| return <Content session={session} />; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
|
|
||
| import React from "react"; | ||
| import { Course } from "./type"; | ||
|
|
||
| interface CourseCardProps { | ||
| course: Course; | ||
| onStartCourse: (courseId: number) => void; // Change to number to match your mock data | ||
| } | ||
|
|
||
| const CourseCard: React.FC<CourseCardProps> = ({ course, onStartCourse }) => { | ||
| return ( | ||
| <div | ||
| className={`rounded-lg p-6 shadow-md ${course.featured ? "bg-orange-100 dark:bg-orange-900" : "bg-gray-100 dark:bg-gray-800"}`} | ||
| > | ||
| {/* Course Title */} | ||
| <h2 className="mb-4 text-2xl font-bold">{course.title}</h2> | ||
|
|
||
| {/* Course Description */} | ||
| <p className="mb-4 text-lg text-gray-700 dark:text-gray-300"> | ||
| {course.description} | ||
| </p> | ||
|
|
||
| {/* Course Progress */} | ||
| <div className="flex items-center gap-4"> | ||
| <p className="text-lg">Progress:</p> | ||
| <div className="flex h-16 w-16 items-center justify-center rounded-full bg-pink-500 text-lg font-bold"> | ||
| {course.progress}% | ||
| </div> | ||
| </div> | ||
|
|
||
| {/* Start Course Button */} | ||
| <button | ||
| className="mt-4 rounded bg-orange-500 px-4 py-2 text-white hover:bg-orange-600" | ||
| onClick={() => onStartCourse(Number(course.id))} // Call the passed function with course ID | ||
| > | ||
| Start Course | ||
| </button> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default CourseCard; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
|
|
||
| import React from "react"; | ||
| import { mockCourses, userProgress } from "./mock"; | ||
| import CourseCard from "./CourseCard"; | ||
| import { type Session } from "next-auth"; | ||
|
|
||
| const CoursesLanding = ({ session }: { session: Session | null }) => { | ||
| const handleStartCourse = (courseId: number) => { | ||
| console.log(`Starting course with ID: ${courseId}`); | ||
| // Add logic here to navigate to the course content page or start the course | ||
| }; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implement navigation logic for course start. The
Would you like assistance in implementing this navigation logic or creating a GitHub issue to track this task? |
||
|
|
||
| return ( | ||
| <div className="flex min-h-screen flex-col gap-8 px-4 py-8 dark:bg-gray-900 dark:text-white lg:px-16 lg:py-12"> | ||
| {/* Page Title */} | ||
| <h1 className="mb-6 text-3xl font-bold lg:text-4xl">Courses</h1> | ||
|
|
||
| {/* Courses List */} | ||
| <div className="grid grid-cols-1 gap-8 lg:grid-cols-2"> | ||
| {mockCourses.map((course) => ( | ||
| <CourseCard | ||
| key={course.id} | ||
| course={course} | ||
| onStartCourse={handleStartCourse} | ||
| /> | ||
| ))} | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default CoursesLanding; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| import { Course } from "./type"; | ||
|
|
||
| export const mockCourses: Course[] = [ | ||
| { | ||
| id: "1", | ||
| title: "Introduction to Web Development", | ||
| description: | ||
| "Learn the basics of HTML, CSS, and JavaScript to build responsive websites.", | ||
| progress: 90, | ||
| featured: true, | ||
| }, | ||
| { | ||
| id: "2", | ||
| title: "Advanced JavaScript Concepts", | ||
| description: | ||
| "Deep dive into JavaScript with advanced concepts and techniques.", | ||
| progress: 65, | ||
| featured: false, | ||
| }, | ||
| { | ||
| id: "3", | ||
| title: "React for Beginners", | ||
| description: "Get started with React and build interactive UIs.", | ||
| progress: 30, | ||
| featured: false, | ||
| }, | ||
| { | ||
| id: "4", | ||
| title: "Full-Stack Web Development", | ||
| description: | ||
| "Become a full-stack developer by learning both front-end and back-end technologies.", | ||
| progress: 45, | ||
| featured: true, | ||
| }, | ||
| { | ||
| id: "5", | ||
| title: "Version Control with Git and GitHub", | ||
| description: | ||
| "Learn how to use Git for version control and GitHub for collaboration.", | ||
| progress: 80, | ||
| featured: false, | ||
| }, | ||
| ]; | ||
|
|
||
| // Function to generate user progress from courses | ||
| export const generateUserProgress = (courses: Course[]) => ({ | ||
| coursesProgress: courses.map((course) => ({ | ||
| courseId: course.id, | ||
| progress: course.progress, | ||
| featured: course.featured, | ||
| })), | ||
| }); | ||
|
|
||
| export const userProgress = generateUserProgress(mockCourses); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| export interface Course { | ||
| id: string; | ||
| title: string; | ||
| description: string; | ||
| progress: number; | ||
| featured: boolean; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ import { posthog } from "posthog-js"; | |
|
|
||
| export const FEATURE_FLAGS = { | ||
| FEATURE_FLAG_TEST: "feature-flag-test", | ||
| // Add more feature flags as needed | ||
| COURSES_LANDING: "courses-landing", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is perfect! Thanks |
||
| } as const; | ||
|
|
||
| export type FeatureFlagName = | ||
|
|
@@ -17,11 +17,11 @@ export function isDevEnvironment() { | |
|
|
||
| export const isFlagEnabled = ( | ||
| featureFlag: FeatureFlagName, | ||
| disableDevCheck = false, // Disable dev check to force feature flag to be checked always | ||
| disableDevCheck = false, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add back in the comment here as it's a note to developer |
||
| ) => { | ||
| if (!disableDevCheck && isDevEnvironment()) { | ||
| console.log("Feature flag check skipped in development environment"); | ||
| return true; | ||
| return true; // Always true in dev environments unless you want to test differently | ||
| } | ||
| return posthog.isFeatureEnabled(featureFlag); | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole folder should have been left where it was an untouched. It is just to use as an example to show how to do feature flags.