mirror of
https://github.com/rjNemo/meal_planner
synced 2026-06-06 02:26:49 +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*
|
||||
yarn-debug.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
|
||||
- Public API: [TheMealDb](https://www.themealdb.com/api.php) and [TheCocktailDb](https://www.thecocktaildb.com/api.php)
|
||||
- Hosting: [Render](https://render.com/)
|
||||
- Authentication : [Auth0](https://auth0.com/)
|
||||
- Analytics : Google Analytics & Mixpanel
|
||||
- Authentication : Firebase or Auth0
|
||||
|
||||
## Versions
|
||||
|
||||
|
|
@ -87,6 +87,7 @@ Free meal planner for cooks short on ideas! (like me …)
|
|||
|
||||
- Progressive Web App
|
||||
- User Interface Enhancement
|
||||
- Secured User Profiles
|
||||
- Contact form
|
||||
|
||||
## TO DO
|
||||
|
|
|
|||
256
package-lock.json
generated
256
package-lock.json
generated
|
|
@ -4,6 +4,19 @@
|
|||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"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": {
|
||||
"version": "7.8.3",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz",
|
||||
|
|
@ -1273,75 +1281,6 @@
|
|||
"@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": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
||||
|
|
@ -1650,14 +1589,6 @@
|
|||
"@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": {
|
||||
"version": "1.0.1",
|
||||
"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": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
|
||||
|
|
@ -3794,11 +3730,6 @@
|
|||
"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": {
|
||||
"version": "4.6.0",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "1.7.0",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz",
|
||||
|
|
@ -4736,15 +4653,6 @@
|
|||
"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": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
|
||||
|
|
@ -4992,6 +4900,11 @@
|
|||
"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": {
|
||||
"version": "1.2.1",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "0.10.0",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
|
|
@ -7022,11 +6935,6 @@
|
|||
"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": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
|
||||
|
|
@ -8371,83 +8279,6 @@
|
|||
"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": {
|
||||
"version": "2.2.3",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
|
||||
|
|
@ -9919,11 +9745,6 @@
|
|||
"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": {
|
||||
"version": "1.0.25",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.0.tgz",
|
||||
|
|
@ -11438,17 +11264,6 @@
|
|||
"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": {
|
||||
"version": "3.0.0",
|
||||
"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": {
|
||||
"version": "1.0.4",
|
||||
"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",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@auth0/auth0-spa-js": "^1.6.3",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.4.0",
|
||||
"@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 { Router } from "./utils/router";
|
||||
import { Switch, Route, Redirect } from "react-router-dom";
|
||||
import { useAuth0 } from "./utils/auth0-spa";
|
||||
import { Home } from "./pages/Home";
|
||||
import { Meal } from "./pages/Meal";
|
||||
import { SearchPage } from "./pages/Search";
|
||||
|
|
@ -13,8 +14,12 @@ import { SearchBar } from "./components/SearchBar";
|
|||
import { Footer } from "./components/Footer";
|
||||
import "./index.css";
|
||||
import { getData } from "./utils/methods";
|
||||
import history from "./utils/history";
|
||||
import { Profile } from "./pages/Profile";
|
||||
import { PrivateRoute } from "./components/PrivateRoute";
|
||||
|
||||
export const App = () => {
|
||||
const { loading } = useAuth0();
|
||||
const [searchString, setSearchString] = useState("");
|
||||
const [categories, setCategories] = useState({ categories: [] });
|
||||
const [searchResults, setSearchResults] = useState({ meals: [] });
|
||||
|
|
@ -103,10 +108,13 @@ export const App = () => {
|
|||
|
||||
const buttonUrl = "/random";
|
||||
|
||||
return (
|
||||
<Router>
|
||||
<Navbar handleClick={getRandomMeal} buttonUrl={buttonUrl} />
|
||||
|
||||
return loading ? (
|
||||
<div>Loading</div>
|
||||
) : (
|
||||
<Router history={history}>
|
||||
<header>
|
||||
<Navbar handleClick={getRandomMeal} buttonUrl={buttonUrl} />
|
||||
</header>
|
||||
<SearchBar
|
||||
searchString={searchString}
|
||||
handleChange={handleChange}
|
||||
|
|
@ -118,6 +126,10 @@ export const App = () => {
|
|||
<Home buttonUrl={buttonUrl} />
|
||||
</Route>
|
||||
|
||||
<PrivateRoute exact path="/profile">
|
||||
<Profile />
|
||||
</PrivateRoute>
|
||||
|
||||
<Route exact path={buttonUrl}>
|
||||
{meal !== undefined && meal.meals !== null ? (
|
||||
<Meal meal={meal} getMeal={getRandomMeal} />
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
|
||||
export const ContactForm = ({ handleSubmit }) => {
|
||||
const fields = ["firstname", "lastname", "email", "phone", "message"];
|
||||
// const fields = ["firstname", "lastname", "email", "phone", "message"];
|
||||
|
||||
// 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 { useAuth0 } from "../utils/auth0-spa";
|
||||
import { Logo } from "./Logo";
|
||||
|
||||
import { RandomButton } from "./RandomButton";
|
||||
import { FooterLink } from "./FooterLink";
|
||||
import { LogInButton } from "./LogInButton";
|
||||
import { LogOutButton } from "./LogOutButton";
|
||||
|
||||
export const Navbar = props => {
|
||||
const { isAuthenticated } = useAuth0();
|
||||
const links = ["categories", "contact"];
|
||||
return (
|
||||
<div className="row">
|
||||
<nav>
|
||||
<div className="nav-wrapper">
|
||||
<div className="container">
|
||||
<div className="container ">
|
||||
<Logo />
|
||||
<ul id="nav-mobile" className="right hide-on-med-and-down">
|
||||
{links.map((link, i) => (
|
||||
<FooterLink key={i} link={link} />
|
||||
))}
|
||||
<li>{isAuthenticated && <FooterLink link="profile" />}</li>
|
||||
<li>
|
||||
<RandomButton
|
||||
handleClick={props.handleClick}
|
||||
|
|
@ -23,6 +27,7 @@ export const Navbar = props => {
|
|||
size="small"
|
||||
/>
|
||||
</li>
|
||||
<li>{!isAuthenticated ? <LogInButton /> : <LogOutButton />}</li>
|
||||
</ul>
|
||||
</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 { App } from "./App";
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export const CategoryPage = props => {
|
|||
|
||||
useEffect(() => {
|
||||
getMeals();
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export const CategoryListPage = props => {
|
|||
|
||||
useEffect(() => {
|
||||
getCategories();
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export const Meal = props => {
|
|||
|
||||
useEffect(() => {
|
||||
idMeal === null ? getMeal() : getMeal(idMeal);
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
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