diff --git a/3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js b/3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js index a99ca177b..f0fc1e9bf 100644 --- a/3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js +++ b/3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js @@ -16,29 +16,42 @@ 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}`); + } + + const data = await response.json(); + return data; + } catch (error) { + throw error; + } } function renderImage(data) { - // TODO render the image to the DOM + const img = document.createElement('img'); + img.src = data.img; + 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.message || error; + 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); diff --git a/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/index.js b/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/index.js index 262113997..4de1e972e 100644 --- a/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/index.js +++ b/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/index.js @@ -21,18 +21,76 @@ 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}`); + } + const data = await response.json(); + return data; + } catch (error) { + console.error('Fetch error:', 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 = ''; + + 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); \ No newline at end of file diff --git a/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/style.css b/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/style.css index 44cb05eeb..82cacc8cd 100644 --- a/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/style.css +++ b/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/style.css @@ -1 +1,96 @@ -/* add your styling here */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Poppins', sans-serif; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + min-height: 100vh; + background-color: #f5f5f5; + color: #222; + text-align: center; + padding: 40px 20px; +} + +h1 { + font-size: 2rem; + color: #333; + margin-bottom: 25px; +} + +#get-button { + padding: 10px 20px; + font-size: 16px; + color: #fff; + background-color: #4caf50; + border: none; + border-radius: 6px; + cursor: pointer; + transition: background 0.2s ease, transform 0.2s ease; + margin-bottom: 20px; +} + +#get-button:hover { + background-color: #45a049; + transform: scale(1.05); +} + +select { + padding: 10px 15px; + font-size: 16px; + border: 1px solid #ccc; + border-radius: 6px; + background-color: #fff; + cursor: pointer; + width: 200px; + margin-bottom: 20px; + transition: border-color 0.2s ease; +} + +select:focus { + border-color: #4caf50; + outline: none; +} + +img { + max-width: 250px; + max-height: 250px; + border-radius: 8px; + box-shadow: 0 4px 8px rgba(0,0,0,0.1); + transition: transform 0.2s ease; + margin-top: 20px; +} + +img:hover { + transform: scale(1.05); +} + +h1.error { + color: #e53935; + font-size: 1.5rem; + margin-top: 20px; +} + +@media (max-width: 480px) { + body { + padding: 20px 10px; + } + + h1 { + font-size: 1.8rem; + } + + img { + max-width: 180px; + max-height: 180px; + } + + select, #get-button { + width: 160px; + } +} \ No newline at end of file diff --git a/3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js b/3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js index 861b31047..ec27f5eb3 100644 --- a/3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js +++ b/3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js @@ -17,21 +17,21 @@ import { rollDie } from '../../helpers/pokerDiceRoller.js'; * @param {DieFace} desiredValue * @returns {Promise} */ -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() { + 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 diff --git a/3-UsingAPIs/Week2/assignment/ex4-diceRace.js b/3-UsingAPIs/Week2/assignment/ex4-diceRace.js index ddff3242c..8cf81c847 100644 --- a/3-UsingAPIs/Week2/assignment/ex4-diceRace.js +++ b/3-UsingAPIs/Week2/assignment/ex4-diceRace.js @@ -15,15 +15,17 @@ 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 @@ -31,4 +33,6 @@ if (process.env.NODE_ENV !== 'test') { main(); } -// TODO Replace this comment by your explanation that was asked for in the assignment description. +// Even after Promise.race() returns the first result, the other dice keep rolling +// because their promises are already running. Promise.race() only waits for the +// first one to finish; it does not stop the rest. \ No newline at end of file diff --git a/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js b/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js index a65448e57..ab91f49fc 100644 --- a/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js +++ b/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js @@ -10,8 +10,18 @@ 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'}, ${birth?.place?.locationString || 'Unknown'}`); + } else { + console.log(`Birth: Unknown`); + } + + if (death) { + console.log(`Death: ${death?.date || 'Unknown'}, ${death?.place?.locationString || 'Unknown'}`); + } else { + console.log(`Death: still alive`); + } } function renderLaureates(laureates) { @@ -20,13 +30,18 @@ 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}`); } } -fetchAndRender(); +fetchAndRender(); \ No newline at end of file diff --git a/3-UsingAPIs/Week2/assignment/ex6-browserDebug/index.js b/3-UsingAPIs/Week2/assignment/ex6-browserDebug/index.js index 91e0402be..c1000ef11 100644 --- a/3-UsingAPIs/Week2/assignment/ex6-browserDebug/index.js +++ b/3-UsingAPIs/Week2/assignment/ex6-browserDebug/index.js @@ -27,13 +27,31 @@ function addTableRow(table, label, value) { } function renderLaureate(ul, { knownName, birth, death }) { + console.log('Rendering laureate:', knownName.en); const li = createAndAppend('li', ul); const table = createAndAppend('table', li); addTableRow(table, 'Name', knownName.en); - addTableRow(table, 'Birth', `${birth.date}, ${birth.place.locationString}`); - addTableRow(table, 'Death', `${death.date}, ${death.place.locationString}`); + if (birth) { + addTableRow( + table, + 'Birth', + `${birth?.date || 'Unknown'}, ${birth?.place?.locationString || 'Unknown'}` + ); + } else { + addTableRow(table, 'Birth', 'Unknown'); + console.warn(`${knownName.en} has no birth data`); + } + if (death) { + addTableRow( + table, + 'Death', + `${death?.date || 'Unknown'}, ${death?.place?.locationString || 'Unknown'}` + ); + } else { + addTableRow(table, 'Death', 'still alive'); + console.warn(`${knownName.en} is still alive`); + } } - function renderLaureates(laureates) { const ul = createAndAppend('ul', document.body); laureates.forEach((laureate) => renderLaureate(ul, laureate)); @@ -41,10 +59,17 @@ function renderLaureates(laureates) { async function fetchAndRender() { try { - const laureates = getData( + const data = await getData( 'https://api.nobelprize.org/2.0/laureates?birthCountry=Netherlands&format=json&csvLang=en' ); - renderLaureates(laureates); + console.log('Data received from API:', data); + if (!data.laureates || !Array.isArray(data.laureates)) { + throw new Error('No laureates found in the response'); + } + + console.log('Laureates array:', data.laureates); + + renderLaureates(data.laureates); } catch (err) { console.error(`Something went wrong: ${err.message}`); } diff --git a/3-UsingAPIs/Week2/typescript/ex3-rollAnAce.ts b/3-UsingAPIs/Week2/typescript/ex3-rollAnAce.ts index a8bb4ac9f..6da9d4dc0 100644 --- a/3-UsingAPIs/Week2/typescript/ex3-rollAnAce.ts +++ b/3-UsingAPIs/Week2/typescript/ex3-rollAnAce.ts @@ -14,21 +14,28 @@ import { DieFace, rollDie } from './pokerDiceRoller.js'; /** * Rolls a die until the desired value is rolled. */ -export function rollDieUntil(desiredValue: DieFace): Promise { - return rollDie().then((value) => { - if (value !== desiredValue) { - return rollDieUntil(desiredValue); +export async function rollDieUntil(desiredValue: DieFace): Promise { + let value: DieFace; + while (true) { + try { + value = await rollDie(); + if (value === desiredValue) { + return value; + } + } catch (error) { + throw error; } - return value; - }); + } } -function main() { - rollDieUntil('ACE') - .then((results) => console.log('Resolved!', results)) - .catch((error) => console.log('Rejected!', error.message)); +async function main() { + try { + const result = await rollDieUntil('ACE'); + console.log('Resolved!', result); + } catch (error: any) { + console.log('Rejected!', error.message); + } } - // ! Do not change or remove the code below if (process.env.NODE_ENV !== 'test') { main();