diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0c46ef6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "editor.tabSize": 2, + "prettier.jsxSingleQuote": true, + "javascript.preferences.quoteStyle": "single", + "prettier.singleQuote": true +} diff --git a/assets/avatar.png b/assets/avatar.png new file mode 100644 index 0000000..b89c456 Binary files /dev/null and b/assets/avatar.png differ diff --git a/assets/blur.jpg b/assets/blur.jpg new file mode 100644 index 0000000..e79c934 Binary files /dev/null and b/assets/blur.jpg differ diff --git a/assets/empty_box.png b/assets/empty_box.png new file mode 100644 index 0000000..17abdf2 Binary files /dev/null and b/assets/empty_box.png differ diff --git a/assets/familyView.png b/assets/familyView.png new file mode 100644 index 0000000..c26d65c Binary files /dev/null and b/assets/familyView.png differ diff --git a/assets/loginBg.png b/assets/loginBg.png new file mode 100644 index 0000000..c07f2aa Binary files /dev/null and b/assets/loginBg.png differ diff --git a/assets/loginIcon.png b/assets/loginIcon.png new file mode 100644 index 0000000..785ba3e Binary files /dev/null and b/assets/loginIcon.png differ diff --git a/assets/loginPage.png b/assets/loginPage.png new file mode 100644 index 0000000..c23d242 Binary files /dev/null and b/assets/loginPage.png differ diff --git a/assets/openBankingHead.png b/assets/openBankingHead.png new file mode 100644 index 0000000..4b0b627 Binary files /dev/null and b/assets/openBankingHead.png differ diff --git a/assets/personalDefaultPage.png b/assets/personalDefaultPage.png new file mode 100644 index 0000000..80315f4 Binary files /dev/null and b/assets/personalDefaultPage.png differ diff --git a/assets/profile.jpg b/assets/profile.jpg new file mode 100644 index 0000000..2db060d Binary files /dev/null and b/assets/profile.jpg differ diff --git a/babel.config.js b/babel.config.js index f6d217d..58869ad 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,6 +1,9 @@ module.exports = (api) => { api.cache(true); return { - presets: ['babel-preset-expo'], + presets: [ + 'babel-preset-expo', + 'module:react-native-dotenv', + ], }; }; diff --git a/package-lock.json b/package-lock.json index 989d74f..9106219 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2850,6 +2850,14 @@ "requires": { "react-is": "^16.7.0" } + }, + "react-native-screens": { + "version": "1.0.0-alpha.23", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-1.0.0-alpha.23.tgz", + "integrity": "sha512-tOxHGQUN83MTmQB4ghoQkibqOdGiX4JQEmeyEv96MKWO/x8T2PJv84ECUos9hD3blPRQwVwSpAid1PPPhrVEaw==", + "requires": { + "debounce": "^1.2.0" + } } } }, @@ -3634,6 +3642,21 @@ "slash": "^2.0.0" } }, + "babel-plugin-dotenv": { + "version": "0.1.1", + "resolved": "https://registry.npm.taobao.org/babel-plugin-dotenv/download/babel-plugin-dotenv-0.1.1.tgz", + "integrity": "sha1-nI+upnp8A0/n6UCZGHqy51c0ALw=", + "requires": { + "dotenv": "^2.0.0" + }, + "dependencies": { + "dotenv": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/dotenv/download/dotenv-2.0.0.tgz?cache=0&sync_timestamp=1571190782798&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdotenv%2Fdownload%2Fdotenv-2.0.0.tgz", + "integrity": "sha1-vXWcNXqqcDZeAclrewvsCKbg2Uk=" + } + } + }, "babel-plugin-dynamic-import-node": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", @@ -3880,11 +3903,25 @@ "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==" }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, "blueimp-md5": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.12.0.tgz", "integrity": "sha512-zo+HIdIhzojv6F1siQPqPFROyVy7C50KzHv/k/Iz+BtvtVzSHXiMXOpq2wCfNkeBqdCv+V8XOV96tsEt2W/3rQ==" }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, "bplist-creator": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.8.tgz", @@ -4428,6 +4465,38 @@ } } }, + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-tree": { + "version": "1.0.0-alpha.39", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.39.tgz", + "integrity": "sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA==", + "requires": { + "mdn-data": "2.0.6", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "css-what": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz", + "integrity": "sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw==" + }, "cssom": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", @@ -4605,6 +4674,17 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" }, + "deprecated-react-native-listview": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/deprecated-react-native-listview/-/deprecated-react-native-listview-0.0.5.tgz", + "integrity": "sha512-Cy7nDdd+KU+nR3tY1BSMuoZpsYC6OVSZyAiUSTDBop2lIgzCseDx7XI57x6h+NXer/8aor2yiQDQfeFcmBMwgQ==", + "requires": { + "create-react-class": "*", + "fbjs": "*", + "invariant": "*", + "react-clone-referenced-element": "*" + } + }, "destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", @@ -4631,11 +4711,32 @@ "esutils": "^2.0.2" } }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", + "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==" + } + } + }, "dom-walk": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, "domexception": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", @@ -4645,6 +4746,20 @@ "webidl-conversions": "^4.0.2" } }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -4692,6 +4807,11 @@ "once": "^1.4.0" } }, + "entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==" + }, "envinfo": { "version": "5.12.1", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-5.12.1.tgz", @@ -5670,6 +5790,12 @@ "flat-cache": "^2.0.1" } }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, "filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", @@ -5852,13 +5978,14 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz", + "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==", "optional": true, "requires": { + "bindings": "^1.5.0", "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" + "node-pre-gyp": "*" }, "dependencies": { "abbrev": { @@ -5900,7 +6027,7 @@ } }, "chownr": { - "version": "1.1.1", + "version": "1.1.3", "bundled": true, "optional": true }, @@ -5925,7 +6052,7 @@ "optional": true }, "debug": { - "version": "4.1.1", + "version": "3.2.6", "bundled": true, "optional": true, "requires": { @@ -5948,11 +6075,11 @@ "optional": true }, "fs-minipass": { - "version": "1.2.5", + "version": "1.2.7", "bundled": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "^2.6.0" } }, "fs.realpath": { @@ -5976,7 +6103,7 @@ } }, "glob": { - "version": "7.1.3", + "version": "7.1.6", "bundled": true, "optional": true, "requires": { @@ -6002,7 +6129,7 @@ } }, "ignore-walk": { - "version": "3.0.1", + "version": "3.0.3", "bundled": true, "optional": true, "requires": { @@ -6019,7 +6146,7 @@ } }, "inherits": { - "version": "2.0.3", + "version": "2.0.4", "bundled": true, "optional": true }, @@ -6055,7 +6182,7 @@ "optional": true }, "minipass": { - "version": "2.3.5", + "version": "2.9.0", "bundled": true, "optional": true, "requires": { @@ -6064,11 +6191,11 @@ } }, "minizlib": { - "version": "1.2.1", + "version": "1.3.3", "bundled": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "^2.9.0" } }, "mkdirp": { @@ -6080,22 +6207,22 @@ } }, "ms": { - "version": "2.1.1", + "version": "2.1.2", "bundled": true, "optional": true }, "needle": { - "version": "2.3.0", + "version": "2.4.0", "bundled": true, "optional": true, "requires": { - "debug": "^4.1.0", + "debug": "^3.2.6", "iconv-lite": "^0.4.4", "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.12.0", + "version": "0.14.0", "bundled": true, "optional": true, "requires": { @@ -6108,7 +6235,7 @@ "rc": "^1.2.7", "rimraf": "^2.6.1", "semver": "^5.3.0", - "tar": "^4" + "tar": "^4.4.2" } }, "nopt": { @@ -6121,12 +6248,20 @@ } }, "npm-bundled": { - "version": "1.0.6", + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", "bundled": true, "optional": true }, "npm-packlist": { - "version": "1.4.1", + "version": "1.4.7", "bundled": true, "optional": true, "requires": { @@ -6188,7 +6323,7 @@ "optional": true }, "process-nextick-args": { - "version": "2.0.0", + "version": "2.0.1", "bundled": true, "optional": true }, @@ -6225,7 +6360,7 @@ } }, "rimraf": { - "version": "2.6.3", + "version": "2.7.1", "bundled": true, "optional": true, "requires": { @@ -6248,7 +6383,7 @@ "optional": true }, "semver": { - "version": "5.7.0", + "version": "5.7.1", "bundled": true, "optional": true }, @@ -6294,17 +6429,17 @@ "optional": true }, "tar": { - "version": "4.4.8", + "version": "4.4.13", "bundled": true, "optional": true, "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" + "yallist": "^3.0.3" } }, "util-deprecate": { @@ -6326,7 +6461,7 @@ "optional": true }, "yallist": { - "version": "3.0.3", + "version": "3.1.1", "bundled": true, "optional": true } @@ -9728,6 +9863,11 @@ "buffer-alloc": "^1.1.0" } }, + "mdn-data": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.6.tgz", + "integrity": "sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA==" + }, "mem": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", @@ -10503,6 +10643,14 @@ "gauge": "~1.2.5" } }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "requires": { + "boolbase": "~1.0.0" + } + }, "nullthrows": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", @@ -10953,6 +11101,11 @@ "pify": "^2.0.0" } }, + "paths-js": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/paths-js/-/paths-js-0.4.10.tgz", + "integrity": "sha512-JZoqlRSHtx+bc+xKI9o4bropEbqZBF4ZfYImiB1T9RYpHB73h5I8XZ7FfSBbHbBMtdD1c04ujjAPH8wUuu4+Gw==" + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -11084,6 +11237,11 @@ "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", "dev": true }, + "point-in-polygon": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.0.1.tgz", + "integrity": "sha1-1Ztk6P7kHElFiqyCtWcYxZV7Kvc=" + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -11482,6 +11640,24 @@ "resolved": "https://registry.npmjs.org/react-native-branch/-/react-native-branch-3.0.1.tgz", "integrity": "sha512-vbcYxPZlpF5f39GAEUF8kuGQqCNeD3E6zEdvtOq8oCGZunHXlWlKgAS6dgBKCvsHvXgHuMtpvs39VgOp8DaKig==" }, + "react-native-chart-kit": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/react-native-chart-kit/-/react-native-chart-kit-4.3.0.tgz", + "integrity": "sha512-mVi0jT2bbKJOpmyqdn2+kGiInU+7P+ebi2ddQWm/Vfwbmd0InyPi7wj3F5UN9Ymr2tYQxuqpOJtHKmn1bT3/5w==", + "requires": { + "lodash": "^4.17.13", + "paths-js": "^0.4.10", + "point-in-polygon": "^1.0.1" + } + }, + "react-native-dotenv": { + "version": "0.2.0", + "resolved": "https://registry.npm.taobao.org/react-native-dotenv/download/react-native-dotenv-0.2.0.tgz", + "integrity": "sha1-MRVRy2o1o9z+3mSL3tVcDj7OV50=", + "requires": { + "babel-plugin-dotenv": "0.1.1" + } + }, "react-native-drawer": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/react-native-drawer/-/react-native-drawer-2.5.1.tgz", @@ -11573,6 +11749,15 @@ "react-native-modal": "^11.0.2" } }, + "react-native-modal-dropdown": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/react-native-modal-dropdown/-/react-native-modal-dropdown-0.7.0.tgz", + "integrity": "sha512-h2UrozBByQhL56XDboj/wjc/5Ny787eLQ++4ql7TecBdbLqbf+tlE62VeXKz30XVMN3iUVYUR/XmM/RIwLIXEg==", + "requires": { + "deprecated-react-native-listview": "0.0.5", + "prop-types": "^15.6.0" + } + }, "react-native-ratings": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/react-native-ratings/-/react-native-ratings-6.5.0.tgz", @@ -11587,6 +11772,11 @@ "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-1.2.0.tgz", "integrity": "sha512-vkWRHrPK5qfHP/ZawlRoo38oeYe9NZaaOH/lmFxRcsKzaSK6x3H5ZPXI8lK6MfTLveqwo1QhJje3zIKXO4nQQw==" }, + "react-native-safe-area-context": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-0.6.2.tgz", + "integrity": "sha512-VtBW0JymVCwVt0TGxTv25Co3wtOv3Yb/K5pAUYkjKXNhWFDz5ZwUG/Yho/p0EkWYlFdroJcSqlvVFl2n3AU7SA==" + }, "react-native-safe-area-view": { "version": "0.14.8", "resolved": "https://registry.npmjs.org/react-native-safe-area-view/-/react-native-safe-area-view-0.14.8.tgz", @@ -11603,9 +11793,9 @@ } }, "react-native-screens": { - "version": "1.0.0-alpha.23", - "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-1.0.0-alpha.23.tgz", - "integrity": "sha512-tOxHGQUN83MTmQB4ghoQkibqOdGiX4JQEmeyEv96MKWO/x8T2PJv84ECUos9hD3blPRQwVwSpAid1PPPhrVEaw==", + "version": "2.0.0-alpha.22", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-2.0.0-alpha.22.tgz", + "integrity": "sha512-2U++QrTf8H989ekHbgFuia8LLd8/+SbXra+rqDAOihCNRLFi91+y5QGgc7DP4Ic9MtHTaYRtWopyfyUo4ybD0A==", "requires": { "debounce": "^1.2.0" } @@ -11615,6 +11805,15 @@ "resolved": "https://registry.npmjs.org/react-native-status-bar-height/-/react-native-status-bar-height-2.4.0.tgz", "integrity": "sha512-pWvZFlyIHiuxLugLioq97vXiaGSovFXEyxt76wQtbq0gxv4dGXMPqYow46UmpwOgeJpBhqL1E0EKxnfJRrFz5w==" }, + "react-native-svg": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-10.0.0.tgz", + "integrity": "sha512-7x56ji3oP8+Bh1jVuBtrq/JGxqLBAVf43BCuAbPMKaBlq78TXCMuln7fiBxCUOD4Z5hoZZaVkILhrJPPszfENA==", + "requires": { + "css-select": "^2.0.2", + "css-tree": "^1.0.0-alpha.37" + } + }, "react-native-tab-view": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-2.11.0.tgz", @@ -11808,6 +12007,22 @@ } } }, + "react-native-webview": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-8.0.3.tgz", + "integrity": "sha512-Uhd3o73HcqiQ0GWxyz5G5+Jkh1dd1A8Kz/rCYHiX/Ctkg3KO9qrZUmzRetq5y9X1+fUH9XJt6+LO3iO/Dxopfw==", + "requires": { + "escape-string-regexp": "2.0.0", + "invariant": "2.2.4" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" + } + } + }, "react-navigation": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/react-navigation/-/react-navigation-4.0.10.tgz", @@ -11817,6 +12032,11 @@ "@react-navigation/native": "^3.6.2" } }, + "react-navigation-hooks": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/react-navigation-hooks/-/react-navigation-hooks-1.1.0.tgz", + "integrity": "sha512-ZY/aiYJ88KXaOo8iOa4171O/0x6ztGhUPd2OYzdaJhLT/tP64zi5HB/RZFImuKhaBTODXjoSpFaOTA5xpePG4g==" + }, "react-navigation-stack": { "version": "1.10.3", "resolved": "https://registry.npmjs.org/react-navigation-stack/-/react-navigation-stack-1.10.3.tgz", diff --git a/package.json b/package.json index b12690a..134dca9 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "@expo/vector-icons": "^10.0.6", + "dotenv": "^8.2.0", "expo": "^35.0.0", "expo-font": "~7.0.0", "expo-linear-gradient": "~7.0.0", @@ -26,12 +27,20 @@ "react": "16.9.0", "react-dom": "16.9.0", "react-native": "https://github.com/expo/react-native/archive/sdk-35.0.0.tar.gz", + "react-native-chart-kit": "^4.3.0", + "react-native-dotenv": "^0.2.0", "react-native-elements": "^1.2.7", "react-native-gesture-handler": "~1.3.0", "react-native-modal-datetime-picker": "^7.6.1", + "react-native-modal-dropdown": "^0.7.0", "react-native-reanimated": "~1.2.0", + "react-native-safe-area-context": "^0.6.1", + "react-native-screens": "^2.0.0-alpha.22", + "react-native-svg": "^10.0.0", "react-native-web": "^0.11.7", + "react-native-webview": "^8.0.3", "react-navigation": "^4.0.10", + "react-navigation-hooks": "^1.1.0", "react-navigation-stack": "^1.10.3", "react-navigation-tabs": "^2.6.2", "react-redux": "^7.1.3", diff --git a/src/App.jsx b/src/App.jsx index 4429864..5d3b063 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -2,16 +2,13 @@ import React, { useState, useEffect } from 'react'; import { registerRootComponent, AppLoading } from 'expo'; import * as Font from 'expo-font'; import { Provider } from 'react-redux'; -import { createAppContainer } from 'react-navigation'; import { Alert } from 'react-native'; import { PersistGate } from 'redux-persist/integration/react'; -import AppNavigator from './Navigator'; +import AppContainer from './AppContainer'; import { store, persistor } from './reduxStore'; import Roboto from '../assets/Fonts/Roboto/Roboto-Regular.ttf'; import RobotoMedium from '../assets/Fonts/Roboto/Roboto-Medium.ttf'; -const AppContainer = createAppContainer(AppNavigator); - const App = () => { const [fontLoading, setFontLoading] = useState(true); diff --git a/src/AppContainer.jsx b/src/AppContainer.jsx new file mode 100644 index 0000000..44c84e5 --- /dev/null +++ b/src/AppContainer.jsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { useSelector } from 'react-redux'; +import { createAppContainer } from 'react-navigation'; +import AppNavigatorWhite from './Navigator/indexWhite'; +import AppNavigatorBlack from './Navigator/indexBlack'; +import AppNavigatorWhiteProfile from './Navigator/indexWhiteProfile'; +import AppNavigatorBlackProfile from './Navigator/indexBlackProfile'; + +let assigned = false; +export default () => { + const { themeMode } = useSelector((state) => state.theme); + let AppContainer; + if (assigned) { + AppContainer = themeMode === 'Light' ? createAppContainer(AppNavigatorWhiteProfile) : createAppContainer(AppNavigatorBlackProfile); + } else { + AppContainer = themeMode === 'Light' ? createAppContainer(AppNavigatorWhite) : createAppContainer(AppNavigatorBlack); + } + assigned = true; + return ; +}; diff --git a/src/Chart/LineGraph.jsx b/src/Chart/LineGraph.jsx new file mode 100644 index 0000000..6ae6e56 --- /dev/null +++ b/src/Chart/LineGraph.jsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { View, Dimensions } from 'react-native'; +import { LineChart } from 'react-native-chart-kit'; +import PropTypes from 'prop-types'; + +export default function LineGraph({ dataSet }) { + const screenWidth = Dimensions.get('window').width * 0.85; + + const chartConfig = { + backgroundGradientFrom: '#e96d9e', + backgroundGradientTo: '#ffaa8f', + color: (opacity = 1) => `rgba(255, 255, 255, ${opacity})`, + strokeWidth: 2, + }; + + const data = { + labels: dataSet.labels, + datasets: [{ + data: dataSet.total, + color: (opacity = 1) => `rgba(255, 255, 255, ${opacity})`, + strokeWidth: 2, + }], + }; + return ( + + + + ); +} + +LineGraph.propTypes = { + dataSet: PropTypes.shape({ labels: PropTypes.array, total: PropTypes.array }), +}; + +LineGraph.defaultProps = { + dataSet: {}, +}; diff --git a/src/Chart/PieGraph.jsx b/src/Chart/PieGraph.jsx new file mode 100644 index 0000000..2ae63cc --- /dev/null +++ b/src/Chart/PieGraph.jsx @@ -0,0 +1,65 @@ +import React from 'react'; +import { Animated, View, Easing } from 'react-native'; +import { PieChart } from 'react-native-chart-kit'; +import { useSelector } from 'react-redux'; +import PropTypes from 'prop-types'; +import PieLegend from './PieLegend'; +import setThemeStyle from '../Common/theme/setThemeStyle'; + +export default function PieGraph({ graphDataSet }) { + const { themeMode } = useSelector((state) => state.theme); + const styles = setThemeStyle(themeMode); + const spinValue = new Animated.Value(0); + const { dataSet, legendSet } = graphDataSet; + Animated.timing(spinValue, { + toValue: 1, + duration: 900, + easing: Easing.bounce, + }).start(); + + const spin = spinValue.interpolate({ + inputRange: [0, 1], + outputRange: ['0deg', '90deg'], + }); + + dataSet.forEach((item) => { + const value = item; + value.legendFontColor = styles.mainColor.color; + return value; + }); + + const chartConfig = { + backgroundGradientFrom: '#e96d9e', + backgroundGradientTo: '#ffaa8f', + decimalPlaces: 2, + color: (opacity = 1) => `rgba(255, 255, 255, ${opacity})`, + strokeWidth: 2, + }; + + return ( + + + + + + {legendSet.map((item, idx) => )} + + + ); +} + +PieGraph.propTypes = { + graphDataSet: PropTypes.shape({ + dataSet: PropTypes.array, + legendSet: PropTypes.array, + }).isRequired, +}; diff --git a/src/Chart/PieLegend.jsx b/src/Chart/PieLegend.jsx new file mode 100644 index 0000000..2f04c95 --- /dev/null +++ b/src/Chart/PieLegend.jsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { View, Text } from 'react-native'; +import { Icon } from 'react-native-elements'; +import { useSelector } from 'react-redux'; +import PropTypes from 'prop-types'; +import setThemeStyle from '../Common/theme/setThemeStyle'; + +export default function PieLegend({ text, color }) { + const { themeMode } = useSelector((state) => state.theme); + const styles = setThemeStyle(themeMode); + return ( + + + {text} + + ); +} + +PieLegend.propTypes = { + text: PropTypes.string, + color: PropTypes.string, +}; + +PieLegend.defaultProps = { + text: '', + color: '', +}; diff --git a/src/Chart/chartUtils.js b/src/Chart/chartUtils.js new file mode 100644 index 0000000..dbcba35 --- /dev/null +++ b/src/Chart/chartUtils.js @@ -0,0 +1,72 @@ +const moment = require('moment'); + +const convertToLineGraphDataset = (dataList, dataType) => { + const labels = []; + const total = []; + dataList.map((groupedRecordsByDate) => { + const filterData = groupedRecordsByDate.filter((item) => item.type === dataType); + const result = filterData.reduce((sum, { amount }) => { + const parsedAmount = parseFloat(amount); + return sum + parsedAmount; + }, 0); + if (filterData.length !== 0) { + const formatDate = moment(groupedRecordsByDate[0].date, 'MMMM Do YYYY').format('D'); + labels.push(formatDate); + total.push(result); + } + return null; + }); + return { labels: labels.reverse(), total: total.reverse() }; +}; + +const convertToDatasetByCategory = (dataList, dataType) => { + const filterData = dataList.filter((item) => item.type === dataType); + if (filterData.length !== 0) { + const dataSet = []; + const colorSet = []; + const legendSet = []; + filterData.forEach((item) => { + const index = dataSet.findIndex((value) => value.name === item.labelName.name); + if (index === -1) { + dataSet.push({ + name: item.labelName.name, + total: parseFloat(item.amount), + color: item.labelName.color, + }); + colorSet.push(item.labelName.color); + legendSet.push({ + name: item.labelName.name, + color: item.labelName.color, + }); + } else { + const newValue = parseFloat(dataSet[index].total) + parseFloat(item.amount); + dataSet[index].total = newValue; + } + }); + return { dataSet, legendSet }; + } + return []; +}; + +const filterDataByPeriod = (dataList, range, view) => { + const monthRange = range.format('MMM YYYY'); + const yearRange = range.format('YYYY'); + let result; + switch (view) { + case 'month': + result = dataList.filter((value) => moment.unix(value.date).format('MMM YYYY') === monthRange); + break; + case 'year': + result = dataList.filter((value) => moment.unix(value.date).format('YYYY') === yearRange); + break; + default: + break; + } + return result; +}; + +export default { + convertToLineGraphDataset, + convertToDatasetByCategory, + filterDataByPeriod, +}; diff --git a/src/Chart/index.jsx b/src/Chart/index.jsx new file mode 100644 index 0000000..0dfce16 --- /dev/null +++ b/src/Chart/index.jsx @@ -0,0 +1,82 @@ +import React, { useState } from 'react'; +import { View, ScrollView } from 'react-native'; +import { useSelector } from 'react-redux'; +import MainHeader from '../Common/MainHeader'; +import DateSlider from '../Common/DateSlider'; +import DateOverlay from '../Common/DateOverlay'; +import setThemeStyle from '../Common/theme/setThemeStyle'; +import EmptyHistory from '../Stats/EmptyHistory'; +import utils from '../Stats/utils'; +import statsUtils from './chartUtils'; +import LineGraph from './LineGraph'; +import PieGraph from './PieGraph'; + +const moment = require('moment'); + +export default function Chart() { + const { transactions } = useSelector((state) => state.transactions); + const { themeMode } = useSelector((state) => state.theme); + const styles = setThemeStyle(themeMode); + const [view, setCurrentView] = useState('month'); + const [timePeriodOptions, setTimePeriod] = useState(utils.getDateSet(moment(), view)); + const [isOverlayVisible, setOverlayVisibility] = useState(false); + const updateHeaderView = (type) => { + setCurrentView(type); + setTimePeriod(utils.getDateSet(moment(), type)); + setOverlayVisibility(!isOverlayVisible); + }; + + const filterListView = (transactionRecords) => { + const current = timePeriodOptions[1]; + return utils.filterData(transactionRecords, current, view); + }; + + + const navBarFunc = [ + { + name: 'filter', + func: () => setOverlayVisibility(true), + }, + ]; + + const filteredDataByDate = filterListView(utils.groupTransactionsByDate(transactions)); + + const filterDataByPeriod = statsUtils.filterDataByPeriod( + transactions, timePeriodOptions[1], view, + ); + + const dataSetByDate = statsUtils.convertToLineGraphDataset(filteredDataByDate, 'Expense'); + const graphDataSet = statsUtils.convertToDatasetByCategory(filterDataByPeriod, 'Expense'); + + const isLineChartExist = filterDataByPeriod.length !== 0 && dataSetByDate.labels.length !== 0; + const isPieChartExist = filterDataByPeriod.length !== 0 && graphDataSet.length !== 0; + + return ( + + updateHeaderView(viewValue)} + onPressClose={() => setOverlayVisibility(false)} + /> + + setTimePeriod(utils.getDateSet(value, type))} + viewType={view} + /> + + {isLineChartExist && isPieChartExist ? ( + <> + + + + + + + + ) + : } + + + ); +} diff --git a/src/Common/Color.js b/src/Common/Color.js index 738352b..8483fc6 100644 --- a/src/Common/Color.js +++ b/src/Common/Color.js @@ -2,6 +2,9 @@ export default { navColor: { activeTintColor: '#5C6BC0', inactiveTintColor: 'gray', + style: { + backgroundColor: '#e0e0e0', + }, }, headerColor: { @@ -14,5 +17,7 @@ export default { green: ['#2fc899', '#78ef93'], purple: ['#a765cf', '#f8b6cc'], orange: ['#ef6d6b', '#feaa74'], + gray: ['#ababab', '#d1d1d1'], + white: ['#ffffff', '#ffffff'], }, }; diff --git a/src/Common/DateOverlay.jsx b/src/Common/DateOverlay.jsx new file mode 100644 index 0000000..3e93c92 --- /dev/null +++ b/src/Common/DateOverlay.jsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { View } from 'react-native'; +import { ListItem, Overlay, Button } from 'react-native-elements'; +import PropTypes from 'prop-types'; + +export default function DateOverlay(props) { + const { isOverlayVisible, onPressClose, onPressBtn } = props; + + return ( + + + +