Skip to content

Commit

Permalink
improves lessons feature
Browse files Browse the repository at this point in the history
  • Loading branch information
thehashton committed Aug 26, 2023
1 parent 7db50aa commit 0976622
Show file tree
Hide file tree
Showing 17 changed files with 301 additions and 125 deletions.
23 changes: 21 additions & 2 deletions app/components/CourseCard/CourseCard.module.scss
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
.CourseCard {
position: relative;
display: grid;
max-width: 20rem;
border-radius: 8px;
border-radius: 8px !important;
height: 100%;
width: 100%;
background-size: cover;
background-position: top;
min-height: 15rem;
transition: all 300ms ease-out;

&:hover {
transition: all 300ms ease-in;
transform: scale(1.02);
opacity: 1;
}
}

.courseLink {
display: flex;
justify-content: center;
text-align: center;
text-align: center;
text-decoration: none;
width: 100%;
}

.author {
Expand All @@ -19,4 +32,10 @@
gap: 0.5rem;
padding: 1rem 0 0 0;
margin: 0 !important;
}

.cardImage {
position: relative;
margin: auto;
top: -2rem;
}
33 changes: 22 additions & 11 deletions app/components/CourseCard/CourseCard.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,41 @@
"use client";
import React from "react";
import Link from "next/link";
import { Avatar, Paper, Typography } from "@mui/material";
import scss from "./CourseCard.module.scss";
import Button from "@mui/material/Button";
import Image from "next/image";

export type CourseCardProps = {
key: number;
title: string;
description: string;
courseId: number;
thumbnail: string;
};

const CourseCard = (props: CourseCardProps) => {
const { key, title, description, courseId } = props;
const { title, description, courseId, thumbnail } = props;
return (
<Link
className={scss.courseLink}
href={`/courses/${courseId}`}
style={{ textDecoration: "none", width: "100%" }}
>
<Link className={scss.courseLink} href={`/courses/${courseId}`}>
<Paper
className={scss.CourseCard}
key={key}
variant={"elevation"}
sx={{ p: 2, bgcolor: "background.default" }}
sx={{
p: 2,
backgroundColor: "transparent",
}}
>
<Image
className={scss.cardImage}
src={
thumbnail
? `${process?.env?.NEXT_PUBLIC_STRAPI_IMAGES_DOMAIN}${thumbnail}`
: ""
}
alt={title}
title={description}
width={150}
height={150}
/>
<Typography
fontSize={12}
color={"primary.light"}
Expand All @@ -43,7 +54,7 @@ const CourseCard = (props: CourseCardProps) => {
>
{title}
</Typography>
<Typography fontSize={"medium"}>{description}</Typography>
<Typography fontSize={"small"}>{description}</Typography>
<div className={scss.author} style={{ marginBottom: "1rem" }}>
<Avatar sx={{ height: 34, width: 34 }} />
<Typography fontSize={"small"}>Harry Ashton</Typography>
Expand Down
51 changes: 15 additions & 36 deletions app/components/CourseGrid/CourseGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,30 @@
import React from "react";
import CourseCard from "@/app/components/CourseCard/CourseCard";
import scss from "./CourseGrid.module.scss";
import { CourseDataType } from "@/app/courses/course.types";

export type CourseGridProps = {
courseData: CourseDataType[];
};

export type CourseDataType = {
id: number;
attributes: {
title: string;
description: string;
createdAt: string;
publishedAt: string;
updatedAt: string;
lessons: LessonDataType[];
};
};

export type LessonDataType = {
data: {
id: number;
attributes: {
title: string;
description: string;
duration: string;
video_url: string;
createdAt: string;
publishedAt: string;
updatedAt: string;
};
}[];
};

const CourseGrid = (props: CourseGridProps) => {
const { courseData } = props;
console.log(courseData);
return (
<section className={scss.CourseGrid}>
{courseData.map((course: CourseDataType) => (
<CourseCard
key={course.id}
courseId={course.id}
title={course.attributes.title}
description={course.attributes.description}
/>
))}
{courseData.map((course: CourseDataType, id: number) => {
const thumbnailUrl =
course.attributes?.thumbnail?.data?.attributes?.url;
return (
<div key={course.id}>
<CourseCard
courseId={course.id}
title={course.attributes.title}
thumbnail={thumbnailUrl ? thumbnailUrl : ""}
description={course.attributes.description}
/>
</div>
);
})}
</section>
);
};
Expand Down
15 changes: 15 additions & 0 deletions app/components/CourseList/CourseList.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.CourseList {
padding: 0 !important; // overriding MUI
max-height: 30rem;
overflow: auto;
}

.lessonNavigation {
min-width: 25rem;
}

.listItem {
display: flex;
align-items: center;
margin-right: 0.25rem !important;
}
87 changes: 87 additions & 0 deletions app/components/CourseList/CourseList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React, { useState, useEffect } from "react";
import scss from "./CourseList.module.scss";
import { LessonType } from "@/app/courses/course.types";
import { List, ListItemButton, ListItemText, Typography } from "@mui/material";
import SlowMotionVideoIcon from "@mui/icons-material/SlowMotionVideo";
import { useSearchParams } from "next/navigation";
import { useTheme } from "@mui/material/styles";

export type CourseListProps = {
lessons: LessonType[];
lessonAmount: number;
courseId: number;
};

const CourseList = (props: CourseListProps) => {
const { lessons, lessonAmount, courseId } = props;
const [selectedLessonId, setSelectedLessonId] = useState<number | null>(null);
const searchParams = useSearchParams();
const lessonParamId = searchParams.get("lessonId");
const theme = useTheme(); // Get the MUI theme

useEffect(() => {
// Checks and updates selectedLessonId when lessonParamId changes on page load
setSelectedLessonId(lessonParamId ? parseInt(lessonParamId, 10) : 1);
}, [lessonParamId]);

const handleLessonClick = (lessonId: number) => {
const lessonName = lessons[lessonId - 1]?.attributes.title;
const formattedLessonName = lessonName?.replace(/\s+/g, "");
const newUrl = `/courses/${courseId}?lessonId=${lessonId}&lessonName=${formattedLessonName}`;
window.history.replaceState(null, "", newUrl);
setSelectedLessonId(lessonId);
window.location.reload();
};

return (
<nav className={scss.lessonNavigation}>
<List
className={scss.CourseList}
sx={{
overflowY: "scroll",
"&::-webkit-scrollbar": {
width: "8px",
},
"&::-webkit-scrollbar-thumb": {
backgroundColor: theme.palette.primary.main,
borderRadius: "4px",
},
"&::-webkit-scrollbar-track": {
backgroundColor: theme.palette.background.paper,
},
}}
>
{lessons?.slice(0, lessonAmount).map((lesson: any, id: number) => (
<ListItemButton
key={lesson.id}
className={scss.listItem}
style={{
backgroundColor:
selectedLessonId === lesson.id
? theme.palette.primary.main
: "transparent",
}}
component="a"
onClick={() => handleLessonClick(lesson.id)}
>
<div style={{ textAlign: "center" }}>
<SlowMotionVideoIcon fontSize="large" />
<Typography fontSize={"small"}>
{lesson.attributes.duration}
</Typography>
</div>
<div style={{ marginLeft: "1rem" }}>
<ListItemText
style={{ margin: "0.5rem 0" }}
primary={`${id + 1}. ${lesson.attributes.title}`}
secondary={lesson.attributes.description}
/>
</div>
</ListItemButton>
))}
</List>
</nav>
);
};

export default CourseList;
1 change: 1 addition & 0 deletions app/components/CourseList/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./CourseList";
3 changes: 3 additions & 0 deletions app/components/CoursePlayer/CoursePlayer.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.CoursePlayer {
display: flex;
}
62 changes: 62 additions & 0 deletions app/components/CoursePlayer/CoursePlayer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { useEffect, useState } from "react";
import scss from "./CoursePlayer.module.scss";
import PsychologyAltIcon from "@mui/icons-material/PsychologyAlt";
import { Paper, Typography } from "@mui/material";
import { LessonType } from "@/app/courses/course.types";
import { useSearchParams } from "next/navigation";

export type CoursePlayerProps = {
lessons: LessonType[];
lessonVideoUrl: string;
};

const CoursePlayer = (props: CoursePlayerProps) => {
const { lessons, lessonVideoUrl } = props;

const [selectedLessonId, setSelectedLessonId] = useState<number | null>(null);
const searchParams = useSearchParams();
const lessonParamId = searchParams.get("lessonId");

useEffect(() => {
// Checks and updates selectedLessonId when lessonParamId changes on page load
setSelectedLessonId(lessonParamId ? parseInt(lessonParamId, 10) : null);
}, [lessonParamId]);

return (
<Paper
className={scss.CoursePlayer}
sx={{
display: "flex",
width: "100%",
justifyContent: "center",
alignItems: "center",
minHeight: "30rem",
maxHeight: "30rem",
}}
>
{lessons?.length == 0 || undefined ? (
<div style={{ display: "block", textAlign: "center" }}>
<PsychologyAltIcon
color={"error"}
style={{ fontSize: "5rem" }}
></PsychologyAltIcon>
<Typography>
Oops! There are currently no lessons on this course.
</Typography>
</div>
) : (
<iframe
width="100%"
height="480"
src={lessonVideoUrl}
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
title="Embedded youtube"
/>
)}
</Paper>
);
};

export default CoursePlayer;
1 change: 1 addition & 0 deletions app/components/CoursePlayer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./CoursePlayer";
Loading

0 comments on commit 0976622

Please sign in to comment.