├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── _redirects
├── favicon.ico
├── index.html
└── manifest.json
└── src
├── App.css
├── App.js
├── App.test.js
├── Contentful.js
├── components
├── Banner.js
├── FeaturedRooms.js
├── Hero.js
├── Loading.js
├── Navbar.js
├── Room.js
├── RoomsContainer.js
├── RoomsFilter.js
├── RoomsList.js
├── Services.js
├── StyledHero.js
└── Title.js
├── context.js
├── data.js
├── images
├── defaultBcg.jpeg
├── details-1.jpeg
├── details-2.jpeg
├── details-3.jpeg
├── details-4.jpeg
├── gif
│ ├── loading-arrow.gif
│ └── loading-gear.gif
├── logo.svg
├── room-1.jpeg
├── room-10.jpeg
├── room-11.jpeg
├── room-12.jpeg
├── room-2.jpeg
├── room-3.jpeg
├── room-4.jpeg
├── room-5.jpeg
├── room-6.jpeg
├── room-7.jpeg
├── room-8.jpeg
└── room-9.jpeg
├── index.css
├── index.js
├── logo.svg
├── pages
├── Error.js
├── Home.js
├── Rooms.js
└── SingleRoom.js
└── serviceWorker.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 | .env.development
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `npm start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `npm test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `npm run build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `npm run eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `npm run build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "resort",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "contentful": "^7.5.0",
7 | "react": "^16.8.6",
8 | "react-dom": "^16.8.6",
9 | "react-icons": "^3.6.1",
10 | "react-router-dom": "^5.0.0",
11 | "react-scripts": "3.0.0",
12 | "styled-components": "^4.2.0"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test",
18 | "eject": "react-scripts eject"
19 | },
20 | "eslintConfig": {
21 | "extends": "react-app"
22 | },
23 | "browserslist": {
24 | "production": [
25 | ">0.2%",
26 | "not dead",
27 | "not op_mini all"
28 | ],
29 | "development": [
30 | "last 1 chrome version",
31 | "last 1 firefox version",
32 | "last 1 safari version"
33 | ]
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/public/_redirects:
--------------------------------------------------------------------------------
1 | /* /index.html 200
2 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
22 | Beach Resort
23 |
24 |
25 | You need to enable JavaScript to run this app.
26 |
27 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | }
6 | :root {
7 | --primaryColor: #af9a7d;
8 | --mainWhite: #fff;
9 | --offWhite: #f7f7f7;
10 | --mainBlack: #222;
11 | --mainGrey: #ececec;
12 | --darkGrey: #cfcfcf;
13 | --mainTransition: all 0.3s linear;
14 | --mainSpacing: 3px;
15 | --lightShadow: 2px 5px 3px 0px rgba(0, 0, 0, 0.5);
16 | --darkShadow: 4px 10px 5px 0px rgba(0, 0, 0, 0.5);
17 | }
18 | /* globals */
19 | body {
20 | padding-top: 66px;
21 | color: var(--mainBlack);
22 | background: var(--mainWhite);
23 | font-family: Verdana, Geneva, Tahoma, sans-serif;
24 | line-height: 1.4;
25 | }
26 | h1 {
27 | font-size: 3em;
28 | line-height: 1;
29 | margin-bottom: 0.5em;
30 | }
31 | h2 {
32 | font-size: 2em;
33 | margin-bottom: 0.75em;
34 | }
35 | h3 {
36 | font-size: 1.5em;
37 | line-height: 1;
38 | margin-bottom: 1em;
39 | }
40 | h4 {
41 | font-size: 1.2em;
42 | line-height: 1.25;
43 | margin-bottom: 1.25em;
44 | }
45 | h5 {
46 | font-size: 1em;
47 | font-weight: bold;
48 | margin-bottom: 1.5em;
49 | }
50 | h6 {
51 | font-size: 1em;
52 | font-weight: bold;
53 | margin-bottom: 1.5em;
54 | }
55 |
56 | .btn-primary {
57 | display: inline-block;
58 | text-decoration: none;
59 | letter-spacing: var(--mainSpacing);
60 | color: var(--mainBlack);
61 | background: var(--primaryColor);
62 | padding: 0.4rem 0.9rem;
63 | border: 3px solid var(--primaryColor);
64 | transition: var(--mainTransition);
65 | text-transform: uppercase;
66 | cursor: pointer;
67 | }
68 | .btn-primary:hover {
69 | background: transparent;
70 | color: var(--primaryColor);
71 | }
72 | .loading {
73 | text-transform: capitalize;
74 | text-align: center;
75 | margin-top: 3rem;
76 | }
77 | .error {
78 | text-align: center;
79 | text-transform: uppercase;
80 | margin: 2rem 0;
81 | }
82 | .empty-search {
83 | text-align: center;
84 | text-transform: capitalize;
85 | margin: 2rem 0;
86 | padding: 1rem;
87 | letter-spacing: var(--mainSpacing);
88 | }
89 | /* end of globals */
90 | /* Navbar */
91 | .navbar {
92 | position: fixed;
93 | top: 0;
94 | left: 0;
95 | width: 100%;
96 | padding: 0.75rem 2rem;
97 | background: var(--offWhite);
98 | z-index: 1;
99 | }
100 | .nav-header {
101 | display: flex;
102 | justify-content: space-between;
103 | }
104 | .nav-btn {
105 | background: transparent;
106 | border: none;
107 | cursor: pointer;
108 | outline: none;
109 | }
110 | .nav-icon {
111 | font-size: 1.5rem;
112 | color: var(--primaryColor);
113 | }
114 | .nav-links {
115 | height: 0;
116 | overflow: hidden;
117 | transition: var(--mainTransition);
118 | list-style-type: none;
119 | }
120 | .nav-links a {
121 | display: block;
122 | text-decoration: none;
123 | padding: 1rem 0;
124 | color: var(--mainBlack);
125 | transition: var(--mainTransition);
126 | text-align: center;
127 | font-size: 1rem;
128 | font-weight: 600;
129 | letter-spacing: var(--mainSpacing);
130 | }
131 | .nav-links a:hover {
132 | color: var(--primaryColor);
133 | }
134 |
135 | .show-nav {
136 | height: 100px;
137 | }
138 | @media screen and (min-width: 768px) {
139 | .nav-btn {
140 | display: none;
141 | }
142 | .nav-center {
143 | max-width: 1170px;
144 | margin: 0 auto;
145 | display: flex;
146 | }
147 | .nav-links {
148 | height: auto;
149 | display: flex;
150 | margin-left: 4rem;
151 | }
152 | .nav-links a {
153 | margin: 0 1rem;
154 | padding: 0.5rem 0;
155 | }
156 | }
157 | /* end of navbar */
158 | /* Hero */
159 | .defaultHero,
160 | .roomsHero {
161 | min-height: calc(100vh - 66px);
162 | background: url("./images/defaultBcg.jpeg") center/cover no-repeat;
163 | display: flex;
164 | align-items: center;
165 | justify-content: center;
166 | }
167 | .roomsHero {
168 | background-image: url("./images/room-2.jpeg");
169 | min-height: 60vh;
170 | }
171 | /* End of Hero */
172 | /* Banner */
173 | .banner {
174 | display: inline-block;
175 | background: rgba(0, 0, 0, 0.5);
176 | color: var(--mainWhite);
177 | padding: 2rem 1rem;
178 | text-align: center;
179 | text-transform: capitalize;
180 | letter-spacing: var(--mainSpacing);
181 | }
182 | .banner h1 {
183 | font-size: 2.5rem;
184 | }
185 | .banner div {
186 | width: 10rem;
187 | height: 5px;
188 | background: var(--primaryColor);
189 | margin: 1.7rem auto;
190 | }
191 | .banner p {
192 | font-size: 1.2rem;
193 | margin-bottom: 2rem;
194 | }
195 | @media screen and (min-width: 576px) {
196 | .banner {
197 | padding: 2rem 3rem;
198 | }
199 | .banner h1 {
200 | font-size: 3rem;
201 | }
202 | }
203 | @media screen and (min-width: 992px) {
204 | .banner {
205 | padding: 2rem 6rem;
206 | }
207 | .banner h1 {
208 | font-size: 4rem;
209 | }
210 | }
211 | /* End of Banner */
212 | /* Title */
213 | .section-title {
214 | text-align: center;
215 | margin-bottom: 4rem;
216 | }
217 | .section-title h4 {
218 | font-size: 2rem;
219 | letter-spacing: var(--mainSpacing);
220 | text-transform: capitalize;
221 | margin-bottom: 1rem;
222 | }
223 | .section-title div {
224 | width: 5rem;
225 | height: 5px;
226 | margin: 0 auto;
227 | background: var(--primaryColor);
228 | }
229 | /* end of Title */
230 |
231 | /* services */
232 | .services {
233 | padding: 5rem 0;
234 | }
235 | .services {
236 | background: var(--darkGrey);
237 | text-align: center;
238 | }
239 | .services-center {
240 | width: 90vw;
241 | margin: 0 auto;
242 | display: grid;
243 | grid-template-columns: repeat(auto-fit, minmax(255px, 1fr));
244 | grid-row-gap: 2rem;
245 | grid-column-gap: 50px;
246 | }
247 | .service span {
248 | display: inline-block;
249 | color: var(--primaryColor);
250 | font-size: 2.5rem;
251 | margin-bottom: 1.5rem;
252 | }
253 | .services h6 {
254 | letter-spacing: var(--mainSpacing);
255 | }
256 | .services p {
257 | width: 80%;
258 | margin: 0 auto;
259 | }
260 | @media screen and (min-width: 992px) {
261 | .services-center {
262 | width: 95vw;
263 | max-width: 1170px;
264 | }
265 | }
266 |
267 | @media screen and (min-width: 1200px) {
268 | .services p {
269 | width: 100%;
270 | }
271 | }
272 | /*end of services */
273 | /* featured rooms */
274 |
275 | .featured-rooms {
276 | padding: 5rem 0;
277 | }
278 | .featured-rooms-center {
279 | width: 80vw;
280 | margin: 0 auto;
281 | display: grid;
282 | grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
283 | grid-row-gap: 2rem;
284 | grid-column-gap: 40px;
285 | }
286 | @media screen and (min-width: 776px) {
287 | .featured-rooms-center {
288 | width: 90vw;
289 | grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
290 | }
291 | }
292 | @media screen and (min-width: 992px) {
293 | .featured-rooms-center {
294 | width: 95vw;
295 | max-width: 1170px;
296 | }
297 | }
298 | /* end pf featured rooms */
299 | /* room */
300 | .room {
301 | box-shadow: var(--lightShadow);
302 | transition: var(--mainTransition);
303 | }
304 | .room:hover {
305 | box-shadow: var(--darkShadow);
306 | }
307 |
308 | .img-container {
309 | position: relative;
310 | }
311 | .img-container img {
312 | width: 100%;
313 | display: block;
314 | transition: var(--mainTransition);
315 | }
316 | .price-top {
317 | position: absolute;
318 | top: 0;
319 | left: 0;
320 | background: rgba(0, 0, 0, 0.8);
321 | color: var(--mainWhite);
322 | padding: 0.3rem 0.6rem 0.5rem;
323 | border-bottom-right-radius: 1rem;
324 | font-size: 0.5rem;
325 | text-align: center;
326 | transition: var(--mainTransition);
327 | }
328 | .price-top h6 {
329 | margin-bottom: 0;
330 | font-size: 0.9rem;
331 | font-weight: 300;
332 | letter-spacing: var(--mainSpacing);
333 | }
334 | .room-link {
335 | position: absolute;
336 | top: 50%;
337 | left: 50%;
338 | transform: scale(0);
339 | transition: all 0.3s linear;
340 | }
341 | .img-container:hover {
342 | background: rgba(0, 0, 0, 0.8);
343 | }
344 | .img-container:hover img {
345 | opacity: 0.3;
346 | }
347 | .img-container:hover .price-top {
348 | opacity: 0;
349 | }
350 | .img-container:hover .room-link {
351 | transform: translate(-50%, -50%) scale(1);
352 | }
353 | .room-info {
354 | background: var(--darkGrey);
355 | text-transform: capitalize;
356 | padding: 0.5rem 0;
357 | text-align: center;
358 | font-weight: 700;
359 | letter-spacing: var(--mainSpacing);
360 | }
361 | /* end of room */
362 | /* single room*/
363 |
364 | .single-room {
365 | padding: 5rem 0 0 0;
366 | }
367 | .single-room-images {
368 | width: 80vw;
369 | margin: 0 auto;
370 | display: grid;
371 | grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
372 | grid-row-gap: 2rem;
373 | grid-column-gap: 50px;
374 | }
375 | .single-room-images img {
376 | width: 100%;
377 | display: block;
378 | }
379 | .single-room-info {
380 | width: 80vw;
381 | display: grid;
382 | grid-template-columns: 1fr;
383 | margin: 2rem auto;
384 | }
385 | .desc,
386 | .info {
387 | margin: 1rem 0;
388 | }
389 | .desc h3 {
390 | text-transform: capitalize;
391 | letter-spacing: var(--mainSpacing);
392 | }
393 | .desc p {
394 | line-height: 1.5;
395 | }
396 | .info h3,
397 | .info h6 {
398 | text-transform: capitalize;
399 | letter-spacing: var(--mainSpacing);
400 | }
401 |
402 | .info h6 {
403 | font-weight: 300;
404 | }
405 | .room-extras {
406 | width: 80vw;
407 | margin: 0 auto 3rem auto;
408 | }
409 | .room-extras h6 {
410 | text-transform: capitalize;
411 | letter-spacing: var(--mainSpacing);
412 | }
413 | .extras {
414 | list-style-type: none;
415 | display: grid;
416 | grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
417 | grid-column-gap: 2rem;
418 | grid-row-gap: 1rem;
419 | }
420 | @media screen and (min-width: 992px) {
421 | .single-room-images,
422 | .single-room-info,
423 | .room-extras {
424 | width: 95vw;
425 | max-width: 1170px;
426 | }
427 | .single-room-info {
428 | display: grid;
429 | grid-template-columns: 1fr 1fr;
430 | grid-column-gap: 2rem;
431 | }
432 | .info {
433 | padding-left: 3rem;
434 | }
435 | }
436 | /* end of single room*/
437 | /* roomlist */
438 | .roomslist {
439 | padding: 5rem 0;
440 | }
441 | .roomslist-center {
442 | width: 80vw;
443 | margin: 0 auto;
444 | display: grid;
445 | grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
446 | grid-row-gap: 2rem;
447 | grid-column-gap: 30px;
448 | }
449 |
450 | @media screen and (min-width: 776px) {
451 | .roomslist-center {
452 | width: 90vw;
453 | }
454 | }
455 | @media screen and (min-width: 992px) {
456 | .roomslist-center {
457 | width: 95vw;
458 | max-width: 1170px;
459 | }
460 | }
461 | /* end of roomlist */
462 | /* rooms fitler*/
463 | .filter-container {
464 | padding: 5rem 0;
465 | }
466 | .filter-form {
467 | width: 60vw;
468 | margin: 0 auto;
469 | display: grid;
470 | grid-template-columns: repeat(auto-fit, minmax(202px, 1fr));
471 | grid-row-gap: 2rem;
472 | grid-column-gap: 40px;
473 | }
474 | .form-group {
475 | text-transform: capitalize;
476 | }
477 | .form-group label {
478 | display: block;
479 | letter-spacing: var(--mainSpacing);
480 | margin-bottom: 0.5rem;
481 | }
482 | .form-control {
483 | width: 100%;
484 | background: transparent;
485 | font-size: 1rem;
486 | }
487 | .size-inputs {
488 | display: flex;
489 | }
490 | .size-input {
491 | width: 40%;
492 | padding: 0.2rem;
493 | border: 1px solid var(--mainBlack);
494 | border-radius: 0.3rem;
495 | margin-right: 0.3rem;
496 | }
497 | .single-extra label {
498 | display: inline-block;
499 | font-size: 0.8rem;
500 | margin-left: 0.5rem;
501 | }
502 | @media screen and (min-width: 776px) {
503 | .filter-form {
504 | width: 70vw;
505 | }
506 | }
507 | @media screen and (min-width: 992px) {
508 | .filter-form {
509 | width: 95vw;
510 | max-width: 1170px;
511 | }
512 | }
513 | /* end of rooms fitler*/
514 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./App.css";
3 |
4 | import Home from "./pages/Home";
5 | import Rooms from "./pages/Rooms";
6 | import SingleRoom from "./pages/SingleRoom";
7 | import Error from "./pages/Error";
8 |
9 | import Navbar from "./components/Navbar";
10 |
11 | import { Switch, Route } from "react-router-dom";
12 |
13 | function App() {
14 | return (
15 | <>
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | >
24 | );
25 | }
26 |
27 | export default App;
28 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render( , div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/src/Contentful.js:
--------------------------------------------------------------------------------
1 | const contentful = require("contentful");
2 |
3 | export default contentful.createClient({
4 | space: process.env.REACT_APP_API_SPACE,
5 | accessToken: process.env.REACT_APP_ACCESS_TOKEN
6 | });
7 |
--------------------------------------------------------------------------------
/src/components/Banner.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | const Banner = ({ children, title, subtitle }) => {
3 | return (
4 |
5 |
{title}
6 |
7 |
{subtitle}
8 | {children}
9 |
10 | );
11 | };
12 |
13 | export default Banner;
14 |
--------------------------------------------------------------------------------
/src/components/FeaturedRooms.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import Title from "./Title";
3 | import { RoomContext } from "../context";
4 | import Room from "./Room";
5 | import Loading from "./Loading";
6 | export default class FeaturedRooms extends Component {
7 | static contextType = RoomContext;
8 |
9 | render() {
10 | let { loading, featuredRooms: rooms } = this.context;
11 |
12 | rooms = rooms.map(room => {
13 | return ;
14 | });
15 | return (
16 |
17 |
18 |
19 | {loading ? : rooms}
20 |
21 |
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/Hero.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Hero = ({ children, hero }) => {
4 | return ;
5 | };
6 |
7 | export default Hero;
8 |
9 | Hero.defaultProps = {
10 | hero: "defaultHero"
11 | };
12 |
--------------------------------------------------------------------------------
/src/components/Loading.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import loadingGif from "../images/gif/loading-arrow.gif";
3 | const Loading = () => {
4 | return (
5 |
6 |
rooms data loading....
7 |
8 |
9 | );
10 | };
11 |
12 | export default Loading;
13 |
--------------------------------------------------------------------------------
/src/components/Navbar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Link } from "react-router-dom";
3 | import { FaAlignRight } from "react-icons/fa";
4 | import logo from "../images/logo.svg";
5 | export default class Navbar extends Component {
6 | state = {
7 | isOpen: false
8 | };
9 | handleToggle = () => {
10 | this.setState({ isOpen: !this.state.isOpen });
11 | };
12 | render() {
13 | return (
14 |
15 |
16 |
17 |
18 |
19 |
20 |
25 |
26 |
27 |
28 |
31 |
32 | Home
33 |
34 |
35 | Rooms
36 |
37 |
38 |
39 |
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/Room.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 | import defaultImg from "../images/room-1.jpeg";
4 | import PropTypes from "prop-types";
5 | import { memo } from "react";
6 | const Room = memo(({ room }) => {
7 | const { name, slug, images, price } = room;
8 | // console.log(name);
9 | return (
10 |
11 |
12 |
13 |
14 |
${price}
15 |
per night
16 |
17 |
18 | features
19 |
20 |
21 | {name}
22 |
23 | );
24 | });
25 |
26 | Room.propTypes = {
27 | room: PropTypes.shape({
28 | name: PropTypes.string.isRequired,
29 | slug: PropTypes.string.isRequired,
30 | images: PropTypes.arrayOf(PropTypes.string).isRequired,
31 | price: PropTypes.number.isRequired
32 | })
33 | };
34 | export default Room;
35 |
--------------------------------------------------------------------------------
/src/components/RoomsContainer.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { withRoomConsumer } from "../context";
3 | import Loading from "./Loading";
4 | import RoomsFilter from "./RoomsFilter";
5 | import RoomsList from "./RoomsList";
6 |
7 | function RoomContainer({ context }) {
8 | const { loading, sortedRooms, rooms } = context;
9 | if (loading) {
10 | return ;
11 | }
12 | return (
13 | <>
14 |
15 |
16 | >
17 | );
18 | }
19 |
20 | export default withRoomConsumer(RoomContainer);
21 |
22 | // import React from "react";
23 | // import { RoomConsumer } from "../context";
24 | // import Loading from "./Loading";
25 | // import RoomsFilter from "./RoomsFilter";
26 | // import RoomsList from "./RoomsList";
27 | // export default function RoomContainer() {
28 | // return (
29 | //
30 | // {value => {
31 | // const { loading, setRoom, sortedRooms,rooms } = value;
32 | // if (loading) {
33 | // return ;
34 | // }
35 | // return (
36 | // <>
37 | //
38 | //
39 | // >
40 | // );
41 | // }}
42 | //
43 | // );
44 | // }
45 |
--------------------------------------------------------------------------------
/src/components/RoomsFilter.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useContext } from "react";
3 | import { RoomContext } from "../context";
4 | import Title from "./Title";
5 | // get all unique values
6 | const getUnique = (items, value) => {
7 | return [...new Set(items.map(item => item[value]))];
8 | };
9 |
10 | const RoomsFilter = ({ rooms }) => {
11 | // react hooks
12 | const context = useContext(RoomContext);
13 | const {
14 | handleChange,
15 | type,
16 | capacity,
17 | price,
18 | minPrice,
19 | maxPrice,
20 | minSize,
21 | maxSize,
22 | breakfast,
23 | pets
24 | } = context;
25 |
26 | // get unique types
27 | let types = getUnique(rooms, "type");
28 | // add all
29 | types = ["all", ...types];
30 | // map to jsx
31 | types = types.map((item, index) => (
32 |
33 | {item}
34 |
35 | ));
36 | // get unique capacity
37 | let people = getUnique(rooms, "capacity");
38 | people = people.map((item, index) => (
39 |
40 | {item}
41 |
42 | ));
43 | return (
44 |
136 | );
137 | };
138 |
139 | export default RoomsFilter;
140 |
--------------------------------------------------------------------------------
/src/components/RoomsList.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Room from "./Room";
3 | const RoomsList = ({ rooms }) => {
4 | if (rooms.length === 0) {
5 | return (
6 |
7 |
unfortunately no rooms matched your search parameters
8 |
9 | );
10 | }
11 | return (
12 |
13 |
14 | {rooms.map(item => {
15 | return ;
16 | })}
17 |
18 |
19 | );
20 | };
21 |
22 | export default RoomsList;
23 |
--------------------------------------------------------------------------------
/src/components/Services.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { FaCocktail, FaHiking, FaShuttleVan, FaBeer } from "react-icons/fa";
3 | import Title from "./Title";
4 | export default class Services extends Component {
5 | state = {
6 | services: [
7 | {
8 | icon: ,
9 | title: "Free Cocktails",
10 | info:
11 | "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Alias molestias eius libero?"
12 | },
13 | {
14 | icon: ,
15 | title: "Endless Hiking",
16 | info:
17 | "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Alias molestias eius libero?"
18 | },
19 | {
20 | icon: ,
21 | title: "Free Shuttle",
22 | info:
23 | "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Alias molestias eius libero?"
24 | },
25 | {
26 | icon: ,
27 | title: "Strongest Beer",
28 | info:
29 | "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Alias molestias eius libero?"
30 | }
31 | ]
32 | };
33 | render() {
34 | return (
35 |
36 |
37 |
38 | {this.state.services.map(item => {
39 | return (
40 |
41 | {item.icon}
42 | {item.title}
43 | {item.info}
44 |
45 | );
46 | })}
47 |
48 |
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/components/StyledHero.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 | import defaultImg from "../images/room-1.jpeg";
3 | const StyledHero = styled.header`
4 | min-height: 60vh;
5 | /* background: url(${defaultImg}); */
6 | background: url(${props => (props.img ? props.img : defaultImg)});
7 | display: flex;
8 | align-items: center;
9 | justify-content: center;
10 | `;
11 |
12 | export default StyledHero;
13 |
--------------------------------------------------------------------------------
/src/components/Title.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Title = ({ title }) => {
4 | return (
5 |
9 | );
10 | };
11 |
12 | export default Title;
13 |
--------------------------------------------------------------------------------
/src/context.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import items from "./data";
3 | import Client from "./Contentful";
4 |
5 | const RoomContext = React.createContext();
6 |
7 | export default class RoomProvider extends Component {
8 | state = {
9 | rooms: [],
10 | sortedRooms: [],
11 | featuredRooms: [],
12 | loading: true,
13 | //
14 | type: "all",
15 | capacity: 1,
16 | price: 0,
17 | minPrice: 0,
18 | maxPrice: 0,
19 | minSize: 0,
20 | maxSize: 0,
21 | breakfast: false,
22 | pets: false
23 | };
24 |
25 | // getData = async () => {
26 | // try {
27 | // let response = await Client.getEntries({
28 | // content_type: "beachResortRoom"
29 | // });
30 | // let rooms = this.formatData(response.items);
31 |
32 | // let featuredRooms = rooms.filter(room => room.featured === true);
33 | // //
34 | // let maxPrice = Math.max(...rooms.map(item => item.price));
35 | // let maxSize = Math.max(...rooms.map(item => item.size));
36 | // this.setState({
37 | // rooms,
38 | // featuredRooms,
39 | // sortedRooms: rooms,
40 | // loading: false,
41 | // //
42 | // price: maxPrice,
43 | // maxPrice,
44 | // maxSize
45 | // });
46 | // } catch (error) {
47 | // console.log(error);
48 | // }
49 | // };
50 |
51 | componentDidMount() {
52 | // this.getData();
53 | let rooms = this.formatData(items);
54 | let featuredRooms = rooms.filter(room => room.featured === true);
55 | //
56 | let maxPrice = Math.max(...rooms.map(item => item.price));
57 | let maxSize = Math.max(...rooms.map(item => item.size));
58 | this.setState({
59 | rooms,
60 | featuredRooms,
61 | sortedRooms: rooms,
62 | loading: false,
63 | //
64 | price: maxPrice,
65 | maxPrice,
66 | maxSize
67 | });
68 | }
69 |
70 | formatData(items) {
71 | let tempItems = items.map(item => {
72 | let id = item.sys.id;
73 | let images = item.fields.images.map(image => image.fields.file.url);
74 |
75 | let room = { ...item.fields, images, id };
76 | return room;
77 | });
78 | return tempItems;
79 | }
80 | getRoom = slug => {
81 | let tempRooms = [...this.state.rooms];
82 | const room = tempRooms.find(room => room.slug === slug);
83 | return room;
84 | };
85 | handleChange = event => {
86 | const target = event.target;
87 | const value = target.type === "checkbox" ? target.checked : target.value;
88 | const name = target.name;
89 | console.log(name, value);
90 |
91 | this.setState(
92 | {
93 | [name]: value
94 | },
95 | this.filterRooms
96 | );
97 | };
98 | filterRooms = () => {
99 | let {
100 | rooms,
101 | type,
102 | capacity,
103 | price,
104 | minSize,
105 | maxSize,
106 | breakfast,
107 | pets
108 | } = this.state;
109 |
110 | let tempRooms = [...rooms];
111 | // transform values
112 | // get capacity
113 | capacity = parseInt(capacity);
114 | price = parseInt(price);
115 | // filter by type
116 | if (type !== "all") {
117 | tempRooms = tempRooms.filter(room => room.type === type);
118 | }
119 | // filter by capacity
120 | if (capacity !== 1) {
121 | tempRooms = tempRooms.filter(room => room.capacity >= capacity);
122 | }
123 | // filter by price
124 | tempRooms = tempRooms.filter(room => room.price <= price);
125 | //filter by size
126 | tempRooms = tempRooms.filter(
127 | room => room.size >= minSize && room.size <= maxSize
128 | );
129 | //filter by breakfast
130 | if (breakfast) {
131 | tempRooms = tempRooms.filter(room => room.breakfast === true);
132 | }
133 | //filter by pets
134 | if (pets) {
135 | tempRooms = tempRooms.filter(room => room.pets === true);
136 | }
137 | this.setState({
138 | sortedRooms: tempRooms
139 | });
140 | };
141 | render() {
142 | return (
143 |
150 | {this.props.children}
151 |
152 | );
153 | }
154 | }
155 | const RoomConsumer = RoomContext.Consumer;
156 |
157 | export { RoomProvider, RoomConsumer, RoomContext };
158 |
159 | export function withRoomConsumer(Component) {
160 | return function ConsumerWrapper(props) {
161 | return (
162 |
163 | {value => }
164 |
165 | );
166 | };
167 | }
168 |
--------------------------------------------------------------------------------
/src/data.js:
--------------------------------------------------------------------------------
1 | import room1 from "./images/details-1.jpeg";
2 | import room2 from "./images/details-2.jpeg";
3 | import room3 from "./images/details-3.jpeg";
4 | import room4 from "./images/details-4.jpeg";
5 | import img1 from "./images/room-1.jpeg";
6 | import img2 from "./images/room-2.jpeg";
7 | import img3 from "./images/room-3.jpeg";
8 | import img4 from "./images/room-4.jpeg";
9 | import img5 from "./images/room-5.jpeg";
10 | import img6 from "./images/room-6.jpeg";
11 | import img7 from "./images/room-7.jpeg";
12 | import img8 from "./images/room-8.jpeg";
13 | import img9 from "./images/room-9.jpeg";
14 | import img10 from "./images/room-10.jpeg";
15 | import img11 from "./images/room-11.jpeg";
16 | import img12 from "./images/room-12.jpeg";
17 |
18 | export default [
19 | {
20 | sys: {
21 | id: "1"
22 | },
23 | fields: {
24 | name: "single economy",
25 | slug: "single-economy",
26 | type: "single",
27 | price: 100,
28 | size: 200,
29 | capacity: 1,
30 | pets: false,
31 | breakfast: false,
32 | featured: false,
33 | description:
34 | "Street art edison bulb gluten-free, tofu try-hard lumbersexual brooklyn tattooed pickled chambray. Actually humblebrag next level, deep v art party wolf tofu direct trade readymade sustainable hell of banjo. Organic authentic subway tile cliche palo santo, street art XOXO dreamcatcher retro sriracha portland air plant kitsch stumptown. Austin small batch squid gastropub. Pabst pug tumblr gochujang offal retro cloud bread bushwick semiotics before they sold out sartorial literally mlkshk. Vaporware hashtag vice, sartorial before they sold out pok pok health goth trust fund cray.",
35 | extras: [
36 | "Plush pillows and breathable bed linens",
37 | "Soft, oversized bath towels",
38 | "Full-sized, pH-balanced toiletries",
39 | "Complimentary refreshments",
40 | "Adequate safety/security",
41 | "Internet",
42 | "Comfortable beds"
43 | ],
44 | images: [
45 | {
46 | fields: {
47 | file: {
48 | url: img1
49 | }
50 | }
51 | },
52 | {
53 | fields: {
54 | file: {
55 | url: room2
56 | }
57 | }
58 | },
59 | {
60 | fields: {
61 | file: {
62 | url: room3
63 | }
64 | }
65 | },
66 | {
67 | fields: {
68 | file: {
69 | url: room4
70 | }
71 | }
72 | }
73 | ]
74 | }
75 | },
76 | {
77 | sys: {
78 | id: "2"
79 | },
80 | fields: {
81 | name: "single basic",
82 | slug: "single-basic",
83 | type: "single",
84 | price: 150,
85 | size: 250,
86 | capacity: 1,
87 | pets: false,
88 | breakfast: false,
89 | featured: false,
90 | description:
91 | "Street art edison bulb gluten-free, tofu try-hard lumbersexual brooklyn tattooed pickled chambray. Actually humblebrag next level, deep v art party wolf tofu direct trade readymade sustainable hell of banjo. Organic authentic subway tile cliche palo santo, street art XOXO dreamcatcher retro sriracha portland air plant kitsch stumptown. Austin small batch squid gastropub. Pabst pug tumblr gochujang offal retro cloud bread bushwick semiotics before they sold out sartorial literally mlkshk. Vaporware hashtag vice, sartorial before they sold out pok pok health goth trust fund cray.",
92 | extras: [
93 | "Plush pillows and breathable bed linens",
94 | "Soft, oversized bath towels",
95 | "Full-sized, pH-balanced toiletries",
96 | "Complimentary refreshments",
97 | "Adequate safety/security",
98 | "Internet",
99 | "Comfortable beds"
100 | ],
101 | images: [
102 | {
103 | fields: {
104 | file: {
105 | url: img2
106 | }
107 | }
108 | },
109 | {
110 | fields: {
111 | file: {
112 | url: room2
113 | }
114 | }
115 | },
116 | {
117 | fields: {
118 | file: {
119 | url: room3
120 | }
121 | }
122 | },
123 | {
124 | fields: {
125 | file: {
126 | url: room4
127 | }
128 | }
129 | }
130 | ]
131 | }
132 | },
133 | {
134 | sys: {
135 | id: "3"
136 | },
137 | fields: {
138 | name: "single standard",
139 | slug: "single-standard",
140 | type: "single",
141 | price: 250,
142 | size: 300,
143 | capacity: 1,
144 | pets: true,
145 | breakfast: false,
146 | featured: false,
147 | description:
148 | "Street art edison bulb gluten-free, tofu try-hard lumbersexual brooklyn tattooed pickled chambray. Actually humblebrag next level, deep v art party wolf tofu direct trade readymade sustainable hell of banjo. Organic authentic subway tile cliche palo santo, street art XOXO dreamcatcher retro sriracha portland air plant kitsch stumptown. Austin small batch squid gastropub. Pabst pug tumblr gochujang offal retro cloud bread bushwick semiotics before they sold out sartorial literally mlkshk. Vaporware hashtag vice, sartorial before they sold out pok pok health goth trust fund cray.",
149 | extras: [
150 | "Plush pillows and breathable bed linens",
151 | "Soft, oversized bath towels",
152 | "Full-sized, pH-balanced toiletries",
153 | "Complimentary refreshments",
154 | "Adequate safety/security",
155 | "Internet",
156 | "Comfortable beds"
157 | ],
158 | images: [
159 | {
160 | fields: {
161 | file: {
162 | url: img3
163 | }
164 | }
165 | },
166 | {
167 | fields: {
168 | file: {
169 | url: room2
170 | }
171 | }
172 | },
173 | {
174 | fields: {
175 | file: {
176 | url: room3
177 | }
178 | }
179 | },
180 | {
181 | fields: {
182 | file: {
183 | url: room4
184 | }
185 | }
186 | }
187 | ]
188 | }
189 | },
190 | {
191 | sys: {
192 | id: "4"
193 | },
194 | fields: {
195 | name: "single deluxe",
196 | slug: "single-deluxe",
197 | type: "single",
198 | price: 300,
199 | size: 400,
200 | capacity: 1,
201 | pets: true,
202 | breakfast: true,
203 | featured: false,
204 | description:
205 | "Street art edison bulb gluten-free, tofu try-hard lumbersexual brooklyn tattooed pickled chambray. Actually humblebrag next level, deep v art party wolf tofu direct trade readymade sustainable hell of banjo. Organic authentic subway tile cliche palo santo, street art XOXO dreamcatcher retro sriracha portland air plant kitsch stumptown. Austin small batch squid gastropub. Pabst pug tumblr gochujang offal retro cloud bread bushwick semiotics before they sold out sartorial literally mlkshk. Vaporware hashtag vice, sartorial before they sold out pok pok health goth trust fund cray.",
206 | extras: [
207 | "Plush pillows and breathable bed linens",
208 | "Soft, oversized bath towels",
209 | "Full-sized, pH-balanced toiletries",
210 | "Complimentary refreshments",
211 | "Adequate safety/security",
212 | "Internet",
213 | "Comfortable beds"
214 | ],
215 | images: [
216 | {
217 | fields: {
218 | file: {
219 | url: img4
220 | }
221 | }
222 | },
223 | {
224 | fields: {
225 | file: {
226 | url: room2
227 | }
228 | }
229 | },
230 | {
231 | fields: {
232 | file: {
233 | url: room3
234 | }
235 | }
236 | },
237 | {
238 | fields: {
239 | file: {
240 | url: room4
241 | }
242 | }
243 | }
244 | ]
245 | }
246 | },
247 | {
248 | sys: {
249 | id: "5"
250 | },
251 | fields: {
252 | name: "double economy",
253 | slug: "double-economy",
254 | type: "double",
255 | price: 200,
256 | size: 300,
257 | capacity: 2,
258 | pets: false,
259 | breakfast: false,
260 | featured: false,
261 | description:
262 | "Street art edison bulb gluten-free, tofu try-hard lumbersexual brooklyn tattooed pickled chambray. Actually humblebrag next level, deep v art party wolf tofu direct trade readymade sustainable hell of banjo. Organic authentic subway tile cliche palo santo, street art XOXO dreamcatcher retro sriracha portland air plant kitsch stumptown. Austin small batch squid gastropub. Pabst pug tumblr gochujang offal retro cloud bread bushwick semiotics before they sold out sartorial literally mlkshk. Vaporware hashtag vice, sartorial before they sold out pok pok health goth trust fund cray.",
263 | extras: [
264 | "Plush pillows and breathable bed linens",
265 | "Soft, oversized bath towels",
266 | "Full-sized, pH-balanced toiletries",
267 | "Complimentary refreshments",
268 | "Adequate safety/security",
269 | "Internet",
270 | "Comfortable beds"
271 | ],
272 | images: [
273 | {
274 | fields: {
275 | file: {
276 | url: img5
277 | }
278 | }
279 | },
280 | {
281 | fields: {
282 | file: {
283 | url: room2
284 | }
285 | }
286 | },
287 | {
288 | fields: {
289 | file: {
290 | url: room3
291 | }
292 | }
293 | },
294 | {
295 | fields: {
296 | file: {
297 | url: room4
298 | }
299 | }
300 | }
301 | ]
302 | }
303 | },
304 | {
305 | sys: {
306 | id: "6"
307 | },
308 | fields: {
309 | name: "double basic",
310 | slug: "double-basic",
311 | type: "double",
312 | price: 250,
313 | size: 350,
314 | capacity: 2,
315 | pets: false,
316 | breakfast: false,
317 | featured: false,
318 | description:
319 | "Street art edison bulb gluten-free, tofu try-hard lumbersexual brooklyn tattooed pickled chambray. Actually humblebrag next level, deep v art party wolf tofu direct trade readymade sustainable hell of banjo. Organic authentic subway tile cliche palo santo, street art XOXO dreamcatcher retro sriracha portland air plant kitsch stumptown. Austin small batch squid gastropub. Pabst pug tumblr gochujang offal retro cloud bread bushwick semiotics before they sold out sartorial literally mlkshk. Vaporware hashtag vice, sartorial before they sold out pok pok health goth trust fund cray.",
320 | extras: [
321 | "Plush pillows and breathable bed linens",
322 | "Soft, oversized bath towels",
323 | "Full-sized, pH-balanced toiletries",
324 | "Complimentary refreshments",
325 | "Adequate safety/security",
326 | "Internet",
327 | "Comfortable beds"
328 | ],
329 | images: [
330 | {
331 | fields: {
332 | file: {
333 | url: img6
334 | }
335 | }
336 | },
337 | {
338 | fields: {
339 | file: {
340 | url: room2
341 | }
342 | }
343 | },
344 | {
345 | fields: {
346 | file: {
347 | url: room3
348 | }
349 | }
350 | },
351 | {
352 | fields: {
353 | file: {
354 | url: room4
355 | }
356 | }
357 | }
358 | ]
359 | }
360 | },
361 | {
362 | sys: {
363 | id: "7"
364 | },
365 | fields: {
366 | name: "double standard",
367 | slug: "double-standard",
368 | type: "double",
369 | price: 300,
370 | size: 400,
371 | capacity: 2,
372 | pets: true,
373 | breakfast: false,
374 | featured: false,
375 | description:
376 | "Street art edison bulb gluten-free, tofu try-hard lumbersexual brooklyn tattooed pickled chambray. Actually humblebrag next level, deep v art party wolf tofu direct trade readymade sustainable hell of banjo. Organic authentic subway tile cliche palo santo, street art XOXO dreamcatcher retro sriracha portland air plant kitsch stumptown. Austin small batch squid gastropub. Pabst pug tumblr gochujang offal retro cloud bread bushwick semiotics before they sold out sartorial literally mlkshk. Vaporware hashtag vice, sartorial before they sold out pok pok health goth trust fund cray.",
377 | extras: [
378 | "Plush pillows and breathable bed linens",
379 | "Soft, oversized bath towels",
380 | "Full-sized, pH-balanced toiletries",
381 | "Complimentary refreshments",
382 | "Adequate safety/security",
383 | "Internet",
384 | "Comfortable beds"
385 | ],
386 | images: [
387 | {
388 | fields: {
389 | file: {
390 | url: img7
391 | }
392 | }
393 | },
394 | {
395 | fields: {
396 | file: {
397 | url: room2
398 | }
399 | }
400 | },
401 | {
402 | fields: {
403 | file: {
404 | url: room3
405 | }
406 | }
407 | },
408 | {
409 | fields: {
410 | file: {
411 | url: room4
412 | }
413 | }
414 | }
415 | ]
416 | }
417 | },
418 | {
419 | sys: {
420 | id: "8"
421 | },
422 | fields: {
423 | name: "double deluxe",
424 | slug: "double-deluxe",
425 | type: "double",
426 | price: 400,
427 | size: 500,
428 | capacity: 2,
429 | pets: true,
430 | breakfast: true,
431 | featured: true,
432 | description:
433 | "Street art edison bulb gluten-free, tofu try-hard lumbersexual brooklyn tattooed pickled chambray. Actually humblebrag next level, deep v art party wolf tofu direct trade readymade sustainable hell of banjo. Organic authentic subway tile cliche palo santo, street art XOXO dreamcatcher retro sriracha portland air plant kitsch stumptown. Austin small batch squid gastropub. Pabst pug tumblr gochujang offal retro cloud bread bushwick semiotics before they sold out sartorial literally mlkshk. Vaporware hashtag vice, sartorial before they sold out pok pok health goth trust fund cray.",
434 | extras: [
435 | "Plush pillows and breathable bed linens",
436 | "Soft, oversized bath towels",
437 | "Full-sized, pH-balanced toiletries",
438 | "Complimentary refreshments",
439 | "Adequate safety/security",
440 | "Internet",
441 | "Comfortable beds"
442 | ],
443 | images: [
444 | {
445 | fields: {
446 | file: {
447 | url: img8
448 | }
449 | }
450 | },
451 | {
452 | fields: {
453 | file: {
454 | url: room2
455 | }
456 | }
457 | },
458 | {
459 | fields: {
460 | file: {
461 | url: room3
462 | }
463 | }
464 | },
465 | {
466 | fields: {
467 | file: {
468 | url: room4
469 | }
470 | }
471 | }
472 | ]
473 | }
474 | },
475 | {
476 | sys: {
477 | id: "9"
478 | },
479 | fields: {
480 | name: "family economy",
481 | slug: "family-economy",
482 | type: "family",
483 | price: 300,
484 | size: 500,
485 | capacity: 3,
486 | pets: false,
487 | breakfast: false,
488 | featured: false,
489 | description:
490 | "Street art edison bulb gluten-free, tofu try-hard lumbersexual brooklyn tattooed pickled chambray. Actually humblebrag next level, deep v art party wolf tofu direct trade readymade sustainable hell of banjo. Organic authentic subway tile cliche palo santo, street art XOXO dreamcatcher retro sriracha portland air plant kitsch stumptown. Austin small batch squid gastropub. Pabst pug tumblr gochujang offal retro cloud bread bushwick semiotics before they sold out sartorial literally mlkshk. Vaporware hashtag vice, sartorial before they sold out pok pok health goth trust fund cray.",
491 | extras: [
492 | "Plush pillows and breathable bed linens",
493 | "Soft, oversized bath towels",
494 | "Full-sized, pH-balanced toiletries",
495 | "Complimentary refreshments",
496 | "Adequate safety/security",
497 | "Internet",
498 | "Comfortable beds"
499 | ],
500 | images: [
501 | {
502 | fields: {
503 | file: {
504 | url: img9
505 | }
506 | }
507 | },
508 | {
509 | fields: {
510 | file: {
511 | url: room2
512 | }
513 | }
514 | },
515 | {
516 | fields: {
517 | file: {
518 | url: room3
519 | }
520 | }
521 | },
522 | {
523 | fields: {
524 | file: {
525 | url: room4
526 | }
527 | }
528 | }
529 | ]
530 | }
531 | },
532 | {
533 | sys: {
534 | id: "10"
535 | },
536 | fields: {
537 | name: "family basic",
538 | slug: "family-basic",
539 | type: "family",
540 | price: 350,
541 | size: 550,
542 | capacity: 4,
543 | pets: false,
544 | breakfast: false,
545 | featured: false,
546 | description:
547 | "Street art edison bulb gluten-free, tofu try-hard lumbersexual brooklyn tattooed pickled chambray. Actually humblebrag next level, deep v art party wolf tofu direct trade readymade sustainable hell of banjo. Organic authentic subway tile cliche palo santo, street art XOXO dreamcatcher retro sriracha portland air plant kitsch stumptown. Austin small batch squid gastropub. Pabst pug tumblr gochujang offal retro cloud bread bushwick semiotics before they sold out sartorial literally mlkshk. Vaporware hashtag vice, sartorial before they sold out pok pok health goth trust fund cray.",
548 | extras: [
549 | "Plush pillows and breathable bed linens",
550 | "Soft, oversized bath towels",
551 | "Full-sized, pH-balanced toiletries",
552 | "Complimentary refreshments",
553 | "Adequate safety/security",
554 | "Internet",
555 | "Comfortable beds"
556 | ],
557 | images: [
558 | {
559 | fields: {
560 | file: {
561 | url: img10
562 | }
563 | }
564 | },
565 | {
566 | fields: {
567 | file: {
568 | url: room2
569 | }
570 | }
571 | },
572 | {
573 | fields: {
574 | file: {
575 | url: room3
576 | }
577 | }
578 | },
579 | {
580 | fields: {
581 | file: {
582 | url: room4
583 | }
584 | }
585 | }
586 | ]
587 | }
588 | },
589 | {
590 | sys: {
591 | id: "11"
592 | },
593 | fields: {
594 | name: "family standard",
595 | slug: "family-standard",
596 | type: "family",
597 | price: 400,
598 | size: 600,
599 | capacity: 5,
600 | pets: true,
601 | breakfast: false,
602 | featured: false,
603 | description:
604 | "Street art edison bulb gluten-free, tofu try-hard lumbersexual brooklyn tattooed pickled chambray. Actually humblebrag next level, deep v art party wolf tofu direct trade readymade sustainable hell of banjo. Organic authentic subway tile cliche palo santo, street art XOXO dreamcatcher retro sriracha portland air plant kitsch stumptown. Austin small batch squid gastropub. Pabst pug tumblr gochujang offal retro cloud bread bushwick semiotics before they sold out sartorial literally mlkshk. Vaporware hashtag vice, sartorial before they sold out pok pok health goth trust fund cray.",
605 | extras: [
606 | "Plush pillows and breathable bed linens",
607 | "Soft, oversized bath towels",
608 | "Full-sized, pH-balanced toiletries",
609 | "Complimentary refreshments",
610 | "Adequate safety/security",
611 | "Internet",
612 | "Comfortable beds"
613 | ],
614 | images: [
615 | {
616 | fields: {
617 | file: {
618 | url: img11
619 | }
620 | }
621 | },
622 | {
623 | fields: {
624 | file: {
625 | url: room2
626 | }
627 | }
628 | },
629 | {
630 | fields: {
631 | file: {
632 | url: room3
633 | }
634 | }
635 | },
636 | {
637 | fields: {
638 | file: {
639 | url: room4
640 | }
641 | }
642 | }
643 | ]
644 | }
645 | },
646 | {
647 | sys: {
648 | id: "12"
649 | },
650 | fields: {
651 | name: "family deluxe",
652 | slug: "family-deluxe",
653 | type: "family",
654 | price: 500,
655 | size: 700,
656 | capacity: 6,
657 | pets: true,
658 | breakfast: true,
659 | featured: true,
660 | description:
661 | "Street art edison bulb gluten-free, tofu try-hard lumbersexual brooklyn tattooed pickled chambray. Actually humblebrag next level, deep v art party wolf tofu direct trade readymade sustainable hell of banjo. Organic authentic subway tile cliche palo santo, street art XOXO dreamcatcher retro sriracha portland air plant kitsch stumptown. Austin small batch squid gastropub. Pabst pug tumblr gochujang offal retro cloud bread bushwick semiotics before they sold out sartorial literally mlkshk. Vaporware hashtag vice, sartorial before they sold out pok pok health goth trust fund cray.",
662 | extras: [
663 | "Plush pillows and breathable bed linens",
664 | "Soft, oversized bath towels",
665 | "Full-sized, pH-balanced toiletries",
666 | "Complimentary refreshments",
667 | "Adequate safety/security",
668 | "Internet",
669 | "Comfortable beds"
670 | ],
671 | images: [
672 | {
673 | fields: {
674 | file: {
675 | url: img12
676 | }
677 | }
678 | },
679 | {
680 | fields: {
681 | file: {
682 | url: room2
683 | }
684 | }
685 | },
686 | {
687 | fields: {
688 | file: {
689 | url: room3
690 | }
691 | }
692 | },
693 | {
694 | fields: {
695 | file: {
696 | url: room4
697 | }
698 | }
699 | }
700 | ]
701 | }
702 | },
703 | {
704 | sys: {
705 | id: "13"
706 | },
707 | fields: {
708 | name: "presidential",
709 | slug: "presidential-room",
710 | type: "presidential",
711 | price: 600,
712 | size: 1000,
713 | capacity: 10,
714 | pets: true,
715 | breakfast: true,
716 | featured: true,
717 | description:
718 | "Street art edison bulb gluten-free, tofu try-hard lumbersexual brooklyn tattooed pickled chambray. Actually humblebrag next level, deep v art party wolf tofu direct trade readymade sustainable hell of banjo. Organic authentic subway tile cliche palo santo, street art XOXO dreamcatcher retro sriracha portland air plant kitsch stumptown. Austin small batch squid gastropub. Pabst pug tumblr gochujang offal retro cloud bread bushwick semiotics before they sold out sartorial literally mlkshk. Vaporware hashtag vice, sartorial before they sold out pok pok health goth trust fund cray.",
719 | extras: [
720 | "Plush pillows and breathable bed linens",
721 | "Soft, oversized bath towels",
722 | "Full-sized, pH-balanced toiletries",
723 | "Complimentary refreshments",
724 | "Adequate safety/security",
725 | "Internet",
726 | "Comfortable beds"
727 | ],
728 | images: [
729 | {
730 | fields: {
731 | file: {
732 | url: room1
733 | }
734 | }
735 | },
736 | {
737 | fields: {
738 | file: {
739 | url: room2
740 | }
741 | }
742 | },
743 | {
744 | fields: {
745 | file: {
746 | url: room3
747 | }
748 | }
749 | },
750 | {
751 | fields: {
752 | file: {
753 | url: room4
754 | }
755 | }
756 | }
757 | ]
758 | }
759 | }
760 | ];
761 |
--------------------------------------------------------------------------------
/src/images/defaultBcg.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/defaultBcg.jpeg
--------------------------------------------------------------------------------
/src/images/details-1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/details-1.jpeg
--------------------------------------------------------------------------------
/src/images/details-2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/details-2.jpeg
--------------------------------------------------------------------------------
/src/images/details-3.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/details-3.jpeg
--------------------------------------------------------------------------------
/src/images/details-4.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/details-4.jpeg
--------------------------------------------------------------------------------
/src/images/gif/loading-arrow.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/gif/loading-arrow.gif
--------------------------------------------------------------------------------
/src/images/gif/loading-gear.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/gif/loading-gear.gif
--------------------------------------------------------------------------------
/src/images/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/images/room-1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/room-1.jpeg
--------------------------------------------------------------------------------
/src/images/room-10.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/room-10.jpeg
--------------------------------------------------------------------------------
/src/images/room-11.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/room-11.jpeg
--------------------------------------------------------------------------------
/src/images/room-12.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/room-12.jpeg
--------------------------------------------------------------------------------
/src/images/room-2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/room-2.jpeg
--------------------------------------------------------------------------------
/src/images/room-3.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/room-3.jpeg
--------------------------------------------------------------------------------
/src/images/room-4.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/room-4.jpeg
--------------------------------------------------------------------------------
/src/images/room-5.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/room-5.jpeg
--------------------------------------------------------------------------------
/src/images/room-6.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/room-6.jpeg
--------------------------------------------------------------------------------
/src/images/room-7.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/room-7.jpeg
--------------------------------------------------------------------------------
/src/images/room-8.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/room-8.jpeg
--------------------------------------------------------------------------------
/src/images/room-9.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-beach-resort-project/9c06f54c8548579846d47abf9afac379ad9998cc/src/images/room-9.jpeg
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | // import './index.css';
4 | import App from "./App";
5 | import * as serviceWorker from "./serviceWorker";
6 | import { RoomProvider } from "./context";
7 | import { BrowserRouter } from "react-router-dom";
8 |
9 | ReactDOM.render(
10 |
11 |
12 |
13 |
14 | ,
15 | document.getElementById("root")
16 | );
17 |
18 | // If you want your app to work offline and load faster, you can change
19 | // unregister() to register() below. Note this comes with some pitfalls.
20 | // Learn more about service workers: https://bit.ly/CRA-PWA
21 | serviceWorker.unregister();
22 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/pages/Error.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Hero from "../components/Hero";
3 | import Banner from "../components/Banner";
4 | import { Link } from "react-router-dom";
5 | const Error = () => {
6 | return (
7 |
8 |
9 |
10 | return home
11 |
12 |
13 |
14 | );
15 | };
16 |
17 | export default Error;
18 |
--------------------------------------------------------------------------------
/src/pages/Home.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 | import Hero from "../components/Hero";
4 | import Banner from "../components/Banner";
5 | import Services from "../components/Services";
6 | import FeaturedRooms from "../components/FeaturedRooms";
7 | const home = () => {
8 | return (
9 | <>
10 |
11 |
15 |
16 | our rooms
17 |
18 |
19 |
20 |
21 |
22 | >
23 | );
24 | };
25 |
26 | export default home;
27 |
--------------------------------------------------------------------------------
/src/pages/Rooms.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Hero from "../components/Hero";
3 | import Banner from "../components/Banner";
4 | import { Link } from "react-router-dom";
5 | import RoomsContainer from "../components/RoomsContainer";
6 | const Rooms = () => {
7 | return (
8 | <>
9 |
10 |
11 |
12 | return home
13 |
14 |
15 |
16 |
17 | >
18 | );
19 | };
20 |
21 | export default Rooms;
22 |
--------------------------------------------------------------------------------
/src/pages/SingleRoom.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import defaultBcg from "../images/room-1.jpeg";
3 | import Hero from "../components/Hero";
4 | import Banner from "../components/Banner";
5 | import { Link } from "react-router-dom";
6 | import { RoomContext } from "../context";
7 |
8 | import StyledHero from "../components/StyledHero";
9 | export default class SingleRoom extends Component {
10 | constructor(props) {
11 | super(props);
12 | console.log(this.props);
13 | this.state = {
14 | slug: this.props.match.params.slug,
15 | defaultBcg: defaultBcg
16 | };
17 | }
18 | static contextType = RoomContext;
19 |
20 | // componentDidMount() {
21 | // console.log(this.props);
22 | // }
23 | render() {
24 | const { getRoom } = this.context;
25 | const room = getRoom(this.state.slug);
26 |
27 | if (!room) {
28 | return (
29 |
30 |
no such room could be found...
31 |
32 | back to rooms
33 |
34 |
35 | );
36 | }
37 | const {
38 | name,
39 | description,
40 | capacity,
41 | size,
42 | price,
43 | extras,
44 | breakfast,
45 | pets,
46 | images
47 | } = room;
48 | const [main, ...defaultImages] = images;
49 | console.log(defaultImages);
50 |
51 | return (
52 | <>
53 |
54 |
55 |
56 | back to rooms
57 |
58 |
59 |
60 |
61 |
62 | {defaultImages.map((item, index) => (
63 |
64 | ))}
65 |
66 |
67 |
68 | details
69 | {description}
70 |
71 |
72 | info
73 | price : ${price}
74 | size : {size} SQFT
75 |
76 | max capacity :
77 | {capacity > 1 ? `${capacity} people` : `${capacity} person`}
78 |
79 | {pets ? "pets allowed" : "no pets allowed"}
80 | {breakfast && "free breakfast included"}
81 |
82 |
83 |
84 |
85 | extras
86 |
87 | {extras.map((item, index) => (
88 | - {item}
89 | ))}
90 |
91 |
92 | >
93 | );
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.1/8 is considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl)
104 | .then(response => {
105 | // Ensure service worker exists, and that we really are getting a JS file.
106 | const contentType = response.headers.get('content-type');
107 | if (
108 | response.status === 404 ||
109 | (contentType != null && contentType.indexOf('javascript') === -1)
110 | ) {
111 | // No service worker found. Probably a different app. Reload the page.
112 | navigator.serviceWorker.ready.then(registration => {
113 | registration.unregister().then(() => {
114 | window.location.reload();
115 | });
116 | });
117 | } else {
118 | // Service worker found. Proceed as normal.
119 | registerValidSW(swUrl, config);
120 | }
121 | })
122 | .catch(() => {
123 | console.log(
124 | 'No internet connection found. App is running in offline mode.'
125 | );
126 | });
127 | }
128 |
129 | export function unregister() {
130 | if ('serviceWorker' in navigator) {
131 | navigator.serviceWorker.ready.then(registration => {
132 | registration.unregister();
133 | });
134 | }
135 | }
136 |
--------------------------------------------------------------------------------