diff --git a/.env.dev b/.env.dev index 0b9bf72..46630b7 100644 --- a/.env.dev +++ b/.env.dev @@ -1,5 +1,6 @@ APP_CONFIG=dev KANVAS_URL=https://graphapidev.kanvas.dev/graphql -KANVAS_KEY=7d0488b2-632e-4045-9d2d-370d9161644a +KANVAS_KEY=9f8a5dfe-be5d-4958-b654-28150f86172a +KANVAS_ADMIN_KEY=flvVB5dsLy2t2dGDmiWyz9vxvKtYffoJ8uGYik8D6UVddkIQGzlmxGfLn3uz7srwq397XEiyeZP14xfQlPinWMBVybW5febG0ALQIX30faWbhdTrz9KpnlV3EOi4nweB GOOGLE_WEB_CLIENT_ID='815133161926-qr8dm7hovaa3su0j6l217cdka4otpla6.apps.googleusercontent.com' GOOGLE_IOS_CLIENT_ID='815133161926-be4gebpe0tg5674tru8ckqiom3uurdpe.apps.googleusercontent.com' \ No newline at end of file diff --git a/README.md b/README.md index de45dfd..25eae21 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## **Kanvas Mobile App** +## **Go Parking Mobile App** This repository serves as a foundation for future projects at Mctekk. Currently, it includes modules from Kanvas as well as other UI/UX components. @@ -15,5 +15,14 @@ The app currently contains the following Kanvas modules: - Update User Data - Get User by ID - Retrieve User Information -- Payments - -IAP Payments webhook support \ No newline at end of file +- Payments: + - IAP Payments webhook support +- Notifications: + - Push Notifications + - In-App Notifications +- Analytics: + - User Activity Tracking + - Event Logging +- Settings: + - Update Preferences + - Manage Subscriptions \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 05f58f5..f3c469f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1287,7 +1287,7 @@ PODS: - React-Core - react-native-netinfo (11.4.1): - React-Core - - react-native-safe-area-context (4.14.0): + - react-native-safe-area-context (4.14.1): - React-Core - react-native-splash-screen (3.3.0): - React-Core @@ -1576,7 +1576,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - RNGestureHandler (2.20.2): + - RNGestureHandler (2.22.0): - DoubleConversion - glog - hermes-engine @@ -1667,7 +1667,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - RNScreens (4.0.0): + - RNScreens (4.5.0): - DoubleConversion - glog - hermes-engine @@ -1691,7 +1691,7 @@ PODS: - Yoga - RNSVG (15.1.0): - React-Core - - RNVectorIcons (10.1.0): + - RNVectorIcons (10.2.0): - DoubleConversion - glog - hermes-engine @@ -2017,7 +2017,7 @@ SPEC CHECKSUMS: react-native-config: 86038147314e2e6d10ea9972022aa171e6b1d4d8 react-native-fbsdk-next: de7d8792163c648b27ed853d0dab181cf928aa32 react-native-netinfo: f0a9899081c185db1de5bb2fdc1c88c202a059ac - react-native-safe-area-context: 4532f1a0c5d34a46b9324ccaaedcb5582a302b7d + react-native-safe-area-context: 141eca0fd4e4191288dfc8b96a7c7e1c2983447a react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457 React-nativeconfig: 7af2ccce165f86b233a9f9d63295f6207e62640e React-NativeModulesApple: db1c1ee9dda26c9e58d824b4100fed83add82ae9 @@ -2048,13 +2048,13 @@ SPEC CHECKSUMS: RNAppleAuthentication: e00c76acb03351f5544373c78fa7f359bef6d5d3 RNCAsyncStorage: d35c79ffba52c1013013e16b1fc295aec2feabb6 RNCMaskedView: e07a0b5e9e8d6962826def06e6ff2ecdb815433f - RNGestureHandler: 511250b190a284388f9dd0d2e56c1df76f14cfb8 + RNGestureHandler: 9decfddf99dcf2397b50c9adae0188fc84c74231 RNGoogleSignin: 9e68b9bcc3888219357924e32ee563624745647d RNIap: f3ca6e7597afccb2c1631de97d88f2e33b10dafd RNReanimated: 74413c59c47123d7144db601d065627c75c746a3 - RNScreens: de948b09c9a30f3ea52f9840dd6f8ce92b4e33d3 + RNScreens: b51f1a8be0dd7bb470b757f6cca8ba878acb2000 RNSVG: 50cf2c7018e57cf5d3522d98d0a3a4dd6bf9d093 - RNVectorIcons: ef957b2a1cd5efb71e53397257ec4ccffa34d0c4 + RNVectorIcons: 6382277afab3c54658e9d555ee0faa7a37827136 SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d Yoga: 06fc4b2c3664ae0e278964b8fbcb0ee9d21f0a5a diff --git a/ios/goparking.xcodeproj/project.pbxproj b/ios/goparking.xcodeproj/project.pbxproj index f122823..0815896 100644 --- a/ios/goparking.xcodeproj/project.pbxproj +++ b/ios/goparking.xcodeproj/project.pbxproj @@ -656,7 +656,10 @@ "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", ); - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; @@ -727,7 +730,10 @@ "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", ); - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = true; @@ -806,7 +812,10 @@ "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", ); - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = true; @@ -949,7 +958,10 @@ "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", ); - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = true; @@ -1084,7 +1096,10 @@ "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", ); - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = true; @@ -1215,7 +1230,10 @@ "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", ); - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = true; diff --git a/package-lock.json b/package-lock.json index 5a1d830..923c3e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "kanvas_app", + "name": "goparking", "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "kanvas_app", + "name": "goparking", "version": "0.0.1", "dependencies": { "@invertase/react-native-apple-authentication": "^2.4.0", @@ -14,11 +14,12 @@ "@react-native-community/netinfo": "^11.4.1", "@react-native-google-signin/google-signin": "^13.1.0", "@react-native-masked-view/masked-view": "^0.3.2", - "@react-navigation/drawer": "^6.6.15", - "@react-navigation/material-bottom-tabs": "^6.2.28", - "@react-navigation/native": "^6.1.17", - "@react-navigation/native-stack": "^6.9.26", - "@react-navigation/stack": "^6.3.29", + "@react-navigation/bottom-tabs": "^7.2.0", + "@react-navigation/drawer": "^7.1.1", + "@react-navigation/material-bottom-tabs": "^6.2.29", + "@react-navigation/native": "^7.0.14", + "@react-navigation/native-stack": "^7.2.0", + "@react-navigation/stack": "^7.1.1", "babel-plugin-transform-remove-console": "^6.9.4", "formik": "^2.4.5", "i18n-js": "^4.4.3", @@ -29,18 +30,18 @@ "react-native-deep-linking": "^2.2.0", "react-native-fbsdk-next": "^13.1.4", "react-native-formik": "^1.7.8", - "react-native-gesture-handler": "^2.20.2", + "react-native-gesture-handler": "^2.22.0", "react-native-iap": "^12.15.7", "react-native-keyboard-aware-scroll-view": "^0.9.5", "react-native-modal": "^13.0.1", - "react-native-paper": "^5.12.5", + "react-native-paper": "^5.13.1", "react-native-reanimated": "^3.15.0", "react-native-rename": "^3.2.14", - "react-native-safe-area-context": "^4.14.0", - "react-native-screens": "^4.0.0", + "react-native-safe-area-context": "^4.14.1", + "react-native-screens": "^4.5.0", "react-native-splash-screen": "^3.3.0", "react-native-svg": "^15.1.0", - "react-native-vector-icons": "^10.1.0", + "react-native-vector-icons": "^10.2.0", "styled-components": "^6.1.8", "styled-is": "^1.3.0", "yarn": "^1.22.22", @@ -3721,45 +3722,124 @@ } } }, + "node_modules/@react-navigation/bottom-tabs": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.2.0.tgz", + "integrity": "sha512-1LxjgnbPyFINyf9Qr5d1YE0pYhuJayg5TCIIFQmbcX4PRhX7FKUXV7cX8OzrKXEdZi/UE/VNXugtozPAR9zgvA==", + "dependencies": { + "@react-navigation/elements": "^2.2.5", + "color": "^4.2.3" + }, + "peerDependencies": { + "@react-navigation/native": "^7.0.14", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, + "node_modules/@react-navigation/bottom-tabs/node_modules/@react-navigation/elements": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.2.5.tgz", + "integrity": "sha512-sDhE+W14P7MNWLMxXg1MEVXwkLUpMZJGflE6nQNzLmolJQIHgcia0Mrm8uRa3bQovhxYu1UzEojLZ+caoZt7Fg==", + "dependencies": { + "color": "^4.2.3" + }, + "peerDependencies": { + "@react-native-masked-view/masked-view": ">= 0.2.0", + "@react-navigation/native": "^7.0.14", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0" + }, + "peerDependenciesMeta": { + "@react-native-masked-view/masked-view": { + "optional": true + } + } + }, "node_modules/@react-navigation/core": { - "version": "6.4.16", - "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-6.4.16.tgz", - "integrity": "sha512-UDTJBsHxnzgFETR3ZxhctP+RWr4SkyeZpbhpkQoIGOuwSCkt1SE0qjU48/u6r6w6XlX8OqVudn1Ab0QFXTHxuQ==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.3.1.tgz", + "integrity": "sha512-S3KCGvNsoqVk8ErAtQI2EAhg9185lahF5OY01ofrrD4Ij/uk3QEHHjoGQhR5l5DXSCSKr1JbMQA7MEKMsBiWZA==", "dependencies": { - "@react-navigation/routers": "^6.1.9", + "@react-navigation/routers": "^7.1.2", "escape-string-regexp": "^4.0.0", - "nanoid": "^3.1.23", + "nanoid": "3.3.8", "query-string": "^7.1.3", - "react-is": "^16.13.0", - "use-latest-callback": "^0.1.9" + "react-is": "^18.2.0", + "use-latest-callback": "^0.2.1", + "use-sync-external-store": "^1.2.2" }, "peerDependencies": { - "react": "*" + "react": ">= 18.2.0" + } + }, + "node_modules/@react-navigation/core/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" + }, + "node_modules/@react-navigation/core/node_modules/use-latest-callback": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.3.tgz", + "integrity": "sha512-7vI3fBuyRcP91pazVboc4qu+6ZqM8izPWX9k7cRnT8hbD5svslcknsh3S9BUhaK11OmgTV4oWZZVSeQAiV53SQ==", + "peerDependencies": { + "react": ">=16.8" } }, "node_modules/@react-navigation/drawer": { - "version": "6.6.15", - "resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-6.6.15.tgz", - "integrity": "sha512-GLkFQNxjtmxB/qXSHmu1DfoB89jCzW64tmX68iPndth+9U+0IP27GcCCaMZxQfwj+nI8Kn2zlTlXAZDIIHE+DQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-7.1.1.tgz", + "integrity": "sha512-34UqRS5OLFaNXPs5ocz3Du9c7em0P7fFMPYCZn/MxadDzQ4Mn/74pmJczmiyvyvz8vcWsNRbZ3Qswm0Dv6z60w==", "dependencies": { - "@react-navigation/elements": "^1.3.30", + "@react-navigation/elements": "^2.2.5", "color": "^4.2.3", - "warn-once": "^0.1.0" + "react-native-drawer-layout": "^4.1.1", + "use-latest-callback": "^0.2.1" }, "peerDependencies": { - "@react-navigation/native": "^6.0.0", - "react": "*", + "@react-navigation/native": "^7.0.14", + "react": ">= 18.2.0", "react-native": "*", - "react-native-gesture-handler": ">= 1.0.0", - "react-native-reanimated": ">= 1.0.0", - "react-native-safe-area-context": ">= 3.0.0", - "react-native-screens": ">= 3.0.0" + "react-native-gesture-handler": ">= 2.0.0", + "react-native-reanimated": ">= 2.0.0", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, + "node_modules/@react-navigation/drawer/node_modules/@react-navigation/elements": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.2.5.tgz", + "integrity": "sha512-sDhE+W14P7MNWLMxXg1MEVXwkLUpMZJGflE6nQNzLmolJQIHgcia0Mrm8uRa3bQovhxYu1UzEojLZ+caoZt7Fg==", + "dependencies": { + "color": "^4.2.3" + }, + "peerDependencies": { + "@react-native-masked-view/masked-view": ">= 0.2.0", + "@react-navigation/native": "^7.0.14", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0" + }, + "peerDependenciesMeta": { + "@react-native-masked-view/masked-view": { + "optional": true + } + } + }, + "node_modules/@react-navigation/drawer/node_modules/use-latest-callback": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.3.tgz", + "integrity": "sha512-7vI3fBuyRcP91pazVboc4qu+6ZqM8izPWX9k7cRnT8hbD5svslcknsh3S9BUhaK11OmgTV4oWZZVSeQAiV53SQ==", + "peerDependencies": { + "react": ">=16.8" } }, "node_modules/@react-navigation/elements": { - "version": "1.3.30", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.30.tgz", - "integrity": "sha512-plhc8UvCZs0UkV+sI+3bisIyn78wz9O/BiWZXpounu72k/R/Sj5PuZYFJ1fi6psvriUveMCGh4LeZckAZu2qiQ==", + "version": "1.3.31", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.31.tgz", + "integrity": "sha512-bUzP4Awlljx5RKEExw8WYtif8EuQni2glDaieYROKTnaxsu9kEIA515sXQgUDZU4Ob12VoL7+z70uO3qrlfXcQ==", "peerDependencies": { "@react-navigation/native": "^6.0.0", "react": "*", @@ -3768,11 +3848,11 @@ } }, "node_modules/@react-navigation/material-bottom-tabs": { - "version": "6.2.28", - "resolved": "https://registry.npmjs.org/@react-navigation/material-bottom-tabs/-/material-bottom-tabs-6.2.28.tgz", - "integrity": "sha512-w+rkBOvhPpV5G7Ai9wt86IiGIUBpQUmAywQ3qfCFjP4v2j9yG1x7bu6wWqzzDs4tSIFG7X1HwMzkHOnjo2I0CA==", + "version": "6.2.29", + "resolved": "https://registry.npmjs.org/@react-navigation/material-bottom-tabs/-/material-bottom-tabs-6.2.29.tgz", + "integrity": "sha512-K/RHIXGaBfSpn9ErLyQvm/jYKDpfsG2dpNsRilAClBCodFV99JRvr4xAA6pRyPslj3nv0XjV7ezZRpn1c5ifgg==", "dependencies": { - "@react-navigation/elements": "^1.3.30" + "@react-navigation/elements": "^1.3.31" }, "peerDependencies": { "@react-navigation/native": "^6.0.0", @@ -3784,60 +3864,108 @@ } }, "node_modules/@react-navigation/native": { - "version": "6.1.17", - "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.17.tgz", - "integrity": "sha512-mer3OvfwWOHoUSMJyLa4vnBH3zpFmCwuzrBPlw7feXklurr/ZDiLjLxUScOot6jLRMz/67GyilEYMmP99LL0RQ==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.0.14.tgz", + "integrity": "sha512-Gi6lLw4VOGSWAhmUdJOMauOKGK51/YA1CprjXm91sNfgERWvznqEMw8QmUQx9SEqYfi0LfZhbzpMst09SJ00lw==", "dependencies": { - "@react-navigation/core": "^6.4.16", + "@react-navigation/core": "^7.3.1", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", - "nanoid": "^3.1.23" + "nanoid": "3.3.8", + "use-latest-callback": "^0.2.1" }, "peerDependencies": { - "react": "*", + "react": ">= 18.2.0", "react-native": "*" } }, "node_modules/@react-navigation/native-stack": { - "version": "6.9.26", - "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.9.26.tgz", - "integrity": "sha512-++dueQ+FDj2XkZ902DVrK79ub1vp19nSdAZWxKRgd6+Bc0Niiesua6rMCqymYOVaYh+dagwkA9r00bpt/U5WLw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.2.0.tgz", + "integrity": "sha512-mw7Nq9qQrGsmJmCTwIIWB7yY/3tWYXvQswx+HJScGAadIjemvytJXm1fcl3+YZ9T9Ym0aERcVe5kDs+ny3X4vA==", "dependencies": { - "@react-navigation/elements": "^1.3.30", - "warn-once": "^0.1.0" + "@react-navigation/elements": "^2.2.5", + "warn-once": "^0.1.1" }, "peerDependencies": { - "@react-navigation/native": "^6.0.0", - "react": "*", + "@react-navigation/native": "^7.0.14", + "react": ">= 18.2.0", "react-native": "*", - "react-native-safe-area-context": ">= 3.0.0", - "react-native-screens": ">= 3.0.0" + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, + "node_modules/@react-navigation/native-stack/node_modules/@react-navigation/elements": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.2.5.tgz", + "integrity": "sha512-sDhE+W14P7MNWLMxXg1MEVXwkLUpMZJGflE6nQNzLmolJQIHgcia0Mrm8uRa3bQovhxYu1UzEojLZ+caoZt7Fg==", + "dependencies": { + "color": "^4.2.3" + }, + "peerDependencies": { + "@react-native-masked-view/masked-view": ">= 0.2.0", + "@react-navigation/native": "^7.0.14", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0" + }, + "peerDependenciesMeta": { + "@react-native-masked-view/masked-view": { + "optional": true + } + } + }, + "node_modules/@react-navigation/native/node_modules/use-latest-callback": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.3.tgz", + "integrity": "sha512-7vI3fBuyRcP91pazVboc4qu+6ZqM8izPWX9k7cRnT8hbD5svslcknsh3S9BUhaK11OmgTV4oWZZVSeQAiV53SQ==", + "peerDependencies": { + "react": ">=16.8" } }, "node_modules/@react-navigation/routers": { - "version": "6.1.9", - "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.1.9.tgz", - "integrity": "sha512-lTM8gSFHSfkJvQkxacGM6VJtBt61ip2XO54aNfswD+KMw6eeZ4oehl7m0me3CR9hnDE4+60iAZR8sAhvCiI3NA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.1.2.tgz", + "integrity": "sha512-emdEjpVDK8zbiu2GChC8oYIAub9i/OpNuQJekVsbyFCBz4/TzaBzms38Q53YaNhdIFNmiYLfHv/Y1Ub7KYfm3w==", "dependencies": { - "nanoid": "^3.1.23" + "nanoid": "3.3.8" } }, "node_modules/@react-navigation/stack": { - "version": "6.3.29", - "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-6.3.29.tgz", - "integrity": "sha512-tzlGkoRgB6P7vgw7rHuWo3TL7Gzu6xh5LMf+zSdCuEiKp/qASzxYfnTEr9tOLbVs/gf+qeukEDheCSAJKVpBXw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-7.1.1.tgz", + "integrity": "sha512-CBTKQlIkELp05zRiTAv5Pa7OMuCpKyBXcdB3PGMN2Mm55/5MkDsA1IaZorp/6TsVCdllITD6aTbGX/HA/88A6w==", "dependencies": { - "@react-navigation/elements": "^1.3.30", - "color": "^4.2.3", - "warn-once": "^0.1.0" + "@react-navigation/elements": "^2.2.5", + "color": "^4.2.3" }, "peerDependencies": { - "@react-navigation/native": "^6.0.0", - "react": "*", + "@react-navigation/native": "^7.0.14", + "react": ">= 18.2.0", "react-native": "*", - "react-native-gesture-handler": ">= 1.0.0", - "react-native-safe-area-context": ">= 3.0.0", - "react-native-screens": ">= 3.0.0" + "react-native-gesture-handler": ">= 2.0.0", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, + "node_modules/@react-navigation/stack/node_modules/@react-navigation/elements": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.2.5.tgz", + "integrity": "sha512-sDhE+W14P7MNWLMxXg1MEVXwkLUpMZJGflE6nQNzLmolJQIHgcia0Mrm8uRa3bQovhxYu1UzEojLZ+caoZt7Fg==", + "dependencies": { + "color": "^4.2.3" + }, + "peerDependencies": { + "@react-native-masked-view/masked-view": ">= 0.2.0", + "@react-navigation/native": "^7.0.14", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0" + }, + "peerDependenciesMeta": { + "@react-native-masked-view/masked-view": { + "optional": true + } } }, "node_modules/@sideway/address": { @@ -10093,9 +10221,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "funding": [ { "type": "github", @@ -11148,6 +11276,28 @@ "resolved": "https://registry.npmjs.org/react-native-deep-linking/-/react-native-deep-linking-2.2.0.tgz", "integrity": "sha512-PKShbOsa/oxjSzZ/Bag98O/J+jaZOI6ic5YdanPirTpRAraAvKUzJWQUhE5Yy0Isl9yfIkSogOClE9BRfSyUbA==" }, + "node_modules/react-native-drawer-layout": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/react-native-drawer-layout/-/react-native-drawer-layout-4.1.1.tgz", + "integrity": "sha512-ob6O3ph7PZ3A2FpdlsSxHuMpHDXREZPR8A6S3q0dSxV7i6d+8Z6CPCTbegfN2QZyizSow9NLrKyXP93tlqZ3dA==", + "dependencies": { + "use-latest-callback": "^0.2.1" + }, + "peerDependencies": { + "react": ">= 18.2.0", + "react-native": "*", + "react-native-gesture-handler": ">= 2.0.0", + "react-native-reanimated": ">= 2.0.0" + } + }, + "node_modules/react-native-drawer-layout/node_modules/use-latest-callback": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.3.tgz", + "integrity": "sha512-7vI3fBuyRcP91pazVboc4qu+6ZqM8izPWX9k7cRnT8hbD5svslcknsh3S9BUhaK11OmgTV4oWZZVSeQAiV53SQ==", + "peerDependencies": { + "react": ">=16.8" + } + }, "node_modules/react-native-fbsdk-next": { "version": "13.1.4", "resolved": "https://registry.npmjs.org/react-native-fbsdk-next/-/react-native-fbsdk-next-13.1.4.tgz", @@ -11180,14 +11330,13 @@ } }, "node_modules/react-native-gesture-handler": { - "version": "2.20.2", - "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.20.2.tgz", - "integrity": "sha512-HqzFpFczV4qCnwKlvSAvpzEXisL+Z9fsR08YV5LfJDkzuArMhBu2sOoSPUF/K62PCoAb+ObGlTC83TKHfUd0vg==", + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.22.0.tgz", + "integrity": "sha512-m5Ps1cOSxSiMP4re+XsbeWcC9DNJuIEjMSmtUxBdyfYEJtdu5iAAiX7KlHHrf2mnK4I/56Ncy4PvPKWBwSpWpQ==", "dependencies": { "@egjs/hammerjs": "^2.0.17", "hoist-non-react-statics": "^3.3.0", - "invariant": "^2.2.4", - "prop-types": "^15.7.2" + "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", @@ -11252,9 +11401,9 @@ } }, "node_modules/react-native-paper": { - "version": "5.12.5", - "resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.12.5.tgz", - "integrity": "sha512-Qpqd1g9PClmjGj/Dkr1htAwt8cTZ3SCHVmhttxRuG/QML7KzHm5ArLNgR7vz5dW1EwJqTmyl/3gd6gnrtw90mw==", + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.13.1.tgz", + "integrity": "sha512-8frKVKJ5JBd8WL1G3tpcYzOgK40kxkD/U+yLHGKNeLnD6v1Qc9W6DxWTHWN7lsX/DPYnhgvw1aKkYaPTmDj5pg==", "dependencies": { "@callstack/react-theme-provider": "^3.0.9", "color": "^3.1.2", @@ -11377,18 +11526,18 @@ } }, "node_modules/react-native-safe-area-context": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.14.0.tgz", - "integrity": "sha512-/SyYpCulWQOnnXhRq6wepkhoyQMowHm1ptDyRz20s+YS/R9mbd+mK+jFyFCyXFJn8jp7vFl43VUCgspuOiEbwA==", + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.14.1.tgz", + "integrity": "sha512-+tUhT5WBl8nh5+P+chYhAjR470iCByf9z5EYdCEbPaAK3Yfzw+o8VRPnUgmPAKlSccOgQBxx3NOl/Wzckn9ujg==", "peerDependencies": { "react": "*", "react-native": "*" } }, "node_modules/react-native-screens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.0.0.tgz", - "integrity": "sha512-QGQ8+d90chOZ9JwA2K01nFzrGCTMNjsiAKJGPUXcLEiIF77/VSjLjQE9ZluMtkva0gzGI9tb/yxETkJnkw1iag==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.5.0.tgz", + "integrity": "sha512-yBWeN5EHNeew9f0ia9VE7JSlUQzCZEwkb87r7A7/Sg41OJHuRKHNRhmdCOiMBUqwwQi3F+b4NZGywjeM/gWMyg==", "dependencies": { "react-freeze": "^1.0.0", "warn-once": "^0.1.0" @@ -11420,9 +11569,9 @@ } }, "node_modules/react-native-vector-icons": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.1.0.tgz", - "integrity": "sha512-fdQjCHIdoXmRoTZ5gvN1FmT4sGLQ2wmQiNZHKJQUYnE2tkIwjGnxNch+6Nd4lHAACvMWO7LOzBNot2u/zlOmkw==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.2.0.tgz", + "integrity": "sha512-n5HGcxUuVaTf9QJPs/W22xQpC2Z9u0nb0KgLPnVltP8vdUvOp6+R26gF55kilP/fV4eL4vsAHUqUjewppJMBOQ==", "dependencies": { "prop-types": "^15.7.2", "yargs": "^16.1.1" @@ -13240,6 +13389,14 @@ "react": ">=16.8" } }, + "node_modules/use-sync-external-store": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", + "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 0e3fcf3..0b2669c 100644 --- a/package.json +++ b/package.json @@ -21,11 +21,12 @@ "@react-native-community/netinfo": "^11.4.1", "@react-native-google-signin/google-signin": "^13.1.0", "@react-native-masked-view/masked-view": "^0.3.2", - "@react-navigation/drawer": "^6.6.15", - "@react-navigation/material-bottom-tabs": "^6.2.28", - "@react-navigation/native": "^6.1.17", - "@react-navigation/native-stack": "^6.9.26", - "@react-navigation/stack": "^6.3.29", + "@react-navigation/bottom-tabs": "^7.2.0", + "@react-navigation/drawer": "^7.1.1", + "@react-navigation/material-bottom-tabs": "^6.2.29", + "@react-navigation/native": "^7.0.14", + "@react-navigation/native-stack": "^7.2.0", + "@react-navigation/stack": "^7.1.1", "babel-plugin-transform-remove-console": "^6.9.4", "formik": "^2.4.5", "i18n-js": "^4.4.3", @@ -36,18 +37,18 @@ "react-native-deep-linking": "^2.2.0", "react-native-fbsdk-next": "^13.1.4", "react-native-formik": "^1.7.8", - "react-native-gesture-handler": "^2.20.2", + "react-native-gesture-handler": "^2.22.0", "react-native-iap": "^12.15.7", "react-native-keyboard-aware-scroll-view": "^0.9.5", "react-native-modal": "^13.0.1", - "react-native-paper": "^5.12.5", + "react-native-paper": "^5.13.1", "react-native-reanimated": "^3.15.0", "react-native-rename": "^3.2.14", - "react-native-safe-area-context": "^4.14.0", - "react-native-screens": "^4.0.0", + "react-native-safe-area-context": "^4.14.1", + "react-native-screens": "^4.5.0", "react-native-splash-screen": "^3.3.0", "react-native-svg": "^15.1.0", - "react-native-vector-icons": "^10.1.0", + "react-native-vector-icons": "^10.2.0", "styled-components": "^6.1.8", "styled-is": "^1.3.0", "yarn": "^1.22.22", diff --git a/src/assets/icons/bell.tsx b/src/assets/icons/bell.tsx index 9aaed63..d36614c 100644 --- a/src/assets/icons/bell.tsx +++ b/src/assets/icons/bell.tsx @@ -1,13 +1,15 @@ import * as React from 'react'; import Svg, { SvgProps, Path, G, Defs, ClipPath } from "react-native-svg" import { Colors } from 'styles'; +import { DEFAULT_THEME } from 'styles/theme'; const BellV2 = (props: any) => { const { - color = Colors.WHITE, - width = 24, - height = 24, + color = DEFAULT_THEME.primary, + width = 26, + height = 26, + fill = DEFAULT_THEME.primary, } = props; return ( @@ -15,12 +17,20 @@ const BellV2 = (props: any) => { xmlns="http://www.w3.org/2000/svg" width={width} height={height} - fill="none" - viewBox="0 0 20 22" + fill={fill} + viewBox="0 0 23 23" {...props} > - - + + { + + const { + fill = '#424242', + width = 24, + height = 25, + } = props; + + return ( + + + + ); +}; + +export default LockIcon; diff --git a/src/assets/icons/tab-bookmark-icon.tsx b/src/assets/icons/tab-bookmark-icon.tsx new file mode 100644 index 0000000..1f1c934 --- /dev/null +++ b/src/assets/icons/tab-bookmark-icon.tsx @@ -0,0 +1,28 @@ +import * as React from 'react'; +import Svg, { SvgProps, Path } from 'react-native-svg'; + +const TabBookmarkIcon = (props: SvgProps) => { + + const { + width = 25, + height = 24, + fill = '#AAA', + } = props; + + return ( + + + + ); +}; + +export default TabBookmarkIcon; diff --git a/src/assets/icons/tab-home-icon.tsx b/src/assets/icons/tab-home-icon.tsx new file mode 100644 index 0000000..1f322e1 --- /dev/null +++ b/src/assets/icons/tab-home-icon.tsx @@ -0,0 +1,27 @@ +import * as React from 'react'; +import Svg, { SvgProps, Path } from 'react-native-svg'; + +const TabHomeIcon = (props: SvgProps) => { + + const { + width = 24, + height = 24, + fill = '#F8D73A', + } = props; + + return ( + + + + ); +} +export default TabHomeIcon; diff --git a/src/assets/icons/tab-receipt-icon.tsx b/src/assets/icons/tab-receipt-icon.tsx new file mode 100644 index 0000000..fa0488d --- /dev/null +++ b/src/assets/icons/tab-receipt-icon.tsx @@ -0,0 +1,28 @@ +import * as React from 'react'; +import Svg, { SvgProps, Path } from 'react-native-svg'; + +const TabReceiptIcon = (props: SvgProps) => { + + const { + width = 25, + height = 24, + fill = '#AAA', + } = props; + + return ( + + + + + ); +} +export default TabReceiptIcon; diff --git a/src/assets/icons/tab-time-icon.tsx b/src/assets/icons/tab-time-icon.tsx new file mode 100644 index 0000000..287711f --- /dev/null +++ b/src/assets/icons/tab-time-icon.tsx @@ -0,0 +1,32 @@ +import * as React from 'react'; +import Svg, { SvgProps, Path } from 'react-native-svg'; + +const TabTimeIcon = (props: SvgProps) => { + + const { + width = 25, + height = 24, + fill = '#AAA', + } = props; + + return ( + + + + + ); +}; + +export default TabTimeIcon; diff --git a/src/assets/icons/tab-user-icon.tsx b/src/assets/icons/tab-user-icon.tsx new file mode 100644 index 0000000..28e5d88 --- /dev/null +++ b/src/assets/icons/tab-user-icon.tsx @@ -0,0 +1,28 @@ +import * as React from 'react'; +import Svg, { SvgProps, Path } from 'react-native-svg'; + +const TabUserIcon = (props: SvgProps) => { + + const { + width = 24, + height = 24, + fill = '#AAA', + } = props; + + return ( + + + + ); +}; + +export default TabUserIcon; diff --git a/src/assets/icons/user-icon.tsx b/src/assets/icons/user-icon.tsx new file mode 100644 index 0000000..96453ba --- /dev/null +++ b/src/assets/icons/user-icon.tsx @@ -0,0 +1,28 @@ +import * as React from 'react'; +import Svg, { SvgProps, Path } from 'react-native-svg'; + +const UserIcon = (props: SvgProps) => { + + const { + fill = '#424242', + width = 24, + height = 25, + } = props; + + return ( + + + + ); +}; + +export default UserIcon; diff --git a/src/assets/images/go_parking_logo.png b/src/assets/images/go_parking_logo.png new file mode 100644 index 0000000..e26a350 Binary files /dev/null and b/src/assets/images/go_parking_logo.png differ diff --git a/src/components/atoms/small-button.tsx b/src/components/atoms/small-button.tsx index bee24a9..36ca532 100644 --- a/src/components/atoms/small-button.tsx +++ b/src/components/atoms/small-button.tsx @@ -24,7 +24,7 @@ const Container = styled.TouchableOpacity` width: 50px; height: 50px; border-radius: 8px; - background-color: ${Colors.PRIMARY}; + background-color: ${Colors.WHITE}; margin-bottom: 10px; justify-content: center; align-items: center; diff --git a/src/components/molecules/line-text-input.tsx b/src/components/molecules/line-text-input.tsx index da73830..f850501 100644 --- a/src/components/molecules/line-text-input.tsx +++ b/src/components/molecules/line-text-input.tsx @@ -13,13 +13,14 @@ import IconButton from 'components/atoms/icon-button'; const Container = styled.View` border-width: 1px; - height: 42px; + height: 50px; border-width: 1px; border-color: ${props => props.isFocused ? DEFAULT_THEME.inputFocus : DEFAULT_THEME.boderColor}; - border-radius: 4px; + border-radius: 10px; padding-horizontal: 10px; - background-color: ${DEFAULT_THEME.inputBg}; + background-color: rgba(244, 244, 244, 1); justify-content: center; + align-items: center; flex-direction: row; ${is('error')` border-color: ${DEFAULT_THEME.error}; @@ -85,6 +86,11 @@ interface IProps { isFocused?: boolean; error?: boolean | string; customRef?: any; + leftIconType?: string; + leftIconSize?: number; + leftIconColor?: string; + leftIconName?: string; + customLeftIcon?: () => JSX.Element; } const LineTextInput = ({ @@ -106,6 +112,11 @@ const LineTextInput = ({ error, customRef, containerStyle, + leftIconName = '', + leftIconType = 'Ionicons', + leftIconSize = 24, + leftIconColor = DEFAULT_THEME.placeHolderText, + customLeftIcon, ...props }: IProps) => { @@ -143,7 +154,31 @@ const LineTextInput = ({ ); } return ( - + + + + {customLeftIcon ? ( + <> + {customLeftIcon()} + + ) : ( + togglePasswordVisibility(!showPassword)} + /> + )} + + void; + onBackDetail?: () => void; + diableBackButton?: boolean; + backIconColor?: string; + hasBackButton?: boolean; +} + +const SCREEN_MARGIN = 15; +const HEADER_HEIGHT = Platform.OS === 'ios' ? 150 : 90; +const HEADER_PADDING_TOP = Platform.OS === 'ios' ? 60 : 1; + +const Container = styled.View` + width: 100%; + height: ${HEADER_HEIGHT}px; + padding-top: ${HEADER_PADDING_TOP}px; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding-horizontal: 20px; + padding-bottom: ${SCREEN_MARGIN}px; + background-color: ${DEFAULT_THEME.primary}; +`; + +// @ts-ignore +const Title = styled(Text)` + color: ${Colors.BLACK}; + font-size: ${Typography.FONT_SIZE_16}px; + line-height: ${Typography.FONT_SIZE_20}px; + width: 200px; + padding-top: 10px; + font-weight: bold; +`; + +const SubTitle = styled(Text)` + color: ${Colors.BLACK}; + font-size: ${Typography.FONT_SIZE_10}px; + line-height: ${Typography.FONT_SIZE_12}px; + padding-top: 5px; +`; + +const CustomHeader = styled.View` + position: absolute; + align-items: center; + align-self: center; + justify-content: center; + width: 100%; + margin-horizontal: ${SCREEN_MARGIN}px; + padding-bottom: ${SCREEN_MARGIN}px; + z-index: -1; +`; + +const IconContainer = styled.TouchableOpacity` + height: 50px; + width: 50px; + border-radius: 15px; + align-items: center; + justify-content: center; + background-color: ${DEFAULT_THEME.background}; +`; + +const MainHeader = (props: IProps) => { + + // Props + const { + title, + titleProps, + subtitle, + subtitleProps, + customHeader, + rightButtonComponent, + leftButtonComponent, + onLeftButtonPress = () => navigation.goBack(), + style, + closeButtonType = 'BACK', + buttonTitleProps, + onBackDetail, + diableBackButton = false, + hasBackButton = true, + backIconColor = Colors.WHITE, + barStyle = 'dark-content', + } = props; + + // Hooks + const navigation = useNavigation(); + + const onBackPress = () => { + onLeftButtonPress(); + onBackDetail && onBackDetail(); + }; + + const openNotifications = () => { + navigation.navigate('Notifications'); + }; + + + return ( + + + + {customHeader ? ( + + {customHeader} + + ) : ( + + + {title} + + + {subtitle} + + + )} + + {rightButtonComponent ? ( + <> + {rightButtonComponent} + + ) : ( + + + + )} + + ); +}; + +export default MainHeader; diff --git a/src/components/molecules/tab-icon.tsx b/src/components/molecules/tab-icon.tsx new file mode 100644 index 0000000..cb68ce0 --- /dev/null +++ b/src/components/molecules/tab-icon.tsx @@ -0,0 +1,87 @@ +/* eslint-disable @typescript-eslint/camelcase */ +import React, { useContext } from 'react'; +import styled from 'styled-components'; +import { useNavigation } from '@react-navigation/native'; + +// Styles +import { Colors } from 'styles'; +import { DEFAULT_THEME } from 'styles/theme'; + +// Utils +import { sendAmplitudeEvent } from 'utils'; + +// Context +import { UserContext } from 'components/context/user-context'; +import KanvasLogo from 'assets/icons/kanvas-logo'; +import TabHomeIcon from 'assets/icons/tab-home-icon'; +import TabReceiptIcon from 'assets/icons/tab-receipt-icon'; +import TabUserIcon from 'assets/icons/tab-user-icon'; +import TabTimeIcon from 'assets/icons/tab-time-icon'; +import TabBookmarkIcon from 'assets/icons/tab-bookmark-icon'; + +// Icons + +interface IProps { + name: string; + focused: boolean; +} + +const Button = styled.TouchableOpacity` + height: 100%; + width: 100%; + justify-content: center; + align-items: center; + `; + +const TabIcon = (props: IProps) => { + + const { + name, + focused, + } = props; + + // Hooks + const navigation = useNavigation(); + + // Context + const { userData } = useContext(UserContext) + + const tintColor = focused ? 'rgba(248, 215, 58, 1)' : 'rgba(170, 170, 170, 1)'; + + switch (name) { + case 'home': + return ( + + ); + case 'parkinghistory': + return ( + + ); + case 'userprofile': + return ( + + ); + case 'parkingscreen': + return ( + + ); + case 'saveplacesscreen': + return ( + + ); + default: + return null; + } +}; + +export default TabIcon; diff --git a/src/components/molecules/text-input.tsx b/src/components/molecules/text-input.tsx index d13a4cb..d22e871 100644 --- a/src/components/molecules/text-input.tsx +++ b/src/components/molecules/text-input.tsx @@ -88,6 +88,7 @@ const TextInput = (props: IProps) => { error = false | '', isFocused, customRef, + customLeftIcon, } = props; return ( @@ -124,6 +125,7 @@ const TextInput = (props: IProps) => { secureTextEntry={secureTextEntry} error={error} containerStyle={containerStyle} + customLeftIcon={customLeftIcon} {...inputProps} /> diff --git a/src/components/organisms/view-container.tsx b/src/components/organisms/view-container.tsx new file mode 100644 index 0000000..7190b55 --- /dev/null +++ b/src/components/organisms/view-container.tsx @@ -0,0 +1,43 @@ +import React, { useState, useCallback, useEffect } from "react"; +import styled from "styled-components/native"; +import { DEFAULT_THEME } from "styles/theme"; + +interface IViewContainerProps { + +}; + +const Container = styled.View` + flex: 1px; +`; + +const HeaderView = styled.View` + width: 100%; + height: 25%; + background-color: ${DEFAULT_THEME.primary}; + position: absolute; + top: 0; +`; + +const ContentView = styled.View` + flex: 1; + background-color: ${DEFAULT_THEME.background}; +`; + +export const ViewContainer = (props: IViewContainerProps) => { + + // Props + const { + children, + } = props; + + return ( + + + + {children} + + + ); +}; + +export default ViewContainer; diff --git a/src/locales/en.ts b/src/locales/en.ts index 84b0274..711a452 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -5,12 +5,13 @@ export default { email: 'Email', displayName: 'Display Name', welcome: 'Welcome', - placeholderMail: 'Enter your email', + placeholderMail: 'Email address', password: 'Password', + passwordConfirmation: 'Password confirmation', placeholderPassword: 'Enter your password', signIn: 'Sign In', signUp: 'Sign Up', - forgotPassword: 'Forgot Password', + recoverPassword: 'Recover password', signUpNow: 'Sign Up Now', signingIn: 'Signing In...', error: 'Error', @@ -43,4 +44,17 @@ export default { savingChanges: 'Saving changes...', saveChanges: 'Save changes', notification: 'Notification', + login: 'Login', + loginMsg: 'Welcome back! Enter your details below', + notAMember: 'Not a member?', + registerNow: 'Register Now', + orContinueWith: 'Or continue with', + createYourAccount: 'Create your Account', + alreadyHaveAnAccount: 'Already have an account?', + parkingSesion: 'Parking Session', + parkingSesionMsg: 'Manage and enhance your recent parking sessions', + history: 'History', + historyMsg: 'Your Transactions at a Glance', + savedPlaces: 'Saved Places', + savedPlacesMsg: 'Discover Your Saved Locations', }; diff --git a/src/navigations/main-stack.tsx b/src/navigations/main-stack.tsx index b21e879..85de530 100644 --- a/src/navigations/main-stack.tsx +++ b/src/navigations/main-stack.tsx @@ -2,6 +2,7 @@ import React, { useEffect, useReducer, useMemo } from 'react'; import { createStackNavigator } from '@react-navigation/stack'; import AsyncStorage from '@react-native-async-storage/async-storage'; +import NetInfo, { useNetInfoInstance } from '@react-native-community/netinfo'; // Scenes import HomeStack from './stacks/home-stack'; @@ -21,72 +22,119 @@ import { USER_DATA_UPDATE, SIGN_UP, UPDATE_TOKEN, + HAS_INTERNET, } from 'utils/constants'; // core import { client } from 'core/kanvas_client'; import kanvasService from 'core/services/kanvas-service'; import authService from 'core/services/auth-service'; +import NavigationService from './navigation-service'; // Constants const Stack = createStackNavigator(); -const initialState = { - isLoading: true, - isSignout: false, - userToken: null, - refresh_token: null, - userData: null, -}; +const MainStack = ({ navigation }) => { -const reducer = (prevState, action) => { - switch (action.type) { - case SIGN_IN: - case SIGN_UP: - return { - ...prevState, - isSignout: false, - userToken: action.token, - refresh_token: action.refresh_token, - userData: action.user, - isLoading: false, - }; - case REFRESH_TOKEN: - return { - ...prevState, - userToken: action.token, - refresh_token: action.refresh_token, - userData: action.user, - isLoading: false, - }; - case USER_DATA_UPDATE: - return { - ...prevState, - userData: action.user, - isLoading: false, - }; - case SIGN_OUT: - return { - ...prevState, - isSignout: true, - userToken: null, - refresh_token: null, - userData: null, - }; - case UPDATE_TOKEN: - return { - ...prevState, - userToken: action.token, - refresh_token: action.refresh_token, - }; - default: - return prevState; - } -}; + // Hooks + // Hooks + const { + netInfo, + refresh, + } = useNetInfoInstance(); -const MainStack = ({ navigation }) => { - const AsyncKeys = [AUTH_TOKEN, USER_DATA, REFRESH_TOKEN]; - const [state, dispatch] = useReducer(reducer, initialState); + const AsyncKeys = [ + AUTH_TOKEN, + USER_DATA, + REFRESH_TOKEN, + ]; + + const [state, dispatch] = React.useReducer( + (prevState, action) => { + switch (action.type) { + case SIGN_IN: + return { + ...prevState, + isSignout: false, + userToken: action.token, + refresh_token: action.refresh_token, + userData: action.user, + isLoading: false, + }; + case SIGN_UP: + return { + ...prevState, + isSignout: false, + userToken: action.token, + refresh_token: action.refresh_token, + userData: action.user, + isLoading: false, + }; + case REFRESH_TOKEN: + return { + ...prevState, + userToken: action.token, + refresh_token: action.refresh_token, + userData: action.user, + isLoading: false, + }; + case USER_DATA_UPDATE: + return { + ...prevState, + userData: action.user, + isLoading: false, + }; + case SIGN_OUT: + return { + isLoading: true, + isSignout: true, + userToken: null, + refresh_token: null, + userData: null, + isConnected: true, + }; + case UPDATE_TOKEN: + return { + ...prevState, + userToken: action.token, + refresh_token: action.refresh_token, + }; + case HAS_INTERNET: + return { + ...prevState, + isConnected: action.isConnected, + }; + } + }, + { + isLoading: true, + isSignout: false, + userToken: null, + refresh_token: null, + userData: null, + isConnected: netInfo?.isConnected, + iAP_products: [], + }, + ); + + const onConnectionChange = async (hasInternet: boolean) => { + if (!hasInternet && hasInternet !== null) { + console.log('No internet connection', hasInternet); + // Toast.show(, Toast.Duration.STATIC, Toast.Position.BOTTOM); + dispatch({ type: HAS_INTERNET, isConnected: false }); + return; + } + }; + + useEffect(() => { + if (!netInfo?.isConnected) { + onConnectionChange(netInfo?.isConnected); + } + if (netInfo?.isConnected) { + // Toast.hide(); + dispatch({ type: HAS_INTERNET, isConnected: netInfo?.isConnected }); + } + }, [netInfo?.isConnected]); const onRefreshToken = async () => { try { @@ -121,22 +169,32 @@ const MainStack = ({ navigation }) => { useEffect(() => { const bootstrapAsync = async () => { + let userToken; + let userData; try { const token = await AsyncStorage.getItem(AUTH_TOKEN); - if (token) { + userToken = token; + if (userToken) { onRefreshToken(); onUserUpdate(); } const user = await AsyncStorage.getItem(USER_DATA); - const userInfo = JSON.parse(user || '{}'); - dispatch({ type: REFRESH_TOKEN, token, user: userInfo }); + const userInfo = JSON.parse(user || ''); // Provide a default value of an empty string + userData = userInfo; } catch (e) { await AsyncStorage.multiRemove(AsyncKeys); - dispatch({ type: SIGN_OUT }); + dispatch({ type: SIGN_OUT }); // Restoring token failed } + dispatch({ + type: REFRESH_TOKEN, + token: userToken, + user: userData, + isConnected: netInfo?.isConnected, + }); }; bootstrapAsync(); + NavigationService.setTopLevelNavigator(navigation); }, []); const onUserLogout = async () => { @@ -150,35 +208,43 @@ const MainStack = ({ navigation }) => { } }; - const authContext = useMemo( + const authContext = React.useMemo( () => ({ signIn: async data => { - console.log('data', data); - await AsyncStorage.multiSet([ - [AUTH_TOKEN, data.token], - [USER_DATA, JSON.stringify(data.user)], - [REFRESH_TOKEN, data.refresh_token], - ]); - dispatch({ type: SIGN_IN, token: data.token, user: data.user, refresh_token: data.refresh_token }); + AsyncStorage.setItem(AUTH_TOKEN, data.token); + AsyncStorage.setItem(USER_DATA, JSON.stringify(data.user)); + AsyncStorage.setItem(REFRESH_TOKEN, data.refresh_token); + dispatch({ + type: SIGN_IN, + token: data.token, + user: data.user, + refresh_token: data.refresh_token, + }); }, signUp: async data => { - await AsyncStorage.multiSet([ - [AUTH_TOKEN, data.token], - [USER_DATA, JSON.stringify(data.user)], - [REFRESH_TOKEN, data.refresh_token], - ]); - dispatch({ type: SIGN_UP, token: data.token, user: data.user, refresh_token: data.refresh_token }); + AsyncStorage.setItem(AUTH_TOKEN, data.token); + AsyncStorage.setItem(USER_DATA, JSON.stringify(data.user)); + AsyncStorage.setItem(REFRESH_TOKEN, data.refresh_token); + dispatch({ + type: SIGN_UP, + token: data.token, + user: data.user, + refresh_token: data.refresh_token, + }); }, signOut: async () => { onUserLogout(); dispatch({ type: SIGN_OUT }); }, - updateUserData: async data => { - await AsyncStorage.setItem(USER_DATA, JSON.stringify(data.user || data)); - dispatch({ type: USER_DATA_UPDATE, user: data.user || data }); + updateUserData: async (data: IUser) => { + AsyncStorage.setItem(USER_DATA, JSON.stringify(data)); + dispatch({ + type: USER_DATA_UPDATE, + user: data + }); }, }), - [] + [], ); return ( @@ -190,11 +256,19 @@ const MainStack = ({ navigation }) => { isLoading: state.isLoading, isUserLogged: !!state.userData?.id, }}> - + {state.userToken == null ? ( - + ) : ( - + )} diff --git a/src/navigations/navigation-service.ts b/src/navigations/navigation-service.ts new file mode 100644 index 0000000..2749f7d --- /dev/null +++ b/src/navigations/navigation-service.ts @@ -0,0 +1,41 @@ +import { CommonActions, StackActions } from '@react-navigation/native'; + +class NavigationService { + private static navigator: any; + + public static setTopLevelNavigator(navigatorRef: any) { + this.navigator = navigatorRef; + } + + public static navigate(routeName: string, params?: any) { + this.navigator.dispatch( + CommonActions.navigate({ + name: routeName, + params, + }), + ); + } + + public static setCustomParams(params: any, routeKey: string) { + this.navigator.dispatch({ + ...CommonActions.setParams({ params }), + source: routeKey, + }); + } + + public static navigateToStack(stackName: string, action = {}) { + const navigateAction = CommonActions.navigate(stackName, action); + this.navigator.dispatch(navigateAction); + } + + public static push(routeName: string, routeParams?: any) { + const pushAction = StackActions.push(routeName, routeParams); + this.navigator.dispatch(pushAction); + } + + public static dispatch(action: any) { + this.navigator.dispatch(action); + } +} + +export default NavigationService; diff --git a/src/navigations/stacks/home-stack.tsx b/src/navigations/stacks/home-stack.tsx index d1d9607..08d3e99 100644 --- a/src/navigations/stacks/home-stack.tsx +++ b/src/navigations/stacks/home-stack.tsx @@ -1,39 +1,79 @@ +/* eslint-disable react/no-unstable-nested-components */ +/* eslint-disable react-native/no-inline-styles */ +/* eslint-disable prettier/prettier */ + // Modules -import React, { useEffect } from 'react'; +import React, { memo, useContext, useEffect } from 'react'; import { createStackNavigator } from '@react-navigation/stack'; -import { createDrawerNavigator } from '@react-navigation/drawer'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; // Screens -import { navigationScreen } from 'navigations/navigation-screen'; import { Home } from 'screens/home'; import { Settings } from 'screens/settings'; -import { DrawerContent } from 'components/molecules/drawer-content'; + +// Styles import { Colors } from 'styles'; +import { DEFAULT_THEME, theme } from 'styles/theme'; + +// Molecules +import TabIcon from 'components/molecules/tab-icon'; + +// Context +import { UserContext } from 'components/context/user-context'; + +// Navigations +import { navigationScreen } from 'navigations/navigation-screen'; +import ReceiptScreen from 'screens/parking-history'; +import UserProfile from 'screens/user-profile'; +import SavePlacesScreen from 'screens/save-places/indext'; +import ParkingScreen from 'screens/parking'; + const Stack = createStackNavigator(); -const Drawer = createDrawerNavigator(); +const Tab = createBottomTabNavigator(); + +const TabNavigatior = ({ navigation }) => { + + const { userToken } = useContext(UserContext); -const DrawerNavigator = ({ navigation }) => { return ( - } - screenOptions={{ + screenOptions={({ route }) => ({ + tabBarShowLabel: false, headerShown: false, - drawerActiveBackgroundColor: Colors.PRIMARY_CLEAR, - drawerLabelStyle: { color: Colors.PRIMARY }, - }} + tabBarIcon: ({ focused }) => , + tabBarStyle: { + backgroundColor: 'rgba(66, 66, 66, 1)', + borderTopColor: 'rgba(24, 24, 24, 0.16)', + shadowRadius: 0, + shadowOffset: { + height: 0, + }, + }, + })} > - - - + + + + + + + ); }; -const HomeStack = ({ navigation }) => { + +const HomeStack = ({ navigation, route }) => { return ( - - + + + {navigationScreen.map((navScreen, index) => { return ( @@ -48,6 +88,7 @@ const HomeStack = ({ navigation }) => { /> ); })} + ); }; diff --git a/src/screens/home/index.tsx b/src/screens/home/index.tsx index 88772ea..680d8fe 100644 --- a/src/screens/home/index.tsx +++ b/src/screens/home/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/no-unstable-nested-components */ // Modules import React, { useContext, useEffect } from 'react'; import { Title } from 'react-native-paper'; @@ -18,30 +19,22 @@ import BellV2 from 'assets/icons/bell'; // Styles import { IconContainer, - Container, ScreenHeader, - Content, - UserInfoContainer, - InfoText, } from './styles'; +// Organisms +import ViewContainer from 'components/organisms/view-container'; + // Interfaces interface IHomeProps { navigation: any; } -const LeftButtonComponent = ({ navigation }: { navigation: any }) => ( - navigation.openDrawer()}> - - -); - export const Home = (props: IHomeProps) => { // Props const { navigation } = props; // Context - const { signOut } = useContext(AuthContext); const { userData } = useContext(UserContext); useEffect(() => { @@ -49,41 +42,14 @@ export const Home = (props: IHomeProps) => { console.log('User Data:', userData); }, []); - const openNotifications = () => { - navigation.navigate('Notifications'); - }; - - const RightComponent = () => ( - - - - ); - return ( - + + } - rightButtonComponent={} + subtitle={'Your Transactions at a Glance'} /> - - Kanvas Home - - - {translate('id', TextTransform.CAPITALIZE)}: {userData?.id} - {translate('firstName', TextTransform.CAPITALIZE)}: {userData?.firstname} - {translate('lastName', TextTransform.CAPITALIZE)}: {userData?.lastname} - {translate('email', TextTransform.CAPITALIZE)}: {userData?.email} - {translate('displayName', TextTransform.CAPITALIZE)}: {userData?.displayname} - - -