├── .gitignore ├── intro.png ├── photo.png ├── src ├── assets │ ├── logo.png │ └── restau.png ├── modules │ ├── counter.test.js │ └── functions.js ├── index.html ├── index.js └── style.css ├── babel.config.js ├── dist ├── assets │ └── logo-a8be307ad975a70883e3.png ├── index.html └── main.js ├── .hintrc ├── .stylelintrc.json ├── .eslintrc.json ├── webpack.config.js ├── LICENSE ├── package.json ├── .github └── workflows │ └── linters.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | usefulCommands.txt 4 | 5 | coverage 6 | -------------------------------------------------------------------------------- /intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/momo-87/JS-capstone-project/HEAD/intro.png -------------------------------------------------------------------------------- /photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/momo-87/JS-capstone-project/HEAD/photo.png -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/momo-87/JS-capstone-project/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/restau.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/momo-87/JS-capstone-project/HEAD/src/assets/restau.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [['@babel/preset-env', { targets: { node: 'current' } }]], 3 | }; -------------------------------------------------------------------------------- /dist/assets/logo-a8be307ad975a70883e3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/momo-87/JS-capstone-project/HEAD/dist/assets/logo-a8be307ad975a70883e3.png -------------------------------------------------------------------------------- /.hintrc: -------------------------------------------------------------------------------- 1 | { 2 | "connector": { 3 | "name": "local", 4 | "options": { 5 | "pattern": ["**", "!.git/**", "!node_modules/**"] 6 | } 7 | }, 8 | "extends": ["development"], 9 | "formatters": ["stylish"], 10 | "hints": [ 11 | "button-type", 12 | "disown-opener", 13 | "html-checker", 14 | "meta-charset-utf-8", 15 | "meta-viewport", 16 | "no-inline-styles:error" 17 | ] 18 | } -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["stylelint-config-standard"], 3 | "plugins": ["stylelint-scss", "stylelint-csstree-validator"], 4 | "rules": { 5 | "at-rule-no-unknown": null, 6 | "scss/at-rule-no-unknown": [ 7 | true, 8 | { 9 | "ignoreAtRules": [ 10 | "tailwind", 11 | "apply", 12 | "variants", 13 | "responsive", 14 | "screen" 15 | ] 16 | } 17 | ] 18 | }, 19 | "csstree/validator": true, 20 | "ignoreFiles": ["build/**", "dist/**", "**/reset*.css", "**/bootstrap*.css"] 21 | } 22 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "jest": true 6 | }, 7 | "parser": "babel-eslint", 8 | "parserOptions": { 9 | "ecmaVersion": 2018, 10 | "sourceType": "module" 11 | }, 12 | "extends": ["airbnb-base"], 13 | "rules": { 14 | "max-classes-per-file": 0, 15 | "no-shadow": "off", 16 | "no-param-reassign": "off", 17 | "eol-last": "off", 18 | "import/extensions": [ 1, { 19 | "js": "always", "json": "always" 20 | }] 21 | }, 22 | "ignorePatterns": [ 23 | "dist/", 24 | "build/" 25 | ] 26 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | 4 | module.exports = { 5 | mode: 'development', 6 | entry: './src/index.js', 7 | devServer: { 8 | static: './dist', 9 | }, 10 | plugins: [ 11 | new HtmlWebpackPlugin({ 12 | template: './src/index.html', 13 | }), 14 | ], 15 | output: { 16 | filename: 'main.js', 17 | path: path.resolve(__dirname, 'dist'), 18 | clean: true, 19 | }, 20 | module: { 21 | rules: [ 22 | { 23 | test: /\.css$/i, 24 | use: ['style-loader', 'css-loader'], 25 | }, 26 | { 27 | test: /\.html$/i, 28 | use: 'html-loader', 29 | }, 30 | { 31 | test: /\.(png|jpg|gif|svg|eot|ttf|woff)$/i, 32 | type: 'asset/resource', 33 | generator: { 34 | filename: 'assets/[name]-[hash][ext]', 35 | }, 36 | }, 37 | ], 38 | }, 39 | }; -------------------------------------------------------------------------------- /src/modules/counter.test.js: -------------------------------------------------------------------------------- 1 | // import the counter function 2 | import { counter } from './functions.js'; 3 | 4 | const MOCK_DATA = { 5 | meals: 6 | [ 7 | { idMeal: 1, meal: 'Eru', ingredients: 'ingred1, ingred2, ingred3' }, 8 | { idMeal: 2, meal: 'Ndolès', ingredients: 'ingred1, ingred2, ingred3' }, 9 | { idMeal: 3, meal: 'Achu', ingredients: 'ingred1, ingred2, ingred3' }, 10 | { idMeal: 4, meal: 'Koki', ingredients: 'ingred1, ingred2, ingred3' }, 11 | { idMeal: 5, meal: 'Okok', ingredients: 'ingred1, ingred2, ingred3' }, 12 | ], 13 | }; 14 | const MOCK_NB_OF_ITEMS = MOCK_DATA.meals.length; 15 | // Mock the fetch call 16 | global.fetch = jest.fn(() => Promise.resolve({ 17 | json: () => Promise.resolve(MOCK_DATA), 18 | })); 19 | 20 | describe('Testing counter function', () => { 21 | test('The correct number of items should be returned', async () => { 22 | const nbOfItems = await counter(); 23 | expect(fetch).toHaveBeenCalledTimes(1); 24 | expect(nbOfItems).toBe(MOCK_NB_OF_ITEMS); 25 | }); 26 | }); -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | API-Perso 9 | 10 | 11 |
12 |
13 | 18 |
19 |
20 | 21 |
22 | 23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Christian Romuald MOMO TONFACK 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | API-Perso 11 | 12 | 13 |
14 |
15 | 20 |
21 |
22 | 23 |
24 | 25 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "repository": { 3 | "url": "https://github.com/momo-87/JS-capstone-project.git" 4 | }, 5 | "name": "js-capstone-project", 6 | "version": "1.0.0", 7 | "description": "", 8 | "private": true, 9 | "scripts": { 10 | "test": "jest --coverage", 11 | "build": "webpack", 12 | "start": "webpack serve --open", 13 | "predeploy": "npm run build", 14 | "deploy": "gh-pages -d dist" 15 | }, 16 | "keywords": [], 17 | "author": "", 18 | "license": "ISC", 19 | "devDependencies": { 20 | "@babel/core": "^7.21.8", 21 | "@babel/preset-env": "^7.21.5", 22 | "@types/jest": "^29.5.1", 23 | "babel-eslint": "^10.1.0", 24 | "babel-jest": "^29.5.0", 25 | "css-loader": "^6.7.4", 26 | "eslint": "^7.32.0", 27 | "eslint-config-airbnb-base": "^14.2.1", 28 | "eslint-plugin-import": "^2.27.5", 29 | "gh-pages": "^5.0.0", 30 | "hint": "^7.1.8", 31 | "html-loader": "^4.2.0", 32 | "html-webpack-plugin": "^5.5.1", 33 | "jest": "^29.5.0", 34 | "style-loader": "^3.3.3", 35 | "stylelint": "^13.13.1", 36 | "stylelint-config-standard": "^21.0.0", 37 | "stylelint-csstree-validator": "^1.9.0", 38 | "stylelint-scss": "^3.21.0", 39 | "ts-jest": "^29.1.0", 40 | "typescript": "^5.0.4", 41 | "webpack": "^5.83.1", 42 | "webpack-cli": "^5.1.1", 43 | "webpack-dev-server": "^4.15.0" 44 | }, 45 | "dependencies": { 46 | "axios": "^1.4.0" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /.github/workflows/linters.yml: -------------------------------------------------------------------------------- 1 | name: Linters 2 | 3 | on: pull_request 4 | 5 | env: 6 | FORCE_COLOR: 1 7 | 8 | jobs: 9 | lighthouse: 10 | name: Lighthouse 11 | runs-on: ubuntu-22.04 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: actions/setup-node@v3 15 | with: 16 | node-version: "18.x" 17 | - name: Setup Lighthouse 18 | run: npm install -g @lhci/cli@0.11.x 19 | - name: Lighthouse Report 20 | run: lhci autorun --upload.target=temporary-public-storage --collect.staticDistDir=. 21 | webhint: 22 | name: Webhint 23 | runs-on: ubuntu-22.04 24 | steps: 25 | - uses: actions/checkout@v3 26 | - uses: actions/setup-node@v3 27 | with: 28 | node-version: "18.x" 29 | - name: Setup Webhint 30 | run: | 31 | npm install --save-dev hint@7.x 32 | [ -f .hintrc ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.hintrc 33 | - name: Webhint Report 34 | run: npx hint . 35 | stylelint: 36 | name: Stylelint 37 | runs-on: ubuntu-22.04 38 | steps: 39 | - uses: actions/checkout@v3 40 | - uses: actions/setup-node@v3 41 | with: 42 | node-version: "18.x" 43 | - name: Setup Stylelint 44 | run: | 45 | npm install --save-dev stylelint@13.x stylelint-scss@3.x stylelint-config-standard@21.x stylelint-csstree-validator@1.x 46 | [ -f .stylelintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.stylelintrc.json 47 | - name: Stylelint Report 48 | run: npx stylelint "**/*.{css,scss}" 49 | eslint: 50 | name: ESLint 51 | runs-on: ubuntu-22.04 52 | steps: 53 | - uses: actions/checkout@v3 54 | - uses: actions/setup-node@v3 55 | with: 56 | node-version: "18.x" 57 | - name: Setup ESLint 58 | run: | 59 | npm install --save-dev eslint@7.x eslint-config-airbnb-base@14.x eslint-plugin-import@2.x babel-eslint@10.x 60 | [ -f .eslintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.eslintrc.json 61 | - name: ESLint Report 62 | run: npx eslint . 63 | nodechecker: 64 | name: node_modules checker 65 | runs-on: ubuntu-22.04 66 | steps: 67 | - uses: actions/checkout@v3 68 | - name: Check node_modules existence 69 | run: | 70 | if [ -d "node_modules/" ]; then echo -e "\e[1;31mThe node_modules/ folder was pushed to the repo. Please remove it from the GitHub repository and try again."; echo -e "\e[1;32mYou can set up a .gitignore file with this folder included on it to prevent this from happening in the future." && exit 1; fi 71 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // import style from style.css file (required) 2 | import './style.css'; 3 | 4 | // import the required functions from module 5 | import { 6 | getMealData, populatedishes, addLike, getLikesData, diplayLikes, counter, diplayNumberOfItems, 7 | PopupContent, errorMsg, addComment, getCommentData, populateComments, commentcounter, 8 | diplayNumberOfComments, 9 | } from './modules/functions.js'; 10 | 11 | // Getting data from the theMealDB API 12 | const mealData = await getMealData(); 13 | 14 | // Getting data from the Involvement API function 15 | const likesData = await getLikesData(); 16 | 17 | // Populating items in the home page 18 | populatedishes(mealData); 19 | 20 | // Getting and diplaying the number of items 21 | const nbOfItems = await counter(); 22 | diplayNumberOfItems(nbOfItems); 23 | 24 | // Diplaying likes data in the home page 25 | mealData.forEach((element) => { 26 | diplayLikes(likesData, `M${element.idMeal}`); 27 | }); 28 | 29 | const foodListSection = document.querySelector('.food-list'); 30 | // Add event listener to the like icon and open comment button 31 | foodListSection.addEventListener('click', async (e) => { 32 | e.preventDefault(); 33 | if (e.target && e.target.matches('i.heart')) { 34 | const targetId = e.target.id; 35 | await addLike(targetId); 36 | const likesData = await getLikesData(); 37 | diplayLikes(likesData, targetId); 38 | } else if (e.target && e.target.matches('button.comment')) { 39 | const targetId = e.target.id; 40 | const idMeal = targetId.replace('CBtn', ''); 41 | PopupContent(mealData, idMeal); 42 | 43 | // We need to use the prefix M because we initially used it to post likes in the API 44 | const itemId = targetId.replace('CBtn', 'M'); 45 | 46 | // Getting and displaying the number of comments 47 | const nbComments = await commentcounter(itemId); 48 | diplayNumberOfComments(nbComments); 49 | 50 | // Get comment the corresponding comment data from the API 51 | const commentData = await getCommentData(itemId); 52 | 53 | // Populate comment data in the popup window after checking that data is not empty 54 | if (commentData.length) { 55 | populateComments(commentData); 56 | } 57 | 58 | // Add event listener to the submit comment button 59 | const submitCommentBtn = document.querySelector('button.submit-comment'); 60 | submitCommentBtn.addEventListener('click', async (e) => { 61 | e.preventDefault(); 62 | const userName = document.querySelector('input.user-name').value; 63 | const insights = document.querySelector('textarea.insights').value; 64 | if (!userName || !insights) { 65 | errorMsg(userName, insights); 66 | } 67 | await addComment(itemId, userName, insights); 68 | document.querySelector('input.user-name').value = ''; 69 | document.querySelector('textarea.insights').value = ''; 70 | 71 | // Clean the board 72 | document.querySelector('div.comments-box').innerHTML = ''; 73 | // Gettint the updated comment data from the API and populate 74 | const commentData = await getCommentData(itemId); 75 | // Repopulate using the updated comment data 76 | populateComments(commentData); 77 | 78 | // Getting and displaying the number of comments 79 | const nbComments = await commentcounter(itemId); 80 | diplayNumberOfComments(nbComments); 81 | }); 82 | } 83 | }); 84 | 85 | // Add event listener to close popup icon 86 | const popupWindow = document.querySelector('.popup-window'); 87 | popupWindow.addEventListener('click', (e) => { 88 | if (e.target && e.target.matches('i.close-popup')) { 89 | popupWindow.innerHTML = ''; 90 | } 91 | }); 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |
3 | photo 4 | logo 5 |
6 | 7 |

API-based Webapp (Resraurant)

8 |
9 |
10 | screenshot 11 |
12 | 13 | # 📗 Table of Contents 14 | 15 | - [📖 About the Project](#about-project) 16 | - [🛠 Built With](#built-with) 17 | - [Tech Stack](#tech-stack) 18 | - [Key Features](#key-features) 19 | - [🚀 Live Demo](#live-demo) 20 | - [💻 Getting Started](#getting-started) 21 | - [Setup](#setup) 22 | - [Prerequisites](#prerequisites) 23 | - [Install](#install) 24 | - [Usage](#usage) 25 | - [Run tests](#run-tests) 26 | - [Deployment](#triangular_flag_on_post-deployment) 27 | - [👥 Authors](#authors) 28 | - [🔭 Future Features](#future-features) 29 | - [🤝 Contributing](#contributing) 30 | - [⭐️ Show your support](#support) 31 | - [🙏 Acknowledgements](#acknowledgements) 32 | - [❓ FAQ (OPTIONAL)](#faq) 33 | - [📝 License](#license) 34 | 35 |
36 | 37 | # 📖 API-based Webapp(Restaurant) 38 | > The Restaurant web application is based on an external API. We used JavaScript to make the websites dynamic and build a basic single-page app. The application has three user interfaces: A home page showing a list of dishes that a user can "like", a popup window with more data about a dish that a user can leave a comment and a popup window with more data about a dish that a user can use to reserve it for some time. 39 |
40 | 41 | ## 🛠 Built With 42 | - JavaScript 43 | - HTML 44 | - CSS 45 | - Webpack 46 | - Jest for testing 47 | 48 | ### Tech Stack 49 |
50 | Client 51 | 58 |
59 |
60 | API 61 | 65 |
66 |
67 | 68 | ### Key Features 69 | - A home page showing a list of items that a user can "like." 70 | - A popup window with more data about an item that user can use to comment on it. 71 |

(back to top)

72 | 73 | ## 🚀 Live Demo 74 | >[Live Demo](https://momo-87.github.io/JS-capstone-project/) 75 |

(back to top)

76 | 77 | 78 | ## 💻 Getting Started 79 | >To get a local copy up and running, follow these steps. 80 | 81 | ### Prerequisites 82 | 1. Web browser. 83 | 2. Code Editor. 84 | 3. Git-smc. 85 | 86 | ### Setup 87 | > To clone this repository to your desired folder, run this command: 88 | ```sh 89 | cd my-folder 90 | git clone https://github.com/momo-87/JS-capstone-project.git 91 | ``` 92 | 93 | ### Install 94 | > Run this command: 95 | ```sh 96 | cd my-project 97 | npm install 98 | ``` 99 | 100 | ### Usage 101 | > To run the project, open index.html from dist folder using live server extension. 102 | 103 | ### Run tests 104 | > Coming soon 105 | 106 | ### Deployment 107 | > Published 108 |

(back to top)

109 | 110 | 111 | ## 👥 Author 112 | 👤 Christian Romuald MOMO TONFACK 113 | - GitHub: [@githubhandle](https://github.com/Momo-87) 114 | - Twitter: [@twitterhandle](https://twitter.com/Momo_yde) 115 | - LinkedIn: [LinkedIn](https://www.linkedin.com/in/christian-momo/) 116 |

(back to top)

117 | 118 | 119 | ## 🔭 Future Features 120 | - [ ] A popup window with more data about an item that user can use to reserve it for a period of time. 121 | - [ ] Reservation popup window 122 |

(back to top)

123 | 124 | ## 🤝 Contributing 125 | > Contributions, issues, and feature requests are welcome! 126 | Feel free to check the [issues page](https://github.com/momo-87/JS-capstone-project/issues). 127 |

(back to top)

128 | 129 | 130 | ## ⭐️ Show your support 131 | >If you like this project just give it a star ⭐️. 132 |

(back to top)

133 | 134 | ## 🙏 Acknowledgments 135 | >I would like to thank Microverse comnunity for their supports. 136 |

(back to top)

137 | 138 | ## 📝 License 139 | >This project is [MIT](./LICENSE) licensed. 140 |

(back to top)

141 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | padding: 0; 4 | margin: 0; 5 | color: #2f2c28; 6 | } 7 | 8 | body { 9 | background-color: #d3d3d3; 10 | font-size: 1rem; 11 | } 12 | 13 | .flex-column { 14 | display: flex; 15 | flex-direction: column; 16 | } 17 | 18 | .flex-row { 19 | display: flex; 20 | flex-direction: row; 21 | } 22 | 23 | ul { 24 | list-style: none; 25 | } 26 | 27 | button:hover, 28 | .heart:hover { 29 | cursor: pointer; 30 | } 31 | 32 | @media only screen and (min-width: 320px) { 33 | /* Styling Home page start */ 34 | header { 35 | width: 100%; 36 | justify-content: space-between; 37 | align-items: center; 38 | padding-top: 10px; 39 | position: fixed; 40 | background-color: #8b4513; 41 | } 42 | 43 | .logo-box { 44 | width: 30%; 45 | } 46 | 47 | .logo { 48 | width: 100%; 49 | } 50 | 51 | ul { 52 | width: 65%; 53 | column-gap: 5%; 54 | } 55 | 56 | ul li:nth-child(1) { 57 | text-decoration: underline; 58 | color: #ffffed; 59 | } 60 | 61 | ul li a { 62 | color: #2beb83; 63 | text-decoration: none; 64 | } 65 | 66 | section.food-list { 67 | width: 100%; 68 | padding-top: 60px; 69 | gap: 10px; 70 | } 71 | 72 | .food-card { 73 | width: 90%; 74 | justify-content: center; 75 | margin: 0 5%; 76 | row-gap: 30px; 77 | } 78 | 79 | .image-box { 80 | width: 100%; 81 | } 82 | 83 | .image-box img { 84 | width: 100%; 85 | border-radius: 15px; 86 | } 87 | 88 | .image-box img:hover { 89 | width: 103%; 90 | border-radius: 15px; 91 | } 92 | 93 | .meal-title-and-interactions-box { 94 | margin-top: -30px; 95 | justify-content: space-between; 96 | } 97 | 98 | .meal-title-and-interactions-box h2 { 99 | font-size: 1.2rem; 100 | width: 67%; 101 | } 102 | 103 | .meal-title-and-interactions-box span { 104 | font-size: 1.1rem; 105 | color: #8b4513; 106 | } 107 | 108 | .buttons-box { 109 | justify-content: space-between; 110 | margin-top: -20px; 111 | } 112 | 113 | button { 114 | width: 30%; 115 | } 116 | 117 | /* Styling Home page end */ 118 | 119 | /* Styling popup window start */ 120 | .popup-window { 121 | width: 100%; 122 | position: fixed; 123 | top: 0; 124 | } 125 | 126 | .popup-wrapper { 127 | width: 95%; 128 | position: fixed; 129 | top: 10px; 130 | height: 98%; 131 | background-color: #d3d3d3; 132 | align-items: center; 133 | margin: 0 2.5% 0 2.5%; 134 | border-radius: 20px; 135 | z-index: 10; 136 | overflow-y: auto; 137 | padding-bottom: 20px; 138 | border: 2px solid #cd853f; 139 | } 140 | 141 | i.close-popup:hover { 142 | cursor: pointer; 143 | } 144 | 145 | .popup-wrapper h2 { 146 | font-size: 1.2rem; 147 | } 148 | 149 | h2.add-comment { 150 | margin-top: 30px; 151 | } 152 | 153 | .popup-window i { 154 | margin: 15px 10% 15px 90%; 155 | } 156 | 157 | .meal-section { 158 | width: 100%; 159 | align-items: center; 160 | } 161 | 162 | .popup-image-box { 163 | width: 90%; 164 | align-items: center; 165 | } 166 | 167 | img.popup-img { 168 | width: 100%; 169 | border-radius: 15px; 170 | } 171 | 172 | h2.meal-name { 173 | margin-top: 10px; 174 | } 175 | 176 | .meal-infos { 177 | display: grid; 178 | grid-template-columns: auto auto; 179 | width: 90%; 180 | margin-top: 10px; 181 | } 182 | 183 | .meal-infos span { 184 | font-weight: bolder; 185 | } 186 | 187 | .instruction-box { 188 | grid-column: 1 / span 2; 189 | margin-top: 10px; 190 | text-align: justify; 191 | } 192 | 193 | .comments-section { 194 | display: flex; 195 | margin-top: 30px; 196 | width: 90%; 197 | justify-content: center; 198 | } 199 | 200 | .comments-box p { 201 | font-size: 0.9rem; 202 | margin-top: 5px; 203 | font-style: italic; 204 | } 205 | 206 | .add-comment-section { 207 | width: 100%; 208 | align-items: center; 209 | } 210 | 211 | form.add-comment { 212 | width: 90%; 213 | row-gap: 5px; 214 | } 215 | 216 | input.user-name { 217 | height: 25px; 218 | } 219 | 220 | textarea.insights { 221 | height: 60px; 222 | } 223 | 224 | input.user-name:focus, 225 | textarea.insights:focus { 226 | outline-color: #8b4513; 227 | padding: 3%; 228 | } 229 | 230 | ::placeholder { 231 | padding-left: 2%; 232 | } 233 | 234 | /* Styling popup window end */ 235 | } 236 | 237 | @media only screen and (min-width: 375px) { 238 | header ul { 239 | width: 60%; 240 | column-gap: 5%; 241 | margin-left: 15%; 242 | } 243 | 244 | .meal-title-and-interactions-box h2 { 245 | width: 70%; 246 | } 247 | } 248 | 249 | @media only screen and (min-width: 425px) { 250 | header ul { 251 | width: 60%; 252 | column-gap: 5%; 253 | margin-left: 18%; 254 | } 255 | 256 | section.food-list { 257 | padding-top: 80px; 258 | } 259 | 260 | .meal-title-and-interactions-box h2 { 261 | width: 75%; 262 | } 263 | 264 | button { 265 | width: 20%; 266 | } 267 | } 268 | 269 | @media only screen and (min-width: 768px) { 270 | .logo { 271 | width: 90%; 272 | } 273 | 274 | header ul { 275 | column-gap: 5%; 276 | margin-left: 40%; 277 | } 278 | 279 | section.food-list { 280 | width: 100%; 281 | padding-top: 100px; 282 | display: grid; 283 | grid-template-columns: 49% 49%; 284 | grid-template-columns: auto auto; 285 | } 286 | 287 | button { 288 | width: 25%; 289 | } 290 | 291 | /* Styling popup window start */ 292 | button.submit-comment { 293 | width: 12%; 294 | } 295 | 296 | /* Styling popup window end */ 297 | } 298 | 299 | @media only screen and (min-width: 1024px) { 300 | section.food-list { 301 | width: 100%; 302 | padding-top: 100px; 303 | display: grid; 304 | grid-template-columns: 35% 35% 35%; 305 | grid-template-columns: auto auto auto; 306 | } 307 | 308 | /* Styling popup window start */ 309 | .meal-section { 310 | width: 95%; 311 | flex-direction: row; 312 | column-gap: 2%; 313 | } 314 | 315 | .popup-image-box { 316 | width: 40%; 317 | } 318 | 319 | .add-comment-section { 320 | width: 70%; 321 | } 322 | 323 | /* Styling popup window end */ 324 | } 325 | 326 | @media only screen and (min-width: 1440px) { 327 | section.food-list { 328 | width: 80%; 329 | margin: 0 10%; 330 | } 331 | 332 | .logo-box { 333 | width: 20%; 334 | } 335 | 336 | .logo { 337 | width: 100%; 338 | } 339 | 340 | header ul { 341 | column-gap: 5%; 342 | margin-left: 50%; 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /src/modules/functions.js: -------------------------------------------------------------------------------- 1 | // Getting data from the theMealDB API function 2 | export const getMealData = async () => { 3 | const request = new Request('https://themealdb.com/api/json/v1/1/search.php?f=c'); 4 | const response = await fetch(request); 5 | const data = await response.json(); 6 | return data.meals; 7 | }; 8 | 9 | // Populating items in the DOM function 10 | export const populatedishes = async (mealData) => { 11 | const foodListSection = document.querySelector('.food-list'); 12 | mealData.forEach((element) => { 13 | const foodCard = document.createElement('div'); 14 | foodCard.classList.add('food-card', 'flex-column'); 15 | foodCard.innerHTML = `
meal
16 |
17 |

${element.strMeal}

18 | 0 likes 19 |
20 |
21 | 22 | 23 |
24 |
25 | `; 26 | foodListSection.appendChild(foodCard); 27 | }); 28 | }; 29 | 30 | // Create new app function 31 | export const newApp = async () => { 32 | const request = new Request('https://us-central1-involvement-api.cloudfunctions.net/capstoneApi/apps/'); 33 | await fetch(request, { 34 | method: 'POST', 35 | }); 36 | }; 37 | 38 | // Add likes to API function 39 | export const addLike = async (targetId) => { 40 | const request = new Request('https://us-central1-involvement-api.cloudfunctions.net/capstoneApi/apps/R20mJzx45L3RyqatiuEZ/likes/'); 41 | await fetch(request, { 42 | headers: { 43 | 'Content-type': 'application/json', 44 | }, 45 | method: 'POST', 46 | body: JSON.stringify({ 47 | item_id: targetId, 48 | }), 49 | }); 50 | }; 51 | 52 | // Getting likes data from the Involvement API function 53 | export const getLikesData = async () => { 54 | const request = new Request('https://us-central1-involvement-api.cloudfunctions.net/capstoneApi/apps/R20mJzx45L3RyqatiuEZ/likes/'); 55 | const response = await fetch(request); 56 | const data = await response.json(); 57 | return data; 58 | }; 59 | 60 | // Diplaying likes data in the home page function 61 | export const diplayLikes = async (likesData, itemId) => { 62 | likesData.forEach((element) => { 63 | if (element.item_id === itemId) { 64 | // Replace M from the i tag id by L for obtaining the span id 65 | const likeId = itemId.replace('M', 'L'); 66 | const span = document.querySelector(`#${likeId}`); 67 | span.textContent = `${element.likes} likes`; 68 | } 69 | }); 70 | }; 71 | 72 | // counter meals items function 73 | export const counter = async () => { 74 | const request = new Request('https://themealdb.com/api/json/v1/1/search.php?f=c'); 75 | const response = await fetch(request); 76 | const data = await response.json(); 77 | return data.meals.length; 78 | }; 79 | 80 | // Display the number of meal on the home page function 81 | export const diplayNumberOfItems = (nbOfItems) => { 82 | const li = document.querySelector('li.number-of-items'); 83 | li.textContent = `Meals(${nbOfItems})`; 84 | }; 85 | 86 | // Populating popup window content function 87 | export const PopupContent = (data, id) => { 88 | const popupBox = document.querySelector('.popup-window'); 89 | data.forEach((element) => { 90 | if (element.idMeal === id) { 91 | popupBox.innerHTML = ` 123 | `; 124 | } 125 | }); 126 | }; 127 | 128 | // Throw error message function 129 | export const errorMsg = (userName, insights) => { 130 | const p1 = document.querySelector('p.user-name-error'); 131 | const p2 = document.querySelector('p.insights-error'); 132 | if (!userName) { 133 | p1.innerHTML = 'required field'; 134 | p1.style.color = 'red'; 135 | p1.style.fontSize = '0.9rem'; 136 | } else { 137 | p1.innerHTML = ''; 138 | } 139 | if (!insights) { 140 | p2.innerHTML = 'required field'; 141 | p2.style.color = 'red'; 142 | p2.style.fontSize = '0.9rem'; 143 | } else { 144 | p2.innerHTML = ''; 145 | } 146 | }; 147 | 148 | // Add comment to API function 149 | export const addComment = async (id, userName, insights) => { 150 | const request = new Request('https://us-central1-involvement-api.cloudfunctions.net/capstoneApi/apps/R20mJzx45L3RyqatiuEZ/comments'); 151 | await fetch(request, { 152 | headers: { 153 | 'Content-type': 'application/json', 154 | }, 155 | method: 'POST', 156 | body: JSON.stringify({ 157 | item_id: id, 158 | username: userName, 159 | comment: insights, 160 | }), 161 | }); 162 | }; 163 | 164 | // Getting comment data from the Involvement API function 165 | export const getCommentData = async (id) => { 166 | const request = new Request(`https://us-central1-involvement-api.cloudfunctions.net/capstoneApi/apps/R20mJzx45L3RyqatiuEZ/comments?item_id=${id}`); 167 | const response = await fetch(request); 168 | const data = await response.json(); 169 | return data; 170 | }; 171 | 172 | // populating comment data function 173 | export const populateComments = (data) => { 174 | const commentsBox = document.querySelector('div.comments-box'); 175 | data.forEach((element) => { 176 | if (element.creation_date && element.username && element.comment) { 177 | const p = document.createElement('p'); 178 | p.textContent = `${element.creation_date} ${element.username}: ${element.comment}`; 179 | commentsBox.appendChild(p); 180 | } 181 | }); 182 | }; 183 | 184 | // counter comment function 185 | export const commentcounter = async (id) => { 186 | const request = new Request(`https://us-central1-involvement-api.cloudfunctions.net/capstoneApi/apps/R20mJzx45L3RyqatiuEZ/comments?item_id=${id}`); 187 | const response = await fetch(request); 188 | const data = await response.json(); 189 | // Since some data objects are empty: 190 | let n = 0; 191 | if (data.length) { 192 | data.forEach((element) => { 193 | if (element.creation_date && element.username && element.comment) { 194 | n += 1; 195 | } 196 | }); 197 | } 198 | return n; 199 | }; 200 | 201 | // Display the number of comment on the popup window function 202 | export const diplayNumberOfComments = (nbOfItems) => { 203 | const h2 = document.querySelector('h2.comment-title'); 204 | h2.textContent = `comments (${nbOfItems})`; 205 | }; -------------------------------------------------------------------------------- /dist/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). 3 | * This devtool is neither made for production nor for readable output files. 4 | * It uses "eval()" calls to create a separate source file in the browser devtools. 5 | * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) 6 | * or disable the default devtool with "devtool: false". 7 | * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). 8 | */ 9 | /******/ (() => { // webpackBootstrap 10 | /******/ "use strict"; 11 | /******/ var __webpack_modules__ = ({ 12 | 13 | /***/ "./node_modules/css-loader/dist/cjs.js!./src/style.css": 14 | /*!*************************************************************!*\ 15 | !*** ./node_modules/css-loader/dist/cjs.js!./src/style.css ***! 16 | \*************************************************************/ 17 | /***/ ((module, __webpack_exports__, __webpack_require__) => { 18 | 19 | eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \"* {\\r\\n box-sizing: border-box;\\r\\n padding: 0;\\r\\n margin: 0;\\r\\n color: #2f2c28;\\r\\n}\\r\\n\\r\\nbody {\\r\\n background-color: #d3d3d3;\\r\\n font-size: 1rem;\\r\\n}\\r\\n\\r\\n.flex-column {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n}\\r\\n\\r\\n.flex-row {\\r\\n display: flex;\\r\\n flex-direction: row;\\r\\n}\\r\\n\\r\\nul {\\r\\n list-style: none;\\r\\n}\\r\\n\\r\\nbutton:hover,\\r\\n.heart:hover {\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n@media only screen and (min-width: 320px) {\\r\\n /* Styling Home page start */\\r\\n header {\\r\\n width: 100%;\\r\\n justify-content: space-between;\\r\\n align-items: center;\\r\\n padding-top: 10px;\\r\\n position: fixed;\\r\\n background-color: #8b4513;\\r\\n }\\r\\n\\r\\n .logo-box {\\r\\n width: 30%;\\r\\n }\\r\\n\\r\\n .logo {\\r\\n width: 100%;\\r\\n }\\r\\n\\r\\n ul {\\r\\n width: 65%;\\r\\n column-gap: 5%;\\r\\n }\\r\\n\\r\\n ul li:nth-child(1) {\\r\\n text-decoration: underline;\\r\\n color: #ffffed;\\r\\n }\\r\\n\\r\\n ul li a {\\r\\n color: #2beb83;\\r\\n text-decoration: none;\\r\\n }\\r\\n\\r\\n section.food-list {\\r\\n width: 100%;\\r\\n padding-top: 60px;\\r\\n gap: 10px;\\r\\n }\\r\\n\\r\\n .food-card {\\r\\n width: 90%;\\r\\n justify-content: center;\\r\\n margin: 0 5%;\\r\\n row-gap: 30px;\\r\\n }\\r\\n\\r\\n .image-box {\\r\\n width: 100%;\\r\\n }\\r\\n\\r\\n .image-box img {\\r\\n width: 100%;\\r\\n border-radius: 15px;\\r\\n }\\r\\n\\r\\n .image-box img:hover {\\r\\n width: 103%;\\r\\n border-radius: 15px;\\r\\n }\\r\\n\\r\\n .meal-title-and-interactions-box {\\r\\n margin-top: -30px;\\r\\n justify-content: space-between;\\r\\n }\\r\\n\\r\\n .meal-title-and-interactions-box h2 {\\r\\n font-size: 1.2rem;\\r\\n width: 67%;\\r\\n }\\r\\n\\r\\n .meal-title-and-interactions-box span {\\r\\n font-size: 1.1rem;\\r\\n color: #8b4513;\\r\\n }\\r\\n\\r\\n .buttons-box {\\r\\n justify-content: space-between;\\r\\n margin-top: -20px;\\r\\n }\\r\\n\\r\\n button {\\r\\n width: 30%;\\r\\n }\\r\\n\\r\\n /* Styling Home page end */\\r\\n\\r\\n /* Styling popup window start */\\r\\n .popup-window {\\r\\n width: 100%;\\r\\n position: fixed;\\r\\n top: 0;\\r\\n }\\r\\n\\r\\n .popup-wrapper {\\r\\n width: 95%;\\r\\n position: fixed;\\r\\n top: 10px;\\r\\n height: 98%;\\r\\n background-color: #d3d3d3;\\r\\n align-items: center;\\r\\n margin: 0 2.5% 0 2.5%;\\r\\n border-radius: 20px;\\r\\n z-index: 10;\\r\\n overflow-y: auto;\\r\\n padding-bottom: 20px;\\r\\n border: 2px solid #cd853f;\\r\\n }\\r\\n\\r\\n i.close-popup:hover {\\r\\n cursor: pointer;\\r\\n }\\r\\n\\r\\n .popup-wrapper h2 {\\r\\n font-size: 1.2rem;\\r\\n }\\r\\n\\r\\n h2.add-comment {\\r\\n margin-top: 30px;\\r\\n }\\r\\n\\r\\n .popup-window i {\\r\\n margin: 15px 10% 15px 90%;\\r\\n }\\r\\n\\r\\n .meal-section {\\r\\n width: 100%;\\r\\n align-items: center;\\r\\n }\\r\\n\\r\\n .popup-image-box {\\r\\n width: 90%;\\r\\n align-items: center;\\r\\n }\\r\\n\\r\\n img.popup-img {\\r\\n width: 100%;\\r\\n border-radius: 15px;\\r\\n }\\r\\n\\r\\n h2.meal-name {\\r\\n margin-top: 10px;\\r\\n }\\r\\n\\r\\n .meal-infos {\\r\\n display: grid;\\r\\n grid-template-columns: auto auto;\\r\\n width: 90%;\\r\\n margin-top: 10px;\\r\\n }\\r\\n\\r\\n .meal-infos span {\\r\\n font-weight: bolder;\\r\\n }\\r\\n\\r\\n .instruction-box {\\r\\n grid-column: 1 / span 2;\\r\\n margin-top: 10px;\\r\\n text-align: justify;\\r\\n }\\r\\n\\r\\n .comments-section {\\r\\n display: flex;\\r\\n margin-top: 30px;\\r\\n width: 90%;\\r\\n justify-content: center;\\r\\n }\\r\\n\\r\\n .comments-box p {\\r\\n font-size: 0.9rem;\\r\\n margin-top: 5px;\\r\\n font-style: italic;\\r\\n }\\r\\n\\r\\n .add-comment-section {\\r\\n width: 100%;\\r\\n align-items: center;\\r\\n }\\r\\n\\r\\n form.add-comment {\\r\\n width: 90%;\\r\\n row-gap: 5px;\\r\\n }\\r\\n\\r\\n input.user-name {\\r\\n height: 25px;\\r\\n }\\r\\n\\r\\n textarea.insights {\\r\\n height: 60px;\\r\\n }\\r\\n\\r\\n input.user-name:focus,\\r\\n textarea.insights:focus {\\r\\n outline-color: #8b4513;\\r\\n padding: 3%;\\r\\n }\\r\\n\\r\\n ::placeholder {\\r\\n padding-left: 2%;\\r\\n }\\r\\n\\r\\n /* Styling popup window end */\\r\\n}\\r\\n\\r\\n@media only screen and (min-width: 375px) {\\r\\n header ul {\\r\\n width: 60%;\\r\\n column-gap: 5%;\\r\\n margin-left: 15%;\\r\\n }\\r\\n\\r\\n .meal-title-and-interactions-box h2 {\\r\\n width: 70%;\\r\\n }\\r\\n}\\r\\n\\r\\n@media only screen and (min-width: 425px) {\\r\\n header ul {\\r\\n width: 60%;\\r\\n column-gap: 5%;\\r\\n margin-left: 18%;\\r\\n }\\r\\n\\r\\n section.food-list {\\r\\n padding-top: 80px;\\r\\n }\\r\\n\\r\\n .meal-title-and-interactions-box h2 {\\r\\n width: 75%;\\r\\n }\\r\\n\\r\\n button {\\r\\n width: 20%;\\r\\n }\\r\\n}\\r\\n\\r\\n@media only screen and (min-width: 768px) {\\r\\n .logo {\\r\\n width: 90%;\\r\\n }\\r\\n\\r\\n header ul {\\r\\n column-gap: 5%;\\r\\n margin-left: 40%;\\r\\n }\\r\\n\\r\\n section.food-list {\\r\\n width: 100%;\\r\\n padding-top: 100px;\\r\\n display: grid;\\r\\n grid-template-columns: 49% 49%;\\r\\n grid-template-columns: auto auto;\\r\\n }\\r\\n\\r\\n button {\\r\\n width: 25%;\\r\\n }\\r\\n\\r\\n /* Styling popup window start */\\r\\n button.submit-comment {\\r\\n width: 12%;\\r\\n }\\r\\n\\r\\n /* Styling popup window end */\\r\\n}\\r\\n\\r\\n@media only screen and (min-width: 1024px) {\\r\\n section.food-list {\\r\\n width: 100%;\\r\\n padding-top: 100px;\\r\\n display: grid;\\r\\n grid-template-columns: 35% 35% 35%;\\r\\n grid-template-columns: auto auto auto;\\r\\n }\\r\\n\\r\\n /* Styling popup window start */\\r\\n .meal-section {\\r\\n width: 95%;\\r\\n flex-direction: row;\\r\\n column-gap: 2%;\\r\\n }\\r\\n\\r\\n .popup-image-box {\\r\\n width: 40%;\\r\\n }\\r\\n\\r\\n .add-comment-section {\\r\\n width: 70%;\\r\\n }\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n /* Styling popup window end */\\r\\n}\\r\\n\\r\\n@media only screen and (min-width: 1440px) {\\r\\n section.food-list {\\r\\n width: 80%;\\r\\n margin: 0 10%;\\r\\n }\\r\\n\\r\\n .logo-box {\\r\\n width: 20%;\\r\\n }\\r\\n\\r\\n .logo {\\r\\n width: 100%;\\r\\n }\\r\\n\\r\\n header ul {\\r\\n column-gap: 5%;\\r\\n margin-left: 50%;\\r\\n }\\r\\n}\\r\\n\", \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://js-capstone-project/./src/style.css?./node_modules/css-loader/dist/cjs.js"); 20 | 21 | /***/ }), 22 | 23 | /***/ "./node_modules/css-loader/dist/runtime/api.js": 24 | /*!*****************************************************!*\ 25 | !*** ./node_modules/css-loader/dist/runtime/api.js ***! 26 | \*****************************************************/ 27 | /***/ ((module) => { 28 | 29 | eval("\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\nmodule.exports = function (cssWithMappingToString) {\n var list = [];\n\n // return the list of modules as css string\n list.toString = function toString() {\n return this.map(function (item) {\n var content = \"\";\n var needLayer = typeof item[5] !== \"undefined\";\n if (item[4]) {\n content += \"@supports (\".concat(item[4], \") {\");\n }\n if (item[2]) {\n content += \"@media \".concat(item[2], \" {\");\n }\n if (needLayer) {\n content += \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\");\n }\n content += cssWithMappingToString(item);\n if (needLayer) {\n content += \"}\";\n }\n if (item[2]) {\n content += \"}\";\n }\n if (item[4]) {\n content += \"}\";\n }\n return content;\n }).join(\"\");\n };\n\n // import a list of modules into the list\n list.i = function i(modules, media, dedupe, supports, layer) {\n if (typeof modules === \"string\") {\n modules = [[null, modules, undefined]];\n }\n var alreadyImportedModules = {};\n if (dedupe) {\n for (var k = 0; k < this.length; k++) {\n var id = this[k][0];\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n for (var _k = 0; _k < modules.length; _k++) {\n var item = [].concat(modules[_k]);\n if (dedupe && alreadyImportedModules[item[0]]) {\n continue;\n }\n if (typeof layer !== \"undefined\") {\n if (typeof item[5] === \"undefined\") {\n item[5] = layer;\n } else {\n item[1] = \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\").concat(item[1], \"}\");\n item[5] = layer;\n }\n }\n if (media) {\n if (!item[2]) {\n item[2] = media;\n } else {\n item[1] = \"@media \".concat(item[2], \" {\").concat(item[1], \"}\");\n item[2] = media;\n }\n }\n if (supports) {\n if (!item[4]) {\n item[4] = \"\".concat(supports);\n } else {\n item[1] = \"@supports (\".concat(item[4], \") {\").concat(item[1], \"}\");\n item[4] = supports;\n }\n }\n list.push(item);\n }\n };\n return list;\n};\n\n//# sourceURL=webpack://js-capstone-project/./node_modules/css-loader/dist/runtime/api.js?"); 30 | 31 | /***/ }), 32 | 33 | /***/ "./node_modules/css-loader/dist/runtime/noSourceMaps.js": 34 | /*!**************************************************************!*\ 35 | !*** ./node_modules/css-loader/dist/runtime/noSourceMaps.js ***! 36 | \**************************************************************/ 37 | /***/ ((module) => { 38 | 39 | eval("\n\nmodule.exports = function (i) {\n return i[1];\n};\n\n//# sourceURL=webpack://js-capstone-project/./node_modules/css-loader/dist/runtime/noSourceMaps.js?"); 40 | 41 | /***/ }), 42 | 43 | /***/ "./src/style.css": 44 | /*!***********************!*\ 45 | !*** ./src/style.css ***! 46 | \***********************/ 47 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { 48 | 49 | eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/styleDomAPI.js */ \"./node_modules/style-loader/dist/runtime/styleDomAPI.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/insertBySelector.js */ \"./node_modules/style-loader/dist/runtime/insertBySelector.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ \"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/insertStyleElement.js */ \"./node_modules/style-loader/dist/runtime/insertStyleElement.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/styleTagTransform.js */ \"./node_modules/style-loader/dist/runtime/styleTagTransform.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../node_modules/css-loader/dist/cjs.js!./style.css */ \"./node_modules/css-loader/dist/cjs.js!./src/style.css\");\n\n \n \n \n \n \n \n \n \n \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__[\"default\"], options);\n\n\n\n\n /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__[\"default\"] && _node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals ? _node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals : undefined);\n\n\n//# sourceURL=webpack://js-capstone-project/./src/style.css?"); 50 | 51 | /***/ }), 52 | 53 | /***/ "./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js": 54 | /*!****************************************************************************!*\ 55 | !*** ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js ***! 56 | \****************************************************************************/ 57 | /***/ ((module) => { 58 | 59 | eval("\n\nvar stylesInDOM = [];\nfunction getIndexByIdentifier(identifier) {\n var result = -1;\n for (var i = 0; i < stylesInDOM.length; i++) {\n if (stylesInDOM[i].identifier === identifier) {\n result = i;\n break;\n }\n }\n return result;\n}\nfunction modulesToDom(list, options) {\n var idCountMap = {};\n var identifiers = [];\n for (var i = 0; i < list.length; i++) {\n var item = list[i];\n var id = options.base ? item[0] + options.base : item[0];\n var count = idCountMap[id] || 0;\n var identifier = \"\".concat(id, \" \").concat(count);\n idCountMap[id] = count + 1;\n var indexByIdentifier = getIndexByIdentifier(identifier);\n var obj = {\n css: item[1],\n media: item[2],\n sourceMap: item[3],\n supports: item[4],\n layer: item[5]\n };\n if (indexByIdentifier !== -1) {\n stylesInDOM[indexByIdentifier].references++;\n stylesInDOM[indexByIdentifier].updater(obj);\n } else {\n var updater = addElementStyle(obj, options);\n options.byIndex = i;\n stylesInDOM.splice(i, 0, {\n identifier: identifier,\n updater: updater,\n references: 1\n });\n }\n identifiers.push(identifier);\n }\n return identifiers;\n}\nfunction addElementStyle(obj, options) {\n var api = options.domAPI(options);\n api.update(obj);\n var updater = function updater(newObj) {\n if (newObj) {\n if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) {\n return;\n }\n api.update(obj = newObj);\n } else {\n api.remove();\n }\n };\n return updater;\n}\nmodule.exports = function (list, options) {\n options = options || {};\n list = list || [];\n var lastIdentifiers = modulesToDom(list, options);\n return function update(newList) {\n newList = newList || [];\n for (var i = 0; i < lastIdentifiers.length; i++) {\n var identifier = lastIdentifiers[i];\n var index = getIndexByIdentifier(identifier);\n stylesInDOM[index].references--;\n }\n var newLastIdentifiers = modulesToDom(newList, options);\n for (var _i = 0; _i < lastIdentifiers.length; _i++) {\n var _identifier = lastIdentifiers[_i];\n var _index = getIndexByIdentifier(_identifier);\n if (stylesInDOM[_index].references === 0) {\n stylesInDOM[_index].updater();\n stylesInDOM.splice(_index, 1);\n }\n }\n lastIdentifiers = newLastIdentifiers;\n };\n};\n\n//# sourceURL=webpack://js-capstone-project/./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?"); 60 | 61 | /***/ }), 62 | 63 | /***/ "./node_modules/style-loader/dist/runtime/insertBySelector.js": 64 | /*!********************************************************************!*\ 65 | !*** ./node_modules/style-loader/dist/runtime/insertBySelector.js ***! 66 | \********************************************************************/ 67 | /***/ ((module) => { 68 | 69 | eval("\n\nvar memo = {};\n\n/* istanbul ignore next */\nfunction getTarget(target) {\n if (typeof memo[target] === \"undefined\") {\n var styleTarget = document.querySelector(target);\n\n // Special case to return head of iframe instead of iframe itself\n if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n try {\n // This will throw an exception if access to iframe is blocked\n // due to cross-origin restrictions\n styleTarget = styleTarget.contentDocument.head;\n } catch (e) {\n // istanbul ignore next\n styleTarget = null;\n }\n }\n memo[target] = styleTarget;\n }\n return memo[target];\n}\n\n/* istanbul ignore next */\nfunction insertBySelector(insert, style) {\n var target = getTarget(insert);\n if (!target) {\n throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\n }\n target.appendChild(style);\n}\nmodule.exports = insertBySelector;\n\n//# sourceURL=webpack://js-capstone-project/./node_modules/style-loader/dist/runtime/insertBySelector.js?"); 70 | 71 | /***/ }), 72 | 73 | /***/ "./node_modules/style-loader/dist/runtime/insertStyleElement.js": 74 | /*!**********************************************************************!*\ 75 | !*** ./node_modules/style-loader/dist/runtime/insertStyleElement.js ***! 76 | \**********************************************************************/ 77 | /***/ ((module) => { 78 | 79 | eval("\n\n/* istanbul ignore next */\nfunction insertStyleElement(options) {\n var element = document.createElement(\"style\");\n options.setAttributes(element, options.attributes);\n options.insert(element, options.options);\n return element;\n}\nmodule.exports = insertStyleElement;\n\n//# sourceURL=webpack://js-capstone-project/./node_modules/style-loader/dist/runtime/insertStyleElement.js?"); 80 | 81 | /***/ }), 82 | 83 | /***/ "./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js": 84 | /*!**********************************************************************************!*\ 85 | !*** ./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js ***! 86 | \**********************************************************************************/ 87 | /***/ ((module, __unused_webpack_exports, __webpack_require__) => { 88 | 89 | eval("\n\n/* istanbul ignore next */\nfunction setAttributesWithoutAttributes(styleElement) {\n var nonce = true ? __webpack_require__.nc : 0;\n if (nonce) {\n styleElement.setAttribute(\"nonce\", nonce);\n }\n}\nmodule.exports = setAttributesWithoutAttributes;\n\n//# sourceURL=webpack://js-capstone-project/./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js?"); 90 | 91 | /***/ }), 92 | 93 | /***/ "./node_modules/style-loader/dist/runtime/styleDomAPI.js": 94 | /*!***************************************************************!*\ 95 | !*** ./node_modules/style-loader/dist/runtime/styleDomAPI.js ***! 96 | \***************************************************************/ 97 | /***/ ((module) => { 98 | 99 | eval("\n\n/* istanbul ignore next */\nfunction apply(styleElement, options, obj) {\n var css = \"\";\n if (obj.supports) {\n css += \"@supports (\".concat(obj.supports, \") {\");\n }\n if (obj.media) {\n css += \"@media \".concat(obj.media, \" {\");\n }\n var needLayer = typeof obj.layer !== \"undefined\";\n if (needLayer) {\n css += \"@layer\".concat(obj.layer.length > 0 ? \" \".concat(obj.layer) : \"\", \" {\");\n }\n css += obj.css;\n if (needLayer) {\n css += \"}\";\n }\n if (obj.media) {\n css += \"}\";\n }\n if (obj.supports) {\n css += \"}\";\n }\n var sourceMap = obj.sourceMap;\n if (sourceMap && typeof btoa !== \"undefined\") {\n css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\n }\n\n // For old IE\n /* istanbul ignore if */\n options.styleTagTransform(css, styleElement, options.options);\n}\nfunction removeStyleElement(styleElement) {\n // istanbul ignore if\n if (styleElement.parentNode === null) {\n return false;\n }\n styleElement.parentNode.removeChild(styleElement);\n}\n\n/* istanbul ignore next */\nfunction domAPI(options) {\n if (typeof document === \"undefined\") {\n return {\n update: function update() {},\n remove: function remove() {}\n };\n }\n var styleElement = options.insertStyleElement(options);\n return {\n update: function update(obj) {\n apply(styleElement, options, obj);\n },\n remove: function remove() {\n removeStyleElement(styleElement);\n }\n };\n}\nmodule.exports = domAPI;\n\n//# sourceURL=webpack://js-capstone-project/./node_modules/style-loader/dist/runtime/styleDomAPI.js?"); 100 | 101 | /***/ }), 102 | 103 | /***/ "./node_modules/style-loader/dist/runtime/styleTagTransform.js": 104 | /*!*********************************************************************!*\ 105 | !*** ./node_modules/style-loader/dist/runtime/styleTagTransform.js ***! 106 | \*********************************************************************/ 107 | /***/ ((module) => { 108 | 109 | eval("\n\n/* istanbul ignore next */\nfunction styleTagTransform(css, styleElement) {\n if (styleElement.styleSheet) {\n styleElement.styleSheet.cssText = css;\n } else {\n while (styleElement.firstChild) {\n styleElement.removeChild(styleElement.firstChild);\n }\n styleElement.appendChild(document.createTextNode(css));\n }\n}\nmodule.exports = styleTagTransform;\n\n//# sourceURL=webpack://js-capstone-project/./node_modules/style-loader/dist/runtime/styleTagTransform.js?"); 110 | 111 | /***/ }), 112 | 113 | /***/ "./src/index.js": 114 | /*!**********************!*\ 115 | !*** ./src/index.js ***! 116 | \**********************/ 117 | /***/ ((module, __webpack_exports__, __webpack_require__) => { 118 | 119 | eval("__webpack_require__.a(module, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {\n__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _style_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./style.css */ \"./src/style.css\");\n/* harmony import */ var _modules_functions_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modules/functions.js */ \"./src/modules/functions.js\");\n// import style from style.css file (required)\n\n\n// import the required functions from module\n\n\n// Getting data from the theMealDB API\nconst mealData = await (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.getMealData)();\n\n// Getting data from the Involvement API function\nconst likesData = await (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.getLikesData)();\n\n// Populating items in the home page\n(0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.populatedishes)(mealData);\n\n// Getting and diplaying the number of items\nconst nbOfItems = await (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.counter)();\n(0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.diplayNumberOfItems)(nbOfItems);\n\n// Diplaying likes data in the home page\nmealData.forEach((element) => {\n (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.diplayLikes)(likesData, `M${element.idMeal}`);\n});\n\nconst foodListSection = document.querySelector('.food-list');\n// Add event listener to the like icon and open comment button\nfoodListSection.addEventListener('click', async (e) => {\n e.preventDefault();\n if (e.target && e.target.matches('i.heart')) {\n const targetId = e.target.id;\n await (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.addLike)(targetId);\n const likesData = await (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.getLikesData)();\n (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.diplayLikes)(likesData, targetId);\n } else if (e.target && e.target.matches('button.comment')) {\n const targetId = e.target.id;\n const idMeal = targetId.replace('CBtn', '');\n (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.PopupContent)(mealData, idMeal);\n\n // We need to use the prefix M because we initially used it to post likes in the API\n const itemId = targetId.replace('CBtn', 'M');\n\n // Getting and displaying the number of comments\n const nbComments = await (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.commentcounter)(itemId);\n (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.diplayNumberOfComments)(nbComments);\n\n // Get comment the corresponding comment data from the API\n const commentData = await (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.getCommentData)(itemId);\n\n // Populate comment data in the popup window after checking that data is not empty\n if (commentData.length) {\n (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.populateComments)(commentData);\n }\n\n // Add event listener to the submit comment button\n const submitCommentBtn = document.querySelector('button.submit-comment');\n submitCommentBtn.addEventListener('click', async (e) => {\n e.preventDefault();\n const userName = document.querySelector('input.user-name').value;\n const insights = document.querySelector('textarea.insights').value;\n if (!userName || !insights) {\n (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.errorMsg)(userName, insights);\n }\n await (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.addComment)(itemId, userName, insights);\n document.querySelector('input.user-name').value = '';\n document.querySelector('textarea.insights').value = '';\n\n // Clean the board\n document.querySelector('div.comments-box').innerHTML = '';\n // Gettint the updated comment data from the API and populate\n const commentData = await (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.getCommentData)(itemId);\n // Repopulate using the updated comment data\n (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.populateComments)(commentData);\n\n // Getting and displaying the number of comments\n const nbComments = await (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.commentcounter)(itemId);\n (0,_modules_functions_js__WEBPACK_IMPORTED_MODULE_1__.diplayNumberOfComments)(nbComments);\n });\n }\n});\n\n// Add event listener to close popup icon\nconst popupWindow = document.querySelector('.popup-window');\npopupWindow.addEventListener('click', (e) => {\n if (e.target && e.target.matches('i.close-popup')) {\n popupWindow.innerHTML = '';\n }\n});\n\n__webpack_async_result__();\n} catch(e) { __webpack_async_result__(e); } }, 1);\n\n//# sourceURL=webpack://js-capstone-project/./src/index.js?"); 120 | 121 | /***/ }), 122 | 123 | /***/ "./src/modules/functions.js": 124 | /*!**********************************!*\ 125 | !*** ./src/modules/functions.js ***! 126 | \**********************************/ 127 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { 128 | 129 | eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ PopupContent: () => (/* binding */ PopupContent),\n/* harmony export */ addComment: () => (/* binding */ addComment),\n/* harmony export */ addLike: () => (/* binding */ addLike),\n/* harmony export */ commentcounter: () => (/* binding */ commentcounter),\n/* harmony export */ counter: () => (/* binding */ counter),\n/* harmony export */ diplayLikes: () => (/* binding */ diplayLikes),\n/* harmony export */ diplayNumberOfComments: () => (/* binding */ diplayNumberOfComments),\n/* harmony export */ diplayNumberOfItems: () => (/* binding */ diplayNumberOfItems),\n/* harmony export */ errorMsg: () => (/* binding */ errorMsg),\n/* harmony export */ getCommentData: () => (/* binding */ getCommentData),\n/* harmony export */ getLikesData: () => (/* binding */ getLikesData),\n/* harmony export */ getMealData: () => (/* binding */ getMealData),\n/* harmony export */ newApp: () => (/* binding */ newApp),\n/* harmony export */ populateComments: () => (/* binding */ populateComments),\n/* harmony export */ populatedishes: () => (/* binding */ populatedishes)\n/* harmony export */ });\n// Getting data from the theMealDB API function\nconst getMealData = async () => {\n const request = new Request('https://themealdb.com/api/json/v1/1/search.php?f=c');\n const response = await fetch(request);\n const data = await response.json();\n return data.meals;\n};\n\n// Populating items in the DOM function\nconst populatedishes = async (mealData) => {\n const foodListSection = document.querySelector('.food-list');\n mealData.forEach((element) => {\n const foodCard = document.createElement('div');\n foodCard.classList.add('food-card', 'flex-column');\n foodCard.innerHTML = `
meal
\n
\n

${element.strMeal}

\n 0 likes\n
\n
\n \n \n
\n
\n `;\n foodListSection.appendChild(foodCard);\n });\n};\n\n// Create new app function\nconst newApp = async () => {\n const request = new Request('https://us-central1-involvement-api.cloudfunctions.net/capstoneApi/apps/');\n await fetch(request, {\n method: 'POST',\n });\n};\n\n// Add likes to API function\nconst addLike = async (targetId) => {\n const request = new Request('https://us-central1-involvement-api.cloudfunctions.net/capstoneApi/apps/R20mJzx45L3RyqatiuEZ/likes/');\n await fetch(request, {\n headers: {\n 'Content-type': 'application/json',\n },\n method: 'POST',\n body: JSON.stringify({\n item_id: targetId,\n }),\n });\n};\n\n// Getting likes data from the Involvement API function\nconst getLikesData = async () => {\n const request = new Request('https://us-central1-involvement-api.cloudfunctions.net/capstoneApi/apps/R20mJzx45L3RyqatiuEZ/likes/');\n const response = await fetch(request);\n const data = await response.json();\n return data;\n};\n\n// Diplaying likes data in the home page function\nconst diplayLikes = async (likesData, itemId) => {\n likesData.forEach((element) => {\n if (element.item_id === itemId) {\n // Replace M from the i tag id by L for obtaining the span id\n const likeId = itemId.replace('M', 'L');\n const span = document.querySelector(`#${likeId}`);\n span.textContent = `${element.likes} likes`;\n }\n });\n};\n\n// counter meals items function\nconst counter = async () => {\n const request = new Request('https://themealdb.com/api/json/v1/1/search.php?f=c');\n const response = await fetch(request);\n const data = await response.json();\n return data.meals.length;\n};\n\n// Display the number of meal on the home page function\nconst diplayNumberOfItems = (nbOfItems) => {\n const li = document.querySelector('li.number-of-items');\n li.textContent = `Meals(${nbOfItems})`;\n};\n\n// Populating popup window content function\nconst PopupContent = (data, id) => {\n const popupBox = document.querySelector('.popup-window');\n data.forEach((element) => {\n if (element.idMeal === id) {\n popupBox.innerHTML = `
\n \n
\n \n
\n
Area: ${element.strArea}
\n
Category: ${element.strCategory}
\n
Instructions: ${element.strInstructions}
\n
\n
\n
\n
\n

Comments (0)

\n
\n
\n
\n
\n

Add a comment

\n
\n \n \n

\n \n \n

\n \n
\n
\n
\n `;\n }\n });\n};\n\n// Throw error message function\nconst errorMsg = (userName, insights) => {\n const p1 = document.querySelector('p.user-name-error');\n const p2 = document.querySelector('p.insights-error');\n if (!userName) {\n p1.innerHTML = 'required field';\n p1.style.color = 'red';\n p1.style.fontSize = '0.9rem';\n } else {\n p1.innerHTML = '';\n }\n if (!insights) {\n p2.innerHTML = 'required field';\n p2.style.color = 'red';\n p2.style.fontSize = '0.9rem';\n } else {\n p2.innerHTML = '';\n }\n};\n\n// Add comment to API function\nconst addComment = async (id, userName, insights) => {\n const request = new Request('https://us-central1-involvement-api.cloudfunctions.net/capstoneApi/apps/R20mJzx45L3RyqatiuEZ/comments');\n await fetch(request, {\n headers: {\n 'Content-type': 'application/json',\n },\n method: 'POST',\n body: JSON.stringify({\n item_id: id,\n username: userName,\n comment: insights,\n }),\n });\n};\n\n// Getting comment data from the Involvement API function\nconst getCommentData = async (id) => {\n const request = new Request(`https://us-central1-involvement-api.cloudfunctions.net/capstoneApi/apps/R20mJzx45L3RyqatiuEZ/comments?item_id=${id}`);\n const response = await fetch(request);\n const data = await response.json();\n return data;\n};\n\n// populating comment data function\nconst populateComments = (data) => {\n const commentsBox = document.querySelector('div.comments-box');\n data.forEach((element) => {\n if (element.creation_date && element.username && element.comment) {\n const p = document.createElement('p');\n p.textContent = `${element.creation_date} ${element.username}: ${element.comment}`;\n commentsBox.appendChild(p);\n }\n });\n};\n\n// counter comment function\nconst commentcounter = async (id) => {\n const request = new Request(`https://us-central1-involvement-api.cloudfunctions.net/capstoneApi/apps/R20mJzx45L3RyqatiuEZ/comments?item_id=${id}`);\n const response = await fetch(request);\n const data = await response.json();\n // Since some data objects are empty:\n let n = 0;\n if (data.length) {\n data.forEach((element) => {\n if (element.creation_date && element.username && element.comment) {\n n += 1;\n }\n });\n }\n return n;\n};\n\n// Display the number of comment on the popup window function\nconst diplayNumberOfComments = (nbOfItems) => {\n const h2 = document.querySelector('h2.comment-title');\n h2.textContent = `comments (${nbOfItems})`;\n};\n\n//# sourceURL=webpack://js-capstone-project/./src/modules/functions.js?"); 130 | 131 | /***/ }) 132 | 133 | /******/ }); 134 | /************************************************************************/ 135 | /******/ // The module cache 136 | /******/ var __webpack_module_cache__ = {}; 137 | /******/ 138 | /******/ // The require function 139 | /******/ function __webpack_require__(moduleId) { 140 | /******/ // Check if module is in cache 141 | /******/ var cachedModule = __webpack_module_cache__[moduleId]; 142 | /******/ if (cachedModule !== undefined) { 143 | /******/ return cachedModule.exports; 144 | /******/ } 145 | /******/ // Create a new module (and put it into the cache) 146 | /******/ var module = __webpack_module_cache__[moduleId] = { 147 | /******/ id: moduleId, 148 | /******/ // no module.loaded needed 149 | /******/ exports: {} 150 | /******/ }; 151 | /******/ 152 | /******/ // Execute the module function 153 | /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); 154 | /******/ 155 | /******/ // Return the exports of the module 156 | /******/ return module.exports; 157 | /******/ } 158 | /******/ 159 | /************************************************************************/ 160 | /******/ /* webpack/runtime/async module */ 161 | /******/ (() => { 162 | /******/ var webpackQueues = typeof Symbol === "function" ? Symbol("webpack queues") : "__webpack_queues__"; 163 | /******/ var webpackExports = typeof Symbol === "function" ? Symbol("webpack exports") : "__webpack_exports__"; 164 | /******/ var webpackError = typeof Symbol === "function" ? Symbol("webpack error") : "__webpack_error__"; 165 | /******/ var resolveQueue = (queue) => { 166 | /******/ if(queue && !queue.d) { 167 | /******/ queue.d = 1; 168 | /******/ queue.forEach((fn) => (fn.r--)); 169 | /******/ queue.forEach((fn) => (fn.r-- ? fn.r++ : fn())); 170 | /******/ } 171 | /******/ } 172 | /******/ var wrapDeps = (deps) => (deps.map((dep) => { 173 | /******/ if(dep !== null && typeof dep === "object") { 174 | /******/ if(dep[webpackQueues]) return dep; 175 | /******/ if(dep.then) { 176 | /******/ var queue = []; 177 | /******/ queue.d = 0; 178 | /******/ dep.then((r) => { 179 | /******/ obj[webpackExports] = r; 180 | /******/ resolveQueue(queue); 181 | /******/ }, (e) => { 182 | /******/ obj[webpackError] = e; 183 | /******/ resolveQueue(queue); 184 | /******/ }); 185 | /******/ var obj = {}; 186 | /******/ obj[webpackQueues] = (fn) => (fn(queue)); 187 | /******/ return obj; 188 | /******/ } 189 | /******/ } 190 | /******/ var ret = {}; 191 | /******/ ret[webpackQueues] = x => {}; 192 | /******/ ret[webpackExports] = dep; 193 | /******/ return ret; 194 | /******/ })); 195 | /******/ __webpack_require__.a = (module, body, hasAwait) => { 196 | /******/ var queue; 197 | /******/ hasAwait && ((queue = []).d = 1); 198 | /******/ var depQueues = new Set(); 199 | /******/ var exports = module.exports; 200 | /******/ var currentDeps; 201 | /******/ var outerResolve; 202 | /******/ var reject; 203 | /******/ var promise = new Promise((resolve, rej) => { 204 | /******/ reject = rej; 205 | /******/ outerResolve = resolve; 206 | /******/ }); 207 | /******/ promise[webpackExports] = exports; 208 | /******/ promise[webpackQueues] = (fn) => (queue && fn(queue), depQueues.forEach(fn), promise["catch"](x => {})); 209 | /******/ module.exports = promise; 210 | /******/ body((deps) => { 211 | /******/ currentDeps = wrapDeps(deps); 212 | /******/ var fn; 213 | /******/ var getResult = () => (currentDeps.map((d) => { 214 | /******/ if(d[webpackError]) throw d[webpackError]; 215 | /******/ return d[webpackExports]; 216 | /******/ })) 217 | /******/ var promise = new Promise((resolve) => { 218 | /******/ fn = () => (resolve(getResult)); 219 | /******/ fn.r = 0; 220 | /******/ var fnQueue = (q) => (q !== queue && !depQueues.has(q) && (depQueues.add(q), q && !q.d && (fn.r++, q.push(fn)))); 221 | /******/ currentDeps.map((dep) => (dep[webpackQueues](fnQueue))); 222 | /******/ }); 223 | /******/ return fn.r ? promise : getResult(); 224 | /******/ }, (err) => ((err ? reject(promise[webpackError] = err) : outerResolve(exports)), resolveQueue(queue))); 225 | /******/ queue && (queue.d = 0); 226 | /******/ }; 227 | /******/ })(); 228 | /******/ 229 | /******/ /* webpack/runtime/compat get default export */ 230 | /******/ (() => { 231 | /******/ // getDefaultExport function for compatibility with non-harmony modules 232 | /******/ __webpack_require__.n = (module) => { 233 | /******/ var getter = module && module.__esModule ? 234 | /******/ () => (module['default']) : 235 | /******/ () => (module); 236 | /******/ __webpack_require__.d(getter, { a: getter }); 237 | /******/ return getter; 238 | /******/ }; 239 | /******/ })(); 240 | /******/ 241 | /******/ /* webpack/runtime/define property getters */ 242 | /******/ (() => { 243 | /******/ // define getter functions for harmony exports 244 | /******/ __webpack_require__.d = (exports, definition) => { 245 | /******/ for(var key in definition) { 246 | /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { 247 | /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); 248 | /******/ } 249 | /******/ } 250 | /******/ }; 251 | /******/ })(); 252 | /******/ 253 | /******/ /* webpack/runtime/hasOwnProperty shorthand */ 254 | /******/ (() => { 255 | /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) 256 | /******/ })(); 257 | /******/ 258 | /******/ /* webpack/runtime/make namespace object */ 259 | /******/ (() => { 260 | /******/ // define __esModule on exports 261 | /******/ __webpack_require__.r = (exports) => { 262 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 263 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 264 | /******/ } 265 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 266 | /******/ }; 267 | /******/ })(); 268 | /******/ 269 | /******/ /* webpack/runtime/nonce */ 270 | /******/ (() => { 271 | /******/ __webpack_require__.nc = undefined; 272 | /******/ })(); 273 | /******/ 274 | /************************************************************************/ 275 | /******/ 276 | /******/ // startup 277 | /******/ // Load entry module and return exports 278 | /******/ // This entry module can't be inlined because the eval devtool is used. 279 | /******/ var __webpack_exports__ = __webpack_require__("./src/index.js"); 280 | /******/ 281 | /******/ })() 282 | ; --------------------------------------------------------------------------------