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

[Render test] Finish the rest of the features #2

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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