Skip to content

Commit f11ce8f

Browse files
author
proghead00
committed
first commit
0 parents  commit f11ce8f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+21819
-0
lines changed

client/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.next
2+
node_modules
3+
.env.local

client/components/TopNav.js

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import { useState, useEffect, useContext } from "react";
2+
import { Menu } from "antd";
3+
import Link from "next/link";
4+
import {
5+
AppstoreOutlined,
6+
CoffeeOutlined,
7+
LoginOutlined,
8+
LogoutOutlined,
9+
ProfileOutlined,
10+
UserAddOutlined,
11+
CarryOutOutlined,
12+
TeamOutlined,
13+
} from "@ant-design/icons";
14+
import { Context } from "../context";
15+
import axios from "axios";
16+
import { useRouter } from "next/router";
17+
import { toast } from "react-toastify";
18+
19+
const { Item, SubMenu, ItemGroup } = Menu;
20+
21+
const TopNav = () => {
22+
const [current, setCurrent] = useState("");
23+
24+
const { state, dispatch } = useContext(Context);
25+
const { user } = state;
26+
27+
const router = useRouter();
28+
29+
useEffect(() => {
30+
process.browser && setCurrent(window.location.pathname);
31+
}, [process.browser && window.location.pathname]);
32+
33+
const logout = async () => {
34+
dispatch({ type: "LOGOUT" });
35+
window.localStorage.removeItem("user");
36+
const { data } = await axios.get("/api/logout");
37+
toast(data.message);
38+
router.push("/login");
39+
};
40+
41+
return (
42+
<Menu
43+
// theme="dark"
44+
mode="horizontal"
45+
selectedKeys={[current]}
46+
className="mb-2"
47+
>
48+
<Item
49+
key="/"
50+
onClick={(e) => setCurrent(e.key)}
51+
icon={<AppstoreOutlined />}
52+
>
53+
<Link href="/">
54+
<a style={{ fontFamily: "MuseoSans" }}>Home</a>
55+
</Link>
56+
</Item>
57+
58+
{user && user.role && user.role.includes("Instructor") ? (
59+
<Item
60+
key="/instructor/course/create"
61+
onClick={(e) => setCurrent(e.key)}
62+
icon={<CarryOutOutlined />}
63+
>
64+
<Link href="/instructor/course/create">
65+
<a style={{ fontFamily: "MuseoSans" }}>Create course</a>
66+
</Link>
67+
</Item>
68+
) : (
69+
<Item
70+
key="/user/become-instructor"
71+
onClick={(e) => setCurrent(e.key)}
72+
icon={<TeamOutlined />}
73+
>
74+
<Link href="/user/become-instructor">
75+
<a>Become an instructor</a>
76+
</Link>
77+
</Item>
78+
)}
79+
80+
{user === null && (
81+
<>
82+
<Item
83+
key="/login"
84+
onClick={(e) => setCurrent(e.key)}
85+
icon={<LoginOutlined />}
86+
>
87+
<Link href="/login">
88+
<a>Login</a>
89+
</Link>
90+
</Item>
91+
92+
<Item
93+
key="/register"
94+
onClick={(e) => setCurrent(e.key)}
95+
icon={<UserAddOutlined />}
96+
>
97+
<Link href="/register">
98+
<a>Register</a>
99+
</Link>
100+
</Item>
101+
</>
102+
)}
103+
{user !== null && (
104+
<SubMenu
105+
style={{ fontFamily: "MuseoSans" }}
106+
icon={<CoffeeOutlined />}
107+
title={user && user.name}
108+
className="float-right"
109+
>
110+
<ItemGroup>
111+
<Item
112+
key="/user"
113+
icon={<ProfileOutlined />}
114+
title={user && user.name}
115+
className="float-right"
116+
>
117+
<Link href="/user">
118+
<a style={{ fontFamily: "MuseoSans" }}> Dashboard </a>
119+
</Link>
120+
</Item>
121+
<Item
122+
onClick={logout}
123+
icon={<LogoutOutlined />}
124+
className="float-right"
125+
style={{ fontFamily: "MuseoSans" }}
126+
>
127+
Logout
128+
</Item>
129+
</ItemGroup>
130+
</SubMenu>
131+
)}
132+
133+
{user && user.role && user.role.includes("Instructor") && (
134+
<Item
135+
key="/instructor"
136+
onClick={(e) => setCurrent(e.key)}
137+
icon={<TeamOutlined />}
138+
className="float-right"
139+
>
140+
<Link href="/instructor">
141+
<a style={{ fontFamily: "MuseoSans" }}>Instructor</a>
142+
</Link>
143+
</Item>
144+
)}
145+
</Menu>
146+
);
147+
};
148+
149+
export default TopNav;

client/components/cards/CourseCard.js

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Card, Badge } from "antd";
2+
import Link from "next/link";
3+
import { currencyFormatter } from "../../utils/helpers";
4+
5+
const { Meta } = Card;
6+
7+
const CourseCard = ({ course }) => {
8+
const { name, instructor, price, image, slug, paid, category } = course;
9+
return (
10+
<Link href={`/course/${slug}`}>
11+
<a>
12+
<Card
13+
className="mb-4 cardsie"
14+
cover={
15+
<img
16+
src={image.Location}
17+
alt={name}
18+
style={{
19+
height: "300px",
20+
objectFit: "cover",
21+
borderRadius: "11px",
22+
}}
23+
className="p-1"
24+
></img>
25+
}
26+
>
27+
<h2>{name}</h2>
28+
<p>by {instructor.name}</p>
29+
30+
<Badge
31+
count={category}
32+
style={{
33+
backgroundColor: "#4c4177",
34+
backgroundImage:
35+
" linear-gradient(315deg, #4c4177 0%, #2a5470 74%);",
36+
}}
37+
className="pb-2 mr-2"
38+
/>
39+
<h4 className="pt-2">
40+
{paid
41+
? currencyFormatter({
42+
amount: price,
43+
// currency: "inr",
44+
})
45+
: "Free"}
46+
</h4>
47+
</Card>
48+
</a>
49+
</Link>
50+
);
51+
};
52+
53+
export default CourseCard;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import SingleCourse from "../../pages/course/[slug]";
2+
import { currencyFormatter } from "../../utils/helpers";
3+
import { Badge, Modal, Button } from "antd";
4+
import ReactPlayer from "react-player";
5+
import { LoadingOutlined, SafetyOutlined } from "@ant-design/icons";
6+
7+
const SingleCourseJumbotron = ({
8+
course,
9+
showModal,
10+
setShowModal,
11+
preview,
12+
setPreview,
13+
loading,
14+
user,
15+
handlePaidEnrollment,
16+
handleFreeEnrollment,
17+
enrolled,
18+
setEnrolled,
19+
}) => {
20+
// destructure
21+
const {
22+
name,
23+
description,
24+
instructor,
25+
updatedAt,
26+
lessons,
27+
image,
28+
price,
29+
paid,
30+
category,
31+
} = course;
32+
33+
return (
34+
<div className="jumbotron bg-primary square">
35+
<div className="row">
36+
<div className="col-md-8">
37+
{/* title */}
38+
<h1>{name}</h1>
39+
{/* description */}
40+
<p className="lead">
41+
{description && description.substring(0, description.length - 1)}
42+
</p>
43+
{/* category */}
44+
<Badge
45+
count={category}
46+
style={{ backgroundColor: "#03a9f4" }}
47+
className="pb-4 mr-2"
48+
/>
49+
50+
{/* author */}
51+
<p className="namep">Created by {instructor.name}</p>
52+
{/* updated at */}
53+
<p>Last udpated {new Date(updatedAt).toLocaleDateString()}</p>
54+
{/* price */}
55+
<div className="price-det">
56+
<h4 className="pprice">
57+
{paid
58+
? currencyFormatter({
59+
amount: price,
60+
currency: "usd",
61+
})
62+
: "Free"}
63+
</h4>
64+
</div>
65+
</div>
66+
<div className="col-md-4">
67+
{/* {JSON.stringify(lessons[0])} */}
68+
{/* show video preview or course image */}
69+
{lessons[0].video && lessons[0].video.Location ? (
70+
<div
71+
onClick={() => {
72+
setPreview(lessons[0].video.Location);
73+
setShowModal(!showModal);
74+
}}
75+
>
76+
<ReactPlayer
77+
className="react-player-div"
78+
url={lessons[0].video.Location}
79+
light={image.Location}
80+
width="100%"
81+
height="300px"
82+
/>
83+
</div>
84+
) : (
85+
<>
86+
<img src={image.Location} alt={name} className="img img-fluid" />
87+
</>
88+
)}
89+
{/* enroll button */}
90+
{loading ? (
91+
<div className="d-flex justify-content-center mt-3">
92+
<LoadingOutlined className="h1 text-danger" />
93+
</div>
94+
) : (
95+
<Button
96+
className="mb-3 mt-3 enroll"
97+
type="danger"
98+
block
99+
shape="round"
100+
icon={<SafetyOutlined />}
101+
size="large"
102+
disabled={loading}
103+
onClick={paid ? handlePaidEnrollment : handleFreeEnrollment}
104+
>
105+
{user
106+
? enrolled.status
107+
? "Go to course "
108+
: "Enroll"
109+
: "Login to enroll"}
110+
</Button>
111+
)}
112+
</div>
113+
</div>
114+
</div>
115+
);
116+
};
117+
118+
export default SingleCourseJumbotron;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { List, Avatar } from "antd";
2+
const { Item } = List;
3+
4+
const SingleCourseLessons = ({
5+
lessons,
6+
setPreview,
7+
showModal,
8+
setShowModal,
9+
}) => {
10+
return (
11+
<div className="container mt-5">
12+
<div className="row">
13+
<div className="col lesson-list">
14+
{lessons && <h3>{lessons.length} lessons</h3>}
15+
<hr />
16+
<List
17+
itemLayout="horizontal"
18+
dataSource={lessons}
19+
renderItem={(item, index) => (
20+
<Item>
21+
<Item.Meta
22+
avatar={<Avatar>{index + 1}</Avatar>}
23+
title={item.title}
24+
/>
25+
{item.video && item.video !== null && item.free_preview && (
26+
<span
27+
className="preview2"
28+
style={{ cursor: "pointer" }}
29+
onClick={() => {
30+
setPreview(item.video.Location);
31+
setShowModal(!showModal);
32+
}}
33+
>
34+
Preview
35+
</span>
36+
)}
37+
</Item>
38+
)}
39+
/>
40+
</div>
41+
</div>
42+
</div>
43+
);
44+
};
45+
46+
export default SingleCourseLessons;

0 commit comments

Comments
 (0)