From b8330b33951d579344a27b133cb840a2552aeedf Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Thu, 3 Dec 2020 23:12:47 +0800 Subject: [PATCH 01/41] packages: add firebase Signed-off-by: Isabella Hu --- package-lock.json | 578 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 1 + 2 files changed, 575 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3f2d4ee..fc73cbc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1458,6 +1458,288 @@ } } }, + "@firebase/analytics": { + "version": "0.6.2", + "resolved": "https://registry.npm.taobao.org/@firebase/analytics/download/@firebase/analytics-0.6.2.tgz", + "integrity": "sha1-f0VnWhtST/9Nnp/jGP1uLtBnoyU=", + "requires": { + "@firebase/analytics-types": "0.4.0", + "@firebase/component": "0.1.21", + "@firebase/installations": "0.4.19", + "@firebase/logger": "0.2.6", + "@firebase/util": "0.3.4", + "tslib": "^1.11.1" + } + }, + "@firebase/analytics-types": { + "version": "0.4.0", + "resolved": "https://registry.npm.taobao.org/@firebase/analytics-types/download/@firebase/analytics-types-0.4.0.tgz", + "integrity": "sha1-1nFvn6NqbjQLwOz+aK8yWqb2BQg=" + }, + "@firebase/app": { + "version": "0.6.13", + "resolved": "https://registry.npm.taobao.org/@firebase/app/download/@firebase/app-0.6.13.tgz", + "integrity": "sha1-8un6nnWBXlQWHcNGWaYPH//ZpFA=", + "requires": { + "@firebase/app-types": "0.6.1", + "@firebase/component": "0.1.21", + "@firebase/logger": "0.2.6", + "@firebase/util": "0.3.4", + "dom-storage": "2.1.0", + "tslib": "^1.11.1", + "xmlhttprequest": "1.8.0" + } + }, + "@firebase/app-types": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/@firebase/app-types/download/@firebase/app-types-0.6.1.tgz", + "integrity": "sha1-3L0jAwpxwMdPyV1KP3W6gWU4UOk=" + }, + "@firebase/auth": { + "version": "0.15.2", + "resolved": "https://registry.npm.taobao.org/@firebase/auth/download/@firebase/auth-0.15.2.tgz", + "integrity": "sha1-mto/N2INExocVplBOKWZtcn5yi4=", + "requires": { + "@firebase/auth-types": "0.10.1" + } + }, + "@firebase/auth-interop-types": { + "version": "0.1.5", + "resolved": "https://registry.npm.taobao.org/@firebase/auth-interop-types/download/@firebase/auth-interop-types-0.1.5.tgz", + "integrity": "sha1-n8m9fIefFrjRuwg3Og9Iw6i3RVc=" + }, + "@firebase/auth-types": { + "version": "0.10.1", + "resolved": "https://registry.npm.taobao.org/@firebase/auth-types/download/@firebase/auth-types-0.10.1.tgz", + "integrity": "sha1-eBXnHJxvByA0QVUkspyo8dF3BmA=" + }, + "@firebase/component": { + "version": "0.1.21", + "resolved": "https://registry.npm.taobao.org/@firebase/component/download/@firebase/component-0.1.21.tgz", + "integrity": "sha1-VgYusNRJ3B57vvPAhKm1+kjHwU0=", + "requires": { + "@firebase/util": "0.3.4", + "tslib": "^1.11.1" + } + }, + "@firebase/database": { + "version": "0.8.1", + "resolved": "https://registry.npm.taobao.org/@firebase/database/download/@firebase/database-0.8.1.tgz", + "integrity": "sha1-p7wcAQUtNYF6JCwhv+Casp7khaM=", + "requires": { + "@firebase/auth-interop-types": "0.1.5", + "@firebase/component": "0.1.21", + "@firebase/database-types": "0.6.1", + "@firebase/logger": "0.2.6", + "@firebase/util": "0.3.4", + "faye-websocket": "0.11.3", + "tslib": "^1.11.1" + }, + "dependencies": { + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npm.taobao.org/faye-websocket/download/faye-websocket-0.11.3.tgz", + "integrity": "sha1-XA6aiWjokSwoZjn96XeosgnyUI4=", + "requires": { + "websocket-driver": ">=0.5.1" + } + } + } + }, + "@firebase/database-types": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/@firebase/database-types/download/@firebase/database-types-0.6.1.tgz", + "integrity": "sha1-zxz8A+YX7UwlYXA3gfhbpMcH/2U=", + "requires": { + "@firebase/app-types": "0.6.1" + } + }, + "@firebase/firestore": { + "version": "2.0.4", + "resolved": "https://registry.npm.taobao.org/@firebase/firestore/download/@firebase/firestore-2.0.4.tgz", + "integrity": "sha1-xL5vNUD2B/2OIAz7qDxJl8KUR/4=", + "requires": { + "@firebase/component": "0.1.21", + "@firebase/firestore-types": "2.0.0", + "@firebase/logger": "0.2.6", + "@firebase/util": "0.3.4", + "@firebase/webchannel-wrapper": "0.4.1", + "@grpc/grpc-js": "^1.0.0", + "@grpc/proto-loader": "^0.5.0", + "node-fetch": "2.6.1", + "tslib": "^1.11.1" + } + }, + "@firebase/firestore-types": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/@firebase/firestore-types/download/@firebase/firestore-types-2.0.0.tgz", + "integrity": "sha1-H2ISVTskDxqJBbuNzx+HdpE4xcA=" + }, + "@firebase/functions": { + "version": "0.6.1", + "resolved": "https://registry.npm.taobao.org/@firebase/functions/download/@firebase/functions-0.6.1.tgz", + "integrity": "sha1-MmQLj4d2NwV9+q6xIr6MjpmtGvc=", + "requires": { + "@firebase/component": "0.1.21", + "@firebase/functions-types": "0.4.0", + "@firebase/messaging-types": "0.5.0", + "node-fetch": "2.6.1", + "tslib": "^1.11.1" + } + }, + "@firebase/functions-types": { + "version": "0.4.0", + "resolved": "https://registry.npm.taobao.org/@firebase/functions-types/download/@firebase/functions-types-0.4.0.tgz", + "integrity": "sha1-C3ifT+mpwLmHYGxNoQE5NFtA9rk=" + }, + "@firebase/installations": { + "version": "0.4.19", + "resolved": "https://registry.npm.taobao.org/@firebase/installations/download/@firebase/installations-0.4.19.tgz", + "integrity": "sha1-U/UK6wIplpY/ifWVYNe0z4AYado=", + "requires": { + "@firebase/component": "0.1.21", + "@firebase/installations-types": "0.3.4", + "@firebase/util": "0.3.4", + "idb": "3.0.2", + "tslib": "^1.11.1" + } + }, + "@firebase/installations-types": { + "version": "0.3.4", + "resolved": "https://registry.npm.taobao.org/@firebase/installations-types/download/@firebase/installations-types-0.3.4.tgz", + "integrity": "sha1-WJqUHXE/T2S/n0/rf0Y1Bbqxr6I=" + }, + "@firebase/logger": { + "version": "0.2.6", + "resolved": "https://registry.npm.taobao.org/@firebase/logger/download/@firebase/logger-0.2.6.tgz", + "integrity": "sha1-OqLKT+EDJ8q/eAi9OZTojbJteYk=" + }, + "@firebase/messaging": { + "version": "0.7.3", + "resolved": "https://registry.npm.taobao.org/@firebase/messaging/download/@firebase/messaging-0.7.3.tgz", + "integrity": "sha1-Md3tiSRV5NBoDhRS/y+/37nkzps=", + "requires": { + "@firebase/component": "0.1.21", + "@firebase/installations": "0.4.19", + "@firebase/messaging-types": "0.5.0", + "@firebase/util": "0.3.4", + "idb": "3.0.2", + "tslib": "^1.11.1" + } + }, + "@firebase/messaging-types": { + "version": "0.5.0", + "resolved": "https://registry.npm.taobao.org/@firebase/messaging-types/download/@firebase/messaging-types-0.5.0.tgz", + "integrity": "sha1-xdDvMJztF1j9qT7zrHCnht4uc8Q=" + }, + "@firebase/performance": { + "version": "0.4.4", + "resolved": "https://registry.npm.taobao.org/@firebase/performance/download/@firebase/performance-0.4.4.tgz", + "integrity": "sha1-XxPqO5pyoK6cNlIMQZvjFEiglVo=", + "requires": { + "@firebase/component": "0.1.21", + "@firebase/installations": "0.4.19", + "@firebase/logger": "0.2.6", + "@firebase/performance-types": "0.0.13", + "@firebase/util": "0.3.4", + "tslib": "^1.11.1" + } + }, + "@firebase/performance-types": { + "version": "0.0.13", + "resolved": "https://registry.npm.taobao.org/@firebase/performance-types/download/@firebase/performance-types-0.0.13.tgz", + "integrity": "sha1-WM5UU/V+NLGBhvdO8RVQ38VY7eY=" + }, + "@firebase/polyfill": { + "version": "0.3.36", + "resolved": "https://registry.npm.taobao.org/@firebase/polyfill/download/@firebase/polyfill-0.3.36.tgz", + "integrity": "sha1-wFfM5nSBcPNpZrVVdJRysl79sUU=", + "requires": { + "core-js": "3.6.5", + "promise-polyfill": "8.1.3", + "whatwg-fetch": "2.0.4" + }, + "dependencies": { + "whatwg-fetch": { + "version": "2.0.4", + "resolved": "https://registry.npm.taobao.org/whatwg-fetch/download/whatwg-fetch-2.0.4.tgz?cache=0&sync_timestamp=1604658531975&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwhatwg-fetch%2Fdownload%2Fwhatwg-fetch-2.0.4.tgz", + "integrity": "sha1-3eal3zFfnTmZGqF2IYU9cguFVm8=" + } + } + }, + "@firebase/remote-config": { + "version": "0.1.30", + "resolved": "https://registry.npm.taobao.org/@firebase/remote-config/download/@firebase/remote-config-0.1.30.tgz", + "integrity": "sha1-LNa7vtUmqYsVThOizHPnSKd9fD0=", + "requires": { + "@firebase/component": "0.1.21", + "@firebase/installations": "0.4.19", + "@firebase/logger": "0.2.6", + "@firebase/remote-config-types": "0.1.9", + "@firebase/util": "0.3.4", + "tslib": "^1.11.1" + } + }, + "@firebase/remote-config-types": { + "version": "0.1.9", + "resolved": "https://registry.npm.taobao.org/@firebase/remote-config-types/download/@firebase/remote-config-types-0.1.9.tgz", + "integrity": "sha1-/mu+TQjztukvzjDkt6n01qltaWU=" + }, + "@firebase/storage": { + "version": "0.4.2", + "resolved": "https://registry.npm.taobao.org/@firebase/storage/download/@firebase/storage-0.4.2.tgz", + "integrity": "sha1-vFkkuHvS/dSrDeSYUcASXrwja4k=", + "requires": { + "@firebase/component": "0.1.21", + "@firebase/storage-types": "0.3.13", + "@firebase/util": "0.3.4", + "tslib": "^1.11.1" + } + }, + "@firebase/storage-types": { + "version": "0.3.13", + "resolved": "https://registry.npm.taobao.org/@firebase/storage-types/download/@firebase/storage-types-0.3.13.tgz", + "integrity": "sha1-zUPpOaKrV0LhCetjmjE2c6SLVFg=" + }, + "@firebase/util": { + "version": "0.3.4", + "resolved": "https://registry.npm.taobao.org/@firebase/util/download/@firebase/util-0.3.4.tgz", + "integrity": "sha1-44nQ4OKqyIpSNbBrqUMduZnUiSs=", + "requires": { + "tslib": "^1.11.1" + } + }, + "@firebase/webchannel-wrapper": { + "version": "0.4.1", + "resolved": "https://registry.npm.taobao.org/@firebase/webchannel-wrapper/download/@firebase/webchannel-wrapper-0.4.1.tgz", + "integrity": "sha1-YA8idf9Uc5rVrAEC8UZ7iWPNX3E=" + }, + "@grpc/grpc-js": { + "version": "1.2.2", + "resolved": "https://registry.npm.taobao.org/@grpc/grpc-js/download/@grpc/grpc-js-1.2.2.tgz", + "integrity": "sha1-7kp0F/4Vpoao42nDbsTIBnhEXGc=", + "requires": { + "@types/node": "^12.12.47", + "google-auth-library": "^6.1.1", + "semver": "^6.2.0" + }, + "dependencies": { + "@types/node": { + "version": "12.19.8", + "resolved": "https://registry.npm.taobao.org/@types/node/download/@types/node-12.19.8.tgz?cache=0&sync_timestamp=1606764776703&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-12.19.8.tgz", + "integrity": "sha1-79bRqQUlUZ/GCMnbFsinj3aTqXg=" + } + } + }, + "@grpc/proto-loader": { + "version": "0.5.5", + "resolved": "https://registry.npm.taobao.org/@grpc/proto-loader/download/@grpc/proto-loader-0.5.5.tgz", + "integrity": "sha1-ZyXnoYJ7346S4p+/Tp7wIDwJBqk=", + "requires": { + "lodash.camelcase": "^4.3.0", + "protobufjs": "^6.8.6" + } + }, "@hapi/address": { "version": "2.1.4", "resolved": "https://registry.npm.taobao.org/@hapi/address/download/@hapi/address-2.1.4.tgz?cache=0&sync_timestamp=1603524710662&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40hapi%2Faddress%2Fdownload%2F%40hapi%2Faddress-2.1.4.tgz", @@ -2614,6 +2896,60 @@ } } }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/@protobufjs/aspromise/download/@protobufjs/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/@protobufjs/base64/download/@protobufjs/base64-1.1.2.tgz", + "integrity": "sha1-TIVzDlm5ofHzSQR9vyQpYDS7JzU=" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npm.taobao.org/@protobufjs/codegen/download/@protobufjs/codegen-2.0.4.tgz", + "integrity": "sha1-fvN/DQEPsCitGtWXIuUG2SYoFcs=" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/@protobufjs/eventemitter/download/@protobufjs/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/@protobufjs/fetch/download/@protobufjs/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/@protobufjs/float/download/@protobufjs/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/@protobufjs/inquire/download/@protobufjs/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/@protobufjs/path/download/@protobufjs/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/@protobufjs/pool/download/@protobufjs/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/@protobufjs/utf8/download/@protobufjs/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, "@reach/router": { "version": "1.3.4", "resolved": "https://registry.npm.taobao.org/@reach/router/download/@reach/router-1.3.4.tgz", @@ -6295,6 +6631,11 @@ "resolved": "https://registry.npm.taobao.org/@types/json5/download/@types/json5-0.0.29.tgz?cache=0&sync_timestamp=1596840204942&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fjson5%2Fdownload%2F%40types%2Fjson5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npm.taobao.org/@types/long/download/@types/long-4.0.1.tgz", + "integrity": "sha1-RZxl+hhn2v5qjzIsTFFpVmPMVek=" + }, "@types/markdown-to-jsx": { "version": "6.11.3", "resolved": "https://registry.npm.taobao.org/@types/markdown-to-jsx/download/@types/markdown-to-jsx-6.11.3.tgz", @@ -7194,6 +7535,14 @@ "integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg=", "dev": true }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/abort-controller/download/abort-controller-3.0.0.tgz", + "integrity": "sha1-6vVNU7YrrkE46AnKIlyEOabvs5I=", + "requires": { + "event-target-shim": "^5.0.0" + } + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npm.taobao.org/accepts/download/accepts-1.3.7.tgz", @@ -7253,6 +7602,14 @@ } } }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npm.taobao.org/agent-base/download/agent-base-6.0.2.tgz?cache=0&sync_timestamp=1603480011934&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fagent-base%2Fdownload%2Fagent-base-6.0.2.tgz", + "integrity": "sha1-Sf/1hXfP7j83F2/qtMIuAPhtf3c=", + "requires": { + "debug": "4" + } + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npm.taobao.org/aggregate-error/download/aggregate-error-3.1.0.tgz", @@ -8636,6 +8993,11 @@ "resolved": "https://registry.npm.taobao.org/big.js/download/big.js-5.2.2.tgz", "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg=" }, + "bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npm.taobao.org/bignumber.js/download/bignumber.js-9.0.1.tgz", + "integrity": "sha1-jXuhJMiCv9jkMmDGdHVRjQaJ5OU=" + }, "binary-extensions": { "version": "2.1.0", "resolved": "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-2.1.0.tgz", @@ -8946,6 +9308,11 @@ "isarray": "^1.0.0" } }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/buffer-equal-constant-time/download/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npm.taobao.org/buffer-from/download/buffer-from-1.1.1.tgz", @@ -10554,6 +10921,11 @@ } } }, + "dom-storage": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/dom-storage/download/dom-storage-2.1.0.tgz", + "integrity": "sha1-APuGi8kgE1fqJDx7z9MwTB406jk=" + }, "dom-walk": { "version": "0.1.2", "resolved": "https://registry.npm.taobao.org/dom-walk/download/dom-walk-0.1.2.tgz", @@ -10704,6 +11076,14 @@ "safer-buffer": "^2.1.0" } }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npm.taobao.org/ecdsa-sig-formatter/download/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha1-rg8PothQRe8UqBfao86azQSJ5b8=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", @@ -11717,6 +12097,11 @@ "resolved": "https://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npm.taobao.org/event-target-shim/download/event-target-shim-5.0.1.tgz", + "integrity": "sha1-XU0+vflYPWOlMzzi3rdICrKwV4k=" + }, "eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npm.taobao.org/eventemitter3/download/eventemitter3-4.0.7.tgz?cache=0&sync_timestamp=1598517714257&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feventemitter3%2Fdownload%2Feventemitter3-4.0.7.tgz", @@ -12181,6 +12566,11 @@ "resolved": "https://registry.npm.taobao.org/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, + "fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npm.taobao.org/fast-text-encoding/download/fast-text-encoding-1.0.3.tgz", + "integrity": "sha1-7AKsjgGrijGa8YLa4mgSE8/pzlM=" + }, "fastq": { "version": "1.9.0", "resolved": "https://registry.npm.taobao.org/fastq/download/fastq-1.9.0.tgz?cache=0&sync_timestamp=1603877198135&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffastq%2Fdownload%2Ffastq-1.9.0.tgz", @@ -12402,6 +12792,27 @@ "locate-path": "^3.0.0" } }, + "firebase": { + "version": "8.1.1", + "resolved": "https://registry.npm.taobao.org/firebase/download/firebase-8.1.1.tgz", + "integrity": "sha1-N5CUtyQFOTH9oQhukCChe1eOUNU=", + "requires": { + "@firebase/analytics": "0.6.2", + "@firebase/app": "0.6.13", + "@firebase/app-types": "0.6.1", + "@firebase/auth": "0.15.2", + "@firebase/database": "0.8.1", + "@firebase/firestore": "2.0.4", + "@firebase/functions": "0.6.1", + "@firebase/installations": "0.4.19", + "@firebase/messaging": "0.7.3", + "@firebase/performance": "0.4.4", + "@firebase/polyfill": "0.3.36", + "@firebase/remote-config": "0.1.30", + "@firebase/storage": "0.4.2", + "@firebase/util": "0.3.4" + } + }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npm.taobao.org/flat-cache/download/flat-cache-2.0.1.tgz", @@ -12754,6 +13165,25 @@ } } }, + "gaxios": { + "version": "4.0.1", + "resolved": "https://registry.npm.taobao.org/gaxios/download/gaxios-4.0.1.tgz", + "integrity": "sha1-vHsgWonYg0UoIsx14ThiDDXjKR4=", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + }, + "dependencies": { + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/is-stream/download/is-stream-2.0.0.tgz", + "integrity": "sha1-venDJoDW+uBBKdasnZIc54FfeOM=" + } + } + }, "gaze": { "version": "1.1.3", "resolved": "https://registry.npm.taobao.org/gaze/download/gaze-1.1.3.tgz", @@ -12763,6 +13193,15 @@ "globule": "^1.0.0" } }, + "gcp-metadata": { + "version": "4.2.1", + "resolved": "https://registry.npm.taobao.org/gcp-metadata/download/gcp-metadata-4.2.1.tgz", + "integrity": "sha1-MYSfvPkCXvNMIpfDKomh5+nyzWI=", + "requires": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + } + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npm.taobao.org/gensync/download/gensync-1.0.0-beta.2.tgz?cache=0&sync_timestamp=1603830155677&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgensync%2Fdownload%2Fgensync-1.0.0-beta.2.tgz", @@ -13009,6 +13448,45 @@ "delegate": "^3.1.2" } }, + "google-auth-library": { + "version": "6.1.3", + "resolved": "https://registry.npm.taobao.org/google-auth-library/download/google-auth-library-6.1.3.tgz", + "integrity": "sha1-OdhoFAtw0MSzLG9tj0zMFADYTco=", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + }, + "dependencies": { + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/arrify/download/arrify-2.0.1.tgz", + "integrity": "sha1-yWVekzHgq81YjSp8rX6ZVvZnAfo=" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-6.0.0.tgz?cache=0&sync_timestamp=1594427567713&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-6.0.0.tgz", + "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "google-p12-pem": { + "version": "3.0.3", + "resolved": "https://registry.npm.taobao.org/google-p12-pem/download/google-p12-pem-3.0.3.tgz", + "integrity": "sha1-ZzrDp105A6h/BYePPHXgb8FRZp4=", + "requires": { + "node-forge": "^0.10.0" + } + }, "graceful-fs": { "version": "4.2.4", "resolved": "https://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.2.4.tgz", @@ -13020,6 +13498,17 @@ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "optional": true }, + "gtoken": { + "version": "5.1.0", + "resolved": "https://registry.npm.taobao.org/gtoken/download/gtoken-5.1.0.tgz", + "integrity": "sha1-S6jS/JqEWQmPdufo/Xvqo5/an+Q=", + "requires": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.0.3", + "jws": "^4.0.0", + "mime": "^2.2.0" + } + }, "gud": { "version": "1.0.0", "resolved": "https://registry.npm.taobao.org/gud/download/gud-1.0.0.tgz", @@ -13530,6 +14019,15 @@ "resolved": "https://registry.npm.taobao.org/https-browserify/download/https-browserify-1.0.0.tgz", "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npm.taobao.org/https-proxy-agent/download/https-proxy-agent-5.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttps-proxy-agent%2Fdownload%2Fhttps-proxy-agent-5.0.0.tgz", + "integrity": "sha1-4qkFQqu2inYuCghQ9sntrf2FBrI=", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, "human-signals": { "version": "1.1.1", "resolved": "https://registry.npm.taobao.org/human-signals/download/human-signals-1.1.1.tgz", @@ -13557,6 +14055,11 @@ "postcss": "^7.0.14" } }, + "idb": { + "version": "3.0.2", + "resolved": "https://registry.npm.taobao.org/idb/download/idb-3.0.2.tgz", + "integrity": "sha1-yOkSLV3dQPE7YK5mXkhi+LE/o4Q=" + }, "identity-obj-proxy": { "version": "3.0.0", "resolved": "https://registry.npm.taobao.org/identity-obj-proxy/download/identity-obj-proxy-3.0.0.tgz", @@ -17018,6 +17521,14 @@ "resolved": "https://registry.npm.taobao.org/jsesc/download/jsesc-2.5.2.tgz", "integrity": "sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q=" }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/json-bigint/download/json-bigint-1.0.0.tgz", + "integrity": "sha1-rlR4I6wMrYOYZn+M2e9HMPWwH/E=", + "requires": { + "bignumber.js": "^9.0.0" + } + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npm.taobao.org/json-parse-better-errors/download/json-parse-better-errors-1.0.2.tgz", @@ -17097,6 +17608,25 @@ "object.assign": "^4.1.1" } }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/jwa/download/jwa-2.0.0.tgz", + "integrity": "sha1-p+nD8p2ulAJ+vK9Jl1yTRVk0EPw=", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/jws/download/jws-4.0.0.tgz", + "integrity": "sha1-LU6M9qMY/6oSYV6d7H6G5slzEPQ=", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npm.taobao.org/killable/download/killable-1.0.1.tgz", @@ -17288,8 +17818,7 @@ "lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npm.taobao.org/lodash.camelcase/download/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", - "dev": true + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" }, "lodash.clonedeep": { "version": "4.5.0", @@ -17467,6 +17996,11 @@ "object.assign": "^4.1.0" } }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/long/download/long-4.0.0.tgz", + "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npm.taobao.org/loose-envify/download/loose-envify-1.4.0.tgz", @@ -18285,8 +18819,7 @@ "node-fetch": { "version": "2.6.1", "resolved": "https://registry.npm.taobao.org/node-fetch/download/node-fetch-2.6.1.tgz?cache=0&sync_timestamp=1599309206591&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnode-fetch%2Fdownload%2Fnode-fetch-2.6.1.tgz", - "integrity": "sha1-BFvTI2Mfdu0uK1VXM5RBa2OaAFI=", - "dev": true + "integrity": "sha1-BFvTI2Mfdu0uK1VXM5RBa2OaAFI=" }, "node-forge": { "version": "0.10.0", @@ -20339,6 +20872,11 @@ "resolved": "https://registry.npm.taobao.org/promise-inflight/download/promise-inflight-1.0.1.tgz", "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" }, + "promise-polyfill": { + "version": "8.1.3", + "resolved": "https://registry.npm.taobao.org/promise-polyfill/download/promise-polyfill-8.1.3.tgz", + "integrity": "sha1-jJmzz1PzqRxoIm/9573oHX+QQRY=" + }, "promise.allsettled": { "version": "1.0.2", "resolved": "https://registry.npm.taobao.org/promise.allsettled/download/promise.allsettled-1.0.2.tgz", @@ -20440,6 +20978,33 @@ "xtend": "^4.0.0" } }, + "protobufjs": { + "version": "6.10.2", + "resolved": "https://registry.npm.taobao.org/protobufjs/download/protobufjs-6.10.2.tgz", + "integrity": "sha1-uctr2OyPh1FFkro/39KOk/M6Rps=", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": "^13.7.0", + "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "13.13.34", + "resolved": "https://registry.npm.taobao.org/@types/node/download/@types/node-13.13.34.tgz?cache=0&sync_timestamp=1606764776703&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-13.13.34.tgz", + "integrity": "sha1-yTAKG2Vg2QgX+yu6ZQ4lARaldfk=" + } + } + }, "proxy-addr": { "version": "2.0.6", "resolved": "https://registry.npm.taobao.org/proxy-addr/download/proxy-addr-2.0.6.tgz", @@ -26054,6 +26619,11 @@ "resolved": "https://registry.npm.taobao.org/xmlchars/download/xmlchars-2.2.0.tgz", "integrity": "sha1-Bg/hvLf5x2/ioX24apvDq4lCEMs=" }, + "xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npm.taobao.org/xmlhttprequest/download/xmlhttprequest-1.8.0.tgz", + "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npm.taobao.org/xtend/download/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index fc7fe1a..43480f5 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "axios": "^0.21.0", "classnames": "^2.2.6", "date-fns": "^2.16.1", + "firebase": "^8.1.1", "history": "^5.0.0", "immer": "^7.0.14", "normalize.css": "^8.0.1", From 208ecf9ca85c51782eb82bee54ab983c97ddce08 Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Thu, 3 Dec 2020 23:13:27 +0800 Subject: [PATCH 02/41] feat: add firebase variables to .env Signed-off-by: Isabella Hu --- .env | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.env b/.env index 7d910f1..f36f53e 100644 --- a/.env +++ b/.env @@ -1 +1,9 @@ -SKIP_PREFLIGHT_CHECK=true \ No newline at end of file +SKIP_PREFLIGHT_CHECK=true +REACT_APP_API_KEY=AIzaSyAk9yEazTIYHCIMdhpnujjVPtr9GBN4HZs +REACT_APP_AUTH_DOMAIN=feed-f9aa9.firebaseapp.com +REACT_APP_DATABASE_URL=https://feed-f9aa9.firebaseio.com +REACT_APP_PROJECT_ID=feed-f9aa9 +REACT_APP_STORAGE_BUCKET=feed-f9aa9.appspot.com +REACT_APP_MESSAGING_SENDER_ID=987818686949 +REACT_APP_APP_ID=1:987818686949:web:730d44693bad5dc62a170c +REACT_APP_MEASUREMENT_ID=G-6NRTFZGBBX \ No newline at end of file From afe682467897e9f1f813b3ebd2664cf47126f8df Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Thu, 3 Dec 2020 23:14:25 +0800 Subject: [PATCH 03/41] feat: add Firebase module (FirebaseContext, Firebase, hook) Signed-off-by: Isabella Hu --- src/components/Firebase/context.ts | 4 ++++ src/components/Firebase/index.ts | 23 +++++++++++++++++++++++ src/components/Firebase/useFirebase.ts | 7 +++++++ 3 files changed, 34 insertions(+) create mode 100644 src/components/Firebase/context.ts create mode 100644 src/components/Firebase/index.ts create mode 100644 src/components/Firebase/useFirebase.ts diff --git a/src/components/Firebase/context.ts b/src/components/Firebase/context.ts new file mode 100644 index 0000000..0fbfc47 --- /dev/null +++ b/src/components/Firebase/context.ts @@ -0,0 +1,4 @@ +import { createContext } from "react"; +const FirebaseContext = createContext(null); + +export default FirebaseContext; diff --git a/src/components/Firebase/index.ts b/src/components/Firebase/index.ts new file mode 100644 index 0000000..2fa9968 --- /dev/null +++ b/src/components/Firebase/index.ts @@ -0,0 +1,23 @@ +import app from "firebase/app"; +import FirebaseContext from "./context"; + +//TODO: .env.production, .env.development +const config = { + apiKey: process.env.REACT_APP_API_KEY, + authDomain: process.env.REACT_APP_AUTH_DOMAIN, + databaseURL: process.env.REACT_APP_DATABASE_URL, + projectId: process.env.REACT_APP_PROJECT_ID, + storageBucket: process.env.REACT_APP_STORAGE_BUCKET, + messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, + appId: process.env.REACT_APP_APP_ID, + measurementId: process.env.REACT_APP_MEASUREMENT_ID, +}; + +class Firebase { + constructor() { + app.initializeApp(config); + } +} + +export default Firebase; +export { FirebaseContext }; diff --git a/src/components/Firebase/useFirebase.ts b/src/components/Firebase/useFirebase.ts new file mode 100644 index 0000000..5395c02 --- /dev/null +++ b/src/components/Firebase/useFirebase.ts @@ -0,0 +1,7 @@ +import { useContext } from "react"; +import FirebaseContext from "./context"; + +export default function useFirebase() { + const firebase = useContext(FirebaseContext); + return firebase; +} From de476ca27e8b70fbd7418b24e3c9b611c392302b Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Thu, 3 Dec 2020 23:15:52 +0800 Subject: [PATCH 04/41] feat: provide firebase instance to App Signed-off-by: Isabella Hu --- src/index.tsx | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 1d011eb..7bd9373 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -4,6 +4,7 @@ import { Provider } from "react-redux"; import { BrowserRouter } from "react-router-dom"; import { CookiesProvider } from "react-cookie"; import ThemeContext, { themes, Mode } from "./context/ThemeContext"; +import Firebase, { FirebaseContext } from "./components/Firebase"; import store from "./store/index"; @@ -20,15 +21,23 @@ if (process.env.NODE_ENV === "development") { const Entry = () => { const [mode, setMode] = useState("pink"); return ( - - - - - - - - - + + + + + + + + + + + ); }; From 07c3e5ddc14b44481c80f8c28c938fe9b0335d24 Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Thu, 3 Dec 2020 23:54:43 +0800 Subject: [PATCH 05/41] feat: add auth API to Firebase Signed-off-by: Isabella Hu --- src/components/Firebase/index.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/components/Firebase/index.ts b/src/components/Firebase/index.ts index 2fa9968..30af4f8 100644 --- a/src/components/Firebase/index.ts +++ b/src/components/Firebase/index.ts @@ -1,4 +1,5 @@ import app from "firebase/app"; +import "firebase/auth"; import FirebaseContext from "./context"; //TODO: .env.production, .env.development @@ -14,9 +15,24 @@ const config = { }; class Firebase { + auth: app.auth.Auth; constructor() { app.initializeApp(config); + this.auth = app.auth(); } + + /** + * Auth API + */ + doCreateUserWithEmailAndPassword = (email: string, password: string) => + this.auth.createUserWithEmailAndPassword(email, password); + doSignInWithEmailAndPassword = (email: string, password: string) => + this.auth.signInWithEmailAndPassword(email, password); + doSignOut = () => this.auth.signOut(); + doPasswordReset = (email: string) => + this.auth.sendPasswordResetEmail(email); + doPasswordUpdate = (newPassword: string) => + this.auth.currentUser?.updatePassword(newPassword); } export default Firebase; From 366a05cb8f9bbb32467cd63576845dd607176004 Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Fri, 4 Dec 2020 01:19:55 +0800 Subject: [PATCH 06/41] feat: add routes to Navbar Signed-off-by: Isabella Hu --- src/NavBar.tsx | 37 +++++++++++++++++++++++++++++-------- src/constants/routes.ts | 8 ++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 src/constants/routes.ts diff --git a/src/NavBar.tsx b/src/NavBar.tsx index 863ed66..20349ed 100644 --- a/src/NavBar.tsx +++ b/src/NavBar.tsx @@ -1,15 +1,36 @@ import React from "react"; import { Link } from "react-router-dom"; +import { + LANDING, + NOTIFICATIONS, + SIGN_IN, + HOME, + ACCOUNT, + ADMIN, +} from "./constants/routes"; + const NavBar = () => ( - + ); export default NavBar; diff --git a/src/constants/routes.ts b/src/constants/routes.ts new file mode 100644 index 0000000..cf9a883 --- /dev/null +++ b/src/constants/routes.ts @@ -0,0 +1,8 @@ +export const LANDING = "/"; +export const SIGN_UP = "/signup"; +export const SIGN_IN = "/signin"; +export const HOME = "/home"; +export const ACCOUNT = "/account"; +export const ADMIN = "/admin"; +export const PASSWORD_FORGET = "/pw-forget"; +export const NOTIFICATIONS = "/notifications"; From 6dace2b300953ad6c6d83775ebecb10c95274ed0 Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Fri, 4 Dec 2020 01:20:46 +0800 Subject: [PATCH 07/41] feat: export useFirebase Signed-off-by: Isabella Hu --- src/components/Firebase/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Firebase/index.ts b/src/components/Firebase/index.ts index 30af4f8..e79b7b1 100644 --- a/src/components/Firebase/index.ts +++ b/src/components/Firebase/index.ts @@ -1,6 +1,7 @@ import app from "firebase/app"; import "firebase/auth"; import FirebaseContext from "./context"; +import useFirebase from "./useFirebase"; //TODO: .env.production, .env.development const config = { @@ -36,4 +37,4 @@ class Firebase { } export default Firebase; -export { FirebaseContext }; +export { FirebaseContext, useFirebase }; From f9560c79b6c735195dd2cdbe6cda3e77c689fd34 Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Fri, 4 Dec 2020 01:21:35 +0800 Subject: [PATCH 08/41] feat: add SignUp component (Page, Form, Link) Signed-off-by: Isabella Hu --- src/components/SignUp/index.tsx | 127 ++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 src/components/SignUp/index.tsx diff --git a/src/components/SignUp/index.tsx b/src/components/SignUp/index.tsx new file mode 100644 index 0000000..322d0a7 --- /dev/null +++ b/src/components/SignUp/index.tsx @@ -0,0 +1,127 @@ +import React, { useReducer } from "react"; +import { Link, useHistory } from "react-router-dom"; +import Firebase, { useFirebase } from "../Firebase/index"; +import Input from "../input/Input"; +import * as ROUTES from "../../constants/routes"; + +const initialState = { + username: "", + email: "", + passwordOne: "", + passwordTwo: "", + error: "", +}; +type ActionType = + | { type: "TYPE_USERNAME"; payload: string } + | { type: "TYPE_EMAIL"; payload: string } + | { type: "TYPE_PASSWORDONE"; payload: string } + | { type: "TYPE_PASSWORDTWO"; payload: string } + | { type: "ERROR_SIGNUP"; payload: string } + | { type: "RESET_INITIAL"; payload: typeof initialState }; + +type Types = + | "TYPE_USERNAME" + | "TYPE_EMAIL" + | "TYPE_PASSWORDONE" + | "TYPE_PASSWORDTWO" + | "ERROR_SIGNUP"; + +const reducer = (state: typeof initialState, action: ActionType) => { + switch (action.type) { + case "TYPE_USERNAME": + return { ...state, username: action.payload }; + case "TYPE_EMAIL": + return { ...state, email: action.payload }; + case "TYPE_PASSWORDONE": + return { ...state, passwordOne: action.payload }; + case "TYPE_PASSWORDTWO": + return { ...state, passwordTwo: action.payload }; + case "ERROR_SIGNUP": + return { ...state, error: action.payload }; + case "RESET_INITIAL": + return { ...action.payload }; + } +}; + +const SignUpForm = () => { + const [state, dispatch] = useReducer(reducer, initialState); + const firebase = useFirebase() as Firebase; + const history = useHistory(); + + const { email, passwordOne, passwordTwo, username, error } = state; + const onInputChanged = (e: React.SyntheticEvent) => { + const { name, value } = e.target as typeof e.target & { + name: string; + value: string; + }; + const type = `TYPE_${name.toUpperCase()}` as Types; + dispatch({ type, payload: value }); + }; + + const canSubmit = + Boolean(email) && + Boolean(passwordOne) && + Boolean(username) && + passwordOne === passwordTwo; + + const onSubmit = async (e: React.SyntheticEvent) => { + e.preventDefault(); + try { + await firebase.doCreateUserWithEmailAndPassword(email, passwordOne); + dispatch({ type: "RESET_INITIAL", payload: initialState }); + history.push(ROUTES.HOME); + } catch (error) { + dispatch({ type: "ERROR_SIGNUP", payload: error.message }); + } + }; + return ( +
+ + + + +

{Boolean(error) ? error : ""}

+ +
+ ); +}; + +const SignUpPage = () => ( +
+

SignUp

+ +
+); + +const SignUpLink = () => ( +

+ Don't have an account? Sign Up +

+); + +export { SignUpForm, SignUpLink }; +export default SignUpPage; From 77c711c1767690f8455fcaad37c4e277d0fda5d1 Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Fri, 4 Dec 2020 05:30:37 +0800 Subject: [PATCH 09/41] packages: add ts-jest Signed-off-by: Isabella Hu --- package-lock.json | 66 ++++++++++++++ package.json | 214 +++++++++++++++++++++++----------------------- 2 files changed, 174 insertions(+), 106 deletions(-) diff --git a/package-lock.json b/package-lock.json index fc73cbc..670bdce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9290,6 +9290,15 @@ "node-releases": "^1.1.61" } }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npm.taobao.org/bs-logger/download/bs-logger-0.2.6.tgz", + "integrity": "sha1-6302UwenLPl0zGzadraDVK0za9g=", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, "bser": { "version": "2.1.1", "resolved": "https://registry.npm.taobao.org/bser/download/bser-2.1.1.tgz", @@ -18086,6 +18095,12 @@ } } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npm.taobao.org/make-error/download/make-error-1.3.6.tgz", + "integrity": "sha1-LrLjfqm2fEiR9oShOUeZr0hM96I=", + "dev": true + }, "makeerror": { "version": "1.0.11", "resolved": "https://registry.npm.taobao.org/makeerror/download/makeerror-1.0.11.tgz", @@ -24988,6 +25003,57 @@ "integrity": "sha1-yTA/PXT3X6dSjD1JuA4ImrCdh0U=", "dev": true }, + "ts-jest": { + "version": "26.4.4", + "resolved": "https://registry.npm.taobao.org/ts-jest/download/ts-jest-26.4.4.tgz?cache=0&sync_timestamp=1606405640935&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fts-jest%2Fdownload%2Fts-jest-26.4.4.tgz", + "integrity": "sha1-YfE/shq0AIU8UyJw5SzA7X5QLEk=", + "dev": true, + "requires": { + "@types/jest": "26.x", + "bs-logger": "0.x", + "buffer-from": "1.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^26.1.0", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "1.x", + "mkdirp": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-6.0.0.tgz?cache=0&sync_timestamp=1594427567713&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-6.0.0.tgz", + "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npm.taobao.org/mkdirp/download/mkdirp-1.0.4.tgz?cache=0&sync_timestamp=1593529694459&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmkdirp%2Fdownload%2Fmkdirp-1.0.4.tgz", + "integrity": "sha1-PrXtYmInVteaXw4qIh3+utdcL34=", + "dev": true + }, + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npm.taobao.org/semver/download/semver-7.3.4.tgz?cache=0&sync_timestamp=1606854810932&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.4.tgz", + "integrity": "sha1-J6qn0uTKdkUvmNOt0JOnLJQ+3Jc=", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-20.2.4.tgz?cache=0&sync_timestamp=1604886694625&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs-parser%2Fdownload%2Fyargs-parser-20.2.4.tgz", + "integrity": "sha1-tCiQ8UVmeW+Fro46JSkNIF8VSlQ=", + "dev": true + } + } + }, "ts-pnp": { "version": "1.1.6", "resolved": "https://registry.npm.taobao.org/ts-pnp/download/ts-pnp-1.1.6.tgz", diff --git a/package.json b/package.json index 43480f5..cf34635 100644 --- a/package.json +++ b/package.json @@ -1,109 +1,111 @@ { - "name": "demo", - "version": "0.1.0", - "private": true, - "dependencies": { - "@reduxjs/toolkit": "^1.4.0", - "@testing-library/dom": "^7.26.3", - "@testing-library/jest-dom": "^4.2.4", - "@testing-library/react": "^9.3.2", - "@testing-library/user-event": "^7.1.2", - "@types/jest": "^26.0.15", - "@types/ramda": "^0.27.31", - "@types/react-redux": "^7.1.11", - "@types/react-router-dom": "^5.1.6", - "@types/styled-components": "^5.1.4", - "axios": "^0.21.0", - "classnames": "^2.2.6", - "date-fns": "^2.16.1", - "firebase": "^8.1.1", - "history": "^5.0.0", - "immer": "^7.0.14", - "normalize.css": "^8.0.1", - "prop-types": "^15.7.2", - "ramda": "^0.27.1", - "react": "^16.14.0", - "react-cookie": "^4.0.3", - "react-dom": "^16.14.0", - "react-icons": "^3.11.0", - "react-redux": "^7.2.2", - "react-router-dom": "^5.2.0", - "react-scripts": "^4.0.0-next.117", - "styled-components": "^5.2.1", - "typescript": "^4.0.5", - "use-immer": "^0.4.1", - "validator": "^13.1.17" - }, - "scripts": { - "start": "react-scripts start", - "lint": "eslint --ext .js,.jsx,.ts,.tsx src/ --fix ", - "test": "react-scripts test", - "eject": "react-scripts eject", - "build": "react-scripts build", - "postinstall": "husky install", - "test:nowatch": "react-scripts test --watchAll=false ", - "storybook": "start-storybook -p 6006 -s public --no-dll", - "build-storybook": "build-storybook -s public --no-dll" - }, - "husky": { - "hooks": { - "pre-commit": "npm run lint", - "pre-push": "npm run lint && npm run test:nowatch" + "name": "demo", + "version": "0.1.0", + "private": true, + "dependencies": { + "@reduxjs/toolkit": "^1.4.0", + "@testing-library/dom": "^7.26.3", + "@testing-library/jest-dom": "^4.2.4", + "@testing-library/react": "^9.3.2", + "@testing-library/user-event": "^7.1.2", + "@types/jest": "^26.0.15", + "@types/ramda": "^0.27.31", + "@types/react-redux": "^7.1.11", + "@types/react-router-dom": "^5.1.6", + "@types/styled-components": "^5.1.4", + "axios": "^0.21.0", + "classnames": "^2.2.6", + "date-fns": "^2.16.1", + "firebase": "^8.1.1", + "history": "^5.0.0", + "immer": "^7.0.14", + "normalize.css": "^8.0.1", + "prop-types": "^15.7.2", + "ramda": "^0.27.1", + "react": "^16.14.0", + "react-cookie": "^4.0.3", + "react-dom": "^16.14.0", + "react-icons": "^3.11.0", + "react-redux": "^7.2.2", + "react-router-dom": "^5.2.0", + "react-scripts": "^4.0.0-next.117", + "styled-components": "^5.2.1", + "typescript": "^4.0.5", + "use-immer": "^0.4.1", + "validator": "^13.1.17" + }, + "scripts": { + "start": "react-scripts start", + "lint": "eslint --ext .js,.jsx,.ts,.tsx src/ --fix ", + "test": "react-scripts test", + "eject": "react-scripts eject", + "build": "react-scripts build", + "postinstall": "husky install", + "test:nowatch": "react-scripts test --watchAll=false ", + "storybook": "start-storybook -p 6006 -s public --no-dll", + "build-storybook": "build-storybook -s public --no-dll" + }, + "husky": { + "hooks": { + "pre-commit": "npm run lint", + "pre-push": "npm run lint && npm run test:nowatch" + } + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "devDependencies": { + "@babel/core": "^7.12.3", + "@storybook/addon-actions": "^6.0.28", + "@storybook/addon-essentials": "^6.0.28", + "@storybook/addon-links": "^6.0.28", + "@storybook/node-logger": "^6.0.28", + "@storybook/preset-create-react-app": "^3.1.5", + "@storybook/react": "^6.0.28", + "@testing-library/react-hooks": "^3.4.2", + "@typescript-eslint/eslint-plugin": "^4.8.1", + "@typescript-eslint/parser": "^4.8.1", + "babel-eslint": "^10.1.0", + "babel-loader": "^8.1.0", + "eslint": "^7.12.0", + "eslint-config-react-app": "^6.0.0", + "eslint-plugin-flowtype": "^5.2.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-jest": "^24.1.3", + "eslint-plugin-jsx-a11y": "^6.4.1", + "eslint-plugin-react": "^7.21.5", + "eslint-plugin-react-hooks": "^4.2.0", + "eslint-plugin-testing-library": "^3.10.0", + "husky": "^5.0.0-beta.0", + "jest-styled-components": "^7.0.3", + "miragejs": "^0.1.41", + "node-sass": "^4.14.1", + "prettier": "^2.1.2", + "react-is": "^17.0.1", + "react-test-renderer": "^17.0.1", + "ts-jest": "^26.4.4" + }, + "jest": { + "collectCoverageFrom": [ + "**/api/*.{js,jsx,tsx,ts}", + "**/features/**/*.{js,jsx,tsx,ts}", + "**/components/**/*.{js,jsx,tsx,ts}", + "**/{NavBar,Routes}.*{js,jsx,tsx,ts}", + "!**/node_modules/**", + "!**/stories/**", + "!**/*.stories.jsx" + ] } - }, - "eslintConfig": { - "extends": "react-app" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - }, - "devDependencies": { - "@babel/core": "^7.12.3", - "@storybook/addon-actions": "^6.0.28", - "@storybook/addon-essentials": "^6.0.28", - "@storybook/addon-links": "^6.0.28", - "@storybook/node-logger": "^6.0.28", - "@storybook/preset-create-react-app": "^3.1.5", - "@storybook/react": "^6.0.28", - "@testing-library/react-hooks": "^3.4.2", - "@typescript-eslint/eslint-plugin": "^4.8.1", - "@typescript-eslint/parser": "^4.8.1", - "babel-eslint": "^10.1.0", - "babel-loader": "^8.1.0", - "eslint": "^7.12.0", - "eslint-config-react-app": "^6.0.0", - "eslint-plugin-flowtype": "^5.2.0", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jest": "^24.1.3", - "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-react": "^7.21.5", - "eslint-plugin-react-hooks": "^4.2.0", - "eslint-plugin-testing-library": "^3.10.0", - "husky": "^5.0.0-beta.0", - "jest-styled-components": "^7.0.3", - "miragejs": "^0.1.41", - "node-sass": "^4.14.1", - "prettier": "^2.1.2", - "react-is": "^17.0.1", - "react-test-renderer": "^17.0.1" - }, - "jest": { - "collectCoverageFrom": [ - "**/api/*.{js,jsx,tsx,ts}", - "**/features/**/*.{js,jsx,tsx,ts}", - "**/{NavBar,Routes}.*{js,jsx,tsx,ts}", - "!**/node_modules/**", - "!**/stories/**", - "!**/*.stories.jsx" - ] - } } From d4f182f86d3d3e52ea0161ca2e02a712477186c5 Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Fri, 4 Dec 2020 05:31:14 +0800 Subject: [PATCH 10/41] config: update jest.config.js Signed-off-by: Isabella Hu --- src/components/jest.config.js | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/components/jest.config.js diff --git a/src/components/jest.config.js b/src/components/jest.config.js new file mode 100644 index 0000000..91a2d2c --- /dev/null +++ b/src/components/jest.config.js @@ -0,0 +1,4 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', +}; \ No newline at end of file From 84974def84f64b6e607e003cbe805cb77f72cff3 Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Fri, 4 Dec 2020 05:31:58 +0800 Subject: [PATCH 11/41] test: add test for SignUp (Page, Form, Link) Signed-off-by: Isabella Hu --- src/components/SignUp/SignUp.test.tsx | 112 ++++++++++++++++++ .../SignUp/__snapshots__/SignUp.test.tsx.snap | 43 +++++++ src/components/SignUp/index.tsx | 9 +- 3 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 src/components/SignUp/SignUp.test.tsx create mode 100644 src/components/SignUp/__snapshots__/SignUp.test.tsx.snap diff --git a/src/components/SignUp/SignUp.test.tsx b/src/components/SignUp/SignUp.test.tsx new file mode 100644 index 0000000..ed392fc --- /dev/null +++ b/src/components/SignUp/SignUp.test.tsx @@ -0,0 +1,112 @@ +import React from "react"; +import { mocked } from "ts-jest/utils"; +import { BrowserRouter } from "react-router-dom"; +import SignUpPage, { SignUpForm, SignUpLink } from "./index"; +import Firebase, { FirebaseContext, useFirebase } from "../Firebase/index"; +import * as ROUTES from "../../constants/routes"; +import user from "@testing-library/user-event"; +import { render } from "@testing-library/react"; + +jest.mock("../Firebase/index"); + +describe("SignUpForm test", () => { + beforeEach(() => { + mocked(Firebase).mockClear(); + }); + it("signup successfully and redirect to home page after filling in username, email, password", async () => { + mocked(useFirebase).mockReturnValue({ + doCreateUserWithEmailAndPassword: jest.fn(), + }); + const ui = ( + + + + + + ); + const { getByTestId, findByTestId } = render(ui); + + user.type(getByTestId("username"), "eunice"); + user.type(getByTestId("email"), "eunice@gamil.com"); + user.type(getByTestId("passwordOne"), "password**"); + user.type(getByTestId("passwordTwo"), "password**"); + user.click(getByTestId("submit")); + + expect(await findByTestId("email")).toHaveValue(""); + expect(window.location.pathname).toBe(ROUTES.HOME); + }); + + it("cannot submit when any of field is blank or passwordOne is not identical to passwordTwo", () => { + const ui = ( + + + + + + ); + const { getByTestId } = render(ui); + const submitBtn = getByTestId("submit") as HTMLButtonElement; + + user.type(getByTestId("username"), "eunice"); + expect(submitBtn.disabled).toBeTruthy(); + + user.type(getByTestId("email"), "eunice@gamil.com"); + user.type(getByTestId("passwordOne"), "password**"); + user.type(getByTestId("passwordTwo"), "password**LLL"); + user.click(submitBtn); + + expect(submitBtn.disabled).toBeTruthy(); + user.type(getByTestId("passwordTwo"), "password**"); + expect(submitBtn.disabled).toBeFalsy(); + }); + it("show error message when Firebase signup authentication failed", async () => { + const mockDoCreateUserWithEmailAndPassword = jest + .fn() + .mockRejectedValueOnce({ message: "failed to create user" }); + mocked(useFirebase).mockImplementation(() => ({ + doCreateUserWithEmailAndPassword: mockDoCreateUserWithEmailAndPassword, + })); + + const ui = ( + + + + + + ); + const { getByTestId, findByText } = render(ui); + + user.type(getByTestId("username"), "eunice"); + user.type(getByTestId("email"), "eunice@gamil.com"); + user.type(getByTestId("passwordOne"), "password**"); + user.type(getByTestId("passwordTwo"), "password**"); + user.click(getByTestId("submit")); + + expect(Firebase).toHaveBeenCalledTimes(1); + expect(mockDoCreateUserWithEmailAndPassword).toHaveBeenLastCalledWith( + "eunice@gamil.com", + "password**" + ); + expect(await findByText(/failed to create user/i)).toBeInTheDocument(); + }); +}); + +describe("SignUpLink test", () => { + it("click to change url to /signup", () => { + const ui = ( + + + + ); + const { getByText } = render(ui); + user.click(getByText(/Sign Up/i)); + expect(window.location.pathname).toBe(ROUTES.SIGN_UP); + }); +}); + +describe("SignUpPage test", () => { + it("render correctly", () => { + const { asFragment } = render(); + expect(asFragment()).toMatchSnapshot(); + }); +}); diff --git a/src/components/SignUp/__snapshots__/SignUp.test.tsx.snap b/src/components/SignUp/__snapshots__/SignUp.test.tsx.snap new file mode 100644 index 0000000..95e929c --- /dev/null +++ b/src/components/SignUp/__snapshots__/SignUp.test.tsx.snap @@ -0,0 +1,43 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SignUpPage test render correctly 1`] = ` + +
+

+ SignUp +

+
+ + + + +

+

+
+`; diff --git a/src/components/SignUp/index.tsx b/src/components/SignUp/index.tsx index 322d0a7..ce00ed0 100644 --- a/src/components/SignUp/index.tsx +++ b/src/components/SignUp/index.tsx @@ -78,24 +78,28 @@ const SignUpForm = () => {
{

{Boolean(error) ? error : ""}

); From dae52ac96908c36bc5a7fca294a8bff62958241c Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Fri, 4 Dec 2020 23:54:08 +0800 Subject: [PATCH 12/41] feat: add style for SignUpPage Signed-off-by: Isabella Hu --- src/components/SignUp/index.tsx | 42 ++++++++++++++++++++++++++++----- src/index.scss | 3 +++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/components/SignUp/index.tsx b/src/components/SignUp/index.tsx index ce00ed0..78db6cc 100644 --- a/src/components/SignUp/index.tsx +++ b/src/components/SignUp/index.tsx @@ -1,9 +1,33 @@ import React, { useReducer } from "react"; import { Link, useHistory } from "react-router-dom"; +import styled from "styled-components"; import Firebase, { useFirebase } from "../Firebase/index"; import Input from "../input/Input"; import * as ROUTES from "../../constants/routes"; +const StyledForm = styled.form` + display: flex; + flex-direction: column; + * { + margin: var(--margin) 0; + border-radius: var(--borderRadius); + } +`; + +const StyledSignUpPage = styled.div` + text-align: center; + width: 30%; + min-width: 300px; + margin: auto; +`; + +const StyledSubmitButton = styled.button` + width: 50%; + min-width: 150px; + margin: auto; + padding: 10px; +`; + const initialState = { username: "", email: "", @@ -75,13 +99,14 @@ const SignUpForm = () => { } }; return ( -
+ { name="email" value={email} onChange={onInputChanged} + placeholder="email" > { name="passwordOne" value={passwordOne} onChange={onInputChanged} + placeholder="password" > { name="passwordTwo" value={passwordTwo} onChange={onInputChanged} + placeholder="comfirm password" >

{Boolean(error) ? error : ""}

- - + > + Sign Up + +
); }; const SignUpPage = () => ( -
+

SignUp

-
+ ); const SignUpLink = () => ( diff --git a/src/index.scss b/src/index.scss index 8ab2574..efe6711 100644 --- a/src/index.scss +++ b/src/index.scss @@ -3,6 +3,8 @@ html { --gutter: 8px; --font-size: 8px; --spacing: 16px; + --margin: 10px; + --borderRadius: 4px; font-family: "Montserrat", sans-serif; color: var(--color-text-primary); @@ -19,6 +21,7 @@ html { --gutter: 16px; --font-size: 16px; --spacing: 32px; + --margin: 10px; } } body { From 67c1f53c6e60ac35839a49f2ac9ed7fad1d3dc39 Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Fri, 4 Dec 2020 23:54:59 +0800 Subject: [PATCH 13/41] fix: singleton instance for Firebase Signed-off-by: Isabella Hu --- src/index.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 7bd9373..1b587ec 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useMemo } from "react"; import ReactDOM from "react-dom"; import { Provider } from "react-redux"; import { BrowserRouter } from "react-router-dom"; @@ -20,8 +20,9 @@ if (process.env.NODE_ENV === "development") { const Entry = () => { const [mode, setMode] = useState("pink"); + const fireBase = useMemo(() => new Firebase(), []); return ( - + Date: Fri, 4 Dec 2020 23:55:39 +0800 Subject: [PATCH 14/41] feat: add SignUp route Signed-off-by: Isabella Hu --- src/Routes.tsx | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/Routes.tsx b/src/Routes.tsx index cb11d95..570e2f5 100644 --- a/src/Routes.tsx +++ b/src/Routes.tsx @@ -5,24 +5,30 @@ import PostsList from "./features/posts/PostsList"; import EditPostForm from "./features/posts/EditPostForm"; import NotificationsList from "./features/notifications/NotificationsList"; +import * as ROUTES from "./constants/routes"; +import SignUpPage from "./components/SignUp"; + const NoMatch = () => <>No match; const Routes = () => ( - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + ); export default Routes; From b05dd811fcd53557f3581c6cd435e01b13fe9742 Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Sat, 19 Dec 2020 23:20:28 +0800 Subject: [PATCH 15/41] feat: add SignIn (page, form) & test Signed-off-by: Isabella Hu --- src/Routes.tsx | 4 ++ src/components/SignIn/SignIn.test.tsx | 70 ++++++++++++++++++++++++ src/components/SignIn/index.tsx | 77 +++++++++++++++++++++++++++ src/components/SignUp/index.tsx | 10 ++-- 4 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 src/components/SignIn/SignIn.test.tsx create mode 100644 src/components/SignIn/index.tsx diff --git a/src/Routes.tsx b/src/Routes.tsx index 570e2f5..9ec971d 100644 --- a/src/Routes.tsx +++ b/src/Routes.tsx @@ -7,6 +7,7 @@ import NotificationsList from "./features/notifications/NotificationsList"; import * as ROUTES from "./constants/routes"; import SignUpPage from "./components/SignUp"; +import SignInPage from "./components/SignIn"; const NoMatch = () => <>No match; const Routes = () => ( @@ -17,6 +18,9 @@ const Routes = () => ( + + + diff --git a/src/components/SignIn/SignIn.test.tsx b/src/components/SignIn/SignIn.test.tsx new file mode 100644 index 0000000..21188ce --- /dev/null +++ b/src/components/SignIn/SignIn.test.tsx @@ -0,0 +1,70 @@ +import React from "react"; +import { BrowserRouter } from "react-router-dom"; +import { render } from "@testing-library/react"; +import user from "@testing-library/user-event"; +import SignInPage from "./index"; +import Firebase, { FirebaseContext } from "../Firebase"; + +describe("SignIn page", () => { + let firebase = new Firebase(); + let doSignInWithEmailAndPasswordMock: jest.SpyInstance = jest.spyOn( + firebase, + "doSignInWithEmailAndPassword" + ); + + beforeEach(() => { + doSignInWithEmailAndPasswordMock.mockClear(); + }); + it("form submit success", async () => { + doSignInWithEmailAndPasswordMock.mockResolvedValue({ + name: "isabella", + }); + const ui = ( + + + + + + ); + const { getByTestId, findByTestId } = render(ui); + const EmailInput = getByTestId("email"); + const PasswordInput = getByTestId("password"); + const SubmitButton = getByTestId("submit"); + + user.type(EmailInput, "eunicejhu@gmail.com"); + user.type(PasswordInput, "*****"); + user.click(SubmitButton); + expect(doSignInWithEmailAndPasswordMock).toHaveBeenCalledWith( + "eunicejhu@gmail.com", + "*****" + ); + expect(await findByTestId("email")).toHaveValue(""); + expect(await findByTestId("password")).toHaveValue(""); + expect(window.location.pathname).toBe("/account"); + }); + it("form submit failure", async () => { + doSignInWithEmailAndPasswordMock.mockRejectedValue( + new Error("Failed to signin") + ); + const ui = ( + + + + + + ); + const { getByTestId, findByText } = render(ui); + const EmailInput = getByTestId("email"); + const PasswordInput = getByTestId("password"); + const SubmitButton = getByTestId("submit"); + + user.type(EmailInput, "eunicejhu@gmail.com"); + user.type(PasswordInput, "*****"); + user.click(SubmitButton); + expect(doSignInWithEmailAndPasswordMock).toHaveBeenCalledWith( + "eunicejhu@gmail.com", + "*****" + ); + expect(await findByText(/Failed to sign in/g)).toBeInTheDocument(); + }); +}); diff --git a/src/components/SignIn/index.tsx b/src/components/SignIn/index.tsx new file mode 100644 index 0000000..a600e03 --- /dev/null +++ b/src/components/SignIn/index.tsx @@ -0,0 +1,77 @@ +import React, { useState } from "react"; +import Input from "../input/Input"; +import Firebase, { useFirebase } from "../Firebase"; +import { useHistory } from "react-router-dom"; +import * as ROUTES from "../../constants/routes"; +import { StyledForm, StyledPage, StyledSubmitButton } from "../SignUp"; +const SignInForm = () => { + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [error, setError] = useState(""); + + const firebase = useFirebase() as Firebase; + const history = useHistory(); + + const onChangeInput = (e: React.SyntheticEvent) => { + const { name, value } = e.target as typeof e.target & { + name: string; + value: string; + }; + if (name === "email") { + setEmail(value); + } else { + setPassword(value); + } + }; + const onSubmit = async (e: React.SyntheticEvent) => { + e.preventDefault(); + try { + await firebase.doSignInWithEmailAndPassword(email, password); + setEmail(""); + setPassword(""); + history.push(ROUTES.ACCOUNT); + } catch (error) { + setError("Failed to sign in"); + } + }; + + const canSubmit = Boolean(email) && Boolean(password); + return ( + + + +

{error}

+ + Sign in + +
+ ); +}; + +const SignInPage = () => ( + +

Sign In

+ +
+); + +export default SignInPage; diff --git a/src/components/SignUp/index.tsx b/src/components/SignUp/index.tsx index 78db6cc..23aa100 100644 --- a/src/components/SignUp/index.tsx +++ b/src/components/SignUp/index.tsx @@ -5,7 +5,7 @@ import Firebase, { useFirebase } from "../Firebase/index"; import Input from "../input/Input"; import * as ROUTES from "../../constants/routes"; -const StyledForm = styled.form` +export const StyledForm = styled.form` display: flex; flex-direction: column; * { @@ -14,14 +14,14 @@ const StyledForm = styled.form` } `; -const StyledSignUpPage = styled.div` +export const StyledPage = styled.div` text-align: center; width: 30%; min-width: 300px; margin: auto; `; -const StyledSubmitButton = styled.button` +export const StyledSubmitButton = styled.button` width: 50%; min-width: 150px; margin: auto; @@ -146,10 +146,10 @@ const SignUpForm = () => { }; const SignUpPage = () => ( - +

SignUp

-
+ ); const SignUpLink = () => ( From cdef0e24ddb79380ee5c72b87e9796f52a9b4c70 Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Sun, 20 Dec 2020 04:51:47 +0800 Subject: [PATCH 16/41] feat: add SignoutButton & test Signed-off-by: Isabella Hu --- src/components/SignOut/SignOut.test.tsx | 22 ++++++++++ src/components/SignOut/index.tsx | 53 +++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 src/components/SignOut/SignOut.test.tsx create mode 100644 src/components/SignOut/index.tsx diff --git a/src/components/SignOut/SignOut.test.tsx b/src/components/SignOut/SignOut.test.tsx new file mode 100644 index 0000000..4f705d8 --- /dev/null +++ b/src/components/SignOut/SignOut.test.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import { BrowserRouter } from "react-router-dom"; +import { render } from "@testing-library/react"; +import user from "@testing-library/user-event"; +import SignOutButton from "./index"; +import Firebase, { FirebaseContext } from "../Firebase"; + +const firebase = new Firebase(); +const doSignOutMock = jest.spyOn(firebase, "doSignOut"); +it("SignOutButton", () => { + const ui = ( + + + + + + ); + const { getByTestId } = render(ui); + user.click(getByTestId("signout")); + expect(doSignOutMock).toHaveBeenCalledTimes(1); + expect(window.location.pathname).toBe("/"); +}); diff --git a/src/components/SignOut/index.tsx b/src/components/SignOut/index.tsx new file mode 100644 index 0000000..dfe8a5f --- /dev/null +++ b/src/components/SignOut/index.tsx @@ -0,0 +1,53 @@ +import React from "react"; +import Firebase, { useFirebase } from "../Firebase"; +import { useHistory } from "react-router-dom"; +import * as ROUTES from "../../constants/routes"; +import useTheme from "../../hooks/useTheme"; +import { Themes, Mode } from "../../context/ThemeContext"; + +import styled from "styled-components"; + +interface StyledButtonProps { + themes: Themes; + mode: Mode; +} +const StyledButton = styled.button` + ${({ themes, mode }) => { + return ` --btn-text-hover: ${themes[mode].btnTextHover}; + --btn-bg-hover: ${themes[mode].btnBackgroundHover}; + --color-bg: ${themes[mode].background} ; + --color-text:${themes[mode].text};`; + }} + text-decoration: none; + color: var(--color-text); + background-color: transparent; + border: none; + + &:hover { + color: var(--btn-text-hover); + cursor: pointer; + background-color: var(--btn-bg-hover); + } +`; +const SignOutButton = () => { + const firebase = useFirebase() as Firebase; + const history = useHistory(); + const { themes, mode } = useTheme(); + const onSignOut = (e: React.SyntheticEvent) => { + firebase.doSignOut(); + history.push(ROUTES.LANDING); + }; + return ( + + Sign Out + + ); +}; + +export default SignOutButton; From 0329f6d57e81f2ec846fe17a0483e4a7e75fa596 Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Sun, 20 Dec 2020 04:52:15 +0800 Subject: [PATCH 17/41] feat: add SignOutButton to NavBar Signed-off-by: Isabella Hu --- src/NavBar.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NavBar.tsx b/src/NavBar.tsx index 20349ed..f2b81b7 100644 --- a/src/NavBar.tsx +++ b/src/NavBar.tsx @@ -1,5 +1,6 @@ import React from "react"; import { Link } from "react-router-dom"; +import SignOutButton from "./components/SignOut"; import { LANDING, @@ -30,6 +31,7 @@ const NavBar = () => (
  • Notifications
  • + ); From 42371d8702aa8869b876760b623f3070846bfc2c Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Sun, 20 Dec 2020 05:23:01 +0800 Subject: [PATCH 18/41] feat: reorganize ThemeContext,useTheme into components/Theme Signed-off-by: Isabella Hu --- src/App.test.tsx | 2 +- src/App.tsx | 2 +- src/components/SignOut/index.tsx | 4 +- src/components/Theme/Context.tsx | 64 +++++++++++++++++++++ src/components/Theme/index.ts | 5 ++ src/{hooks => components/Theme}/useTheme.ts | 2 +- src/components/buttons/Button.stories.tsx | 2 +- src/components/buttons/Button.test.tsx | 2 +- src/components/buttons/Button.tsx | 2 +- src/components/select/Select.stories.tsx | 2 +- src/components/select/Select.test.tsx | 2 +- src/components/select/Select.tsx | 2 +- src/features/posts/AddPostForm.tsx | 2 +- src/features/posts/EditPostForm.tsx | 2 +- src/index.tsx | 2 +- src/pages/Main/Main.jsx | 1 - src/test/withTheme.jsx | 2 +- 17 files changed, 84 insertions(+), 16 deletions(-) create mode 100644 src/components/Theme/Context.tsx create mode 100644 src/components/Theme/index.ts rename src/{hooks => components/Theme}/useTheme.ts (73%) diff --git a/src/App.test.tsx b/src/App.test.tsx index 2c98081..bb4396e 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -5,7 +5,7 @@ import { Provider } from "react-redux"; import { BrowserRouter } from "react-router-dom"; import store from "./store/index"; -import { themes } from "./context/ThemeContext"; +import { themes } from "./components/Theme"; it("render correctly", () => { const ui = ( diff --git a/src/App.tsx b/src/App.tsx index a80f344..e28a16e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,7 +2,7 @@ import React, { useEffect } from "react"; import NavBar from "./NavBar"; import Routes from "./Routes"; import styled from "styled-components"; -import { Mode, Themes, SetMode } from "./context/ThemeContext"; +import { Mode, Themes, SetMode } from "./components/Theme"; import Select from "./components/select/Select"; import { useDispatch } from "react-redux"; diff --git a/src/components/SignOut/index.tsx b/src/components/SignOut/index.tsx index dfe8a5f..4558f5e 100644 --- a/src/components/SignOut/index.tsx +++ b/src/components/SignOut/index.tsx @@ -2,8 +2,8 @@ import React from "react"; import Firebase, { useFirebase } from "../Firebase"; import { useHistory } from "react-router-dom"; import * as ROUTES from "../../constants/routes"; -import useTheme from "../../hooks/useTheme"; -import { Themes, Mode } from "../../context/ThemeContext"; +import { useTheme } from "../Theme"; +import { Themes, Mode } from "../Theme"; import styled from "styled-components"; diff --git a/src/components/Theme/Context.tsx b/src/components/Theme/Context.tsx new file mode 100644 index 0000000..0a6283c --- /dev/null +++ b/src/components/Theme/Context.tsx @@ -0,0 +1,64 @@ +import React from "react"; + +export const LIGHT = { + text: "rgba(0, 0, 0, 1)", + background: "rgba(255, 255, 255, 1)", + btnBackground: "transparent", + btnBorder: "rgba(0, 0, 0, 1)", + btnTextHover: "rgba(255, 255, 255, 0.8)", + btnBackgroundHover: "rgba(0, 0, 0, 0.8)", + disabled: "rgba(0, 0, 0, 0.24)", + disabledBackground: "rgba(255, 255, 255, 0.2)", +}; +export const DARK = { + text: "rgba(255, 255, 255, 1)", + background: "rgba(0, 0, 0, 1)", + btnBackground: "transparent", + btnBorder: "rgba(255, 255, 255, 1)", + btnTextHover: "rgba(0, 0, 0, 0.8)", + btnBackgroundHover: "rgba(255, 255, 255, 0.8)", + disabled: "rgba(255, 255, 255, 0.4)", + disabledBackground: "rgba(0, 0, 0, 0.2)", +}; + +const PINK = { + text: "rgba(196, 139, 159, 1)", + background: "rgba(255, 255, 255, 1)", + btnBackground: "transparent", + btnBorder: "rgba(196, 139, 159, 1)", + btnTextHover: "rgba(255, 255, 255, 0.8)", + btnBackgroundHover: "rgba(196, 139, 159, 0.8)", + disabled: "rgba(196, 139, 159, 0.4)", + disabledBackground: "rgba(196, 139, 159, 0.2)", +}; + +const OTHER = { + borderRadius: "4px", + transition: "all 0.2s", + spacing: "10px", + width: "100%", +}; + +export const themes = { + dark: { ...DARK, ...OTHER }, + light: { ...LIGHT, ...OTHER }, + pink: { ...PINK, ...OTHER }, +}; + +export type Mode = "pink" | "dark" | "light"; +export type Themes = typeof themes; +export type SetMode = (mode: Mode) => void; + +const ThemeContext = React.createContext<{ + mode: Mode; + themes: Themes; + setMode: SetMode; +}>({ + mode: "pink", + themes: themes, + setMode: () => {}, +}); + +ThemeContext.displayName = "ThemeContext"; + +export default ThemeContext; diff --git a/src/components/Theme/index.ts b/src/components/Theme/index.ts new file mode 100644 index 0000000..dc9ce92 --- /dev/null +++ b/src/components/Theme/index.ts @@ -0,0 +1,5 @@ +import ThemeContext, { themes } from "./Context"; +import useTheme from "./useTheme"; + +export type { Mode, Themes, SetMode } from "./Context"; +export { ThemeContext, themes, useTheme }; diff --git a/src/hooks/useTheme.ts b/src/components/Theme/useTheme.ts similarity index 73% rename from src/hooks/useTheme.ts rename to src/components/Theme/useTheme.ts index 2ead7ad..f747682 100644 --- a/src/hooks/useTheme.ts +++ b/src/components/Theme/useTheme.ts @@ -1,5 +1,5 @@ import { useContext } from "react"; -import ThemeContext from "../context/ThemeContext"; +import ThemeContext from "./Context"; export default function useTheme() { const theme = useContext(ThemeContext); diff --git a/src/components/buttons/Button.stories.tsx b/src/components/buttons/Button.stories.tsx index 8f005f0..9c9fef9 100644 --- a/src/components/buttons/Button.stories.tsx +++ b/src/components/buttons/Button.stories.tsx @@ -2,7 +2,7 @@ import React from "react"; // also exported from '@storybook/react' if you can deal with breaking changes in 6.1 import { Story, Meta } from "@storybook/react/types-6-0"; -import { themes } from "../../context/ThemeContext"; +import { themes } from "../Theme"; import Button, { ButtonProps } from "./Button"; export default { diff --git a/src/components/buttons/Button.test.tsx b/src/components/buttons/Button.test.tsx index 5795794..a55254a 100644 --- a/src/components/buttons/Button.test.tsx +++ b/src/components/buttons/Button.test.tsx @@ -1,7 +1,7 @@ import React from "react"; import Button from "./Button"; -import { themes } from "../../context/ThemeContext"; +import { themes } from "../Theme"; import { render } from "@testing-library/react"; import "jest-styled-components"; diff --git a/src/components/buttons/Button.tsx b/src/components/buttons/Button.tsx index 2c5f4d8..a6bd271 100644 --- a/src/components/buttons/Button.tsx +++ b/src/components/buttons/Button.tsx @@ -1,6 +1,6 @@ import React from "react"; import styled from "styled-components"; -import { Themes, Mode } from "../../context/ThemeContext"; +import { Themes, Mode } from "../Theme"; const StyledButton = styled.button` ${({ themes, mode }: ButtonProps) => { diff --git a/src/components/select/Select.stories.tsx b/src/components/select/Select.stories.tsx index 954b18e..7f620aa 100644 --- a/src/components/select/Select.stories.tsx +++ b/src/components/select/Select.stories.tsx @@ -2,7 +2,7 @@ import React from "react"; // also exported from '@storybook/react' if you can deal with breaking changes in 6.1 import { Story, Meta } from "@storybook/react/types-6-0"; -import { themes } from "../../context/ThemeContext"; +import { themes } from "../Theme"; import Select, { SelectProps } from "./Select"; import { data } from "./Select.test"; diff --git a/src/components/select/Select.test.tsx b/src/components/select/Select.test.tsx index 3079462..0bc2c97 100644 --- a/src/components/select/Select.test.tsx +++ b/src/components/select/Select.test.tsx @@ -1,7 +1,7 @@ import React from "react"; import { render } from "@testing-library/react"; import Select from "./Select"; -import { themes } from "../../context/ThemeContext"; +import { themes } from "../Theme"; import { fireEvent } from "@testing-library/react"; export const data = [ diff --git a/src/components/select/Select.tsx b/src/components/select/Select.tsx index 7e16c37..016d5de 100644 --- a/src/components/select/Select.tsx +++ b/src/components/select/Select.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect, useCallback } from "react"; import styled from "styled-components"; -import { Themes, Mode } from "../../context/ThemeContext"; +import { Themes, Mode } from "../Theme"; export interface SelectProps { themes: Themes; mode: Mode; diff --git a/src/features/posts/AddPostForm.tsx b/src/features/posts/AddPostForm.tsx index 8b5b003..6008b28 100644 --- a/src/features/posts/AddPostForm.tsx +++ b/src/features/posts/AddPostForm.tsx @@ -3,7 +3,7 @@ import { useSelector } from "react-redux"; import { addNewPost } from "./postsSlice"; import { State, useAppDispatch } from "../../store"; import { unwrapResult } from "@reduxjs/toolkit"; -import useTheme from "../../hooks/useTheme"; +import { useTheme } from "../../components/Theme"; import Button from "../../components/buttons/Button"; import Select from "../../components/select/Select"; import Input from "../../components/input/Input"; diff --git a/src/features/posts/EditPostForm.tsx b/src/features/posts/EditPostForm.tsx index 9d8802d..b1efcb5 100644 --- a/src/features/posts/EditPostForm.tsx +++ b/src/features/posts/EditPostForm.tsx @@ -7,7 +7,7 @@ import { State } from "../../store/index"; import Button from "../../components/buttons/Button"; import Input from "../../components/input/Input"; import TextArea from "../../components/textarea/TextArea"; -import useTheme from "../../hooks/useTheme"; +import { useTheme } from "../../components/Theme"; import StyledForm from "../../components/form/StyledForm"; interface Params { diff --git a/src/index.tsx b/src/index.tsx index 1b587ec..d37d1df 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,7 +3,7 @@ import ReactDOM from "react-dom"; import { Provider } from "react-redux"; import { BrowserRouter } from "react-router-dom"; import { CookiesProvider } from "react-cookie"; -import ThemeContext, { themes, Mode } from "./context/ThemeContext"; +import { ThemeContext, themes, Mode } from "./components/Theme"; import Firebase, { FirebaseContext } from "./components/Firebase"; import store from "./store/index"; diff --git a/src/pages/Main/Main.jsx b/src/pages/Main/Main.jsx index 63308d3..7e45e6f 100644 --- a/src/pages/Main/Main.jsx +++ b/src/pages/Main/Main.jsx @@ -6,7 +6,6 @@ import Projects from "../Projects/Projects"; import Login from "../Login/Login"; import "./Main.scss"; -import ThemeContext from "../../context/ThemeContext"; const ROUTES = [ { diff --git a/src/test/withTheme.jsx b/src/test/withTheme.jsx index 8e19fd7..a621bfb 100644 --- a/src/test/withTheme.jsx +++ b/src/test/withTheme.jsx @@ -1,5 +1,5 @@ import React from "react"; -import ThemeContext, { themes } from "../context/ThemeContext"; +import { ThemeContext, themes } from "../components/Theme"; export const theme = { themes: themes, mode: "pink", setTheme: jest.fn() }; From 2b32fdef7ffb0e35bd4a20f48d04faef63cd88ba Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Sun, 20 Dec 2020 05:59:32 +0800 Subject: [PATCH 19/41] feat: fix NavBar style Signed-off-by: Isabella Hu --- src/App.tsx | 6 +-- src/NavBar.tsx | 76 +++++++++++++++++++++++--------- src/components/SignOut/index.tsx | 6 ++- 3 files changed, 60 insertions(+), 28 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index e28a16e..928c44e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -33,14 +33,10 @@ const StyledApp = styled.div` nav { display: flex; + align-items: center; li { margin: 0 ${themes[mode].spacing}; list-style: none; - &:hover { - cursor: pointer; - color: ${themes[mode].background}; - background-color: ${themes[mode].text}; - } } } diff --git a/src/NavBar.tsx b/src/NavBar.tsx index f2b81b7..8dcc4dc 100644 --- a/src/NavBar.tsx +++ b/src/NavBar.tsx @@ -1,7 +1,10 @@ import React from "react"; import { Link } from "react-router-dom"; +import styled from "styled-components"; import SignOutButton from "./components/SignOut"; +import { useTheme, Themes, Mode } from "./components/Theme"; + import { LANDING, NOTIFICATIONS, @@ -11,28 +14,59 @@ import { ADMIN, } from "./constants/routes"; -const NavBar = () => ( - -); + ); +}; + +const NavBar = () => { + return ( + + ); +}; export default NavBar; diff --git a/src/components/SignOut/index.tsx b/src/components/SignOut/index.tsx index 4558f5e..602c5ea 100644 --- a/src/components/SignOut/index.tsx +++ b/src/components/SignOut/index.tsx @@ -16,12 +16,14 @@ const StyledButton = styled.button` return ` --btn-text-hover: ${themes[mode].btnTextHover}; --btn-bg-hover: ${themes[mode].btnBackgroundHover}; --color-bg: ${themes[mode].background} ; - --color-text:${themes[mode].text};`; + --color-text:${themes[mode].text}; + --spacing:${themes[mode].spacing};`; }} text-decoration: none; color: var(--color-text); - background-color: transparent; + background-color: var(--color-bg); border: none; + padding: var(--spacing); &:hover { color: var(--btn-text-hover); From e54cc6804f7d619daf1942c35ebc949344db3380 Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Sun, 20 Dec 2020 05:59:58 +0800 Subject: [PATCH 20/41] test: fix NavBar test & snapshot Signed-off-by: Isabella Hu --- src/NavBar.test.tsx | 34 ++++++++-------- src/__snapshots__/NavBar.test.tsx.snap | 56 ++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 17 deletions(-) diff --git a/src/NavBar.test.tsx b/src/NavBar.test.tsx index d30bed7..709cb68 100644 --- a/src/NavBar.test.tsx +++ b/src/NavBar.test.tsx @@ -6,29 +6,29 @@ import { Provider } from "react-redux"; import store from "./store/index"; const withBrowserRouterAndStore = (ui: React.ReactNode, route = "/initial") => { - window.history.pushState({}, "", route); - return ( - - {ui} - - ); + window.history.pushState({}, "", route); + return ( + + {ui} + + ); }; test("click Home, location pathname set to /", () => { - const ui = withBrowserRouterAndStore(); - render(ui); - fireEvent.click(screen.getByText(/Home/i)); - expect(window.location.pathname).toBe("/"); + const ui = withBrowserRouterAndStore(); + render(ui); + fireEvent.click(screen.getByText(/Home/i)); + expect(window.location.pathname).toBe("/home"); }); test("click Notifications, location pathname set to /notifications", () => { - const ui = withBrowserRouterAndStore(); - render(ui); - fireEvent.click(screen.getByText(/Notifications/i)); - expect(window.location.pathname).toBe("/notifications"); + const ui = withBrowserRouterAndStore(); + render(ui); + fireEvent.click(screen.getByText(/Notifications/i)); + expect(window.location.pathname).toBe("/notifications"); }); test("renders correctly", () => { - const ui = withBrowserRouterAndStore(); - const { asFragment } = render(ui); + const ui = withBrowserRouterAndStore(); + const { asFragment } = render(ui); - expect(asFragment()).toMatchSnapshot(); + expect(asFragment()).toMatchSnapshot(); }); diff --git a/src/__snapshots__/NavBar.test.tsx.snap b/src/__snapshots__/NavBar.test.tsx.snap index fb24344..125de5b 100644 --- a/src/__snapshots__/NavBar.test.tsx.snap +++ b/src/__snapshots__/NavBar.test.tsx.snap @@ -5,18 +5,74 @@ exports[`renders correctly 1`] = ` `; From 1d6766724334c0579304d3b536334196ad45a3fb Mon Sep 17 00:00:00 2001 From: Isabella Hu Date: Mon, 21 Dec 2020 03:38:12 +0800 Subject: [PATCH 21/41] feat: session handling using global state Signed-off-by: Isabella Hu --- src/App.tsx | 23 +++++++++++++++++++++-- src/NavBar.tsx | 39 +++++++++++++++++++++++++-------------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 928c44e..84ed42e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,12 +1,14 @@ -import React, { useEffect } from "react"; +import React, { useEffect, useState } from "react"; import NavBar from "./NavBar"; import Routes from "./Routes"; import styled from "styled-components"; import { Mode, Themes, SetMode } from "./components/Theme"; import Select from "./components/select/Select"; +import app from "firebase/app"; import { useDispatch } from "react-redux"; import { fetchUsers } from "./features/users/usersSlice"; +import Firebase, { useFirebase } from "./components/Firebase"; export interface AppProps { themes: Themes; @@ -53,17 +55,34 @@ const StyledApp = styled.div` const modeData = (data: string[]) => data.map((mode: string) => ({ id: mode, name: mode })); +export const useAuthUser = () => { + const [authUser, setAuthUser] = useState(null); + const firebase = useFirebase() as Firebase; + useEffect(() => { + const listener = firebase.auth.onAuthStateChanged((authUser) => + setAuthUser(authUser) + ); + return () => { + listener(); + }; + }, [firebase]); + + return authUser; +}; + const App: React.FC = (props) => { + const authUser = useAuthUser(); const dispatch = useDispatch(); const { themes, mode, setMode } = props; useEffect(() => { dispatch(fetchUsers()); }, [dispatch]); + return (
    - +
    -
      -
    • - dark -
    • -
    • - pink -
    • -
    • - light -
    • -
    -
    - -
    -
    -
    -
    -
    - - -
    -
    - -