From a84811bfae9a8fb07d8f94c73359a5666ae217dd Mon Sep 17 00:00:00 2001 From: shree-77 Date: Thu, 26 Oct 2023 11:56:23 +0530 Subject: [PATCH 1/3] Fetch time optimised --- .../assets/Recipe-Hub-logo-bg.svg | 0 .../favicon/android-chrome-192x192.png | Bin .../favicon/android-chrome-512x512.png | Bin .../favicon/apple-touch-icon.png | Bin .../favicon/favicon-16x16.png | Bin .../favicon/favicon-32x32.png | Bin .../favicon/favicon.ico | Bin .../favicon/site.webmanifest | 0 {Food Receipe => Food-Recipe}/index.html | 0 {Food Receipe => Food-Recipe}/index.js | 240 ++++++++++++------ {Food Receipe => Food-Recipe}/styles.css | 0 11 files changed, 160 insertions(+), 80 deletions(-) rename {Food Receipe => Food-Recipe}/assets/Recipe-Hub-logo-bg.svg (100%) rename {Food Receipe => Food-Recipe}/favicon/android-chrome-192x192.png (100%) rename {Food Receipe => Food-Recipe}/favicon/android-chrome-512x512.png (100%) rename {Food Receipe => Food-Recipe}/favicon/apple-touch-icon.png (100%) rename {Food Receipe => Food-Recipe}/favicon/favicon-16x16.png (100%) rename {Food Receipe => Food-Recipe}/favicon/favicon-32x32.png (100%) rename {Food Receipe => Food-Recipe}/favicon/favicon.ico (100%) rename {Food Receipe => Food-Recipe}/favicon/site.webmanifest (100%) rename {Food Receipe => Food-Recipe}/index.html (100%) rename {Food Receipe => Food-Recipe}/index.js (57%) rename {Food Receipe => Food-Recipe}/styles.css (100%) diff --git a/Food Receipe/assets/Recipe-Hub-logo-bg.svg b/Food-Recipe/assets/Recipe-Hub-logo-bg.svg similarity index 100% rename from Food Receipe/assets/Recipe-Hub-logo-bg.svg rename to Food-Recipe/assets/Recipe-Hub-logo-bg.svg diff --git a/Food Receipe/favicon/android-chrome-192x192.png b/Food-Recipe/favicon/android-chrome-192x192.png similarity index 100% rename from Food Receipe/favicon/android-chrome-192x192.png rename to Food-Recipe/favicon/android-chrome-192x192.png diff --git a/Food Receipe/favicon/android-chrome-512x512.png b/Food-Recipe/favicon/android-chrome-512x512.png similarity index 100% rename from Food Receipe/favicon/android-chrome-512x512.png rename to Food-Recipe/favicon/android-chrome-512x512.png diff --git a/Food Receipe/favicon/apple-touch-icon.png b/Food-Recipe/favicon/apple-touch-icon.png similarity index 100% rename from Food Receipe/favicon/apple-touch-icon.png rename to Food-Recipe/favicon/apple-touch-icon.png diff --git a/Food Receipe/favicon/favicon-16x16.png b/Food-Recipe/favicon/favicon-16x16.png similarity index 100% rename from Food Receipe/favicon/favicon-16x16.png rename to Food-Recipe/favicon/favicon-16x16.png diff --git a/Food Receipe/favicon/favicon-32x32.png b/Food-Recipe/favicon/favicon-32x32.png similarity index 100% rename from Food Receipe/favicon/favicon-32x32.png rename to Food-Recipe/favicon/favicon-32x32.png diff --git a/Food Receipe/favicon/favicon.ico b/Food-Recipe/favicon/favicon.ico similarity index 100% rename from Food Receipe/favicon/favicon.ico rename to Food-Recipe/favicon/favicon.ico diff --git a/Food Receipe/favicon/site.webmanifest b/Food-Recipe/favicon/site.webmanifest similarity index 100% rename from Food Receipe/favicon/site.webmanifest rename to Food-Recipe/favicon/site.webmanifest diff --git a/Food Receipe/index.html b/Food-Recipe/index.html similarity index 100% rename from Food Receipe/index.html rename to Food-Recipe/index.html diff --git a/Food Receipe/index.js b/Food-Recipe/index.js similarity index 57% rename from Food Receipe/index.js rename to Food-Recipe/index.js index 0ffc14e..4d7b6dc 100644 --- a/Food Receipe/index.js +++ b/Food-Recipe/index.js @@ -21,10 +21,20 @@ document.addEventListener("DOMContentLoaded", () => { const API_KEY = "c0ceab46e0msh0eadabf65682e61p12dd5ejsnbcab6b2c9a32"; -// Fetching AutoComplete the User input -async function Autocomplete(recipeName) { + const RATE_LIMIT = 5; // Requests per second + +const fetchQueue = []; // Queue to manage fetch requests +async function executeFetchQueue() { + while (fetchQueue.length > 0) { + const { recipeName, originalName } = fetchQueue.shift(); + await fetchThumbnailVideoDescription(recipeName, originalName); + await new Promise((resolve) => setTimeout(resolve, 1000 / RATE_LIMIT)); + } +} + // Fetching AutoComplete the User input +async function Autocomplete(recipeName) { // //by Andrei : ot make it easy to add elements and check styling. Will require commenting (overriding) out actual APi functionality. DO NOT DELETE // if (localStorage['resultForLS']) { // fetchThumbnailVideoDescription('chicken breast') @@ -36,26 +46,23 @@ async function Autocomplete(recipeName) { method: "GET", headers: { "X-RapidAPI-Key": API_KEY, - "X-RapidAPI-Host": "tasty.p.rapidapi.com" - } + "X-RapidAPI-Host": "tasty.p.rapidapi.com", + }, }; try { const response = await fetch(url, options); const result = await response.json(); - console.log(result) - let firstResultFetched = false; // 1 result is enough for now -testing purpose + console.log(result); + fetchQueue.length = 0; // Clear the fetchQueue for (const element of result.results) { if (element.display.toLowerCase() !== recipeName.toLowerCase()) { - if (firstResultFetched) { - break; - } - await new Promise((resolve) => setTimeout(resolve, 1000)); // 1-second delay - fetchThumbnailVideoDescription(element.display); - firstResultFetched = true; + fetchQueue.push({ recipeName: element.display, originalName: recipeName }); } } + + executeFetchQueue(); // Start processing the fetch queue } catch (error) { console.error(error); } @@ -81,21 +88,70 @@ async function fetchThumbnailVideoDescription(recipeName) { } const data = await response.json(); - console.log(data) + console.log(data.results[0]) if (Array.isArray(data.results) && data.results.length > 0) { const thumbnail = data.results[0].thumbnail_url; const video_url = data.results[0].original_video_url; const description = data.results[0].description; - - createRecipe(recipeName, thumbnail, video_url, description); - - - const resultForLS = { //can comment out once LS is set - 'recipeName': recipeName, - 'thumbnail': thumbnail, - 'video_url': video_url, - 'description': description + const countryTag = () => { + let result = '' + data.results[0]?.tags.filter((entry) => { + if (entry.root_tag_type === 'cuisine' && entry.display_name !== 'Cuisine') + result += entry.display_name + }); + return result + } + const rating = Math.ceil(data.results[0].user_ratings.score * 5) + const yields = data.results[0].yields + const cookTime = data.results[0]?.total_time_tier?.display_tier + const instructionsTag = data.results[0]?.instructions + const nutrition = () => { + const obj = data.results[0]?.nutrition + console.log(obj) + let temp = '' + let result = '' + if (Object.keys(obj).length > 0) { + for (const key in obj) { + if (obj.hasOwnProperty(key) && key !== 'updated_at') { + temp += `${key}: ${obj[key]}, `; + } + } + temp.slice(0, -2).split(',').forEach(item => { + result += `
  • ${item}
  • ` + }) + } + return result } + const difficultyTag = () => { + const master = data.results[0]?.tags; + const filteredDifficultyTags = master.filter((entry) => { + return ( + entry.root_tag_type === 'difficulty' && + (entry.display_name === 'Easy' || + entry.display_name === 'Medium' || + entry.display_name === 'Difficult' || + entry.display_name === 'Hard') + ); + }); + const result = filteredDifficultyTags.map((entry) => entry.display_name); + return result; + }; + + createRecipe(recipeName, thumbnail, video_url, description, countryTag, rating, cookTime, yields, instructionsTag, nutrition, difficultyTag); + + + // const resultForLS = { //can comment out once LS is set + // 'recipeName': recipeName, + // 'thumbnail': thumbnail, + // 'video_url': video_url, + // 'description': description, + // 'country': countryTag, + // 'rating': rating, + // 'yields': yields, + // 'cookTime': cookTime + // } + // localStorage.setItem('resultForLS', JSON.stringify(resultForLS)) + } else { console.error("No results found in thumbnail API for:", recipeName); } @@ -105,19 +161,22 @@ async function fetchThumbnailVideoDescription(recipeName) { // // by Andrei : to make it easy to add elements and check styling. Will require commenting (overriding) out actual API functionality. // // by Andrei: set LS for faster display of search result (mock result will aways display 'chicken') DO NOT DELETE - // if (!localStorage['resultForLS']) { - // localStorage.setItem('resultForLS', JSON.stringify(resultForLS)) - // } else { console.log('exists') } - - // const fromLS = JSON.parse(localStorage['resultForLS']) - // console.log(fromLS) - // createRecipe(fromLS['recipeName'], fromLS['thumbnail'], fromLS['video_url'], fromLS['description']); - // //END + // if (!localStorage['resultForLS']) { + // localStorage.setItem('resultForLS', JSON.stringify(resultForLS)) + // } else { console.log('exists') } + + // const fromLS = JSON.parse(localStorage['resultForLS']) + // console.log(fromLS) + // createRecipe(fromLS['recipeName'], fromLS['thumbnail'], fromLS['video_url'], fromLS['description']); + // const dataMea = JSON.parse(localStorage.getItem('entire data')) + // console.log(dataMea.results[0].yields) + // //END + } //Creating the dynamic receipe content box -function createRecipe(recipeName, img_url, video_url, description) { +function createRecipe(recipeName, img_url, video_url, description, countryTag, rating, cookTime, yields, instructionsTag, nutrition, difficultyTag) { const box = document.createElement("div"); const resultIntro = document.createElement("div"); resultIntro.classList.add("results__result--intro"); @@ -133,7 +192,7 @@ function createRecipe(recipeName, img_url, video_url, description) { img.src = img_url; button.addEventListener('click', () => { - addDialog(recipeName, img_url, video_url, description); + addDialog(recipeName, img_url, video_url, description, countryTag, rating, cookTime, yields, instructionsTag, nutrition, difficultyTag); }); @@ -163,10 +222,13 @@ function Capitalize(name) { return result } + + + // Function for view Recipe button -function addDialog(name, url, video_url, description) { - const dialogbox = document.createElement('dialog'); - dialogbox.classList.add('modal'); +function addDialog(name, url, video_url, description, countryTag, rating, cookTime, yields, instructionsTag, nutrition, difficultyTag) { + const modal = document.createElement('div'); + modal.classList.add('modal'); const close = document.createElement('button'); close.classList.add('modal__close'); @@ -185,30 +247,30 @@ function addDialog(name, url, video_url, description) { list.classList.add('modal__tags') const country = document.createElement('li') - country.textContent = 'to be decided'.toUpperCase() + country.textContent = countryTag() + + const difficulty = document.createElement('li') + difficulty.textContent += `Difficulty: ${difficultyTag()}` const stars = document.createElement('li') stars.classList.add('modal-tag__rating') stars.innerHTML = '' - list.append(country, stars) + list.append(country, difficulty, stars) const info = document.createElement('div') info.classList.add('modal__info') - const servings = document.createElement('div') - const servingTitle = document.createElement('h4') - servingTitle.textContent = 'Servings: ' - const servingNumber = document.createElement('p') - servingNumber.textContent = '100?' + const servings = document.createElement('h4') + servings.textContent = yields const timeInfo = document.createElement('div') const timeTitle = document.createElement('h4') - timeTitle.textContent = 'Cook Time: ' + timeTitle.textContent = 'Cooking Time: ' const timeNumber = document.createElement('p') - timeNumber.textContent = '100?' - servings.append(servingTitle, servingNumber) + timeNumber.textContent = cookTime + timeInfo.append(timeTitle, timeNumber) info.append(servings, timeInfo) @@ -222,9 +284,24 @@ function addDialog(name, url, video_url, description) { const instructionsTitle = document.createElement('h4') instructionsTitle.textContent = 'Instructions: ' - const instructionsText = document.createElement('p'); + const instructionsText = document.createElement('ol'); instructionsText.classList.add('modal__instructions'); - instructionsText.textContent = description; + instructionsText.innerHTML = getInstructions(instructionsTag); + + function getInstructions(data) { + + result = '' + for (let i = 0; i < data.length; i++) { + result += ` +
  • + ${data[i].display_text} +
  • +` + } + return result + } + + const linkContainer = document.createElement('div') linkContainer.classList.add('modal__btn-wrapper') @@ -239,37 +316,41 @@ function addDialog(name, url, video_url, description) { details.classList.add('modal__nutrition') const summary = document.createElement('summary') summary.textContent = 'Nutrition Information' - const para = document.createElement('p') - para.textContent = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolo in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim' - details.append(summary, para) + const nutritionList = document.createElement('ul') + + nutritionList.innerHTML = nutrition() + + details.append(summary, nutritionList) //Need to work on other things to display. - dialogbox.append(close, mealName, mealImage); - dialogbox.append(list, info) - dialogbox.append(ingredientsTitle, ingredientsText); - dialogbox.append(instructionsTitle, instructionsText); - dialogbox.append(linkContainer, details); + modal.append(close, mealName, mealImage); + modal.append(list, info) + modal.append(ingredientsTitle, ingredientsText); + modal.append(instructionsTitle, instructionsText); + modal.append(linkContainer, details); - document.body.appendChild(dialogbox); - dialogbox.showModal(); + document.querySelector('.results-section').appendChild(modal); + modal.style.display = 'block'; close.addEventListener('click', function () { - dialogbox.close(); - document.body.removeChild(dialogbox); + document.querySelector('.results-section').removeChild(modal); }); - // // //by Andrei: to properly dispose of the dialog element on Escape key press//but it doesn't work - // document.body.addEventListener('keypress', (e) => { - // if (e.key === 'Escape') { - // dialogbox.close(); - // document.body.removeChild(dialogbox); - // } - // }) - - colorStars(Math.ceil(Math.random() * 5)) + //by Andrei: to properly dispose of the dialog element on Escape key press + //works, but throws an exception + document.body.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + try { + document.querySelector('.results-section').removeChild(modal); + } catch (error) { + console.error("Caught an exception:", error); + } + } + }) + colorStars(rating) } @@ -283,16 +364,6 @@ function clearResults() { } } -//by Andrei : to see the styling changes we make to the modal -const modal = document.querySelector('.modal') -const openModal = document.querySelector('.result__get-recipe') -const closeModal = document.querySelector('.modal__close') -closeModal.addEventListener('click', () => modal.style.display = 'none') -openModal.addEventListener('click', () => modal.style.display = 'block') - - - - function colorStars(score) { for (let i = 1; i <= 5; i++) { const star = document.querySelector(`.fa-star:nth-child(${i})`); @@ -300,8 +371,17 @@ function colorStars(score) { star.style.color = 'rgb(255, 196, 0)'; } } - console.log(score) + console.log('the modal should display:', score, 'stars') } -//static modal functionality + + +//by Andrei : static modal functionality + +//by Andrei : to see the styling changes we make to the modal +const modal = document.querySelector('.modal') +const openModal = document.querySelector('.result__get-recipe') +const closeModal = document.querySelector('.modal__close') +closeModal.addEventListener('click', () => modal.style.display = 'none') +openModal.addEventListener('click', () => modal.style.display = 'block') \ No newline at end of file diff --git a/Food Receipe/styles.css b/Food-Recipe/styles.css similarity index 100% rename from Food Receipe/styles.css rename to Food-Recipe/styles.css From b665217cba28b2f08086364382dcfb20fd39b8c3 Mon Sep 17 00:00:00 2001 From: shree-77 Date: Thu, 26 Oct 2023 12:07:42 +0530 Subject: [PATCH 2/3] ESC key bug fixed --- Food-Recipe/index.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Food-Recipe/index.js b/Food-Recipe/index.js index 4d7b6dc..0ec9094 100644 --- a/Food-Recipe/index.js +++ b/Food-Recipe/index.js @@ -342,14 +342,18 @@ function addDialog(name, url, video_url, description, countryTag, rating, cookTi //by Andrei: to properly dispose of the dialog element on Escape key press //works, but throws an exception document.body.addEventListener('keydown', (e) => { - if (e.key === 'Escape') { - try { - document.querySelector('.results-section').removeChild(modal); - } catch (error) { - console.error("Caught an exception:", error); + if (e.key === 'Escape') { + try { + const resultsSection = document.querySelector('.results-section'); + if (resultsSection.contains(modal)) { + resultsSection.removeChild(modal); } + } catch (error) { + console.error("Caught an exception:", error); } - }) + } +}); + colorStars(rating) } From 3b02d2e6d553f60a44310f6bca99e58f8bbba494 Mon Sep 17 00:00:00 2001 From: andreimaier <113696878+andreimaier@users.noreply.github.com> Date: Thu, 26 Oct 2023 21:39:26 +0800 Subject: [PATCH 3/3] Update index.js --- Food-Recipe/index.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Food-Recipe/index.js b/Food-Recipe/index.js index 5ba4c75..94b310d 100644 --- a/Food-Recipe/index.js +++ b/Food-Recipe/index.js @@ -32,7 +32,7 @@ async function executeFetchQueue() { await new Promise((resolve) => setTimeout(resolve, 1000 / RATE_LIMIT)); } } - // Fetching AutoComplete the User input +// Fetching AutoComplete the User input async function Autocomplete(recipeName) { // //by Andrei : ot make it easy to add elements and check styling. Will require commenting (overriding) out actual APi functionality. DO NOT DELETE // if (localStorage['resultForLS']) { @@ -96,7 +96,7 @@ async function fetchThumbnailVideoDescription(recipeName) { let result = '' data.results[0]?.tags.filter((entry) => { if (entry.root_tag_type === 'cuisine' && entry.display_name !== 'Cuisine') - result += entry.display_name + result += `${entry.display_name} ` }); return result } @@ -340,17 +340,17 @@ function addDialog(name, url, video_url, description, countryTag, rating, cookTi //by Andrei: to properly dispose of the dialog element on Escape key press //works, but throws an exception document.body.addEventListener('keydown', (e) => { - if (e.key === 'Escape') { - try { - const resultsSection = document.querySelector('.results-section'); - if (resultsSection.contains(modal)) { - resultsSection.removeChild(modal); + if (e.key === 'Escape') { + try { + const resultsSection = document.querySelector('.results-section'); + if (resultsSection.contains(modal)) { + resultsSection.removeChild(modal); + } + } catch (error) { + console.error("Caught an exception:", error); } - } catch (error) { - console.error("Caught an exception:", error); } - } -}); + }); colorStars(rating) }