From 0fbe4c930d6ef0a98fa49db17d07ebb212f895fc Mon Sep 17 00:00:00 2001 From: Guilherme Guy Date: Sun, 5 Sep 2021 16:53:00 -0300 Subject: [PATCH 01/37] Setup SonarCloud integration --- .github/workflows/sonar_cloud.yml | 16 ++++++++++ .gitignore | 3 ++ package.json | 19 ++++++++++-- sonar-project.properties | 3 ++ yarn.lock | 51 ++----------------------------- 5 files changed, 41 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/sonar_cloud.yml create mode 100644 sonar-project.properties diff --git a/.github/workflows/sonar_cloud.yml b/.github/workflows/sonar_cloud.yml new file mode 100644 index 0000000..44ded7e --- /dev/null +++ b/.github/workflows/sonar_cloud.yml @@ -0,0 +1,16 @@ +on: [push, pull_request] + +name: Sonar Cloud +jobs: + sonarcloud: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + # Disabling shallow clone is recommended for improving relevancy of reporting + fetch-depth: 0 + - name: SonarCloud Scan + uses: sonarsource/sonarcloud-github-action@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.gitignore b/.gitignore index ad572e6..581265d 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,6 @@ buck-out/ # CocoaPods /ios/Pods/ + +# Tests +/coverage \ No newline at end of file diff --git a/package.json b/package.json index 5ca4d88..45fa480 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "start": "react-native start --reset-cache", "android-release": "npx jetify && cd android && ./gradlew assembleRelease --daemon", "test": "jest", + "test:cov": "jest --coverage", "lint": "eslint ./src", "postinstall": "patch-package" }, @@ -76,11 +77,25 @@ "react-test-renderer": "16.13.1" }, "jest": { - "preset": "react-native" + "preset": "react-native", + "collectCoverage": true, + "collectCoverageFrom": [ + "./src/**/*.(t|j)s" + ], + "coveragePathIgnorePatterns": [ + "/dist/", + "/test/", + "/android/", + "/ios/", + ".*\\.module\\.ts$", + ".eslintrc.js" + ], + "coverageDirectory": "./coverage", + "testEnvironment": "node" }, "husky": { "hooks": { "pre-push": "yarn lint --fix --max-warnings=0" } } -} +} \ No newline at end of file diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..1e8b44a --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,3 @@ +sonar.projectKey=fga-eps-mds_2021.1-Cartografia-social-front +sonar.organization=fga-eps-mds-1 +sonar.sources=src/ diff --git a/yarn.lock b/yarn.lock index 728eec4..1573cc0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1190,19 +1190,6 @@ resolved "https://registry.yarnpkg.com/@react-native-community/eslint-plugin/-/eslint-plugin-1.1.0.tgz#e42b1bef12d2415411519fd528e64b593b1363dc" integrity sha512-W/J0fNYVO01tioHjvYWQ9m6RgndVtbElzYozBq1ZPrHO/iCzlqoySHl4gO/fpCl9QEFjvJfjPgtPMTMlsoq5DQ== -"@react-native-firebase/app@^11.0.0": - version "11.5.0" - resolved "https://registry.yarnpkg.com/@react-native-firebase/app/-/app-11.5.0.tgz#cc7656d8bd580ddf63676774c5f4e73af3652c9c" - integrity sha512-Jz5CBhqkybxHjTFr5V0K+Jq2YivzPbu9exSze61/z1zSaIfBhR4G38wmHk44VWAl+PEX8GaYy9yfT69tLiCERA== - dependencies: - opencollective-postinstall "^2.0.1" - superstruct "^0.6.2" - -"@react-native-firebase/messaging@^11.0.0": - version "11.5.0" - resolved "https://registry.yarnpkg.com/@react-native-firebase/messaging/-/messaging-11.5.0.tgz#724a65683a23e40fd4a36553198f27227cfe78fd" - integrity sha512-bjsoJByiNtikNLCf5RMmUdIj3uH8Uf0eeyM9PdqfNRB1mtVaYrU8AmXnzbSd5SqJ/sxqwyZVuxzWNEJrcOnhZw== - "@react-native-masked-view/masked-view@^0.2.2": version "0.2.6" resolved "https://registry.yarnpkg.com/@react-native-masked-view/masked-view/-/masked-view-0.2.6.tgz#b26c52d5db3ad0926b13deea79c69620966a9221" @@ -2572,16 +2559,6 @@ clone-deep@^0.2.4: lazy-cache "^1.0.3" shallow-clone "^0.1.2" -clone-deep@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713" - integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ== - dependencies: - for-own "^1.0.0" - is-plain-object "^2.0.4" - kind-of "^6.0.0" - shallow-clone "^1.0.0" - clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -4036,13 +4013,6 @@ for-own@^0.1.3: dependencies: for-in "^1.0.1" -for-own@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" - integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= - dependencies: - for-in "^1.0.1" - forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -5506,7 +5476,7 @@ kind-of@^5.0.0: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== -kind-of@^6.0.0, kind-of@^6.0.1, kind-of@^6.0.2: +kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== @@ -6503,7 +6473,7 @@ open@^7.4.2: is-docker "^2.0.0" is-wsl "^2.1.1" -opencollective-postinstall@^2.0.1, opencollective-postinstall@^2.0.2: +opencollective-postinstall@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== @@ -7784,15 +7754,6 @@ shallow-clone@^0.1.2: lazy-cache "^0.2.3" mixin-object "^2.0.1" -shallow-clone@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571" - integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA== - dependencies: - is-extendable "^0.1.1" - kind-of "^5.0.0" - mixin-object "^2.0.1" - shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -8262,14 +8223,6 @@ sudo-prompt@^9.0.0: resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.2.1.tgz#77efb84309c9ca489527a4e749f287e6bdd52afd" integrity sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw== -superstruct@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.6.2.tgz#c5eb034806a17ff98d036674169ef85e4c7f6a1c" - integrity sha512-lvA97MFAJng3rfjcafT/zGTSWm6Tbpk++DP6It4Qg7oNaeM+2tdJMuVgGje21/bIpBEs6iQql1PJH6dKTjl4Ig== - dependencies: - clone-deep "^2.0.1" - kind-of "^6.0.1" - supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" From 9a820dbb9ace7dc786fe2dea48af4dddbd2ab912 Mon Sep 17 00:00:00 2001 From: Guilherme Guy Date: Sun, 5 Sep 2021 18:12:02 -0300 Subject: [PATCH 02/37] Add Release pipeline --- .github/workflows/release.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e2b7689 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,29 @@ +name: release +on: + push: + tags: + - "v*" + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Get current date + id: date + run: echo "::set-output name=date::$(date +'%d-%m-%Y')" + + - name: Copy repository + uses: actions/checkout@v2 + - run: mkdir -p /tmp/sonar/ + - run: curl --location --request POST 'https://sonarcloud.io/api/measures/component_tree?component=fga-eps-mds_2021.1-Cartografia-social-front&metricKeys=files,functions,complexity,comment_lines_density,duplicated_lines_density,coverage,ncloc,security_rating,tests,test_success_density,test_execution_time,reliability_rating&ps=500' > /tmp/sonar/fga-eps-mds-2021_1-Cartografia-social-front-${{ steps.date.outputs.date }}.json + - uses: actions/upload-artifact@v2 + with: + name: fga-eps-mds-2021_1-Cartografia-social-front-${{ steps.date.outputs.date }}.json + path: /tmp/sonar/fga-eps-mds-2021_1-Cartografia-social-front-${{ steps.date.outputs.date }}.json + - uses: "marvinpinto/action-automatic-releases@latest" + with: + repo_token: "${{ secrets.GITHUB_TOKEN }}" + prerelease: true + files: | + /tmp/sonar/fga-eps-mds-2021_1-Cartografia-social-front-${{ steps.date.outputs.date }}.json From d614d99917eb67e99ba914253585f8977d7543af Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Tue, 7 Sep 2021 12:10:27 -0300 Subject: [PATCH 03/37] ajusting reanimated Signed-off-by: Guilherme Banci --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5ca4d88..456c2e3 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "react-native-material-ripple": "^0.9.1", "react-native-permissions": "^3.0.1", "react-native-popover-view": "^4.0.1", - "react-native-reanimated": "2.0.0-rc.2", + "react-native-reanimated": "^2.2.0", "react-native-safe-area-context": "^3.1.9", "react-native-screens": "^2.18.0", "react-native-svg": "^12.1.0", From a24d9ac848dbfac795c6b6ffa981728fbee73d81 Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Tue, 7 Sep 2021 17:16:56 -0300 Subject: [PATCH 04/37] [#3] chore - add map dependency Co-authored-by: Alexandre Miguel --- android/app/src/main/AndroidManifest.xml | 3 + ios/Podfile | 2 + ios/Podfile.lock | 47 +++++++++++++-- ios/cartografiasocial/AppDelegate.m | 9 ++- ios/cartografiasocial/Info.plist | 2 - package.json | 1 + yarn.lock | 77 ++++++++---------------- 7 files changed, 79 insertions(+), 62 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 281f3d3..95c52ca 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -16,6 +16,9 @@ android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:theme="@style/AppTheme"> + config["reactNativePath"]) + rn_maps_path = '../node_modules/react-native-maps' pod 'Permission-LocationWhenInUse', :path => "#{permissions_path}/LocationWhenInUse" pod 'Permission-LocationAlways', :path => "#{permissions_path}/LocationAlways" pod 'Permission-LocationAccuracy', :path => "#{permissions_path}/LocationAccuracy" + pod 'react-native-google-maps', :path => rn_maps_path target 'cartografiasocialTests' do inherit! :complete diff --git a/ios/Podfile.lock b/ios/Podfile.lock index ccb8ba2..d800d2e 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -19,6 +19,27 @@ PODS: - DoubleConversion - glog - glog (0.3.5) + - Google-Maps-iOS-Utils (2.1.0): + - Google-Maps-iOS-Utils/Clustering (= 2.1.0) + - Google-Maps-iOS-Utils/Geometry (= 2.1.0) + - Google-Maps-iOS-Utils/Heatmap (= 2.1.0) + - Google-Maps-iOS-Utils/QuadTree (= 2.1.0) + - GoogleMaps + - Google-Maps-iOS-Utils/Clustering (2.1.0): + - Google-Maps-iOS-Utils/QuadTree + - GoogleMaps + - Google-Maps-iOS-Utils/Geometry (2.1.0): + - GoogleMaps + - Google-Maps-iOS-Utils/Heatmap (2.1.0): + - Google-Maps-iOS-Utils/QuadTree + - GoogleMaps + - Google-Maps-iOS-Utils/QuadTree (2.1.0): + - GoogleMaps + - GoogleMaps (3.5.0): + - GoogleMaps/Maps (= 3.5.0) + - GoogleMaps/Base (3.5.0) + - GoogleMaps/Maps (3.5.0): + - GoogleMaps/Base - lottie-ios (3.2.3) - lottie-react-native (4.0.3): - lottie-ios (~> 3.2.3) @@ -211,6 +232,12 @@ PODS: - React - react-native-geolocation-service (5.2.0): - React + - react-native-google-maps (0.29.3): + - Google-Maps-iOS-Utils (= 2.1.0) + - GoogleMaps (= 3.5.0) + - React-Core + - react-native-maps (0.29.3): + - React-Core - react-native-safe-area-context (3.3.0): - React-Core - React-RCTActionSheet (0.63.4): @@ -283,7 +310,7 @@ PODS: - React-Core - RNPermissions (3.0.5): - React-Core - - RNReanimated (2.0.0-rc.2): + - RNReanimated (2.2.0): - DoubleConversion - FBLazyVector - FBReactNativeSpec @@ -347,6 +374,8 @@ DEPENDENCIES: - react-native-config (from `../node_modules/react-native-config`) - react-native-connectivity-status (from `../node_modules/react-native-connectivity-status`) - react-native-geolocation-service (from `../node_modules/react-native-geolocation-service`) + - react-native-google-maps (from `../node_modules/react-native-maps`) + - react-native-maps (from `../node_modules/react-native-maps`) - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) @@ -372,6 +401,8 @@ DEPENDENCIES: SPEC REPOS: trunk: - boost-for-react-native + - Google-Maps-iOS-Utils + - GoogleMaps EXTERNAL SOURCES: DoubleConversion: @@ -422,6 +453,10 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-connectivity-status" react-native-geolocation-service: :path: "../node_modules/react-native-geolocation-service" + react-native-google-maps: + :path: "../node_modules/react-native-maps" + react-native-maps: + :path: "../node_modules/react-native-maps" react-native-safe-area-context: :path: "../node_modules/react-native-safe-area-context" React-RCTActionSheet: @@ -472,6 +507,8 @@ SPEC CHECKSUMS: FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e Folly: b73c3869541e86821df3c387eb0af5f65addfab4 glog: 5337263514dd6f09803962437687240c5dc39aa4 + Google-Maps-iOS-Utils: c32891ff472eaaa1fca032beedafa1a013af7875 + GoogleMaps: 32ca02de09de357a10ac773f2c70f1986751392d lottie-ios: c058aeafa76daa4cf64d773554bccc8385d0150e lottie-react-native: 96361a9891cf651534ea35c4f85f33d4cf14ed13 Permission-LocationAccuracy: c008fa8c4a90fcb6e33f465c2a8684e92d93b794 @@ -491,6 +528,8 @@ SPEC CHECKSUMS: react-native-config: 72d948053a442779b3178fddd571e37f118ef606 react-native-connectivity-status: 2325459ddad171e1f88af01f52a6a1f34ad37102 react-native-geolocation-service: 7c9436da6dfdecd9526c62eac62ea2bc3f0cc8ea + react-native-google-maps: d6a30377b40a338bd09d6ad36ce48dc5d12b5792 + react-native-maps: 41d01d8e0afcebe32bec9eea3bd945adc1b18f7a react-native-safe-area-context: 61c8c484a3a9e7d1fda19f7b1794b35bbfd2262a React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336 React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b @@ -507,12 +546,12 @@ SPEC CHECKSUMS: RNCMaskedView: c298b644a10c0c142055b3ae24d83879ecb13ccd RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211 RNPermissions: 7043bacbf928eae25808275cfe73799b8f618911 - RNReanimated: e8a1520b15df106c96214161078c69e4a23b8b29 + RNReanimated: d9da990fc90123f4ffbfdda93d00fc15174863a8 RNScreens: f7ad633b2e0190b77b6a7aab7f914fad6f198d8d RNSVG: 551acb6562324b1d52a4e0758f7ca0ec234e278f RNVectorIcons: 31cebfcf94e8cf8686eb5303ae0357da64d7a5a4 Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6 -PODFILE CHECKSUM: 2c127b0b15afea8bbc40981b09b96c9f678a561f +PODFILE CHECKSUM: 614f0d44978b11f38cc42c9f97bf17059b507438 -COCOAPODS: 1.10.1 +COCOAPODS: 1.11.0 diff --git a/ios/cartografiasocial/AppDelegate.m b/ios/cartografiasocial/AppDelegate.m index d2f5d70..a2ecab2 100644 --- a/ios/cartografiasocial/AppDelegate.m +++ b/ios/cartografiasocial/AppDelegate.m @@ -3,6 +3,7 @@ #import #import #import +#import #ifdef FB_SONARKIT_ENABLED #import @@ -27,9 +28,11 @@ @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { -#ifdef FB_SONARKIT_ENABLED - InitializeFlipper(application); -#endif + [GMSServices provideAPIKey:@"AIzaSyDdZl8FuAMi4qmPodsRg0YcCJiFXgrIXMU"]; + + #ifdef FB_SONARKIT_ENABLED + InitializeFlipper(application); + #endif RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge diff --git a/ios/cartografiasocial/Info.plist b/ios/cartografiasocial/Info.plist index a7a4413..941113e 100644 --- a/ios/cartografiasocial/Info.plist +++ b/ios/cartografiasocial/Info.plist @@ -63,8 +63,6 @@ - NSLocationWhenInUseUsageDescription - UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities diff --git a/package.json b/package.json index 456c2e3..f9a7c8a 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "react-native-geolocation-service": "^5.2.0", "react-native-gesture-handler": "^1.10.3", "react-native-keyboard-aware-scroll-view": "^0.9.3", + "react-native-maps": "^0.29.3", "react-native-material-ripple": "^0.9.1", "react-native-permissions": "^3.0.1", "react-native-popover-view": "^4.0.1", diff --git a/yarn.lock b/yarn.lock index 728eec4..b6dbd52 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1190,19 +1190,6 @@ resolved "https://registry.yarnpkg.com/@react-native-community/eslint-plugin/-/eslint-plugin-1.1.0.tgz#e42b1bef12d2415411519fd528e64b593b1363dc" integrity sha512-W/J0fNYVO01tioHjvYWQ9m6RgndVtbElzYozBq1ZPrHO/iCzlqoySHl4gO/fpCl9QEFjvJfjPgtPMTMlsoq5DQ== -"@react-native-firebase/app@^11.0.0": - version "11.5.0" - resolved "https://registry.yarnpkg.com/@react-native-firebase/app/-/app-11.5.0.tgz#cc7656d8bd580ddf63676774c5f4e73af3652c9c" - integrity sha512-Jz5CBhqkybxHjTFr5V0K+Jq2YivzPbu9exSze61/z1zSaIfBhR4G38wmHk44VWAl+PEX8GaYy9yfT69tLiCERA== - dependencies: - opencollective-postinstall "^2.0.1" - superstruct "^0.6.2" - -"@react-native-firebase/messaging@^11.0.0": - version "11.5.0" - resolved "https://registry.yarnpkg.com/@react-native-firebase/messaging/-/messaging-11.5.0.tgz#724a65683a23e40fd4a36553198f27227cfe78fd" - integrity sha512-bjsoJByiNtikNLCf5RMmUdIj3uH8Uf0eeyM9PdqfNRB1mtVaYrU8AmXnzbSd5SqJ/sxqwyZVuxzWNEJrcOnhZw== - "@react-native-masked-view/masked-view@^0.2.2": version "0.2.6" resolved "https://registry.yarnpkg.com/@react-native-masked-view/masked-view/-/masked-view-0.2.6.tgz#b26c52d5db3ad0926b13deea79c69620966a9221" @@ -1511,6 +1498,11 @@ resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== +"@types/geojson@^7946.0.7": + version "7946.0.8" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.8.tgz#30744afdb385e2945e22f3b033f897f76b1f12ca" + integrity sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA== + "@types/graceful-fs@^4.1.2": version "4.1.5" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" @@ -2572,16 +2564,6 @@ clone-deep@^0.2.4: lazy-cache "^1.0.3" shallow-clone "^0.1.2" -clone-deep@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713" - integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ== - dependencies: - for-own "^1.0.0" - is-plain-object "^2.0.4" - kind-of "^6.0.0" - shallow-clone "^1.0.0" - clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -4036,13 +4018,6 @@ for-own@^0.1.3: dependencies: for-in "^1.0.1" -for-own@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" - integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= - dependencies: - for-in "^1.0.1" - forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -5506,7 +5481,7 @@ kind-of@^5.0.0: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== -kind-of@^6.0.0, kind-of@^6.0.1, kind-of@^6.0.2: +kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== @@ -6161,6 +6136,11 @@ mkdirp@^0.5.1, mkdirp@~0.5.1: dependencies: minimist "^1.2.5" +mockdate@^3.0.2: + version "3.0.5" + resolved "https://registry.yarnpkg.com/mockdate/-/mockdate-3.0.5.tgz#789be686deb3149e7df2b663d2bc4392bc3284fb" + integrity sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ== + moo@^0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4" @@ -6503,7 +6483,7 @@ open@^7.4.2: is-docker "^2.0.0" is-wsl "^2.1.1" -opencollective-postinstall@^2.0.1, opencollective-postinstall@^2.0.2: +opencollective-postinstall@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== @@ -7095,6 +7075,13 @@ react-native-keyboard-aware-scroll-view@^0.9.3: prop-types "^15.6.2" react-native-iphone-x-helper "^1.0.3" +react-native-maps@^0.29.3: + version "0.29.3" + resolved "https://registry.yarnpkg.com/react-native-maps/-/react-native-maps-0.29.3.tgz#ab873fa5e7301c29f07886df5f3cbef667d46cca" + integrity sha512-742ipC71NdGHXmrCHPY9SEGDuKoSx2l0RMC1W9WXe/jd6+Eg5OllRBcR6Y+ORnzvuYZrd0Hj6q6bK3QR5ZL8sA== + dependencies: + "@types/geojson" "^7946.0.7" + react-native-material-ripple@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/react-native-material-ripple/-/react-native-material-ripple-0.9.1.tgz#db1ad9dd7cf97011e4cd8475ae2041ade0f891cb" @@ -7112,13 +7099,14 @@ react-native-popover-view@^4.0.1: resolved "https://registry.yarnpkg.com/react-native-popover-view/-/react-native-popover-view-4.0.2.tgz#61cfa78c7dfb956d91d01d2bd10794bef35b0e1e" integrity sha512-8wCGzmC14oKYKDWd1PZHiZVZbUu+t8xeJPUSc5KfbJuEpkGGHpvwhls+Jhb38VaGQIDTDbQ+Rwgzuo1z3Ltl4g== -react-native-reanimated@2.0.0-rc.2: - version "2.0.0-rc.2" - resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-2.0.0-rc.2.tgz#8ff0210986c5234940d951e384793874802f81aa" - integrity sha512-drOPEIMSh+224RTBZJrMasxZBdNodTcQcJKIfH5vMZPYhfSbljxfKTGfn7ZKn7ZYkX+wCPKKhJJPdD5+9Pevyw== +react-native-reanimated@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-2.2.0.tgz#a6412c56b4e591d1f00fac949f62d0c72c357c78" + integrity sha512-lOJDd+5w1gY6DHGXG2jD1dsjzQmXQ2699HUc3IztvI2WP4zUT+UAA+zSG+5JiBS5DUnTL8YhhkmUQmr1KNGO5w== dependencies: "@babel/plugin-transform-object-assign" "^7.10.4" fbjs "^3.0.0" + mockdate "^3.0.2" string-hash-64 "^1.0.3" react-native-safe-area-context@^3.1.9: @@ -7784,15 +7772,6 @@ shallow-clone@^0.1.2: lazy-cache "^0.2.3" mixin-object "^2.0.1" -shallow-clone@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571" - integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA== - dependencies: - is-extendable "^0.1.1" - kind-of "^5.0.0" - mixin-object "^2.0.1" - shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -8262,14 +8241,6 @@ sudo-prompt@^9.0.0: resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.2.1.tgz#77efb84309c9ca489527a4e749f287e6bdd52afd" integrity sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw== -superstruct@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.6.2.tgz#c5eb034806a17ff98d036674169ef85e4c7f6a1c" - integrity sha512-lvA97MFAJng3rfjcafT/zGTSWm6Tbpk++DP6It4Qg7oNaeM+2tdJMuVgGje21/bIpBEs6iQql1PJH6dKTjl4Ig== - dependencies: - clone-deep "^2.0.1" - kind-of "^6.0.1" - supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" From ede30de2a55e779833a7589fc7601567d99aca3d Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Tue, 7 Sep 2021 17:32:18 -0300 Subject: [PATCH 05/37] [#3] feat - creating get location function Co-authored-by: Alexandre Miguel --- src/services/useLocation.js | 77 +++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 src/services/useLocation.js diff --git a/src/services/useLocation.js b/src/services/useLocation.js new file mode 100644 index 0000000..6e99eea --- /dev/null +++ b/src/services/useLocation.js @@ -0,0 +1,77 @@ +import {useEffect, useState} from 'react'; +import {Alert, Platform} from 'react-native'; +import Geolocation from 'react-native-geolocation-service'; +import {request, PERMISSIONS, RESULTS} from 'react-native-permissions'; + +export default () => { + const [location, setLocation] = useState(null); + const [hasLocationPermission, setHasLocationPermission] = useState(false); + + const requestLocation = () => { + let permission; + if (Platform.OS === 'ios') { + permission = PERMISSIONS.IOS.LOCATION_ALWAYS; + } else { + permission = PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION; + } + + request(permission).then((result) => { + switch (result) { + case RESULTS.UNAVAILABLE: + Alert.alert( + 'Atenção', + 'This feature is not available (on this device / in this context)', + ); + break; + case RESULTS.DENIED: + Alert.alert( + 'Atenção', + 'The permission has not been requested / is denied but requestable', + ); + break; + case RESULTS.LIMITED: + Alert.alert( + 'Atenção', + 'The permission is limited: some actions are possible', + ); + break; + case RESULTS.GRANTED: + setHasLocationPermission(true); + break; + case RESULTS.BLOCKED: + Alert.alert( + 'Atenção', + 'The permission is denied and not requestable anymore', + ); + break; + default: + } + }); + }; + const getLocation = () => { + if (hasLocationPermission) { + Geolocation.getCurrentPosition( + (position) => { + setLocation(position.coords); + }, + (error) => { + Alert.alert('Atenção', error.message); + }, + {enableHighAccuracy: true, timeout: 15000, maximumAge: 10000}, + ); + } + }; + + useEffect(() => { + getLocation(); + }, [hasLocationPermission]); + + useEffect(() => { + requestLocation(); + }, []); + + return { + location, + requestLocation, + }; +}; From 2af001c178740e16258ddfada86a2233428eec1b Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Tue, 7 Sep 2021 17:33:54 -0300 Subject: [PATCH 06/37] [#3] feat - creating map screen Co-authored-by: Alexandre Miguel --- src/app/Routes.js | 50 +++++++++++++++++------------------------ src/pages/Map/index.js | 27 ++++++++++++++++++++++ src/pages/Map/styles.js | 19 ++++++++++++++++ 3 files changed, 66 insertions(+), 30 deletions(-) create mode 100644 src/pages/Map/index.js create mode 100644 src/pages/Map/styles.js diff --git a/src/app/Routes.js b/src/app/Routes.js index f2ffc40..996bf14 100644 --- a/src/app/Routes.js +++ b/src/app/Routes.js @@ -1,50 +1,40 @@ import React from 'react'; -import {SafeAreaView, StatusBar, Platform} from 'react-native'; +import {StatusBar} from 'react-native'; import {NavigationContainer} from '@react-navigation/native'; import {createStackNavigator} from '@react-navigation/stack'; import {ThemeProvider} from 'styled-components/native'; -import {useSelector} from 'react-redux'; -import {auth} from 'store/selectors'; +// import {useSelector} from 'react-redux'; +// import {auth} from 'store/selectors'; import theme from 'theme/theme'; import Page1 from 'pages/Page1'; -import Page2 from 'pages/Page2'; + +import Map from 'pages/Map'; const Routes = () => { - const user = useSelector(auth); + // const user = useSelector(auth); const Stack = createStackNavigator(); - const safeAreaViewStyle = { - flexGrow: 1, - backgroundColor: theme.colors.white, - }; - return ( <> - - - - -
}} - /> - - - - + + + + null}} + /> + + + ); diff --git a/src/pages/Map/index.js b/src/pages/Map/index.js new file mode 100644 index 0000000..6459edc --- /dev/null +++ b/src/pages/Map/index.js @@ -0,0 +1,27 @@ +import React from 'react'; +import {View} from 'components/UI'; +import useLocation from 'services/useLocation'; +import {MapView} from './styles'; + +const Map = () => { + const {location} = useLocation(); + + if (location) { + return ( + + + + ); + } + + return null; +}; + +export default Map; diff --git a/src/pages/Map/styles.js b/src/pages/Map/styles.js new file mode 100644 index 0000000..85eeaa2 --- /dev/null +++ b/src/pages/Map/styles.js @@ -0,0 +1,19 @@ +import styled from 'styled-components/native'; +import OriginalMapView from 'react-native-maps'; + +export const MapView = styled(OriginalMapView)` + flex: 1; +`; + +export const Container = styled.View` + padding: 20px; +`; + +export const FirstInput = styled.View` + flex-direction: row; + align-items: center; +`; + +export const InputView = styled.View` + flex: 1; +`; From 33a699f72e12258b81906a8d18ba160380f96716 Mon Sep 17 00:00:00 2001 From: Alexandre Miguel Date: Wed, 8 Sep 2021 03:45:13 -0300 Subject: [PATCH 07/37] [#8] docs - add contribution guide Co-authored-by: Guilherme Banci --- CODE_OF_CONDUCT.md | 128 +++++++++++++++++ README.md | 249 ++++++++++++++++++++++++++++++++- images-git/gitflow_adapted.png | Bin 0 -> 84407 bytes 3 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 images-git/gitflow_adapted.png diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..18c9147 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/README.md b/README.md index 6be22a4..ac2cc54 100644 --- a/README.md +++ b/README.md @@ -1 +1,248 @@ -# 2021.1-Cartografia-social-front \ No newline at end of file +# 2021.1-Cartografia-social-front + +Repositório do frontend do projeto de Cartografia Social +## Sumário + +* [Dependências](#Dependências) +* [Execução](#Execução) +* [Guia de Contribuição](#Guia-de-Contribuição) + * [Issues](#Issues) + * [Branches](#Branches) + * [Commits](#Commits) + * [Pull Requests](#Pull-Requests) +* [Licença](#Licença) +* [Código de Conduta](#Código-de-Conduta) + +## [**Dependências**](#Sumário) + +Para a execução local da Wiki do projeto serão necessárias as seguintes dependências: + +* [NodeJs](https://nodejs.org/en/) +* [VSCode](https://code.visualstudio.com/) (Opcional) + +## [**Execução**](#Sumário) + +Para executar o repositório de documentação é necessários os seguintes passos: + +```bash +# 1. Clone o repositório atual +$ git clone https://github.com/fga-eps-mds/2021.1-Cartografia-social-front + +# 2. Entre na página src do repositório +$ cd 2021.1-Cartografia-social-front/ + +# 3. Install as dependências +$ npm install + +# 4. Execute o projeto +$ npm run dev +``` + +## [**Guia de Contribuição**](#Sumário) + +Para a contribuição e evolução das informações presentes nesse repositório, o seguinte guia de contribuição foi criado, especificando instruções de uso e dos padrões utilizados. + +### [**Issues**](#Sumário) + +As issues devem ser criadas conforme template predefinido, contendo: + +* ***Descrição*** - Descrição simples e direta do problema que a issue busca resolver ou da adição da issue; + +* ***Tarefas*** - *Checklist* trazendo o passo a passo granularizado de como a issue deve ser executada, permitindo que cada tarefa seja marcada quando concluída; + +* ***Critérios de Aceitação*** - *Checklist* do funcionamento ou resultado esperado após a conclusão da issue de forma satisfatória, permitindo que cada critério seja marcado quando concluído; + +* ***Issue Vinculada*** - Referência a outra issue que esteja vinculada à issue presente, com link para a issue referenciada. Caso não haja issue, deve ser preenchido como 'Não se aplica.' somente; + +* ***Assignees*** - As issues criadas devem ser atribuídas a um membro para execução, se houver alguém responsável por realizá-la; + +* ***Labels*** - As issues criadas devem conter labels que categorizem aquela issue, para informar aos demais contribuidores sobre a natureza de seu conteúdo; + +* ***Sprint*** - As issues devem possuir a sprint a qual se referem no campo destinado; + +* ***Estimate*** - As issues devem ser pontuadas conforme seu grau de dificuldade; + +#### **Nomenclatura** + +A Nomenclatura das issues deve seguir o padrão: + +``` +[PREFIXO] Breve descrição da issue em português +``` + +De forma que o elemento **PREFIXO** siga o seguinte padrão + +| Prefixo | Tema | Exemplo | +| --- | --- | --- | +| DOCS | Documentação | `[DOCS] Melhorar README`| +| DEVOPS | Integração, DevOps | `[DEVOPS] Implementar CI/CD`| +| USXX | História de Usuário, em que *XX* se refera ao número da história de usuário | `[US12] Questionário para criação de uma nova comunidade`| + + + +### [**Branches**](#Sumário) + +Para a padronização das branches foi tomada uma adaptação do modelo padrão do [gitflow](https://nvie.com/posts/a-successful-git-branching-model/) conforme representado pelo diagrama abaixo: + +![gitflow-adapted](./images-git/gitflow_adapted.png) + +Esse modelo segue a seguinte categorização para as respectivas branches: + +* ***Main*** - A Branch *Main* contém o histórico oficial do código ou projeto em questão, sendo assim a versão do código que estará em produção no ciclo de vida do projeto. + +* ***Hotfix*** - As Branches *Hotfix* servem para manutenção ou correção de forma rápida dos lançamentos em produção, feitas a partir da *Main* para uma integração mais rápida. + +* ***Develop*** - A Branch *Develop* serve como uma ramificação para integração de recursos, sendo a versão do projeto disponível no ambiente de Homologação. + +* ***Feature*** - As Branches de *Feature* servem para a realização de novas adições e funcionalidades para o projeto, sendo criadas a partir da branch *develop* para serem integradas a essa branch à medida que a *feature* (ou funcionalidade) em questão é concluída. Essas funcionalidades representam novas adições ao projeto em si, através da inserção de códigos. + +* ***Support*** - As Branches *Support* servem para armazenar modificações que integram o projeto mas não representam funcionalidades (ou *features*), como documentação, Integração Contínua, Deploy Contínuo e demais configurações focadas na estrutura do projeto. + +* ***Release*** - Esse tipo de branch representa uma estabilização dos recursos presentes na *develop* para uma integração com os dados existentes na *master*, representando um próximo ciclo de lançamento. + +#### **Nomenclatura** + +A Nomenclatura das branches deve seguir o seguinte padrão + +| Branch | Nomenclatura | +| --- | --- | +| Main | main | +| Develop | develop | +| Feature | feature/[NUMERO-USER-STORY]-[BREVE-DESCRIÇÃO-EM-INGLES]
Ex.: `feature/01-mark-point-on-map` | +| Support | support/[BREVE-DESCRIÇÃO-EM-INGLES]
Ex.: `support/document-contribution-guide` | +| Release | release/v-[NUMERO-DA-VERSAO]
Ex.: `release/v-0.1` | +| Hotfix | hotfix/[BREVE-DESCRIÇÃO-EM-INGLES]
Ex.: `hotfix/remove-second-callback` | + +### [**Commits**](#Sumário) + +Os commits devem seguir padrões paa identificação de alterações feitas e implementadas, tanto para futuras modificações quanto para gerar rastro de informação. + +#### **Nomenclatura** + +A Padronização de commits foi baseada na proposta de [ConventionalCommits](https://www.conventionalcommits.org/pt-br/v1.0.0-beta.4/#resumo) com adaptações, de forma que a mensagem final de commits assume a seguinte forma: + +* [#NUMERO_ISSUE] tipo - breve descrição em inglês, com verbo no imperativo + +Sendo o **Número da Issue** o Id atribuído a ela no momento de sua criação, o **Tipo** conforme descrito na próxima sessão e a Breve Descrição estando na língua inglesa, contendo o verbo principal no [imperativo](https://www.infoescola.com/ingles/frases-imperativas-imperatives/), conforme o seguinte exemplo: + +* [#15] feat - Add user validation to point info + + +#### **Lista de Tipos** + +Os tipos de commits a serem implementados são: + +* ***test*** + +Indica qualquer tipo de criação ou alteração de códigos de teste. Exemplo: Criação de testes unitários. + +``` +[#1] test - add unit test of main module +``` + +* ***feat*** + +Indica o desenvolvimento de uma nova feature ao projeto. Exemplo: Acréscimo de um serviço, funcionalidade, endpoint, etc. + +``` +[#2] feat - create get location function +``` + +* ***refactor*** + +Usado quando houver uma refatoração de código que não tenha qualquer tipo de impacto na lógica/regras de negócio do sistema. Exemplo: Mudanças de código após um code review + +``` +[#3] refactor - reorder validation flow +``` + +* ***style*** + +Empregado quando há mudanças de formatação e estilo do código que não alteram o sistema de nenhuma forma. +Exemplo: Mudar o style-guide, mudar de convenção lint, arrumar indentações, remover espaços em brancos, remover comentários, etc.. + +``` +[#4] style - change primary color +``` + +* ***fix*** + +Utilizado quando há correção de erros que estão gerando bugs no sistema. +Exemplo: Aplicar tratativa para uma função que não está tendo o comportamento esperado e retornando erro. + +``` +[#5] fix - remove second callback +``` + +* ***chore*** + +Indica mudanças no projeto que não afetem o sistema ou arquivos de testes. São mudanças de desenvolvimento. +Exemplo: Mudar regras do eslint, adicionar prettier, adicionar mais extensões de arquivos ao .gitignore + +``` +[#6] chore - add map library +``` + +* ***docs*** + +Usado quando há mudanças na documentação do projeto. +Exemplo: adicionar informações na documentação da API, mudar o README, etc. + +``` +[#7] docs - add architecture document +``` + +* ***build*** + +Utilizada para indicar mudanças que afetam o processo de build do projeto ou dependências externas. +Exemplo: Gulp, adicionar/remover dependências do npm, etc. + +``` +[#8] build - remove unused dependencies +``` + +* ***perf*** + +Indica uma alteração que melhorou a performance do sistema. +Exemplo: alterar ForEach por while, melhorar a query ao banco, etc. + +``` +[#9] perf - optmize validation flow +``` + +* ***ci*** + +Utilizada para mudanças nos arquivos de configuração de CI. +Exemplo: Circle, Travis, BrowserStack, etc. + +``` +[#10] ci - implement ci/cd +``` + +* ***revert*** + +Indica a reverão de um commit anterior. + +``` +[#11] revert - revert previous commit +``` + +### [**Pull Requests**](#Sumário) + +Deve seguir o mesmo padrão de nomenclatura da issue. + +## [**Licença**](#Sumário) + +A Licença do repositório presente é a [**Licença MIT**](https://opensource.org/licenses/MIT), de seguinte texto: + +*Copyright 2021,* + +*Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:* + +*The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.* + +*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.* + +## [**Código de Conduta**](#Sumário) + +O Código de Conduta do repositório leva em conta comportamentos que favoreçam o crescimento da comunidade e respeite a individualidade de cada membro, detalhado no [documento completo](./CODE_OF_CONDUCT.md). diff --git a/images-git/gitflow_adapted.png b/images-git/gitflow_adapted.png new file mode 100644 index 0000000000000000000000000000000000000000..4faf54bccd4d53bcf604b0ae8cdc5851e370f566 GIT binary patch literal 84407 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�h_^`?)-XlaZ)>t1$ zj=T6+nleg)Rjjyld*b9?O8oupl9w% zQnDGjN9ODNC>Ps4h`Ke)`0gs-Ws}m)YWq8vB+HW?I{S>Qx5f#48SGh-dBC+>AozNl zuy+`xfb)>&sD9MhHcZCt`q2Z7(FVnpz(&Mv6{;zKFJnneuHH&&dR6aIU27gL>@Cu7U>U1^qY!$;`2R*HwvT4bWX=YbcWWcTcm@BV%$=S@@bcLO)iGf zKCx7@)+Ih&<$eAtEhe-^%6XPyliH?v>}&K_ES~eBetIvy$6qL=^jXyXaj<|kR_#4X z`{8w#C67mE|B9lSM9L*are`^?N+`QVo{0S+)yaPL8Gq|X8$Pv(eV%wQ1OEs}B4TB; zrbpXh?@5P8)oZqv{&d}zt>tXrvOCzeu!boly%*desa$)$Hyu@f@MZW7g`l%JxNfGd z`nZ_=9elSZ^CsS9KRdLf8e>p@;t#`x7HIwavHmPofsM+{*KdeDAyqqE*De^AL@`rk zO;qh{@E#v)zE5WOJm1iMZRQ~AeRkdv`_cKn;R1*Jl(<>!fq)&Y)xF^h4+(W-(DRaR4uz&Y*fF~vF4)!G zOn9L-9aHc?NJ}duD)xeUvq5t2k6Flj$_v4uemN`@h>g+q{yk@|lBrUU%URcd;|WYd zRS{Ev9O@nzOv~LtdNV-4bCxL31*E9k=IV3MXt-|x7vf2K%$Fsbs}k9Z521&xBhOPD zIXkBJaCf0&rZ=!lel{0j_!|n z50!4i5_GPo5LdRj8&uek00U#{;V+eno|7Z!jZO|8wc6CXdvlt!8Ry2(@64@D)V((* z2C2p`Fwe`{V_x;~ge!*L@f7iz*~`4zCYkD2?d#|F1?%i)B$9*|Qc_aNtFwP|w(ryp z%wYPzcrhGjJ#zc)w{PG0_16BJ2A?YYstf72iAwSb9G_YHvAaBL7QK9!3x!*qAkE@0 z^KN5%x?Z7tv+dvgUvwB%%pR<|C-oObvr0yMFy#oyG#WLE+MzcHc913B1(eLA@LL*$ zr$8=KaA^7SJL6%OiKknk(|iZv0||-h(+yg?j6&~IY$7hq-#pLXjoeSya>N)2w|?fw zOpzrslllC;BKgwvRUM;j`<+Wv^3_~2R|lB+I8!y}D(96|&_$esF^sn*U&^7C52df= z^c#3lYS8L%GJ3S0^Eg@EQQ3;>vS1=3cc!7dbZxDfl3tcP{Ukd#+1<07FJ9>B#9*k* z7cC2OnxGHH3zjR-HFY?dEG$hL6pyfT4N%#AAHIF<)1VO0nhSE?#}E&@@b(D(LiFvF5$@J~;N$8h&NaAjrao<9J#% z;<)UBBzM9mA&?kF;j#0X6ah6WPrK~W<(qfD0G=Dy)A2Gsqd(v(?+e|KF4*LANxG#) zm=r~tv;{htj{s;>>AIP^y7w{iiM#IBSHJ_zK)xvfN^4^Zm_r4lS$`&)z0^XfenT2l z`lR1AzIFWrq?MvV*Siu01wb1dV}GN^#@+4C{s|*t>p})weljDv@zO`{S6=7Ff~$;j zc^GRH-aPEe?I*5tnhDN#i(KL8jHjYHI^R1ry=YbG0_tWOtsxzJ)6TlXA;+UbZ;ZAW z+~je1k5xpS!`obcYsWceKPl4|-*CiNL*hXaAF>ke)NqnK(b)4(C|446_TuA=hu0&% zsrFXN#2E%=F*%&oXxD=`Z)OQZP8U!xEf=RIFOA2yXU+uIU>KJZPWn^1DC~KASFMky zF)1bp`jxNWwX0TlCi>yx;JU>(WK@gAe(&kjIhZhV&BBzn#tFCNroJm0K($0`6KX7d z9v6P)%o-$iZ!N@}-W@NqTxfdV9pIIaE!Yf+@OKbaI0D2WR)NWIrw(*&KUxpt!s#e( zH^0{ZeOQ^KL7De@iingn(UACeKt8dSTySK z2D$JIZVBYaKl}#}%$Kyeu7)(F${q6Dbgg3;RPYCsL6EvGiZxnQgfe-s(0~j|QDSRj z*A72Xb9~fKl&x=&;oqyB#zE`5l(T!?P zezEA*JIW?5S!r+(?N%kKTwbADyp+jp!F{)tE37|1`H&~tqDmQ{g5IdE6lG_;uo5V^ z@RWvwXm4$zV%0cmUPJL_Ct5>)wsoIyHS6u(^qr=v(>udo)HVx6hBK{G^98;cTv}6l zUGp+;yIaQc^tEqtH2cC@gd77C4oA9j^mwhF`9v9oI+Qq{)CjIb_wtU>WK_6D{MNDO zbo*^ACB~@{p=S$W8lmw}&Uin;MnA3q+0D#2hd=xc(A{Z-ys$3%nyoOIdg;a3leT!tH*a{n^Kc}PKI~qEJ4cl%IrIP5EUi8%$1QB9zoOfQ-~$4gx~FV zy1djeOl82m^3Zz{fHS$}lkFvV+i@EUaSFH({GlOnR5( zOWd^jJuLv&9O_)}1nd}kGvqVfH(b^xME^;2Im%xt+I#9Taaz_wXjw`U0*SX3`*x~uJNBDo~6UW>=7fD?{4`Zdm)zSa*VC(&r$T}5&V zVeBSU%f)2&D~W0%-dl$)vBd*+YMAJ5D+8TIL|h|OgGFG1waQABa#H(^iygPGB2Bg~ zRVh*R1*}vLC_C8Tgc{xZEzw@Q_^hJZMd6Rh6;ppj^`r2Yf-2OL-eZ$20fMzHEt|Bo zT}ozrNY6St#tUEQl02s!kBd%>l(_Rgj2clp{T#_>Vt?wtMK=SbWQ7eW zYZW86123v(4;ZqcmZ! zD6ifzu6Ub<%)c0H6u-)8?+t+paR~69j(njis(O`+_&G{WtPx7cf>>r<@zO;U_#vn7 zO=A!4UC%B~>RG?0WmLk%4Jl#Hf%(e?6?JlAxgn$j!!PIvU1?ubhq&S9^jGsAMJcLE zlsVY$dzV9;bK1K4Qzkv9s6Vt(gUfl#lN9}+^Lindi(}b8HA3yw{yAM(;GIvjKl=eh z&;uw*SB7V%ulc^@n2dK25T!=O> zt2L8g`C;T@w9!-hE3HGO+pa@}1|iUp;eEucSws$DM*y^k_lXL-7kJ#gy|CG0v2`n- zekv!uMkci4n3*Rz9GhKE$laiVoAMwKck?OyrE}1cR=JJWOob+f$F}6KhAEgbIq=)d z_OiiCg?kA;%xDaKG|SBcAGK9YU4azafxM)BhYn1n>m=fWdY}}=BU3;S&dwP(X!YV| zPW`JfzAfsdz3fuDjiC`?HlIai-JojRb$%Qbyd0)^rt1VoSb@oZMGGZ19F1l zQHFE`MhTS!5pGXjMWR=j!=gD$jS|2|GUZrl9;AN^sOZeI*eFZaE*)&4BT#TwlD`$S4W^1`@E#3i+OUB98b zWz%M|o&<&$-vbQ!ho_dqB{a}Hngczx*v6K9ZuA+LsQGAjW%zY2v~NB`tLQldJeJe- zI9s>z@XilMF$(mr(00zxHeH7M@5j*gBcGncTj z%kewNxXiCZlQi6`VUXt*--Lg#zO;tZVu8XND#O{MCBA^$JU0HAe!=r^dPyZZ)}fa@ z?bXBe=(9iSw#TB|)gB()p4YxONe+^CLHhSTC~?_MHKNU#@cm{b%ag)7M}$Q!L7q~A z0|NO(CwmR2`^0hIlVp?5r=QoSfM>>}$wz4~-NGx{?b3l> zl?J&DCMKrTZ}&Pq!!NGTj|l=G246~K+6(BsW>0J!jFC~z4=wbN&NKqp4_Cp;YrKf!%7bVA8|V@qP^f4-WWf1M+&NTpB`Dk_ z_rMJrI-|-y`-S7P+cEK|)&zkHo1$C$RsB~V@TU?%2|p)gR^;#fwZsYKkyWW#gpL%_ z&fu^HdNM+SfxL!L<$?U$5JCM#UGI}4x3PM!+b1U{EfCmVB4EzSbQ!3#A3?vZtK6vbd;QUG+3n>a#hX_aQCPnc zd~p&TG+zEr*@8eWGG;hgW<9r~;-sp+0nc`JFYl;+AeV5ns-H>rAc_MT(W>8qTo7Es zIV^LLDafh)R9U9i&M^QryB~c`1yaG>w_h;SN$+znuBvdV zTW0b@LNQK0_sAUfD-bU^xotr7?D-_?z^Zm)4CyPHH+0t3xE*mc_ngxP9;4roGUgx%=daF zq_(pkzk`MqMM}@3$wu#fGIB=u5mA{P;a@>&?mk2NI+R7+mjAr zmh$lqU@g+J!XfY={qFO)tY`gh+>NVnD)m3ty7E-|dW*&WfbJp6LQ|XyjT=j91{wW8 zFD8?(pFJ!q%ZHYoqzUPci7zxUW}xLQzwcWc0S<2uMJpeNvfwbT09j}PsBibwO*;0} zppe1gQ1D;^RN?OEEdl2|7rMD$)P|Jssq&F>FVD`xlnU-a1EC&F6zjt|g;z8Uc*+B( zcZr1IBK4m8PmliCeRW|#Qv%Ga*tb-=%nY=^v{y0(?rqp!6lgnGx^?dONX-M9TT!2U z4p(^q#eDy`l{b|FQ!arY9~lM`Q3#5uFsU5>%1_}0YBWKBBjp4z_gsXXz$N!XVJRsM ztbY#W&!M28P{5W6_yKUEr6CJ_IR>gY~DEscH3M!^qEv#2exL=<1KFnV@ z?|_1zFpe8Kehf1N%BGWEWmD$#=1C_*?yOno&OP*;yRSP-of1BeCY1OuicG`{K7GI} zXa1GFnkErySl&6m9wxb2DtsztmYagwuKh?5V^9yVfV$4Dpym`=Dn<(h6Q1mt3K)83 z+!Fd}rkD>wH3=bbH=2nx7!}Uid}=XBNq*lQIyDK;u&-T{ge*S)!n5z;U<~N9+%ZEd z{(@CpL%`#&7pof?LoE{g&NHsslrUc+6!MORybkEaiYcOq)X0LA>)b&(q*TI9l;00* zhW5BLFL*xR0!%K8UK9`&l{~}0sr4qmHf2Fq**k#-rP8wk?XsM{_48KW4L?$c+QS#B zb_Kiqg=4uQkTllwyH8#DD4DNbS=j}dd?OI7Bn@sGl_n2vM23-_9i3V_zeTu2_~Kv!%J4kI0;;+!D(SDDxbS!KqW~!RvZ#nH)0a*m{uOw3 z?ThGCG-y$9vDLAt1O8rYr6l;bcVct+QkRP#@!hY5!WVbulqLZ!qU0#`{7Ox+*30TQ zq7Nb=xn_7ya7XtRjEPio!3_p$k<5e+NE4VAOB0{C1CT2b?}^?#Q4weAYs9=tSi7-i ziN#TUk6Le9%_b@5$U^W}eUI-i4A1v9YQ3S|hjCf-8xU|g2dPBRw=^U|fy zP}PqtGBPsCf7!Ua2}4w_sT}^W$;FPqdK@4T*$f-cB^`=i{79h$502TO zUN_eIFEFR*ZiE8?E*l{{T3T89rn67w1b|4+sWptizybKo>oiK=3m6znlXmV|R_K7< zavWj7BPMjw)D9uTrW_Mbk0cb3rRdW)U*0Dy;J9#sTXEzL*r!RjgOaJ6>V zq7;&Zu3FsxWe!$S9N^>~x4EdO&{!cMTN1A%J_}@|8ad&(1!pq9j#t^weTK9mzQ9OTsxT@^Y?{yiVEAZ*fAFMqCJNpLK$r?`jL#|DhkCo0rEpu!?@s}( z3?Y};Ef2Dcdcuot2B-jeCc61NEgNVABT6$^C9a#(KL8e0_1x4EvAQ?Z>M&!({<-23 za1drkA1ig1?vR2mek`KKMGpxcfvN*G9v-j#EGFXgA82MNQ6T-DFF1#^AE87>;d64- zHmfMOb3-A4f9|#!FB4pNQROv$xS%v_Ce2GH+BXXm7m$ zbnf9d!Y&zfS|n3JNgHD#-p%kKtZOGpYw-pXiP35~kTxM4mpBdX6Vt;B)lP)2ySgVc zByIo=%dtudT8e))@LTlNxTfSlR&4qt^^}kw;7G_I>yNU3zM>rubDa;*Z^($@wnQ>S zsO}RpoRZU!A)cH8Y$vzLnCs26xXl*>Zl2}2;U)%TfC2;#jA=-f5I$k=soI2%6MBh* zjI+{kKE%J8#gAVM6uZ)R^UbqLp03i?L>Uj^0sykH7Ug|ad<5IF~NQmT}NBJPl7iMt6{4f%4cr)zzgA%$Zp#k!*p#$~67#s`H**b&h$dQ$CK=09}m{Q+Xj&n5mlcZ4P5hP@vAs$BRdx zwW{b?1Il%7TeRrt=v+I`Bixc2p_KI;%svAiLu*g6AfQVB6}-A zE21oZIy|Fr|9GM06{-C~X}OlecpY_(s!0rjVs9KnA*FSA#SEg5LE;1Bh0~>n;BCQQ zFIh0SH!Nh!#pGu8epTYHTGvf%B z0oQXI!EH9a!lAkWM10~`to48H^PGIg>BfrZwL^E?npekwN);~B4cc!c_CraX1Ar^$ z-@D+5xFQ?XG~RO8&Bt8UKa}=;hF41rKcOEBC|q-rPlnyrtbCd>owkx}39~{AyzW*z zK-g31yc&o55;KP~uNQt!hpdQ<2LhSKDgu$AP*ZiTt?QwC#^D+@h;siQ;HG!tkyB9s zQWCaP>`(k(PcXF!W?{+ag_QiA>`s#km{10875~5`o^&Zr1gw1#$hLiL2BribiS$s} z7KT#+gk(Qpn9}qy7!C@_)3b=4rpTxn8)1TB6#?Fw*L5S=?R>eRF#_y`oId@*ow9Wx zH$4%>y%LM+M|c@tAK>XAA1^`!JFkwu`1O(Q>8%J;g5LgT66lH7|7BHBl>cQ_xN=ah z%Rlq&myZ|ns(T#wI2FJUFTj{ZP2jbd=8_BiNwDLq-7*C2@v_G2rLDbBs%&Jp< zg|&9$*;jftUEB?9Ff|iD+m!!ejMc#Ot6zAfPdeQaMn$h#l+1D2rNWi4Qv4+_XW1al zPk-R?XXDWgdZk9n?}xMGW9n1eEOdJ94tyqEziPn`s+DitSy%;SC*>S923y7U zO>Ro^_3yKFapSl1m_y0?h%EH_Npn4*oNn$A#ED#Uv}v+inqeYzHldDzjvs=XpwmOl8b0gdY--F>^AD%$a8r zWz77oTlKvAeZRfG?;m*g(eWIPXZQTvzw5rPb**)-^E_9d)-7fA+cM5Wa?9B=IT;-f`-BbUV6SbEiZ$SKp4+uK?D_V zLB~EQHT41BK?FYi42b8Q&`zA-EhDTVk(^*7TmY2lf7A---9kG_ zU*x&XWai4hbY4;VEc@YNq_JvmbelD#LXTI9)7?^iEpoB&ACN~pbDucX1ra5U%MT*@ zE5H!jO4c`AAS2hTs^6^^MW&5k;WCeAUk7#AGbkY1&vMvF5xk{`-#gGDka6;R#SoQ5 z5NA3B0+^>wamj>1F5!_!*j)@Jsvn>n$$%uRtpEz$!0Njj!hS#~GJsImCJus53J8E} zhrxWOV3`$gcvEm)_m;Blrkik5_ZnOKsVD^^jLsB~K{WG&Ly6+xm4uuT?(Cajw2ge> zF$7`%+Q-X>sEVsMx&+!RsDT?GL*o~H@giHlk|^l-u8(`~e~&)*(c^`58UTMlC4XZ- z2p71Oz~_@=OCQN)p{`x&*h-XHTPp%_*l5-F27wN|+9DW^Lx-5ZWJo=yCJIh5c;UMP zcjuO{A+lodC-M&LD-~?{nXfP!nzauE-!Ij|_uGqnNO3Zs_>%F&7#=$V?UV$Z%L0Bs zL7iGhY}W*9?SVbJ3Yrfy&mgFP@S1Vi`&mZ+? z5DO4{o_3eai?lX0=>GUQ%2~LNBrC_xlkuYAKQL>ikG!eFKl;IAkVqUTtN4V3hAX~{ zLO6?|u;9sbPgZ~DOoC7p_Veb|m%a?^GssuU2(-gU%dVtE^e)+Z)6gs0I?2naLf07oc^|;X!8d&j2O}c^@|nF5CoKJ1_cY6`hMfu097yYQZmR z$-}u85xJ`vB8QuVka1<+qaRDlV&VLK-RgRL=YrB&4F}oH{(Y*iN#YPuD-~V*3jNkw zau=$rJnZiB7<-T4~nGqq} zfJ}+Nq+H8AgGc&k)OV2&XE739D>;3@&EMc6$nd5~FaC4{AyLRTxN^bu)*|!@uGcm? z`Y>JvbO(&);f&rES5I)pys1|c%8=rE=jAP0T1<^M+C5$9T@djn2{G(10U9&kHVP+= z9s1;JgnGQW{FvI`rb9$m858n2&O#uuK(3?j2ORFmf`8^hUsddPa-Zhgfz3LZ6{lFGfj@2C{xD=G$>fZ*0n2M58l(+^p z_2l`q)!-ZQOkLDi2r+B8kjHk8pPwOZlqif;xBWRSG4}@0KT&h)FTZmnZ=3cto2t3) zR0@c}sgS0KK7xd&5sIc5DKK(;f_s_yKBax26r$)$LxH02&pmn%xkqvCor#lGIcsJ; zW!jsBLg4YA^5P%=6>}E`LDyI3l_J30121WWU0H*DX4RQPW(9uG5QXl)*qz2&CS=qs z$x#{W1J|A*Vaqgl`|)w2;^LSop6k+db>~RfMa?t5gvwHaZ89`elrbis8a8**2@SHs zzTE4?69VLx61^RHht+g%y${`?1Nw1cdI)-`mgFIlVWa_zi;Iu^&z(PiH&xin5|3;a zyJWl*8o;y-g#d@=eytwgO>7m(^}2rWot{Em@c3ZE825P*1iA8yf77W=)JZy3%ueYC znHwV3lTT^SB^xBWdW*C29!4dCk7+EWar}OT;YgTp5Q34lxQIzi(uH&9ng9;PG2_n+ zkQV9!z7<@l0e~z{!b8ujs>YXy~AW!1= zz&c(P3OFT6P4Gb>Jhh$8@x#lWnHzdF)dg<~#vbuRuh_>9n$=KIVw45tI1|>7mkuY{ z2+rigVvN&XBp`SUw?31KRDoS??mdoce$ag#T5kL*7k-RrI9&Zc8xnlxLt>u7#j%rD z$%4Gf(UoVvcpo-lXQQ2f$=-Xd7Psjf9kuD(x5aO{JLdbnmt#p&Jo+rYAmYeLz%g&r z{3}&`sv+x_5yqza;FrapprpYE5sO2cBp5l&^iOV$Jf5nf$KrSIM?Am#JAtR}U-dc;dR>47nSNp(#eZSWXt zHR;T?(bLLV=)F(SNJ23DBs>+8ul>Fh%O&7~){1v@d%hA5dI2!va$Z-!EP<;fZ`I+U z0N2Et(uLIOLF}c&WQ$;-Ecn>0kVL1ntC&eq%j=^O)w1 zwUR5LM6R`xzJ;dgFG!+dJTlX@KohAQUAM0JK?8pZfQ675WRmQG_G^*|-|8J^ z)tty_*FU%D4Az|pY0(AD4u+g@;j`MB7?bFc{4|mDSIQ~yMm>h6ZmOtJim@eU)8XuN z9ph%UVmvYsVliZRF%Fm%Eqo<&11~j-hIq>;|L1$ZIeL zBptkwJY7L_{cEtZ5W~zK-a@4zyB-MNlm*{p^CVD>Bd4Tdg6 zDUfBs7t-Cm8pMa2*?s1b+Z6tAo`rAX{){uqm}fe%;SAb=Zxylc*$uxRAu)rzSO z*p#G5D8n~pl~*a$6}k>qVP>bfzU9ie?1TJLfGdrF&1osrMTu{PB!Wh(c1xtsVn6Ie z({uisAhw8zNW>?FRW#!uM6q)#^0j2RlR#8^z+j$a8aV$Tv|08^5G7F+_8mn697Qfiw1||S zY8pSSESuf%w2HdRn_}nCveU0bq3KY-+(Em-*Vn|iqtwqs!*8QEm-ljH0h6s2x$O@1 zBrzIhoR{jI$!6in5zRUg;*0mM1dS7wad68SQ>t)Lj%B?1{9YNeM{7ogVA6Y3UXw{O zGQEk$hvqf<1#5H#&d{pu)!p(ny@|Q%gyOz4y&?q@m+y8Xm1*56i1g_xRjChJe+sRa*UWHD%T7!QoSxQZ zcaqoSzS4q@1OS@pO|)TmvNF#jh>Q-#JfUg^H~OGUvl8z0OJz|UV^Pq1^0Z&YM(t$y zw&=~Q%8{SLB*I+PJ7aw<#N&n*2c?zzcjwF0#Br zb}sb8rQqoEy-0}9VeV;tBR-rQPw*@_xCp1Xrze6`O1iTTp8}<~R&>0ukz|fKeddf9 zW`nPpN*|;QR>+^U%Kp6qEWkc9ML2n|6XWX?h&%xdnuDJlarehil;NQozC@O8o)<$tcD{y&zB}iwzg&Q3IYv6H%o5+A zOni}3MJ|3F-KWs8e4kC#CAXCOv|Bt>ekCe%IY^Ih1jE};bT*WCirb2t(qe{}P5rvN z$7s0PwcVYDnK~)}1U3;gdz}4+z0WlUl=oJ@hAVVuUkLsBlX%Y6SSn!7%*GnDnv2e@ zX7=VRFRh=lo9d;#7@UGj!N=BgSdV%j_(Rod~$QLX*Z8uf4TG8;i%RYK#wc|6mj$o+`eW6NU-HC$8QXcU7okN3iE_0Y%NB}6}Wg_xuH8e zM!UsB9ue_%<2IXGXH4$ueVY$kM6-<;RbKnw%OVF6=zN~OF3@qlbq(0(R&%i{17O&7 z04U@C2QQNM^t?cvuzc0k`f~^9*4b+m+8mbx);-jt zw(L01lZS~_SP5t{aUAm$TaIi^Uv>sR}{U_k`DD61XRBZsDGz=BC}sRkvaQRyt!s%4TPy* zaNQ>_r&i9ZRra<~p!Z$^2MaQU+yUEmf2;;%S=q)U61cNYdxijBq~I^Nsp+r(v-iy>Swu2+!|h+?mQ- zNaAzp+WpOnjOmI7@z6o%#bTAas|=ks0*@aLmJwf=PBJ~ zlPIq@yiGKYeHv$1{?eB9*udt!2rX02vWt$AqL-(2=n;pKGe<}czeyKa8Ib|(l;#88-<7&S$PoPT2!n2JwIPhtXL5-hM?jmIvYIP#Wqq8Uw z<;8Cw~0g(IwCODYSAdwnCp(2 zCbuifEwWZoLFLq|<9uhdHOUx?+qkGx#`#Y-jh}hkINgR3L`R>)+)$vGw8#?n{vc}H zXt|SO=zuEvfZ|NY)BTPTeTmy@db_qAd|3UT7VbV<5PQa#$2mn7GNy*&CT+I3^L)sRpbxRooH%89;(IF#28kUfyz02*J` zd!Hn*`8R3nqTi7W^`YCC5*8|^W}!-ZkNu*r5=`XKW;cVzl-CVplpV@bhnos#$)r`H z1!aW44}d!fLf3eI-0!YK_uZ;j zM6=<^EEbpxdKa1{YC(2(b|uQY!$nI+3PYdta^qaZ#Kf%VuE4xXJTq=Oz12RG!9A1ULQGt) z^#U%I;bi72)$jBIp+<2iBq(-NaC!UK>Qo#*qW{?Dq>&N57pa44Ey|pi>bf7S)6Vze z^IH`Q=a!S7}&W!!ashWvtho4%C!9(4}=W%^nL1gUeUO>4Hs5o(r5RhAb` zplnSXN0cSzPlh`+xFmpqnBS);=cXz>!NjFXeEt69hHF-HisN~r9@T^=JspywcuF5V zRj=S9^mmJ~PM2}FPfI)byI^#BhiiE%;pu5;9IZhWk#I>17bT59y@T{n>MYdtz3c4)e1vUb(V(slT2}Oo`DaXOLP5s^5S- zJbTh(C@_H6_+un#+pmDAaL~{Gu{e%x94YY`ocmFA3L=M(1pM^N{#cw0JTdr@Bk+f% z6?{j2YbfI2svu{j!oPzu?1cow5&Yq;=dS%6fenwjy_J+&m9rHxoHl{3)%>UV=~zNO z{9hm~`25a9VXhP=hKcHCAUIB99i%2bC^Z(k7AU$W0c(Z6CVkjyjD~JKbc3Q7p^YB^ zz7`3bnt>AF3IeH;%L*UIZ`_dp*3&*%Fx;233%}@-^>7MybL)-9$Z?T^fMDV=8y$ zbObWG>wbypa{>uyhG)(Tz%oN20i>q6R-|l$KdMO6QzD+8OeVZuHg0!uQIdLLUufB& z>1n5G#Cyo$f6V>LYAdg=uZIR`-)woUmvY|6Ja+=VG_8O7%@y0FgSw5!M>`^At8)@a zDoFRoDMbNC^qb0+X1Z*VZXJb^>%T#r{?v@kAk1@!msvfb)bB0T0ZWj;SGC;44TcUa z{B|Wjn1nu;Tbnu2qrKH1mgjV{s{Y~%Kv!T#K`E&A3wG^=eVr~<;7ZjcV5%4D0s?K$ zSPyt82>^%h=+F5}>VTFnU$0g-_#w14a=;q2KI7FsqD}>>M;xL1Z*=bm0>s`7$ixP( z2sB`?Gz0r3TGpTam*MZi_+_TG!utNVvZJT&R<-q8SIc57&R$~lh39DK?q+S>@2{yd z|B331n1S^B52f4Q0FY_QKSi-VG?j7`(;pK&0voR)aI|(fW7WI(muJ^wHC{~uYz7{) zl5@{6Jtbj1)`lF65p0&yj~3c#a|Cuz5kpw2(s435@&2WWnyDUnwc(c|Zx$Xgu&K>Q zCfL8(sF=yt90co#(sDbp9qhMkVIE1YmvQ35>HvX6nv-<-f4otQ&we5J`IoBs5U_P( zu(LM{9wMQ|F$L!mRBQ>~Z)VD0hcj6{LGb7~N5*^W+Ns>!y;hH~7yUUhq>6agDn92L zqr4`e(l7vgQ`p1`q_XEn@0W8LJlm<>jJq1!SH-0+-&SKaE_K~%7+djv z`=xA{qvMwpr2z)W_#3_`h!l8o{06+p>_{T(fY%!w6omb813Yr5T~bnFBH^DTGZLjA-@{{$VedeFLGA^`YX63}cZ zXa>HKAB_QZs;w7RRc}R5DP}&8&DiunT8sZ)G`Nw;2PgqYodS z&otxThkl&6c&QeU@_qtSiSPn+9$Rss8%qwSS|)m_H>>gc*9cPf1VK-gfQ8@k4@Nc# zNl6+;#uimJ_A3OR5w?zd3x?N83z9(U^^askjjCtO`|zQMtK z=}){$vR&eeP9;??Yt#_UnsFYdy!cnALU-dxy$TNJa#$_N!EmJ$OIsXk;S=RdDg12f9^;_rZ17rX?}<9IjhEYr z?Y{0)jL}4K&RmRi&vjd$RU+$(XUq8V(`QEfj)Ju4F~p{25y{O+Bwm8;;$xJN%34gF zgyp3oDSi@JAvV4?#wy-S<0Qvgyt8LHGJ_JXTn8<6jD%tRZJpyQ-3eSQneVBQyYK)r z#ciI1Ovqgo#}R~{jJnn3yQg@Ro&XGf7rGHKK_NspLg4az$#@6ow*RIlXD^MQuV9)t z>mLZ<8%q?J|KKVs19yT}-x~w^V9h|@iWY@H7z`0HUc{DAq8#`nKn4{L&H=jIFSw!a zU7`}BLO(=m+Ene&geTz!Uhi+F_oM>`G&7x-SG|^c>7dc^alyL>={l?tn8FZogl%R- zz!did{3_Pu+j`XK{%Ll{D>s<7MKhtg>g!>Zrjh6+^Lw{^zJc_atjrg$z>^2#NR9PD z{A9)l%3q5*k^k?89d%PMr3ufj%R*OjCwWQhtEj*v_)F@q_MoBmbJ!&H<#m}rF^oNg zxpp1Lf&=?Wi8Fd&DXdr=Xg_G_UxEgyxkG(Ak zfRRRD^i!N$eo=0B)4;Z;2+3--# zrgyt*=uOy1giH&n7xxqX5fRc;n?CD1g>Wi;Q;?|T;JkPhetv+{@?4K^&!P-?%A{~A z*(}OKpJ7T(QlT?#QPGL4&vDiwU&&r;u2%oR<_Arvy7cq`gdV>mqE4(=tRl zbjaJ!gA~xbG?YUZeipiD`<*}tW-oa{N6_6iOc-{g>vLbujHuU+&QW9GZ~<>jhmvVp zVW6XCvc;lCCbz!8B2ZYz}dP?jw5y#&tI zzYA=;wXF82E9rrs5|BZIT4Xp*qYoa;btV#nw2vcjWAg>(IRunMkGdOolA$ugk=3O8 z5{l5>6)=H(g*N=sxC|0U0j}KMsKU*FlROCFtRn42f8n1^gox_8lF*j35T6&6#&8f( zp?XLT0q*w}8+Q5xZ~0+G)b-FqQ;{&>cn^MEc$C;6{CrP#5=uZ<;6FzHf);2n%q5HG z);$e-=0}idilCeA`mFR^0N7Pcvtj>Lh=h~@$*KWfjrqm3C3>7I2;F;TF7(>TYczsg zQhEKK-7ZQE_v%T<)nMDXj>WP>C>cj4wX_E2-~ke-YsJg2`2jgLIg|`!+0a& zGj|N_`b;r}CEy15Cj8@KDn`VtijBxa9B{+uu>ML8qMsvaAz&XK2K48FOQ;X0GR6YP zehAa847onIxg0}JilIj?s1@Z>EnuGh0ON;vL34ySX}dNqlqr`ufYSs$&gl<#mG`KB z05von+WsLbkWhVs5@K_X_5+Y;k&{^bgq;joid%%RC5_wY4PiUnA^^DuvlG;q$+bWY zv&_7>2)t-fTpVzxxB~4mP#Ga!pg>7(=y6RX`bS8hB2BKH>m!S7l56m3P!btIIXg8RM|0)U1fut-j7CbaH?Zx6vq_>Eqz z^(myI3xeJI#HVQ((8FL`_k(Tc34@hu* z?1z`Tm7vU_M@r2{I7YlD+ngS<$j)fFX3+BJb7GuO3`YupvV6bFxuB;Ztrq?g6J;cL zTagJk->XmwKWOjqNjSnrd^vl0JFEre(rU?iXdEDdn|D>SBg;;33k#OwwG@p%@-w3! zvVq~kR;yM>6vt|DGe7hcL_?3i&E#Px@Q@1)tyxeWWIGR;&{O>(MSw#l;T7F%Qb_F{K zi6wdYX^>*RFIPqK=Q7AZ>Y>1MoTnQDX6AqV4!8W^zchqgLI(3sy^TkPufqUz^QXQR z88j6OkiUXGb_PNN3d06M*4YWqjWG7B7CIJ~DPJPd&>)urxg3(AR3hj`S#G)^{7m!@ zF;J!iFop)u7+fb1YNQ2H4x>&bC)gxsi6WkxO3zvL+lVN#7F7-EmM=E-dD{DLkg2~NUt^{FhPoP7>;0xAECa#Y~DcsVD|8M>| zUK~3=Xjt^`V8D!PdLXUmi*viIYIDNO$|uj+Y2leA5gm*;yaI%h=fOuwi3aT0{0vl- zk@6dDKFf(3ou9@)*h6??^3@qvk=z&db*kZADP+|HVb%NJ=4Q;m&-B!k4^crV=lx0l z3qK%0C7xu~w2@c-*@|Vr=%=tS0*;>RYQ;hl!2hdcAf!yca0V=2?<2zNv$QX%5Pg)d z5~NpL=JSg@@bgQAem_^F$6*v#6j?We^Vbpk=0kEduly^6J1sDxhydgi`4<)z;e(#Q z2R)-rFgW=jeB^^34lDxx<4b}Q&8UPyoj)Q+sv_-=xPt@x7O`kDFffpbM1&o1mq+qD znLC_$GqY$7cI=3p4>Bc{YO>#!w|RzzOQbmQND8qr7mW{hU!<=Yl4!~?lVHQo^*HdT z#s*L|s7uYq3jJT-KvkrlzI_o}~Nd%q_s^ zVvEZPx-h>U%3<*{DLq&OZ;2pw47BlNoMf3|$laFX*z@4zj7QSEwr@IylPePqzXK5j z-Xr4@gL~>C#_`dWKJub@_A%d0I=I)-pijT z3$DT=Yh%M_!=L|lzW=%dD+C`v0Q?B;lj~BCsiMGJKPY~={Oo#ec1i zhun9@(g4YV*)|Ad(ttK5ydL!Bg>NbBj8gEr7eWezMFe-y$$r`euk?PTZ%_`zHdX3l zAl4}XDtY#WehaO>5JvB&RQT~%D_{>Uj+EwYiT+}o1|0VcY-knZKirFX8XMjl@QHs7 zu>X4w^^D*Or)lIDwqxLH8Eh{05M|ZBm9Epo%w&t<%qiA_L={on-aq>|;#JIEKS*tx zq0qc^q2_Q~t9old>*T@F;JN2WPtr32DEPpOUJj2OUe;SiKVZA@a=pUE!wcZdZi`}w zkO;nIN$~c(A0(1#P+tLa$;y`q-4_Kw^cd6L56`Cn*7;22)WH(2+2<1P5i6bdVF0xo8f106$%gq zqjjq|)Qa|R3>aj+E(M7Ph(AIM1`GnQ$`F7a<*Zmf@XVPB7usUl2QJNN~1ms9_hHxiK{aos+^QN-ABWiyNIC zf3zUnHMTIm_TZUO>Hf;0Na}G-T$E4OaAF;dcK63}hUDJ$yALGlR9G8*BZd(|vGvT_ z{1`83^mTvwKy182oD>st*;S_Blhu}1UBBT84tt_czp(dC)x=V`z^c@W=w=`qh8$5^ z+Q=hzc~O}CbW!TPs2a?+VP@Wh_-hV_HGK+{K3PCP%gf1;nh$0S|AlFu1pG_d4NP$- zr_$ng?_yF@3jtT3B%`odv`iwze3@q5BKeS#!gUfoCN?(E$rzWJSjSQ6;pw0v;`OUE zNec2bwbrz4g5<;S>d5&W883Z?M9WB5&SmMxz9-waFK`gKLmfets#*LfShl0-v1l`{ zqGIPzpTiU~@I?z_{?m$0mQ_5S2VaHK){Tox+mcG*jH9Nyi5R};J z#kSGt%(p{7;#A?D&3H9mlUp;13FhkaP7yv>_brG~DygTak>z67oCK98GYiWXpz=02 zhm}gSwzq>XW)vsDT*yf0?UGQ7r|)=}J`GfipA5p-Zg#?E9ryXd-4F!A(@X8 zU4m>zxQwL{Fm6~Lovb@pn)a=x;n6Eu->+8{I8B=&+WD zv#k2UxmQQCO~&*44%8^jx{pxq-|yY-zogD_ST~$V;`@%L>wQM#1+CnsQc&Cl0Xx6+ z?Rl86u^Ke7@iSb;d*-s^zUTTkXK!i=Vl#i{FRL)|u^*;sM7iJo{ZM$5EQQt78$#{K z3&Y8@x$U&|q4&AXD~p|Dja(<P8=`5s(XH?%>u4RCt=kr|QMYXL*!fSZ|AY zk99ngQ|-a^GmhJ#oX(O*<`UJCuEqbh! z^S%&#`ta_~o@uanI=9{HO&Gpt#(*fx!mhAUuT*NzJu;JCiXk1|>4-1f$#T--a$arc zcm4JCt#F4cV0F(b^lDRr-toL_{Aat{j|i=|(D)5{T2Me)JXkgn=)?MnpMN(@t&3ve zxt`B#ZaQPeWlR9tTDv5s(4iF9Tzyd|M0$2 zzon{?^=u+nd(xU}(oBksI{BpK$Jqxo>r*67{-<7Qcp@a9x7@_qwn!yGtl>M$b5nRh zfxfmYyM@2bG@u@?0~DaV1BaY_x28Q?JA3muB=htPvdcgHSodCsTPOiikPej`rwHgt zpbLY$5KL3x0#~UX-3u)7N_KQjjULn7^Y&Tl@ZnGQHZ3eM$SSeP+l-*8XVCJ{ zrE2x)53ooJ zauRYd3@SU~z{rp4ZP%v9+6UtK5g4~11oI$Ch1^SGc)}n&I>DI}@w&aY|5dpwx1QmF ziw`yV5Z&eQ7hUDz{O;oJ7O{@MES5Y>WN*knfB%8d^Kr@Xqort1vqst8iSgLYGbUuL6ym(?KlI(V%uVD8MZPMhbQ%gJlb!6G0OFvF{Dqqd z)SVSsK2du`W}Z7yJ_Dmh30wLn*X!Pj`!f#aE}2 zt027lNT?l+nNx{82{s#iVnjyzF$i_jx2a_Dc5(9N+XRm0-R?e>nLoZmd1Z|FF-SwEuOQ=2pyR_DmH;im>S3 z)Xxd=;il$dwA{nZTQHRG{#n7j#f$`AyN5YmpSUYV-Y>qVw-PlHh#$^Dd9==qysKq) zY&+Q9K<1f#z3KV&yorr6TtvTP8I#Rd9p_;q_C)1=p@d3lyxlEs8{LSz-XDl|tgB5W z`k^6?nevc=$67neKUY9+{cB0z`;TSJ0`1;nDqn9$*@^6a7Q29zBEwa?Sm=S=Qi}Ju z+B0q8ZWh6WfI@oX0`Nt?KVVf8ymtMC?z&CAPlDl?=Tf3juS8T9w~oT5KJM%J?oZt^ zRpW6rBBFaeKQTJv3oZfn=&#TW1i>x+}vDxUMlx|c7pJB zw)B_ynpyHr*ZE|{W8=6bDUl(D8@`vELf`TH;PsfX6u{km8?#i;V>zAfar@?^cp_1K?2?8ZWa!);5X>^B`d{e>q zYlpNrDvxi%#5TVs-1xzF9qx*y5p7r^D&04&2n7@i#*rK9aVqQiZ^tml*6eUZq)R$c z-hg~&CG6dI#@R-7W~c9nYz&Wto%SIbsK5H5y?@nd=JI-CWwjd{`|j2qzAeL*p&~J0 zg!LiQaZVd@U*wWd+t2|c4Bs4d$pqG`#L+pDaVk;H&x^(tpsG|e4pZH@RgZvUK>8C8 z{Rsmn@h&MBmQROd>YO5{@fBT1-nIL7SbeDy4Y{5-z1jg)x%ZOW%(pVrF}0EHiF%DA zt@m->uBDG~ORnn0ZmXZ>DKyVX+gqnys#?oDdrVh;6UBE_sXB7h6)cx)Uc2ryY?GNk zV{tIt6#J#w-FRiBRCd11u=K(^=dcIabV_Fohh!hl#m4Mf#wY#QH5Ftn>KFssh8D4& zr(Mp5uFhApLqi@O;rmH9aD9G8BWXroJ0R0{c$SN_B~==Kx`%>|pQ15Gd_p6Zi55p; zf%$aE+}dr8`3$=VQ*srJ2D&((Fw}z@ixGDG`Z`L`IJs;z} z!HHtBe7{DeCP;O-c6TY%PkBnMUJjJ7v8Zk7v3+Tg8g5<{^AyDoKhEcVe_4OL-R!vZ z<4B)sd-GXVMt?nCP6vNM@}88Jb?mFls#XsLDgw5y&&jqVv_-K}txu@~6O5jR!no&9 z%jN?YXA9n`vzwN=hu?IzdjiU;?N-~}R}0!c`;dVi7XTl^UoH+CS|0w_Hzqpf)#epm zoiF^9lb?Ui@)z*pCM_+NO4a1Fi)Ih}F9?4Iyjo=yOk+h~CV%;2u=*k*P=v{Q&y&-U z4rpeBkVL%#;EHFjKN3bfLrZNrGfEy;%i?puTB&2})3bw9Z98V)_x+`!zF_6u72zbp z(=I>1@jkLb;{lA7m1wG`hrICo0Ut;*?<;+8_QP_g$J&W94*LRv0j!5?J~c;s7T+w` z@H$y*J5_RxGlWB)I6EG!SS~!$bTcrbklQQkSb2B?~%St2o5&+?7&`pygae;iE6R+5`~ zw^7ksQ!731vo=BR#4owL@oo`IEpf=vvs2@l+w#XV&)BXL*j3}GTR%`zl(QD@nBE7r z0S?~!w`uB5@`(xW&sVf!g?CMa-sV#`zdQ6H?HZrGXkwFOB}ql`UirvU();iw&)1yR z!h%cRLq(UkBoZ8+iL5f5J$v?)Y^pX;J<_=hcildFUo(W`?Ow{}A) zciDoeD#mdnBJ1%~eW^x-C(Yp&pV=CHuG`t%eTm+eaZ+nXx_j;(Zxu&8LN|BM^qR2B zOsHd}Dt;HBa$RLOCegl@=JwukuTG!hb&y3f@7h4%Syb4^fhW7Iagjnq>MugE>9+^BBAms&XAswdr8x9qTux3fYz4!y`@lO!}u!KZfVS`WPGXZK-HgcK#bh( z;rCzH`&{dD*uW~{Fw$+9KU!QIL4Tl1%A9!x zn4>~^PxbmvpIoP);m|V!BO8f!LP&95;++%~(wA-R@cJ`#ZA18X+BF@Srlp78@-l?7 zQ;|Q9cyfz>P#Q|)j)Xk=S`eDyeOzcDMRghM@=^-d3d^TRrc;3O`|bQ8uqn5|_2Fs3 zhXfRtDmX4(84~Tjq}Z7X5VKom{VkYGi{MIw>~{o_N+AK~ml3gE?Yo&3xzqntbaVgX zoAf2K28@j?y_=Xwa!hK_6U@RBsKE_`s*4m42AM9+utNq_&I+*WAsIdu%u$`R@I#@P zOTjF5g_N22;GR%biQI^j)o6tRmWUqNK<)4YZXO;UGsD-FhDje<(YnTYzlPrtw#+&h z4nNrAuz9Z(rKiO-LgFX2VKnoYU~AFdyw{igr#HJ+DU|PWjhXh+@c6zK7zk0o z&CQK5|B;QLl8YD$Ncm>a=Xp~^D|ju5P@c3%?4M$A_Z|7}mdUtf27T>&PlC>chC@LoaQn_|^LlkS_3yuIs zL9=#M&!LEy!INKN+YWCZG2-wMQL^R(-RB>LJc|^+6;`%JxwF*Wn}U*w}*v*b>+n*sch@Lcrqg9R$pZ z4I)otCgoVZr4x9L%L+!Jooq5eraRN+{Q-;l#dwGOGU> zfJ|*`LaP+{(A* zqR*e*fQMFwrVE$adMM17#-_Y@{}iAttGHitnAM5iq4$ej5XuCy;Kvb(krXH!azFm3 zQ&Q(?a19P0Lf?3OCz%aWSai%g7{+A-#l`GU@GF4jn`!YqUELIDR%8Ov83oQLa>61i z@&K;f`;V)wUvujMOf$Ct{8;xH$F-C5Esg{zFb9(Yilz#jt_&GO!f9t$BqIY2hs3X@ z9;BF9w%f+^lmGq_A>ZNafQ9@4i;9XH2@OELwmzM{w<{_q2d17SZi4ItRavPyJUomf zXAt;RRaM3D`(=u!?(#CA^}ITpbR$yG@{X`zlYG76EDzS=we!;6LQV4i>G7;)k>WSe z(Vt>5=I|$x-GRByCljIn$3GBWL1oN^S0`KM1a19q|M=hk`hQpLUsm9Mcgw#l#($lp e|L-X|qF@YA7umZ}t$+sqla`Pde{)Cw@&5s*P1@-I literal 0 HcmV?d00001 From b738100991c1b19418a45336fbba444666054c94 Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Wed, 8 Sep 2021 18:59:49 -0300 Subject: [PATCH 08/37] [#5] feat - creating fabs --- src/app/App.js | 1 + src/components/Fabs/index.js | 62 +++++++++++++++++++++++++++++++++++ src/components/Fabs/styles.js | 28 ++++++++++++++++ src/pages/Map/index.js | 19 +++++++++++ src/theme/theme.js | 3 +- 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/components/Fabs/index.js create mode 100644 src/components/Fabs/styles.js diff --git a/src/app/App.js b/src/app/App.js index 990b18b..1b9ef04 100644 --- a/src/app/App.js +++ b/src/app/App.js @@ -1,6 +1,7 @@ /* eslint-disable no-console */ import React from 'react'; import 'config/ReactotronConfig'; +import 'config/LayoutAnimationConfig'; import Routes from './Routes'; const App = () => { diff --git a/src/components/Fabs/index.js b/src/components/Fabs/index.js new file mode 100644 index 0000000..cc8f223 --- /dev/null +++ b/src/components/Fabs/index.js @@ -0,0 +1,62 @@ +import React, {useEffect, useState} from 'react'; +import {LayoutAnimation} from 'react-native'; +import PropTypes from 'prop-types'; +import {Container, Icon, Option} from './styles'; + +const Fabs = ({actions, alwaysOpenActions}) => { + const [showOptions, setShowOptions] = useState(false); + + useEffect(() => { + if (showOptions) { + LayoutAnimation.easeInEaseOut(); + } else { + LayoutAnimation.spring(); + } + }, [showOptions]); + + const onPressItem = (item) => { + setShowOptions(false); + item.onPress(); + }; + + const renderItem = (item) => ( + + ); + + const Options = ({items}) => { + return items.map(renderItem); + }; + + return ( + + + {showOptions ? : null} + + + ); +}; + +Fabs.propTypes = { + actions: PropTypes.arrayOf( + PropTypes.shape({ + icon: PropTypes.string, + onPress: PropTypes.func, + }), + ), + alwaysOpenActions: PropTypes.arrayOf( + PropTypes.shape({ + icon: PropTypes.string, + onPress: PropTypes.func, + }), + ), +}; + +Fabs.defaultProps = { + actions: [], + alwaysOpenActions: [], +}; +export default Fabs; diff --git a/src/components/Fabs/styles.js b/src/components/Fabs/styles.js new file mode 100644 index 0000000..98c0440 --- /dev/null +++ b/src/components/Fabs/styles.js @@ -0,0 +1,28 @@ +import styled from 'styled-components/native'; +import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome5'; +import theme from 'theme/theme'; + +export const Icon = styled(FontAwesomeIcon).attrs({ + color: theme.colors.white, +})``; + +export const Container = styled.View` + position: absolute; + right: 0; + bottom: 0; + margin: 20px; + align-items: center; + justify-content: flex-end; +`; + +export const Option = styled.TouchableHighlight.attrs({ + underlayColor: theme.colors.secondary, +})` + border-radius: 100px; + width: ${({size}) => size}px; + height: ${({size}) => size}px; + background-color: ${theme.colors.primary}; + align-items: center; + justify-content: center; + margin: 5px; +`; diff --git a/src/pages/Map/index.js b/src/pages/Map/index.js index 6459edc..03e8dda 100644 --- a/src/pages/Map/index.js +++ b/src/pages/Map/index.js @@ -1,10 +1,28 @@ import React from 'react'; import {View} from 'components/UI'; import useLocation from 'services/useLocation'; +import Fabs from 'components/Fabs'; import {MapView} from './styles'; const Map = () => { const {location} = useLocation(); + const actions = [ + { + icon: 'draw-polygon', + onPress: () => {}, + }, + { + icon: 'map-marker-alt', + onPress: () => {}, + }, + ]; + + const alwaysOpenActions = [ + { + icon: 'street-view', + onPress: () => {}, + }, + ]; if (location) { return ( @@ -17,6 +35,7 @@ const Map = () => { longitudeDelta: 0.0421, }} /> + ); } diff --git a/src/theme/theme.js b/src/theme/theme.js index f653e58..ec3b939 100644 --- a/src/theme/theme.js +++ b/src/theme/theme.js @@ -12,7 +12,8 @@ export default { }, }, colors: { - primary: '#448AFF', + primary: '#913426', + secondary: '#B6594A', red: '#ff0000', grey: '#9E9E9E', white: '#ffffff', From b1a6a66d38e28ffd9fa1416c8b7e3ec16fae998b Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Wed, 8 Sep 2021 19:23:59 -0300 Subject: [PATCH 09/37] [#5] feat - creating marker modal Co-authored-by: Alexandre Miguel --- src/components/CreatePointModal/index.js | 45 +++++++++++++++++++++++ src/components/CreatePointModal/styles.js | 29 +++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 src/components/CreatePointModal/index.js create mode 100644 src/components/CreatePointModal/styles.js diff --git a/src/components/CreatePointModal/index.js b/src/components/CreatePointModal/index.js new file mode 100644 index 0000000..1ec7e19 --- /dev/null +++ b/src/components/CreatePointModal/index.js @@ -0,0 +1,45 @@ +import React, {useRef, useMemo} from 'react'; +import BottomSheet, {BottomSheetScrollView} from '@gorhom/bottom-sheet'; +import PropTypes from 'prop-types'; +import {Text, Btn} from 'components/UI'; +import theme from 'theme/theme'; + +import {Container, Option} from './styles'; + +const CreatePoint = ({locationSelected}) => { + const snapPoints = useMemo(() => ['50%', '90%'], []); + const sheetRef = useRef(null); + + const onSave = () => { + return locationSelected; + }; + + return ( + <> + + + + + + Teste + + + + + ); +}; + +CreatePoint.propTypes = { + locationSelected: PropTypes.shape({ + latitude: PropTypes.string, + longitude: PropTypes.func, + }), +}; + +CreatePoint.defaultProps = { + locationSelected: {}, +}; + +export default CreatePoint; diff --git a/src/components/CreatePointModal/styles.js b/src/components/CreatePointModal/styles.js new file mode 100644 index 0000000..89042c9 --- /dev/null +++ b/src/components/CreatePointModal/styles.js @@ -0,0 +1,29 @@ +import styled from 'styled-components/native'; +import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome5'; +import theme from 'theme/theme'; + +export const Icon = styled(FontAwesomeIcon).attrs({ + color: theme.colors.white, +})``; + +export const Container = styled.View` + position: absolute; + right: 0; + bottom: 0; + left: 0; + margin: 20px; + align-items: center; + justify-content: center; +`; + +export const Option = styled.TouchableHighlight.attrs({ + underlayColor: theme.colors.secondary, +})` + border-radius: 100px; + width: ${({size}) => size}px; + height: ${({size}) => size}px; + background-color: ${theme.colors.primary}; + align-items: center; + justify-content: center; + margin: 5px; +`; From 811ae9f15c795ff22550753cbcaacf751f81af02 Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Wed, 8 Sep 2021 19:24:54 -0300 Subject: [PATCH 10/37] [#5] feat - adding animations Co-authored-by: Alexandre Miguel Signed-off-by: Guilherme Banci --- src/config/LayoutAnimationConfig.js | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/config/LayoutAnimationConfig.js diff --git a/src/config/LayoutAnimationConfig.js b/src/config/LayoutAnimationConfig.js new file mode 100644 index 0000000..bc03b2d --- /dev/null +++ b/src/config/LayoutAnimationConfig.js @@ -0,0 +1,7 @@ +import {Platform, UIManager} from 'react-native'; + +if (Platform.OS === 'android') { + if (UIManager.setLayoutAnimationEnabledExperimental) { + UIManager.setLayoutAnimationEnabledExperimental(true); + } +} From f28f5fd1906673103e807d4ac1c1f618a3128828 Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Wed, 8 Sep 2021 19:33:02 -0300 Subject: [PATCH 11/37] [#5] feat - opening creation modal Co-authored-by: Alexandre Miguel Signed-off-by: Guilherme Banci --- src/components/CreatePoint/index.js | 51 +++++++++++++++++++ .../styles.js | 0 src/components/CreatePointModal/index.js | 45 ---------------- src/pages/Map/index.js | 7 ++- 4 files changed, 56 insertions(+), 47 deletions(-) create mode 100644 src/components/CreatePoint/index.js rename src/components/{CreatePointModal => CreatePoint}/styles.js (100%) delete mode 100644 src/components/CreatePointModal/index.js diff --git a/src/components/CreatePoint/index.js b/src/components/CreatePoint/index.js new file mode 100644 index 0000000..1176c14 --- /dev/null +++ b/src/components/CreatePoint/index.js @@ -0,0 +1,51 @@ +import React, {useRef, useMemo} from 'react'; +import BottomSheet, {BottomSheetScrollView} from '@gorhom/bottom-sheet'; +import PropTypes from 'prop-types'; +import {Text, Btn} from 'components/UI'; +import theme from 'theme/theme'; + +import {Container, Option} from './styles'; + +const CreatePoint = ({locationSelected, show}) => { + const snapPoints = useMemo(() => ['10%', '50%', '95%'], []); + const sheetRef = useRef(null); + + const onSave = () => { + return locationSelected; + }; + + if (show) { + return ( + <> + + + + + + Teste + + + + + ); + } + + return null; +}; + +CreatePoint.propTypes = { + locationSelected: PropTypes.shape({ + latitude: PropTypes.string, + longitude: PropTypes.func, + }), + show: PropTypes.bool, +}; + +CreatePoint.defaultProps = { + locationSelected: {}, + show: false, +}; + +export default CreatePoint; diff --git a/src/components/CreatePointModal/styles.js b/src/components/CreatePoint/styles.js similarity index 100% rename from src/components/CreatePointModal/styles.js rename to src/components/CreatePoint/styles.js diff --git a/src/components/CreatePointModal/index.js b/src/components/CreatePointModal/index.js deleted file mode 100644 index 1ec7e19..0000000 --- a/src/components/CreatePointModal/index.js +++ /dev/null @@ -1,45 +0,0 @@ -import React, {useRef, useMemo} from 'react'; -import BottomSheet, {BottomSheetScrollView} from '@gorhom/bottom-sheet'; -import PropTypes from 'prop-types'; -import {Text, Btn} from 'components/UI'; -import theme from 'theme/theme'; - -import {Container, Option} from './styles'; - -const CreatePoint = ({locationSelected}) => { - const snapPoints = useMemo(() => ['50%', '90%'], []); - const sheetRef = useRef(null); - - const onSave = () => { - return locationSelected; - }; - - return ( - <> - - - - - - Teste - - - - - ); -}; - -CreatePoint.propTypes = { - locationSelected: PropTypes.shape({ - latitude: PropTypes.string, - longitude: PropTypes.func, - }), -}; - -CreatePoint.defaultProps = { - locationSelected: {}, -}; - -export default CreatePoint; diff --git a/src/pages/Map/index.js b/src/pages/Map/index.js index 03e8dda..067bf78 100644 --- a/src/pages/Map/index.js +++ b/src/pages/Map/index.js @@ -1,11 +1,13 @@ -import React from 'react'; +import React, {useState} from 'react'; import {View} from 'components/UI'; import useLocation from 'services/useLocation'; import Fabs from 'components/Fabs'; import {MapView} from './styles'; +import CreatePoint from 'components/CreatePoint'; const Map = () => { const {location} = useLocation(); + const [showPointCreation, setShowPointCreation] = useState(false); const actions = [ { icon: 'draw-polygon', @@ -13,7 +15,7 @@ const Map = () => { }, { icon: 'map-marker-alt', - onPress: () => {}, + onPress: () => setShowPointCreation(true), }, ]; @@ -36,6 +38,7 @@ const Map = () => { }} /> + ); } From 360e9e51deb2c1b2b701c9c9103fbd3826bf3550 Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Wed, 8 Sep 2021 20:00:25 -0300 Subject: [PATCH 12/37] [#5] feat - ajusting create marker modal Co-authored-by: Alexandre Miguel Signed-off-by: Guilherme Banci --- __tests__/App-test.js | 6 +- jest.config.js | 3 + package.json | 1 + patches/rn-material-ui-textfield+1.0.5.patch | 26 +++++++++ src/components/CreatePoint/index.js | 61 ++++++++++++++++---- src/components/CreatePoint/styles.js | 8 +-- src/components/UI/Input/index.js | 10 +++- src/pages/Map/index.js | 8 ++- src/pages/Settings/index.js | 12 ++++ src/pages/Settings/styles.js | 14 +++++ yarn.lock | 56 +++++++++++++++++- 11 files changed, 181 insertions(+), 24 deletions(-) create mode 100644 jest.config.js create mode 100644 patches/rn-material-ui-textfield+1.0.5.patch create mode 100644 src/pages/Settings/index.js create mode 100644 src/pages/Settings/styles.js diff --git a/__tests__/App-test.js b/__tests__/App-test.js index 1784766..5f8b132 100644 --- a/__tests__/App-test.js +++ b/__tests__/App-test.js @@ -4,11 +4,11 @@ import 'react-native'; import React from 'react'; -import App from '../App'; +import renderer from 'react-test-renderer'; +import Map from '../src/pages/Map'; // Note: test renderer must be required after react-native. -import renderer from 'react-test-renderer'; it('renders correctly', () => { - renderer.create(); + renderer.create(); }); diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..8eb675e --- /dev/null +++ b/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + preset: 'react-native', +}; diff --git a/package.json b/package.json index f9a7c8a..015c6b5 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "postinstall": "patch-package" }, "dependencies": { + "@gorhom/bottom-sheet": "^4", "@react-native-community/async-storage": "^1.12.1", "@react-native-community/clipboard": "^1.5.1", "@react-native-masked-view/masked-view": "^0.2.2", diff --git a/patches/rn-material-ui-textfield+1.0.5.patch b/patches/rn-material-ui-textfield+1.0.5.patch new file mode 100644 index 0000000..c3beb32 --- /dev/null +++ b/patches/rn-material-ui-textfield+1.0.5.patch @@ -0,0 +1,26 @@ +diff --git a/node_modules/rn-material-ui-textfield/src/components/outline/index.js b/node_modules/rn-material-ui-textfield/src/components/outline/index.js +index 8d0d8c1..660a28e 100644 +--- a/node_modules/rn-material-ui-textfield/src/components/outline/index.js ++++ b/node_modules/rn-material-ui-textfield/src/components/outline/index.js +@@ -2,7 +2,8 @@ import PropTypes from 'prop-types' + import React, { Fragment, PureComponent } from 'react' + import { View, Animated, I18nManager } from 'react-native' + +-import styles, { borderRadius } from './styles' ++import styles from './styles' ++const borderRadius = 4 + + export default class Line extends PureComponent { + static defaultProps = { +diff --git a/node_modules/rn-material-ui-textfield/src/components/outline/styles.js b/node_modules/rn-material-ui-textfield/src/components/outline/styles.js +index a6e0d0f..64b407b 100644 +--- a/node_modules/rn-material-ui-textfield/src/components/outline/styles.js ++++ b/node_modules/rn-material-ui-textfield/src/components/outline/styles.js +@@ -1,6 +1,6 @@ + import { StyleSheet, Platform } from 'react-native' + +-export const borderRadius = 4 ++export const borderRadius = 10 + + let containerStyle = { + position: 'absolute', diff --git a/src/components/CreatePoint/index.js b/src/components/CreatePoint/index.js index 1176c14..13e6339 100644 --- a/src/components/CreatePoint/index.js +++ b/src/components/CreatePoint/index.js @@ -1,31 +1,70 @@ -import React, {useRef, useMemo} from 'react'; +import React, {useRef, useMemo, useState} from 'react'; import BottomSheet, {BottomSheetScrollView} from '@gorhom/bottom-sheet'; import PropTypes from 'prop-types'; -import {Text, Btn} from 'components/UI'; +import {Text, Btn, Input, View} from 'components/UI'; import theme from 'theme/theme'; +import required from 'validators/required'; -import {Container, Option} from './styles'; +import {Container, Icon} from './styles'; -const CreatePoint = ({locationSelected, show}) => { - const snapPoints = useMemo(() => ['10%', '50%', '95%'], []); +const CreatePoint = ({locationSelected, show, onClose}) => { + const snapPoints = useMemo(() => ['12%', '50%', '95%'], []); const sheetRef = useRef(null); + const [name, setName] = useState({ + isValid: false, + value: '', + }); + + const [description, setDescription] = useState({ + isValid: false, + value: '', + }); + const onSave = () => { + sheetRef.current.close(); + setTimeout(() => { + onClose(); + }, 1000); return locationSelected; }; + const pointName = () => ( + + setName(value)} + value={name.value} + autoCapitalize="words" + onFocus={() => sheetRef.current.snapToIndex(2)} + rules={[required]} + /> + + ); + if (show) { return ( <> - + - + - Teste - + + + setDescription(value)} + value={description.value} + multiline + /> + + + diff --git a/src/components/CreatePoint/styles.js b/src/components/CreatePoint/styles.js index 89042c9..ac4c61d 100644 --- a/src/components/CreatePoint/styles.js +++ b/src/components/CreatePoint/styles.js @@ -3,15 +3,13 @@ import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome5'; import theme from 'theme/theme'; export const Icon = styled(FontAwesomeIcon).attrs({ - color: theme.colors.white, + color: theme.colors.black, })``; export const Container = styled.View` position: absolute; - right: 0; - bottom: 0; - left: 0; - margin: 20px; + top: 50%; + left: 47%; align-items: center; justify-content: center; `; diff --git a/src/components/UI/Input/index.js b/src/components/UI/Input/index.js index 063105a..f68f41c 100644 --- a/src/components/UI/Input/index.js +++ b/src/components/UI/Input/index.js @@ -2,7 +2,7 @@ import React, {useRef, useState, useEffect} from 'react'; import {PixelRatio} from 'react-native'; import PropTypes from 'prop-types'; import theme from 'theme/theme'; -import {TextField} from 'rn-material-ui-textfield'; +import {OutlinedTextField} from 'rn-material-ui-textfield'; const Input = ({ label, @@ -28,6 +28,8 @@ const Input = ({ externalError, multiline, autoCorrect, + onFocus, + style, }) => { const inputEl = useRef(null); @@ -78,7 +80,7 @@ const Input = ({ }, [blurredOnce, value]); return ( - { setBlurredOnce(true); }} + onFocus={onFocus} formatText={inputMask} onError={onError} error={externalError || validationError} @@ -105,6 +108,7 @@ const Input = ({ renderRightAccessory={rightAccessory} multiline={multiline} autoCorrect={autoCorrect} + style={style} /> ); }; @@ -133,6 +137,7 @@ Input.propTypes = { multiline: PropTypes.bool, autoCorrect: PropTypes.bool, errorMessage: PropTypes.bool, + onFocus: PropTypes.func, }; Input.defaultProps = { @@ -156,6 +161,7 @@ Input.defaultProps = { externalError: '', multiline: false, autoCorrect: false, + onFocus: () => {}, }; export default Input; diff --git a/src/pages/Map/index.js b/src/pages/Map/index.js index 067bf78..9456bc1 100644 --- a/src/pages/Map/index.js +++ b/src/pages/Map/index.js @@ -2,8 +2,8 @@ import React, {useState} from 'react'; import {View} from 'components/UI'; import useLocation from 'services/useLocation'; import Fabs from 'components/Fabs'; -import {MapView} from './styles'; import CreatePoint from 'components/CreatePoint'; +import {MapView} from './styles'; const Map = () => { const {location} = useLocation(); @@ -38,7 +38,11 @@ const Map = () => { }} /> - + setShowPointCreation(false)} + /> ); } diff --git a/src/pages/Settings/index.js b/src/pages/Settings/index.js new file mode 100644 index 0000000..64d9ad8 --- /dev/null +++ b/src/pages/Settings/index.js @@ -0,0 +1,12 @@ +import React from 'react'; +import {View, Text} from 'components/UI'; + +const Page2 = () => { + return ( + + Page 2 + + ); +}; + +export default Page2; diff --git a/src/pages/Settings/styles.js b/src/pages/Settings/styles.js new file mode 100644 index 0000000..15469b1 --- /dev/null +++ b/src/pages/Settings/styles.js @@ -0,0 +1,14 @@ +import styled from 'styled-components/native'; + +export const Container = styled.View` + padding: 20px; +`; + +export const FirstInput = styled.View` + flex-direction: row; + align-items: center; +`; + +export const InputView = styled.View` + flex: 1; +`; diff --git a/yarn.lock b/yarn.lock index b6dbd52..074a316 100644 --- a/yarn.lock +++ b/yarn.lock @@ -759,6 +759,24 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@gorhom/bottom-sheet@^4": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@gorhom/bottom-sheet/-/bottom-sheet-4.0.3.tgz#465d28bd39ff19e8ba248b514427c0d790d5de30" + integrity sha512-aIStbi8FxquhH4FRuzyQBau8QUPWQljkrq7kaSo+BFanuAoO0B/YpfakxlDSgum+m7p5jXDopj2GU6cLzw9+qw== + dependencies: + "@gorhom/portal" "^1.0.7" + invariant "^2.2.4" + nanoid "^3.1.20" + react-native-redash "^16.1.1" + +"@gorhom/portal@^1.0.7": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@gorhom/portal/-/portal-1.0.8.tgz#1582f7f2ce288e4622382c19ca4a5dff9f56c11a" + integrity sha512-APBRdSEPzxK5lOHU5zFoc9y938ACWBzkNBSDajubvtw5XGIWsxggCSyateDnIVs94LTuw1hWyYvM4OsYeepBQw== + dependencies: + immer "^9.0.3" + nanoid "^3.1.23" + "@hapi/address@2.x.x": version "2.1.4" resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" @@ -1691,6 +1709,11 @@ abort-controller@^3.0.0: dependencies: event-target-shim "^5.0.0" +abs-svg-path@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/abs-svg-path/-/abs-svg-path-0.1.1.tgz#df601c8e8d2ba10d4a76d625e236a9a39c2723bf" + integrity sha1-32Acjo0roQ1KdtYl4japo5wnI78= + absolute-path@^0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/absolute-path/-/absolute-path-0.0.0.tgz#a78762fbdadfb5297be99b15d35a785b2f095bf7" @@ -4412,6 +4435,11 @@ image-size@^0.6.0: resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.6.3.tgz#e7e5c65bb534bd7cdcedd6cb5166272a85f75fb2" integrity sha512-47xSUiQioGaB96nqtp5/q55m0aBQSQdyIloMOc/x+QVTDZLNmXE892IIDrJ0hM1A5vcNUDD5tDffkSP5lCaIIA== +immer@^9.0.3: + version "9.0.6" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.6.tgz#7a96bf2674d06c8143e327cbf73539388ddf1a73" + integrity sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ== + import-fresh@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" @@ -6176,7 +6204,7 @@ nan@^2.12.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== -nanoid@^3.1.15: +nanoid@^3.1.15, nanoid@^3.1.20, nanoid@^3.1.23: version "3.1.25" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== @@ -6294,6 +6322,13 @@ normalize-path@^3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +normalize-svg-path@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/normalize-svg-path/-/normalize-svg-path-1.1.0.tgz#0e614eca23c39f0cffe821d6be6cd17e569a766c" + integrity sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg== + dependencies: + svg-arc-to-cubic-bezier "^3.0.0" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -6638,6 +6673,11 @@ parse-node-version@^1.0.0: resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== +parse-svg-path@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/parse-svg-path/-/parse-svg-path-0.1.2.tgz#7a7ec0d1eb06fa5325c7d3e009b859a09b5d49eb" + integrity sha1-en7A0esG+lMlx9PgCbhZoJtdSes= + parse5-htmlparser2-tree-adapter@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" @@ -7109,6 +7149,15 @@ react-native-reanimated@^2.2.0: mockdate "^3.0.2" string-hash-64 "^1.0.3" +react-native-redash@^16.1.1: + version "16.2.2" + resolved "https://registry.yarnpkg.com/react-native-redash/-/react-native-redash-16.2.2.tgz#99ecb49810aab8ed778b6d8c8726a29117065d96" + integrity sha512-febggvSI93H796DS1ufNNf/8FQMw21UTiMYBRscmhzyIamcC194oNamW1UtbreRSC1OweKBDEbyxPSugiuncmQ== + dependencies: + abs-svg-path "^0.1.1" + normalize-svg-path "^1.0.1" + parse-svg-path "^0.1.2" + react-native-safe-area-context@^3.1.9: version "3.3.0" resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-3.3.0.tgz#6e0b45baa031589ec9c54f8359ace166a36aa5e5" @@ -8270,6 +8319,11 @@ supports-hyperlinks@^2.0.0: has-flag "^4.0.0" supports-color "^7.0.0" +svg-arc-to-cubic-bezier@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz#390c450035ae1c4a0104d90650304c3bc814abe6" + integrity sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g== + svg-parser@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" From 2648e20a2c517c4f8ac262fb4a1b2a78cb3dae99 Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Thu, 9 Sep 2021 03:00:42 -0300 Subject: [PATCH 13/37] [#5] feat - ajust inputs on marker creation Co-authored-by: Alexandre Miguel Signed-off-by: Guilherme Banci --- src/components/CreatePoint/index.js | 52 +++++++++++++++++------------ src/components/UI/Input/index.js | 6 ++-- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/components/CreatePoint/index.js b/src/components/CreatePoint/index.js index 13e6339..bf3c75b 100644 --- a/src/components/CreatePoint/index.js +++ b/src/components/CreatePoint/index.js @@ -8,33 +8,35 @@ import required from 'validators/required'; import {Container, Icon} from './styles'; const CreatePoint = ({locationSelected, show, onClose}) => { - const snapPoints = useMemo(() => ['12%', '50%', '95%'], []); + const snapPoints = useMemo(() => [110, '50%', '95%'], []); const sheetRef = useRef(null); - const [name, setName] = useState({ + const DEFAULT_STATE = { isValid: false, value: '', - }); + } - const [description, setDescription] = useState({ - isValid: false, - value: '', - }); + const [title, setTitle] = useState(DEFAULT_STATE); + + const [description, setDescription] = useState(DEFAULT_STATE); const onSave = () => { sheetRef.current.close(); + setTimeout(() => { onClose(); + setTitle(DEFAULT_STATE); + setDescription(DEFAULT_STATE); }, 1000); return locationSelected; }; const pointName = () => ( - + setName(value)} - value={name.value} + label="Digite aqui o título do novo ponto" + onChange={(value) => setTitle(value)} + value={title.value} autoCapitalize="words" onFocus={() => sheetRef.current.snapToIndex(2)} rules={[required]} @@ -42,28 +44,36 @@ const CreatePoint = ({locationSelected, show, onClose}) => { ); + const formIsValid = () => { + return title.isValid; + }; + if (show) { return ( <> - + - - + + + {pointName()} setDescription(value)} value={description.value} multiline /> - + @@ -76,8 +86,8 @@ const CreatePoint = ({locationSelected, show, onClose}) => { CreatePoint.propTypes = { locationSelected: PropTypes.shape({ - latitude: PropTypes.string, - longitude: PropTypes.func, + latitude: PropTypes.number, + longitude: PropTypes.number, }), show: PropTypes.bool, }; diff --git a/src/components/UI/Input/index.js b/src/components/UI/Input/index.js index f68f41c..6dcc126 100644 --- a/src/components/UI/Input/index.js +++ b/src/components/UI/Input/index.js @@ -29,7 +29,8 @@ const Input = ({ multiline, autoCorrect, onFocus, - style, + height, + characterRestriction, }) => { const inputEl = useRef(null); @@ -108,7 +109,8 @@ const Input = ({ renderRightAccessory={rightAccessory} multiline={multiline} autoCorrect={autoCorrect} - style={style} + height={height} + characterRestriction={characterRestriction} /> ); }; From 40e3731e0fa8022311ecd1d2549b950c82cf1fea Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Thu, 9 Sep 2021 03:05:05 -0300 Subject: [PATCH 14/37] [#5] feat - ajust inputs and eslint Co-authored-by: Alexandre Miguel Signed-off-by: Guilherme Banci --- src/components/CreatePoint/index.js | 5 ++--- src/components/UI/Input/index.js | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/CreatePoint/index.js b/src/components/CreatePoint/index.js index bf3c75b..54e6c36 100644 --- a/src/components/CreatePoint/index.js +++ b/src/components/CreatePoint/index.js @@ -1,8 +1,7 @@ import React, {useRef, useMemo, useState} from 'react'; import BottomSheet, {BottomSheetScrollView} from '@gorhom/bottom-sheet'; import PropTypes from 'prop-types'; -import {Text, Btn, Input, View} from 'components/UI'; -import theme from 'theme/theme'; +import {Btn, Input, View} from 'components/UI'; import required from 'validators/required'; import {Container, Icon} from './styles'; @@ -60,7 +59,7 @@ const CreatePoint = ({locationSelected, show, onClose}) => { {pointName()} {}, + height: 45, }; export default Input; From 741fc2504a02b6f1b15f3e5bc846986a4ed76d16 Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Thu, 9 Sep 2021 03:07:38 -0300 Subject: [PATCH 15/37] [#5] feat - ajust input props Co-authored-by: Alexandre Miguel Signed-off-by: Guilherme Banci --- src/components/CreatePoint/index.js | 4 +++- src/components/UI/Input/index.js | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/CreatePoint/index.js b/src/components/CreatePoint/index.js index 54e6c36..34d1a30 100644 --- a/src/components/CreatePoint/index.js +++ b/src/components/CreatePoint/index.js @@ -13,7 +13,7 @@ const CreatePoint = ({locationSelected, show, onClose}) => { const DEFAULT_STATE = { isValid: false, value: '', - } + }; const [title, setTitle] = useState(DEFAULT_STATE); @@ -89,11 +89,13 @@ CreatePoint.propTypes = { longitude: PropTypes.number, }), show: PropTypes.bool, + onClose: PropTypes.func, }; CreatePoint.defaultProps = { locationSelected: {}, show: false, + onClose: () => {}, }; export default CreatePoint; diff --git a/src/components/UI/Input/index.js b/src/components/UI/Input/index.js index 5135b80..a57b62e 100644 --- a/src/components/UI/Input/index.js +++ b/src/components/UI/Input/index.js @@ -141,6 +141,7 @@ Input.propTypes = { errorMessage: PropTypes.bool, onFocus: PropTypes.func, height: PropTypes.number, + characterRestriction: PropTypes.number, }; Input.defaultProps = { @@ -166,6 +167,7 @@ Input.defaultProps = { autoCorrect: false, onFocus: () => {}, height: 45, + characterRestriction: null, }; export default Input; From acb9447a3ef89a9d5a9a1aea5dbacd1a5458a5bc Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Thu, 9 Sep 2021 03:46:38 -0300 Subject: [PATCH 16/37] [#5] feat - create marker store Co-authored-by: Alexandre Miguel Signed-off-by: Guilherme Banci --- src/components/CreatePoint/index.js | 15 +++++++++-- src/components/CreatePoint/styles.js | 4 ++- src/pages/Map/index.js | 40 +++++++++++++++++++++------- src/store/actions/actionTypes.js | 1 + src/store/actions/index.js | 1 + src/store/actions/markers.js | 8 ++++++ src/store/reducers/index.js | 2 ++ src/store/reducers/markers.js | 18 +++++++++++++ src/store/selectors/index.js | 1 + src/store/selectors/markers.js | 1 + 10 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 src/store/actions/markers.js create mode 100644 src/store/reducers/markers.js create mode 100644 src/store/selectors/markers.js diff --git a/src/components/CreatePoint/index.js b/src/components/CreatePoint/index.js index 34d1a30..cdc720f 100644 --- a/src/components/CreatePoint/index.js +++ b/src/components/CreatePoint/index.js @@ -3,10 +3,13 @@ import BottomSheet, {BottomSheetScrollView} from '@gorhom/bottom-sheet'; import PropTypes from 'prop-types'; import {Btn, Input, View} from 'components/UI'; import required from 'validators/required'; - +import {useDispatch} from 'react-redux'; +import * as Actions from 'store/actions'; import {Container, Icon} from './styles'; const CreatePoint = ({locationSelected, show, onClose}) => { + const dispatch = useDispatch(); + const snapPoints = useMemo(() => [110, '50%', '95%'], []); const sheetRef = useRef(null); @@ -20,6 +23,14 @@ const CreatePoint = ({locationSelected, show, onClose}) => { const [description, setDescription] = useState(DEFAULT_STATE); const onSave = () => { + dispatch( + Actions.createMarker({ + latitude: locationSelected.latitude, + longitude: locationSelected.longitude, + title: title.value, + description: description.value, + }), + ); sheetRef.current.close(); setTimeout(() => { @@ -51,7 +62,7 @@ const CreatePoint = ({locationSelected, show, onClose}) => { return ( <> - + diff --git a/src/components/CreatePoint/styles.js b/src/components/CreatePoint/styles.js index ac4c61d..4215a69 100644 --- a/src/components/CreatePoint/styles.js +++ b/src/components/CreatePoint/styles.js @@ -9,7 +9,9 @@ export const Icon = styled(FontAwesomeIcon).attrs({ export const Container = styled.View` position: absolute; top: 50%; - left: 47%; + left: 50%; + margin-left: -15px; + margin-top: -28px; align-items: center; justify-content: center; `; diff --git a/src/pages/Map/index.js b/src/pages/Map/index.js index 9456bc1..3e445ff 100644 --- a/src/pages/Map/index.js +++ b/src/pages/Map/index.js @@ -1,13 +1,20 @@ -import React, {useState} from 'react'; +/* eslint-disable react/no-array-index-key */ +import React, {useState, useEffect} from 'react'; import {View} from 'components/UI'; import useLocation from 'services/useLocation'; import Fabs from 'components/Fabs'; import CreatePoint from 'components/CreatePoint'; +import {useSelector} from 'react-redux'; +import * as selectors from 'store/selectors'; +import {Marker} from 'react-native-maps'; import {MapView} from './styles'; const Map = () => { const {location} = useLocation(); const [showPointCreation, setShowPointCreation] = useState(false); + const [region, setRegion] = useState({}); + const markers = useSelector(selectors.markers); + const actions = [ { icon: 'draw-polygon', @@ -19,6 +26,17 @@ const Map = () => { }, ]; + useEffect(() => { + if (location) { + setRegion({ + latitude: location.latitude, + longitude: location.longitude, + latitudeDelta: 0.0922, + longitudeDelta: 0.0421, + }); + } + }, [location]); + const alwaysOpenActions = [ { icon: 'street-view', @@ -30,16 +48,20 @@ const Map = () => { return ( + region={region} + onRegionChangeComplete={(value) => setRegion(value)}> + {markers.map((marker, index) => ( + + ))} + setShowPointCreation(false)} /> diff --git a/src/store/actions/actionTypes.js b/src/store/actions/actionTypes.js index 24b3ace..687e441 100644 --- a/src/store/actions/actionTypes.js +++ b/src/store/actions/actionTypes.js @@ -2,3 +2,4 @@ export const LOGIN = 'LOGIN'; export const LOGOUT = 'LOGOUT'; export const ENABLE_LOADER = 'ENABLE_LOADER'; export const DISABLE_LOADER = 'DISABLE_LOADER'; +export const ADD_MARKER = 'ADD_MARKER'; diff --git a/src/store/actions/index.js b/src/store/actions/index.js index 42b999e..854ba5c 100644 --- a/src/store/actions/index.js +++ b/src/store/actions/index.js @@ -1,2 +1,3 @@ export {enableLoader, disableLoader} from './loader'; export {login, logout} from './auth'; +export {createMarker} from './markers'; diff --git a/src/store/actions/markers.js b/src/store/actions/markers.js new file mode 100644 index 0000000..f38af5e --- /dev/null +++ b/src/store/actions/markers.js @@ -0,0 +1,8 @@ +import * as actionTypes from './actionTypes'; + +export const createMarker = (newMarker) => { + return { + type: actionTypes.ADD_MARKER, + newMarker, + }; +}; diff --git a/src/store/reducers/index.js b/src/store/reducers/index.js index 6074349..c9b56e7 100644 --- a/src/store/reducers/index.js +++ b/src/store/reducers/index.js @@ -1,10 +1,12 @@ import {combineReducers} from 'redux'; import auth from './auth'; import loader from './loader'; +import markers from './markers'; const reducers = combineReducers({ auth, loader, + markers, }); export default reducers; diff --git a/src/store/reducers/markers.js b/src/store/reducers/markers.js new file mode 100644 index 0000000..2a3304d --- /dev/null +++ b/src/store/reducers/markers.js @@ -0,0 +1,18 @@ +import * as actionTypes from '../actions/actionTypes'; + +const INITIAL_STATE = { + list: [], +}; + +const reducer = (state = INITIAL_STATE, action) => { + switch (action.type) { + case actionTypes.ADD_MARKER: + return {...state, list: [...state.list, action.newMarker]}; + case actionTypes.LOGOUT: + return INITIAL_STATE; + default: + return state; + } +}; + +export default reducer; diff --git a/src/store/selectors/index.js b/src/store/selectors/index.js index ec1c282..6c29684 100644 --- a/src/store/selectors/index.js +++ b/src/store/selectors/index.js @@ -1,2 +1,3 @@ export {default as auth} from './auth'; export {default as loader} from './loader'; +export {default as markers} from './markers'; diff --git a/src/store/selectors/markers.js b/src/store/selectors/markers.js new file mode 100644 index 0000000..d4e387c --- /dev/null +++ b/src/store/selectors/markers.js @@ -0,0 +1 @@ +export default (state) => state.markers.list; From 60c48fc8ed0dbea48d6373d64687cc17d8f4bcc3 Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Thu, 9 Sep 2021 21:44:14 -0300 Subject: [PATCH 17/37] [#5] fix - android build Signed-off-by: Guilherme Banci --- android/app/build.gradle | 6 ++++-- android/app/src/main/AndroidManifest.xml | 4 ++++ .../java/com/cartografiasocial/MainApplication.java | 7 +++++++ android/build.gradle | 1 + android/settings.gradle | 3 +++ package.json | 2 +- src/components/CreatePoint/styles.js | 3 ++- src/components/Fabs/index.js | 13 +++++++------ yarn.lock | 8 ++++---- 9 files changed, 33 insertions(+), 14 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 9ac069f..2b9d13e 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -78,7 +78,7 @@ import com.android.build.OutputFile */ project.ext.react = [ - enableHermes: false, // clean and rebuild if changing + enableHermes: true, // clean and rebuild if changing ] apply from: "../../node_modules/react-native/react.gradle" @@ -131,6 +131,7 @@ android { targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" + missingDimensionStrategy 'react-native-camera', 'general' } splits { abi { @@ -182,9 +183,9 @@ dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) //noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:+" // From node_modules - implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" + compile project(':react-native-vector-icons') debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { exclude group:'com.facebook.fbjni' } @@ -215,3 +216,4 @@ task copyDownloadableDepsToLibs(type: Copy) { } apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) +apply from: "../../node_modules/react-native-vector-icons/fonts.gradle" diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 95c52ca..08535cd 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -3,6 +3,10 @@ + + + + diff --git a/android/app/src/main/java/com/cartografiasocial/MainApplication.java b/android/app/src/main/java/com/cartografiasocial/MainApplication.java index 1d292cf..642e0e4 100644 --- a/android/app/src/main/java/com/cartografiasocial/MainApplication.java +++ b/android/app/src/main/java/com/cartografiasocial/MainApplication.java @@ -10,6 +10,8 @@ import com.facebook.soloader.SoLoader; import java.lang.reflect.InvocationTargetException; import java.util.List; +import com.facebook.react.bridge.JSIModulePackage; +import com.swmansion.reanimated.ReanimatedJSIModulePackage; public class MainApplication extends Application implements ReactApplication { @@ -20,6 +22,11 @@ public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } + @Override + protected JSIModulePackage getJSIModulePackage() { + return new ReanimatedJSIModulePackage(); // <- add + } + @Override protected List getPackages() { @SuppressWarnings("UnnecessaryLocalVariable") diff --git a/android/build.gradle b/android/build.gradle index e64d31e..440c98a 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -34,5 +34,6 @@ allprojects { google() maven { url 'https://www.jitpack.io' } + jcenter() } } diff --git a/android/settings.gradle b/android/settings.gradle index 7e019d1..e360c8d 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,3 +1,6 @@ rootProject.name = 'cartografiasocial' apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) include ':app' + +include ':react-native-vector-icons' +project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') \ No newline at end of file diff --git a/package.json b/package.json index 015c6b5..64edd57 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "react": "16.13.1", "react-native": "0.63.4", "react-native-android-location-enabler": "^1.2.2", - "react-native-camera": "^3.43.0", + "react-native-camera": "^4.1.1", "react-native-config": "^1.4.4", "react-native-connectivity-status": "^1.5.2", "react-native-geolocation-service": "^5.2.0", diff --git a/src/components/CreatePoint/styles.js b/src/components/CreatePoint/styles.js index 4215a69..5f9e8b8 100644 --- a/src/components/CreatePoint/styles.js +++ b/src/components/CreatePoint/styles.js @@ -1,4 +1,5 @@ import styled from 'styled-components/native'; +import {Platform} from 'react-native'; import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome5'; import theme from 'theme/theme'; @@ -11,7 +12,7 @@ export const Container = styled.View` top: 50%; left: 50%; margin-left: -15px; - margin-top: -28px; + margin-top: ${Platform.OS === 'ios' ? '-28px' : '-43px'}; align-items: center; justify-content: center; `; diff --git a/src/components/Fabs/index.js b/src/components/Fabs/index.js index cc8f223..b61bf22 100644 --- a/src/components/Fabs/index.js +++ b/src/components/Fabs/index.js @@ -1,26 +1,27 @@ import React, {useEffect, useState} from 'react'; -import {LayoutAnimation} from 'react-native'; +import {LayoutAnimation, Platform, UIManager} from 'react-native'; import PropTypes from 'prop-types'; import {Container, Icon, Option} from './styles'; const Fabs = ({actions, alwaysOpenActions}) => { const [showOptions, setShowOptions] = useState(false); - useEffect(() => { + const onPressOpenOptions = () => { + setShowOptions(!showOptions) if (showOptions) { LayoutAnimation.easeInEaseOut(); } else { LayoutAnimation.spring(); } - }, [showOptions]); + } const onPressItem = (item) => { setShowOptions(false); item.onPress(); }; - const renderItem = (item) => ( - ); @@ -33,7 +34,7 @@ const Fabs = ({actions, alwaysOpenActions}) => { {showOptions ? : null} - diff --git a/yarn.lock b/yarn.lock index 074a316..f5fcd3d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7064,10 +7064,10 @@ react-native-android-location-enabler@^1.2.2: resolved "https://registry.yarnpkg.com/react-native-android-location-enabler/-/react-native-android-location-enabler-1.2.2.tgz#84b8dbbda0d5198d99cf264e6be4edaa7f256ba1" integrity sha512-CC5ghRoK3jkGNK8jdIiYIc3l0XZuQuMt2KEfldDpnMCkNz2aAfUWyLCoOniFLqtdD9poA3az+kCmUzTvLAyTiA== -react-native-camera@^3.43.0: - version "3.44.3" - resolved "https://registry.yarnpkg.com/react-native-camera/-/react-native-camera-3.44.3.tgz#f8f35f2484e508b0694dee54a8801a1e0833d851" - integrity sha512-Efb5aKhFsE7qnqvTnbSEwFAom79L5BT4jMn+B2wYVUnZeRgWh45gNSG7Ou3MQ6zU2DpUHBPlBFKGVS5yOSfSZQ== +react-native-camera@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/react-native-camera/-/react-native-camera-4.1.1.tgz#294a7c9818b571a06d304c7736fc57ec8876ed1a" + integrity sha512-ENlQ3NXxhyL/zNJNB3RYrxsES3TYF+ouOMxlp0E4aUVwwc9KY7cK7FT3ZjAwl7NGJ13etaGqZc4vaKWqrgn8Eg== dependencies: prop-types "^15.6.2" From 5208c077763388d91e005641316b0b7ddcb9fe8f Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Thu, 9 Sep 2021 21:58:11 -0300 Subject: [PATCH 18/37] [#5] feat - integrate with backend Co-authored-by: Alexandre Miguel Signed-off-by: Guilherme Banci --- src/components/CreatePoint/index.js | 39 ++++++++++++++++++++--------- src/components/Fabs/index.js | 8 +++--- src/store/persistReducers.js | 2 +- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/components/CreatePoint/index.js b/src/components/CreatePoint/index.js index cdc720f..66b5b40 100644 --- a/src/components/CreatePoint/index.js +++ b/src/components/CreatePoint/index.js @@ -1,15 +1,18 @@ import React, {useRef, useMemo, useState} from 'react'; +import {Alert} from 'react-native'; import BottomSheet, {BottomSheetScrollView} from '@gorhom/bottom-sheet'; import PropTypes from 'prop-types'; import {Btn, Input, View} from 'components/UI'; import required from 'validators/required'; -import {useDispatch} from 'react-redux'; +import {useDispatch, useSelector} from 'react-redux'; +import {auth} from 'store/selectors'; import * as Actions from 'store/actions'; +import api from 'services/api'; import {Container, Icon} from './styles'; const CreatePoint = ({locationSelected, show, onClose}) => { const dispatch = useDispatch(); - + const user = useSelector(auth); const snapPoints = useMemo(() => [110, '50%', '95%'], []); const sheetRef = useRef(null); @@ -21,16 +24,28 @@ const CreatePoint = ({locationSelected, show, onClose}) => { const [title, setTitle] = useState(DEFAULT_STATE); const [description, setDescription] = useState(DEFAULT_STATE); + const [showMarker, setShowMarker] = useState(true); - const onSave = () => { - dispatch( - Actions.createMarker({ - latitude: locationSelected.latitude, - longitude: locationSelected.longitude, - title: title.value, - description: description.value, - }), - ); + const onSave = async () => { + setShowMarker(false); + setTimeout(() => { + setShowMarker(true); + }, 2000); + const newMarker = { + latitude: locationSelected.latitude, + longitude: locationSelected.longitude, + title: title.value, + description: description.value, + }; + + dispatch(Actions.createMarker(newMarker)); + if (user && user.id) { + try { + await api.post('/maps/point', newMarker); + } catch (error) { + Alert.alert('Cartografia Social', error.message); + } + } sheetRef.current.close(); setTimeout(() => { @@ -62,7 +77,7 @@ const CreatePoint = ({locationSelected, show, onClose}) => { return ( <> - + {showMarker ? : null} diff --git a/src/components/Fabs/index.js b/src/components/Fabs/index.js index b61bf22..93aa2d2 100644 --- a/src/components/Fabs/index.js +++ b/src/components/Fabs/index.js @@ -1,5 +1,5 @@ -import React, {useEffect, useState} from 'react'; -import {LayoutAnimation, Platform, UIManager} from 'react-native'; +import React, {useState} from 'react'; +import {LayoutAnimation} from 'react-native'; import PropTypes from 'prop-types'; import {Container, Icon, Option} from './styles'; @@ -7,13 +7,13 @@ const Fabs = ({actions, alwaysOpenActions}) => { const [showOptions, setShowOptions] = useState(false); const onPressOpenOptions = () => { - setShowOptions(!showOptions) + setShowOptions(!showOptions); if (showOptions) { LayoutAnimation.easeInEaseOut(); } else { LayoutAnimation.spring(); } - } + }; const onPressItem = (item) => { setShowOptions(false); diff --git a/src/store/persistReducers.js b/src/store/persistReducers.js index c63b860..51f7bda 100644 --- a/src/store/persistReducers.js +++ b/src/store/persistReducers.js @@ -6,7 +6,7 @@ export default (reducers) => { { storage: AsyncStorage, key: 'cartografia', - whitelist: ['auth'], + blacklist: ['loader'], }, reducers, ); From d1538d1b3398096d1607ad6f36758d02f7f3578f Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Thu, 9 Sep 2021 23:51:50 -0300 Subject: [PATCH 19/37] [#14] feat - initial screen Co-authored-by: Arthur Rodrigues Signed-off-by: Guilherme Banci --- src/app/Routes.js | 8 +++++- src/assets/logo.png | Bin 0 -> 68586 bytes src/pages/InitialPage/index.js | 46 ++++++++++++++++++++++++++++++++ src/pages/InitialPage/styles.js | 18 +++++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/assets/logo.png create mode 100644 src/pages/InitialPage/index.js create mode 100644 src/pages/InitialPage/styles.js diff --git a/src/app/Routes.js b/src/app/Routes.js index 996bf14..c0a3408 100644 --- a/src/app/Routes.js +++ b/src/app/Routes.js @@ -12,6 +12,7 @@ import theme from 'theme/theme'; import Page1 from 'pages/Page1'; import Map from 'pages/Map'; +import InitialPage from 'pages/InitialPage'; const Routes = () => { // const user = useSelector(auth); @@ -26,12 +27,17 @@ const Routes = () => { backgroundColor={theme.colors.white} /> - + null}} /> + null}} + /> diff --git a/src/assets/logo.png b/src/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..20f4ccf905f39fb7eff02715631a631dc60da3c2 GIT binary patch literal 68586 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

cU2w(vOW! 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 { + // const dispatch = useDispatch(); + + const navigateToScreen = async (screen) => { + navigation.navigate(screen); + }; + + return ( + + + Nova Cartografia Social + + + navigateToScreen('Map')} + /> + navigateToScreen('')} + /> + navigateToScreen('')} + /> + + ); +}; + +export default InitialPage; diff --git a/src/pages/InitialPage/styles.js b/src/pages/InitialPage/styles.js new file mode 100644 index 0000000..e7925e9 --- /dev/null +++ b/src/pages/InitialPage/styles.js @@ -0,0 +1,18 @@ +import styled from 'styled-components/native'; +import logo from 'assets/logo.png'; + +export const Container = styled.View` + padding: 20px; + flex: 1; + justify-content: center; +`; + +export const Logo = styled.Image.attrs({ + source: logo, + resizeMode: 'contain', +})` + width: 200px; + height: 200px; + align-self: center; + margin-bottom: 40px; +`; From dc4d9641453ffe777890639660fcad65c90ef181 Mon Sep 17 00:00:00 2001 From: Mikhaelle Bueno Date: Sat, 11 Sep 2021 18:04:22 -0300 Subject: [PATCH 20/37] [#11] feat- config android firebase Co-authored-by: Marco Antonio --- android/app/google-services.json | 47 +++++++ package.json | 4 +- yarn.lock | 212 +++++++++++++++++++++++++++++-- 3 files changed, 253 insertions(+), 10 deletions(-) create mode 100644 android/app/google-services.json diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 0000000..50972bf --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,47 @@ +{ + "project_info": { + "project_number": "1071557975088", + "project_id": "cartografi-social-app", + "storage_bucket": "cartografi-social-app.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:1071557975088:android:0181d87d727dd6a840a1f5", + "android_client_info": { + "package_name": "com.cartografiasocial" + } + }, + "oauth_client": [ + { + "client_id": "1071557975088-1vth3i4om5ssdmh678ukv3ms0cpdn2l0.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.cartografiasocial", + "certificate_hash": "5e8f16062ea3cd2c4a0d547876baa6f38cabf625" + } + }, + { + "client_id": "1071557975088-k9h54o90i8s78ai2mhd1c6evv3lkc6d1.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBRUF1jSMLmaWWYEd1aUN9hN3cgnxzr4js" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "1071557975088-k9h54o90i8s78ai2mhd1c6evv3lkc6d1.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/package.json b/package.json index d73852c..ff3452a 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,8 @@ "@gorhom/bottom-sheet": "^4", "@react-native-community/async-storage": "^1.12.1", "@react-native-community/clipboard": "^1.5.1", + "@react-native-firebase/app": "^12.7.5", + "@react-native-firebase/auth": "^12.7.5", "@react-native-masked-view/masked-view": "^0.2.2", "@react-navigation/native": "^5.9.3", "@react-navigation/stack": "^5.14.3", @@ -100,4 +102,4 @@ "pre-push": "yarn lint --fix --max-warnings=0" } } -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index f5fcd3d..220d9eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,6 +16,13 @@ dependencies: "@babel/highlight" "^7.14.5" +"@babel/code-frame@~7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== + dependencies: + "@babel/highlight" "^7.10.4" + "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.7", "@babel/compat-data@^7.15.0": version "7.15.0" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" @@ -759,6 +766,49 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@expo/config-plugins@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-3.1.0.tgz#0752ff33c5eab21cf42034a44e79df97f0f867f8" + integrity sha512-V5qxaxCAExBM0TXmbU1QKiZcAGP3ecu7KXede8vByT15cro5PkcWu2sSdJCYbHQ/gw6Vf/i8sr8gKlN8V8TSLg== + dependencies: + "@expo/config-types" "^42.0.0" + "@expo/json-file" "8.2.33" + "@expo/plist" "0.0.14" + chalk "^4.1.2" + debug "^4.3.1" + find-up "~5.0.0" + fs-extra "9.0.0" + getenv "^1.0.0" + glob "7.1.6" + resolve-from "^5.0.0" + semver "^7.3.5" + slash "^3.0.0" + xcode "^3.0.1" + xml2js "^0.4.23" + +"@expo/config-types@^42.0.0": + version "42.0.0" + resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-42.0.0.tgz#3e3e125ec092c0c34dbfaf19be5480402de3d677" + integrity sha512-Rj02OMZke2MrGa/1Y/EScmR7VuWbDEHPJyvfFyyLbadUt+Yv6isCdeFzDt71I7gJlPR9T4fzixeYLrtXXOTq0w== + +"@expo/json-file@8.2.33": + version "8.2.33" + resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.2.33.tgz#78f56f33a2cfb807b23c81e00237a33159aa1f32" + integrity sha512-CDnhjdirUs6OdN5hOSTJ2y3i9EiJMk7Z5iDljC5xyCHCrUex7oyI8vbRsZEojAahxZccgL/PrO+CjakiFFWurg== + dependencies: + "@babel/code-frame" "~7.10.4" + json5 "^1.0.1" + write-file-atomic "^2.3.0" + +"@expo/plist@0.0.14": + version "0.0.14" + resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.0.14.tgz#a756903bd28aabe0a961222df2e7858a39a218c9" + integrity sha512-bb4Ua1M/OdNgS8KiGdSDUjZ/bbPfv3xdPY/lz8Ctp/adlj/QgB8xA7tVPeqSSfJPZqFRwU0qLCnRhpUOnP51VQ== + dependencies: + "@xmldom/xmldom" "~0.7.0" + base64-js "^1.2.3" + xmlbuilder "^14.0.0" + "@gorhom/bottom-sheet@^4": version "4.0.3" resolved "https://registry.yarnpkg.com/@gorhom/bottom-sheet/-/bottom-sheet-4.0.3.tgz#465d28bd39ff19e8ba248b514427c0d790d5de30" @@ -1208,6 +1258,20 @@ resolved "https://registry.yarnpkg.com/@react-native-community/eslint-plugin/-/eslint-plugin-1.1.0.tgz#e42b1bef12d2415411519fd528e64b593b1363dc" integrity sha512-W/J0fNYVO01tioHjvYWQ9m6RgndVtbElzYozBq1ZPrHO/iCzlqoySHl4gO/fpCl9QEFjvJfjPgtPMTMlsoq5DQ== +"@react-native-firebase/app@^12.7.5": + version "12.7.5" + resolved "https://registry.yarnpkg.com/@react-native-firebase/app/-/app-12.7.5.tgz#337fd517a6329dd9d734b36ca91bf0c54cc3a337" + integrity sha512-q3NjTHiO4zjPmXopuRuBxbJw5rX5JqqQmE6a+77ONEI+yCx1VF/p+545+plOY1HhA8PqUuWfbqZlbWlYo5K5IA== + dependencies: + "@expo/config-plugins" "^3.1.0" + opencollective-postinstall "^2.0.1" + superstruct "^0.6.2" + +"@react-native-firebase/auth@^12.7.5": + version "12.7.5" + resolved "https://registry.yarnpkg.com/@react-native-firebase/auth/-/auth-12.7.5.tgz#67b16ba9f244e0c6387f1498bb4a36e2759f17da" + integrity sha512-skpbmPJl2YvkS9eGuJ8mSnlr4sVjkMzPFi98kEAOuOTHmRB72/YXVqR72AS4HFBxvGJDIRtZJCeLm+Vc2Ngcrw== + "@react-native-masked-view/masked-view@^0.2.2": version "0.2.6" resolved "https://registry.yarnpkg.com/@react-native-masked-view/masked-view/-/masked-view-0.2.6.tgz#b26c52d5db3ad0926b13deea79c69620966a9221" @@ -1692,6 +1756,11 @@ semver "^7.3.2" tsutils "^3.17.1" +"@xmldom/xmldom@~0.7.0": + version "0.7.4" + resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.4.tgz#93b2f9486c88b6464e97f76c9ab49b0a548fbe57" + integrity sha512-wdxC79cvO7PjSM34jATd/RYZuYWQ8y/R7MidZl1NYYlbpFn1+spfjkiR3ZsJfcaTs2IyslBN7VwBBJwrYKM+zw== + "@yarnpkg/lockfile@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" @@ -2047,6 +2116,11 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" @@ -2257,7 +2331,7 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base64-js@^1.1.2, base64-js@^1.5.1: +base64-js@^1.1.2, base64-js@^1.2.3, base64-js@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -2480,7 +2554,7 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0: +chalk@^4.0.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -2587,6 +2661,16 @@ clone-deep@^0.2.4: lazy-cache "^1.0.3" shallow-clone "^0.1.2" +clone-deep@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713" + integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ== + dependencies: + for-own "^1.0.0" + is-plain-object "^2.0.4" + kind-of "^6.0.0" + shallow-clone "^1.0.0" + clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -2992,7 +3076,7 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== @@ -3984,7 +4068,7 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" -find-up@^5.0.0: +find-up@^5.0.0, find-up@~5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== @@ -4041,6 +4125,13 @@ for-own@^0.1.3: dependencies: for-in "^1.0.1" +for-own@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" + integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= + dependencies: + for-in "^1.0.1" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -4067,6 +4158,16 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= +fs-extra@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.0.tgz#b6afc31036e247b2466dc99c29ae797d5d4580a3" + integrity sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^1.0.0" + fs-extra@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" @@ -4185,6 +4286,11 @@ get-value@^2.0.3, get-value@^2.0.6: resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= +getenv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/getenv/-/getenv-1.0.0.tgz#874f2e7544fbca53c7a4738f37de8605c3fcfc31" + integrity sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg== + getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" @@ -4199,6 +4305,18 @@ glob-parent@^5.1.2: dependencies: is-glob "^4.0.1" +glob@7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.1.7" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" @@ -5447,6 +5565,15 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -5509,7 +5636,7 @@ kind-of@^5.0.0: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== -kind-of@^6.0.0, kind-of@^6.0.2: +kind-of@^6.0.0, kind-of@^6.0.1, kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== @@ -6518,7 +6645,7 @@ open@^7.4.2: is-docker "^2.0.0" is-wsl "^2.1.1" -opencollective-postinstall@^2.0.2: +opencollective-postinstall@^2.0.1, opencollective-postinstall@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== @@ -7700,7 +7827,7 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sax@^1.2.1, sax@~1.2.4: +sax@>=0.6.0, sax@^1.2.1, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -7745,7 +7872,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.2: +semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== @@ -7821,6 +7948,15 @@ shallow-clone@^0.1.2: lazy-cache "^0.2.3" mixin-object "^2.0.1" +shallow-clone@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571" + integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA== + dependencies: + is-extendable "^0.1.1" + kind-of "^5.0.0" + mixin-object "^2.0.1" + shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -7891,7 +8027,7 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -simple-plist@^1.0.0: +simple-plist@^1.0.0, simple-plist@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/simple-plist/-/simple-plist-1.1.1.tgz#54367ca28bc5996a982c325c1c4a4c1a05f4047c" integrity sha512-pKMCVKvZbZTsqYR6RKgLfBHkh2cV89GXcA/0CVPje3sOiNOnXA8+rp/ciAMZ7JRaUdLzlEM6JFfUn+fS6Nt3hg== @@ -8290,6 +8426,14 @@ sudo-prompt@^9.0.0: resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.2.1.tgz#77efb84309c9ca489527a4e749f287e6bdd52afd" integrity sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw== +superstruct@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.6.2.tgz#c5eb034806a17ff98d036674169ef85e4c7f6a1c" + integrity sha512-lvA97MFAJng3rfjcafT/zGTSWm6Tbpk++DP6It4Qg7oNaeM+2tdJMuVgGje21/bIpBEs6iQql1PJH6dKTjl4Ig== + dependencies: + clone-deep "^2.0.1" + kind-of "^6.0.1" + supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -8681,6 +8825,16 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +universalify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d" + integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -8748,6 +8902,11 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" + integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== + v8-compile-cache@^2.0.3: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" @@ -8927,6 +9086,15 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +write-file-atomic@^2.3.0: + version "2.4.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" + integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + write-file-atomic@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" @@ -8965,16 +9133,42 @@ xcode@^2.0.0: simple-plist "^1.0.0" uuid "^3.3.2" +xcode@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/xcode/-/xcode-3.0.1.tgz#3efb62aac641ab2c702458f9a0302696146aa53c" + integrity sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA== + dependencies: + simple-plist "^1.1.0" + uuid "^7.0.3" + xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +xml2js@^0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" + integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xmlbuilder@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-14.0.0.tgz#876b5aec4f05ffd5feb97b0a871c855d16fbeb8c" + integrity sha512-ts+B2rSe4fIckR6iquDjsKbQFK2NlUk6iG5nf14mDEyldgoc2nEKZ3jZWMPTxGQwVgToSjt6VGIho1H8/fNFTg== + xmlbuilder@^9.0.7: version "9.0.7" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + xmlchars@^2.1.1: version "2.2.0" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" From 345bb507e82ac3dba4462a5fb096137ec02391c0 Mon Sep 17 00:00:00 2001 From: Mikhaelle Date: Sat, 11 Sep 2021 18:14:14 -0300 Subject: [PATCH 21/37] [#11] fix eslint problems Co-authored-by: Marco Antonio --- src/app/Routes.js | 74 +++++++++++---------- src/pages/LoginPage/index.js | 84 ++++++++++++++++++++++++ src/pages/{Page1 => LoginPage}/styles.js | 0 src/pages/Page1/index.js | 78 ---------------------- 4 files changed, 124 insertions(+), 112 deletions(-) create mode 100644 src/pages/LoginPage/index.js rename src/pages/{Page1 => LoginPage}/styles.js (100%) delete mode 100644 src/pages/Page1/index.js diff --git a/src/app/Routes.js b/src/app/Routes.js index c0a3408..1b79fb5 100644 --- a/src/app/Routes.js +++ b/src/app/Routes.js @@ -1,49 +1,55 @@ import React from 'react'; -import {StatusBar} from 'react-native'; +import { StatusBar } from 'react-native'; -import {NavigationContainer} from '@react-navigation/native'; -import {createStackNavigator} from '@react-navigation/stack'; -import {ThemeProvider} from 'styled-components/native'; +import { NavigationContainer } from '@react-navigation/native'; +import { createStackNavigator } from '@react-navigation/stack'; +import { ThemeProvider } from 'styled-components/native'; // import {useSelector} from 'react-redux'; // import {auth} from 'store/selectors'; import theme from 'theme/theme'; -import Page1 from 'pages/Page1'; +import Page1 from 'pages/LoginPage'; import Map from 'pages/Map'; import InitialPage from 'pages/InitialPage'; const Routes = () => { - // const user = useSelector(auth); - - const Stack = createStackNavigator(); - - return ( - <> - - + < + ThemeProvider theme = { theme } > + < + StatusBar barStyle = "dark-content" + backgroundColor = { theme.colors.white } + /> < + NavigationContainer theme = { + { colors: { background: theme.colors.white } } } > + < + Stack.Navigator initialRouteName = "InitialPage" > + < + Stack.Screen name = "Map" + component = { Map } + options = { + { header: () => null } } + /> < + Stack.Screen name = "InitialPage" + component = { InitialPage } + options = { + { header: () => null } } + /> < + Stack.Screen name = "Page1" + component = { Page1 } + /> < + /Stack.Navigator> < + /NavigationContainer> < + /ThemeProvider> < /> - - - null}} - /> - null}} - /> - - - - - - ); + ); }; -export default Routes; +export default Routes; \ No newline at end of file diff --git a/src/pages/LoginPage/index.js b/src/pages/LoginPage/index.js new file mode 100644 index 0000000..2e3f9e6 --- /dev/null +++ b/src/pages/LoginPage/index.js @@ -0,0 +1,84 @@ +import React, { useState } from 'react'; +import ScrollView from 'components/UI/ScrollView'; +import Input from 'components/UI/Input'; +import required from 'validators/required'; +import phoneValidator from 'validators/phone'; +import phoneMask from 'masks/phoneMask'; +import Btn from 'components/UI/Btn'; +import Text from 'components/UI/Text'; +import theme from 'theme/theme'; +import { Container } from './styles'; + +// import {Alert} from 'react-native'; +// import api from 'services/api'; +// import {useDispatch} from 'react-redux'; +// import * as Actions from 'store/actions'; + +const Page1 = ({ navigation }) => { + // const dispatch = useDispatch(); + + const [phone, setPhone] = useState({ + isValid: false, + value: '', + }); + + const [name, setName] = useState({ + isValid: false, + value: '', + }); + + const formIsValid = () => { + return phone.isValid && name.isValid; + }; + + const onPress = async() => { + navigation.navigate('Page2'); + // dispatch(Actions.enableLoader()); + // const params = {} + // try { + // await api.post('/route/', params); + // } catch (error) { + // Alert.alert('Cartografia Social', 'Ocorreu um erro ao se conectar com o servidor'); + // dispatch(Actions.disableLoader()); + // } + }; + + return ( < + ScrollView > + < + Container > + < + Text alignSelf = "center" + fontSize = { theme.font.sizes.L } + my = { 3 } > + Texto exemplo { ' ' } < + /Text>{' '} < + Input label = "Seu nome" + onChange = { + (value) => setName(value) } + value = { name.value } + autoCapitalize = "words" + rules = { + [required] } + />{' '} < + Input label = "Número de telefone" + onChange = { + (value) => setPhone(value) } + value = { phone.value } + inputMask = { phoneMask } + keyboardType = "numeric" + rules = { + [required, phoneValidator] } + />{' '} < + Btn disabled = {!formIsValid() } + style = { + { marginVertical: 50 } } + title = "Próximo" + onPress = { onPress } + />{' '} < + /Container>{' '} < + /ScrollView> + ); +}; + +export default Page1; \ No newline at end of file diff --git a/src/pages/Page1/styles.js b/src/pages/LoginPage/styles.js similarity index 100% rename from src/pages/Page1/styles.js rename to src/pages/LoginPage/styles.js diff --git a/src/pages/Page1/index.js b/src/pages/Page1/index.js deleted file mode 100644 index 991bea0..0000000 --- a/src/pages/Page1/index.js +++ /dev/null @@ -1,78 +0,0 @@ -import React, {useState} from 'react'; -import ScrollView from 'components/UI/ScrollView'; -import Input from 'components/UI/Input'; -import required from 'validators/required'; -import phoneValidator from 'validators/phone'; -import phoneMask from 'masks/phoneMask'; -import Btn from 'components/UI/Btn'; -import Text from 'components/UI/Text'; -import theme from 'theme/theme'; -import {Container} from './styles'; - -// import {Alert} from 'react-native'; -// import api from 'services/api'; -// import {useDispatch} from 'react-redux'; -// import * as Actions from 'store/actions'; - -const Page1 = ({navigation}) => { - // const dispatch = useDispatch(); - - const [phone, setPhone] = useState({ - isValid: false, - value: '', - }); - - const [name, setName] = useState({ - isValid: false, - value: '', - }); - - const formIsValid = () => { - return phone.isValid && name.isValid; - }; - - const onPress = async () => { - navigation.navigate('Page2'); - // dispatch(Actions.enableLoader()); - // const params = {} - // try { - // await api.post('/route/', params); - // } catch (error) { - // Alert.alert('Cartografia Social', 'Ocorreu um erro ao se conectar com o servidor'); - // dispatch(Actions.disableLoader()); - // } - }; - - return ( - - - - Texto exemplo - - setName(value)} - value={name.value} - autoCapitalize="words" - rules={[required]} - /> - setPhone(value)} - value={phone.value} - inputMask={phoneMask} - keyboardType="numeric" - rules={[required, phoneValidator]} - /> - - - - ); -}; - -export default Page1; From f7e2c294c9e3e9f6af355b95a1fb683844514e38 Mon Sep 17 00:00:00 2001 From: Mikhaelle Date: Sat, 11 Sep 2021 18:17:28 -0300 Subject: [PATCH 22/37] [#11] fix eslint problems Co-authored-by: Marco Antonio --- src/app/Routes.js | 24 ++++++++++++++++++------ src/pages/LoginPage/index.js | 12 ++++++------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/app/Routes.js b/src/app/Routes.js index 1b79fb5..0031035 100644 --- a/src/app/Routes.js +++ b/src/app/Routes.js @@ -36,18 +36,30 @@ const Routes = () => { component = { Map } options = { { header: () => null } } - /> < + /> + + < Stack.Screen name = "InitialPage" component = { InitialPage } options = { { header: () => null } } - /> < + /> + + < Stack.Screen name = "Page1" component = { Page1 } - /> < - /Stack.Navigator> < - /NavigationContainer> < - /ThemeProvider> < + /> + + < + /Stack.Navigator> + + < + /NavigationContainer> + + < + /ThemeProvider> + + < /> ); }; diff --git a/src/pages/LoginPage/index.js b/src/pages/LoginPage/index.js index 2e3f9e6..25a7207 100644 --- a/src/pages/LoginPage/index.js +++ b/src/pages/LoginPage/index.js @@ -51,8 +51,8 @@ const Page1 = ({ navigation }) => { Text alignSelf = "center" fontSize = { theme.font.sizes.L } my = { 3 } > - Texto exemplo { ' ' } < - /Text>{' '} < + Texto exemplo < + /Text> < Input label = "Seu nome" onChange = { (value) => setName(value) } @@ -60,7 +60,7 @@ const Page1 = ({ navigation }) => { autoCapitalize = "words" rules = { [required] } - />{' '} < + /> < Input label = "Número de telefone" onChange = { (value) => setPhone(value) } @@ -69,14 +69,14 @@ const Page1 = ({ navigation }) => { keyboardType = "numeric" rules = { [required, phoneValidator] } - />{' '} < + /> < Btn disabled = {!formIsValid() } style = { { marginVertical: 50 } } title = "Próximo" onPress = { onPress } - />{' '} < - /Container>{' '} < + /> < + /Container> < /ScrollView> ); }; From 92e7f72eb9faae3006810609028d732470ae95d0 Mon Sep 17 00:00:00 2001 From: Mikhaelle Date: Sat, 11 Sep 2021 18:24:40 -0300 Subject: [PATCH 23/37] [#11] fix eslint problems Co-authored-by: Marco Antonio --- src/app/Routes.js | 80 +++++++++-------------- src/pages/LoginPage/index.js | 120 +++++++++++++++++------------------ 2 files changed, 88 insertions(+), 112 deletions(-) diff --git a/src/app/Routes.js b/src/app/Routes.js index 0031035..abca145 100644 --- a/src/app/Routes.js +++ b/src/app/Routes.js @@ -1,9 +1,9 @@ import React from 'react'; -import { StatusBar } from 'react-native'; +import {StatusBar} from 'react-native'; -import { NavigationContainer } from '@react-navigation/native'; -import { createStackNavigator } from '@react-navigation/stack'; -import { ThemeProvider } from 'styled-components/native'; +import {NavigationContainer} from '@react-navigation/native'; +import {createStackNavigator} from '@react-navigation/stack'; +import {ThemeProvider} from 'styled-components/native'; // import {useSelector} from 'react-redux'; // import {auth} from 'store/selectors'; @@ -15,53 +15,35 @@ import Map from 'pages/Map'; import InitialPage from 'pages/InitialPage'; const Routes = () => { - // const user = useSelector(auth); + // const user = useSelector(auth); - const Stack = createStackNavigator(); + const Stack = createStackNavigator(); - return ( < - > - < - ThemeProvider theme = { theme } > - < - StatusBar barStyle = "dark-content" - backgroundColor = { theme.colors.white } - /> < - NavigationContainer theme = { - { colors: { background: theme.colors.white } } } > - < - Stack.Navigator initialRouteName = "InitialPage" > - < - Stack.Screen name = "Map" - component = { Map } - options = { - { header: () => null } } + return ( + <> + + - - < - Stack.Screen name = "InitialPage" - component = { InitialPage } - options = { - { header: () => null } } - /> - - < - Stack.Screen name = "Page1" - component = { Page1 } - /> - - < - /Stack.Navigator> - - < - /NavigationContainer> - - < - /ThemeProvider> - - < - /> - ); + + + null}} + /> + null}} + /> + + + + + + ); }; -export default Routes; \ No newline at end of file +export default Routes; diff --git a/src/pages/LoginPage/index.js b/src/pages/LoginPage/index.js index 25a7207..991bea0 100644 --- a/src/pages/LoginPage/index.js +++ b/src/pages/LoginPage/index.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, {useState} from 'react'; import ScrollView from 'components/UI/ScrollView'; import Input from 'components/UI/Input'; import required from 'validators/required'; @@ -7,78 +7,72 @@ import phoneMask from 'masks/phoneMask'; import Btn from 'components/UI/Btn'; import Text from 'components/UI/Text'; import theme from 'theme/theme'; -import { Container } from './styles'; +import {Container} from './styles'; // import {Alert} from 'react-native'; // import api from 'services/api'; // import {useDispatch} from 'react-redux'; // import * as Actions from 'store/actions'; -const Page1 = ({ navigation }) => { - // const dispatch = useDispatch(); +const Page1 = ({navigation}) => { + // const dispatch = useDispatch(); - const [phone, setPhone] = useState({ - isValid: false, - value: '', - }); + const [phone, setPhone] = useState({ + isValid: false, + value: '', + }); - const [name, setName] = useState({ - isValid: false, - value: '', - }); + const [name, setName] = useState({ + isValid: false, + value: '', + }); - const formIsValid = () => { - return phone.isValid && name.isValid; - }; + const formIsValid = () => { + return phone.isValid && name.isValid; + }; - const onPress = async() => { - navigation.navigate('Page2'); - // dispatch(Actions.enableLoader()); - // const params = {} - // try { - // await api.post('/route/', params); - // } catch (error) { - // Alert.alert('Cartografia Social', 'Ocorreu um erro ao se conectar com o servidor'); - // dispatch(Actions.disableLoader()); - // } - }; + const onPress = async () => { + navigation.navigate('Page2'); + // dispatch(Actions.enableLoader()); + // const params = {} + // try { + // await api.post('/route/', params); + // } catch (error) { + // Alert.alert('Cartografia Social', 'Ocorreu um erro ao se conectar com o servidor'); + // dispatch(Actions.disableLoader()); + // } + }; - return ( < - ScrollView > - < - Container > - < - Text alignSelf = "center" - fontSize = { theme.font.sizes.L } - my = { 3 } > - Texto exemplo < - /Text> < - Input label = "Seu nome" - onChange = { - (value) => setName(value) } - value = { name.value } - autoCapitalize = "words" - rules = { - [required] } - /> < - Input label = "Número de telefone" - onChange = { - (value) => setPhone(value) } - value = { phone.value } - inputMask = { phoneMask } - keyboardType = "numeric" - rules = { - [required, phoneValidator] } - /> < - Btn disabled = {!formIsValid() } - style = { - { marginVertical: 50 } } - title = "Próximo" - onPress = { onPress } - /> < - /Container> < - /ScrollView> - ); + return ( + + + + Texto exemplo + + setName(value)} + value={name.value} + autoCapitalize="words" + rules={[required]} + /> + setPhone(value)} + value={phone.value} + inputMask={phoneMask} + keyboardType="numeric" + rules={[required, phoneValidator]} + /> + + + + ); }; -export default Page1; \ No newline at end of file +export default Page1; From c93d891d1928608ae830b3ffcbcc7d047651e782 Mon Sep 17 00:00:00 2001 From: Mikhaelle Date: Sat, 11 Sep 2021 21:01:39 -0300 Subject: [PATCH 24/37] [#11] add some style and firebase sing-in Co-authored-by: Marco Antonio --- android/app/build.gradle | 2 + android/build.gradle | 2 + src/app/Routes.js | 4 +- src/pages/InitialPage/index.js | 2 +- src/pages/LoginPage/index.js | 91 ++++++++++++++++------------------ src/pages/LoginPage/styles.js | 21 ++++++++ 6 files changed, 72 insertions(+), 50 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 2b9d13e..f3f4b07 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -217,3 +217,5 @@ task copyDownloadableDepsToLibs(type: Copy) { apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) apply from: "../../node_modules/react-native-vector-icons/fonts.gradle" +apply plugin: 'com.android.application' +apply plugin: 'com.google.gms.google-services' diff --git a/android/build.gradle b/android/build.gradle index 440c98a..90382da 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -14,6 +14,8 @@ buildscript { } dependencies { classpath("com.android.tools.build:gradle:4.2.1") + classpath 'com.google.gms:google-services:4.3.10' + // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/src/app/Routes.js b/src/app/Routes.js index abca145..95fc9f7 100644 --- a/src/app/Routes.js +++ b/src/app/Routes.js @@ -9,7 +9,7 @@ import {ThemeProvider} from 'styled-components/native'; import theme from 'theme/theme'; -import Page1 from 'pages/LoginPage'; +import LoginPage from 'pages/LoginPage'; import Map from 'pages/Map'; import InitialPage from 'pages/InitialPage'; @@ -38,7 +38,7 @@ const Routes = () => { component={InitialPage} options={{header: () => null}} /> - + diff --git a/src/pages/InitialPage/index.js b/src/pages/InitialPage/index.js index 9042d21..24f858b 100644 --- a/src/pages/InitialPage/index.js +++ b/src/pages/InitialPage/index.js @@ -32,7 +32,7 @@ const InitialPage = ({navigation}) => { navigateToScreen('')} + onPress={() => navigateToScreen('LoginPage')} /> { +const LoginPage = ({navigation}) => { // const dispatch = useDispatch(); - const [phone, setPhone] = useState({ + const [password, setPassword] = useState({ isValid: false, value: '', }); - const [name, setName] = useState({ + const [email, setEmail] = useState({ isValid: false, value: '', }); const formIsValid = () => { - return phone.isValid && name.isValid; + return password.isValid && email.isValid; }; const onPress = async () => { - navigation.navigate('Page2'); - // dispatch(Actions.enableLoader()); - // const params = {} - // try { - // await api.post('/route/', params); - // } catch (error) { - // Alert.alert('Cartografia Social', 'Ocorreu um erro ao se conectar com o servidor'); - // dispatch(Actions.disableLoader()); - // } + auth() + .signInWithEmailAndPassword(email.value, password.value) + .then(() => { + navigation.navigate('Map'); + }) + .catch((error) => { + console.error(error); + }); }; return ( - - - - Texto exemplo - - setName(value)} - value={name.value} - autoCapitalize="words" - rules={[required]} - /> - setPhone(value)} - value={phone.value} - inputMask={phoneMask} - keyboardType="numeric" - rules={[required, phoneValidator]} - /> - - - + <> +

+ Fazer Login +
+ + + setEmail(value)} + value={email.value} + autoCapitalize="words" + rules={[required]} + /> + setPassword(value)} + hide + value={password.value} + rules={[required]} + /> + + + + ); }; -export default Page1; +export default LoginPage; diff --git a/src/pages/LoginPage/styles.js b/src/pages/LoginPage/styles.js index 15469b1..5ab27e8 100644 --- a/src/pages/LoginPage/styles.js +++ b/src/pages/LoginPage/styles.js @@ -1,9 +1,30 @@ import styled from 'styled-components/native'; +import theme from 'theme/theme'; export const Container = styled.View` padding: 20px; `; +export const Header = styled.View` + width: auto; + height: 30%; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; + background: ${theme.colors.primary}; +`; + +export const HeadeText = styled.Text` + position: absolute; + bottom: 10%; + left: 5%; + font-family: Roboto; + font-style: normal; + font-weight: bold; + color: ${theme.colors.white} + font-size: ${theme.font.sizes.X}; + line-height: 35px; +`; + export const FirstInput = styled.View` flex-direction: row; align-items: center; From 0d622e0a0b2d66ad16891087963c38eab033eea0 Mon Sep 17 00:00:00 2001 From: Mikhaelle Date: Sat, 11 Sep 2021 21:03:37 -0300 Subject: [PATCH 25/37] [#11] add some style and firebase sing-in Co-authored-by: Marco Antonio --- src/pages/LoginPage/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/LoginPage/index.js b/src/pages/LoginPage/index.js index 3f3b449..1713d47 100644 --- a/src/pages/LoginPage/index.js +++ b/src/pages/LoginPage/index.js @@ -35,6 +35,7 @@ const LoginPage = ({navigation}) => { navigation.navigate('Map'); }) .catch((error) => { + // eslint-disable-next-line no-console console.error(error); }); }; From c4eca470c9f7e81040f33f9e4b2b012472ef340d Mon Sep 17 00:00:00 2001 From: Mikhaelle Date: Sat, 11 Sep 2021 22:25:48 -0300 Subject: [PATCH 26/37] [#11] auth persist Co-authored-by: Marco Antonio --- src/components/CreatePoint/index.js | 4 ++-- src/pages/LoginPage/index.js | 31 ++++++++++++++++++++++++----- src/store/reducers/auth.js | 2 +- src/store/selectors/index.js | 2 +- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/components/CreatePoint/index.js b/src/components/CreatePoint/index.js index 66b5b40..904786a 100644 --- a/src/components/CreatePoint/index.js +++ b/src/components/CreatePoint/index.js @@ -5,14 +5,14 @@ import PropTypes from 'prop-types'; import {Btn, Input, View} from 'components/UI'; import required from 'validators/required'; import {useDispatch, useSelector} from 'react-redux'; -import {auth} from 'store/selectors'; +import {authSelector} from 'store/selectors'; import * as Actions from 'store/actions'; import api from 'services/api'; import {Container, Icon} from './styles'; const CreatePoint = ({locationSelected, show, onClose}) => { const dispatch = useDispatch(); - const user = useSelector(auth); + const user = useSelector(authSelector); const snapPoints = useMemo(() => [110, '50%', '95%'], []); const sheetRef = useRef(null); diff --git a/src/pages/LoginPage/index.js b/src/pages/LoginPage/index.js index 1713d47..21144f2 100644 --- a/src/pages/LoginPage/index.js +++ b/src/pages/LoginPage/index.js @@ -1,9 +1,11 @@ -import React, {useState} from 'react'; +import React, {useState, useEffect} from 'react'; import ScrollView from 'components/UI/ScrollView'; import Input from 'components/UI/Input'; import required from 'validators/required'; import Btn from 'components/UI/Btn'; import auth from '@react-native-firebase/auth'; +import {useDispatch} from 'react-redux'; +import * as Actions from 'store/actions'; import {Container, Header, HeadeText} from './styles'; // import {Alert} from 'react-native'; @@ -12,7 +14,8 @@ import {Container, Header, HeadeText} from './styles'; // import * as Actions from 'store/actions'; const LoginPage = ({navigation}) => { - // const dispatch = useDispatch(); + const dispatch = useDispatch(); + const [initializing, setInitializing] = useState(true); const [password, setPassword] = useState({ isValid: false, @@ -24,6 +27,25 @@ const LoginPage = ({navigation}) => { value: '', }); + // eslint-disable-next-line no-shadow + function onAuthStateChanged(user) { + if (user != null) { + const loginUser = { + email: user.email, + id: user.uid, + token: '', + }; + dispatch(Actions.login(loginUser)); + navigation.navigate('Map'); + } + if (initializing) setInitializing(false); + } + + useEffect(() => { + const subscriber = auth().onAuthStateChanged(onAuthStateChanged); + return subscriber; + }, []); + const formIsValid = () => { return password.isValid && email.isValid; }; @@ -31,15 +53,14 @@ const LoginPage = ({navigation}) => { const onPress = async () => { auth() .signInWithEmailAndPassword(email.value, password.value) - .then(() => { - navigation.navigate('Map'); - }) .catch((error) => { // eslint-disable-next-line no-console console.error(error); }); }; + if (initializing) return null; + return ( <>
diff --git a/src/store/reducers/auth.js b/src/store/reducers/auth.js index 55de3b1..b5a8f5f 100644 --- a/src/store/reducers/auth.js +++ b/src/store/reducers/auth.js @@ -1,7 +1,7 @@ import * as actionTypes from '../actions/actionTypes'; const INITIAL_STATE = { - name: '', + email: '', id: '', token: '', }; diff --git a/src/store/selectors/index.js b/src/store/selectors/index.js index 6c29684..28edc14 100644 --- a/src/store/selectors/index.js +++ b/src/store/selectors/index.js @@ -1,3 +1,3 @@ -export {default as auth} from './auth'; +export {default as authSelector} from './auth'; export {default as loader} from './loader'; export {default as markers} from './markers'; From 8e0663ccd43d03c37f6d3df01988d7bcaec9978b Mon Sep 17 00:00:00 2001 From: Marco Antonio Date: Sun, 12 Sep 2021 19:28:58 -0300 Subject: [PATCH 27/37] [#11] change login page top bar Co-authored-by: Mikhaelle Bueno --- src/app/Routes.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/app/Routes.js b/src/app/Routes.js index 95fc9f7..6ace901 100644 --- a/src/app/Routes.js +++ b/src/app/Routes.js @@ -38,7 +38,18 @@ const Routes = () => { component={InitialPage} options={{header: () => null}} /> - + From 6577e1e4a4330ea73bb0eb68c5c35979f2c6b118 Mon Sep 17 00:00:00 2001 From: Marco Antonio Date: Sun, 12 Sep 2021 19:32:15 -0300 Subject: [PATCH 28/37] Revert "[#11] auth persist" This reverts commit c4eca470c9f7e81040f33f9e4b2b012472ef340d. --- src/components/CreatePoint/index.js | 4 ++-- src/pages/LoginPage/index.js | 31 +++++------------------------ src/store/reducers/auth.js | 2 +- src/store/selectors/index.js | 2 +- 4 files changed, 9 insertions(+), 30 deletions(-) diff --git a/src/components/CreatePoint/index.js b/src/components/CreatePoint/index.js index 904786a..66b5b40 100644 --- a/src/components/CreatePoint/index.js +++ b/src/components/CreatePoint/index.js @@ -5,14 +5,14 @@ import PropTypes from 'prop-types'; import {Btn, Input, View} from 'components/UI'; import required from 'validators/required'; import {useDispatch, useSelector} from 'react-redux'; -import {authSelector} from 'store/selectors'; +import {auth} from 'store/selectors'; import * as Actions from 'store/actions'; import api from 'services/api'; import {Container, Icon} from './styles'; const CreatePoint = ({locationSelected, show, onClose}) => { const dispatch = useDispatch(); - const user = useSelector(authSelector); + const user = useSelector(auth); const snapPoints = useMemo(() => [110, '50%', '95%'], []); const sheetRef = useRef(null); diff --git a/src/pages/LoginPage/index.js b/src/pages/LoginPage/index.js index 21144f2..1713d47 100644 --- a/src/pages/LoginPage/index.js +++ b/src/pages/LoginPage/index.js @@ -1,11 +1,9 @@ -import React, {useState, useEffect} from 'react'; +import React, {useState} from 'react'; import ScrollView from 'components/UI/ScrollView'; import Input from 'components/UI/Input'; import required from 'validators/required'; import Btn from 'components/UI/Btn'; import auth from '@react-native-firebase/auth'; -import {useDispatch} from 'react-redux'; -import * as Actions from 'store/actions'; import {Container, Header, HeadeText} from './styles'; // import {Alert} from 'react-native'; @@ -14,8 +12,7 @@ import {Container, Header, HeadeText} from './styles'; // import * as Actions from 'store/actions'; const LoginPage = ({navigation}) => { - const dispatch = useDispatch(); - const [initializing, setInitializing] = useState(true); + // const dispatch = useDispatch(); const [password, setPassword] = useState({ isValid: false, @@ -27,25 +24,6 @@ const LoginPage = ({navigation}) => { value: '', }); - // eslint-disable-next-line no-shadow - function onAuthStateChanged(user) { - if (user != null) { - const loginUser = { - email: user.email, - id: user.uid, - token: '', - }; - dispatch(Actions.login(loginUser)); - navigation.navigate('Map'); - } - if (initializing) setInitializing(false); - } - - useEffect(() => { - const subscriber = auth().onAuthStateChanged(onAuthStateChanged); - return subscriber; - }, []); - const formIsValid = () => { return password.isValid && email.isValid; }; @@ -53,14 +31,15 @@ const LoginPage = ({navigation}) => { const onPress = async () => { auth() .signInWithEmailAndPassword(email.value, password.value) + .then(() => { + navigation.navigate('Map'); + }) .catch((error) => { // eslint-disable-next-line no-console console.error(error); }); }; - if (initializing) return null; - return ( <>
diff --git a/src/store/reducers/auth.js b/src/store/reducers/auth.js index b5a8f5f..55de3b1 100644 --- a/src/store/reducers/auth.js +++ b/src/store/reducers/auth.js @@ -1,7 +1,7 @@ import * as actionTypes from '../actions/actionTypes'; const INITIAL_STATE = { - email: '', + name: '', id: '', token: '', }; diff --git a/src/store/selectors/index.js b/src/store/selectors/index.js index 28edc14..6c29684 100644 --- a/src/store/selectors/index.js +++ b/src/store/selectors/index.js @@ -1,3 +1,3 @@ -export {default as authSelector} from './auth'; +export {default as auth} from './auth'; export {default as loader} from './loader'; export {default as markers} from './markers'; From 88a21623f5b2f7b92621343bc914dd65a1888482 Mon Sep 17 00:00:00 2001 From: Marco Antonio Date: Sun, 12 Sep 2021 19:40:54 -0300 Subject: [PATCH 29/37] [#11] change login page top bar Co-authored-by: Mikhaelle Bueno --- src/app/Routes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/Routes.js b/src/app/Routes.js index 6ace901..2376035 100644 --- a/src/app/Routes.js +++ b/src/app/Routes.js @@ -38,8 +38,8 @@ const Routes = () => { component={InitialPage} options={{header: () => null}} /> - Date: Sun, 12 Sep 2021 19:43:53 -0300 Subject: [PATCH 30/37] [#11] fix login page style Co-authored-by: Mikhaelle Bueno --- src/pages/LoginPage/index.js | 7 +++++-- src/pages/LoginPage/styles.js | 20 ++++++++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/pages/LoginPage/index.js b/src/pages/LoginPage/index.js index 1713d47..1a03bc5 100644 --- a/src/pages/LoginPage/index.js +++ b/src/pages/LoginPage/index.js @@ -4,7 +4,7 @@ import Input from 'components/UI/Input'; import required from 'validators/required'; import Btn from 'components/UI/Btn'; import auth from '@react-native-firebase/auth'; -import {Container, Header, HeadeText} from './styles'; +import {Container, Header, HeaderText, InputText, TextBtn} from './styles'; // import {Alert} from 'react-native'; // import api from 'services/api'; @@ -43,10 +43,11 @@ const LoginPage = ({navigation}) => { return ( <>
- Fazer Login + Fazer Login
+ Email setEmail(value)} @@ -54,6 +55,7 @@ const LoginPage = ({navigation}) => { autoCapitalize="words" rules={[required]} /> + Senha setPassword(value)} @@ -61,6 +63,7 @@ const LoginPage = ({navigation}) => { value={password.value} rules={[required]} /> + null}>Esqueci a senha Date: Mon, 13 Sep 2021 18:39:38 -0300 Subject: [PATCH 31/37] [#13] chore - installing react native image picker Co-authored-by: Mikhaelle Bueno Signed-off-by: Guilherme Banci --- android/app/src/main/AndroidManifest.xml | 2 +- ios/Podfile.lock | 18 ++++++++++++------ ios/cartografiasocial/Info.plist | 2 ++ package.json | 3 ++- yarn.lock | 5 +++++ 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 08535cd..4f62a04 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -2,7 +2,7 @@ package="com.cartografiasocial"> - + diff --git a/ios/Podfile.lock b/ios/Podfile.lock index d800d2e..1523cde 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -216,13 +216,13 @@ PODS: - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsinspector (0.63.4) - - react-native-camera (3.44.3): + - react-native-camera (4.1.1): - React-Core - - react-native-camera/RCT (= 3.44.3) - - react-native-camera/RN (= 3.44.3) - - react-native-camera/RCT (3.44.3): + - react-native-camera/RCT (= 4.1.1) + - react-native-camera/RN (= 4.1.1) + - react-native-camera/RCT (4.1.1): - React-Core - - react-native-camera/RN (3.44.3): + - react-native-camera/RN (4.1.1): - React-Core - react-native-config (1.4.4): - react-native-config/App (= 1.4.4) @@ -236,6 +236,8 @@ PODS: - Google-Maps-iOS-Utils (= 2.1.0) - GoogleMaps (= 3.5.0) - React-Core + - react-native-image-picker (4.0.6): + - React-Core - react-native-maps (0.29.3): - React-Core - react-native-safe-area-context (3.3.0): @@ -375,6 +377,7 @@ DEPENDENCIES: - react-native-connectivity-status (from `../node_modules/react-native-connectivity-status`) - react-native-geolocation-service (from `../node_modules/react-native-geolocation-service`) - react-native-google-maps (from `../node_modules/react-native-maps`) + - react-native-image-picker (from `../node_modules/react-native-image-picker`) - react-native-maps (from `../node_modules/react-native-maps`) - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) @@ -455,6 +458,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-geolocation-service" react-native-google-maps: :path: "../node_modules/react-native-maps" + react-native-image-picker: + :path: "../node_modules/react-native-image-picker" react-native-maps: :path: "../node_modules/react-native-maps" react-native-safe-area-context: @@ -524,11 +529,12 @@ SPEC CHECKSUMS: React-jsi: a0418934cf48f25b485631deb27c64dc40fb4c31 React-jsiexecutor: 93bd528844ad21dc07aab1c67cb10abae6df6949 React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a - react-native-camera: b8cc03e2feec0c04403d0998e37cf519d8fd4c6f + react-native-camera: 85210eb59b028e9430d29fa33b0252c56113beff react-native-config: 72d948053a442779b3178fddd571e37f118ef606 react-native-connectivity-status: 2325459ddad171e1f88af01f52a6a1f34ad37102 react-native-geolocation-service: 7c9436da6dfdecd9526c62eac62ea2bc3f0cc8ea react-native-google-maps: d6a30377b40a338bd09d6ad36ce48dc5d12b5792 + react-native-image-picker: a6e56460d34905c849ada551db30897dc7f3d535 react-native-maps: 41d01d8e0afcebe32bec9eea3bd945adc1b18f7a react-native-safe-area-context: 61c8c484a3a9e7d1fda19f7b1794b35bbfd2262a React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336 diff --git a/ios/cartografiasocial/Info.plist b/ios/cartografiasocial/Info.plist index 941113e..654ef50 100644 --- a/ios/cartografiasocial/Info.plist +++ b/ios/cartografiasocial/Info.plist @@ -30,6 +30,8 @@ Usar Loc NSLocationWhenInUseUsageDescription Usar Loc + NSPhotoLibraryUsageDescription + Usar fotos UIAppFonts AntDesign.ttf diff --git a/package.json b/package.json index d73852c..54d94c8 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "react-native-connectivity-status": "^1.5.2", "react-native-geolocation-service": "^5.2.0", "react-native-gesture-handler": "^1.10.3", + "react-native-image-picker": "^4.0.6", "react-native-keyboard-aware-scroll-view": "^0.9.3", "react-native-maps": "^0.29.3", "react-native-material-ripple": "^0.9.1", @@ -100,4 +101,4 @@ "pre-push": "yarn lint --fix --max-warnings=0" } } -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index f5fcd3d..5438de3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7102,6 +7102,11 @@ react-native-gesture-handler@^1.10.3: invariant "^2.2.4" prop-types "^15.7.2" +react-native-image-picker@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/react-native-image-picker/-/react-native-image-picker-4.0.6.tgz#0dfa5bb83bcf6ff58635ebb9201a185c2271e8cc" + integrity sha512-Pp3UWKUADuMG1mz12m6dSO/R2KnvXVEd77bldrfTMFpz4PFc4iVKo+bHeS79It0mUBezfzDMgfesg/OPLSugvQ== + react-native-iphone-x-helper@^1.0.3, react-native-iphone-x-helper@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz#20c603e9a0e765fd6f97396638bdeb0e5a60b010" From 182d80f7cc106503c0714b232f83fecdcd50a936 Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Mon, 13 Sep 2021 18:40:34 -0300 Subject: [PATCH 32/37] [#13] feat - show options for pick images Co-authored-by: Mikhaelle Bueno Signed-off-by: Guilherme Banci --- src/components/CreatePoint/index.js | 55 ++++++++++++++++++++++++++-- src/components/CreatePoint/styles.js | 7 ++++ src/components/UI/FlatList/index.js | 15 ++++++++ src/components/UI/index.js | 1 + 4 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 src/components/UI/FlatList/index.js diff --git a/src/components/CreatePoint/index.js b/src/components/CreatePoint/index.js index 66b5b40..7c0fb3c 100644 --- a/src/components/CreatePoint/index.js +++ b/src/components/CreatePoint/index.js @@ -1,14 +1,18 @@ import React, {useRef, useMemo, useState} from 'react'; import {Alert} from 'react-native'; +import {launchCamera, launchImageLibrary} from 'react-native-image-picker'; import BottomSheet, {BottomSheetScrollView} from '@gorhom/bottom-sheet'; import PropTypes from 'prop-types'; -import {Btn, Input, View} from 'components/UI'; +import {Btn, Input, View, FlatList, Text} from 'components/UI'; import required from 'validators/required'; import {useDispatch, useSelector} from 'react-redux'; import {auth} from 'store/selectors'; import * as Actions from 'store/actions'; import api from 'services/api'; -import {Container, Icon} from './styles'; +import Fabs from 'components/Fabs'; + +import theme from 'theme/theme'; +import {Container, Icon, Image} from './styles'; const CreatePoint = ({locationSelected, show, onClose}) => { const dispatch = useDispatch(); @@ -25,6 +29,34 @@ const CreatePoint = ({locationSelected, show, onClose}) => { const [description, setDescription] = useState(DEFAULT_STATE); const [showMarker, setShowMarker] = useState(true); + const [images, setImages] = useState([]); + + const cameraOptions = { + mediaType: 'photo', + maxWidth: 1300, + maxHeight: 1300, + quality: 0.9, + saveToPhotos: true, + selectionLimit: 0, + }; + + const onSelectImage = (response) => { + console.tron.log(response, response.assets); + if (response.assets && response.assets.length) { + setImages([...images, ...response.assets]); + } + }; + + const actions = [ + { + icon: 'draw-polygon', + onPress: () => launchCamera(cameraOptions, onSelectImage), + }, + { + icon: 'map-marker-alt', + onPress: () => launchImageLibrary(cameraOptions, onSelectImage), + }, + ]; const onSave = async () => { setShowMarker(false); @@ -36,6 +68,7 @@ const CreatePoint = ({locationSelected, show, onClose}) => { longitude: locationSelected.longitude, title: title.value, description: description.value, + multimedia: images, }; dispatch(Actions.createMarker(newMarker)); @@ -57,7 +90,7 @@ const CreatePoint = ({locationSelected, show, onClose}) => { }; const pointName = () => ( - + setTitle(value)} @@ -73,6 +106,8 @@ const CreatePoint = ({locationSelected, show, onClose}) => { return title.isValid; }; + const renderItem = ({item}) => ; + if (show) { return ( <> @@ -83,6 +118,19 @@ const CreatePoint = ({locationSelected, show, onClose}) => { {pointName()} + {images.length ? ( + + + Multimídia + + item.uri} + /> + + ) : null} { /> + ); diff --git a/src/components/CreatePoint/styles.js b/src/components/CreatePoint/styles.js index 5f9e8b8..0f0d70b 100644 --- a/src/components/CreatePoint/styles.js +++ b/src/components/CreatePoint/styles.js @@ -28,3 +28,10 @@ export const Option = styled.TouchableHighlight.attrs({ justify-content: center; margin: 5px; `; + +export const Image = styled.Image` + width: 100px; + height: 100px; + border-radius: 7px; + margin-right: 10px; +`; diff --git a/src/components/UI/FlatList/index.js b/src/components/UI/FlatList/index.js new file mode 100644 index 0000000..0788277 --- /dev/null +++ b/src/components/UI/FlatList/index.js @@ -0,0 +1,15 @@ +import styled from 'styled-components/native'; +import theme from 'theme/theme'; +import {space, typography, flexbox} from 'styled-system'; + +export default styled.FlatList.attrs({ + showsHorizontalScrollIndicator: false, + showsVerticalScrollIndicator: false, +})` + font-size: ${(props) => + props.fontSize ? props.fontSize : theme.font.sizes.M}px; + color: ${(props) => (props.color ? props.color : theme.colors.black)}; + ${space}; + ${typography}; + ${flexbox}; +`; diff --git a/src/components/UI/index.js b/src/components/UI/index.js index fc7a23b..224266f 100644 --- a/src/components/UI/index.js +++ b/src/components/UI/index.js @@ -1,6 +1,7 @@ export {default as Btn} from './Btn'; export {default as Input} from './Input'; export {default as ScrollView} from './ScrollView'; +export {default as FlatList} from './FlatList'; export {default as Text} from './Text'; export {default as View} from './View'; export {default as Touchable} from './Touchable'; From 3fc4e4ee33a5280041191bf72e7de0467c21ff56 Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Mon, 13 Sep 2021 20:28:45 -0300 Subject: [PATCH 33/37] [#13] feat - show marker details Co-authored-by: Mikhaelle Bueno Signed-off-by: Guilherme Banci --- package.json | 1 + src/components/Marker/index.js | 35 +++++++++++++ src/components/Marker/styles.js | 13 +++++ src/components/MarkerDetails/index.js | 68 ++++++++++++++++++++++++++ src/components/MarkerDetails/styles.js | 13 +++++ src/components/UI/Divisor/index.js | 25 ++++++++++ src/components/UI/Input/index.js | 3 ++ src/components/UI/index.js | 1 + src/pages/Map/index.js | 22 ++++++--- src/store/persistReducers.js | 2 +- yarn.lock | 36 +++++++++++++- 11 files changed, 209 insertions(+), 10 deletions(-) create mode 100644 src/components/Marker/index.js create mode 100644 src/components/Marker/styles.js create mode 100644 src/components/MarkerDetails/index.js create mode 100644 src/components/MarkerDetails/styles.js create mode 100644 src/components/UI/Divisor/index.js diff --git a/package.json b/package.json index 54d94c8..3042aa7 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "react-native-reanimated": "^2.2.0", "react-native-safe-area-context": "^3.1.9", "react-native-screens": "^2.18.0", + "react-native-snap-carousel": "^3.9.1", "react-native-svg": "^12.1.0", "react-native-svg-uri": "^1.2.3", "react-native-vector-icons": "^8.1.0", diff --git a/src/components/Marker/index.js b/src/components/Marker/index.js new file mode 100644 index 0000000..e8a0fd7 --- /dev/null +++ b/src/components/Marker/index.js @@ -0,0 +1,35 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; +import {Marker as OriginalMarker} from 'react-native-maps'; + +const Marker = ({marker, onPress}) => { + const onPressMarker = () => { + onPress(marker); + }; + + if (marker) { + return ( + + ); + } + + return null; +}; + +// Marker.propTypes = { +// marker: PropTypes.shape({ +// icon: PropTypes.string, +// onPress: PropTypes.func, +// }), +// }; + +// Marker.defaultProps = { +// marker: {}, +// }; + +export default Marker; diff --git a/src/components/Marker/styles.js b/src/components/Marker/styles.js new file mode 100644 index 0000000..cbd6e0f --- /dev/null +++ b/src/components/Marker/styles.js @@ -0,0 +1,13 @@ +import styled from 'styled-components/native'; +import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome5'; +import theme from 'theme/theme'; + +export const Icon = styled(FontAwesomeIcon).attrs({ + color: theme.colors.white, +})``; + +export const Image = styled.Image` + width: 200px; + height: 200px; + border-radius: 7px; +`; diff --git a/src/components/MarkerDetails/index.js b/src/components/MarkerDetails/index.js new file mode 100644 index 0000000..2791ccc --- /dev/null +++ b/src/components/MarkerDetails/index.js @@ -0,0 +1,68 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; +import { Dimensions } from 'react-native'; +import BottomSheet, {BottomSheetScrollView} from '@gorhom/bottom-sheet'; +import {View, Text, Divisor} from 'components/UI'; +import Carousel from 'react-native-snap-carousel'; +import theme from 'theme/theme'; +import {onChange} from 'react-native-reanimated'; +import {Image} from './styles'; + +const MarkerDetails = ({marker, sheetRef}) => { + const snapPoints = [400, '90%']; + const renderItem = ({item}) => ; + const windowWidth = Dimensions.get('window').width; + return ( + + + {marker && marker.title ? ( + <> + + {marker.title} + + + + {marker.multimedia.length ? ( + + + Visualizar todos + + item.uri} + sliderWidth={windowWidth} + itemWidth={200} + loop + /> + + ) : null} + + {marker.description} + + + + ) : ( + + )} + + + ); +}; + +// MarkerDetails.propTypes = { +// marker: PropTypes.shape({ +// icon: PropTypes.string, +// onPress: PropTypes.func, +// }), +// }; + +// MarkerDetails.defaultProps = { +// marker: {}, +// }; + +export default MarkerDetails; diff --git a/src/components/MarkerDetails/styles.js b/src/components/MarkerDetails/styles.js new file mode 100644 index 0000000..cbd6e0f --- /dev/null +++ b/src/components/MarkerDetails/styles.js @@ -0,0 +1,13 @@ +import styled from 'styled-components/native'; +import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome5'; +import theme from 'theme/theme'; + +export const Icon = styled(FontAwesomeIcon).attrs({ + color: theme.colors.white, +})``; + +export const Image = styled.Image` + width: 200px; + height: 200px; + border-radius: 7px; +`; diff --git a/src/components/UI/Divisor/index.js b/src/components/UI/Divisor/index.js new file mode 100644 index 0000000..5376601 --- /dev/null +++ b/src/components/UI/Divisor/index.js @@ -0,0 +1,25 @@ +import styled from 'styled-components/native'; + +import { + space, + color, + shadow, + layout, + flexbox, + border, + position, +} from 'styled-system'; +import theme from 'theme/theme'; + +export default styled.View` + height: 1px; + background-color: ${theme.colors.grey}; + align-self: stretch; + ${color} + ${space}; + ${layout}; + ${flexbox}; + ${border}; + ${position}; + ${shadow}; +`; diff --git a/src/components/UI/Input/index.js b/src/components/UI/Input/index.js index a57b62e..8ce9f4f 100644 --- a/src/components/UI/Input/index.js +++ b/src/components/UI/Input/index.js @@ -1,3 +1,4 @@ +/* eslint-disable react/jsx-props-no-spreading */ import React, {useRef, useState, useEffect} from 'react'; import {PixelRatio} from 'react-native'; import PropTypes from 'prop-types'; @@ -31,6 +32,7 @@ const Input = ({ onFocus, height, characterRestriction, + ...props }) => { const inputEl = useRef(null); @@ -111,6 +113,7 @@ const Input = ({ autoCorrect={autoCorrect} height={height} characterRestriction={characterRestriction} + {...props} /> ); }; diff --git a/src/components/UI/index.js b/src/components/UI/index.js index 224266f..7209fdd 100644 --- a/src/components/UI/index.js +++ b/src/components/UI/index.js @@ -4,4 +4,5 @@ export {default as ScrollView} from './ScrollView'; export {default as FlatList} from './FlatList'; export {default as Text} from './Text'; export {default as View} from './View'; +export {default as Divisor} from './Divisor'; export {default as Touchable} from './Touchable'; diff --git a/src/pages/Map/index.js b/src/pages/Map/index.js index 3e445ff..c103def 100644 --- a/src/pages/Map/index.js +++ b/src/pages/Map/index.js @@ -1,18 +1,23 @@ /* eslint-disable react/no-array-index-key */ -import React, {useState, useEffect} from 'react'; +import React, {useState, useEffect, useRef} from 'react'; import {View} from 'components/UI'; import useLocation from 'services/useLocation'; import Fabs from 'components/Fabs'; import CreatePoint from 'components/CreatePoint'; import {useSelector} from 'react-redux'; import * as selectors from 'store/selectors'; -import {Marker} from 'react-native-maps'; +import Marker from 'components/Marker'; +import MarkerDetails from 'components/MarkerDetails'; + import {MapView} from './styles'; const Map = () => { const {location} = useLocation(); const [showPointCreation, setShowPointCreation] = useState(false); const [region, setRegion] = useState({}); + const [selectedMarker, setSelectedMarker] = useState({}); + const detailsRef = useRef(null); + const markers = useSelector(selectors.markers); const actions = [ @@ -44,6 +49,11 @@ const Map = () => { }, ]; + const onPressMarker = (marker) => { + setSelectedMarker(marker); + detailsRef.current.snapToIndex(0); + }; + if (location) { return ( @@ -51,12 +61,7 @@ const Map = () => { region={region} onRegionChangeComplete={(value) => setRegion(value)}> {markers.map((marker, index) => ( - + ))} @@ -65,6 +70,7 @@ const Map = () => { show={showPointCreation} onClose={() => setShowPointCreation(false)} /> + ); } diff --git a/src/store/persistReducers.js b/src/store/persistReducers.js index 51f7bda..f372b9f 100644 --- a/src/store/persistReducers.js +++ b/src/store/persistReducers.js @@ -6,7 +6,7 @@ export default (reducers) => { { storage: AsyncStorage, key: 'cartografia', - blacklist: ['loader'], + blacklist: ['loader', 'markers'], }, reducers, ); diff --git a/yarn.lock b/yarn.lock index 5438de3..e5c58b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2790,6 +2790,11 @@ core-js-pure@^3.16.0: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.16.4.tgz#8b23122628d88c560f209812b9b2d9ebbce5e29c" integrity sha512-bY1K3/1Jy9D8Jd12eoeVahNXHLfHFb4TXWI8SQ4y8bImR9qDPmGITBAfmcffTkgUvbJn87r8dILOTWW5kZzkgA== +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY= + core-js@^2.4.1: version "2.6.12" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" @@ -3864,6 +3869,19 @@ fbjs-scripts@^1.1.0: semver "^5.1.0" through2 "^2.0.0" +fbjs@^0.8.4: + version "0.8.17" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" + integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90= + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + fbjs@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-1.0.0.tgz#52c215e0883a3c86af2a7a776ed51525ae8e0a5a" @@ -6960,7 +6978,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.5.10, prop-types@^15.5.9, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.5.10, prop-types@^15.5.9, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -7046,6 +7064,14 @@ range-parser@~1.2.1: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== +react-addons-shallow-compare@15.6.2: + version "15.6.2" + resolved "https://registry.yarnpkg.com/react-addons-shallow-compare/-/react-addons-shallow-compare-15.6.2.tgz#198a00b91fc37623db64a28fd17b596ba362702f" + integrity sha1-GYoAuR/DdiPbZKKP0XtZa6NicC8= + dependencies: + fbjs "^0.8.4" + object-assign "^4.1.0" + react-devtools-core@^4.6.0: version "4.17.0" resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.17.0.tgz#83eb8a2c79b542d6b7bfa5406084a969cb7897ba" @@ -7180,6 +7206,14 @@ react-native-screens@^2.18.0: resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-2.18.1.tgz#47b9991c6f762d00d0ed3233e5283d523e859885" integrity sha512-r5WZLpmx2hHjC1RgMdPq5YpSU9tEhBpUaZ5M1SUtNIONyiLqQVxabhRCINdebIk4depJiIl7yw2Q85zJyeX6fw== +react-native-snap-carousel@^3.9.1: + version "3.9.1" + resolved "https://registry.yarnpkg.com/react-native-snap-carousel/-/react-native-snap-carousel-3.9.1.tgz#6fd9bd8839546c2c6043a41d2035afbc6fe0443e" + integrity sha512-xWEGusacIgK1YaDXLi7Gao2+ISLoGPVEBR8fcMf4tOOJQufutlNwkoLu0l6B8Qgsrre0nTxoVZikRgGRDWlLaQ== + dependencies: + prop-types "^15.6.1" + react-addons-shallow-compare "15.6.2" + react-native-svg-transformer@^0.14.3: version "0.14.3" resolved "https://registry.yarnpkg.com/react-native-svg-transformer/-/react-native-svg-transformer-0.14.3.tgz#43c8e176f5a11f16f39b87a64018e0ac090ffbdb" From 7ca4c860bf30ddd6a8fd3905e707851a110edd9e Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Mon, 13 Sep 2021 20:34:59 -0300 Subject: [PATCH 34/37] [#13] chore - eslint Co-authored-by: Mikhaelle Bueno Signed-off-by: Guilherme Banci --- src/components/CreatePoint/index.js | 7 ++----- src/components/MarkerDetails/index.js | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/components/CreatePoint/index.js b/src/components/CreatePoint/index.js index 7c0fb3c..00e8123 100644 --- a/src/components/CreatePoint/index.js +++ b/src/components/CreatePoint/index.js @@ -10,8 +10,8 @@ import {auth} from 'store/selectors'; import * as Actions from 'store/actions'; import api from 'services/api'; import Fabs from 'components/Fabs'; - import theme from 'theme/theme'; + import {Container, Icon, Image} from './styles'; const CreatePoint = ({locationSelected, show, onClose}) => { @@ -41,7 +41,6 @@ const CreatePoint = ({locationSelected, show, onClose}) => { }; const onSelectImage = (response) => { - console.tron.log(response, response.assets); if (response.assets && response.assets.length) { setImages([...images, ...response.assets]); } @@ -120,9 +119,7 @@ const CreatePoint = ({locationSelected, show, onClose}) => { {pointName()} {images.length ? ( - - Multimídia - + Multimídia { From 8a8b492896abb31f7d88fb6b9b9442e310403ae3 Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Mon, 13 Sep 2021 20:56:11 -0300 Subject: [PATCH 35/37] [#13] feat - redirecting to marker in the map Co-authored-by: Mikhaelle Bueno Signed-off-by: Guilherme Banci --- src/components/CreatePoint/index.js | 8 +++++--- src/components/MarkerDetails/index.js | 2 +- src/pages/Map/index.js | 10 ++++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/components/CreatePoint/index.js b/src/components/CreatePoint/index.js index 00e8123..9e25a00 100644 --- a/src/components/CreatePoint/index.js +++ b/src/components/CreatePoint/index.js @@ -48,11 +48,11 @@ const CreatePoint = ({locationSelected, show, onClose}) => { const actions = [ { - icon: 'draw-polygon', + icon: 'camera', onPress: () => launchCamera(cameraOptions, onSelectImage), }, { - icon: 'map-marker-alt', + icon: 'paperclip', onPress: () => launchImageLibrary(cameraOptions, onSelectImage), }, ]; @@ -119,7 +119,9 @@ const CreatePoint = ({locationSelected, show, onClose}) => { {pointName()} {images.length ? ( - Multimídia + + Multimídia + { - const snapPoints = [400, '90%']; + const snapPoints = [400, '95%']; const renderItem = ({item}) => ; const windowWidth = Dimensions.get('window').width; return ( diff --git a/src/pages/Map/index.js b/src/pages/Map/index.js index c103def..bfe8b06 100644 --- a/src/pages/Map/index.js +++ b/src/pages/Map/index.js @@ -14,7 +14,7 @@ import {MapView} from './styles'; const Map = () => { const {location} = useLocation(); const [showPointCreation, setShowPointCreation] = useState(false); - const [region, setRegion] = useState({}); + const [region, setRegion] = useState(null); const [selectedMarker, setSelectedMarker] = useState({}); const detailsRef = useRef(null); @@ -52,9 +52,15 @@ const Map = () => { const onPressMarker = (marker) => { setSelectedMarker(marker); detailsRef.current.snapToIndex(0); + setRegion({ + latitude: marker.latitude - 0.008, + longitude: marker.longitude, + latitudeDelta: 0.0122, + longitudeDelta: 0.02, + }); }; - if (location) { + if (region) { return ( Date: Mon, 13 Sep 2021 21:28:28 -0300 Subject: [PATCH 36/37] [#13] fix - fix scroll images on android Co-authored-by: Mikhaelle Bueno Signed-off-by: Guilherme Banci --- patches/react-native-snap-carousel+3.9.1.patch | 16 ++++++++++++++++ src/components/CreatePoint/index.js | 1 + src/components/UI/FlatList/index.js | 3 ++- src/components/UI/View/index.js | 17 ++++++++--------- 4 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 patches/react-native-snap-carousel+3.9.1.patch diff --git a/patches/react-native-snap-carousel+3.9.1.patch b/patches/react-native-snap-carousel+3.9.1.patch new file mode 100644 index 0000000..978749c --- /dev/null +++ b/patches/react-native-snap-carousel+3.9.1.patch @@ -0,0 +1,16 @@ +diff --git a/node_modules/react-native-snap-carousel/src/carousel/Carousel.js b/node_modules/react-native-snap-carousel/src/carousel/Carousel.js +index dae71a3..cad216d 100644 +--- a/node_modules/react-native-snap-carousel/src/carousel/Carousel.js ++++ b/node_modules/react-native-snap-carousel/src/carousel/Carousel.js +@@ -1,5 +1,10 @@ + import React, { Component } from 'react'; +-import { Animated, Easing, FlatList, I18nManager, Platform, ScrollView, View, ViewPropTypes } from 'react-native'; ++import { Animated, Easing, I18nManager, Platform, View, ViewPropTypes } from 'react-native'; ++import { ++ ScrollView, ++ FlatList ++} from 'react-native-gesture-handler'; ++ + import PropTypes from 'prop-types'; + import shallowCompare from 'react-addons-shallow-compare'; + import { diff --git a/src/components/CreatePoint/index.js b/src/components/CreatePoint/index.js index 9e25a00..57f0b88 100644 --- a/src/components/CreatePoint/index.js +++ b/src/components/CreatePoint/index.js @@ -84,6 +84,7 @@ const CreatePoint = ({locationSelected, show, onClose}) => { onClose(); setTitle(DEFAULT_STATE); setDescription(DEFAULT_STATE); + setImages([]); }, 1000); return locationSelected; }; diff --git a/src/components/UI/FlatList/index.js b/src/components/UI/FlatList/index.js index 0788277..234b676 100644 --- a/src/components/UI/FlatList/index.js +++ b/src/components/UI/FlatList/index.js @@ -1,8 +1,9 @@ import styled from 'styled-components/native'; import theme from 'theme/theme'; import {space, typography, flexbox} from 'styled-system'; +import {FlatList} from 'react-native-gesture-handler'; -export default styled.FlatList.attrs({ +export default styled(FlatList).attrs({ showsHorizontalScrollIndicator: false, showsVerticalScrollIndicator: false, })` diff --git a/src/components/UI/View/index.js b/src/components/UI/View/index.js index 616b4b3..4eefcbb 100644 --- a/src/components/UI/View/index.js +++ b/src/components/UI/View/index.js @@ -11,13 +11,12 @@ import { } from 'styled-system'; export default styled.View` -elevation: ${(props) => props.elevation || '0px'} -flex-direction: ${(props) => (props.row ? 'row' : 'column')}; -${color} -${space}; -${layout}; -${flexbox}; -${border}; -${position}; -${shadow}; + flex-direction: ${(props) => (props.row ? 'row' : 'column')}; + ${color} + ${space}; + ${layout}; + ${flexbox}; + ${border}; + ${position}; + ${shadow}; `; From 3e7a92312bded9121233d1f7a750f460cbac780d Mon Sep 17 00:00:00 2001 From: Guilherme Banci Date: Mon, 13 Sep 2021 22:14:22 -0300 Subject: [PATCH 37/37] [#2] chore - create CD/CI workflow Signed-off-by: Guilherme Banci --- .github/workflows/cd.yml | 56 ++++++++++++++++++++++++++++++++++++++++ .github/workflows/ci.yml | 28 ++++++++++++++++++++ ios/Podfile.lock | 18 +++++-------- package.json | 1 - yarn.lock | 5 ---- 5 files changed, 90 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/cd.yml create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 0000000..62864b3 --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,56 @@ +name: CD Production + +on: + push: + branches: + - main + +jobs: + # test: + # name: CI Tests + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v2 + # - name: Install Modules + # run: yarn install --frozen-lockfile + # - name: Run Tests + # run: yarn test + + build: + name: CD Build Android + # needs: test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Build container + run: | + echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p + yarn install --frozen-lockfile + cd ./android + ./gradlew clean + ./gradlew assembleRelease --warning-mode=all + - uses: actions/upload-artifact@master + with: + name: apk + path: ./android/app/build/outputs/apk/release/app-release.apk + + tagged-release: + name: "Tagged Release" + needs: build + runs-on: "ubuntu-latest" + steps: + - uses: actions/checkout@v2 + - name: Downlaod APK File + uses: actions/download-artifact@master + with: + name: apk + path: ./ + - name: Add Github Release + uses: "marvinpinto/action-automatic-releases@latest" + with: + repo_token: "${{ secrets.GITHUB_TOKEN }}" + automatic_release_tag: "latest" + prerelease: false + files: | + *.apk + LICENSE \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..5eaea05 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,28 @@ +# name: CI - Lint, Test, Build + +# on: +# push: +# pull_request: + +# jobs: +# lint: +# name: CI Lint +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v2 +# - name: Install Modules +# run: npm ci +# - name: ESLint +# env: +# CI: true +# run: npm run lint + +# test: +# name: CI Tests +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v2 +# - name: Install Modules +# run: npm ci +# - name: Run Tests +# run: npm run test diff --git a/ios/Podfile.lock b/ios/Podfile.lock index d800d2e..7dec9ae 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -216,20 +216,18 @@ PODS: - React-cxxreact (= 0.63.4) - React-jsi (= 0.63.4) - React-jsinspector (0.63.4) - - react-native-camera (3.44.3): + - react-native-camera (4.1.1): - React-Core - - react-native-camera/RCT (= 3.44.3) - - react-native-camera/RN (= 3.44.3) - - react-native-camera/RCT (3.44.3): + - react-native-camera/RCT (= 4.1.1) + - react-native-camera/RN (= 4.1.1) + - react-native-camera/RCT (4.1.1): - React-Core - - react-native-camera/RN (3.44.3): + - react-native-camera/RN (4.1.1): - React-Core - react-native-config (1.4.4): - react-native-config/App (= 1.4.4) - react-native-config/App (1.4.4): - React-Core - - react-native-connectivity-status (1.5.1): - - React - react-native-geolocation-service (5.2.0): - React - react-native-google-maps (0.29.3): @@ -372,7 +370,6 @@ DEPENDENCIES: - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) - react-native-camera (from `../node_modules/react-native-camera`) - react-native-config (from `../node_modules/react-native-config`) - - react-native-connectivity-status (from `../node_modules/react-native-connectivity-status`) - react-native-geolocation-service (from `../node_modules/react-native-geolocation-service`) - react-native-google-maps (from `../node_modules/react-native-maps`) - react-native-maps (from `../node_modules/react-native-maps`) @@ -449,8 +446,6 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-camera" react-native-config: :path: "../node_modules/react-native-config" - react-native-connectivity-status: - :path: "../node_modules/react-native-connectivity-status" react-native-geolocation-service: :path: "../node_modules/react-native-geolocation-service" react-native-google-maps: @@ -524,9 +519,8 @@ SPEC CHECKSUMS: React-jsi: a0418934cf48f25b485631deb27c64dc40fb4c31 React-jsiexecutor: 93bd528844ad21dc07aab1c67cb10abae6df6949 React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a - react-native-camera: b8cc03e2feec0c04403d0998e37cf519d8fd4c6f + react-native-camera: 85210eb59b028e9430d29fa33b0252c56113beff react-native-config: 72d948053a442779b3178fddd571e37f118ef606 - react-native-connectivity-status: 2325459ddad171e1f88af01f52a6a1f34ad37102 react-native-geolocation-service: 7c9436da6dfdecd9526c62eac62ea2bc3f0cc8ea react-native-google-maps: d6a30377b40a338bd09d6ad36ce48dc5d12b5792 react-native-maps: 41d01d8e0afcebe32bec9eea3bd945adc1b18f7a diff --git a/package.json b/package.json index d73852c..d18cbe3 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,6 @@ "react-native-android-location-enabler": "^1.2.2", "react-native-camera": "^4.1.1", "react-native-config": "^1.4.4", - "react-native-connectivity-status": "^1.5.2", "react-native-geolocation-service": "^5.2.0", "react-native-gesture-handler": "^1.10.3", "react-native-keyboard-aware-scroll-view": "^0.9.3", diff --git a/yarn.lock b/yarn.lock index f5fcd3d..36882f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7076,11 +7076,6 @@ react-native-config@^1.4.4: resolved "https://registry.yarnpkg.com/react-native-config/-/react-native-config-1.4.4.tgz#e0e10802d1e61ef051040c84dfd19f85a5984620" integrity sha512-bu47sJHn/HrB7COAWBI8DieAhrbFLINHFE2HBCcVkDu0Y5ScrMs6vL+jhIm+pMSgxouseLhXG8h7xYYpxE38PA== -react-native-connectivity-status@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/react-native-connectivity-status/-/react-native-connectivity-status-1.5.2.tgz#cdb0a1e34c8e068e6a021cbb2d918ab7aa98c23d" - integrity sha512-w1zmJETgn1XvmZ20q69k5yuvA4dUWFbDfR0MOfQWKB9I3xKnNhFABIOoqVc6pvll3zjnSurIhbzkMgUVONrXqw== - react-native-flipper@^0.34.0: version "0.34.0" resolved "https://registry.yarnpkg.com/react-native-flipper/-/react-native-flipper-0.34.0.tgz#7df1f38ba5d97a9321125fe0fccbe47d99e6fa1d"