Skip to content

Commit

Permalink
Finish the rest of the features
Browse files Browse the repository at this point in the history
  • Loading branch information
sztupy committed Dec 5, 2023
1 parent cb556ab commit 2b7562d
Show file tree
Hide file tree
Showing 11 changed files with 674 additions and 149 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/run-features.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ run-name: Enforce selenium feature tests pass on committed files

on:
workflow_dispatch:
# pull_request:
pull_request:

jobs:
run-features:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/run-server-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ run-name: Enforce tests pass on committed files

on:
workflow_dispatch:
# pull_request:
pull_request:

jobs:
run-server-tests:
Expand Down
182 changes: 98 additions & 84 deletions client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,120 +4,133 @@ import VideoList from "./components/VideoList";
import VideoSubmission from "./components/VideoSubmission";
import OrderingSelector from "./components/OrderingSelector";

const VIDEO_LIST = [
{
id: 523523,
title: "Never Gonna Give You Up",
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
rating: 23,
},
{
id: 523427,
title: "The Coding Train",
url: "https://www.youtube.com/watch?v=HerCR8bw_GE",
rating: 230,
},
{
id: 82653,
title: "Mac & Cheese | Basics with Babish",
url: "https://www.youtube.com/watch?v=FUeyrEN14Rk",
rating: 2111,
},
{
id: 858566,
title: "Videos for Cats to Watch - 8 Hour Bird Bonanza",
url: "https://www.youtube.com/watch?v=xbs7FT7dXYc",
rating: 11,
},
{
id: 453538,
title:
"The Complete London 2012 Opening Ceremony | London 2012 Olympic Games",
url: "https://www.youtube.com/watch?v=4As0e4de-rI",
rating: 3211,
},
{
id: 283634,
title: "Learn Unity - Beginner's Game Development Course",
url: "https://www.youtube.com/watch?v=gB1F9G0JXOo",
rating: 211,
},
{
id: 562824,
title: "Cracking Enigma in 2021 - Computerphile",
url: "https://www.youtube.com/watch?v=RzWB5jL5RX0",
rating: 111,
},
{
id: 442452,
title: "Coding Adventure: Chess AI",
url: "https://www.youtube.com/watch?v=U4ogK0MIzqk",
rating: 671,
},
{
id: 536363,
title: "Coding Adventure: Ant and Slime Simulations",
url: "https://www.youtube.com/watch?v=X-iSQQgOd1A",
rating: 76,
},
{
id: 323445,
title: "Why the Tour de France is so brutal",
url: "https://www.youtube.com/watch?v=ZacOS8NBK6U",
rating: 73,
},
];

const App = () => {
let [videos, setVideos] = useState([]);
let [message, setMessage] = useState(null);
let [order, setOrder] = useState("id");

function orderVideos(videos, order, initial) {
function orderVideos(videos, order) {
switch (order) {
case "rating_asc":
return videos.sort((a, b) => a.rating - b.rating);
case "rating_desc":
return videos.sort((a, b) => b.rating - a.rating);
case "random":
if (initial) {
return videos.sort(() => 0.5 - Math.random());
} else {
return videos; // this should only sort once when getting from backend, then keep it as-is
}
return videos; // this should only sort once when getting from backend, then keep it as-is
case "id":
return videos.sort((a, b) => a.id - b.id);
}
}

useEffect(() => {
setVideos([...orderVideos(VIDEO_LIST, order, true)]);
}, [setVideos, order]);
const fetchVideos = async () => {
try {
const videoResults = await fetch(`/api/videos?order=${order}`);
const videoResultsJson = await videoResults.json();
if (videoResultsJson.success) {
setVideos(videoResultsJson.data);
setMessage(null);
} else {
setMessage(
videoResultsJson.message ||
"Error while loading video recommendations, please try again by reloading the page!"
);
}
} catch (error) {
setMessage(
"Error while loading video recommendations, please try again by reloading the page!"
);
}
};
fetchVideos();
}, [setVideos, setMessage, order]);

const addVideo = function (title, url) {
const newVideo = {
id: Math.max(...videos.map((v) => v.id)) + 1,
title: title,
url: url,
rating: 0,
const publishToApi = async () => {
try {
const results = await fetch("/api/videos", {
method: "POST",
body: JSON.stringify({ title: title, url: url }),
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
});
const data = await results.json();
if (data.success) {
setVideos(orderVideos([...videos, data.data], order));
} else {
setMessage(
data.message ||
"Error while publishing the new video. Please reload the page and try again!"
);
}
} catch (error) {
setMessage(
"Error while publishing the new video. Please reload the page and try again!"
);
}
};
VIDEO_LIST.push(newVideo);
setVideos([...orderVideos(VIDEO_LIST, order)]);
publishToApi();
};

const updateVideo = function (video, action) {
const deleteVideo = async (selectedVideo) => {
VIDEO_LIST.splice(VIDEO_LIST.indexOf(selectedVideo), 1);
setVideos([...orderVideos(VIDEO_LIST, order)]);
try {
const results = await fetch(`/api/videos/${selectedVideo.id}`, {
method: "DELETE",
headers: {
"Access-Control-Allow-Origin": "*",
},
});
const data = await results.json();
if (data.success) {
videos = videos.filter((e) => e.id !== selectedVideo.id);
} else {
selectedVideo.message =
data.message ||
"There was an error while trying to delete the video. Please reload the page and try again!";
}
} catch (error) {
selectedVideo.message =
"There was an error while trying to delete the video. Please reload the page and try again!";
}
setVideos(orderVideos([...videos], order));
};

const voteOnVideo = async (selectedVideo, action) => {
selectedVideo.rating += action == "up" ? 1 : -1;
setVideos([...orderVideos(VIDEO_LIST, order)]);
try {
const results = await fetch(
`/api/videos/${selectedVideo.id}/${action}`,
{
method: "POST",
headers: {
"Access-Control-Allow-Origin": "*",
},
}
);
const data = await results.json();
if (data.success) {
selectedVideo.rating = data.data.rating;
selectedVideo.message = null;
} else {
selectedVideo.message =
data.message ||
"There was an error while updating rating to the video. Please reload the page and try again!";
}
} catch (error) {
selectedVideo.message =
"There was an error while updating rating to the video. Please reload the page and try again!";
}
setVideos(orderVideos([...videos], order));
};

let selectedVideo = VIDEO_LIST.find((e) => e.id === video.id);
let selectedVideo = videos.find((e) => e.id === video.id);

if (selectedVideo) {
selectedVideo.message = " ";
setVideos(orderVideos([...videos], order));

switch (action) {
case "up":
case "down":
Expand All @@ -133,6 +146,7 @@ const App = () => {
return (
<>
<h1>Video Recommendations</h1>
{message && <h2 className="message">{message}</h2>}
<OrderingSelector order={order} setOrder={setOrder} />
<VideoList videos={videos} updateVideo={updateVideo} />
<VideoSubmission addVideo={addVideo} />
Expand Down
24 changes: 21 additions & 3 deletions client/src/components/Video.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,35 @@ export default function Video({ video, updateVideo }) {
allowFullScreen
></iframe>
)}
<h3>Recommended since</h3>
<div title="Recommended since" className="recommended-since">
{new Date(video.created_at).toLocaleString()}
</div>
<h3>Rating</h3>
<div title="Rating" className="rating">
{video.rating}
</div>
<h3>Controls</h3>
<div className="control-message">{video.message}</div>
<div className="controls">
<button onClick={() => updateVideo(video, "delete")}>
<button
disabled={video.message ? true : false}
onClick={() => updateVideo(video, "delete")}
>
Remove video
</button>
<button onClick={() => updateVideo(video, "up")}>Up Vote</button>
<button onClick={() => updateVideo(video, "down")}>Down Vote</button>
<button
disabled={video.message ? true : false}
onClick={() => updateVideo(video, "up")}
>
Up Vote
</button>
<button
disabled={video.message ? true : false}
onClick={() => updateVideo(video, "down")}
>
Down Vote
</button>
</div>
</li>
);
Expand Down
35 changes: 35 additions & 0 deletions client/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ h1 {
text-align: center;
}

.message {
width: auto;
padding: 1em;
margin: 1em;
border: 1px solid red;
border-radius: 5px;
background-color: lightsalmon;
}

#videos {
display: grid;
grid-auto-flow: row;
Expand Down Expand Up @@ -83,6 +92,25 @@ h1 {
background-color: bisque;
}

.video .recommended-since:before {
content: "🕒 ";
}

.video .recommended-since {
max-width: fit-content;
padding: 0.5em;

display: block;
font-size: 1em;

margin: 0.5em auto;

border: 1px solid black;
border-radius: 5px;

background-color: bisque;
}

.video h3 {
position: absolute;
left: -10000px;
Expand Down Expand Up @@ -118,6 +146,13 @@ h1 {
grid-template-columns: 1fr 1fr 1fr;
}

.control-message {
position: absolute;
bottom: 0;
background-color: white;
border: 1px solid red;
}

#submit-video {
text-align: center;
width: auto;
Expand Down
Loading

0 comments on commit 2b7562d

Please sign in to comment.