diff --git a/README.md b/README.md index 5b6aa3642..f7ae50f7c 100644 --- a/README.md +++ b/README.md @@ -1,99 +1,80 @@ -# Webpack Starter Kit +# Overlook Hotel -## Clone This Repo +## Introduction -That's right, _clone_ not fork. You will use this repo multiple times, but you can only fork a repository once. So here is what you need to do to clone the repo and still be able to push changes to your repo: +The Overlook Hotel is an application where users can book hotel rooms. The user can book rooms by date, and by room type as long as there is availability. Customers can also view their upcoming and past stays. As a manager, users can see hotel information, add and delete bookings for a customer, and see any customers bookings. -1. Clone down this repo. Since you don't want to name your project "webpack-starter-kit", you can use an optional argument when you run `git clone` (you replace the `[...]` with the terminal command arguments): `git clone [remote-address] [what you want to name the repo]` -1. Remove the default remote: `git remote rm origin` (notice that `git remote -v` not gives you back nothing) -1. Create a new repo on GitHub with the name of `[what you want to name the repo]` to be consistent with naming -1. Copy the address that you would use to clone down this repo - something like `git@github.com:...` -1. Add this remote to your cloned down repo: `git remote add origin [address you copied in the previous step]` - do not include the brackets +This application was written by [Dani Bagley ](https://github.com/daniabee) -Now try to commit something (just add a line in the README) and push it up to your new repo. If everything is setup correctly, you should see the changes on GitHub. +**Login View** -## Setup - -After one person has gone through the steps of cloning down this repo and editing the remote, everyone should clone down the repo. - -Then install the library dependencies. Run: - -```bash -npm install -``` - -To verify that it is setup correctly, run `npm start` in your terminal. Go to `http://localhost:8080/` and you should see a page with the Turing logo image and a beautiful gradient background. If that's the case, you're good to go. Enter `control + c` in your terminal to stop the server at any time. - -## Where to Add Your Code - -### JavaScript +Upon opening the applications, the user is shown a login page where they can login with a customers username and password or managers username and password. -You have to be very intentional with where you add your feature code. This repo uses a tool called [webpack](https://webpack.js.org/) to combine many JavaScript files into one big file. Webpack enables you to have many, separate JavaScript files to keep your code organized and readable. Webpack expects all of your code files to be in a specific place, or else it doesn't know how to combine them all behind the scenes. +loginView -**Create all of your feature code files in the `src` directory.** +**Welcome View** -Since code is separated into multiple files, you need to use the `import` and `export` syntax to share code across file. +When the user logs in, they are taken to a welcome page that displays their name or their employee title. -Here is a video that walks through some information about [import and export](https://www.youtube.com/watch?v=_3oSWwapPKQ). There are a lot of resources out there about `import` and `export`, and resources will sometimes call them `ES6 modules`. It's something you will see in React and beyond. +WelcomView -### HTML +**Check Availability By Date & Room Type** -Add the HTML you need in the `index.html` file in the `./dist` directory. There is some boilerplate HTML that exists from the start that you can modify. +A user can check room availabilty by date. They can narrow their search by choosing what type of room they are looking for. -### Images +https://user-images.githubusercontent.com/108088961/201994789-dd03e275-e7a9-4ead-bbfc-04ba34ea381e.mov -Add your image files in the `src/images` directory. Similar to CSS files, you need to `import` image files in the JavaScript entry file (`scripts.js`). Then go into the HTML and add an `img` element with the `src` attribute pointing to the `images` directory. There is an example in the `index.html` file for you to see. +**Book Room** -## How to View Your Code in Action +A user can double click or tab to the room and press enter to book a room for the current set or loged in customer. -In the terminal, run: +https://user-images.githubusercontent.com/108088961/201995246-8f182d94-0ce0-4daf-8f39-65a3d85d0618.mov -```bash -npm start -``` +**See Customer Bookings** -You will see a bunch of lines output to your terminal. One of those lines will be something like: +A user can see all bookings associated with a customer. -```bash -Project is running at http://localhost:8080/ -``` +CustomerBookings -Go to `http://localhost:8080/` in your browser to view your code running in the browser. +**Manager Dashboard** ---- +A manager can add and search rooms like a customer, but they can choose which costumer they are booking for and see todays information for the hotel in their dashboard. -## Test Files Organization +ManagerDashboard -Similar to feature code, your test code needs to be put in a specific place for it to run successfully. +**Manager View of Customer Bookings** -**Put all of your test files in the `test` directory.** As a convention, all test filenames should end with `-test.js`. For instance: `box-test.js`. +Only a manager can delete bookings and only future bookings can be deleted. Bookings that can be deleted show up with a red text saying the user can double click to delete the booking or the user can tab to the booking and press enter. -## Running Your Tests +ManagerViewOfCustomerBookings -Run your test suite using the command: - -```bash -npm test -``` - -The test results will output to the terminal. - ---- - -## Linting Your Code - -Run the command in your terminal `npm run lint` to run the linter on your JavaScript code. There will be errors and warnings right from the start in this starter kit - the linter is still running successfully. +## Setup -Your linter will look at the JavaScript files you have within the `src` directory and the `test` directory. +1. Clone down this [repo](https://github.com/turingschool-examples/overlook-api) +2. cd into the directory and run `npm install` +3. Run `npm start`. +4. cd out of that directory and clone down this [repo](https://github.com:/daniabee/Hotel-Dani) +5. cd into the director and run `npm install` +6. Run `npm start` +7. Go to `http://localhos:8080/` to view the webpage -## Webpack? +## Technologies used -If you look in the `package.json` file, you'll see one of the library dependencies called `webpack`. If you're interested in learning more about what Webpack is and how it works behind the scenes, take a look through the [Webpack configuration documentation](https://webpack.js.org/concepts/). +- Mocha +- Chai +- Javascript +- HTML +- CSS/SASS +- Github +- Get & Post Netork Requests +- Webpack -## Deploying to GitHub Pages +## Ending Thoughts -_If you are finished with the functionality and testing of your project_, then you can consider deploying your project to the web! This way anyone can play it without cloning down your repo. +At this point in my journey as a software developer, I am very proud of this application. Being able to navigate network requests for the first time was a very big win. Another win was being able to change the origonal webpack loader to handle SASS files. -[GitHub Pages](https://pages.github.com/) is a great way to deploy your project to the web. Don't worry about this until your project is free of bugs and well tested! +Possible Improvements: -If you _are_ done, you can follow [this procedure](./gh-pages-procedure.md) to get your project live on GitHub Pages. +- Add an additional view or section to display past bookings and upcoming bookings, rather than displaying them in the same place. +- Adding dynamic functionality for error handling as do dry up my code even further. +- Cleaning up the error handling css and styling to be more visually appealing. diff --git a/dist/index.html b/dist/index.html index 35332a6f9..34dc42343 100644 --- a/dist/index.html +++ b/dist/index.html @@ -1,16 +1,136 @@ - - - - - Webpack Starter Kit - - - turing logo - - - - - + + + + + + + + Hotel Dani + + +

The

+

Overlook

+
+ +
+ +

Welcome

+ +
+

+ You have not choosen a customer's bookings to view yet! Please + choose a customer. +

+
+
+
+
+ + +
+
+ + +
+
+ +
+
+
+ + +
+
+ +
+
+

Hotel Information:

+

PLACEHOLDER

+

PLACEHOLDER

+

PLACEHOLDER

+

+ Customer: None selected +

+
+
+
+
+

Double click on a room to book it!

+
+ +
+
+
+
+
+ + diff --git a/package-lock.json b/package-lock.json index 2c2dd90c0..9654cfbc7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,12 @@ { "name": "webpack-starter-kit", - "version": "1.0.0", + "version": "2.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "1.0.0", + "name": "webpack-starter-kit", + "version": "2.0.0", "license": "MIT", "devDependencies": { "chai": "^4.3.4", @@ -14,10 +15,10 @@ "file-loader": "^6.2.0", "mocha": "^8.4.0", "mochapack": "^2.1.2", - "sass": "^1.34.0", - "sass-loader": "^12.0.0", + "sass": "^1.56.1", + "sass-loader": "^12.6.0", "style-loader": "^2.0.0", - "webpack": "^5.38.1", + "webpack": "^5.75.0", "webpack-cli": "^4.7.0", "webpack-dev-server": "^3.11.2" } @@ -194,9 +195,9 @@ } }, "node_modules/@types/eslint": { - "version": "7.2.13", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.13.tgz", - "integrity": "sha512-LKmQCWAlnVHvvXq4oasNUMTJJb2GwSyTY8+1C7OH5ILR8mPLaljv1jxL1bXW3xB3jFbQxTKxJAvI8PyjB09aBg==", + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", "dev": true, "dependencies": { "@types/estree": "*", @@ -204,9 +205,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", - "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", "dev": true, "dependencies": { "@types/eslint": "*", @@ -214,9 +215,9 @@ } }, "node_modules/@types/estree": { - "version": "0.0.47", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.47.tgz", - "integrity": "sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==", + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "dev": true }, "node_modules/@types/glob": { @@ -230,9 +231,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "node_modules/@types/minimatch": { @@ -254,148 +255,148 @@ "dev": true }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", - "integrity": "sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", "dev": true, "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0" + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz", - "integrity": "sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", "dev": true }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz", - "integrity": "sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", "dev": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz", - "integrity": "sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", "dev": true }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz", - "integrity": "sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", "dev": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.0", - "@webassemblyjs/helper-api-error": "1.11.0", + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz", - "integrity": "sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", "dev": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz", - "integrity": "sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz", - "integrity": "sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", "dev": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.0.tgz", - "integrity": "sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", "dev": true, "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.0.tgz", - "integrity": "sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", "dev": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz", - "integrity": "sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/helper-wasm-section": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0", - "@webassemblyjs/wasm-opt": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0", - "@webassemblyjs/wast-printer": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz", - "integrity": "sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/ieee754": "1.11.0", - "@webassemblyjs/leb128": "1.11.0", - "@webassemblyjs/utf8": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz", - "integrity": "sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz", - "integrity": "sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-api-error": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/ieee754": "1.11.0", - "@webassemblyjs/leb128": "1.11.0", - "@webassemblyjs/utf8": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz", - "integrity": "sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/ast": "1.11.1", "@xtuc/long": "4.2.2" } }, @@ -1805,9 +1806,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz", - "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -1854,9 +1855,9 @@ } }, "node_modules/es-module-lexer": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.1.tgz", - "integrity": "sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", "dev": true }, "node_modules/escalade": { @@ -2823,9 +2824,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "node_modules/growl": { @@ -3201,6 +3202,12 @@ "node": ">= 4" } }, + "node_modules/immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "dev": true + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3625,10 +3632,10 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, "node_modules/json-schema-traverse": { @@ -5595,24 +5602,26 @@ "dev": true }, "node_modules/sass": { - "version": "1.34.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.34.1.tgz", - "integrity": "sha512-scLA7EIZM+MmYlej6sdVr0HRbZX5caX5ofDT9asWnUJj21oqgsC+1LuNfm0eg+vM0fCTZHhwImTiCU0sx9h9CQ==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.56.1.tgz", + "integrity": "sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==", "dev": true, "dependencies": { - "chokidar": ">=3.0.0 <4.0.0" + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { "sass": "sass.js" }, "engines": { - "node": ">=8.9.0" + "node": ">=12.0.0" } }, "node_modules/sass-loader": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.0.0.tgz", - "integrity": "sha512-LJQMyDdNdhcvoO2gJFw7KpTaioVFDeRJOuatRDUNgCIqyu4s4kgDsNofdGzAZB1zFOgo/p3fy+aR/uGXamcJBg==", + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", "dev": true, "dependencies": { "klona": "^2.0.4", @@ -5627,8 +5636,9 @@ }, "peerDependencies": { "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", "sass": "^1.3.0", + "sass-embedded": "*", "webpack": "^5.0.0" }, "peerDependenciesMeta": { @@ -5640,16 +5650,19 @@ }, "sass": { "optional": true + }, + "sass-embedded": { + "optional": true } } }, "node_modules/schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.6", + "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" }, @@ -6164,12 +6177,6 @@ "ms": "^2.1.1" } }, - "node_modules/source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -6521,9 +6528,9 @@ "dev": true }, "node_modules/tapable": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", - "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true, "engines": { "node": ">=6" @@ -6886,9 +6893,9 @@ } }, "node_modules/watchpack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", - "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dev": true, "dependencies": { "glob-to-regexp": "^0.4.1", @@ -6908,34 +6915,35 @@ } }, "node_modules/webpack": { - "version": "5.38.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.38.1.tgz", - "integrity": "sha512-OqRmYD1OJbHZph6RUMD93GcCZy4Z4wC0ele4FXyYF0J6AxO1vOSuIlU1hkS/lDlR9CDYBz64MZRmdbdnFFoT2g==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.47", - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/wasm-edit": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0", - "acorn": "^8.2.1", + "version": "5.75.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", + "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.0", - "es-module-lexer": "^0.4.0", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.4", - "json-parse-better-errors": "^1.0.2", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.0.0", + "schema-utils": "^3.1.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.1", - "watchpack": "^2.2.0", - "webpack-sources": "^2.3.0" + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" }, "bin": { "webpack": "bin/webpack.js" @@ -7759,22 +7767,18 @@ } }, "node_modules/webpack-sources": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.0.tgz", - "integrity": "sha512-WyOdtwSvOML1kbgtXbTDnEW0jkJ7hZr/bDByIwszhWd/4XX1A3XMkrbFMsuH4+/MfLlZCUzlAdg4r7jaGKEIgQ==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "dev": true, - "dependencies": { - "source-list-map": "^2.0.1", - "source-map": "^0.6.1" - }, "engines": { "node": ">=10.13.0" } }, "node_modules/webpack/node_modules/acorn": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.3.0.tgz", - "integrity": "sha512-tqPKHZ5CaBJw0Xmy0ZZvLs1qTV+BNFSyvn77ASXkpBNfIRk8ev26fKrD9iLGwGA9zedPao52GSHzq8lyZG0NUw==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -7783,6 +7787,15 @@ "node": ">=0.4.0" } }, + "node_modules/webpack/node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", @@ -8147,9 +8160,9 @@ } }, "@types/eslint": { - "version": "7.2.13", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.13.tgz", - "integrity": "sha512-LKmQCWAlnVHvvXq4oasNUMTJJb2GwSyTY8+1C7OH5ILR8mPLaljv1jxL1bXW3xB3jFbQxTKxJAvI8PyjB09aBg==", + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", "dev": true, "requires": { "@types/estree": "*", @@ -8157,9 +8170,9 @@ } }, "@types/eslint-scope": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", - "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", "dev": true, "requires": { "@types/eslint": "*", @@ -8167,9 +8180,9 @@ } }, "@types/estree": { - "version": "0.0.47", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.47.tgz", - "integrity": "sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==", + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "dev": true }, "@types/glob": { @@ -8183,9 +8196,9 @@ } }, "@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, "@types/minimatch": { @@ -8207,148 +8220,148 @@ "dev": true }, "@webassemblyjs/ast": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", - "integrity": "sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", "dev": true, "requires": { - "@webassemblyjs/helper-numbers": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0" + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz", - "integrity": "sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", "dev": true }, "@webassemblyjs/helper-api-error": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz", - "integrity": "sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", "dev": true }, "@webassemblyjs/helper-buffer": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz", - "integrity": "sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", "dev": true }, "@webassemblyjs/helper-numbers": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz", - "integrity": "sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", "dev": true, "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.0", - "@webassemblyjs/helper-api-error": "1.11.0", + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", "@xtuc/long": "4.2.2" } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz", - "integrity": "sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", "dev": true }, "@webassemblyjs/helper-wasm-section": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz", - "integrity": "sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" } }, "@webassemblyjs/ieee754": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz", - "integrity": "sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", "dev": true, "requires": { "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.0.tgz", - "integrity": "sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", "dev": true, "requires": { "@xtuc/long": "4.2.2" } }, "@webassemblyjs/utf8": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.0.tgz", - "integrity": "sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", "dev": true }, "@webassemblyjs/wasm-edit": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz", - "integrity": "sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/helper-wasm-section": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0", - "@webassemblyjs/wasm-opt": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0", - "@webassemblyjs/wast-printer": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" } }, "@webassemblyjs/wasm-gen": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz", - "integrity": "sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/ieee754": "1.11.0", - "@webassemblyjs/leb128": "1.11.0", - "@webassemblyjs/utf8": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" } }, "@webassemblyjs/wasm-opt": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz", - "integrity": "sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" } }, "@webassemblyjs/wasm-parser": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz", - "integrity": "sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-api-error": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/ieee754": "1.11.0", - "@webassemblyjs/leb128": "1.11.0", - "@webassemblyjs/utf8": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" } }, "@webassemblyjs/wast-printer": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz", - "integrity": "sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/ast": "1.11.1", "@xtuc/long": "4.2.2" } }, @@ -9447,9 +9460,9 @@ } }, "enhanced-resolve": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz", - "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -9481,9 +9494,9 @@ } }, "es-module-lexer": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.1.tgz", - "integrity": "sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", "dev": true }, "escalade": { @@ -10236,9 +10249,9 @@ } }, "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "growl": { @@ -10545,6 +10558,12 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "dev": true + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -10854,10 +10873,10 @@ "esprima": "^4.0.0" } }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, "json-schema-traverse": { @@ -12345,18 +12364,20 @@ "dev": true }, "sass": { - "version": "1.34.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.34.1.tgz", - "integrity": "sha512-scLA7EIZM+MmYlej6sdVr0HRbZX5caX5ofDT9asWnUJj21oqgsC+1LuNfm0eg+vM0fCTZHhwImTiCU0sx9h9CQ==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.56.1.tgz", + "integrity": "sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==", "dev": true, "requires": { - "chokidar": ">=3.0.0 <4.0.0" + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" } }, "sass-loader": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.0.0.tgz", - "integrity": "sha512-LJQMyDdNdhcvoO2gJFw7KpTaioVFDeRJOuatRDUNgCIqyu4s4kgDsNofdGzAZB1zFOgo/p3fy+aR/uGXamcJBg==", + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", "dev": true, "requires": { "klona": "^2.0.4", @@ -12364,12 +12385,12 @@ } }, "schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", "dev": true, "requires": { - "@types/json-schema": "^7.0.6", + "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" } @@ -12807,12 +12828,6 @@ } } }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -13094,9 +13109,9 @@ } }, "tapable": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", - "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true }, "terser": { @@ -13380,9 +13395,9 @@ "dev": true }, "watchpack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", - "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dev": true, "requires": { "glob-to-regexp": "^0.4.1", @@ -13399,41 +13414,49 @@ } }, "webpack": { - "version": "5.38.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.38.1.tgz", - "integrity": "sha512-OqRmYD1OJbHZph6RUMD93GcCZy4Z4wC0ele4FXyYF0J6AxO1vOSuIlU1hkS/lDlR9CDYBz64MZRmdbdnFFoT2g==", - "dev": true, - "requires": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.47", - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/wasm-edit": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0", - "acorn": "^8.2.1", + "version": "5.75.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", + "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.0", - "es-module-lexer": "^0.4.0", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.4", - "json-parse-better-errors": "^1.0.2", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.0.0", + "schema-utils": "^3.1.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.1", - "watchpack": "^2.2.0", - "webpack-sources": "^2.3.0" + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" }, "dependencies": { "acorn": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.3.0.tgz", - "integrity": "sha512-tqPKHZ5CaBJw0Xmy0ZZvLs1qTV+BNFSyvn77ASXkpBNfIRk8ev26fKrD9iLGwGA9zedPao52GSHzq8lyZG0NUw==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true + }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "requires": {} } } }, @@ -14063,14 +14086,10 @@ } }, "webpack-sources": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.0.tgz", - "integrity": "sha512-WyOdtwSvOML1kbgtXbTDnEW0jkJ7hZr/bDByIwszhWd/4XX1A3XMkrbFMsuH4+/MfLlZCUzlAdg4r7jaGKEIgQ==", - "dev": true, - "requires": { - "source-list-map": "^2.0.1", - "source-map": "^0.6.1" - } + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true }, "websocket-driver": { "version": "0.7.4", diff --git a/package.json b/package.json index d17cebc1d..bf15a3115 100644 --- a/package.json +++ b/package.json @@ -16,10 +16,10 @@ "file-loader": "^6.2.0", "mocha": "^8.4.0", "mochapack": "^2.1.2", - "sass": "^1.34.0", - "sass-loader": "^12.0.0", + "sass": "^1.56.1", + "sass-loader": "^12.6.0", "style-loader": "^2.0.0", - "webpack": "^5.38.1", + "webpack": "^5.75.0", "webpack-cli": "^4.7.0", "webpack-dev-server": "^3.11.2" }, diff --git a/src/apiCalls.js b/src/apiCalls.js new file mode 100644 index 000000000..11a340ccd --- /dev/null +++ b/src/apiCalls.js @@ -0,0 +1,10 @@ +function loadData(URL) { + return fetch(URL).then((res) => { + if (!res.ok) { + throw new Error("Failed to fetch at loadData"); + } + return res.json(); + }); +} + +export default loadData; diff --git a/src/classes/booking.js b/src/classes/booking.js new file mode 100644 index 000000000..3451ee5c0 --- /dev/null +++ b/src/classes/booking.js @@ -0,0 +1,10 @@ +class Booking { + constructor(data) { + this.id = data.id; + this.userID = data.userID; + this.date = data.date; + this.roomNumber = data.roomNumber; + } +} + +export default Booking; diff --git a/src/classes/customer.js b/src/classes/customer.js new file mode 100644 index 000000000..a38cc6722 --- /dev/null +++ b/src/classes/customer.js @@ -0,0 +1,26 @@ +class Customer { + constructor(data) { + this.id = data.id; + this.name = data.name; + this.username = `customer${data.id}`; + this.password = "overlook2021"; + } + getMyBookings(bookings) { + let myBookings = bookings + .filter((booking) => booking.userID === this.id) + .sort((a, b) => { + if (a.date >= b.date) { + return -1; + } + }); + + console.log(myBookings); + if (myBookings.length > 0) { + return myBookings; + } else { + return `You have not made any bookings.`; + } + } +} + +export default Customer; diff --git a/src/classes/hotel.js b/src/classes/hotel.js new file mode 100644 index 000000000..55c037a2e --- /dev/null +++ b/src/classes/hotel.js @@ -0,0 +1,140 @@ +import Room from "./room"; +import Booking from "./booking"; +import Customer from "./customer"; + +class Hotel { + constructor(roomData, bookingData) { + this.allRooms = this.createRooms(roomData); + this.allBookings = this.createBookings(bookingData); + this.allCustomers = []; + this.availableRooms = []; + } + createRooms(roomData) { + this.allRooms = roomData.map((room) => new Room(room)); + return this.allRooms; + } + createBookings(bookingData) { + this.allBookings = bookingData.map((details) => new Booking(details)); + return this.allBookings; + } + + createCustomers(customerData) { + this.allCustomers = customerData.map((details) => new Customer(details)); + return this.allCustomers; + } + + login(username, password) { + const user = this.allCustomers.find((customer) => { + if (customer.username === username && customer.password === password) { + return customer; + } + }); + if (username === "manager" && password === "overlook2021") { + return "manager"; + } else { + return user; + } + } + + findCustomerBookings(currentUser) { + return currentUser.getMyBookings(this.allBookings); + } + + findBookingByID(id) { + return this.allBookings.find((booking) => booking.id === id); + } + + findBookedRoomNumber(date) { + const bookedRoom = this.allBookings.filter( + (booking) => date === booking.date + ); + return bookedRoom.map((room) => room.roomNumber); + } + + findSpecificRoomByNumber(number, dataSet = this.allRooms) { + return dataSet.find((room) => room.number === number); + } + + filterRoomsByType(type, data = this.availableRooms) { + if (type === "no-preference") { + return data; + } else { + return data.filter((room) => room.roomType === type); + } + } + + findACustomer(name) { + return this.allCustomers.find( + (customer) => customer.name.toLowerCase() == name.toLowerCase() + ); + } + + findAvailableRooms(date) { + this.availableRooms = []; + const bookedRooms = this.findBookedRoomNumber(date); + this.availableRooms = this.allRooms.filter( + (room) => !bookedRooms.includes(room.number) + ); + return this.availableRooms; + } + + findCustomerBookingExpenses(currentUser) { + let myRooms = this.findCustomerBookings(currentUser); + if (myRooms === "You have not made any bookings.") { + return myRooms; + } else { + myRooms = myRooms.map((room) => room.roomNumber); + return myRooms.reduce((acc, current) => { + let room = this.findSpecificRoomByNumber(current); + acc = acc + room.costPerNight; + return acc; + }, 0); + } + } + + totalRevenue(date) { + const todaysBookings = this.findBookedRoomNumber(date); + return todaysBookings.reduce((acc, current) => { + let room = this.findSpecificRoomByNumber(current); + acc = acc + room.costPerNight; + return acc; + }, 0); + } + + chooseADate(date) { + const today = this.getToday(); + let chosenDate = new Date(date); + if (chosenDate >= today) { + chosenDate = chosenDate.toISOString(); + chosenDate = chosenDate.split("T"); + let newChosenDate = chosenDate[0].split("-").join("/"); + return newChosenDate; + } else { + return `Please choose a valid date`; + } + } + + getToday() { + const today = Date.now(); + const date = new Date(today); + date.setHours(0, 0, 0, 0); + return date; + } + + createNewBooking(currentUser, roomNumber, date) { + const newBooking = new Object(); + newBooking.userID = currentUser.id; + newBooking.date = date; + newBooking.roomNumber = roomNumber; + return newBooking; + } + + deleteABooking(id) { + const booking = this.allBookings.find((booking) => booking.id === id); + const index = this.allBookings.indexOf(booking); + this.allBookings.splice(index, 1); + return this.allBookings; + } +} + +export default Hotel; diff --git a/src/classes/room.js b/src/classes/room.js new file mode 100644 index 000000000..0ecf836c4 --- /dev/null +++ b/src/classes/room.js @@ -0,0 +1,12 @@ +class Room { + constructor(data) { + this.number = data.number; + this.roomType = data.roomType; + this.bidet = data.bidet; + this.bedSize = data.bedSize; + this.numBeds = data.numBeds; + this.costPerNight = data.costPerNight; + } +} + +export default Room; diff --git a/src/css/styles.css b/src/css/styles.css deleted file mode 100644 index 2a7971ab1..000000000 --- a/src/css/styles.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - background: radial-gradient(circle, rgba(63,94,251,1) 0%, rgba(252,70,107,1) 100%); -} diff --git a/src/css/styles.scss b/src/css/styles.scss new file mode 100644 index 000000000..4bf8a8108 --- /dev/null +++ b/src/css/styles.scss @@ -0,0 +1,280 @@ +$lightBlue: rgba(0, 238, 255); +$medBlue: rgba(19, 165, 255); +$darkBlue: rgb(22, 42, 193); +$white: rgb(255, 229, 208); +$sand: rgb(231, 231, 231); +$navy: rgb(0, 0, 30); +$fontGreatVibes: "Great Vibes", cursive; +$fontCantanaOne: "Cantata One", serif; +$backgroundPicture: url("../images/vacation.jpg"); + +body { + font-family: $fontCantanaOne; + background-image: $backgroundPicture; + background-size: cover; + background-repeat: repeat-y; +} + +.title { + color: $navy; + display: flex; + flex-direction: row; + margin: 1%; + margin-bottom: 0; + + #Overlook { + font-family: $fontGreatVibes; + font-size: 13vw; + margin: 0; + text-shadow: -0.1rem 0.1rem 0 $sand, 0.1rem 0.1rem 0 $sand, + 0.1rem -0.1rem 0 $sand, -0.1rem -0.1rem 0 $sand; + } + + #The { + font-family: $fontCantanaOne; + font-size: 3vw; + align-self: center; + margin: 0; + margin-bottom: 9%; + text-shadow: -0.1rem 0.1rem 0 $sand, 0.1rem 0.1rem 0 $sand, + 0.1rem -0.1rem 0 $sand, -0.1rem -0.1rem 0 $sand; + } +} + +.navigation { + display: flex; + flex-direction: row; + justify-content: space-between; + + .first-navigation { + margin-left: 3rem; + } +} + +button { + padding: 1%; + font-family: $fontCantanaOne; + font-size: 1vw; + height: auto; + width: 15vw; + border: solid $sand 2px; + border-radius: 0.25rem; + background-color: $navy; + color: $sand; +} + +button:hover { + cursor: pointer; +} + +.sign-in { + margin-right: 4%; + padding: 0; +} + +.log-in { + display: flex; + flex-direction: column; + width: 90vw; + justify-content: center; + align-items: center; + + .input-bar { + display: flex; + flex-direction: column; + margin-bottom: 2rem; + .icon-image { + width: 3vw; + height: auto; + padding: 0.25rem; + padding-bottom: 0; + } + label { + align-self: center; + font-family: $fontCantanaOne; + font-size: 3vw; + } + input { + height: 6vh; + width: 35vw; + border-radius: 0.5rem; + font-size: 2vw; + text-align: center; + } + } +} + +.main { + display: flex; + justify-content: center; + align-content: center; + opacity: 90%; +} + +.main-box { + display: flex; + min-height: 60vh; + height: min-content; + width: 100vw; + border-radius: 0.6rem; + background-image: linear-gradient($lightBlue, $navy); + box-shadow: $sand 0 0.3rem 2rem 0.1rem; + margin: 3%; + margin-top: 1%; +} + +.welcome-normal { + text-align: center; + padding: 5%; + padding-top: 8%; + font-family: $fontCantanaOne; + font-size: 10vw; + color: $sand; + margin: 0; + text-shadow: -0.1rem 0.1rem 0 $navy, 0.1rem 0.1rem 0 $navy, + 0.1rem -0.1rem 0 $navy, -0.1rem -0.1rem 0 $navy; +} + +.welcome-styling { + align-self: center; + text-align: center; + font-family: $fontGreatVibes; + background-image: linear-gradient( + -225deg, + $sand 0%, + $white 10%, + $lightBlue 20%, + $medBlue 40%, + $darkBlue 60%, + $navy 70%, + $lightBlue 80%, + $white 90%, + $sand 100% + ); + background-size: 300% auto; + color: #fff; + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + animation: transition 15s linear infinite; + display: inline-block; + font-size: 10vw; + margin: 0; + padding: 5rem; +} + +@keyframes transition { + to { + background-position: 200% center; + } +} + +.add-booking { + display: flex; + flex-direction: row; +} + +.booking-results { + width: 50vw; +} + +#booking-form { + display: flex; + flex-direction: column; + border: 2px solid $white; + border-radius: 0.25rem; + width: 40vw; + background-color: $navy; + margin: 1%; + + label { + margin-bottom: 1rem; + color: $white; + } + input, + .form-control { + display: block; + height: 2.5rem; + padding: 0.375rem 0.75rem; + color: $white; + background-color: $navy; + border: 2px solid $lightBlue; + border-radius: 0.25rem; + } + .form-group { + display: flex; + flex-direction: column; + padding: 1rem; + padding-bottom: 0; + margin: 1%; + } + .submit-button { + background-color: $white; + color: $navy; + align-self: center; + margin-bottom: 1rem; + .submit-button:hover { + cursor: pointer; + } + } +} + +#available-rooms { + text-align: center; +} + +.room-thumbnails { + display: grid; + grid-template-columns: repeat(2, 1fr); +} + +.single-room-thumbnail { + justify-self: center; + color: $white; + border: $white solid 2px; + border-radius: 0.25rem; + background-color: $navy; + width: min-content; + padding: 2%; + margin: 5%; +} + +.single-room-img { + height: 22vh; + width: auto; +} + +.try-again, +.delete { + font-style: italic; + color: rgb(154, 0, 0); +} + +.manage-bookings { + padding: 1%; + display: grid; + grid-template-columns: repeat(5, 1fr); + grid-gap: 2rem; +} + +.user-booking { + padding: 2%; + color: $sand; + border-radius: 1rem; + background-color: $navy; + border: 2px solid $white; +} + +.hotel-info { + padding-left: 2rem; + font-size: 1vw; + color: $white; +} + +.total-spent { + color: $white; +} + +.hide { + display: none; +} diff --git a/src/images/HotelRoom1.png b/src/images/HotelRoom1.png new file mode 100644 index 000000000..015a8536f Binary files /dev/null and b/src/images/HotelRoom1.png differ diff --git a/src/images/HotelRoom2.png b/src/images/HotelRoom2.png new file mode 100644 index 000000000..f478c466b Binary files /dev/null and b/src/images/HotelRoom2.png differ diff --git a/src/images/HotelRoom3.png b/src/images/HotelRoom3.png new file mode 100644 index 000000000..9f0c2b95c Binary files /dev/null and b/src/images/HotelRoom3.png differ diff --git a/src/images/HotelRoom4.png b/src/images/HotelRoom4.png new file mode 100644 index 000000000..5bf17c607 Binary files /dev/null and b/src/images/HotelRoom4.png differ diff --git a/src/images/lock.png b/src/images/lock.png new file mode 100644 index 000000000..c4f07b9d6 Binary files /dev/null and b/src/images/lock.png differ diff --git a/src/images/user.png b/src/images/user.png new file mode 100644 index 000000000..ff20a20a6 Binary files /dev/null and b/src/images/user.png differ diff --git a/src/images/vacation.jpg b/src/images/vacation.jpg new file mode 100644 index 000000000..971e8516c Binary files /dev/null and b/src/images/vacation.jpg differ diff --git a/src/sampleData/booking_sample_data.js b/src/sampleData/booking_sample_data.js new file mode 100644 index 000000000..598f39b69 --- /dev/null +++ b/src/sampleData/booking_sample_data.js @@ -0,0 +1,34 @@ +const bookingsData = [ + { + id: "5fwrgu4i7k55hl6sz", + userID: 9, + date: "2023/04/22", + roomNumber: 15, + }, + { + id: "5fwrgu4i7k55hl6t5", + userID: 43, + date: "2022/01/24", + roomNumber: 24, + }, + { + id: "5fwrgu4i7k55hl6t6", + userID: 13, + date: "2022/01/10", + roomNumber: 12, + }, + { + id: "5fwrgu4i7k55hl6t7", + userID: 20, + date: "2022/02/16", + roomNumber: 7, + }, + { + id: "5fwrgu4i7k55hl6t8", + userID: 1, + date: "2023/02/05", + roomNumber: 12, + }, +]; + +export default bookingsData; diff --git a/src/sampleData/customer_sample_data.js b/src/sampleData/customer_sample_data.js new file mode 100644 index 000000000..7e464fc97 --- /dev/null +++ b/src/sampleData/customer_sample_data.js @@ -0,0 +1,28 @@ +const customerData = [ + { + id: 1, + name: "Leatha Ullrich", + }, + { + id: 2, + name: "Rocio Schuster", + }, + { + id: 3, + name: "Kelvin Schiller", + }, + { + id: 4, + name: "Kennedi Emard", + }, + { + id: 5, + name: "Rhiannon Little", + }, + { + id: 6, + name: "Fleta Schuppe", + }, +]; + +export default customerData; diff --git a/src/sampleData/room_sample_data.js b/src/sampleData/room_sample_data.js new file mode 100644 index 000000000..aff60ea45 --- /dev/null +++ b/src/sampleData/room_sample_data.js @@ -0,0 +1,52 @@ +const roomData = [ + { + number: 1, + roomType: "residential suite", + bidet: true, + bedSize: "queen", + numBeds: 1, + costPerNight: 358.4, + }, + { + number: 2, + roomType: "suite", + bidet: false, + bedSize: "full", + numBeds: 2, + costPerNight: 477.38, + }, + { + number: 3, + roomType: "single room", + bidet: false, + bedSize: "king", + numBeds: 1, + costPerNight: 491.14, + }, + { + number: 4, + roomType: "single room", + bidet: false, + bedSize: "queen", + numBeds: 1, + costPerNight: 429.44, + }, + { + number: 15, + roomType: "single room", + bidet: true, + bedSize: "queen", + numBeds: 2, + costPerNight: 340.17, + }, + { + number: 12, + roomType: "single room", + bidet: true, + bedSize: "queen", + numBeds: 2, + costPerNight: 50.25, + }, +]; + +export default roomData; diff --git a/src/scripts.js b/src/scripts.js index f743b4444..5ef024315 100644 --- a/src/scripts.js +++ b/src/scripts.js @@ -1,11 +1,395 @@ -// This is the JavaScript entry file - your code begins here -// Do not delete or rename this file ******** +import "./css/styles.scss"; +import Hotel from "./classes/hotel"; +import loadData from "./apiCalls"; +import "./images/HotelRoom1.png"; +import "./images/HotelRoom2.png"; +import "./images/HotelRoom3.png"; +import "./images/HotelRoom4.png"; +import "./images/lock.png"; +import "./images/user.png"; -// An example of how you tell webpack to use a CSS (SCSS) file -import './css/styles.css'; +let currentUser; +let overlookHotel; +let chosenDate; +let manager = false; -// An example of how you tell webpack to use an image (also need to link to it in the index.html) -import './images/turing-logo.png' +const loginSection = document.querySelector(".log-in"); +const loginButton = document.getElementById("login-btn"); +const username = document.getElementById("name"); +const password = document.getElementById("password"); +const loginError = document.querySelector(".bad-login"); +const signIn = document.querySelector(".sign-in"); +const navigationBar = document.querySelector(".first-navigation"); +const manageBookingsSection = document.querySelector(".manage-bookings"); +const addBookingsSection = document.querySelector(".add-booking"); +const welcome = document.querySelector(".welcome"); +let availableRooms = document.querySelector(".room-thumbnails"); +let myBookings = document.querySelector(".manage-bookings"); +let wantedRoomType = document.querySelector("#select-room"); +const submitBookingButton = document.querySelector("#submit-booking"); +const calendar = document.getElementById("calendar"); +const managerFormSection = document.querySelector(".managers-form-section"); +const roomsAvailableInfo = document.querySelector("#rooms-available"); +const totalRevenueInfo = document.querySelector("#total-revenue"); +const occupiedRoomsInfo = document.querySelector("#percentage-occupied"); +const currentSearchedCustomer = document.querySelector( + "#current-searched-customer" +); +const chooseCustomerButton = document.querySelector("#search-customers"); +const findCustomerInput = document.querySelector("#find-customer"); +window.addEventListener("load", loadAllData); +loginButton.addEventListener("click", loginCustomer); +navigationBar.addEventListener("click", changePageDisplay); +signIn.addEventListener("click", backToLogin); +submitBookingButton.addEventListener("click", searchForBookableRooms); +availableRooms.addEventListener("dblclick", bookRoom); +availableRooms.addEventListener("keydown", function (e) { + if (e.key === "Enter") { + bookRoomKeyDown(e); + } +}); +chooseCustomerButton.addEventListener("click", managerCustomerSearch); +myBookings.addEventListener("dblclick", function (e) { + if (manager) { + deleteBooking(e); + } +}); +myBookings.addEventListener("keydown", function (e) { + if (e.key === "Enter" && manager) { + deleteBooking(e); + } +}); -console.log('This is the JavaScript entry file - your code begins here.'); +function loadAllData() { + Promise.all([ + loadData("http://localhost:3001/api/v1/customers"), + loadData("http://localhost:3001/api/v1/rooms"), + loadData("http://localhost:3001/api/v1/bookings"), + ]) + .then((data) => { + overlookHotel = new Hotel(data[1].rooms, data[2].bookings); + overlookHotel.createCustomers(data[0].customers); + }) + .catch((error) => { + loginError.innerText = + "We are so sorry! There was a problem loading the data!"; + show(loginError); + }); +} + +function loginCustomer() { + event.preventDefault(); + currentUser = overlookHotel.login(username.value, password.value); + if (currentUser === undefined) { + loginError.innerText = "Invalid credentials! Please try again!"; + show(loginError); + return "did not work"; + } else { + getCustomer(currentUser.id); + } +} + +function getCustomer(id) { + if (currentUser != "manager") { + loginACustomer(); + fetch(`http://localhost:3001/api/v1/customers/${currentUser.id}`) + .then((res) => { + if (!res.ok) { + throw new Error("Something went wrong!"); + } + return res.json; + }) + .then((data) => { + loginACustomer(); + }) + .catch((err) => { + loginError.innerText = + "We are so sorry! We cannot log you in at this time."; + show(loginError); + }); + } else { + loginManager(); + } +} + +function loginACustomer() { + hide(loginSection); + hide(managerFormSection); + show(navigationBar); + show(welcome); + show(signIn); + welcome.innerText = `Welcome ${currentUser.name}`; + updateCustomerBookings(); + manager = false; + return currentUser; +} + +function loginManager() { + displayHotelInfo(); + hide(loginSection); + show(navigationBar); + show(welcome); + show(signIn); + show(managerFormSection); + myBookings.innerHTML = ` +

No customer chosen yet! To see bookings, choose a customer!

`; + welcome.innerText = `Welcome Manager`; + currentSearchedCustomer.innerText = `Current Customer: None selected`; + manager = true; + return currentUser; +} + +function backToLogin() { + hide(manageBookingsSection); + hide(addBookingsSection); + hide(welcome); + hide(navigationBar); + hide(signIn); + show(loginSection); + currentUser = ""; + availableRooms.innerHTML = ""; + username.value = ""; +} + +function changePageDisplay(event) { + hide(manageBookingsSection); + hide(addBookingsSection); + hide(welcome); + if (event.target.classList.contains("manage-bookings-button")) { + if (currentUser != "manager") { + updateCustomerBookings(); + } + show(manageBookingsSection); + } else if (event.target.classList.contains("create-bookings-button")) { + show(addBookingsSection); + displayHotelInfo(); + availableRooms.innerHTML = ""; + } +} + +function updateCustomerBookings() { + displayRoomBookings(generateCustomerBookings()); +} + +function generateCustomerBookings() { + const booking = currentUser.getMyBookings(overlookHotel.allBookings); + return booking; +} + +function displayRoomBookings(data) { + let cost = overlookHotel.findCustomerBookingExpenses(currentUser); + const today = overlookHotel.chooseADate(overlookHotel.getToday()); + if (cost === "You have not made any bookings.") { + myBookings.innerHTML = `

${cost}

`; + } else { + cost = cost.toFixed(2); + myBookings.innerHTML = ""; + if (!manager) { + data.forEach((booking) => { + myBookings.innerHTML += ` +
Date: ${booking.date}

+

Room: ${booking.roomNumber}

+
+ `; + }); + } else { + data.forEach((booking) => { + if (booking.date >= today) { + myBookings.innerHTML += ` +
+

Date: ${booking.date}

+

Room: ${booking.roomNumber}

+

Double click to delete

+
+ `; + } else { + myBookings.innerHTML += ` +
+

Date: ${booking.date}

+

Room: ${booking.roomNumber}

+
+ `; + } + }); + } + myBookings.innerHTML += `

Total Spent: $${cost}

`; + } +} + +function searchForBookableRooms() { + event.preventDefault(); + getAllBookings(); + displayHotelInfo(); + let date = `${calendar.value}`; + date = date.split("-").join("/"); + chosenDate = overlookHotel.chooseADate(date); + availableRooms.innerHTML = ""; + const room = wantedRoomType.value; + const foundRooms = overlookHotel.findAvailableRooms(date); + if (chosenDate === "Please choose a valid date") { + availableRooms.innerHTML = ` +

We cannot search for bookings with a past or invalid date! Please try again.

+ `; + } else if (room === "") { + availableRooms.innerHTML = ` +

Please select a room prefrence!

+ `; + } else if (foundRooms.length === 0) { + availableRooms.innerHTML = `

We are so sorry, there are no bookings available with your specifications! + Please modify your search!

`; + } else { + if (room === "no-preference") { + displayAvailableRooms(foundRooms); + } else if (room != "no-preference") { + const withRoom = overlookHotel.filterRoomsByType(room, foundRooms); + if (withRoom.length === 0) { + availableRooms.innerHTML = `

We are so sorry, there are no bookings available with your specifications! + Please modify your search!

`; + } else { + displayAvailableRooms(withRoom); + } + } + } +} + +function displayAvailableRooms(data) { + data.forEach((room) => { + availableRooms.innerHTML += ` +
+ Image of room ${room.number} +
+

Room number: ${room.number}

+

Room type: ${room.roomType}

+

Bidet: ${room.bidet}

+

Bed size: ${room.bedSize}

+

Number of beds: ${room.numBeds}

+

Cost per night: ${room.costPerNight}

+
+
`; + }); +} + +function bookRoom(event) { + const id = +event.target.parentElement.id; + const booking = overlookHotel.createNewBooking(currentUser, id, chosenDate); + postBooking(booking); +} + +function bookRoomKeyDown(event) { + const id = +event.target.id; + const booking = overlookHotel.createNewBooking(currentUser, id, chosenDate); + postBooking(booking); +} + +function postBooking(bookingToSend) { + fetch("http://localhost:3001/api/v1/bookings", { + method: "POST", + body: JSON.stringify(bookingToSend), + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => { + if (!response.ok) { + throw new Error("Something went wrong"); + } + return response.json(); + }) + .then((data) => { + availableRooms.innerHTML = ` +

Saved Booking!

`; + getAllBookings(); + }) + .catch((err) => { + if (currentUser === "manager") { + availableRooms.innerHTML = ` +

There was a problem saving your booking! Please check to see if you have a customer selected!

+ `; + } else { + availableRooms.innerHTML = ` +

There was a problem saving your booking!

+ `; + } + }); +} + +function getAllBookings() { + fetch("http://localhost:3001/api/v1/bookings") + .then((res) => { + if (!res.ok) { + throw new Error("Failed to fetch data"); + } + return res.json(); + }) + .then((data) => { + overlookHotel.createBookings(data.bookings); + updateCustomerBookings(); + }) + .catch((error) => { + myBookings.innerHTML = ` +

There was a problem retrieving your bookings data!

+ `; + }); +} + +function displayHotelInfo() { + const today = overlookHotel.chooseADate(overlookHotel.getToday()); + const available = overlookHotel.findAvailableRooms(today); + const totalRevenue = overlookHotel.totalRevenue(today); + const percentageBooked = + (available.length / overlookHotel.allRooms.length) * 100; + roomsAvailableInfo.innerText = `Current number of rooms available: ${available.length}`; + totalRevenueInfo.innerText = `Today's hotel revenue: $${totalRevenue.toFixed( + 2 + )}`; + occupiedRoomsInfo.innerText = `Percentage of rooms booked: ${percentageBooked}%`; +} + +function managerCustomerSearch() { + event.preventDefault(); + const name = findCustomerInput.value; + currentUser = overlookHotel.findACustomer(name); + currentSearchedCustomer.innerText = `Current Customer: ${currentUser.name}`; + updateCustomerBookings(); + findCustomerInput.value = ""; +} + +function deleteBooking(event) { + event.preventDefault(); + let id = event.target.dataset.indexNumber; + const found = overlookHotel.findBookingByID(id); + const today = overlookHotel.chooseADate(overlookHotel.getToday()); + if (found.date >= today) { + fetch(`http://localhost:3001/api/v1/bookings/${id}`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => { + if (!response.ok) { + throw new Error("Something went wrong"); + } + return response.json(); + }) + .then((data) => { + overlookHotel.deleteABooking(id); + myBookings.innerHTML = `

${data.message}! Click the 'Manage Bookings" button to go back!

`; + }) + .catch((err) => { + myBookings.innerHTML = `

There was a problem deleting your data! Please click the 'Manage Bookings' button to try again!

`; + }); + } else { + myBookings.innerHTML = `

We cannot delete past bookings! Please click the 'Manage Bookings' button to try again!

`; + } +} + +function hide(element) { + element.classList.add("hide"); +} + +function show(element) { + element.classList.remove("hide"); +} diff --git a/test/booking_test.js b/test/booking_test.js new file mode 100644 index 000000000..df0e2e090 --- /dev/null +++ b/test/booking_test.js @@ -0,0 +1,31 @@ +import chai from "chai"; +import Booking from "../src/classes/booking"; +import bookingsData from "../src/sampleData/booking_sample_data"; +const expect = chai.expect; + +describe("Booking", function () { + let data = bookingsData[0]; + let data2 = bookingsData[1]; + let booking1 = new Booking(data); + let booking2 = new Booking(data2); + + it("Should take in an object", function () { + expect(data).to.be.an("object"); + }); + it("Should have an id", function () { + expect(booking1.id).to.equal("5fwrgu4i7k55hl6sz"); + expect(booking2.id).to.equal("5fwrgu4i7k55hl6t5"); + }); + it("Should have a user ID", function () { + expect(booking1.userID).to.equal(9); + expect(booking2.userID).to.equal(43); + }); + it("Should have a date", function () { + expect(booking1.date).to.equal("2023/04/22"); + expect(booking2.date).to.equal("2022/01/24"); + }); + it("Should have a room number", function () { + expect(booking1.roomNumber).to.equal(15); + expect(booking2.roomNumber).to.equal(24); + }); +}); diff --git a/test/customer_test.js b/test/customer_test.js new file mode 100644 index 000000000..193eb7e06 --- /dev/null +++ b/test/customer_test.js @@ -0,0 +1,47 @@ +import chai from "chai"; +import Customer from "../src/classes/customer"; +import customerData from "../src/sampleData/customer_sample_data"; +import bookingsData from "../src/sampleData/booking_sample_data"; +const expect = chai.expect; + +describe("Customer", function () { + let data = customerData[0]; + let data2 = customerData[1]; + let customer1 = new Customer(data); + let customer2 = new Customer(data2); + + it("Should take in an object", function () { + expect(data).to.be.an("object"); + }); + it("Should have an id", function () { + expect(customer1.id).to.equal(1); + expect(customer2.id).to.equal(2); + }); + it("Should have a name", function () { + expect(customer1.name).to.equal("Leatha Ullrich"); + expect(customer2.name).to.equal("Rocio Schuster"); + }); + it("Should have a username", function () { + expect(customer1.username).to.equal("customer1"); + expect(customer2.username).to.equal("customer2"); + }); + it("Should have a password", function () { + expect(customer1.password).to.equal("overlook2021"); + expect(customer2.password).to.equal("overlook2021"); + }); + it("Should be able to find customers bookings", function () { + expect(customer1.getMyBookings(bookingsData)).to.deep.equal([ + { + id: "5fwrgu4i7k55hl6t8", + userID: 1, + date: "2023/02/05", + roomNumber: 12, + }, + ]); + }); + it("Should should tell the customer if they have no bookings", function () { + expect(customer2.getMyBookings(bookingsData)).to.equal( + "You have not made any bookings." + ); + }); +}); diff --git a/test/hotel_test.js b/test/hotel_test.js new file mode 100644 index 000000000..fb071682e --- /dev/null +++ b/test/hotel_test.js @@ -0,0 +1,503 @@ +import chai from "chai"; +import Booking from "../src/classes/booking"; +import Room from "../src/classes/room"; +import Hotel from "../src/classes/hotel"; +import customerData from "../src/sampleData/customer_sample_data"; +import roomData from "../src/sampleData/room_sample_data"; +import bookingsData from "../src/sampleData/booking_sample_data"; +import Customer from "../src/classes/customer"; +const expect = chai.expect; + +describe("Hotel", function () { + let hotelDani = new Hotel(roomData, bookingsData); + it("Should have an array that can hold all the rooms in the hotel", function () { + expect(hotelDani.allRooms).to.deep.equal([ + { + number: 1, + roomType: "residential suite", + bidet: true, + bedSize: "queen", + numBeds: 1, + costPerNight: 358.4, + }, + { + number: 2, + roomType: "suite", + bidet: false, + bedSize: "full", + numBeds: 2, + costPerNight: 477.38, + }, + { + number: 3, + roomType: "single room", + bidet: false, + bedSize: "king", + numBeds: 1, + costPerNight: 491.14, + }, + { + number: 4, + roomType: "single room", + bidet: false, + bedSize: "queen", + numBeds: 1, + costPerNight: 429.44, + }, + { + number: 15, + roomType: "single room", + bidet: true, + bedSize: "queen", + numBeds: 2, + costPerNight: 340.17, + }, + { + number: 12, + roomType: "single room", + bidet: true, + bedSize: "queen", + numBeds: 2, + costPerNight: 50.25, + }, + ]); + }); + it("Should have the list of rooms be instances of Rooms", function () { + expect(hotelDani.allRooms[0]).to.be.instanceOf(Room); + expect(hotelDani.allRooms[3]).to.be.instanceOf(Room); + }); + it("Should have a list of all bookings for the hotel", function () { + expect(hotelDani.allBookings).to.deep.equal([ + { + id: "5fwrgu4i7k55hl6sz", + userID: 9, + date: "2023/04/22", + roomNumber: 15, + }, + { + id: "5fwrgu4i7k55hl6t5", + userID: 43, + date: "2022/01/24", + roomNumber: 24, + }, + { + id: "5fwrgu4i7k55hl6t6", + userID: 13, + date: "2022/01/10", + roomNumber: 12, + }, + { + id: "5fwrgu4i7k55hl6t7", + userID: 20, + date: "2022/02/16", + roomNumber: 7, + }, + { + id: "5fwrgu4i7k55hl6t8", + userID: 1, + date: "2023/02/05", + roomNumber: 12, + }, + ]); + }); + it("Should have the list of bookings be instances of Booking", function () { + expect(hotelDani.allBookings[0]).to.be.instanceOf(Booking); + expect(hotelDani.allBookings[3]).to.be.instanceOf(Booking); + }); + it("Should be able to update list of rooms", function () { + const newRoomData = [roomData[0]]; + hotelDani.createRooms(newRoomData); + expect(hotelDani.allRooms).to.deep.equal([ + { + number: 1, + roomType: "residential suite", + bidet: true, + bedSize: "queen", + numBeds: 1, + costPerNight: 358.4, + }, + ]); + }); + it("Should be able to update list of bookings", function () { + const newBookingData = [bookingsData[0]]; + hotelDani.createBookings(newBookingData); + expect(hotelDani.allBookings).to.deep.equal([ + { + id: "5fwrgu4i7k55hl6sz", + userID: 9, + date: "2023/04/22", + roomNumber: 15, + }, + ]); + }); + it("Should have a list of customers", function () { + hotelDani.createCustomers(customerData); + expect(hotelDani.allCustomers).to.deep.equal([ + { + id: 1, + name: "Leatha Ullrich", + username: "customer1", + password: "overlook2021", + }, + { + id: 2, + name: "Rocio Schuster", + username: "customer2", + password: "overlook2021", + }, + { + id: 3, + name: "Kelvin Schiller", + username: "customer3", + password: "overlook2021", + }, + { + id: 4, + name: "Kennedi Emard", + username: "customer4", + password: "overlook2021", + }, + { + id: 5, + name: "Rhiannon Little", + username: "customer5", + password: "overlook2021", + }, + { + id: 6, + name: "Fleta Schuppe", + username: "customer6", + password: "overlook2021", + }, + ]); + }); + it("Should be able to find a user based on their login information", function () { + const found1 = hotelDani.login("customer1", "overlook2021"); + const found2 = hotelDani.login("customer2", "overlook2021"); + expect(found1).to.deep.equal({ + id: 1, + name: "Leatha Ullrich", + password: "overlook2021", + username: "customer1", + }); + expect(found2).to.deep.equal({ + id: 2, + name: "Rocio Schuster", + password: "overlook2021", + username: "customer2", + }); + }); + it("Should be able to login the manager", function () { + const found1 = hotelDani.login("manager", "overlook2021"); + expect(found1).to.equal("manager"); + }); + it("Should return undefined if there is no valid user or manager credentials", function () { + const found1 = hotelDani.login("customer150", "overlook2021"); + expect(found1).to.equal(undefined); + }); + it("Should find bookings for any given customer", function () { + hotelDani.createBookings(bookingsData); + const currentCustomer = new Customer(customerData[0]); + const myBookings = hotelDani.findCustomerBookings(currentCustomer); + expect(myBookings).to.deep.equal([ + { + id: "5fwrgu4i7k55hl6t8", + userID: 1, + date: "2023/02/05", + roomNumber: 12, + }, + ]); + }); + it("Should let the customer know if there are no bookings for any given customer", function () { + const currentCustomer = new Customer(customerData[3]); + const myBookings = hotelDani.findCustomerBookings(currentCustomer); + expect(myBookings).to.deep.equal("You have not made any bookings."); + }); + it("Should be able to find total booking expenses for any given customer", function () { + const currentCustomer = new Customer(customerData[0]); + hotelDani.createRooms(roomData); + hotelDani.createBookings(bookingsData); + const expenses = hotelDani.findCustomerBookingExpenses(currentCustomer); + expect(expenses).to.equal(50.25); + }); + it("Should tell if there are no bookings", function () { + const currentCustomer = new Customer(customerData[1]); + const expenses = hotelDani.findCustomerBookingExpenses(currentCustomer); + expect(expenses).to.equal("You have not made any bookings."); + }); + it("Should tell what rooms are available for a given date", function () { + const roomsAvailable1 = hotelDani.findAvailableRooms("2023/02/05"); + expect(roomsAvailable1).to.deep.equal([ + { + number: 1, + roomType: "residential suite", + bidet: true, + bedSize: "queen", + numBeds: 1, + costPerNight: 358.4, + }, + { + number: 2, + roomType: "suite", + bidet: false, + bedSize: "full", + numBeds: 2, + costPerNight: 477.38, + }, + { + number: 3, + roomType: "single room", + bidet: false, + bedSize: "king", + numBeds: 1, + costPerNight: 491.14, + }, + { + number: 4, + roomType: "single room", + bidet: false, + bedSize: "queen", + numBeds: 1, + costPerNight: 429.44, + }, + { + number: 15, + roomType: "single room", + bidet: true, + bedSize: "queen", + numBeds: 2, + costPerNight: 340.17, + }, + ]); + const roomsAvailable2 = hotelDani.findAvailableRooms("2023/04/22"); + expect(roomsAvailable2).to.deep.equal([ + { + number: 1, + roomType: "residential suite", + bidet: true, + bedSize: "queen", + numBeds: 1, + costPerNight: 358.4, + }, + { + number: 2, + roomType: "suite", + bidet: false, + bedSize: "full", + numBeds: 2, + costPerNight: 477.38, + }, + { + number: 3, + roomType: "single room", + bidet: false, + bedSize: "king", + numBeds: 1, + costPerNight: 491.14, + }, + { + number: 4, + roomType: "single room", + bidet: false, + bedSize: "queen", + numBeds: 1, + costPerNight: 429.44, + }, + { + number: 12, + roomType: "single room", + bidet: true, + bedSize: "queen", + numBeds: 2, + costPerNight: 50.25, + }, + ]); + }); + it("Should be able to filter rooms by room type", function () { + const found1 = hotelDani.filterRoomsByType("residential suite", roomData); + const found2 = hotelDani.filterRoomsByType("suite", roomData); + const found3 = hotelDani.filterRoomsByType("single room", roomData); + expect(found1).to.deep.equal([ + { + number: 1, + roomType: "residential suite", + bidet: true, + bedSize: "queen", + numBeds: 1, + costPerNight: 358.4, + }, + ]); + expect(found2).to.deep.equal([ + { + number: 2, + roomType: "suite", + bidet: false, + bedSize: "full", + numBeds: 2, + costPerNight: 477.38, + }, + ]); + expect(found3).to.deep.equal([ + { + number: 3, + roomType: "single room", + bidet: false, + bedSize: "king", + numBeds: 1, + costPerNight: 491.14, + }, + { + number: 4, + roomType: "single room", + bidet: false, + bedSize: "queen", + numBeds: 1, + costPerNight: 429.44, + }, + { + number: 15, + roomType: "single room", + bidet: true, + bedSize: "queen", + numBeds: 2, + costPerNight: 340.17, + }, + { + number: 12, + roomType: "single room", + bidet: true, + bedSize: "queen", + numBeds: 2, + costPerNight: 50.25, + }, + ]); + }); + it("Should tell if it does not have that room type", function () { + const found = hotelDani.filterRoomsByType("clown room"); + const found1 = hotelDani.filterRoomsByType("sweet"); + expect(found).to.deep.equal([]); + expect(found1).to.deep.equal([]); + }); + it("Should find rooms by number", function () { + const found1 = hotelDani.findSpecificRoomByNumber(1); + const found2 = hotelDani.findSpecificRoomByNumber(2); + expect(found1).to.deep.equal({ + number: 1, + roomType: "residential suite", + bidet: true, + bedSize: "queen", + numBeds: 1, + costPerNight: 358.4, + }); + expect(found2).to.deep.equal({ + number: 2, + roomType: "suite", + bidet: false, + bedSize: "full", + numBeds: 2, + costPerNight: 477.38, + }); + }); + it("Should return nothing if no room is found", function () { + const found1 = hotelDani.findSpecificRoomByNumber(50); + expect(found1).to.deep.equal(undefined); + }); + it("Should should create a new booking", function () { + const currentCustomer = customerData[0]; + const booking = hotelDani.createNewBooking( + currentCustomer, + 4, + "2022/09/23" + ); + expect(booking).to.deep.equal({ + userID: 1, + date: "2022/09/23", + roomNumber: 4, + }); + }); + it("Should let us know total revenue for any given date", function () { + const found1 = hotelDani.totalRevenue(`2023/02/05`); + expect(found1).to.deep.equal(50.25); + }); + it("Should be able to delete a booking", function () { + expect(hotelDani.allBookings).to.deep.equal([ + { + id: "5fwrgu4i7k55hl6sz", + userID: 9, + date: "2023/04/22", + roomNumber: 15, + }, + { + id: "5fwrgu4i7k55hl6t5", + userID: 43, + date: "2022/01/24", + roomNumber: 24, + }, + { + id: "5fwrgu4i7k55hl6t6", + userID: 13, + date: "2022/01/10", + roomNumber: 12, + }, + { + id: "5fwrgu4i7k55hl6t7", + userID: 20, + date: "2022/02/16", + roomNumber: 7, + }, + { + id: "5fwrgu4i7k55hl6t8", + userID: 1, + date: "2023/02/05", + roomNumber: 12, + }, + ]); + hotelDani.deleteABooking("5fwrgu4i7k55hl6sz"); + expect(hotelDani.allBookings).to.deep.equal([ + { + id: "5fwrgu4i7k55hl6t5", + userID: 43, + date: "2022/01/24", + roomNumber: 24, + }, + { + id: "5fwrgu4i7k55hl6t6", + userID: 13, + date: "2022/01/10", + roomNumber: 12, + }, + { + id: "5fwrgu4i7k55hl6t7", + userID: 20, + date: "2022/02/16", + roomNumber: 7, + }, + { + id: "5fwrgu4i7k55hl6t8", + userID: 1, + date: "2023/02/05", + roomNumber: 12, + }, + ]); + }); + it("Should find bookings by id", function () { + const found1 = hotelDani.findBookingByID("5fwrgu4i7k55hl6t7"); + const found2 = hotelDani.findBookingByID("5fwrgu4i7k55hl6t8"); + expect(found1).to.deep.equal({ + id: "5fwrgu4i7k55hl6t7", + userID: 20, + date: "2022/02/16", + roomNumber: 7, + }); + expect(found2).to.deep.equal({ + id: "5fwrgu4i7k55hl6t8", + userID: 1, + date: "2023/02/05", + roomNumber: 12, + }); + }); + it("Should return undefined if nothing was found", function () { + const found1 = hotelDani.findBookingByID("boo"); + expect(found1).to.deep.equal(undefined); + }); +}); diff --git a/test/room_test.js b/test/room_test.js new file mode 100644 index 000000000..3a546754b --- /dev/null +++ b/test/room_test.js @@ -0,0 +1,38 @@ +import chai from "chai"; +const expect = chai.expect; +import Room from "../src/classes/room"; +import roomData from "../src/sampleData/room_sample_data"; + +describe("Room", function () { + let data = roomData[0]; + let data2 = roomData[1]; + let room1 = new Room(data); + let room2 = new Room(data2); + it("Should take in an object", function () { + expect(data).to.be.an("object"); + }); + it("Should have an number", function () { + expect(room1.number).to.equal(1); + expect(room2.number).to.equal(2); + }); + it("Should have a room type", function () { + expect(room1.roomType).to.equal("residential suite"); + expect(room2.roomType).to.equal("suite"); + }); + it("Should tell if it has a bidet or not", function () { + expect(room1.bidet).to.equal(true); + expect(room2.bidet).to.equal(false); + }); + it("Should have a bed size", function () { + expect(room1.bedSize).to.equal("queen"); + expect(room2.bedSize).to.equal("full"); + }); + it("Should let us know how many beds there are", function () { + expect(room1.numBeds).to.equal(1); + expect(room2.numBeds).to.equal(2); + }); + it("Should have a cost per night", function () { + expect(room1.costPerNight).to.equal(358.4); + expect(room2.costPerNight).to.equal(477.38); + }); +}); diff --git a/webpack.config.js b/webpack.config.js index 33523ee8c..a9b9782ff 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,39 +1,44 @@ -const path = require('path'); +const path = require("path"); module.exports = { - "mode": "none", - "entry": "./src/scripts.js", - "output": { - "path": __dirname + '/dist', - "filename": "bundle.js", - sourceMapFilename: "bundle.js.map" + mode: "none", + entry: "./src/scripts.js", + output: { + path: __dirname + "/dist", + filename: "bundle.js", + sourceMapFilename: "bundle.js.map", }, devServer: { - contentBase: path.join(__dirname, 'dist') + contentBase: path.join(__dirname, "dist"), }, - "devtool": "source-map", - "module": { - "rules": [ + devtool: "source-map", + module: { + rules: [ { - test: /\.css$/, + test: /\.s[ac]ss$/, use: [ - { loader: 'style-loader' }, - { loader: 'css-loader' } - ] - }, + { loader: "style-loader" }, + { loader: "css-loader" }, + { loader: "sass-loader" }, + ], + }, + { + test: /\.css$/, + use: [{ loader: "style-loader" }, { loader: "css-loader" }], + }, { test: /\.(png|svg|jpg|gif)$/, use: [ { - loader: 'file-loader', + loader: "file-loader", options: { - name: '[name].[ext]', - outputPath: 'images/', - publicPath: 'images/' - } - } - ] - } - ] - } + name: "[name].[ext]", + outputPath: "images/", + publicPath: "images/", + }, + }, + ], + }, + ], + }, };