Skip to content
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

Video page #52

Merged
merged 13 commits into from
Sep 21, 2023
2 changes: 1 addition & 1 deletion langjo-frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
{ "proxy": "http://localhost:5000",
"name": "langjo-frontend",
"version": "0.1.0",
"private": true,
Expand Down
4 changes: 4 additions & 0 deletions langjo-frontend/src/Home.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ import BeginnerLevel from "./components/BeginnerLevel/BeginnerLevel";
import BlocksCards from "./components/BlockCards/BlocksCards";
import Hero from "./components/Hero/Hero";



function Home() {
return (
<div>
<Hero />
<LevelTest />
<BeginnerLevel />
<BlocksCards />


</div>
);
}
Expand Down
19 changes: 0 additions & 19 deletions langjo-frontend/src/Pages.js

This file was deleted.

25 changes: 19 additions & 6 deletions langjo-frontend/src/components/BeginnerLevel/BeginnerLevel.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@ function BeginnerLevel() {
engaging video tutorials to help you grasp the fundamental concepts of
learning curve...
</p>
<div className="card-group gap-5">
{getRandomSubset(videos, 3).map((video) => {
<div className="d-flex justify-content-center card-group gap-3 border border-0 row">
{getRandomSubset(videos, 4).map((video) => {
const videoId = video.videoUrl.split("/").pop(); // Extract video id from videoUrl
return (
<div className="card video-card gap-5 rounded-5" key={video._id}>
<div className="video-overlay object-fit-fill">
<div className="video-wrapper ratio ratio-1x1 rounded-4">
<i className="bi bi-play-circle"></i>
<div
className="card video-card gap-2 object-fit-fill rounded-5 border border-0 col-6 col-sm-4 "
key={video._id}
>
<div className="video-overlay border border-0">
<div className="video-wrapper ratio ratio-1x1 rounded-4 border border-0">
<iframe
title={video.title}
width="560"
Expand All @@ -50,6 +52,17 @@ function BeginnerLevel() {
></iframe>
</div>
</div>
<div className="d-grid gap-1 col-5 mx-auto px-3 border border-0">
<a
className="btn btn-secondary sign_up-btn rounded-5 py-2 border border-0"
href={`/video-page/${video._id}`}
role="button"
target="_blank"
rel="noopener noreferrer"
>
Click More
</a>
</div>
</div>
);
})}
Expand Down
2 changes: 1 addition & 1 deletion langjo-frontend/src/components/NavBar/NavBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function NavBar() {
<NavDropdown.Item href="/beginnerlevel">
Beginner
</NavDropdown.Item>
<NavDropdown.Item href="#inter">Intermadite </NavDropdown.Item>
<NavDropdown.Item href="#inter">Intermediate </NavDropdown.Item>
<NavDropdown.Item href="#advan">Advance </NavDropdown.Item>
<NavDropdown.Divider />
<NavDropdown.Item href="#action5">Quiz</NavDropdown.Item>
Expand Down
56 changes: 56 additions & 0 deletions langjo-frontend/src/components/VideoPage/VideoPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";


const VideoPage = () => {
const videoId = useParams();
const [videoData, setVideoData] = useState(null);
useEffect(() => {
const fetchVideoData = async () => {
try {
const res = await fetch(
`http://localhost:5000/api/videos/beginners-level/${videoId.id}`
);
if (!res.ok) throw new Error(`HTTP error! Status: ${res.status}`);
const data = await res.json();
setVideoData(data.data);
} catch (error) {
console.error("Failed to fetch video data:", error);
}
};
fetchVideoData();
}, [videoId]);
if (!videoData) {
return (
<div className="d-flex justify-content-center aligin-items-center m-5 p-5">
<div className="spinner-border" role="status">
<span className="visually-hidden">Loading...</span>
</div>
</div>
);
}
const videoGet =
(videoData.videoUrl && videoData.videoUrl.split("/").pop()) || "";
return (
<div className="d-flex justify-content-center algin-items-center mt-5 text-center">
<div className="card border border-0 ">
<div className="card-body ">
<h1 className="card-title ">{videoData.title}</h1>
<p className=" ">{videoData.desc}</p>
<div className="embed-responsive embed-responsive-16by9">
<iframe
title={videoData.title}
className="embed-responsive-item object-fit-sm-contain border rounded-5"
width="760"
height="515"
src={`https://www.youtube.com/embed/${videoGet}`}
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
/>
</div>
</div>
</div>
</div>
);
};
export default VideoPage;
3 changes: 3 additions & 0 deletions langjo-frontend/src/pages/Pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import LogIn from "../components/LogIn/LogIn";
import BeginnerLevel from "../components/BeginnerLevel/BeginnerLevel";
import EnglishLevel from "../components/EnglishLevel/EnglishLevel";
import BlockCards from "../components/BlockCards/BlocksCards";
import VideoPage from "../components/VideoPage/VideoPage";


function Pages() {
return (
Expand All @@ -17,6 +19,7 @@ function Pages() {
<Route path="/englishlevel" element={<EnglishLevel />} />
<Route path="/beginnerlevel" element={<BeginnerLevel />} />
<Route path="/blockcards" element={<BlockCards />} />
<Route path="/video-page/:id" element={<VideoPage />} />
</Routes>
</div>
);
Expand Down
36 changes: 36 additions & 0 deletions server/controllers/video.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,46 @@ export const createVideo = async (req, res, next) => {
};

export const displayVideo = async (req, res, next) => {
try {
const videoId = req.params.id;
const video = await Video.findById(videoId);
if (!video) {
return res
.status(404)
.json({ success: false, message: "Video not found" });
}
res.status(200).json({ success: true, data: video });
} catch (error) {
next(error);
}
};

export const displayVideos = async (req, res, next) => {
try {
const video = await Video.find();
res.status(200).json({ success: true, data: video });
} catch (error) {
next(error);
}
};
export const getVideo = async (req, res, next) => {
try {
const video = await Video.findById(req.params.id);
res.status(200).json({ success: true, data: video });
} catch (error) {
next(error);
}
};
export const getVideoByTitle = async (req, res, next) => {
try {
const video = await Video.findOne({ title: req.params.title });
if (!video) {
return res
.status(404)
.json({ success: false, message: "Video not found" });
}
res.status(200).json({ success: true, data: video });
} catch (error) {
next(error);
}
};
35 changes: 11 additions & 24 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,39 @@ import express from "express";
import mongoose from "mongoose";
import cors from "cors";
import * as dotenv from "dotenv";
import { userRouter } from "./routes/users.js"
import { videoRouter } from "./routes/beginners-level.js"
import { userRouter } from "./routes/users.js";
import { videoRouter } from "./routes/beginners-level.js";
import { authRouter } from "./routes/auth.js";
import { commentRouter } from "./routes/comment.js";
import cookieParser from "cookie-parser";

dotenv.config();

const PORT = process.env.PORT || 5000;
const app = express();

// Enable CORS for all routes
app.use(
cors({
origin: "http://localhost:3000",
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
allowedHeaders: "Content-Type, Authorization, X-Requested-With, Accept",
})
);

const connect = () => {
mongoose.connect(
"mongodb+srv://chioma:[email protected]/?retryWrites=true&w=majority"
);
};

app.get('/', (req, res) => {
res.json({ message: "This is LangJo App 🏴󠁧󠁢󠁥󠁮󠁧󠁿!" });
})
app.use(cookieParser())
app.get("/", (req, res) => {
res.json({ message: "This is LangJo App :flag-england:!" });
});
app.use(cookieParser());
app.use(express.json());
app.use("/api/auth", authRouter)
app.use("/api/users", userRouter)
app.use("/api/videos", videoRouter)
app.use("/api/comments", commentRouter)

// API routes
app.use("/api/auth", authRouter);
app.use("/api/users", userRouter);
app.use("/api/videos", videoRouter);

// Error-handling middleware
app.use("/api/videos", videoRouter); // This route will handle both "/api/videos/" and "/api/videos/:id"
app.use("/api/comments", commentRouter);
app.use((error, req, res, next) => {
// Error handling code
res.status(500).json({ message: error.message });
});

connect();
app.listen(PORT, () => {
connect();
console.log(`Listening on port ${PORT}`);
});
16 changes: 15 additions & 1 deletion server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@
"author": "",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"mongodb": "^5.6.0",
"bcryptjs": "^2.4.3",
"buffer-equal-constant-time": "^1.0.1",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"dotenv": "^16.1.3",
"express": "^4.18.2",
"jsonwebtoken": "^9.0.0",
"mongodb": "^5.6.0",
"mongoose": "^7.3.4",
"nodemon": "^2.0.22"
"nodemon": "^2.0.22",
"yallist": "^4.0.0"
}
}
19 changes: 16 additions & 3 deletions server/routes/beginners-level.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import express from "express";
import cors from "cors";
import { displayVideo, createVideo } from "../controllers/video.js";

import {
getVideo,
getVideoByTitle,
displayVideo,
createVideo,
displayVideos,
} from "../controllers/video.js";
import { verifyToken } from "../verifyToken.js";

const app = express();

app.use(
Expand All @@ -15,7 +24,11 @@ app.use(
app.use(express.json());

const videoRouter = express.Router();
videoRouter.get("/beginners-level", displayVideo);
videoRouter.get("/beginners-level", displayVideos);
videoRouter.get("/beginners-level/:id", displayVideo);
videoRouter.get("/beginners-level", displayVideos);
videoRouter.post("/beginners-level", createVideo);

videoRouter.get("/beginners-level/:videoId", getVideo);
videoRouter.put("/beginners-level/:videoId", verifyToken);
videoRouter.get("/title/:title", getVideoByTitle);
export { videoRouter };
19 changes: 19 additions & 0 deletions server/routes/videos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import express from "express";
import { getVideo, createVideo } from "../controllers/video.js";
import { verifyToken } from "../verifyToken.js";

const videoRouter = express.Router();

// get all videos
videoRouter.get("/videos", getVideo);

// create a new video
videoRouter.post("/videos", createVideo);

// get a video
videoRouter.get("/videos/:videoId", getVideo);

// put a video
videoRouter.put("/videos/:videoId", verifyToken);

export { videoRouter };