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

London10-AfshaHossain-FullStackProjectAssessment-Week2-Level 250 #399

Closed
wants to merge 72 commits into from
Closed
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
88fdbd2
Set up gitignore, tailwind
Afsha10 Aug 18, 2023
362ac54
Added basic VideoCard component
Afsha10 Aug 18, 2023
546d415
Level 100 WIP
Afsha10 Aug 21, 2023
9f59cba
Completed Level 100 and Level 199 WIP
Afsha10 Aug 24, 2023
d9bbe3f
Cleaned up root directory, transferred Tailwind and prettier config f…
Afsha10 Aug 25, 2023
1536a64
Uploaded date
Afsha10 Aug 25, 2023
97f2257
Used Tailwind to style the app
Afsha10 Aug 25, 2023
6203909
Merge pull request #1 from Afsha10/level-100
Afsha10 Aug 25, 2023
4365e2d
Basic setup- Added corrs and dotenv pacakages, and exampleresponse.js…
Afsha10 Aug 25, 2023
ed7800d
Worked on some some level 199 specs and did some styling using Tailwind
Afsha10 Aug 28, 2023
6fb98d0
Completed GET response
Afsha10 Aug 28, 2023
094ddfe
Simplified Import for GET response
Afsha10 Aug 28, 2023
3cac61d
Completed POST request
Afsha10 Aug 28, 2023
d106af8
Get Video by ID
Afsha10 Aug 28, 2023
ec85784
Completed DELETE by id
Afsha10 Aug 28, 2023
d41d555
Merge pull request #2 from Afsha10/level-200
Afsha10 Aug 28, 2023
b1f23f3
Level 250 WIP
Afsha10 Aug 30, 2023
9771eaf
Level 250 WIP
Afsha10 Aug 30, 2023
d09385c
Level 250 WIP
Afsha10 Aug 31, 2023
2eb4d6b
Level 250 WIP
Afsha10 Sep 4, 2023
c138bad
WIP level 250
Afsha10 Sep 5, 2023
46c4fa8
Corrected YouTube URL Validation
Afsha10 Sep 5, 2023
654f50c
Decluttered unnecessary comments, console.logs and a CSS file
Afsha10 Sep 5, 2023
c394491
Merge pull request #3 from Afsha10/level-250
Afsha10 Sep 5, 2023
1b9e46f
Added dotenv package to the server/package.json
Afsha10 Sep 11, 2023
e004e72
Working on local build
Afsha10 Sep 14, 2023
b4a3335
Update server.js
Afsha10 Sep 14, 2023
0a98d5d
Update server.js
Afsha10 Sep 14, 2023
6fa3eb6
Changed the fetch address from local server to successfully deployed …
Afsha10 Sep 15, 2023
5df3897
Connected my front end local host links to my server link
Afsha10 Sep 15, 2023
1f88ff6
Corrected a mistake in my fetch GET url in MainContainers
Afsha10 Sep 15, 2023
1012a51
Corrected paths on the server.js with proper queries
Afsha10 Sep 15, 2023
482bd51
Corrected the paths with the base url from the config
Afsha10 Sep 15, 2023
8ff9f0d
Integrating videos database with Node express js using SQL queries
Afsha10 Sep 18, 2023
9e97097
Added file to create the database table
Afsha10 Sep 18, 2023
8d9682b
Removed the unnecessary items from the object called newData in Vide…
Afsha10 Sep 18, 2023
f832310
Made the upvote and downvote rating work
Afsha10 Sep 18, 2023
2570763
Created a Footer component and made the app responsive using Tailwind…
Afsha10 Sep 18, 2023
9b96469
Merge pull request #4 from Afsha10/level-300
Afsha10 Sep 18, 2023
bd7dc12
Created a Footer component, made the app responsive using Tailwind CS…
Afsha10 Sep 18, 2023
bf46c8b
Added a loading message and animation to indicate data being loaded
Afsha10 Sep 19, 2023
734637a
Small fixes
Afsha10 Sep 20, 2023
ec5f6d8
Added YouTube validation criteria also to server.js for robust security
Afsha10 Sep 20, 2023
2d9b9bb
Fixed loading issue
Afsha10 Sep 20, 2023
9b3ed5f
Merge branch 'main' into level-300
Afsha10 Sep 20, 2023
e5ee4c6
Merge pull request #5 from Afsha10/level-300
Afsha10 Sep 20, 2023
8733d6a
Merge branch 'main' into level-300
Afsha10 Sep 20, 2023
cf043d0
Added a Header component
Afsha10 Sep 21, 2023
70781ac
Added a Header component
Afsha10 Sep 26, 2023
c55af80
Changed the schema
Afsha10 Oct 8, 2023
49688fd
Put ; in query and at the end of config file
Afsha10 Oct 20, 2023
f7ed0b9
Fix adding new videos on mobile
Afsha10 Oct 31, 2023
e4f65f8
Clear console.log, add meaningful comment and variable name
Afsha10 Nov 1, 2023
9d35892
Update config.js with the new render backend URL
Afsha10 Nov 7, 2023
594afe7
Create a shell script for getting the videos from the command line
Afsha10 Dec 19, 2023
357f4b8
Merge pull request #6 from Afsha10/level-300
Afsha10 Dec 21, 2023
26ceafd
Updated README.md with a demo and front-end and back-end
Afsha10 Dec 22, 2023
a197fee
Clean the client folder by deleting unnecessary files and codes
Afsha10 Dec 22, 2023
d12703c
Merge pull request #7 from Afsha10/level-300
Afsha10 Dec 22, 2023
69fc9ab
Update loading message to a friendlier one
Afsha10 Jan 1, 2024
d8e6153
Change copyright year to 2024
Afsha10 Jan 6, 2024
cf27ce9
Read the SSL parameter from the environment variable
Afsha10 Jan 8, 2024
e9d30a8
Merge pull request #8 from Afsha10/level-300
Afsha10 Jan 9, 2024
282d860
Change the title
Afsha10 Jan 17, 2024
2214a6c
Add aws backend link to config, add test.yml to workflow folder
Afsha10 Jan 27, 2024
befd54c
Add workflow for deploying front-end to awl as CI/CD automation
Afsha10 Jan 30, 2024
822cd7c
Fix warning related to Node version 20
Afsha10 Jan 30, 2024
7f7d27b
Test to see if GitHub Action is working
Afsha10 Jan 30, 2024
96168c8
Add delete to replace the old files with the new ones
Afsha10 Jan 30, 2024
fa97d00
Correct the config file link
Afsha10 Jan 31, 2024
55d528b
Merge pull request #9 from Afsha10/level-300
Afsha10 Jan 31, 2024
d3f3df6
Delete frontend-s3-deploy.yml
Afsha10 Feb 2, 2024
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
3 changes: 3 additions & 0 deletions client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
plan.drawio
plan.md
7,670 changes: 4,531 additions & 3,139 deletions client/package-lock.json

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,16 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "^5.0.0",
"valid-url": "^1.0.9",
"web-vitals": "^1.1.2"
},
"devDependencies": {
"autoprefixer": "^10.4.15",
"postcss": "^8.4.28",
"prettier": "^3.0.2",
"prettier-plugin-tailwindcss": "^0.5.3",
"tailwindcss": "^3.3.3"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
Expand Down
53 changes: 53 additions & 0 deletions client/plan.drawio
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<mxfile host="65bd71144e">
<diagram id="BdzzjRRzsWgrQ7JI_RHI" name="Page-1">
<mxGraphModel dx="529" dy="348" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="3" value="App.jsx&lt;br&gt;videoList, setVideoList as props" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="10" y="80" width="150" height="110" as="geometry"/>
</mxCell>
<mxCell id="4" value="VideoList.jsx" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="200" y="80" width="90" height="30" as="geometry"/>
</mxCell>
<mxCell id="5" value="VideoCard.jsx" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="200" y="200" width="90" height="40" as="geometry"/>
</mxCell>
<mxCell id="7" value="" style="endArrow=classic;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="4" target="5" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="240" y="310" as="sourcePoint"/>
<mxPoint x="290" y="260" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="10" value="" style="endArrow=classic;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.25;exitDx=0;exitDy=0;" parent="1" source="3" target="4" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="240" y="310" as="sourcePoint"/>
<mxPoint x="290" y="260" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="11" value="Main" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="80" y="360" width="90" height="60" as="geometry"/>
</mxCell>
<mxCell id="16" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="12" target="13">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="12" value="100" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="80" y="460" width="80" height="60" as="geometry"/>
</mxCell>
<mxCell id="13" value="200" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="80" y="550" width="80" height="60" as="geometry"/>
</mxCell>
<mxCell id="14" value="200" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="205" y="360" width="80" height="60" as="geometry"/>
</mxCell>
<mxCell id="15" value="" style="endArrow=classic;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="11" target="12">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="180" y="480" as="sourcePoint"/>
<mxPoint x="230" y="430" as="targetPoint"/>
<Array as="points"/>
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
124 changes: 124 additions & 0 deletions client/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@

1. Videos should be loaded from a local javascript variable containing the data included in `exampleresponse.json`
```json
{
"id": 523523,
"title": "Never Gonna Give You Up",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"rating": 23
},
```
- Log `exampleresponse.json` into app to check data is arriving into frontend. ✅

- We will create a VideoCard component. This will contain a single videos data.✅
- Hardcode the VideoCard component with information from the object above.✅
* replace watch?v= with embed/;
* data.url.replace("watch?v=", "embed/");

**Notes** We will use props to send the data from exampleresponse.json file to our VideoList component

2. For each video, display a React component that contains
- The videos title ✅
- An embedded video ✅
- The number of votes the video has ✅
- A button that when clicked removes the video ✅

- Create a VideoList component with videoList prop (which is state from app level) ✅
- We need to map through each of the objects from the state that we are passing as a single prop to the VideoList component ✅
- For each of these objects we are rendering a VideoCard component ✅
- Each VideoCard component will take the props [id={id}, title={title}, url={url}, rating={rating}] ✅

3. On each video submission there should be two buttons
- "Up Vote" - This increases the vote score when clicked ✅
- "Down Vote" - This decreases the vote score when clicked ✅

- Hard code one button at time add state where necessary

4. On the page there must be another React component that will add a Video.
- It should include fields to add a
- Title ✅
- Url ✅
- When a button is clicked the video should be added to the list ✅

a. Create a VideoForm component ✅
b. Create mock structure below ✅
```html
<form>
<label for="title">
Please enter your video title below:
<input type="text" name="title" id="title" placeholder="Enter video title here" required/>
</label>
<label for="url">
Please enter your video url below:
<input type="url" name="url" id="url" placeholder="Enter video url here"/>
</label>
<button type="submit">Submit</button>
</form>
```
notes: Check implementation above is correct



5. Your website must follow accessibility guidelines (see below for more details)

==========================================================

App.jsx

State variable to hold videoList (initial value will be the data we get from exampleresponse.json)

VideoList.jsx -> props will be [videoList={videoList}]
VideoCard.jsx -> props will be [id={id}, title={title}, url={url}, rating={rating}]
VideoForm.jsx -> props will be [videoList={videoList} setVideoList={setVideoList}]

State variable to hold information that will be updating the videoList state variable declared in App.jsx



## Youtube URL
embedded version:
https://www.youtube.com/embed/lJIrF4YjHfQ
watch version:
https://www.youtube.com/watch?v=lJIrF4YjHfQ


## Youtube URL from data
embedded version:
https://www.youtube.com/embed/dQw4w9WgXcQ
watch version:
https://www.youtube.com/watch?v=dQw4w9WgXcQ


Helpful related articles:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace



===========================================

Make reusable button

We will always need to hand down the following:

- content (can be a text or icon; this goes between the button tags)
- type attribute (eg. submit or delete)
- onClickHandler
-

=============================================

Validate URL Workings:

function validateUrl(urlObject) {
console.log(urlObject);
if (urlObject.protocol !== "https:") {
throw new Error("Protocol must be https:");
}
return true;
// return either validated URL or an error
}
// const unValidatedTitle = event.target.form.title.value;
const unValidatedUrl = new URL(event.target.form.url.value);
// const isValidated = validateUrl(unValidatedUrl);

4 changes: 4 additions & 0 deletions client/prettier.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// prettier.config.js
module.exports = {
plugins: ["prettier-plugin-tailwindcss"],
};
3 changes: 0 additions & 3 deletions client/src/App.css

This file was deleted.

18 changes: 11 additions & 7 deletions client/src/App.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import "./App.css";
import React from "react";
import MainContainer from "./components/MainContainer";
import youtubeLogo from "./components/images/youtubeLogo.png";

function App() {
const App = () => {
return (
<div className="App">
<header className="App-header">
<h1>Video Recommendation</h1>
</header>
<div className="App text-left">
<div className="font-semi-bold flex flex-row justify-center pt-8 text-5xl">
<img src={youtubeLogo} alt="Logo" className="h-13 mx-7 w-20" />
<h1>Video Recommendations</h1>
</div>
<MainContainer />
</div>
);
}
};

export default App;
14 changes: 14 additions & 0 deletions client/src/components/Button.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";

function Button({ onDelete, id }) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of things to think about with this component:

  1. "Button" is a very general name - can you think of a more specific name for what the button actually is for?
  2. onDelete is a slightly strange name - "on" as a prefix normally means this function is meant to be called when something has happened (e.g. onClick is for when something has been clicked), but this actually does the delete, rather than handles it. Can you think of a name which suggests more this does the delete, rather than is called as a result of the delete?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @illicitonion for pointing these out and paying attention to details! Having the right names is super helpful for me to understand my own code when I look at them.
After going through your review, I made changes to my level 300 as my level 300 is built on top of my level 250.

  1. I have renamed my Button component to DeleteButton.
  2. onDelete does sound strange. I have renamed it to handleDelete.

return (
<button
onClick={() => onDelete(id)}
className="rounded bg-gray-200 p-2 text-lg font-bold"
>
Delete ❌
</button>
);
}

export default Button;
34 changes: 34 additions & 0 deletions client/src/components/CardsContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from "react";
import VideoCard from "./VideoCard";

function CardsContainer({ videoData, setVideoData, setFetchData }) {
async function handleDelete(id) {
fetch(`http://localhost:5000/videos/${id}`, {
method: "delete",
})
.then((response) => response.json())
.then((result) => console.log(result))
.catch((error) => console.log("error", error));
setFetchData(true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is setFetchData for? It's not super clear from its name what it's for, or what "true" vs "false" means for its value?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed setFetchData and added a new useState variable called "setVideoAdded" and set it as false and true when adding new videos data.

}

return (
<div className="grid justify-center gap-9">
{videoData
?.sort((a, b) => b.rating - a.rating)
.map((singleVideo) => {
return (
<VideoCard
key={singleVideo.id}
videoData={videoData}
singleVideo={singleVideo}
onDelete={handleDelete}
setVideoData={setVideoData}
/>
);
})}
</div>
);
}

export default CardsContainer;
34 changes: 34 additions & 0 deletions client/src/components/MainContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, { useEffect, useState } from "react";
import CardsContainer from "./CardsContainer";
import VideoForm from "./VideoForm";

function MainContainer() {
const [videoData, setVideoData] = useState();
const [fetchData, setFetchData] = useState(true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When is this state ever false? What does this state control?


useEffect(() => {
if (fetchData) {
fetch("http://localhost:5000/videos")
.then((response) => response.json())
.then((data) => setVideoData(data));
}
setFetchData(false);
}, [fetchData, videoData]);

return (
<div>
<VideoForm
setFetchData={setFetchData}
videoData={videoData}
setVideoData={setVideoData}
/>
<CardsContainer
setFetchData={setFetchData}
videoData={videoData}
setVideoData={setVideoData}
/>
</div>
);
}

export default MainContainer;
Loading