Skip to content

rizan_ibrahim-w2-UsingApis #66

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
14 changes: 14 additions & 0 deletions .test-summary/TEST_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## Test Summary

**Mentors**: For more information on how to review homework assignments, please refer to the [Review Guide](https://github.com/HackYourFuture/mentors/blob/main/assignment-support/review-guide.md).

### 3-UsingAPIs - Week2

| Exercise | Passed | Failed | ESLint |
|-------------------|--------|--------|--------|
| ex1-programmerFun | 5 | - | ✕ |
| ex2-pokemonApp | 5 | - | ✕ |
| ex3-rollAnAce | 7 | - | ✕ |
| ex4-diceRace | 7 | - | ✕ |
| ex5-vscDebug | - | - | ✕ |
| ex6-browserDebug | - | - | ✕ |
42 changes: 29 additions & 13 deletions 3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,45 @@ Full description at: https://github.com/HackYourFuture/Assignments/blob/main/3-U
url with `.shx`. There is no server at the modified url, therefore this
should result in a network (DNS) error.
------------------------------------------------------------------------------*/
function requestData(url) {
// TODO return a promise using `fetch()`
async function requestData(url) {
try {
const response = await fetch(url);

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

return await response.json();
} catch (error) {
throw new Error(`Network error! ${error.message}`);
}
}

Choose a reason for hiding this comment

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

The requestData() is expected to return a promise that resolves to a JavaScript (from response.json()) or to return a rejected promise in case of network errors or HTTP errors. That is what your code does correctly. However, you don't need a try/catch block here. The same behaviour can be accomplished with this simpler code:

async function requestData(url) {
  const response = await fetch(url);

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  return await response.json();
}


function renderImage(data) {
// TODO render the image to the DOM
const img = document.createElement('img');
img.src = data.img;
img.alt = data.title;
document.body.appendChild(img);

console.log(data);
}

function renderError(error) {
// TODO render the error to the DOM
const h1 = document.createElement('h1');
h1.textContent = `error: ${error.message}`;
document.body.appendChild(h1);

console.log(error);
}

// TODO refactor with async/await and try/catch
function main() {
requestData('https://xkcd.now.sh/?comic=latest')
.then((data) => {
renderImage(data);
})
.catch((error) => {
renderError(error);
});
async function main() {
try {
const data = await requestData('https://xkcd.now.sh/?comic=latest');

renderImage(data);
} catch (error) {
renderError(error);
}
}

window.addEventListener('load', main);
71 changes: 64 additions & 7 deletions 3-UsingAPIs/Week2/assignment/ex2-pokemonApp/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,75 @@ Use async/await and try/catch to handle promises.
Try and avoid using global variables. As much as possible, try and use function
parameters and return values to pass data back and forth.
------------------------------------------------------------------------------*/
function fetchData(/* TODO parameter(s) go here */) {
// TODO complete this function
async function fetchData(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Error fetch data:', error);
throw error;
}
}

function fetchAndPopulatePokemons(/* TODO parameter(s) go here */) {
// TODO complete this function
async function fetchAndPopulatePokemons() {
const url = 'https://pokeapi.co/api/v2/pokemon?limit=150';
try {
const data = await fetchData(url);
const select = document.querySelector('select');
select.innerHTML = '';

Choose a reason for hiding this comment

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

After you press the button the select box shows the name of the first pokemon (bulbasaur) but does not show its image. A solution could be to either show the bubasaur image or add a placeholder for the first option in the select box before you add the pokemon options. For instance:

const option = document.createElement('option');
option.value = '';
option.textContent = 'Select a Pokemon';
option.disabled = true;
option.selected = true;
select.appendChild(option);

I adapted this from StackOverflow: https://stackoverflow.com/questions/5805059/how-do-i-make-a-placeholder-for-a-select-box


data.results.forEach((pokemon) => {
const option = document.createElement('option');
option.value = pokemon.url;
option.textContent = pokemon.name;
select.appendChild(option);
});
} catch (error) {
console.error('Error fetch pokemon list:', error);
}
}

function fetchImage(/* TODO parameter(s) go here */) {
// TODO complete this function
async function fetchImage(pokemonUrl) {
try {
const data = await fetchData(pokemonUrl);
const img = document.querySelector('img');
img.src = data.sprites.front_default;
img.alt = `${data.name} Pokemon sprite`;
} catch (error) {
console.error('Error fetch image:', error);
}
}

function main() {
// TODO complete this function
const button = document.createElement('button');
button.id = 'get-button';
button.textContent = 'get pokemon';
document.body.appendChild(button);

const select = document.createElement('select');
select.id = 'pokemon-select';
document.body.appendChild(select);

const option = document.createElement('option');
option.value = '';
option.textContent = 'Select a Pokemon';
select.appendChild(option);

const img = document.createElement('img');
img.id = 'pokemon-img';
img.alt = `select a pokemon to see it image `;
document.body.appendChild(img);

button.addEventListener('click', fetchAndPopulatePokemons);

select.addEventListener('change', (event) => {
if (event.target.value) {
fetchImage(event.target.value);
}
});
}

window.addEventListener('load', main);

Choose a reason for hiding this comment

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

Apart from the missing button, the code works fine.

91 changes: 90 additions & 1 deletion 3-UsingAPIs/Week2/assignment/ex2-pokemonApp/style.css
Original file line number Diff line number Diff line change
@@ -1 +1,90 @@
/* add your styling here */
/* Basic Reset */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
background-color: #f0f4f8;
color: #333;
text-align: center;
}

#get-button {
padding: 10px 15px;
font-size: 16px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition:
background 0.3s ease,
transform 0.2s ease;
margin-bottom: 15px;
}

#get-button:hover {
background-color: #0056b3;
transform: scale(1.05);
}

select {
padding: 10px;
font-size: 16px;
border: 2px solid #ccc;
border-radius: 5px;
background-color: #fff;
cursor: pointer;
width: 200px;
margin-bottom: 20px;
}

.select:focus {
border-color: #007bff;
outline: none;
}

/* Style the Pokémon image */
img {
margin-top: 20px;
max-width: 100%;
height: auto;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
max-height: 300px;
}

/* Style the fallback error message */
p {
margin-top: 20px;
color: #d9534f;
font-weight: bold;
}

h1 {
font-size: 2rem;
color: #007bff;
margin-bottom: 20px;
}

/* Style for select box container */
select,
img {
transition:
transform 0.3s ease,
box-shadow 0.3s ease;
}

select:hover,
img:hover {
transform: scale(1.05);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
}

Choose a reason for hiding this comment

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

Nice styling job!

27 changes: 14 additions & 13 deletions 3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,22 @@ import { rollDie } from '../../helpers/pokerDiceRoller.js';
* @param {DieFace} desiredValue
* @returns {Promise<DieFace>}
*/
export function rollDieUntil(desiredValue) {
// TODO rewrite this function using async/await
return rollDie().then((value) => {
if (value !== desiredValue) {
return rollDieUntil(desiredValue);
}
return value;
});

export async function rollDieUntil(desiredValue) {
let value;
while (value !== desiredValue) {
value = await rollDie();
}
return value;
}

// TODO refactor this function to use try/catch
function main() {
rollDieUntil('ACE')
.then((results) => console.log('Resolved!', results))
.catch((error) => console.log('Rejected!', error.message));
async function main() {

Choose a reason for hiding this comment

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

Nice solution! But for readability, it is best to separate function definitions with a blank line.

try {
const result = await rollDieUntil('ACE');
console.log('Resolved!', result);
} catch (error) {
console.log('Rejected!', error.message);
}
}

// ! Do not change or remove the code below
Expand Down
20 changes: 13 additions & 7 deletions 3-UsingAPIs/Week2/assignment/ex4-diceRace.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,26 @@ import { rollDie } from '../../helpers/pokerDiceRoller.js';

export function rollDice() {
const dice = [1, 2, 3, 4, 5];
// TODO complete this function; use Promise.race() and rollDie()
rollDie(1); // TODO placeholder: modify as appropriate

const diceRolls = dice.map(rollDie);

return Promise.race(diceRolls);
}

// Refactor this function to use async/await and try/catch
function main() {
rollDice()
.then((results) => console.log('Resolved!', results))
.catch((error) => console.log('Rejected!', error.message));
async function main() {
try {
const result = await rollDice();
console.log('resolved:', result);
} catch (error) {
console.error('rejected :', error.message);
}
}

// ! Do not change or remove the code below
if (process.env.NODE_ENV !== 'test') {
main();
}

// TODO Replace this comment by your explanation that was asked for in the assignment description.
/*
When you use Promise.race(), it starts all the promises at once and gives you the result of the first one that done, regardless of whether it resolved or rejected, However the other promises don’t stop—they keep running in the background. If you need to cancel those extra promises, you'd have to use something like AbortController or add your own logic. It’s not as simple as just calling Promise.race()*/

Choose a reason for hiding this comment

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

It's okay to seek help using AI so long as you understand what it says and learn from it.

26 changes: 22 additions & 4 deletions 3-UsingAPIs/Week2/assignment/ex5-vscDebug.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,21 @@ async function getData(url) {

function renderLaureate({ knownName, birth, death }) {
console.log(`\nName: ${knownName.en}`);
console.log(`Birth: ${birth.date}, ${birth.place.locationString}`);
console.log(`Death: ${death.date}, ${death.place.locationString}`);

if (birth) {
console.log(
`Birth: ${birth?.date || 'Unknown'}, ${typeof birth?.place?.locationString || 'Unknown'}`
);
} else {
console.log(`Birth: Unknown`);
}
if (death) {
console.log(
`Death: ${death?.date || 'Unknown'}, ${typeof death?.place?.locationString || 'Unknown'}`
);
} else {
console.log(`Death: still alive`);
}
}

function renderLaureates(laureates) {
Expand All @@ -20,10 +33,15 @@ function renderLaureates(laureates) {

async function fetchAndRender() {
try {
const laureates = getData(
const data = await getData(
'http://api.nobelprize.org/2.0/laureates?birthCountry=Netherlands&format=json&csvLang=en'
);
renderLaureates(laureates);

if (Array.isArray(data.laureates)) {
renderLaureates(data.laureates);
} else {
console.error('No laureates found.');
}
} catch (err) {
console.error(`Something went wrong: ${err.message}`);
}
Expand Down
Loading