mirror of
https://github.com/rjNemo/meal_planner
synced 2026-06-12 13:26:45 +00:00
auth0 authentication & sample profile page
This commit is contained in:
parent
12fdc42bd5
commit
a649006d87
19 changed files with 263 additions and 339 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -21,3 +21,5 @@
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
|
||||||
|
/src/utils/auth_config.json
|
||||||
|
|
@ -71,8 +71,8 @@ Free meal planner for cooks short on ideas! (like me …)
|
||||||
- [Materialize](https://materializecss.com) CSS librairy for styling
|
- [Materialize](https://materializecss.com) CSS librairy for styling
|
||||||
- Public API: [TheMealDb](https://www.themealdb.com/api.php) and [TheCocktailDb](https://www.thecocktaildb.com/api.php)
|
- Public API: [TheMealDb](https://www.themealdb.com/api.php) and [TheCocktailDb](https://www.thecocktaildb.com/api.php)
|
||||||
- Hosting: [Render](https://render.com/)
|
- Hosting: [Render](https://render.com/)
|
||||||
|
- Authentication : [Auth0](https://auth0.com/)
|
||||||
- Analytics : Google Analytics & Mixpanel
|
- Analytics : Google Analytics & Mixpanel
|
||||||
- Authentication : Firebase or Auth0
|
|
||||||
|
|
||||||
## Versions
|
## Versions
|
||||||
|
|
||||||
|
|
@ -87,6 +87,7 @@ Free meal planner for cooks short on ideas! (like me …)
|
||||||
|
|
||||||
- Progressive Web App
|
- Progressive Web App
|
||||||
- User Interface Enhancement
|
- User Interface Enhancement
|
||||||
|
- Secured User Profiles
|
||||||
- Contact form
|
- Contact form
|
||||||
|
|
||||||
## TO DO
|
## TO DO
|
||||||
|
|
|
||||||
256
package-lock.json
generated
256
package-lock.json
generated
|
|
@ -4,6 +4,19 @@
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@auth0/auth0-spa-js": {
|
||||||
|
"version": "1.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@auth0/auth0-spa-js/-/auth0-spa-js-1.6.3.tgz",
|
||||||
|
"integrity": "sha512-jbK6qrcy3N8bAltP/sEdv9vo0eML9LneAESB05K/MPCwZVUJN9hu+y42DxfI7kH6dnVNyUbJohgpimv+eNonlQ==",
|
||||||
|
"requires": {
|
||||||
|
"browser-tabs-lock": "^1.2.1",
|
||||||
|
"core-js": "^3.2.1",
|
||||||
|
"es-cookie": "^1.2.0",
|
||||||
|
"fast-text-encoding": "^1.0.0",
|
||||||
|
"promise-polyfill": "^8.1.3",
|
||||||
|
"unfetch": "^4.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@babel/code-frame": {
|
"@babel/code-frame": {
|
||||||
"version": "7.8.3",
|
"version": "7.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
|
||||||
|
|
@ -1043,11 +1056,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz",
|
||||||
"integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg=="
|
"integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg=="
|
||||||
},
|
},
|
||||||
"@emotion/hash": {
|
|
||||||
"version": "0.7.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.7.4.tgz",
|
|
||||||
"integrity": "sha512-fxfMSBMX3tlIbKUdtGKxqB1fyrH6gVrX39Gsv3y8lRYKUqlgDt3UMqQyGnR1bQMa2B8aGnhLZokZgg8vT0Le+A=="
|
|
||||||
},
|
|
||||||
"@hapi/address": {
|
"@hapi/address": {
|
||||||
"version": "2.1.4",
|
"version": "2.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz",
|
||||||
|
|
@ -1273,75 +1281,6 @@
|
||||||
"@types/yargs": "^13.0.0"
|
"@types/yargs": "^13.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@material-ui/core": {
|
|
||||||
"version": "4.9.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.9.0.tgz",
|
|
||||||
"integrity": "sha512-zrrr8mPU5DDBYaVil4uJYauW41PjSn5otn7cqGsmWOY0t90fypr9nNgM7rRJaPz2AP6oRSDx1kBQt2igf5uelg==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.4.4",
|
|
||||||
"@material-ui/styles": "^4.9.0",
|
|
||||||
"@material-ui/system": "^4.7.1",
|
|
||||||
"@material-ui/types": "^5.0.0",
|
|
||||||
"@material-ui/utils": "^4.7.1",
|
|
||||||
"@types/react-transition-group": "^4.2.0",
|
|
||||||
"clsx": "^1.0.2",
|
|
||||||
"convert-css-length": "^2.0.1",
|
|
||||||
"hoist-non-react-statics": "^3.2.1",
|
|
||||||
"normalize-scroll-left": "^0.2.0",
|
|
||||||
"popper.js": "^1.14.1",
|
|
||||||
"prop-types": "^15.7.2",
|
|
||||||
"react-is": "^16.8.0",
|
|
||||||
"react-transition-group": "^4.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@material-ui/styles": {
|
|
||||||
"version": "4.9.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.9.0.tgz",
|
|
||||||
"integrity": "sha512-nJHum4RqYBPWsjL/9JET8Z02FZ9gSizlg/7LWVFpIthNzpK6OQ5OSRR4T4x9/p+wK3t1qNn3b1uI4XpnZaPxOA==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.4.4",
|
|
||||||
"@emotion/hash": "^0.7.4",
|
|
||||||
"@material-ui/types": "^5.0.0",
|
|
||||||
"@material-ui/utils": "^4.7.1",
|
|
||||||
"clsx": "^1.0.2",
|
|
||||||
"csstype": "^2.5.2",
|
|
||||||
"hoist-non-react-statics": "^3.2.1",
|
|
||||||
"jss": "^10.0.3",
|
|
||||||
"jss-plugin-camel-case": "^10.0.3",
|
|
||||||
"jss-plugin-default-unit": "^10.0.3",
|
|
||||||
"jss-plugin-global": "^10.0.3",
|
|
||||||
"jss-plugin-nested": "^10.0.3",
|
|
||||||
"jss-plugin-props-sort": "^10.0.3",
|
|
||||||
"jss-plugin-rule-value-function": "^10.0.3",
|
|
||||||
"jss-plugin-vendor-prefixer": "^10.0.3",
|
|
||||||
"prop-types": "^15.7.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@material-ui/system": {
|
|
||||||
"version": "4.7.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.7.1.tgz",
|
|
||||||
"integrity": "sha512-zH02p+FOimXLSKOW/OT2laYkl9bB3dD1AvnZqsHYoseUaq0aVrpbl2BGjQi+vJ5lg8w73uYlt9zOWzb3+1UdMQ==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.4.4",
|
|
||||||
"@material-ui/utils": "^4.7.1",
|
|
||||||
"prop-types": "^15.7.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@material-ui/types": {
|
|
||||||
"version": "5.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.0.0.tgz",
|
|
||||||
"integrity": "sha512-UeH2BuKkwDndtMSS0qgx1kCzSMw+ydtj0xx/XbFtxNSTlXydKwzs5gVW5ZKsFlAkwoOOQ9TIsyoCC8hq18tOwg=="
|
|
||||||
},
|
|
||||||
"@material-ui/utils": {
|
|
||||||
"version": "4.7.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.7.1.tgz",
|
|
||||||
"integrity": "sha512-+ux0SlLdlehvzCk2zdQ3KiS3/ylWvuo/JwAGhvb8dFVvwR21K28z0PU9OQW2PGogrMEdvX3miEI5tGxTwwWiwQ==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.4.4",
|
|
||||||
"prop-types": "^15.7.2",
|
|
||||||
"react-is": "^16.8.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@mrmlnc/readdir-enhanced": {
|
"@mrmlnc/readdir-enhanced": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
||||||
|
|
@ -1650,14 +1589,6 @@
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/react-transition-group": {
|
|
||||||
"version": "4.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.2.3.tgz",
|
|
||||||
"integrity": "sha512-Hk8jiuT7iLOHrcjKP/ZVSyCNXK73wJAUz60xm0mVhiRujrdiI++j4duLiL282VGxwAgxetHQFfqA29LgEeSkFA==",
|
|
||||||
"requires": {
|
|
||||||
"@types/react": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@types/stack-utils": {
|
"@types/stack-utils": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
||||||
|
|
@ -2876,6 +2807,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"browser-tabs-lock": {
|
||||||
|
"version": "1.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/browser-tabs-lock/-/browser-tabs-lock-1.2.6.tgz",
|
||||||
|
"integrity": "sha512-+FUo97nnOix/nQo+j4HyCO47bsJtfx1EFhj1rghqYx7N0MQ8D34aoP4eJGrMtN0D18s2OAGpbPqo/0ONGxDLiA=="
|
||||||
|
},
|
||||||
"browserify-aes": {
|
"browserify-aes": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
|
||||||
|
|
@ -3794,11 +3730,6 @@
|
||||||
"shallow-clone": "^0.1.2"
|
"shallow-clone": "^0.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"clsx": {
|
|
||||||
"version": "1.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.0.4.tgz",
|
|
||||||
"integrity": "sha512-1mQ557MIZTrL/140j+JVdRM6e31/OA4vTYxXgqIIZlndyfjHpyawKZia1Im05Vp9BWmImkcNrNtFYQMyFcgJDg=="
|
|
||||||
},
|
|
||||||
"co": {
|
"co": {
|
||||||
"version": "4.6.0",
|
"version": "4.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||||
|
|
@ -4010,11 +3941,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||||
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
|
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
|
||||||
},
|
},
|
||||||
"convert-css-length": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/convert-css-length/-/convert-css-length-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-iGpbcvhLPRKUbBc0Quxx7w/bV14AC3ItuBEGMahA5WTYqB8lq9jH0kTXFheCBASsYnqeMFZhiTruNxr1N59Axg=="
|
|
||||||
},
|
|
||||||
"convert-source-map": {
|
"convert-source-map": {
|
||||||
"version": "1.7.0",
|
"version": "1.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
|
||||||
|
|
@ -4301,15 +4227,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.1.tgz",
|
||||||
"integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY="
|
"integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY="
|
||||||
},
|
},
|
||||||
"css-vendor": {
|
|
||||||
"version": "2.0.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.7.tgz",
|
|
||||||
"integrity": "sha512-VS9Rjt79+p7M0WkPqcAza4Yq1ZHrsHrwf7hPL/bjQB+c1lwmAI+1FXxYTYt818D/50fFVflw0XKleiBN5RITkg==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.6.2",
|
|
||||||
"is-in-browser": "^1.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"css-what": {
|
"css-what": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz",
|
||||||
|
|
@ -4736,15 +4653,6 @@
|
||||||
"utila": "~0.4"
|
"utila": "~0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dom-helpers": {
|
|
||||||
"version": "5.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.1.3.tgz",
|
|
||||||
"integrity": "sha512-nZD1OtwfWGRBWlpANxacBEZrEuLa16o1nh7YopFWeoF68Zt8GGEmzHu6Xv4F3XaFIC+YXtTLrzgqKxFgLEe4jw==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.6.3",
|
|
||||||
"csstype": "^2.6.7"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dom-serializer": {
|
"dom-serializer": {
|
||||||
"version": "0.2.2",
|
"version": "0.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
|
||||||
|
|
@ -4992,6 +4900,11 @@
|
||||||
"string.prototype.trimright": "^2.1.1"
|
"string.prototype.trimright": "^2.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"es-cookie": {
|
||||||
|
"version": "1.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-cookie/-/es-cookie-1.3.2.tgz",
|
||||||
|
"integrity": "sha512-UTlYYhXGLOy05P/vKVT2Ui7WtC7NiRzGtJyAKKn32g5Gvcjn7KAClLPWlipCtxIus934dFg9o9jXiBL0nP+t9Q=="
|
||||||
|
},
|
||||||
"es-to-primitive": {
|
"es-to-primitive": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
|
||||||
|
|
@ -5855,6 +5768,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
||||||
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
|
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
|
||||||
},
|
},
|
||||||
|
"fast-text-encoding": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ=="
|
||||||
|
},
|
||||||
"faye-websocket": {
|
"faye-websocket": {
|
||||||
"version": "0.10.0",
|
"version": "0.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
|
||||||
|
|
@ -6718,11 +6636,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
|
||||||
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM="
|
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM="
|
||||||
},
|
},
|
||||||
"hyphenate-style-name": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz",
|
|
||||||
"integrity": "sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ=="
|
|
||||||
},
|
|
||||||
"iconv-lite": {
|
"iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
|
|
@ -7022,11 +6935,6 @@
|
||||||
"is-extglob": "^2.1.1"
|
"is-extglob": "^2.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"is-in-browser": {
|
|
||||||
"version": "1.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
|
|
||||||
"integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU="
|
|
||||||
},
|
|
||||||
"is-number": {
|
"is-number": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
|
||||||
|
|
@ -8371,83 +8279,6 @@
|
||||||
"verror": "1.10.0"
|
"verror": "1.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"jss": {
|
|
||||||
"version": "10.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/jss/-/jss-10.0.3.tgz",
|
|
||||||
"integrity": "sha512-AcDvFdOk16If9qvC9KN3oFXsrkHWM9+TaPMpVB9orm3z+nq1Xw3ofHyflRe/mkSucRZnaQtlhZs1hdP3DR9uRw==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.3.1",
|
|
||||||
"csstype": "^2.6.5",
|
|
||||||
"is-in-browser": "^1.1.3",
|
|
||||||
"tiny-warning": "^1.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jss-plugin-camel-case": {
|
|
||||||
"version": "10.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.0.3.tgz",
|
|
||||||
"integrity": "sha512-rild/oFKFkmRP7AoiX9D6bdDAUfmJv8c7sEBvFoi+JP31dn2W8nw4txMKGnV1LJKlFkYprdZt1X99Uvztl1hug==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.3.1",
|
|
||||||
"hyphenate-style-name": "^1.0.3",
|
|
||||||
"jss": "^10.0.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jss-plugin-default-unit": {
|
|
||||||
"version": "10.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.0.3.tgz",
|
|
||||||
"integrity": "sha512-n+XfVLPF9Qh7IOTdQ8M4oRpjpg6egjr/r0NNytubbCafMgCILJYIVrMTGgOTydH+uvak8onQY3f/F9hasPUx6g==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.3.1",
|
|
||||||
"jss": "^10.0.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jss-plugin-global": {
|
|
||||||
"version": "10.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.0.3.tgz",
|
|
||||||
"integrity": "sha512-kNotkAciJIXpIGYnmueaIifBne9rdq31O8Xq1nF7KMfKlskNRANTcEX5rVnsGKl2yubTMYfjKBFCeDgcQn6+gA==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.3.1",
|
|
||||||
"jss": "^10.0.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jss-plugin-nested": {
|
|
||||||
"version": "10.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.0.3.tgz",
|
|
||||||
"integrity": "sha512-OMucRs9YLvWlZ3Ew+VhdgNVMwSS2zZy/2vy+s/etvopnPUzDHgCnJwdY2Wx/SlhLGERJeKKufyih2seH+ui0iw==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.3.1",
|
|
||||||
"jss": "^10.0.3",
|
|
||||||
"tiny-warning": "^1.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jss-plugin-props-sort": {
|
|
||||||
"version": "10.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.0.3.tgz",
|
|
||||||
"integrity": "sha512-ufhvdCMnRcDa0tNHoZ12OcVNQQyE10yLMohxo/UIMarLV245rM6n9D19A12epjldRgyiS13SoSyLFCJEobprYg==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.3.1",
|
|
||||||
"jss": "^10.0.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jss-plugin-rule-value-function": {
|
|
||||||
"version": "10.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.0.3.tgz",
|
|
||||||
"integrity": "sha512-RWwIT2UBAIwf3f6DQtt5gyjxHMRJoeO9TQku+ueR8dBMakqSSe8vFwQNfjXEoe0W+Tez5HZCTkZKNMulv3Z+9A==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.3.1",
|
|
||||||
"jss": "^10.0.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jss-plugin-vendor-prefixer": {
|
|
||||||
"version": "10.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.0.3.tgz",
|
|
||||||
"integrity": "sha512-zVs6e5z4tFRK/fJ5kuTLzXlTFQbLeFTVwk7lTZiYNufmZwKT0kSmnOJDUukcSe7JLGSRztjWhnHB/6voP174gw==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.3.1",
|
|
||||||
"css-vendor": "^2.0.7",
|
|
||||||
"jss": "^10.0.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jsx-ast-utils": {
|
"jsx-ast-utils": {
|
||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz",
|
||||||
|
|
@ -9317,11 +9148,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
|
||||||
"integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI="
|
"integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI="
|
||||||
},
|
},
|
||||||
"normalize-scroll-left": {
|
|
||||||
"version": "0.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/normalize-scroll-left/-/normalize-scroll-left-0.2.0.tgz",
|
|
||||||
"integrity": "sha512-t5oCENZJl8TGusJKoCJm7+asaSsPuNmK6+iEjrZ5TyBj2f02brCRsd4c83hwtu+e5d4LCSBZ0uoDlMjBo+A8yA=="
|
|
||||||
},
|
|
||||||
"normalize-url": {
|
"normalize-url": {
|
||||||
"version": "1.9.1",
|
"version": "1.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
|
||||||
|
|
@ -9919,11 +9745,6 @@
|
||||||
"ts-pnp": "^1.1.2"
|
"ts-pnp": "^1.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"popper.js": {
|
|
||||||
"version": "1.16.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
|
|
||||||
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ=="
|
|
||||||
},
|
|
||||||
"portfinder": {
|
"portfinder": {
|
||||||
"version": "1.0.25",
|
"version": "1.0.25",
|
||||||
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz",
|
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz",
|
||||||
|
|
@ -10972,6 +10793,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
|
||||||
"integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM="
|
"integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM="
|
||||||
},
|
},
|
||||||
|
"promise-polyfill": {
|
||||||
|
"version": "8.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.3.tgz",
|
||||||
|
"integrity": "sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g=="
|
||||||
|
},
|
||||||
"prompts": {
|
"prompts": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.0.tgz",
|
||||||
|
|
@ -11438,17 +11264,6 @@
|
||||||
"workbox-webpack-plugin": "4.3.1"
|
"workbox-webpack-plugin": "4.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-transition-group": {
|
|
||||||
"version": "4.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.3.0.tgz",
|
|
||||||
"integrity": "sha512-1qRV1ZuVSdxPlPf4O8t7inxUGpdyO5zG9IoNfJxSO0ImU2A1YWkEQvFPuIPZmMLkg5hYs7vv5mMOyfgSkvAwvw==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.5.5",
|
|
||||||
"dom-helpers": "^5.0.1",
|
|
||||||
"loose-envify": "^1.4.0",
|
|
||||||
"prop-types": "^15.6.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"read-pkg": {
|
"read-pkg": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
|
||||||
|
|
@ -13319,6 +13134,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"unfetch": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-crP/n3eAPUJxZXM9T80/yv0YhkTEx2K1D3h7D1AJM6fzsWZrxdyRuLN0JH/dkZh1LNH8LxCnBzoPFCPbb2iGpg=="
|
||||||
|
},
|
||||||
"unicode-canonical-property-names-ecmascript": {
|
"unicode-canonical-property-names-ecmascript": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@auth0/auth0-spa-js": "^1.6.3",
|
||||||
"@testing-library/jest-dom": "^4.2.4",
|
"@testing-library/jest-dom": "^4.2.4",
|
||||||
"@testing-library/react": "^9.4.0",
|
"@testing-library/react": "^9.4.0",
|
||||||
"@testing-library/user-event": "^7.2.1",
|
"@testing-library/user-event": "^7.2.1",
|
||||||
|
|
|
||||||
20
src/App.js
20
src/App.js
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Router } from "./utils/router";
|
import { Router } from "./utils/router";
|
||||||
import { Switch, Route, Redirect } from "react-router-dom";
|
import { Switch, Route, Redirect } from "react-router-dom";
|
||||||
|
import { useAuth0 } from "./utils/auth0-spa";
|
||||||
import { Home } from "./pages/Home";
|
import { Home } from "./pages/Home";
|
||||||
import { Meal } from "./pages/Meal";
|
import { Meal } from "./pages/Meal";
|
||||||
import { SearchPage } from "./pages/Search";
|
import { SearchPage } from "./pages/Search";
|
||||||
|
|
@ -13,8 +14,12 @@ import { SearchBar } from "./components/SearchBar";
|
||||||
import { Footer } from "./components/Footer";
|
import { Footer } from "./components/Footer";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
import { getData } from "./utils/methods";
|
import { getData } from "./utils/methods";
|
||||||
|
import history from "./utils/history";
|
||||||
|
import { Profile } from "./pages/Profile";
|
||||||
|
import { PrivateRoute } from "./components/PrivateRoute";
|
||||||
|
|
||||||
export const App = () => {
|
export const App = () => {
|
||||||
|
const { loading } = useAuth0();
|
||||||
const [searchString, setSearchString] = useState("");
|
const [searchString, setSearchString] = useState("");
|
||||||
const [categories, setCategories] = useState({ categories: [] });
|
const [categories, setCategories] = useState({ categories: [] });
|
||||||
const [searchResults, setSearchResults] = useState({ meals: [] });
|
const [searchResults, setSearchResults] = useState({ meals: [] });
|
||||||
|
|
@ -103,10 +108,13 @@ export const App = () => {
|
||||||
|
|
||||||
const buttonUrl = "/random";
|
const buttonUrl = "/random";
|
||||||
|
|
||||||
return (
|
return loading ? (
|
||||||
<Router>
|
<div>Loading</div>
|
||||||
<Navbar handleClick={getRandomMeal} buttonUrl={buttonUrl} />
|
) : (
|
||||||
|
<Router history={history}>
|
||||||
|
<header>
|
||||||
|
<Navbar handleClick={getRandomMeal} buttonUrl={buttonUrl} />
|
||||||
|
</header>
|
||||||
<SearchBar
|
<SearchBar
|
||||||
searchString={searchString}
|
searchString={searchString}
|
||||||
handleChange={handleChange}
|
handleChange={handleChange}
|
||||||
|
|
@ -118,6 +126,10 @@ export const App = () => {
|
||||||
<Home buttonUrl={buttonUrl} />
|
<Home buttonUrl={buttonUrl} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
|
<PrivateRoute exact path="/profile">
|
||||||
|
<Profile />
|
||||||
|
</PrivateRoute>
|
||||||
|
|
||||||
<Route exact path={buttonUrl}>
|
<Route exact path={buttonUrl}>
|
||||||
{meal !== undefined && meal.meals !== null ? (
|
{meal !== undefined && meal.meals !== null ? (
|
||||||
<Meal meal={meal} getMeal={getRandomMeal} />
|
<Meal meal={meal} getMeal={getRandomMeal} />
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useState } from "react";
|
import React from "react";
|
||||||
|
|
||||||
export const ContactForm = ({ handleSubmit }) => {
|
export const ContactForm = ({ handleSubmit }) => {
|
||||||
const fields = ["firstname", "lastname", "email", "phone", "message"];
|
// const fields = ["firstname", "lastname", "email", "phone", "message"];
|
||||||
|
|
||||||
// const [firstName, setFirstName] = useState("");
|
// const [firstName, setFirstName] = useState("");
|
||||||
|
|
||||||
|
|
|
||||||
14
src/components/LogInButton.jsx
Normal file
14
src/components/LogInButton.jsx
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from "react";
|
||||||
|
import { useAuth0 } from "../utils/auth0-spa";
|
||||||
|
|
||||||
|
export const LogInButton = () => {
|
||||||
|
const { loginWithRedirect } = useAuth0();
|
||||||
|
const handleClick = () => {
|
||||||
|
loginWithRedirect({});
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<button className="waves-effect waves-light btn" onClick={handleClick}>
|
||||||
|
Log in
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
14
src/components/LogOutButton.jsx
Normal file
14
src/components/LogOutButton.jsx
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from "react";
|
||||||
|
import { useAuth0 } from "../utils/auth0-spa";
|
||||||
|
|
||||||
|
export const LogOutButton = () => {
|
||||||
|
const { logout } = useAuth0();
|
||||||
|
const handleClick = () => {
|
||||||
|
logout();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<button className="waves-effect waves-teal btn-flat" onClick={handleClick}>
|
||||||
|
Log out
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -1,21 +1,25 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { useAuth0 } from "../utils/auth0-spa";
|
||||||
import { Logo } from "./Logo";
|
import { Logo } from "./Logo";
|
||||||
|
|
||||||
import { RandomButton } from "./RandomButton";
|
import { RandomButton } from "./RandomButton";
|
||||||
import { FooterLink } from "./FooterLink";
|
import { FooterLink } from "./FooterLink";
|
||||||
|
import { LogInButton } from "./LogInButton";
|
||||||
|
import { LogOutButton } from "./LogOutButton";
|
||||||
|
|
||||||
export const Navbar = props => {
|
export const Navbar = props => {
|
||||||
|
const { isAuthenticated } = useAuth0();
|
||||||
const links = ["categories", "contact"];
|
const links = ["categories", "contact"];
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<nav>
|
<nav>
|
||||||
<div className="nav-wrapper">
|
<div className="nav-wrapper">
|
||||||
<div className="container">
|
<div className="container ">
|
||||||
<Logo />
|
<Logo />
|
||||||
<ul id="nav-mobile" className="right hide-on-med-and-down">
|
<ul id="nav-mobile" className="right hide-on-med-and-down">
|
||||||
{links.map((link, i) => (
|
{links.map((link, i) => (
|
||||||
<FooterLink key={i} link={link} />
|
<FooterLink key={i} link={link} />
|
||||||
))}
|
))}
|
||||||
|
<li>{isAuthenticated && <FooterLink link="profile" />}</li>
|
||||||
<li>
|
<li>
|
||||||
<RandomButton
|
<RandomButton
|
||||||
handleClick={props.handleClick}
|
handleClick={props.handleClick}
|
||||||
|
|
@ -23,6 +27,7 @@ export const Navbar = props => {
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
|
<li>{!isAuthenticated ? <LogInButton /> : <LogOutButton />}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
25
src/components/PrivateRoute.jsx
Normal file
25
src/components/PrivateRoute.jsx
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { Route } from "react-router-dom";
|
||||||
|
import { useAuth0 } from "../utils/auth0-spa";
|
||||||
|
|
||||||
|
export const PrivateRoute = ({ component: Component, path, ...rest }) => {
|
||||||
|
const { loading, isAuthenticated, loginWithRedirect } = useAuth0();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (loading || isAuthenticated) {
|
||||||
|
// catches infinite loading when no user is logged in
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const fn = async () => {
|
||||||
|
await loginWithRedirect({
|
||||||
|
appState: { targetUrl: path }
|
||||||
|
});
|
||||||
|
};
|
||||||
|
fn();
|
||||||
|
}, [loading, isAuthenticated, loginWithRedirect, path]);
|
||||||
|
|
||||||
|
const render = props =>
|
||||||
|
isAuthenticated === true ? <Component {...props} /> : null;
|
||||||
|
|
||||||
|
return <Route path={path} render={render} {...rest} />;
|
||||||
|
};
|
||||||
23
src/index.js
23
src/index.js
|
|
@ -3,7 +3,28 @@ import ReactDOM from "react-dom";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
import { App } from "./App";
|
import { App } from "./App";
|
||||||
import * as serviceWorker from "./serviceWorker";
|
import * as serviceWorker from "./serviceWorker";
|
||||||
|
import { Auth0Provider } from "./utils/auth0-spa";
|
||||||
|
import history from "./utils/history";
|
||||||
|
import config from "./utils/auth_config.json"; // for safety reasons this file is not tracked by git
|
||||||
|
|
||||||
ReactDOM.render(<App />, document.getElementById("root"));
|
const onRedirectCallBack = appState => {
|
||||||
|
history.push(
|
||||||
|
appState && appState.targetUrl
|
||||||
|
? appState.targetUrl
|
||||||
|
: window.location.pathname
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<Auth0Provider
|
||||||
|
domain={config.domain}
|
||||||
|
client_id={config.clientId}
|
||||||
|
redirect_uri={window.location.origin}
|
||||||
|
onRedirectCallBack={onRedirectCallBack}
|
||||||
|
>
|
||||||
|
<App />
|
||||||
|
</Auth0Provider>,
|
||||||
|
document.getElementById("root")
|
||||||
|
);
|
||||||
|
|
||||||
serviceWorker.register();
|
serviceWorker.register();
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ export const CategoryPage = props => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getMeals();
|
getMeals();
|
||||||
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ export const CategoryListPage = props => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getCategories();
|
getCategories();
|
||||||
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ export const Meal = props => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
idMeal === null ? getMeal() : getMeal(idMeal);
|
idMeal === null ? getMeal() : getMeal(idMeal);
|
||||||
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const meal = props.meal.meals[0];
|
const meal = props.meal.meals[0];
|
||||||
|
|
|
||||||
17
src/pages/Profile.jsx
Normal file
17
src/pages/Profile.jsx
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import React from "react";
|
||||||
|
import { useAuth0 } from "../utils/auth0-spa";
|
||||||
|
|
||||||
|
export const Profile = () => {
|
||||||
|
const { loading, user } = useAuth0();
|
||||||
|
|
||||||
|
return loading || !user ? (
|
||||||
|
<div>Loading ... </div> // is catched by PrivateRoute
|
||||||
|
) : (
|
||||||
|
<div className="container">
|
||||||
|
<img className="responsive-img" src={user.picture} alt="Avatar" />
|
||||||
|
<h2>{user.name}</h2>
|
||||||
|
<p>{user.email}</p>
|
||||||
|
<code>{JSON.stringify(user, null, 2)}</code>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
93
src/utils/auth0-spa.js
Normal file
93
src/utils/auth0-spa.js
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
// adapted from: https://auth0.com/docs/quickstart/spa/react
|
||||||
|
import React, { useContext, useState, useEffect } from "react";
|
||||||
|
import createAuth0Client from "@auth0/auth0-spa-js";
|
||||||
|
|
||||||
|
const DEFAULT_REDIRECT_CALLBACK = () => {
|
||||||
|
window.history.replaceState({}, document.title, window.location.pathname);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Auth0Context = React.createContext();
|
||||||
|
export const useAuth0 = () => useContext(Auth0Context);
|
||||||
|
|
||||||
|
export const Auth0Provider = ({
|
||||||
|
children,
|
||||||
|
onRedirectCallBack = DEFAULT_REDIRECT_CALLBACK,
|
||||||
|
...initOptions
|
||||||
|
}) => {
|
||||||
|
const [isAuthenticated, setIsAuthenticated] = useState();
|
||||||
|
const [user, setUser] = useState();
|
||||||
|
const [auth0Client, setAuth0] = useState();
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [popUpOpen, setPopUpOpen] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const initAuth0 = async () => {
|
||||||
|
const auth0FromHook = await createAuth0Client(initOptions);
|
||||||
|
setAuth0(auth0FromHook);
|
||||||
|
|
||||||
|
if (
|
||||||
|
window.location.search.includes("code=") &&
|
||||||
|
window.location.search.includes("state=")
|
||||||
|
) {
|
||||||
|
const { appState } = await auth0FromHook.handleRedirectCallback();
|
||||||
|
onRedirectCallBack(appState);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isAuthenticated = await auth0FromHook.isAuthenticated();
|
||||||
|
setIsAuthenticated(isAuthenticated);
|
||||||
|
|
||||||
|
if (isAuthenticated) {
|
||||||
|
const user = await auth0FromHook.getUser();
|
||||||
|
setUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
initAuth0();
|
||||||
|
// eslint-disable-next-line
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const loginWithPopUp = async (params = {}) => {
|
||||||
|
setPopUpOpen(true);
|
||||||
|
try {
|
||||||
|
await auth0Client.loginWithPopUp(params);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
setPopUpOpen(false);
|
||||||
|
}
|
||||||
|
const user = auth0Client.getUser();
|
||||||
|
setUser(user);
|
||||||
|
setIsAuthenticated(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRedirectCallback = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
await auth0Client.handleRedirectCallback();
|
||||||
|
const user = auth0Client.getUser();
|
||||||
|
setLoading(false);
|
||||||
|
setIsAuthenticated(true);
|
||||||
|
setUser(user);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Auth0Context.Provider
|
||||||
|
value={{
|
||||||
|
isAuthenticated,
|
||||||
|
user,
|
||||||
|
loading,
|
||||||
|
popUpOpen,
|
||||||
|
loginWithPopUp,
|
||||||
|
handleRedirectCallback,
|
||||||
|
getIdTokenClaims: (...props) => auth0Client.getIdTokenClaims(...props),
|
||||||
|
loginWithRedirect: (...props) =>
|
||||||
|
auth0Client.loginWithRedirect(...props),
|
||||||
|
getTokenWithPopUp: (...props) =>
|
||||||
|
auth0Client.getTokenWithPopUp(...props),
|
||||||
|
logout: (...props) => auth0Client.logout(...props)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Auth0Context.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
5
src/utils/auth_config.json.example
Normal file
5
src/utils/auth_config.json.example
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
/* This is a dummy auth0 config file. Use https://auth0.com/ to create your own set of keys */
|
||||||
|
{
|
||||||
|
"domain": "{DOMAIN}",
|
||||||
|
"clientId": "{CLIENT_ID}"
|
||||||
|
}
|
||||||
|
|
@ -1,111 +0,0 @@
|
||||||
import React, { useState, useEffect, useContext, createContext } from "react";
|
|
||||||
import queryString from "query-string";
|
|
||||||
import * as firebase from "firebase/app";
|
|
||||||
import "firebase/auth";
|
|
||||||
|
|
||||||
if (!firebase.apps.length) {
|
|
||||||
// Replace with your own Firebase credentials
|
|
||||||
firebase.initializeApp({
|
|
||||||
apiKey: "AIzaSyBkkFF0XhNZeWuDmOfEhsgdfX1VBG7WTas",
|
|
||||||
authDomain: "divjoy-demo.firebaseapp.com",
|
|
||||||
projectId: "divjoy-demo",
|
|
||||||
appID: "divjoy-demo"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const authContext = createContext();
|
|
||||||
|
|
||||||
// Provider component that wraps your app and makes auth object ...
|
|
||||||
// ... available to any child component that calls useAuth().
|
|
||||||
export function ProvideAuth({ children }) {
|
|
||||||
const auth = useProvideAuth();
|
|
||||||
return <authContext.Provider value={auth}>{children}</authContext.Provider>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hook for child components to get the auth object ...
|
|
||||||
// ... update when it changes.
|
|
||||||
export const useAuth = () => {
|
|
||||||
return useContext(authContext);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Provider hook that creates auth object and handles state
|
|
||||||
function useProvideAuth() {
|
|
||||||
const [user, setUser] = useState(null);
|
|
||||||
|
|
||||||
const signin = (email, password) => {
|
|
||||||
return firebase
|
|
||||||
.auth()
|
|
||||||
.signInWithEmailAndPassword(email, password)
|
|
||||||
.then(response => {
|
|
||||||
setUser(response.user);
|
|
||||||
return response.user;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const signup = (email, password) => {
|
|
||||||
return firebase
|
|
||||||
.auth()
|
|
||||||
.createUserWithEmailAndPassword(email, password)
|
|
||||||
.then(response => {
|
|
||||||
setUser(response.user);
|
|
||||||
return response.user;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const signout = () => {
|
|
||||||
return firebase
|
|
||||||
.auth()
|
|
||||||
.signOut()
|
|
||||||
.then(() => {
|
|
||||||
setUser(false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const sendPasswordResetEmail = email => {
|
|
||||||
return firebase
|
|
||||||
.auth()
|
|
||||||
.sendPasswordResetEmail(email)
|
|
||||||
.then(() => {
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const confirmPasswordReset = (password, code) => {
|
|
||||||
// Get code from query string object
|
|
||||||
const resetCode = code || getFromQueryString("oobCode");
|
|
||||||
|
|
||||||
return firebase
|
|
||||||
.auth()
|
|
||||||
.confirmPasswordReset(resetCode, password)
|
|
||||||
.then(() => {
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Subscribe to user on mount
|
|
||||||
useEffect(() => {
|
|
||||||
const unsubscribe = firebase.auth().onAuthStateChanged(user => {
|
|
||||||
if (user) {
|
|
||||||
setUser(user);
|
|
||||||
} else {
|
|
||||||
setUser(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Subscription unsubscribe function
|
|
||||||
return () => unsubscribe();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return {
|
|
||||||
user,
|
|
||||||
signin,
|
|
||||||
signup,
|
|
||||||
signout,
|
|
||||||
sendPasswordResetEmail,
|
|
||||||
confirmPasswordReset
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const getFromQueryString = key => {
|
|
||||||
return queryString.parse(window.location.search)[key];
|
|
||||||
};
|
|
||||||
2
src/utils/history.js
Normal file
2
src/utils/history.js
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
import { createBrowserHistory } from "history";
|
||||||
|
export default createBrowserHistory();
|
||||||
Loading…
Reference in a new issue