├── .github
├── pull_request_template.md
└── workflows
│ ├── build.yml
│ └── submit.yml
├── .gitlab-ci.yml
├── CONTRIBUTING.md
├── README.md
└── app
├── .dockerignore
├── .env-example
├── .eslintrc.js
├── .expo-shared
└── assets.json
├── .gitignore
├── .lintstagedrc
├── .prettierrc.js
├── App.js
├── Dockerfile
├── app.config.js
├── app.json
├── assets
├── fonts
│ ├── Montserrat
│ │ ├── Montserrat-Bold.ttf
│ │ ├── Montserrat-Light.ttf
│ │ ├── Montserrat-Medium.ttf
│ │ ├── Montserrat-Regular.ttf
│ │ ├── Montserrat-SemiBold.ttf
│ │ └── OFL.txt
│ └── loadFonts.js
├── images
│ ├── Seedling.svg
│ ├── TutorialImages
│ │ ├── Step1.svg
│ │ ├── Step2.svg
│ │ ├── Step3.svg
│ │ ├── tela01.png
│ │ ├── tela02.png
│ │ ├── tela03.png
│ │ └── tela04.png
│ ├── back.png
│ ├── blueCat.png
│ ├── blueCatCard.svg
│ ├── blueLogo.png
│ ├── exclamation.svg
│ ├── hand.svg
│ ├── home.png
│ ├── house.svg
│ ├── logo.png
│ ├── noImage.png
│ ├── notFoundImage.svg
│ ├── phone.svg
│ ├── splash.png
│ ├── whileLogo.png
│ └── whiteCat.png
└── styles
│ ├── colorVariables.js
│ ├── fontVariable.js
│ ├── helpDescription.js
│ └── mapstyle.js
├── babel.config.js
├── colors.js
├── docker-compose.yml
├── eas.json
├── metro.config.js
├── package.json
├── setup_env.sh
├── src
├── ExternalServices
│ └── ViaCep.js
├── Navigation
│ ├── AuthNavigation
│ │ └── index.jsx
│ ├── MainNavigation
│ │ ├── GivenHelps
│ │ │ └── index.jsx
│ │ ├── MainNavigationStyles
│ │ │ └── MainStackHeaderStyle.jsx
│ │ ├── Routes
│ │ │ ├── ActivitiesRoutes
│ │ │ │ └── index.jsx
│ │ │ ├── BadgeRoutes
│ │ │ │ └── index.jsx
│ │ │ ├── FeedbackRoutes
│ │ │ │ └── index.jsx
│ │ │ ├── MapRoutes
│ │ │ │ └── index.jsx
│ │ │ ├── MoreInfoRoutes
│ │ │ │ └── index.jsx
│ │ │ ├── ProfileRoutes
│ │ │ │ └── index.jsx
│ │ │ ├── SocialNetworkRoutes
│ │ │ │ └── index.jsx
│ │ │ ├── TimelineRoutes
│ │ │ │ └── index.jsx
│ │ │ └── index.jsx
│ │ ├── index.jsx
│ │ ├── options.js
│ │ └── screenOptions.js
│ └── index.jsx
├── components
│ ├── Avatar
│ │ ├── index.js
│ │ └── styles.js
│ ├── Container
│ │ ├── index.js
│ │ └── styles.js
│ ├── CustomMap
│ │ └── index.jsx
│ ├── FAQModals
│ │ ├── EmergencyNumbersModal
│ │ │ └── index.jsx
│ │ ├── modal.jsx
│ │ └── styles.js
│ ├── HistoricCard
│ │ ├── index.js
│ │ └── styles.js
│ ├── LoadingIndicator
│ │ ├── index.jsx
│ │ └── styles.js
│ ├── MyRequestCard
│ │ ├── index.js
│ │ ├── old.js
│ │ └── styles.js
│ ├── NoHelps
│ │ ├── index.js
│ │ └── styles.js
│ ├── NotificationCard
│ │ ├── index.js
│ │ └── styles.js
│ ├── PlusIconTextButton
│ │ ├── index.js
│ │ └── styles.js
│ ├── SelectCategoryForm
│ │ ├── index.js
│ │ └── styles.js
│ ├── UI
│ │ ├── button
│ │ │ ├── FilterButtons
│ │ │ │ ├── index.js
│ │ │ │ └── styles.js
│ │ │ ├── index.js
│ │ │ └── styles.js
│ │ ├── input
│ │ │ ├── index.js
│ │ │ └── styles.js
│ │ └── selectBox
│ │ │ ├── index.js
│ │ │ └── styles.js
│ ├── UserItem
│ │ └── index.jsx
│ ├── atoms
│ │ ├── ActivityFlatList
│ │ │ └── index.jsx
│ │ ├── Chips
│ │ │ └── index.jsx
│ │ ├── CircleBadge
│ │ │ └── index.jsx
│ │ ├── CircleIconButton
│ │ │ └── index.jsx
│ │ ├── DefaultButton
│ │ │ └── index.jsx
│ │ ├── Divider
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── IconButton
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── InformativeField
│ │ │ └── index.jsx
│ │ ├── Input
│ │ │ └── index.jsx
│ │ ├── RoundedFullButton
│ │ │ └── index.jsx
│ │ ├── SearchBar
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── SliderDescription
│ │ │ └── index.jsx
│ │ ├── SliderTitle
│ │ │ └── index.jsx
│ │ ├── TextButton
│ │ │ └── index.jsx
│ │ ├── TextSwitchButton
│ │ │ └── index.jsx
│ │ ├── UserProfileCard
│ │ │ └── index.jsx
│ │ └── ViewWithDivider
│ │ │ └── index.jsx
│ ├── modals
│ │ ├── ActivityBottomSheet
│ │ │ ├── EntityActivity.jsx
│ │ │ ├── FilterActivity.jsx
│ │ │ ├── UserActivity
│ │ │ │ └── index.jsx
│ │ │ └── index.jsx
│ │ ├── BadgeEarnModal
│ │ │ └── index.jsx
│ │ ├── BaseBottomSheet
│ │ │ └── index.jsx
│ │ ├── BaseModal
│ │ │ └── index.jsx
│ │ ├── category
│ │ │ ├── CategorySelector
│ │ │ │ ├── index.js
│ │ │ │ └── styles.js
│ │ │ └── categoryDescription
│ │ │ │ ├── index.js
│ │ │ │ └── styles.js
│ │ ├── conditionTermsModal
│ │ │ ├── index.js
│ │ │ └── style.js
│ │ ├── expansiveModal
│ │ │ └── index.jsx
│ │ ├── newHelpModal
│ │ │ ├── failure
│ │ │ │ ├── index.js
│ │ │ │ └── styles.js
│ │ │ └── success
│ │ │ │ ├── index.js
│ │ │ │ └── styles.js
│ │ └── privacyPolicyModal
│ │ │ ├── index.js
│ │ │ ├── privacy.js
│ │ │ └── style.js
│ ├── molecules
│ │ ├── ActivityMarker
│ │ │ └── index.jsx
│ │ ├── Badge
│ │ │ └── index.jsx
│ │ ├── BadgeCard
│ │ │ └── index.jsx
│ │ ├── CategoriesList
│ │ │ └── index.jsx
│ │ ├── CustomDrawerItem
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── CustomHeader
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── DefaultButtonWithBagdes
│ │ │ └── index.jsx
│ │ ├── DescriptionBox
│ │ │ └── index.jsx
│ │ ├── Dialog
│ │ │ └── index.jsx
│ │ ├── FloatingIconButton
│ │ │ └── index.jsx
│ │ ├── FollowCount
│ │ │ └── index.jsx
│ │ ├── ProfilePhoto
│ │ │ └── index.jsx
│ │ ├── TextSwitch
│ │ │ └── index.jsx
│ │ ├── TimelineItem
│ │ │ └── index.jsx
│ │ ├── TutorialCard
│ │ │ └── index.jsx
│ │ ├── UserCard
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ └── UserListItem
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ ├── organisms
│ │ ├── ActivitiesList
│ │ │ └── index.jsx
│ │ ├── ActivityCard
│ │ │ └── index.jsx
│ │ ├── AddressForm
│ │ │ ├── constructor.js
│ │ │ └── index.jsx
│ │ ├── AnimatedMap
│ │ │ └── index.jsx
│ │ ├── BadgesList
│ │ │ └── index.jsx
│ │ ├── CustomDrawerList
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── DefaultCamera
│ │ │ └── index.jsx
│ │ ├── DefaultTimeline
│ │ │ └── index.jsx
│ │ ├── HorizontalList
│ │ │ └── index.jsx
│ │ ├── NotFound
│ │ │ └── index.jsx
│ │ ├── PersonalDataForm
│ │ │ ├── constructor.js
│ │ │ └── index.jsx
│ │ └── SliderModal
│ │ │ └── index.jsx
│ ├── profileList
│ │ ├── index.jsx
│ │ └── styles.js
│ └── templates
│ │ ├── BordedScreenLayout
│ │ └── index.jsx
│ │ ├── CustomDrawerContent
│ │ ├── index.jsx
│ │ └── styles.js
│ │ └── HelpScreenLayout
│ │ └── index.jsx
├── config
│ ├── authmiaajuda-firebase-example.json
│ └── envVariables.js
├── docs
│ ├── FAQ
│ │ ├── EmergencyNumbers.js
│ │ ├── HelpOfferedRecommendations.js
│ │ ├── HelpRequestRecommendations.js
│ │ ├── HowToBeVolunteer.js
│ │ ├── HowToChooseHelpOffered.js
│ │ ├── HowToCreateHelp.js
│ │ ├── HowToOfferHelp.js
│ │ └── faqOptions.jsx
│ ├── filterMarkers.js
│ ├── terms.js
│ └── warning.js
├── images
│ ├── catPhoto.png
│ ├── logo.png
│ └── logo.svg
├── index.js
├── pages
│ ├── ActivitiesPages
│ │ ├── History
│ │ │ └── index.jsx
│ │ ├── MyCampaigns
│ │ │ └── index.jsx
│ │ ├── MyOfferedHelp
│ │ │ ├── MyOfferHelpDescription
│ │ │ │ └── index.jsx
│ │ │ └── index.jsx
│ │ ├── MyRequestedHelp
│ │ │ ├── MyRequestHelpDescription
│ │ │ │ ├── FeedbackModal
│ │ │ │ │ └── index.jsx
│ │ │ │ └── index.jsx
│ │ │ └── index.jsx
│ │ ├── SelectedHelpOnMap
│ │ │ └── index.jsx
│ │ └── styles.js
│ ├── AuthPages
│ │ ├── Address
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── ConfirmRegister
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── ForgotPassword
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── InitialScreen
│ │ │ ├── index.js
│ │ │ └── styles.js
│ │ ├── Location
│ │ │ ├── index.jsx
│ │ │ ├── styles.js
│ │ │ └── texts.json
│ │ ├── Login
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── PersonalData
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── Photo
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── RegistrationData
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ └── RiskGroup
│ │ │ ├── index.js
│ │ │ └── styles.js
│ ├── Badges
│ │ └── index.jsx
│ ├── EditProfile
│ │ └── index.jsx
│ ├── Feedback
│ │ └── index.jsx
│ ├── FindUsersPages
│ │ ├── SocialNetworkProfile
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── index.jsx
│ │ └── styles.js
│ ├── HelpPages
│ │ ├── CampaignDescription
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── CreateCampaign
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── CreateHelpOffer
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── CreateHelpRequest
│ │ │ ├── index.jsx
│ │ │ └── styles.js
│ │ ├── HelpsOffered
│ │ │ ├── HelpsFinished
│ │ │ │ └── index.jsx
│ │ │ └── OnGoingHelps
│ │ │ │ └── index.jsx
│ │ └── MyRequests
│ │ │ ├── HelpsFinished
│ │ │ └── index.jsx
│ │ │ └── styles.js
│ ├── InformationsCenter
│ │ ├── index.jsx
│ │ └── styles.js
│ ├── IntroSlides
│ │ ├── index.js
│ │ └── styles.js
│ ├── Main
│ │ ├── MapScreen.jsx
│ │ └── index.jsx
│ ├── Notification
│ │ ├── index.jsx
│ │ └── styles.js
│ ├── Splash
│ │ ├── index.js
│ │ └── styles.js
│ ├── TimeLine
│ │ └── index.jsx
│ ├── UserList
│ │ └── index.jsx
│ └── UserProfile
│ │ └── index.jsx
├── services
│ ├── Activity.js
│ ├── Api.js
│ ├── Badge.js
│ ├── Campaign.js
│ ├── Category.js
│ ├── Entity.js
│ ├── Feedback.js
│ ├── Firebase.js
│ ├── Help.js
│ ├── Notification.js
│ ├── Session.js
│ ├── Timeline.js
│ ├── User.js
│ ├── callService.js
│ ├── socialNetworkProfile.js
│ └── socket.js
├── store
│ ├── actions.js
│ ├── contexts
│ │ ├── ScreenTemplateContext
│ │ │ ├── index.jsx
│ │ │ └── styles.jsx
│ │ ├── activitiesContext.jsx
│ │ ├── activityBottomSheetContext.jsx
│ │ ├── badgeContext.jsx
│ │ ├── categoryContext.jsx
│ │ ├── cepContext.jsx
│ │ ├── deviceInformationContext.js
│ │ ├── feedbackContext.jsx
│ │ ├── helpContext.js
│ │ ├── loadingContext.jsx
│ │ ├── socialNetworkProfileContext.jsx
│ │ ├── timelineContext.jsx
│ │ └── userContext.js
│ └── reducers
│ │ ├── helpReducer.js
│ │ └── userReducer.js
└── utils
│ ├── Alert.js
│ ├── ToastAndroid.js
│ ├── callNumber.js
│ ├── cnpjValidator.js
│ ├── cpfValidator.js
│ ├── createInteraction.js
│ ├── dateValidator.js
│ ├── emailValidator.js
│ ├── formatCNPJ.js
│ ├── formatCpf.js
│ ├── formatDate.js
│ ├── formatPhone.js
│ ├── getActivityIcon.js
│ ├── getPastTime.js
│ ├── getScreenTitle.js
│ ├── getSliderBody.jsx
│ ├── getYearsSince.js
│ ├── helpDistance.js
│ ├── isAllEqual.js
│ ├── isRecentDate.js
│ ├── messageOperation.js
│ ├── navigateToCreateFlow.js
│ ├── navigateToDescription.js
│ ├── navigateToMyActivity.js
│ ├── openMaps.js
│ ├── openWhatsapp.js
│ ├── parseDate.js
│ ├── passwordValidator.js
│ ├── phoneValidator.js
│ ├── removeSpecialChars.js
│ ├── riskGroupsObject.js
│ ├── shortenName.js
│ ├── showDrawerButton.js
│ ├── translateFirebaseAuthError.js
│ ├── translatedActivities.js
│ ├── verifyUserInfo.js
│ └── warningPopUp.js
├── tailwind.config.js
└── yarn.lock
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Descrição
2 |
3 | Descrição concisa do que foi feito
4 |
5 | ## Resolve (Issues)
6 |
7 | Issues que foram resolvidas com o PR
8 |
9 | ## PRs relacionados, se houver
10 |
11 | branch | PR
12 | ------ | ------
13 | outro_pr_relacionado | [link]()
14 |
15 | ## Tarefas gerais realizadas
16 | * Tarefa 1
17 | * Tarefa 2
18 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | ---
2 | image: patwoz/expo-cli:3
3 |
4 | cache:
5 | key: ${CI_COMMIT_REF_SLUG}
6 | paths:
7 | - node_modules/
8 |
9 | stages:
10 | - publish
11 | - staging
12 |
13 | before_script:
14 | - cd app
15 | - cat $GOOGLE_CONFIG > .google-services.json
16 | - cat $FIREBASE_CONFIG_DEV > ./src/config/authmiaajuda-firebase-dev.json
17 | - cat $FIREBASE_CONFIG > ./src/config/authmiaajuda-firebase.json
18 | - yarn install --pure-lockfile --non-interactive
19 |
20 | publishing:
21 | stage: publish
22 | script:
23 | - chmod +x ./setup_env.sh
24 | - ./setup_env.sh
25 | - echo fs.inotify.max_user_watches=524288 | tee -a /etc/sysctl.conf && sysctl -p
26 | - expo login -u $EXPO_USERNAME -p $EXPO_PASSWORD
27 | - expo publish --release-channel prod --non-interactive
28 | only:
29 | - master
30 |
31 | staging:
32 | stage: staging
33 | script:
34 | - chmod +x ./setup_env.sh
35 | - ./setup_env.sh
36 | - echo fs.inotify.max_user_watches=524288 | tee -a /etc/sysctl.conf && sysctl -p
37 | - expo login -u $EXPO_USERNAME -p $EXPO_PASSWORD
38 | - expo publish --release-channel staging --non-interactive
39 | only:
40 | - develop
41 |
--------------------------------------------------------------------------------
/app/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/app/.env-example:
--------------------------------------------------------------------------------
1 | IP_ADDRESS=Adicione Seu IPV4 Aqui
2 | MAPS_API_KEY=
3 | TURN_OFF_OFFER=false
--------------------------------------------------------------------------------
/app/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | es6: true,
4 | node: true,
5 | jest: true,
6 | },
7 | extends: [
8 | 'eslint:recommended',
9 | 'plugin:react/recommended',
10 | 'prettier',
11 | 'eslint-config-prettier',
12 | ],
13 | parserOptions: {
14 | ecmaFeatures: {
15 | jsx: true,
16 | },
17 | ecmaVersion: 11,
18 | sourceType: 'module',
19 | },
20 | plugins: ['react', 'react-hooks', 'prettier'],
21 | rules: {
22 | quotes: ['error', 'single', { avoidEscape: true }],
23 | semi: ['error', 'always'],
24 | 'no-empty-function': 'off',
25 | 'react/display-name': 'off',
26 | 'react/prop-types': 'off',
27 | 'prettier/prettier': 'error',
28 | },
29 | settings: {
30 | react: {
31 | version: 'detect',
32 | },
33 | },
34 | };
35 |
--------------------------------------------------------------------------------
/app/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 | web-report/
12 |
13 | # macOS
14 | .DS_Store
15 | .env
16 |
17 | #webstorm
18 | .idea
19 |
20 | #auth json
21 | authmiaajuda-firebase.json
22 | authmiaajuda-firebase-dev.json
23 | google-services.json
24 |
--------------------------------------------------------------------------------
/app/.lintstagedrc:
--------------------------------------------------------------------------------
1 | {
2 | "*.+(js|ts|tsx)": [
3 | "eslint"
4 | ],
5 | "**/*.+(js|json|ts|tsx)": [
6 | "prettier --write",
7 | "git add"
8 | ]
9 | }
--------------------------------------------------------------------------------
/app/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | singleQuote: true,
3 | trailingComma: 'all',
4 | printWidth: 80,
5 | tabWidth: 4,
6 | };
7 |
--------------------------------------------------------------------------------
/app/App.js:
--------------------------------------------------------------------------------
1 | import 'react-native-gesture-handler';
2 | import React, { useEffect, useState } from 'react';
3 | import Root from './src/index';
4 | import loadFonts from './assets/fonts/loadFonts';
5 | import { View, LogBox, AppRegistry } from 'react-native';
6 |
7 | LogBox.ignoreLogs(['Unrecognized WebSocket']);
8 |
9 | AppRegistry.registerComponent('main', () => App);
10 |
11 | export default function App() {
12 | const [fontsLoaded, setFonts] = useState(false);
13 | useEffect(() => {
14 | async function loadFontsAsync() {
15 | await loadFonts();
16 | setFonts(true);
17 | }
18 | loadFontsAsync();
19 | }, []);
20 |
21 | if (!fontsLoaded) return ;
22 |
23 | return ;
24 | }
25 |
--------------------------------------------------------------------------------
/app/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:14
2 |
3 | # Diretorio de trabalho
4 | WORKDIR /app
5 |
6 | # Docker guarda cache para cada instrução do dockerfile.
7 | # Colocar instruções mais mutáveis no final do arquivo para haver proveito do cache
8 | RUN yarn global add expo-cli
9 |
10 |
11 | COPY package.json /app/
12 |
13 | RUN yarn install
14 |
15 | # Após instalação das dependências do package.json, é hora de instalar o expo que é onde o app é executado
16 | # Copiar todo o diretório para o diretório de trabalho do Docker
17 | # Definir a porta 19000 como porta de trabalho
18 | # Definir o comando yarn start para quando executarmos o comando "run" no container
19 |
20 | COPY . /app/
21 |
22 | EXPOSE 19000
23 |
24 |
25 | ENV EXPO_DEVTOOLS_LISTEN_ADDRESS=0.0.0.0
26 |
27 |
28 | CMD REACT_NATIVE_PACKAGER_HOSTNAME=$IP_ADDRESS yarn start
29 |
--------------------------------------------------------------------------------
/app/app.config.js:
--------------------------------------------------------------------------------
1 |
2 | const { MAPS_API_KEY } = process.env;
3 |
4 | export default ({ config }) => {
5 | return {
6 | ...config,
7 | android: {
8 | package: 'com.unb.miaajuda',
9 | permissions: [
10 | 'ACCESS_COARSE_LOCATION',
11 | 'ACCESS_FINE_LOCATION',
12 | 'CAMERA',
13 | 'MANAGE_DOCUMENTS',
14 | 'READ_EXTERNAL_STORAGE',
15 | 'READ_PHONE_STATE',
16 | 'WRITE_EXTERNAL_STORAGE',
17 | ],
18 | googleServicesFile: './google-services.json',
19 | config: {
20 | googleMaps: {
21 | apiKey: MAPS_API_KEY,
22 | },
23 | },
24 | versionCode: 220,
25 | },
26 | };
27 | };
28 |
--------------------------------------------------------------------------------
/app/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "Mia Ajuda",
4 | "slug": "miaajuda",
5 | "privacy": "public",
6 | "platforms": ["android", "ios"],
7 | "notification": {
8 | "icon": "./assets/images/logo.png",
9 | "color": "#4b8ab9",
10 | "androidMode": "default"
11 | },
12 | "version": "2.2.0 Mutt",
13 | "orientation": "portrait",
14 | "icon": "./assets/images/logo.png",
15 | "splash": {
16 | "image": "./assets/images/splash.png",
17 | "resizeMode": "contain",
18 | "backgroundColor": "#4b8ab9"
19 | },
20 | "updates": {
21 | "fallbackToCacheTimeout": 0
22 | },
23 | "assetBundlePatterns": ["**/*"],
24 | "ios": {
25 | "supportsTablet": true,
26 | "bundleIdentifier": "com.miaajuda.app"
27 | },
28 | "packagerOpts": {
29 | "config": "metro.config.js",
30 | "sourceExts": [
31 | "expo.ts",
32 | "expo.tsx",
33 | "expo.js",
34 | "expo.jsx",
35 | "ts",
36 | "tsx",
37 | "js",
38 | "jsx",
39 | "json",
40 | "wasm",
41 | "svg"
42 | ]
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/assets/fonts/Montserrat/Montserrat-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/fonts/Montserrat/Montserrat-Bold.ttf
--------------------------------------------------------------------------------
/app/assets/fonts/Montserrat/Montserrat-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/fonts/Montserrat/Montserrat-Light.ttf
--------------------------------------------------------------------------------
/app/assets/fonts/Montserrat/Montserrat-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/fonts/Montserrat/Montserrat-Medium.ttf
--------------------------------------------------------------------------------
/app/assets/fonts/Montserrat/Montserrat-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/fonts/Montserrat/Montserrat-Regular.ttf
--------------------------------------------------------------------------------
/app/assets/fonts/Montserrat/Montserrat-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/fonts/Montserrat/Montserrat-SemiBold.ttf
--------------------------------------------------------------------------------
/app/assets/fonts/loadFonts.js:
--------------------------------------------------------------------------------
1 | import * as Font from 'expo-font';
2 |
3 | export default async function loadFonts() {
4 | return Font.loadAsync({
5 | 'montserrat-light': require('../fonts/Montserrat/Montserrat-Light.ttf'),
6 | 'montserrat-regular': require('../fonts/Montserrat/Montserrat-Regular.ttf'),
7 | 'montserrat-medium': require('../fonts/Montserrat/Montserrat-Medium.ttf'),
8 | 'montserrat-semibold': require('../fonts/Montserrat/Montserrat-SemiBold.ttf'),
9 | 'montserrat-bold': require('../fonts/Montserrat/Montserrat-Bold.ttf'),
10 | });
11 | }
12 |
--------------------------------------------------------------------------------
/app/assets/images/Seedling.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/assets/images/TutorialImages/tela01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/images/TutorialImages/tela01.png
--------------------------------------------------------------------------------
/app/assets/images/TutorialImages/tela02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/images/TutorialImages/tela02.png
--------------------------------------------------------------------------------
/app/assets/images/TutorialImages/tela03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/images/TutorialImages/tela03.png
--------------------------------------------------------------------------------
/app/assets/images/TutorialImages/tela04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/images/TutorialImages/tela04.png
--------------------------------------------------------------------------------
/app/assets/images/back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/images/back.png
--------------------------------------------------------------------------------
/app/assets/images/blueCat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/images/blueCat.png
--------------------------------------------------------------------------------
/app/assets/images/blueCatCard.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/assets/images/blueLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/images/blueLogo.png
--------------------------------------------------------------------------------
/app/assets/images/exclamation.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/assets/images/hand.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/assets/images/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/images/home.png
--------------------------------------------------------------------------------
/app/assets/images/house.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/app/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/images/logo.png
--------------------------------------------------------------------------------
/app/assets/images/noImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/images/noImage.png
--------------------------------------------------------------------------------
/app/assets/images/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/images/splash.png
--------------------------------------------------------------------------------
/app/assets/images/whileLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/images/whileLogo.png
--------------------------------------------------------------------------------
/app/assets/images/whiteCat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/assets/images/whiteCat.png
--------------------------------------------------------------------------------
/app/assets/styles/colorVariables.js:
--------------------------------------------------------------------------------
1 | const colors = {
2 | primary: '#4b8ab9',
3 | 'primary-400': 'rgba(75, 138, 185, 0.4)',
4 | primaryContrast: '#81b0ff',
5 | primaryLowOpacity: '#E4F4FF',
6 | secondary: '#f7ef6e',
7 | danger: '#e47171',
8 | 'danger-400': 'rgba(228, 113, 113, 0.4)',
9 | dark: '#353535',
10 | light: '#f7f7f7',
11 | success: '#77dd77',
12 | };
13 |
14 | export default colors;
15 |
--------------------------------------------------------------------------------
/app/assets/styles/fontVariable.js:
--------------------------------------------------------------------------------
1 | import colors from './colorVariables';
2 | import { RFValue } from 'react-native-responsive-fontsize';
3 |
4 | const minimumTextSize = 14;
5 | const fontFamily = 'montserrat-regular';
6 | const defaultProps = {
7 | color: colors.dark,
8 | fontFamily: fontFamily,
9 | };
10 |
11 | const fonts = {
12 | title: {
13 | ...defaultProps,
14 | fontSize: RFValue(minimumTextSize * 1.5, 640),
15 | },
16 | subtitle: {
17 | ...defaultProps,
18 | fontSize: RFValue(minimumTextSize * 1.2, 640),
19 | },
20 | body: {
21 | ...defaultProps,
22 | fontSize: RFValue(minimumTextSize, 640),
23 | },
24 |
25 | small: {
26 | ...defaultProps,
27 | fontSize: RFValue(minimumTextSize * 0.75, 640),
28 | },
29 | };
30 |
31 | export default fonts;
32 |
--------------------------------------------------------------------------------
/app/assets/styles/mapstyle.js:
--------------------------------------------------------------------------------
1 | const mapStyleNight = [
2 | {
3 | elementType: 'geometry',
4 | stylers: [
5 | {
6 | color: '#1d2c4d',
7 | },
8 | ],
9 | },
10 | {
11 | elementType: 'labels.text.fill',
12 | stylers: [
13 | {
14 | color: '#8ec3b9',
15 | },
16 | ],
17 | },
18 | {
19 | elementType: 'labels.text.stroke',
20 | stylers: [
21 | {
22 | color: '#1a3646',
23 | },
24 | ],
25 | },
26 | {
27 | featureType: 'administrative.country',
28 | elementType: 'geometry.stroke',
29 | stylers: [
30 | {
31 | color: '#4b6878',
32 | },
33 | ],
34 | },
35 | ];
36 |
37 | const mapStyleDay = [
38 | {
39 | featureType: 'administrative.land_parcel',
40 | elementType: 'labels',
41 | stylers: [
42 | {
43 | visibility: 'off',
44 | },
45 | ],
46 | },
47 | {
48 | featureType: 'poi',
49 | elementType: 'labels.text',
50 | stylers: [
51 | {
52 | visibility: 'off',
53 | },
54 | ],
55 | },
56 | {
57 | featureType: 'poi.business',
58 | stylers: [
59 | {
60 | visibility: 'off',
61 | },
62 | ],
63 | },
64 | ];
65 |
66 | export default {
67 | night: {
68 | map: mapStyleNight,
69 | },
70 | day: {
71 | map: mapStyleDay,
72 | },
73 | };
74 |
--------------------------------------------------------------------------------
/app/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | plugins: ['react-native-reanimated/plugin', 'nativewind/babel', ["module:react-native-dotenv", {
6 | "envName": "APP_ENV",
7 | "moduleName": "@env",
8 | "path": ".env",
9 | "blocklist": null,
10 | "allowlist": null,
11 | "blacklist": null,
12 | "whitelist": null,
13 | "safe": false,
14 | "allowUndefined": true,
15 | "verbose": false
16 | }]],
17 | };
18 | };
19 |
--------------------------------------------------------------------------------
/app/colors.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | primary: {
3 | DEFAULT: 'rgba(75, 138, 185, 1)',
4 | 100: 'rgba(75, 138, 185, 0.1)',
5 | 200: 'rgba(75, 138, 185, 0.2)',
6 | 300: 'rgba(75, 138, 185, 0.3)',
7 | 400: 'rgba(75, 138, 185, 0.4)',
8 | 500: 'rgba(75, 138, 185, 0.5)',
9 | 600: 'rgba(75, 138, 185, 0.6)',
10 | 700: 'rgba(75, 138, 185, 0.7)',
11 | 800: 'rgba(75, 138, 185, 0.8)',
12 | 900: 'rgba(75, 138, 185, 0.9)',
13 | contrast: '#81b0ff',
14 | darker: '#182C3B',
15 | },
16 | secondary: {
17 | DEFAULT: '#f7ef6e',
18 | 500: '#FAD980',
19 | },
20 | danger: {
21 | DEFAULT: 'rgba(228, 113, 113, 1)',
22 | 100: 'rgba(228, 113, 113, 0.1)',
23 | 200: 'rgba(228, 113, 113, 0.2)',
24 | 300: 'rgba(228, 113, 113, 0.3)',
25 | darker: '#681111',
26 | },
27 | black: {
28 | DEFAULT: 'rgba(53,53,53,1)',
29 | 100: 'rgba(53,53,53,0.1)',
30 | 200: 'rgba(53,53,53,0.2)',
31 | 300: 'rgba(53,53,53,0.3)',
32 | 400: 'rgba(53,53,53,0.4)',
33 | 500: 'rgba(53,53,53,0.5)',
34 | 600: 'rgba(53,53,53,0.6)',
35 | 700: 'rgba(53,53,53,0.7)',
36 | 800: 'rgba(53,53,53,0.8)',
37 | 900: 'rgba(53,53,53,0.9)',
38 | },
39 | light: '#f7f7f7',
40 | success: '#77dd77',
41 | background: '#f1f1f1',
42 | new_background: '#F2F2F7',
43 | gray: {
44 | DEFAULT: '#e6e6e6',
45 | contrast: '#D2D2D2',
46 | },
47 | 'first-rank': '#BF6159',
48 | 'second-rank': '#538D95',
49 | 'thirt-rank': '#D0A408',
50 | };
51 |
--------------------------------------------------------------------------------
/app/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.7'
2 | services:
3 | miajuda-expo:
4 | container_name: miajuda_FrontEnd
5 | build:
6 | context: .
7 | dockerfile: Dockerfile
8 | stdin_open: true
9 | tty: true
10 | env_file:
11 | - '.env'
12 | ports:
13 | - '19000:19000'
14 | - '19001:19001'
15 | - '19002:19002'
16 | volumes:
17 | - '.:/app'
18 | - './package.json:/app/package.json'
19 | - './package-lock.json:/app/package-lock.json'
20 | - 'notused:/app/node_modules'
21 | environment:
22 | - NODE_ENV=development
23 | volumes:
24 | notused:
25 |
--------------------------------------------------------------------------------
/app/eas.json:
--------------------------------------------------------------------------------
1 | {
2 | "cli": {
3 | "version": ">= 0.57.0"
4 | },
5 | "submit": {
6 | "production": {
7 | "android": {
8 | "serviceAccountKeyPath": "./serviceAccountKey.json",
9 | "track": "production"
10 | }
11 | },
12 | "alpha_test": {
13 | "android": {
14 | "serviceAccountKeyPath": "./serviceAccountKey.json",
15 | "track": "alpha"
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/metro.config.js:
--------------------------------------------------------------------------------
1 | const { getDefaultConfig } = require('expo/metro-config');
2 |
3 | const config = getDefaultConfig(__dirname);
4 |
5 | config.transformer.babelTransformerPath = require.resolve(
6 | 'react-native-svg-transformer',
7 | );
8 |
9 | config.resolver.assetExts = config.resolver.assetExts.filter(
10 | (ext) => ext !== 'svg',
11 | );
12 | config.resolver.sourceExts = [...config.resolver.sourceExts, 'svg'];
13 |
14 | module.exports = config;
15 |
--------------------------------------------------------------------------------
/app/setup_env.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo IP_ADDRESS=$IP_ADDRESS >> .env
4 | echo MAPS_API_KEY=$MAPS_API_KEY >> .env
--------------------------------------------------------------------------------
/app/src/ExternalServices/ViaCep.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | class Viacep {
3 | async getCepInformation(currentCep) {
4 | const url = `https://viacep.com.br/ws/${currentCep}/json/`;
5 | const cepInformation = await axios.get(url);
6 | if (cepInformation.data.erro) throw new Error('cep inválido');
7 | return cepInformation.data;
8 | }
9 | }
10 |
11 | export default new Viacep();
12 |
--------------------------------------------------------------------------------
/app/src/Navigation/AuthNavigation/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createStackNavigator } from '@react-navigation/stack';
3 | import Login from '../../pages/AuthPages/Login';
4 | import RegistrationData from '../../pages/AuthPages/RegistrationData';
5 | import PersonalData from '../../pages/AuthPages/PersonalData';
6 | import RiskGroup from '../../pages/AuthPages/RiskGroup';
7 | import ForgotPassword from '../../pages/AuthPages/ForgotPassword';
8 | import InitialScreen from '../../pages/AuthPages/InitialScreen';
9 | import Location from '../../pages/AuthPages/Location';
10 | import ConfirmRegister from '../../pages/AuthPages/ConfirmRegister';
11 |
12 | const Stack = createStackNavigator();
13 | const AuthRoutes = () => {
14 | return (
15 |
21 |
22 |
23 |
24 |
28 |
29 |
30 |
31 |
32 |
33 | );
34 | };
35 | export default AuthRoutes;
36 |
--------------------------------------------------------------------------------
/app/src/Navigation/MainNavigation/GivenHelps/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
3 | import History from '../../../pages/ActivitiesPages/History';
4 | import myOfferedHelp from '../../../pages/ActivitiesPages/MyOfferedHelp';
5 | import myRequestedHelp from '../../../pages/ActivitiesPages/MyRequestedHelp';
6 | import { UserContext } from '../../../store/contexts/userContext';
7 | import myCampaigns from '../../../pages/ActivitiesPages/MyCampaigns';
8 | import { screenOptions } from '../screenOptions';
9 |
10 | const TopTab = createMaterialTopTabNavigator();
11 | export const NavigationGivenHelps = () => {
12 | const { isEntity } = useContext(UserContext);
13 | return (
14 |
18 | {isEntity ? OngGivenHelps() : UserGivenHelps()}
19 |
20 |
21 | );
22 | };
23 |
24 | const OngGivenHelps = () => (
25 |
26 | );
27 |
28 | const UserGivenHelps = () => (
29 | <>
30 |
31 |
32 | >
33 | );
34 |
--------------------------------------------------------------------------------
/app/src/Navigation/MainNavigation/MainNavigationStyles/MainStackHeaderStyle.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { CustomHeader } from '../../../components/molecules/CustomHeader';
3 | import { getScreenTtile } from '../../../utils/getScreenTitle';
4 |
5 | const headerStyle = ({
6 | navigation,
7 | route,
8 | iconType = 'drawer',
9 | buttonProps,
10 | hasTitle = true,
11 | }) => {
12 | return {
13 | header: () => (
14 |
20 | ),
21 | };
22 | };
23 |
24 | export default headerStyle;
25 |
--------------------------------------------------------------------------------
/app/src/Navigation/MainNavigation/Routes/BadgeRoutes/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createStackNavigator } from '@react-navigation/stack';
3 | import { Badges } from '../../../../pages/Badges';
4 |
5 | const Stack = createStackNavigator();
6 |
7 | export const BadgeRoutes = () => {
8 | return (
9 | <>
10 |
11 | >
12 | );
13 | };
14 |
--------------------------------------------------------------------------------
/app/src/Navigation/MainNavigation/Routes/FeedbackRoutes/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createStackNavigator } from '@react-navigation/stack';
3 | import { FeedbackScreen } from '../../../../pages/Feedback';
4 | import headerStyle from '../../MainNavigationStyles/MainStackHeaderStyle';
5 |
6 | const Stack = createStackNavigator();
7 |
8 | export const FeedbackRoutes = () => {
9 | return (
10 | <>
11 |
16 | >
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/app/src/Navigation/MainNavigation/Routes/MapRoutes/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createStackNavigator } from '@react-navigation/stack';
3 | import Main from '../../../../pages/Main';
4 | import headerStyle from '../../MainNavigationStyles/MainStackHeaderStyle';
5 | import MapScreen from '../../../../pages/Main/MapScreen';
6 |
7 | const Stack = createStackNavigator();
8 |
9 | export const MapRoutes = () => {
10 | return (
11 | <>
12 |
13 |
18 | >
19 | );
20 | };
21 |
--------------------------------------------------------------------------------
/app/src/Navigation/MainNavigation/Routes/MoreInfoRoutes/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createStackNavigator } from '@react-navigation/stack';
3 | import Location from '../../../../pages/AuthPages/Location';
4 | import Photo from '../../../../pages/AuthPages/Photo';
5 | import Address from '../../../../pages/AuthPages/Address';
6 | const Stack = createStackNavigator();
7 |
8 | export const MoreInfoRoutes = () => {
9 | return (
10 | <>
11 |
16 |
17 |
18 | >
19 | );
20 | };
21 |
--------------------------------------------------------------------------------
/app/src/Navigation/MainNavigation/Routes/ProfileRoutes/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createStackNavigator } from '@react-navigation/stack';
3 | import headerStyle from '../../MainNavigationStyles/MainStackHeaderStyle';
4 | import { UserProfile } from '../../../../pages/UserProfile';
5 | import { EditProfile } from '../../../../pages/EditProfile';
6 |
7 | const Stack = createStackNavigator();
8 |
9 | export const ProfileRoutes = () => {
10 | return (
11 | <>
12 | {
16 | return headerStyle({
17 | ...props,
18 | iconType: 'drawer',
19 | buttonProps: {
20 | visible: true,
21 | text: 'Editar perfil',
22 | onPress: () =>
23 | props.navigation.navigate('editProfile'),
24 | },
25 | });
26 | }}
27 | />
28 |
29 | >
30 | );
31 | };
32 |
--------------------------------------------------------------------------------
/app/src/Navigation/MainNavigation/Routes/TimelineRoutes/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createStackNavigator } from '@react-navigation/stack';
3 | import { Timeline } from '../../../../pages/TimeLine';
4 | import headerStyle from '../../MainNavigationStyles/MainStackHeaderStyle';
5 |
6 | const Stack = createStackNavigator();
7 |
8 | export const TimelineRoutes = () => {
9 | return (
10 | <>
11 |
16 | >
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/app/src/Navigation/MainNavigation/Routes/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { createStackNavigator } from '@react-navigation/stack';
3 | import headerStyle from '../MainNavigationStyles/MainStackHeaderStyle';
4 | import NotificationPage from '../../../pages/Notification/index';
5 | import { ProfileRoutes } from './ProfileRoutes';
6 | import { SocialNetworkRoutes } from './SocialNetworkRoutes';
7 | import { ActivitiesRoutes } from './ActivitiesRoutes';
8 | import { MoreInfoRoutes } from './MoreInfoRoutes';
9 | import { MapRoutes } from './MapRoutes';
10 | import { BadgeRoutes } from './BadgeRoutes';
11 | import { FeedbackRoutes } from './FeedbackRoutes';
12 | import { TimelineRoutes } from './TimelineRoutes';
13 |
14 | const Stack = createStackNavigator();
15 |
16 | const othersRoutes = [
17 | MapRoutes,
18 | MoreInfoRoutes,
19 | ActivitiesRoutes,
20 | ProfileRoutes,
21 | SocialNetworkRoutes,
22 | TimelineRoutes,
23 | BadgeRoutes,
24 | FeedbackRoutes,
25 | ];
26 |
27 | const Routes = ({ initialRouteName }) => (
28 | headerStyle({ ...props, iconType: 'back' })}
31 | >
32 |
37 | {othersRoutes.map((routes, i) => (
38 | {routes()}
39 | ))}
40 |
41 | );
42 |
43 | export default Routes;
44 |
--------------------------------------------------------------------------------
/app/src/Navigation/MainNavigation/options.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Icon } from 'react-native-elements';
3 | import { RFValue } from 'react-native-responsive-fontsize';
4 | import colors from '../../../assets/styles/colorVariables';
5 |
6 | export const drawerNavigationOptions = {
7 | headerStyle: {
8 | backgroundColor: colors.primary,
9 | },
10 | headerTintColor: colors.light,
11 |
12 | drawerActiveTintColor: colors.dark,
13 | drawerInactiveTintColor: colors.dark,
14 | drawerLabelStyle: {
15 | fontFamily: 'montserrat-regular',
16 | fontSize: RFValue(16, 640),
17 | },
18 | drawerActiveBackgroundColor: colors.primaryLowOpacity,
19 | };
20 |
21 | export const drawerScreenOptions = (screenName, icon, family = 'material') => {
22 | return {
23 | headerTitle: screenName,
24 | title: screenName,
25 | headerShown: false,
26 | drawerIcon: () => (
27 |
33 | ),
34 | };
35 | };
36 |
--------------------------------------------------------------------------------
/app/src/Navigation/MainNavigation/screenOptions.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions, Text } from 'react-native';
3 | import colors from '../../../colors';
4 | import fonts from '../../../assets/styles/fontVariable';
5 | import { RFValue } from 'react-native-responsive-fontsize';
6 |
7 | export const screenOptions = ({ route }) => {
8 | const renderTabText = (text, style) => {text};
9 |
10 | return {
11 | tabBarLabel: ({ focused }) => {
12 | const commonStyle = {
13 | ...fonts.body,
14 | color: colors.dark,
15 | fontSize: RFValue(14, 640),
16 | width: Dimensions.get('screen').width * 0.3,
17 | textAlign: 'center',
18 | };
19 | const style = focused
20 | ? {
21 | ...commonStyle,
22 | fontFamily: 'montserrat-bold',
23 | }
24 | : commonStyle;
25 | return renderTabText(route.name, style);
26 | },
27 | tabBarStyle: {
28 | backgroundColor: 'transparent',
29 | shadowColor: 'transparent',
30 | borderBottomWidth: 1,
31 | borderColor: '#BCCBCA',
32 | paddingHorizontal: 8,
33 | },
34 | tabBarIndicatorStyle: {
35 | backgroundColor: colors.primary.DEFAULT,
36 | borderRadius: 16,
37 | padding: 1,
38 | },
39 | };
40 | };
41 |
--------------------------------------------------------------------------------
/app/src/Navigation/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import AuthRoutes from './AuthNavigation';
3 | import { NavigationContainer } from '@react-navigation/native';
4 | import { UserContext } from '../store/contexts/userContext';
5 | import Splash from '../pages/Splash';
6 | import { MainNavigation } from './MainNavigation';
7 | import { ActivitiesContext } from '../store/contexts/activitiesContext';
8 |
9 | const Routes = () => {
10 | const { user } = useContext(UserContext);
11 | const { loadingActivities } = useContext(ActivitiesContext);
12 | const isLoadingUserInformation = user && user.showSplash;
13 | const isUserAuthenticated = user._id;
14 |
15 | if (isLoadingUserInformation) {
16 | return ;
17 | } else if (isUserAuthenticated && loadingActivities) {
18 | return ;
19 | }
20 |
21 | return (
22 |
23 | {isUserAuthenticated ? : }
24 |
25 | );
26 | };
27 |
28 | export default Routes;
29 |
--------------------------------------------------------------------------------
/app/src/components/Avatar/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { Icon } from 'react-native-elements';
4 | import colors from '../../../assets/styles/colorVariables';
5 | import styles from './styles';
6 |
7 | export default function Avatar({ isRiskGroup, iconType }) {
8 | const iconColor = isRiskGroup ? colors.danger : colors.primary;
9 |
10 | return (
11 |
12 |
18 |
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/components/Avatar/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | const styles = StyleSheet.create({
4 | container: {
5 | width: 40,
6 | height: 40,
7 | backgroundColor: '#fff',
8 | borderRadius: 25,
9 | transform: [{ rotate: '-10deg' }],
10 | },
11 | });
12 |
13 | export default styles;
14 |
--------------------------------------------------------------------------------
/app/src/components/Container/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import styles from './styles';
4 |
5 | export default function Container(props) {
6 | return {props.children};
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/components/Container/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | const styles = StyleSheet.create({
4 | container: {
5 | margin: 16,
6 | height: '100%',
7 | },
8 | });
9 |
10 | export default styles;
11 |
--------------------------------------------------------------------------------
/app/src/components/CustomMap/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useCallback, useRef } from 'react';
2 | import MapView from 'react-native-maps';
3 | import mapstyle from '../../../assets/styles/mapstyle';
4 | import { useFocusEffect } from '@react-navigation/native';
5 |
6 | export default function CustomMap({
7 | children,
8 | initialRegion,
9 | animateToRegion,
10 | showsMyLocationButton = true,
11 | }) {
12 | const mapRef = useRef(null);
13 |
14 | useFocusEffect(
15 | useCallback(() => {
16 | if (animateToRegion) {
17 | mapRef.current.animateToRegion(animateToRegion, 700);
18 | }
19 | }, [animateToRegion]),
20 | );
21 |
22 | return (
23 |
33 | {children}
34 |
35 | );
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/components/FAQModals/EmergencyNumbersModal/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import emergencyNumbers from '../../../docs/FAQ/EmergencyNumbers';
3 | import { ModalComponent } from '../modal';
4 |
5 | export default function EmergencyNumbers({ visible, setVisible }) {
6 | // TODO: replace it later with a new modal
7 | return (
8 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/components/FAQModals/modal.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Modal, ScrollView, Text, View } from 'react-native';
3 | import styles from './styles';
4 | import { FloatingIconButton } from '../molecules/FloatingIconButton';
5 |
6 | export const ModalComponent = (props) => {
7 | return (
8 | props.setVisible(false)}
12 | animationType="fade"
13 | >
14 |
15 |
16 | {
19 | props.setVisible(false);
20 | }}
21 | />
22 |
23 | {props.list.map((numbers) => {
24 | return (
25 |
26 |
27 | {' '}
28 | {numbers.number}{' '}
29 |
30 |
31 | {' '}
32 | {numbers.description}{' '}
33 |
34 |
35 | );
36 | })}
37 |
38 |
39 |
40 |
41 | );
42 | };
43 |
--------------------------------------------------------------------------------
/app/src/components/FAQModals/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import colors from '../../../assets/styles/colorVariables';
3 |
4 | const minimumTextSize = 16;
5 |
6 | const styles = StyleSheet.create({
7 | modalContainer: {
8 | width: '100%',
9 | height: '100%',
10 | backgroundColor: 'rgba(0,0,0,0.3)',
11 | },
12 |
13 | modalContent: {
14 | paddingTop: 50,
15 | backgroundColor: colors.light,
16 | padding: 20,
17 | marginBottom: 50,
18 | borderRadius: 20,
19 | top: '2.5%',
20 | },
21 |
22 | title: {
23 | alignSelf: 'center',
24 | marginBottom: 10,
25 | fontFamily: 'montserrat-semibold',
26 | color: colors.primary,
27 | fontSize: minimumTextSize * 1.5,
28 | },
29 |
30 | description: {
31 | alignSelf: 'center',
32 | marginBottom: 10,
33 | fontFamily: 'montserrat-semibold',
34 | color: colors.primary,
35 | fontSize: minimumTextSize,
36 | },
37 |
38 | icon: {
39 | top: '5.5%',
40 | right: 20,
41 | position: 'absolute',
42 | zIndex: 5,
43 | },
44 | });
45 |
46 | export default styles;
47 |
--------------------------------------------------------------------------------
/app/src/components/HistoricCard/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View, Text } from 'react-native';
3 | import styles from './styles';
4 | export default function HistoricCard({ object, isRiskGroup, children }) {
5 | return (
6 |
13 |
14 |
15 | {object.title}
16 |
17 |
18 |
19 |
20 | {object.description}
21 |
22 |
23 |
24 | {object.categories.map((category) => (
25 |
29 |
30 | {category.name}
31 |
32 |
33 | ))}
34 |
35 |
36 |
37 | {children}
38 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/components/LoadingIndicator/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ActivityIndicator, View } from 'react-native';
3 | import colors from '../../../assets/styles/colorVariables';
4 | import styles from './styles';
5 |
6 | export const LoadingIndicator = () => {
7 | return (
8 |
9 |
10 |
11 | );
12 | };
13 |
--------------------------------------------------------------------------------
/app/src/components/LoadingIndicator/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | const styles = StyleSheet.create({
4 | loadingContainer: {
5 | position: 'absolute',
6 | alignItems: 'center',
7 | justifyContent: 'center',
8 | width: '100%',
9 | height: '100%',
10 | zIndex: 1,
11 | backgroundColor: 'rgba(52, 52, 52, 0.3)',
12 | },
13 | });
14 |
15 | export default styles;
16 |
--------------------------------------------------------------------------------
/app/src/components/MyRequestCard/old.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/src/components/MyRequestCard/old.js
--------------------------------------------------------------------------------
/app/src/components/MyRequestCard/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import colors from '../../../assets/styles/colorVariables';
4 |
5 | export default StyleSheet.create({
6 | deleteIcon: {
7 | position: 'absolute',
8 | bottom: 20,
9 | right: 10,
10 | },
11 | labelBadge: {
12 | color: '#FFF',
13 | fontWeight: 'bold',
14 | },
15 | badgeStyle: {
16 | backgroundColor: colors.danger,
17 | height: 30,
18 | width: 30,
19 | borderRadius: 50,
20 | },
21 |
22 | containerBadge: {
23 | position: 'absolute',
24 | top: -7,
25 | right: -6,
26 | },
27 | });
28 |
--------------------------------------------------------------------------------
/app/src/components/NoHelps/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles';
3 | import { View, Text, Image } from 'react-native';
4 | export default function NoHelps({ title, color }) {
5 | const catImageColor =
6 | color == 'light'
7 | ? require('../../../assets/images/whiteCat.png')
8 | : require('../../../assets/images/blueCat.png');
9 | return (
10 |
11 |
12 |
19 | {title}
20 |
21 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/components/NoHelps/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../assets/styles/fontVariable';
3 | import colors from '../../../assets/styles/colorVariables';
4 |
5 | const styles = StyleSheet.create({
6 | container: {
7 | height: '100%',
8 | width: '100%',
9 | justifyContent: 'center',
10 | alignItems: 'center',
11 | padding: 20,
12 | },
13 | emptyListImage: {
14 | resizeMode: 'contain',
15 | width: 200,
16 | height: 200,
17 | },
18 |
19 | emptyListTextPrimary: {
20 | ...fonts.title,
21 | color: colors.primary,
22 | marginTop: 10,
23 | textAlign: 'center',
24 | },
25 | emptyListTextLight: {
26 | ...fonts.title,
27 | color: colors.light,
28 | marginTop: 10,
29 | textAlign: 'center',
30 | },
31 | });
32 | export default styles;
33 |
--------------------------------------------------------------------------------
/app/src/components/NotificationCard/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import colors from '../../../assets/styles/colorVariables';
4 |
5 | export default StyleSheet.create({
6 | cardContainer: {
7 | maxWidth: 740,
8 | maxHeight: 240,
9 |
10 | marginTop: 15,
11 |
12 | shadowColor: '#000',
13 | shadowOffset: {
14 | width: 0,
15 | height: 1,
16 | },
17 | shadowOpacity: 0.2,
18 | shadowRadius: 1.41,
19 |
20 | elevation: 2,
21 |
22 | backgroundColor: colors.light,
23 | borderRadius: 8,
24 |
25 | flexDirection: 'row',
26 |
27 | paddingVertical: 15,
28 |
29 | width: '100%',
30 | },
31 |
32 | iconContent: {
33 | width: 30,
34 | height: 30,
35 | justifyContent: 'center',
36 | marginLeft: 15,
37 | borderRadius: 50,
38 | backgroundColor: colors.primary,
39 | elevation: 1,
40 | },
41 |
42 | info: {
43 | marginLeft: 15,
44 | width: '75%',
45 | },
46 |
47 | title: {
48 | fontWeight: 'bold',
49 | fontSize: 16,
50 | },
51 |
52 | time: {
53 | color: 'rgba(0, 0, 0, 0.6)',
54 | fontWeight: '400',
55 | },
56 | });
57 |
--------------------------------------------------------------------------------
/app/src/components/PlusIconTextButton/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View, TouchableOpacity, Text } from 'react-native';
3 |
4 | import styles from './styles';
5 | import { Icon } from 'react-native-elements';
6 |
7 | export default function PlusIconTextButton({ text, onPress }) {
8 | return (
9 |
10 |
15 |
16 | {text}
17 |
18 |
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/components/PlusIconTextButton/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { RFValue } from 'react-native-responsive-fontsize';
3 | import colors from '../../../assets/styles/colorVariables';
4 |
5 | export default StyleSheet.create({
6 | createNewOfferButtonView: {
7 | bottom: 16,
8 | right: 8,
9 | position: 'absolute',
10 | zIndex: 3,
11 | },
12 | plusButton: {
13 | width: 150,
14 | height: 50,
15 | flexDirection: 'row',
16 | borderRadius: 25,
17 | backgroundColor: colors.primary,
18 | alignItems: 'center',
19 | justifyContent: 'center',
20 | },
21 | plusButtonText: {
22 | color: '#fff',
23 | fontWeight: '700',
24 | fontSize: RFValue(14, 640),
25 | padding: 8,
26 | },
27 | });
28 |
--------------------------------------------------------------------------------
/app/src/components/SelectCategoryForm/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../assets/styles/fontVariable';
3 | import colors from '../../../assets/styles/colorVariables';
4 | const styles = StyleSheet.create({
5 | addCategory: {
6 | backgroundColor: colors.primary,
7 | borderWidth: 1,
8 | borderColor: colors.primary,
9 | padding: 5,
10 | marginTop: 8,
11 | alignSelf: 'flex-start',
12 | borderRadius: 5,
13 | justifyContent: 'center',
14 | alignItems: 'center',
15 | },
16 | addCategoryText: {
17 | ...fonts.body,
18 | color: '#fff',
19 | fontSize: 18,
20 | },
21 | categoryName: {
22 | backgroundColor: colors.secondary,
23 | padding: 5,
24 | elevation: 2,
25 | margin: 5,
26 | borderRadius: 2,
27 | },
28 | categoriesContainer: {
29 | flexDirection: 'row',
30 | flexWrap: 'wrap',
31 | marginTop: 0,
32 | },
33 | });
34 |
35 | export default styles;
36 |
--------------------------------------------------------------------------------
/app/src/components/UI/button/FilterButtons/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../../../assets/styles/fontVariable';
3 | import colors from '../../../../../assets/styles/colorVariables';
4 |
5 | const styles = StyleSheet.create({
6 | contentButtons: {
7 | marginTop: 10,
8 | flexDirection: 'row',
9 | justifyContent: 'space-around',
10 | alignItems: 'center',
11 | alignSelf: 'center',
12 | },
13 | helpFilterButton: {
14 | flex: 1,
15 | borderRadius: 6,
16 | borderWidth: 2,
17 | borderColor: colors.primary,
18 | height: 100,
19 | marginHorizontal: 5,
20 | justifyContent: 'space-around',
21 | },
22 | info: {
23 | alignItems: 'center',
24 | padding: 5,
25 | height: '100%',
26 | justifyContent: 'center',
27 | },
28 | infoPress: {
29 | backgroundColor: colors.primary,
30 | alignItems: 'center',
31 | padding: 5,
32 | height: '100%',
33 | justifyContent: 'center',
34 | },
35 | infoText: {
36 | ...fonts.body,
37 | color: colors.primary,
38 | fontFamily: 'montserrat-semibold',
39 | fontSize: 11,
40 | textAlign: 'center',
41 | },
42 | infoPressText: {
43 | ...fonts.body,
44 | color: colors.light,
45 | fontFamily: 'montserrat-semibold',
46 | fontSize: 11,
47 | textAlign: 'center',
48 | },
49 | });
50 |
51 | export default styles;
52 |
--------------------------------------------------------------------------------
/app/src/components/UI/input/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../../assets/styles/fontVariable';
3 | import colors from '../../../../assets/styles/colorVariables';
4 |
5 | const styles = StyleSheet.create({
6 | input: {
7 | ...fonts.body,
8 | borderWidth: 2,
9 | borderRadius: 5,
10 | padding: 10,
11 | },
12 | validInput: {
13 | borderColor: colors.primary,
14 | },
15 | invalidInput: {
16 | borderColor: colors.danger,
17 | },
18 | label: {
19 | ...fonts.body,
20 | fontFamily: 'montserrat-semibold',
21 | color: colors.primary,
22 | },
23 | });
24 |
25 | export default styles;
26 |
--------------------------------------------------------------------------------
/app/src/components/UI/selectBox/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { CheckBox } from 'react-native-elements';
3 | import styles from './styles';
4 | export default function SelectBox({
5 | setSelectedCategoryArray,
6 | filterCategoryArray,
7 | category,
8 | selectedCategoryArray,
9 | }) {
10 | const [selectedItem, setSelectItem] = useState(
11 | filterCategoryArray.some((categoryId) => categoryId === category._id),
12 | );
13 |
14 | useEffect(() => {
15 | if (selectedItem) {
16 | setSelectedCategoryArray([...selectedCategoryArray, category._id]);
17 | } else {
18 | const removeFilter = filterCategoryArray.filter(
19 | (id) => id !== category._id,
20 | );
21 | setSelectedCategoryArray(removeFilter);
22 | }
23 | }, [selectedItem]);
24 |
25 | return (
26 | <>
27 | setSelectItem(!selectedItem)}
33 | />
34 | >
35 | );
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/components/UI/selectBox/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | const styles = StyleSheet.create({
4 | checkBoxText: {
5 | fontSize: 15,
6 | },
7 | });
8 |
9 | export default styles;
10 |
--------------------------------------------------------------------------------
/app/src/components/atoms/ActivityFlatList/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useCallback } from 'react';
2 | import { View } from 'react-native';
3 | import { FlatList } from 'react-native-gesture-handler';
4 | import { ActivityCard } from '../../organisms/ActivityCard';
5 |
6 | export const ActivityFlatList = ({ list, onViewableItemsChanged }) => {
7 | const renderCards = ({ item }) => (
8 |
9 |
21 |
22 | );
23 |
24 | const memoizedFlatListItem = useCallback(renderCards, [list]);
25 |
26 | return (
27 | item._id}
31 | horizontal
32 | pagingEnabled
33 | snapToInterval={300}
34 | viewabilityConfig={{
35 | viewAreaCoveragePercentThreshold: 300,
36 | }}
37 | initialNumToRender={2}
38 | maxToRenderPerBatch={2}
39 | showsHorizontalScrollIndicator={false}
40 | renderItem={memoizedFlatListItem}
41 | decelerationRate="fast"
42 | onViewableItemsChanged={onViewableItemsChanged?.current}
43 | />
44 | );
45 | };
46 |
--------------------------------------------------------------------------------
/app/src/components/atoms/Chips/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { Pressable, Text } from 'react-native';
3 | import { Icon } from 'react-native-elements';
4 | import colors from '../../../../colors';
5 |
6 | export const Chips = ({
7 | title,
8 | icon,
9 | hiddenIcon = false,
10 | onPress,
11 | elevated = false,
12 | type,
13 | customStyle,
14 | disabled = false,
15 | selected = false,
16 | }) => {
17 | const [isSelected, setIsSelected] = useState(selected);
18 | const chipColor = isSelected ? 'bg-secondary-500 border-0' : 'bg-white';
19 | const elevatedStyle = elevated && 'shadow shadow-black';
20 | const disabledStyle = disabled && 'opacity-30';
21 | const childrenOrder = type == 'input' ? 'flex-row-reverse' : 'flex-row';
22 |
23 | const variantsAction = {
24 | button: () => onPress(),
25 | input: () => onPress(),
26 | filter: () => {
27 | onPress();
28 | setIsSelected(!isSelected);
29 | },
30 | };
31 |
32 | return (
33 |
41 | {(!hiddenIcon || isSelected) && icon && (
42 |
43 | )}
44 | {title}
45 |
46 | );
47 | };
48 |
--------------------------------------------------------------------------------
/app/src/components/atoms/CircleBadge/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { Icon } from 'react-native-elements';
4 |
5 | export const CircleBadge = ({
6 | rank,
7 | badgeIcon,
8 | isHidden = false,
9 | size = 'sm',
10 | }) => {
11 | const iconBackgrounds = {
12 | 1: 'bg-first-rank',
13 | 2: 'bg-second-rank',
14 | 3: 'bg-thirt-rank',
15 | };
16 |
17 | const sizes = {
18 | sm: {
19 | width: 'w-12',
20 | icon: 34,
21 | },
22 | md: {
23 | width: 'w-16',
24 | icon: 48,
25 | },
26 | };
27 |
28 | const selectedSize = sizes[size];
29 |
30 | const selectedIconBackground = isHidden ? 'bg-gray' : iconBackgrounds[rank];
31 | return (
32 |
35 |
41 |
42 | );
43 | };
44 |
--------------------------------------------------------------------------------
/app/src/components/atoms/CircleIconButton/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { TouchableOpacity, View } from 'react-native';
3 | import { Icon } from 'react-native-elements';
4 |
5 | export const CircleIconButton = ({
6 | icon,
7 | onPress,
8 | iconSize = 'base',
9 | color,
10 | }) => {
11 | const iconSizeVariant = {
12 | sm: 16,
13 | base: 20,
14 | lg: 24,
15 | xl: 28,
16 | '2xl': 32,
17 | };
18 |
19 | const buttonColor = color ? color : '';
20 |
21 | return (
22 |
23 |
26 |
27 |
28 |
29 | );
30 | };
31 |
--------------------------------------------------------------------------------
/app/src/components/atoms/Divider/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { styles } from './styles';
4 |
5 | export const Divider = ({ marginHorizontal = 0 }) => {
6 | return (
7 |
10 | );
11 | };
12 |
--------------------------------------------------------------------------------
/app/src/components/atoms/Divider/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { colors } from 'react-native-elements';
3 |
4 | export const styles = StyleSheet.create({
5 | divider: {
6 | borderBottomColor: colors.dark,
7 | borderBottomWidth: StyleSheet.hairlineWidth,
8 | marginVertical: 8,
9 | opacity: 0.3,
10 | },
11 | });
12 |
--------------------------------------------------------------------------------
/app/src/components/atoms/IconButton/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Icon } from 'react-native-elements';
3 | import { TouchableOpacity } from 'react-native-gesture-handler';
4 | import colors from '../../../../assets/styles/colorVariables';
5 | import { styles } from './styles';
6 |
7 | export const IconButton = ({
8 | icon,
9 | onPress,
10 | theme = 'light',
11 | iconSize = 24,
12 | customStyle,
13 | }) => {
14 | return (
15 |
19 |
20 |
21 | );
22 | };
23 |
--------------------------------------------------------------------------------
/app/src/components/atoms/IconButton/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { RFValue } from 'react-native-responsive-fontsize';
3 |
4 | export const styles = StyleSheet.create({
5 | drawerButtonContainer: {
6 | padding: RFValue(8, 640),
7 | marginRight: RFValue(8, 640),
8 | },
9 | });
10 |
--------------------------------------------------------------------------------
/app/src/components/atoms/InformativeField/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text, View } from 'react-native';
3 | import { Icon } from 'react-native-elements';
4 | import colors from '../../../../colors';
5 |
6 | export const InformativeField = ({
7 | type = 'informative',
8 | title = 'Aguardando contato',
9 | text = '',
10 | }) => {
11 | const variants = {
12 | informative: {
13 | icon: 'info',
14 | color: 'bg-new_background',
15 | },
16 | error: {
17 | icon: 'cancel',
18 | color: 'bg-danger-200',
19 | },
20 | warning: {
21 | icon: 'error',
22 | color: 'bg-secondary-500',
23 | },
24 | };
25 | return (
26 |
29 |
30 |
35 |
36 | {title}
37 |
38 | {text}
39 |
40 |
41 |
42 |
43 | );
44 | };
45 |
--------------------------------------------------------------------------------
/app/src/components/atoms/RoundedFullButton/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text, TouchableOpacity } from 'react-native';
3 |
4 | export const RoundedFullButton = ({
5 | text,
6 | onPress,
7 | variant = 'primary',
8 | disabled = false,
9 | width,
10 | }) => {
11 | const variantStyles = {
12 | primary: 'bg-primary text-white',
13 | secondary: 'bg-white text-primary border border-1 border-primary',
14 | danger: 'bg-danger text-white',
15 | warning: 'bg-warning text-black',
16 | };
17 |
18 | const selectedVariant = variantStyles[variant];
19 |
20 | return (
21 |
22 |
25 | {text}
26 |
27 |
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/app/src/components/atoms/SearchBar/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { TextInput, View } from 'react-native';
3 | import { Icon } from 'react-native-elements';
4 | import { IconButton } from '../IconButton';
5 | import { styles } from './styles';
6 | export const SearchBar = ({ value, setValue, placeholder }) => {
7 | return (
8 |
9 |
15 | setValue(text)}
20 | />
21 |
22 | {!!value && (
23 | setValue('')}
29 | />
30 | )}
31 |
32 |
33 | );
34 | };
35 |
--------------------------------------------------------------------------------
/app/src/components/atoms/SearchBar/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { RFValue } from 'react-native-responsive-fontsize';
3 | import fonts from '../../../../assets/styles/fontVariable';
4 |
5 | export const styles = StyleSheet.create({
6 | searchBarContainer: {
7 | borderRadius: RFValue(32, 640),
8 | width: '100%',
9 | borderWidth: 0.5,
10 | borderColor: '#3535354d',
11 | paddingHorizontal: 12,
12 | paddingVertical: 8,
13 | backgroundColor: 'white',
14 | flexDirection: 'row',
15 | alignItems: 'center',
16 | maxHeight: RFValue(40, 640),
17 | marginBottom: RFValue(24, 640),
18 | },
19 | input: {
20 | marginLeft: 4,
21 | ...fonts.body,
22 | width: '80%',
23 | },
24 | buttonContainer: {
25 | minWidth: '5%',
26 | marginLeft: 'auto',
27 | },
28 | iconButtonStyle: {
29 | padding: 0,
30 | },
31 | });
32 |
--------------------------------------------------------------------------------
/app/src/components/atoms/SliderDescription/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text } from 'react-native';
3 |
4 | export const SliderDescription = ({ description }) => {
5 | return (
6 |
7 | {description}
8 |
9 | );
10 | };
11 |
--------------------------------------------------------------------------------
/app/src/components/atoms/SliderTitle/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text } from 'react-native';
3 |
4 | export const SliderTitle = ({ title }) => {
5 | return (
6 |
7 | {title}
8 |
9 | );
10 | };
11 |
--------------------------------------------------------------------------------
/app/src/components/atoms/TextButton/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text, TouchableOpacity } from 'react-native';
3 |
4 | export const TextButton = ({ text, onPress, className }) => {
5 | return (
6 |
7 |
10 | {text}
11 |
12 |
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/app/src/components/atoms/TextSwitchButton/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text, TouchableOpacity } from 'react-native';
3 |
4 | export const TextSwitchButton = ({ text, isSelected, onPress }) => {
5 | const style = {
6 | container: isSelected ? 'bg-white' : 'bg-transparent',
7 | text: isSelected
8 | ? ' text-primary font-ms-semibold'
9 | : 'text-black font-ms-regular',
10 | };
11 | return (
12 |
16 | {text}
17 |
18 | );
19 | };
20 |
--------------------------------------------------------------------------------
/app/src/components/atoms/ViewWithDivider/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 |
4 | export const ViewWithDivider = ({ children }) => {
5 | return {children};
6 | };
7 |
--------------------------------------------------------------------------------
/app/src/components/modals/BaseModal/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Modal, View } from 'react-native';
3 | import { FloatingIconButton } from '../../molecules/FloatingIconButton';
4 |
5 | export const BaseModal = ({
6 | isVisible,
7 | animationType = 'fade',
8 | children,
9 | onCloseModal,
10 | background = 'bg-white',
11 | }) => {
12 | return (
13 |
19 |
20 |
23 |
27 | {children}
28 |
29 |
30 |
31 | );
32 | };
33 |
--------------------------------------------------------------------------------
/app/src/components/modals/category/categoryDescription/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../../../assets/styles/fontVariable';
3 |
4 | const styles = StyleSheet.create({
5 | modalContainer: {
6 | width: '100%',
7 | height: '100%',
8 | backgroundColor: 'rgba(0,0,0,0.3)',
9 | },
10 | modalContent: {
11 | paddingTop: 50,
12 | backgroundColor: '#fff',
13 | padding: 20,
14 | marginBottom: 50,
15 | borderRadius: 20,
16 | top: '2.5%',
17 | },
18 | title: {
19 | ...fonts.title,
20 | fontSize: 20,
21 | alignSelf: 'center',
22 | marginBottom: 10,
23 | fontFamily: 'montserrat-semibold',
24 | },
25 | description: {
26 | ...fonts.body,
27 | marginBottom: 10,
28 | },
29 | icon: {
30 | top: '5.5%',
31 | right: 20,
32 | position: 'absolute',
33 | zIndex: 5,
34 | },
35 | });
36 |
37 | export default styles;
38 |
--------------------------------------------------------------------------------
/app/src/components/modals/conditionTermsModal/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Modal, TouchableOpacity, ScrollView, View } from 'react-native';
3 | import { Icon } from 'react-native-elements';
4 | import colors from '../../../../assets/styles/colorVariables';
5 | import styles from './style';
6 | import Markdown from 'react-native-markdown-display';
7 | import terms from '../../../docs/terms';
8 |
9 | export default function TermsModal({ visible, setVisible }) {
10 | return (
11 | setVisible(false)}
14 | animationType="slide"
15 | >
16 | setVisible(false)}
19 | >
20 |
26 |
27 |
31 |
32 | {terms}
33 |
34 |
35 |
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/components/modals/conditionTermsModal/style.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../../assets/styles/fontVariable';
3 | const styles = StyleSheet.create({
4 | closeButton: {
5 | position: 'absolute',
6 | zIndex: 5,
7 | right: 15,
8 | top: 15,
9 | },
10 | privacyLink: {
11 | marginVertical: 20,
12 | width: 240,
13 | },
14 | privacyText: {
15 | ...fonts.subtitle,
16 | borderBottomWidth: StyleSheet.hairlineWidth,
17 | borderBottomColor: '#000',
18 | fontSize: 16,
19 | },
20 | });
21 | export default styles;
22 |
--------------------------------------------------------------------------------
/app/src/components/modals/newHelpModal/failure/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Modal, View, Text } from 'react-native';
3 | import Button from '../../../UI/button';
4 | import styles from './styles';
5 |
6 | export default function NewHelpModal({ visible, onOkPressed, errorMessage }) {
7 | return (
8 |
9 |
15 |
16 |
17 | {errorMessage ||
18 | 'Houve algum problema com sua solicitação. Tente mais tarde.'}
19 |
20 |
21 |
27 |
28 |
29 |
30 | );
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/components/modals/newHelpModal/failure/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Dimensions } from 'react-native';
2 | import colors from '../../../../../assets/styles/colorVariables';
3 | import fonts from '../../../../../assets/styles/fontVariable';
4 | const { height: screen_height } = Dimensions.get('window');
5 |
6 | const styles = StyleSheet.create({
7 | modalContainer: {
8 | flex: 1,
9 | justifyContent: 'center',
10 | alignItems: 'center',
11 | },
12 | modal: {
13 | justifyContent: 'space-around',
14 | alignItems: 'center',
15 | },
16 | modalView: {
17 | backgroundColor: colors.light,
18 | padding: 20,
19 | borderRadius: 10,
20 | justifyContent: 'space-around',
21 | alignItems: 'center',
22 | width: '80%',
23 | elevation: 5,
24 | alignSelf: 'center',
25 | marginTop: screen_height * 0.3,
26 | },
27 | modalText: {
28 | ...fonts.subtitle,
29 | fontSize: 20,
30 | textAlign: 'center',
31 | marginVertical: 30,
32 | },
33 | backdrop: {
34 | backgroundColor: '#35353590',
35 | },
36 | });
37 |
38 | export default styles;
39 |
--------------------------------------------------------------------------------
/app/src/components/modals/newHelpModal/success/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Modal, View, Text } from 'react-native';
3 | import Button from '../../../UI/button';
4 | import styles from './styles';
5 |
6 | export default function NewHelpModal({ visible, onOkPressed, message }) {
7 | return (
8 |
9 |
15 |
16 | {message}
17 |
18 |
19 |
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/components/modals/newHelpModal/success/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Dimensions } from 'react-native';
2 | import colors from '../../../../../assets/styles/colorVariables';
3 | import fonts from '../../../../../assets/styles/fontVariable';
4 | const { height: screen_height } = Dimensions.get('window');
5 |
6 | const styles = StyleSheet.create({
7 | modalContainer: {
8 | flex: 1,
9 | justifyContent: 'center',
10 | alignItems: 'center',
11 | },
12 | modal: {
13 | justifyContent: 'space-around',
14 | alignItems: 'center',
15 | },
16 | modalView: {
17 | backgroundColor: colors.light,
18 | padding: 20,
19 | borderRadius: 10,
20 | justifyContent: 'space-around',
21 | alignItems: 'center',
22 | width: '80%',
23 | elevation: 5,
24 | alignSelf: 'center',
25 | marginTop: screen_height * 0.3,
26 | },
27 | modalText: {
28 | ...fonts.subtitle,
29 | fontSize: 20,
30 | textAlign: 'center',
31 | marginVertical: 30,
32 | },
33 | backdrop: {
34 | backgroundColor: '#35353590',
35 | },
36 | });
37 |
38 | export default styles;
39 |
--------------------------------------------------------------------------------
/app/src/components/modals/privacyPolicyModal/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Modal, TouchableOpacity, ScrollView } from 'react-native';
3 | import { Icon } from 'react-native-elements';
4 | import styles from './style';
5 | import Markdown from 'react-native-markdown-display';
6 | import privacy from './privacy';
7 | import colors from '../../../../assets/styles/colorVariables';
8 |
9 | export default function PrivacyPolicyModal({ visible, setVisible }) {
10 | return (
11 | setVisible(false)}
14 | animationType="slide"
15 | >
16 | setVisible(false)}
19 | >
20 |
26 |
27 |
35 | {privacy}
36 |
37 |
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/components/modals/privacyPolicyModal/style.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../../assets/styles/fontVariable';
3 | const styles = StyleSheet.create({
4 | closeButton: {
5 | position: 'absolute',
6 | zIndex: 5,
7 | right: 15,
8 | top: 15,
9 | },
10 | privacyLink: {
11 | marginVertical: 20,
12 | width: 240,
13 | },
14 | privacyText: {
15 | ...fonts.subtitle,
16 | borderBottomWidth: StyleSheet.hairlineWidth,
17 | borderBottomColor: '#000',
18 | fontSize: 16,
19 | },
20 | });
21 | export default styles;
22 |
--------------------------------------------------------------------------------
/app/src/components/molecules/Badge/index.jsx:
--------------------------------------------------------------------------------
1 | import { View, Text } from 'react-native';
2 | import React from 'react';
3 |
4 | export default function Badge({ title, size = 'small' }) {
5 | const viewSize = {
6 | small: 'px-2 py-1 m-0.5',
7 | medium: 'px-3 py-1.5 m-0.5',
8 | large: 'px-3.5 py-2 m-1',
9 | };
10 |
11 | const textSize = {
12 | small: 'text-xss',
13 | medium: 'text-xs',
14 | large: 'text-sm',
15 | };
16 |
17 | return (
18 |
19 |
20 | {title}
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/components/molecules/BadgeCard/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text, View } from 'react-native';
3 | import { CircleBadge } from '../../atoms/CircleBadge';
4 |
5 | export const BadgeCard = ({
6 | badgeTemplate,
7 | showLevel = false,
8 | hidden = false,
9 | }) => {
10 | const getTitle = () => {
11 | return `${badgeTemplate.name.split(' ')[0]} ${badgeTemplate.rank}`;
12 | };
13 |
14 | const title = showLevel ? `Nível ${badgeTemplate.rank}` : getTitle();
15 |
16 | const hiddenBadgeInfo = {
17 | iconName: 'help',
18 | description: '-',
19 | neededValue: '?',
20 | rank: badgeTemplate.rank,
21 | };
22 | const badgeInfo = hidden ? hiddenBadgeInfo : badgeTemplate;
23 |
24 | return (
25 |
26 |
31 |
32 |
36 | {title}
37 |
38 |
42 | {badgeInfo.description}
43 |
44 |
45 |
46 | {badgeInfo.neededValue}/{badgeInfo.neededValue}
47 |
48 |
49 | );
50 | };
51 |
--------------------------------------------------------------------------------
/app/src/components/molecules/CategoriesList/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Badge from '../Badge';
3 | import { View } from 'react-native';
4 |
5 | export const CategoriesList = ({
6 | categories,
7 | size = 'medium',
8 | customStyle = '',
9 | }) => {
10 | const align = categories?.length >= 3 ? 'justify-center' : '';
11 | return (
12 |
13 | {categories?.map((category) => (
14 |
15 | ))}
16 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/app/src/components/molecules/CustomDrawerItem/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text, TouchableOpacity } from 'react-native';
3 | import { styles } from './styles';
4 | export const CustomDrawerItem = ({ isSelected, icon, label, onPress }) => {
5 | return (
6 |
14 | {icon()}
15 | {label}
16 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/app/src/components/molecules/CustomDrawerItem/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { RFValue } from 'react-native-responsive-fontsize';
3 | import colors from '../../../../assets/styles/colorVariables';
4 | import fonts from '../../../../assets/styles/fontVariable';
5 |
6 | const commonContainerStyle = {
7 | width: '100%',
8 | flexDirection: 'row',
9 | marginVertical: RFValue(4, 640),
10 | maxWidth: RFValue(240, 640),
11 | overflow: 'hidden',
12 | paddingVertical: RFValue(8, 640),
13 | };
14 | export const styles = StyleSheet.create({
15 | drawerItemContainer: {
16 | marginLeft: RFValue(16, 640),
17 | ...commonContainerStyle,
18 | },
19 | selectedDrawerItemContainer: {
20 | ...commonContainerStyle,
21 | backgroundColor: colors.primaryLowOpacity,
22 | paddingHorizontal: RFValue(4, 640),
23 | marginLeft: RFValue(12, 640),
24 | borderRadius: 4,
25 | },
26 | label: {
27 | ...fonts.body,
28 | marginLeft: RFValue(16, 640),
29 | },
30 | });
31 |
--------------------------------------------------------------------------------
/app/src/components/molecules/CustomHeader/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text, View } from 'react-native';
3 | import { IconButton } from '../../atoms/IconButton';
4 | import { styles } from './styles';
5 | import { RoundedFullButton } from '../../atoms/RoundedFullButton';
6 |
7 | export const CustomHeader = ({ title, navigation, iconType, buttonProps }) => {
8 | const isDrawerButton = iconType == 'drawer';
9 | const icon = isDrawerButton
10 | ? {
11 | icon: 'menu',
12 | theme: 'light',
13 | customStyle: styles.customMenuStyle,
14 | }
15 | : {
16 | icon: 'arrow-back',
17 | theme: 'dark',
18 | };
19 |
20 | const onPress = isDrawerButton
21 | ? () => navigation.openDrawer()
22 | : () => navigation.goBack();
23 |
24 | return (
25 |
26 |
27 |
28 | {title}
29 | {buttonProps?.visible && (
30 |
31 |
32 |
33 | )}
34 |
35 |
36 | );
37 | };
38 |
--------------------------------------------------------------------------------
/app/src/components/molecules/CustomHeader/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import { RFValue } from 'react-native-responsive-fontsize';
4 | import colors from '../../../../assets/styles/colorVariables';
5 | import fonts from '../../../../assets/styles/fontVariable';
6 |
7 | export const styles = StyleSheet.create({
8 | header: {
9 | width: '100%',
10 | height: RFValue(48, 640),
11 | justifyContent: 'center',
12 | backgroundColor: 'transparent',
13 | },
14 | content: {
15 | flexDirection: 'row',
16 | alignItems: 'center',
17 | },
18 | title: {
19 | ...fonts.subtitle,
20 | color: colors.dark,
21 | fontFamily: 'montserrat-bold',
22 | },
23 | customMenuStyle: {
24 | backgroundColor: colors.primary,
25 | padding: RFValue(4, 640),
26 | marginRight: RFValue(8, 640),
27 | marginLeft: RFValue(8, 640),
28 | borderRadius: 100,
29 | },
30 | });
31 |
--------------------------------------------------------------------------------
/app/src/components/molecules/DefaultButtonWithBagdes/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text, View } from 'react-native';
3 | import { Badge } from 'react-native-elements';
4 | import { DefaultButton } from '../../atoms/DefaultButton';
5 | import styles from '../../../../assets/styles/helpDescription';
6 |
7 | export const DefaultButtonWithBadges = ({
8 | title,
9 | onPress,
10 | badgeValue,
11 | marginTop = '',
12 | disabled,
13 | }) => {
14 | return (
15 |
16 |
21 | {badgeValue}}
23 | badgeStyle={[styles.badgeStyle, styles.smallBadge]}
24 | containerStyle={styles.containerBadge}
25 | />
26 |
27 | );
28 | };
29 |
--------------------------------------------------------------------------------
/app/src/components/molecules/DescriptionBox/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text, View } from 'react-native';
3 |
4 | export const DescriptionBox = ({ title, description, maxLines = 4 }) => {
5 | return (
6 |
7 |
8 | {title}
9 |
10 |
11 |
15 | {description}
16 |
17 |
18 |
19 | );
20 | };
21 |
--------------------------------------------------------------------------------
/app/src/components/molecules/FloatingIconButton/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { CircleIconButton } from '../../atoms/CircleIconButton';
4 |
5 | export const FloatingIconButton = ({
6 | position = 'left',
7 | iconName,
8 | onPress,
9 | customTop = null,
10 | iconSize,
11 | color,
12 | }) => {
13 | const convertPosition = `${position}-2`;
14 | const positionY = customTop || 'top-2';
15 | return (
16 |
17 |
23 |
24 | );
25 | };
26 |
--------------------------------------------------------------------------------
/app/src/components/molecules/FollowCount/index.jsx:
--------------------------------------------------------------------------------
1 | import { useNavigation } from '@react-navigation/native';
2 | import React from 'react';
3 | import { TouchableOpacity, Text } from 'react-native';
4 |
5 | export const FollowCount = ({ count, type, userId }) => {
6 | const navigation = useNavigation();
7 | const types = {
8 | following: 'seguindo',
9 | followers: 'seguidores',
10 | };
11 |
12 | const handlePress = () => {
13 | navigation.navigate('userList', { userId: userId, followType: type });
14 | };
15 |
16 | return (
17 |
18 | {count}
19 | {` ${types[type]}`}
20 |
21 | );
22 | };
23 |
--------------------------------------------------------------------------------
/app/src/components/molecules/ProfilePhoto/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Image } from 'react-native';
3 |
4 | export const ProfilePhoto = ({ base64, size, className }) => {
5 | const imageSource = base64
6 | ? {
7 | uri: `data:image/png;base64,${base64}`,
8 | }
9 | : require('../../../../assets/images/noImage.png');
10 |
11 | const sizes = {
12 | xs: 'w-10 h-10',
13 | sm: 'w-12 h-12',
14 | md: 'w-16 h-16',
15 | lg: 'w-24 h-24',
16 | };
17 | const selectedSize = sizes[size];
18 | return (
19 |
23 | );
24 | };
25 |
--------------------------------------------------------------------------------
/app/src/components/molecules/TextSwitch/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import { TextSwitchButton } from '../../atoms/TextSwitchButton';
4 |
5 | export const TextSwitch = ({
6 | option1,
7 | option2,
8 | selectedOption,
9 | setSelectedOption,
10 | darker = false,
11 | }) => {
12 | const background = darker ? 'bg-gray' : 'bg-background';
13 | return (
14 |
15 | setSelectedOption(0)}
18 | isSelected={selectedOption == 0}
19 | />
20 | setSelectedOption(1)}
23 | isSelected={selectedOption == 1}
24 | />
25 |
26 | );
27 | };
28 |
--------------------------------------------------------------------------------
/app/src/components/molecules/TimelineItem/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Image, Text, View } from 'react-native';
3 | import { Divider } from '../../atoms/Divider';
4 |
5 | export const TimelineItem = ({ data, hasImage }) => {
6 | return (
7 |
8 |
9 | {hasImage && (
10 |
16 | )}
17 |
18 |
19 | {data.title}
20 |
21 |
22 | {data.description}
23 |
24 |
25 |
26 |
27 |
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/app/src/components/molecules/TutorialCard/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Image, Pressable, Text, View } from 'react-native';
3 | import colors from '../../../../colors';
4 |
5 | export const TutorialCard = ({
6 | title,
7 | description,
8 | onPress,
9 | margin = '',
10 | leftAligment = true,
11 | }) => {
12 | const flexRow = leftAligment ? 'flex-row' : 'flex-row-reverse';
13 | return (
14 |
21 |
26 |
27 |
28 | {title}
29 |
30 |
31 | {description}
32 |
33 |
34 |
35 | );
36 | };
37 |
--------------------------------------------------------------------------------
/app/src/components/molecules/UserCard/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { Text, View } from 'react-native';
3 | import { Icon } from 'react-native-elements';
4 | import { TouchableOpacity } from 'react-native-gesture-handler';
5 | import { styles } from './styles';
6 | import shortenName from '../../../utils/shortenName';
7 | import { ProfilePhoto } from '../ProfilePhoto';
8 | import { UserContext } from '../../../store/contexts/userContext';
9 |
10 | export const UserCard = ({ name, email, photo }) => {
11 | const { logout } = useContext(UserContext);
12 | const handleLogout = async () => {
13 | await logout();
14 | };
15 |
16 | return (
17 |
18 |
19 |
20 |
21 |
22 | {shortenName(name)}
23 |
24 |
25 | {email}
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | );
34 | };
35 |
--------------------------------------------------------------------------------
/app/src/components/molecules/UserCard/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { RFValue } from 'react-native-responsive-fontsize';
3 | import fonts from '../../../../assets/styles/fontVariable';
4 |
5 | export const styles = StyleSheet.create({
6 | userCardContainer: {
7 | marginBottom: RFValue(16, 640),
8 | flexDirection: 'row',
9 | justifyContent: 'space-between',
10 | alignItems: 'center',
11 | paddingHorizontal: RFValue(12, 640),
12 | },
13 | userInfo: {
14 | flexDirection: 'row',
15 | maxWidth: RFValue(160, 640),
16 | },
17 | userName: {
18 | ...fonts.body,
19 | fontFamily: 'montserrat-semibold',
20 | },
21 | userEmail: {
22 | ...fonts.small,
23 | },
24 | });
25 |
--------------------------------------------------------------------------------
/app/src/components/molecules/UserListItem/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { RFValue } from 'react-native-responsive-fontsize';
3 | import fonts from '../../../../assets/styles/fontVariable';
4 |
5 | export const styles = StyleSheet.create({
6 | container: {
7 | flexDirection: 'row',
8 | alignItems: 'center',
9 | paddingHorizontal: 8,
10 | paddingVertical: 16,
11 | },
12 | image: {
13 | width: RFValue(54, 640),
14 | height: RFValue(54, 640),
15 | borderRadius: 24,
16 | },
17 | userInfo: {
18 | marginRight: 'auto',
19 | marginLeft: 8,
20 | },
21 | userName: {
22 | ...fonts.subtitle,
23 | fontFamily: 'montserrat-semibold',
24 | },
25 | });
26 |
--------------------------------------------------------------------------------
/app/src/components/organisms/ActivitiesList/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ActivityCard } from '../ActivityCard';
3 | import { NotFound } from '../NotFound';
4 | import { HorizontalList } from '../HorizontalList';
5 |
6 | export const ActivitiesList = ({ activities, userId }) => {
7 | const activitiesTypes = Object.keys(activities);
8 | const activitiesCount = activitiesTypes.reduce((currentValue, newValue) => {
9 | return currentValue + activities[newValue].length;
10 | }, 0);
11 | return activitiesCount > 0 ? (
12 |
13 | {Object.keys(activities).map((activitieName) =>
14 | activities[activitieName].map((activitie, i) => (
15 |
31 | )),
32 | )}
33 |
34 | ) : (
35 |
36 | );
37 | };
38 |
--------------------------------------------------------------------------------
/app/src/components/organisms/AddressForm/constructor.js:
--------------------------------------------------------------------------------
1 | import * as Yup from 'yup';
2 |
3 | export const initialValues = (address) => ({
4 | cep: address?.cep || '',
5 | city: address?.city || '',
6 | complement: address?.complement || '',
7 | state: address?.state || '',
8 | number: address?.number.toString() || '',
9 | });
10 |
11 | export const schema = Yup.object().shape({
12 | cep: Yup.string()
13 | .required('Nome é obrigatório')
14 | .length(8, 'CEP deve possuir 8 caracteres'),
15 | city: Yup.string().required('Cidade é obrigatória'),
16 | complement: Yup.string(),
17 | state: Yup.string()
18 | .required('Estado é obrigatório')
19 | .length(2, 'Utilize apenas a sigla do estado'),
20 | number: Yup.string().required('Número é obrigatório'),
21 | });
22 |
--------------------------------------------------------------------------------
/app/src/components/organisms/AnimatedMap/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import CustomMap from '../../CustomMap';
3 | import { ActivityMarker } from '../../molecules/ActivityMarker';
4 | import navigateToDescription from '../../../utils/navigateToDescription';
5 | import { UserContext } from '../../../store/contexts/userContext';
6 | import { ActivityBottomSheetContext } from '../../../store/contexts/activityBottomSheetContext';
7 |
8 | export function AnimatedMap({
9 | list,
10 | navigation,
11 | focusedCardLocation,
12 | visibleItemData,
13 | }) {
14 | const { user, userPosition } = useContext(UserContext);
15 | const { handleShowModal } = useContext(ActivityBottomSheetContext);
16 | return (
17 |
21 | {list.map((activity) => {
22 | const focused = visibleItemData?._id == activity._id;
23 | return (
24 |
30 | navigateToDescription(
31 | user,
32 | navigation,
33 | activity._id,
34 | activity.ownerId,
35 | activity.type,
36 | handleShowModal,
37 | )
38 | }
39 | focused={focused}
40 | />
41 | );
42 | })}
43 |
44 | );
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/components/organisms/BadgesList/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { NotFound } from '../NotFound';
3 | import { HorizontalList } from '../HorizontalList';
4 | import { useNavigation } from '@react-navigation/native';
5 | import { BadgeCard } from '../../molecules/BadgeCard';
6 |
7 | export const BadgesList = ({ badges, userId }) => {
8 | const navigation = useNavigation();
9 |
10 | const handleOpenBadgeScreen = () => {
11 | navigation.navigate('badges', { userId });
12 | };
13 |
14 | return badges.length > 0 ? (
15 |
20 | {badges.map((badge) => (
21 |
22 | ))}
23 |
24 | ) : (
25 |
26 | );
27 | };
28 |
--------------------------------------------------------------------------------
/app/src/components/organisms/CustomDrawerList/styles.js:
--------------------------------------------------------------------------------
1 | import { Dimensions, StyleSheet } from 'react-native';
2 |
3 | export const styles = StyleSheet.create({
4 | drawerListContainer: {
5 | height: Dimensions.get('screen').height * 0.5,
6 | },
7 | });
8 |
--------------------------------------------------------------------------------
/app/src/components/organisms/DefaultTimeline/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Timeline from 'react-native-timeline-flatlist';
3 | import colors from '../../../../colors';
4 | import { TimelineItem } from '../../molecules/TimelineItem';
5 |
6 | export const DefaultTimeline = ({
7 | data,
8 | lineWidth = 4,
9 | hasImage = false,
10 | useIcon = false,
11 | }) => {
12 | const renderContent = (data, sectionID) => (
13 |
14 | );
15 |
16 | return (
17 |
35 | );
36 | };
37 |
--------------------------------------------------------------------------------
/app/src/components/organisms/HorizontalList/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Pressable, ScrollView, Text, View } from 'react-native';
3 |
4 | export const HorizontalList = ({
5 | children,
6 | className = '',
7 | showMoreButton = false,
8 | onPressMoreButton,
9 | }) => {
10 | const margin = showMoreButton ? 'mt-8' : '';
11 | return (
12 |
13 | {showMoreButton && (
14 |
19 |
20 | VER TUDO
21 |
22 |
23 | )}
24 |
29 | {children}
30 |
31 |
32 | );
33 | };
34 |
--------------------------------------------------------------------------------
/app/src/components/organisms/NotFound/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import NotFoundImage from '../../../../assets/images/notFoundImage';
3 | import { Text, View } from 'react-native';
4 |
5 | export const NotFound = ({
6 | title = 'Sem resultados',
7 | body,
8 | size = 'regular',
9 | }) => {
10 | const sizeOptions = {
11 | image: {
12 | width: {
13 | small: '100',
14 | regular: '180',
15 | large: '300',
16 | },
17 | height: {
18 | small: '100',
19 | regular: '180',
20 | large: '300',
21 | },
22 | },
23 | title: {
24 | small: 'text-base',
25 | regular: 'text-lg ',
26 | large: 'text-xl',
27 | },
28 | body: {
29 | small: 'text-sm',
30 | regular: 'text-base ',
31 | large: 'text-lg',
32 | },
33 | };
34 |
35 | return (
36 |
37 |
41 |
44 | {title}
45 |
46 |
47 | {body}
48 |
49 |
50 | );
51 | };
52 |
--------------------------------------------------------------------------------
/app/src/components/organisms/SliderModal/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Modal, Pressable, Text } from 'react-native';
3 | import Onboarding from 'react-native-onboarding-swiper';
4 |
5 | export const SliderModal = ({ pages, visible, closeModal }) => {
6 | const textButton = ({ onPress, nextLabel, skipLabel }) => (
7 |
8 |
9 | {nextLabel || skipLabel}
10 |
11 |
12 | );
13 |
14 | return (
15 |
16 |
25 | textButton({ nextLabel: 'Finalizar', ...props })
26 | }
27 | />
28 |
29 | );
30 | };
31 |
--------------------------------------------------------------------------------
/app/src/components/profileList/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View, Pressable } from 'react-native';
3 | import styles from './styles';
4 | import { UserListItem } from '../molecules/UserListItem';
5 | import { Divider } from '../atoms/Divider';
6 | import { useNavigation } from '@react-navigation/native';
7 |
8 | export default function ProfileList({ usersProfile, filterList = false }) {
9 | const navigation = useNavigation();
10 |
11 | const filteredUsers = filterList
12 | ? usersProfile?.filter((user) => user.cpf)
13 | : usersProfile;
14 |
15 | const handlenavigate = (profile) => {
16 | navigation.navigate('socialUserProfile', {
17 | userId: profile.userId,
18 | });
19 | };
20 |
21 | return (
22 |
23 | {filteredUsers?.map((profile, i) => (
24 | handlenavigate(profile)}
28 | >
29 |
30 | {i != filteredUsers.length - 1 && }
31 |
32 | ))}
33 |
34 | );
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/components/profileList/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | const styles = StyleSheet.create({
3 | userList: {
4 | borderRadius: 16,
5 | backgroundColor: 'white',
6 | },
7 | });
8 |
9 | export default styles;
10 |
--------------------------------------------------------------------------------
/app/src/components/templates/BordedScreenLayout/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text, View } from 'react-native';
3 | import { ProfilePhoto } from '../../molecules/ProfilePhoto';
4 |
5 | export function BordedScreenLayout({
6 | children,
7 | size = 'md',
8 | additionalStyles,
9 | photo,
10 | displayName,
11 | }) {
12 | const screenOptions = {
13 | sm: 'mt-2',
14 | md: 'mt-10',
15 | lg: 'mt-14',
16 | };
17 | return (
18 |
21 | {photo && (
22 |
27 | )}
28 | {displayName && (
29 |
33 | {displayName}
34 |
35 | )}
36 | {children}
37 |
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/components/templates/CustomDrawerContent/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { DrawerContentScrollView } from '@react-navigation/drawer';
3 | import { useContext } from 'react';
4 | import { Image, Text, View } from 'react-native';
5 | import { UserContext } from '../../../store/contexts/userContext';
6 | import CustomDrawerItemList from '../../organisms/CustomDrawerList/';
7 | import styles from './styles';
8 | import { UserCard } from '../../molecules/UserCard';
9 | import { Divider } from '../../atoms/Divider';
10 |
11 | export function CustomDrawerContent(props) {
12 | const { user } = useContext(UserContext);
13 | return (
14 |
18 |
19 |
20 | Mia Ajuda
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/components/templates/CustomDrawerContent/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { RFValue } from 'react-native-responsive-fontsize';
3 | import colors from '../../../../assets/styles/colorVariables';
4 | import fonts from '../../../../assets/styles/fontVariable';
5 |
6 | const styles = StyleSheet.create({
7 | drawer: {
8 | flex: 1,
9 | justifyContent: 'space-between',
10 | },
11 | header: {
12 | flexDirection: 'row',
13 | justifyContent: 'center',
14 | alignItems: 'center',
15 | },
16 | headerText: {
17 | ...fonts.title,
18 | width: RFValue(90, 640),
19 | marginLeft: RFValue(24, 640),
20 | fontFamily: 'montserrat-bold',
21 | color: colors.primary,
22 | fontSize: RFValue(24, 640),
23 | },
24 | footer: {
25 | marginTop: 'auto',
26 | },
27 | });
28 |
29 | export default styles;
30 |
--------------------------------------------------------------------------------
/app/src/config/authmiaajuda-firebase-example.json:
--------------------------------------------------------------------------------
1 | {
2 | "apiKey": "",
3 | "authDomain": "",
4 | "projectId": "",
5 | "storageBucket": "",
6 | "messagingSenderId": "",
7 | "appId": ""
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/config/envVariables.js:
--------------------------------------------------------------------------------
1 | import Constants from 'expo-constants';
2 | import { IP_ADDRESS, HOMOLOG_API } from '@env';
3 |
4 | const prodUrl = 'http://164.41.92.25:8000/';
5 | const homologUrl = `https://${HOMOLOG_API}/`;
6 | const devUrl = `http://${IP_ADDRESS}:8000/`;
7 |
8 | const ENV = {
9 | dev: {
10 | development: true,
11 | socketUrl: devUrl,
12 | apiUrl: devUrl + 'api',
13 | },
14 | staging: {
15 | staging: true,
16 | socketUrl: homologUrl,
17 | apiUrl: homologUrl + 'api',
18 | },
19 | prod: {
20 | production: true,
21 | socketUrl: prodUrl,
22 | apiUrl: prodUrl + 'api',
23 | },
24 | };
25 |
26 | function getEnvVars(env = '') {
27 | if (env === null || env === undefined || env === '') return ENV.dev;
28 | if (env.indexOf('dev') !== -1) return ENV.dev;
29 | if (env.indexOf('prod') !== -1) return ENV.prod;
30 | if (env.indexOf('staging') !== -1) return ENV.staging;
31 | if (env.startsWith('pr-')) return ENV.staging;
32 | }
33 |
34 | export default getEnvVars(Constants.manifest.releaseChannel);
35 |
--------------------------------------------------------------------------------
/app/src/docs/FAQ/EmergencyNumbers.js:
--------------------------------------------------------------------------------
1 | const emergencyNumbers = [
2 | { id: '1', number: '100', description: 'Disque Direitos Humanos' },
3 | { id: '2', number: '156', description: 'Governo no Distrito Federal' },
4 | {
5 | id: '3',
6 | number: '180',
7 | description: 'Delegacias especializadas de atendimento à mulher',
8 | },
9 | { id: '4', number: '181', description: 'Disque Denúncia (Geral)' },
10 | { id: '5', number: '190', description: 'Polícia Militar' },
11 | { id: '6', number: '191', description: 'Polícia Rodoviária Federal' },
12 | { id: '7', number: '192', description: 'SAMU' },
13 | { id: '8', number: '193', description: 'Corpo de Bombeiros' },
14 | { id: '9', number: '194', description: 'Polícia Federal' },
15 | { id: '10', number: '197', description: 'Polícia Civil' },
16 | { id: '11', number: '(61) 3207-4242', description: 'DECRIN' },
17 | ];
18 |
19 | export default emergencyNumbers;
20 |
--------------------------------------------------------------------------------
/app/src/docs/FAQ/HelpOfferedRecommendations.js:
--------------------------------------------------------------------------------
1 | const acceptHelpRequestRecommendationsDescription = `
2 | 1. Lembre-se que você está lidando com pessoas que precisam de ajuda, logo, tenha paciência, seja prestativo e gentil;
3 |
4 | 2. Ao entrar em contato com o ajudado, considere que o mesmo pode estar em alguma situação de risco, por isso, não peça, e nem ofereça, informações adicionais além das apresentadas no app;
5 |
6 | 3. Recomendamos, caso seja necessário um encontro, que este ocorra em um local público, e de forma segura.
7 | `;
8 |
9 | const createHelpOfferedRecommendationsDescriptions = `
10 | 1. Se um objeto for ofertado, certifique-se de que o mesmo está em boas condições de uso;
11 |
12 | 2. Certifique-se, ao escolher um ajudado, de que este realmente precisa da ajuda;
13 |
14 | 3. Caso seja ofertado um serviço (apoio social, psicológico ou físico, transporte de emergência e pequenos serviços), lembre-se de realizá-lo da melhor forma possível, e sempre com paciência e prestatividade.
15 | `;
16 |
17 | const helpOfferedRecommendations = [
18 | {
19 | id: '1',
20 | title: 'Recomendações importantes para aceitar um pedido de ajuda',
21 | description: acceptHelpRequestRecommendationsDescription,
22 | },
23 | {
24 | id: '2',
25 | title: 'Recomendações importante para oferecer ajuda',
26 | description: createHelpOfferedRecommendationsDescriptions,
27 | },
28 | ];
29 |
30 | export default helpOfferedRecommendations;
31 |
--------------------------------------------------------------------------------
/app/src/docs/FAQ/HelpRequestRecommendations.js:
--------------------------------------------------------------------------------
1 | const acceptHelpOfferRecommendationsDescription = `
2 | 1. Verifique se a oferta está de acordo com a sua necessidade, caso contrário deixe a oportunidade para alguém que realmente precise;
3 |
4 | 2. Caso a oferta se adeque à sua situação, aceite-a e aguarde o contato do responsável por ela;
5 |
6 | 3. Ao receber a ajuda, lembre-se de agradecer ao voluntário.
7 | `;
8 |
9 | const createHelpRequestRecommendationsDescriptions = `
10 | 1. Lembre-se sempre que você está lidando com outras pessoas, então não peça por coisas impossíveis, nem por dinheiro pois é importante que todos possam ajudar;
11 |
12 | 2. Ao receber voluntários para te ajudar, nunca esqueça de ser educado e gentil, pois eles estão tentando fazer o possível para atender à sua solicitação na situação pela qual você está passando;
13 |
14 | 3. Recomendamos, caso seja necessário um encontro, que este ocorra em um local público, e de forma segura.
15 | `;
16 |
17 | const helpRequestRecommendations = [
18 | {
19 | id: '1',
20 | title: 'Recomendações importantes para se interessar por alguma oferta de ajuda',
21 | description: acceptHelpOfferRecommendationsDescription,
22 | },
23 | {
24 | id: '2',
25 | title: 'Recomendações importantes para criar de pedidos de ajuda ',
26 | description: createHelpRequestRecommendationsDescriptions,
27 | },
28 | ];
29 |
30 | export default helpRequestRecommendations;
31 |
--------------------------------------------------------------------------------
/app/src/docs/FAQ/HowToBeVolunteer.js:
--------------------------------------------------------------------------------
1 | const howToVolunteerRecommendations = [
2 | {
3 | id: '1',
4 | title: 'Como ser voluntário?',
5 | description:
6 | 'Para ser voluntário, é só olhar no mapa da página inicial do app, e clicar no ícone.',
7 | },
8 | ];
9 |
10 | export default howToVolunteerRecommendations;
11 |
--------------------------------------------------------------------------------
/app/src/docs/FAQ/HowToChooseHelpOffered.js:
--------------------------------------------------------------------------------
1 | const howToChoseHelpOfferRecommendations = [
2 | {
3 | id: '1',
4 | title: 'Como escolher uma oferta de ajuda?',
5 | description:
6 | 'Para escolher uma oferta de ajuda, é só olhar no mapa da página inicial do app, e clicar no ícone de oferecer ajuda',
7 | },
8 | ];
9 |
10 | export default howToChoseHelpOfferRecommendations;
11 |
--------------------------------------------------------------------------------
/app/src/docs/FAQ/HowToCreateHelp.js:
--------------------------------------------------------------------------------
1 | const HowToCreateHelpRequestModal = `
2 | 1. Para pedir uma ajuda clique no ícone;
3 |
4 | 2. Preencha os dados da página de pedidos: título, categoria e descrição;
5 |
6 | 3. Depois de criado o seu pedido, é só esperar que alguém ofereça ajuda;
7 |
8 | 4. Quando alguém oferecer ajuda, uma notificação será enviado pelo app;
9 |
10 | 5. O contato entre você e o voluntário a lhe ajudar será feito através do telefone ou alguma aplicativo de conversa que vocês utilizem (Exemplo: WhatsApp, Facebook);
11 |
12 | 6. Depois que você recebeu a sua ajuda, é só entrar no app e finalizar o seu pedido.
13 | `;
14 |
15 | const createHelpRecommendations = [
16 | {
17 | id: '1',
18 | title: 'Como criar um pedido de ajuda?',
19 | description: HowToCreateHelpRequestModal,
20 | },
21 | ];
22 |
23 | export default createHelpRecommendations;
24 |
--------------------------------------------------------------------------------
/app/src/docs/FAQ/HowToOfferHelp.js:
--------------------------------------------------------------------------------
1 | const HowToOfferHelpRecommendations = `
2 | 1. Para ofertar uma ajuda clique no ícone de criar oferta ;
3 |
4 | 2. Preencha os dados da página de pedidos: título, categoria e descrição;
5 |
6 | 3. Depois de efetuada a oferta do seu pedido, é só aguardar que uma ou mais pessoas se interessarem pela sua ajuda;
7 |
8 | 4. A lista de interessados aparecerá no histórico da sua oferta e uma notificação será enviada pelo app;
9 |
10 | 5. Você pode aceitar ajudar uma ou mais pessoas;
11 |
12 | 6. O contato entre você e o interessado que você irá ajudar será feito através do telefone ou alguma aplicativo de conversa que vocês utilizem (Exemplo: WhatsApp, Facebook);
13 |
14 | 7. Depois de ajudar os interessados, é só entrar no app e finalizar a sua oferta.`;
15 |
16 | const offerHelpRecommendations = [
17 | {
18 | id: '1',
19 | title: 'Como criar uma oferta de ajuda?',
20 | description: HowToOfferHelpRecommendations,
21 | },
22 | ];
23 |
24 | export default offerHelpRecommendations;
25 |
--------------------------------------------------------------------------------
/app/src/docs/filterMarkers.js:
--------------------------------------------------------------------------------
1 | const filterButtonTypes = [
2 | {
3 | _id: 'help',
4 | name: 'Pedidos',
5 | isEnabled: false,
6 | },
7 | {
8 | _id: 'helpOffer',
9 | name: 'Ofertas',
10 | isEnabled: false,
11 | },
12 | {
13 | _id: 'campaign',
14 | name: 'Campanhas',
15 | isEnabled: false,
16 | },
17 | ];
18 |
19 | export default filterButtonTypes;
20 |
--------------------------------------------------------------------------------
/app/src/docs/warning.js:
--------------------------------------------------------------------------------
1 | const userPositionWarningMessage =
2 | 'Lembre-se de nunca colocar a posição exata da sua residência, mas sempre em um ponto de referência de fácil acesso. Segurança em primeiro lugar!';
3 |
4 | const requestHelpWarningMessage =
5 | 'Lembre-se de nunca colocar informações pessoais nas ajudas que você cria, pois eles ficam públicos para todo mundo.';
6 |
7 | const offeringHelpWarningMessage =
8 | 'Lembre-se que você está lidando com um ser humano. Ao ofertar ajuda, sempre tome cuidado com seus dados pessoais, jamais passe informações sigilosas.';
9 |
10 | export {
11 | userPositionWarningMessage,
12 | requestHelpWarningMessage,
13 | offeringHelpWarningMessage,
14 | };
15 |
--------------------------------------------------------------------------------
/app/src/images/catPhoto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/src/images/catPhoto.png
--------------------------------------------------------------------------------
/app/src/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mia-ajuda/Frontend/6fabb891cd8c4edd07ee2f7c0d4f727803b59587/app/src/images/logo.png
--------------------------------------------------------------------------------
/app/src/images/logo.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/app/src/pages/ActivitiesPages/MyRequestedHelp/MyRequestHelpDescription/FeedbackModal/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { BaseModal } from '../../../../../components/modals/BaseModal';
3 | import { Text, View } from 'react-native';
4 | import { Input } from '../../../../../components/atoms/Input';
5 | import { DefaultButton } from '../../../../../components/atoms/DefaultButton';
6 |
7 | export const FeedbackModal = ({
8 | setShowFeedbackModal,
9 | showFeedbackModal,
10 | onCloseModal,
11 | feedback,
12 | setFeedback,
13 | onSubmit,
14 | }) => {
15 | return (
16 |
22 |
23 | Feedback para Ajudante
24 |
25 |
35 |
36 |
37 |
38 |
39 | );
40 | };
41 |
--------------------------------------------------------------------------------
/app/src/pages/ActivitiesPages/SelectedHelpOnMap/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import CustomMap from '../../../components/CustomMap';
4 | import { ActivityMarker } from '../../../components/molecules/ActivityMarker';
5 |
6 | export const SelectedHelpOnMap = ({ route }) => {
7 | const { help, helpLocationCoordinates, title } = route.params;
8 |
9 | return (
10 |
11 |
12 |
18 |
19 | {/* the feature that change offer location will be developed in another issue
20 |
21 |
25 | */}
26 |
27 | );
28 | };
29 |
--------------------------------------------------------------------------------
/app/src/pages/ActivitiesPages/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import colors from '../../../assets/styles/colorVariables';
3 |
4 | const styles = StyleSheet.create({
5 | container: {
6 | height: '100%',
7 | width: '100%',
8 | justifyContent: 'center',
9 | alignItems: 'center',
10 | flex: 1,
11 | },
12 |
13 | helpList: {
14 | marginLeft: 15,
15 | marginRight: 15,
16 | marginBottom: 15,
17 | },
18 |
19 | tabContainer: {
20 | backgroundColor: colors.primary,
21 | },
22 |
23 | tabLabel: {
24 | color: colors.light,
25 | },
26 |
27 | tabIndicator: {
28 | backgroundColor: colors.light,
29 | padding: 2,
30 | },
31 | });
32 |
33 | export default styles;
34 |
--------------------------------------------------------------------------------
/app/src/pages/AuthPages/Address/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../../assets/styles/fontVariable';
3 | import color from '../../../../assets/styles/colorVariables';
4 |
5 | const styles = StyleSheet.create({
6 | container: {
7 | flex: 1,
8 | alignItems: 'center',
9 | justifyContent: 'space-between',
10 | marginVertical: 20,
11 | marginHorizontal: 16,
12 | },
13 | scrollContainer: {
14 | justifyContent: 'center',
15 | },
16 | formScrollContainer: {
17 | width: '100%',
18 | },
19 | viewText: {
20 | width: '90%',
21 | justifyContent: 'center',
22 | marginBottom: 20,
23 | },
24 | pageDescription: {
25 | ...fonts.subtitle,
26 | fontFamily: 'montserrat-semibold',
27 | marginBottom: 20,
28 | },
29 | inputView: {
30 | width: '100%',
31 | },
32 | btnView: {
33 | width: '100%',
34 | },
35 | inputMask: {
36 | borderWidth: 2,
37 | borderRadius: 5,
38 | padding: 10,
39 | fontSize: 16,
40 | fontFamily: 'montserrat-regular',
41 | },
42 | valid: {
43 | borderColor: color.primary,
44 | },
45 | invalid: {
46 | borderColor: color.danger,
47 | },
48 | label: {
49 | fontFamily: 'montserrat-semibold',
50 | color: color.primary,
51 | },
52 | viewMargin: {
53 | marginVertical: 6,
54 | },
55 | toggleView: {
56 | flexDirection: 'row',
57 | alignItems: 'center',
58 | justifyContent: 'space-between',
59 | },
60 | backIcon: {
61 | alignItems: 'flex-start',
62 | marginVertical: 10,
63 | },
64 | scroll: { width: '100%' },
65 | });
66 |
67 | export default styles;
68 |
--------------------------------------------------------------------------------
/app/src/pages/AuthPages/ForgotPassword/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../../assets/styles/fontVariable';
3 |
4 | export default StyleSheet.create({
5 | container: {
6 | flex: 1,
7 | paddingHorizontal: 20,
8 | paddingVertical: 20,
9 | marginTop: 20,
10 | },
11 | backIcon: {
12 | flex: 1,
13 | width: '100%',
14 | alignItems: 'flex-start',
15 | },
16 | content: {
17 | flex: 8,
18 | justifyContent: 'space-between',
19 | },
20 | contentText: {
21 | marginTop: 40,
22 | width: '100%',
23 | justifyContent: 'center',
24 | alignItems: 'center',
25 | },
26 | inputWrapper: {
27 | width: '100%',
28 | marginTop: 30,
29 | },
30 | textTitle: {
31 | ...fonts.title,
32 | fontWeight: 'bold',
33 | },
34 | subtitle: {
35 | ...fonts.body,
36 | textAlign: 'justify',
37 | marginTop: 10,
38 | },
39 |
40 | scrollContainer: { flexGrow: 1 },
41 | });
42 |
--------------------------------------------------------------------------------
/app/src/pages/AuthPages/InitialScreen/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import colors from '../../../../assets/styles/colorVariables';
3 | import { RFValue } from 'react-native-responsive-fontsize';
4 |
5 | const styles = StyleSheet.create({
6 | initialScreenContainer: {
7 | height: '100%',
8 | width: '100%',
9 | backgroundColor: colors.primary,
10 | display: 'flex',
11 | alignItems: 'center',
12 | textAlign: 'center',
13 | paddingHorizontal: 24,
14 | },
15 | logo: {
16 | marginTop: 80,
17 | height: '20%',
18 | resizeMode: 'contain',
19 | marginBottom: 32,
20 | },
21 | title: {
22 | fontSize: RFValue(22, 640),
23 | textAlign: 'center',
24 | color: 'white',
25 | fontWeight: '600',
26 | fontFamily: 'montserrat-medium',
27 | marginBottom: 24,
28 | },
29 | description: {
30 | fontSize: RFValue(18, 640),
31 | textAlign: 'center',
32 | color: 'white',
33 | fontFamily: 'montserrat-regular',
34 | },
35 | buttonsContainer: {
36 | marginTop: 'auto',
37 | width: '100%',
38 | marginBottom: 16,
39 | },
40 | });
41 |
42 | export default styles;
43 |
--------------------------------------------------------------------------------
/app/src/pages/AuthPages/Location/texts.json:
--------------------------------------------------------------------------------
1 | {
2 | "HelpRequest": {
3 | "instruction": "Arraste para ajustar a posição do seu pedido",
4 | "positionUse": "A posição escolhida será usada para definir a localização do seu pedido",
5 | "confirmPosition": "Podemos confirmar a localização do seu pedido?",
6 | "successText": "Seu pedido foi criada com sucesso"
7 | },
8 | "HelpOffer": {
9 | "instruction": "Arraste para ajustar a posição da sua oferta",
10 | "positionUse": "A posição escolhida será usada para definir a localização da sua oferta",
11 | "confirmPosition": "Podemos confirmar a localização da sua oferta?",
12 | "successText": "Sua oferta foi criada com sucesso"
13 | },
14 | "Campaign": {
15 | "instruction": "Arraste para ajustar a posição da sua campanha",
16 | "positionUse": "A posição escolhida será usada para definir a localização da sua campanha",
17 | "confirmPosition": "Podemos confirmar a localização da sua campanhas?",
18 | "successText": "Sua campanha foi criada com sucesso"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/pages/AuthPages/Login/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import colors from '../../../../assets/styles/colorVariables';
3 | import fonts from '../../../../assets/styles/fontVariable';
4 |
5 | const styles = StyleSheet.create({
6 | container: {
7 | flex: 1,
8 | backgroundColor: colors.primary,
9 | },
10 | logo: {
11 | marginTop: 50,
12 | flex: 1,
13 | alignItems: 'center',
14 | justifyContent: 'center',
15 | width: '100%',
16 | },
17 | input: {
18 | marginTop: 20,
19 | alignItems: 'center',
20 | justifyContent: 'center',
21 | marginHorizontal: 20,
22 | },
23 |
24 | textInput: {
25 | ...fonts.body,
26 | borderBottomWidth: 2,
27 | borderBottomColor: colors.light,
28 | color: colors.light,
29 | marginVertical: 20,
30 | width: '100%',
31 | },
32 | forgotPassword: {
33 | justifyContent: 'flex-end',
34 | },
35 | forgotPasswordButton: {
36 | alignSelf: 'flex-end',
37 | },
38 | forgotPasswordtext: {
39 | ...fonts.body,
40 | marginHorizontal: 20,
41 | marginBottom: 20,
42 | color: colors.light,
43 | },
44 | viewBtn: {
45 | alignItems: 'center',
46 | flex: 1,
47 | },
48 | login: {
49 | width: '90%',
50 | },
51 | signupText: {
52 | ...fonts.body,
53 | color: colors.light,
54 | fontFamily: 'montserrat-semibold',
55 | borderBottomWidth: 1,
56 | borderBottomColor: '#fff',
57 | fontSize: 18,
58 | },
59 | logoImage: {
60 | flex: 1,
61 | resizeMode: 'contain',
62 | },
63 | });
64 |
65 | export default styles;
66 |
--------------------------------------------------------------------------------
/app/src/pages/AuthPages/Photo/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../../assets/styles/fontVariable';
3 |
4 | const styles = StyleSheet.create({
5 | container: {
6 | flex: 1,
7 | paddingVertical: 20,
8 | },
9 | logo: {
10 | flex: 1,
11 | alignItems: 'center',
12 | },
13 | pickPhotoButton: {
14 | alignItems: 'center',
15 | justifyContent: 'center',
16 | },
17 | pickerText: {
18 | ...fonts.body,
19 | fontSize: 14,
20 | },
21 | button: {
22 | backgroundColor: '#c4c4c4',
23 | width: 60,
24 | height: 60,
25 | borderRadius: 35,
26 | justifyContent: 'center',
27 | alignItems: 'center',
28 | },
29 |
30 | text: {
31 | ...fonts.subtitle,
32 | fontFamily: 'montserrat-semibold',
33 | textAlign: 'center',
34 | },
35 |
36 | textView: {
37 | flex: 6,
38 | margin: 16,
39 | alignItems: 'flex-start',
40 | },
41 | btnView: {
42 | flex: 1,
43 | alignItems: 'center',
44 | justifyContent: 'space-evenly',
45 | marginVertical: 40,
46 | flexDirection: 'row',
47 | },
48 |
49 | backIcon: {
50 | alignItems: 'flex-start',
51 | marginTop: 5,
52 | },
53 | });
54 |
55 | export default styles;
56 |
--------------------------------------------------------------------------------
/app/src/pages/AuthPages/RegistrationData/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../../assets/styles/fontVariable';
3 | import colors from '../../../../assets/styles/colorVariables';
4 | const styles = StyleSheet.create({
5 | safeAreaView: {
6 | flex: 1,
7 | paddingVertical: 20,
8 | paddingHorizontal: 30,
9 | backgroundColor: colors.light,
10 | },
11 | form: {
12 | width: '100%',
13 | justifyContent: 'space-between',
14 | height: 250,
15 | },
16 | text1: {
17 | ...fonts.title,
18 | fontFamily: 'montserrat-semibold',
19 | flexDirection: 'column',
20 | justifyContent: 'space-between',
21 | alignItems: 'center',
22 | marginTop: 10,
23 | },
24 | btnView: {
25 | width: '100%',
26 | },
27 | viewMargin: {
28 | marginVertical: 6,
29 | },
30 | scrollOnUserTyping: {
31 | width: '100%',
32 | },
33 | scroll: {
34 | width: '100%',
35 | marginTop: 50,
36 | },
37 | inputMask: {
38 | borderWidth: 2,
39 | borderRadius: 5,
40 | padding: 10,
41 | fontSize: 16,
42 | fontFamily: 'montserrat-regular',
43 | },
44 | valid: {
45 | borderColor: colors.primary,
46 | },
47 | invalid: {
48 | borderColor: colors.danger,
49 | },
50 | label: {
51 | fontFamily: 'montserrat-semibold',
52 | color: colors.primary,
53 | },
54 | backIcon: {
55 | alignItems: 'flex-start',
56 | marginTop: 15,
57 | },
58 | errorMessage: {
59 | ...fonts.body,
60 | alignSelf: 'center',
61 | marginBottom: 20,
62 | color: 'red',
63 | },
64 | scrollContainerStyle: {
65 | flexGrow: 1,
66 | justifyContent: 'center',
67 | },
68 | });
69 |
70 | export default styles;
71 |
--------------------------------------------------------------------------------
/app/src/pages/AuthPages/RiskGroup/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../../assets/styles/fontVariable';
3 | import colors from '../../../../assets/styles/colorVariables';
4 |
5 | const styles = StyleSheet.create({
6 | container: {
7 | flex: 1,
8 | alignItems: 'center',
9 | backgroundColor: colors.light,
10 | },
11 | viewText: {
12 | width: '90%',
13 | justifyContent: 'center',
14 | },
15 | text1: {
16 | ...fonts.title,
17 | fontFamily: 'montserrat-semibold',
18 | marginVertical: 10,
19 | },
20 | input: {
21 | width: '90%',
22 | flexDirection: 'row',
23 | flexWrap: 'wrap',
24 | },
25 | inputItem: {
26 | marginHorizontal: 6,
27 | },
28 | btnView: {
29 | width: '90%',
30 | bottom: 20,
31 | justifyContent: 'flex-end',
32 | position: 'absolute',
33 | },
34 | backIcon: {
35 | alignSelf: 'flex-start',
36 | marginTop: '10%',
37 | marginLeft: 15,
38 | },
39 | });
40 |
41 | export default styles;
42 |
--------------------------------------------------------------------------------
/app/src/pages/FindUsersPages/SocialNetworkProfile/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../../assets/styles/fontVariable';
3 |
4 | const styles = StyleSheet.create({
5 | container: {
6 | flex: 1,
7 | flexDirection: 'column',
8 | width: '100%',
9 | height: '100%',
10 | },
11 |
12 | profileInfoContainer: {
13 | flex: 2,
14 | flexDirection: 'row',
15 | },
16 | profileCardContainer: {
17 | flex: 5,
18 | },
19 |
20 | smallerInfoContainer: {
21 | flex: 1,
22 | flexDirection: 'column',
23 | margin: 10,
24 | },
25 |
26 | nameAndFollowButtonContainer: {
27 | flex: 2,
28 | flexDirection: 'row',
29 | justifyContent: 'space-around',
30 | alignItems: 'center',
31 | },
32 |
33 | followerFollowingContainer: {
34 | flex: 1,
35 | flexDirection: 'row',
36 | alignItems: 'flex-start',
37 | justifyContent: 'space-between',
38 | },
39 |
40 | name: {
41 | flex: 1,
42 | ...fonts.body,
43 | color: '#4B8AB9',
44 | fontSize: 18,
45 | flexWrap: 'wrap',
46 | },
47 |
48 | followerFollowingText: {
49 | ...fonts.body,
50 | color: '#4B8AB9',
51 | },
52 |
53 | profileInfo: {
54 | flexDirection: 'row',
55 | alignItems: 'flex-start',
56 | padding: 20,
57 | },
58 | profileImage: {
59 | width: 120,
60 | height: 120,
61 | resizeMode: 'cover',
62 | borderRadius: 60,
63 | marginHorizontal: 10,
64 | alignSelf: 'center',
65 | },
66 |
67 | text: {
68 | ...fonts.body,
69 | color: '#4B8AB9',
70 | paddingRight: 10,
71 | },
72 |
73 | cardContainer: {
74 | flex: 5,
75 | marginLeft: 15,
76 | marginRight: 15,
77 | marginBottom: 15,
78 | },
79 | });
80 |
81 | export default styles;
82 |
--------------------------------------------------------------------------------
/app/src/pages/FindUsersPages/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | const styles = StyleSheet.create({
4 | container: {
5 | flex: 1,
6 | paddingHorizontal: 16,
7 | paddingVertical: 24,
8 | },
9 | });
10 |
11 | export default styles;
12 |
--------------------------------------------------------------------------------
/app/src/pages/HelpPages/CreateCampaign/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../../assets/styles/fontVariable';
3 | import colors from '../../../../assets/styles/colorVariables';
4 |
5 | const styles = StyleSheet.create({
6 | view: {
7 | flex: 1,
8 | height: '100%',
9 | flexDirection: 'column',
10 | justifyContent: 'space-between',
11 | },
12 | margiView: {
13 | marginVertical: 12,
14 | },
15 | btnContainer: {
16 | height: '25%',
17 | marginTop: 20,
18 | },
19 | input: {
20 | ...fonts.body,
21 | borderWidth: 2,
22 | borderRadius: 5,
23 | borderColor: colors.primary,
24 | padding: 10,
25 | },
26 | picker: {
27 | ...fonts.body,
28 | borderWidth: 2,
29 | borderRadius: 5,
30 | borderColor: colors.primary,
31 | },
32 | catagoryPicker: {
33 | marginTop: 20,
34 | },
35 | pikerItem: {
36 | ...fonts.body,
37 | color: colors.primary,
38 | },
39 | label: {
40 | ...fonts.body,
41 | fontFamily: 'montserrat-semibold',
42 | color: colors.primary,
43 | },
44 | descriptionInput: {
45 | marginTop: 20,
46 | },
47 | addCategory: {
48 | backgroundColor: colors.primary,
49 | borderWidth: 1,
50 | borderColor: colors.primary,
51 | padding: 5,
52 | marginTop: 20,
53 | width: '40%',
54 | borderRadius: 5,
55 | justifyContent: 'center',
56 | alignItems: 'center',
57 | },
58 | addCategoryText: {
59 | ...fonts.body,
60 | color: '#fff',
61 | fontSize: 18,
62 | },
63 | });
64 |
65 | export default styles;
66 |
--------------------------------------------------------------------------------
/app/src/pages/HelpPages/CreateHelpOffer/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../../assets/styles/fontVariable';
3 | import colors from '../../../../assets/styles/colorVariables';
4 |
5 | const styles = StyleSheet.create({
6 | view: {
7 | flex: 1,
8 | height: '100%',
9 | flexDirection: 'column',
10 | justifyContent: 'space-between',
11 | },
12 | margiView: {
13 | marginVertical: 12,
14 | },
15 | btnContainer: {
16 | height: '25%',
17 | marginTop: 20,
18 | },
19 | input: {
20 | ...fonts.body,
21 | borderWidth: 2,
22 | borderRadius: 5,
23 | borderColor: colors.primary,
24 | padding: 10,
25 | },
26 | picker: {
27 | ...fonts.body,
28 | borderWidth: 2,
29 | borderRadius: 5,
30 | borderColor: colors.primary,
31 | },
32 | catagoryPicker: {
33 | marginTop: 20,
34 | },
35 | pikerItem: {
36 | ...fonts.body,
37 | color: colors.primary,
38 | },
39 | label: {
40 | ...fonts.body,
41 | fontFamily: 'montserrat-semibold',
42 | color: colors.primary,
43 | },
44 | descriptionInput: {
45 | marginTop: 20,
46 | },
47 | });
48 |
49 | export default styles;
50 |
--------------------------------------------------------------------------------
/app/src/pages/HelpPages/CreateHelpRequest/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import fonts from '../../../../assets/styles/fontVariable';
3 | import colors from '../../../../assets/styles/colorVariables';
4 |
5 | const styles = StyleSheet.create({
6 | view: {
7 | flex: 1,
8 | height: '100%',
9 | flexDirection: 'column',
10 | justifyContent: 'space-between',
11 | },
12 | margiView: {
13 | marginVertical: 12,
14 | },
15 | btnContainer: {
16 | height: '25%',
17 | marginTop: 20,
18 | },
19 | input: {
20 | ...fonts.body,
21 | borderWidth: 2,
22 | borderRadius: 5,
23 | borderColor: colors.primary,
24 | padding: 10,
25 | },
26 | picker: {
27 | ...fonts.body,
28 | borderWidth: 2,
29 | borderRadius: 5,
30 | borderColor: colors.primary,
31 | },
32 | catagoryPicker: {
33 | marginTop: 20,
34 | },
35 | pikerItem: {
36 | ...fonts.body,
37 | color: colors.primary,
38 | },
39 | label: {
40 | ...fonts.body,
41 | fontFamily: 'montserrat-semibold',
42 | color: colors.primary,
43 | },
44 |
45 | descriptionInput: {
46 | marginTop: 20,
47 | },
48 | addCategory: {
49 | backgroundColor: colors.primary,
50 | borderWidth: 1,
51 | borderColor: colors.primary,
52 | padding: 5,
53 | marginTop: 20,
54 | width: '40%',
55 | borderRadius: 5,
56 | justifyContent: 'center',
57 | alignItems: 'center',
58 | },
59 | addCategoryText: {
60 | ...fonts.body,
61 | color: '#fff',
62 | fontSize: 18,
63 | },
64 | });
65 |
66 | export default styles;
67 |
--------------------------------------------------------------------------------
/app/src/pages/HelpPages/MyRequests/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import colors from '../../../../assets/styles/colorVariables';
3 |
4 | const styles = StyleSheet.create({
5 | container: {
6 | flex: 1,
7 | },
8 |
9 | helpList: {
10 | marginLeft: 15,
11 | marginRight: 15,
12 | marginBottom: 15,
13 | },
14 |
15 | tabContainer: {
16 | backgroundColor: colors.primary,
17 | },
18 |
19 | tabLabel: {
20 | color: colors.light,
21 | },
22 |
23 | tabIndicator: {
24 | backgroundColor: colors.light,
25 | padding: 2,
26 | },
27 | });
28 |
29 | export default styles;
30 |
--------------------------------------------------------------------------------
/app/src/pages/InformationsCenter/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { View } from 'react-native';
3 | import faqOption from '../../docs/FAQ/faqOptions';
4 | import { TutorialCard } from '../../components/molecules/TutorialCard';
5 | import { SliderModal } from '../../components/organisms/SliderModal';
6 | import EmergencyNumbers from '../../components/FAQModals/EmergencyNumbersModal';
7 |
8 | export default function InformationsCenter() {
9 | const [pages, setPages] = useState([]);
10 | const [modalVisible, setModalVisible] = useState(false);
11 | const [emergencyNumbersVisible, setEmergencyNumbersVisible] =
12 | useState(false);
13 |
14 | const handleShowModal = (id) => {
15 | const selectedPages = faqOption[id].pages;
16 | setPages(selectedPages);
17 | setModalVisible(true);
18 | };
19 |
20 | return (
21 |
22 | setModalVisible(false)}
26 | />
27 |
31 | {faqOption.map((faq, i) => (
32 | {
39 | faq.emergencyModal
40 | ? setEmergencyNumbersVisible(true)
41 | : handleShowModal(i);
42 | }}
43 | />
44 | ))}
45 |
46 | );
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/pages/InformationsCenter/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | const styles = StyleSheet.create({
4 | container: {
5 | flex: 1,
6 | },
7 |
8 | cardsDirections: {
9 | height: '90%',
10 | flexDirection: 'row',
11 | flexWrap: 'wrap',
12 | justifyContent: 'center',
13 | alignContent: 'center',
14 | },
15 | });
16 |
17 | export default styles;
18 |
--------------------------------------------------------------------------------
/app/src/pages/IntroSlides/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Dimensions } from 'react-native';
2 | import colors from '../../../assets/styles/colorVariables';
3 |
4 | const styles = StyleSheet.create({
5 | buttonBox: {
6 | backgroundColor: 'transparent',
7 | },
8 | buttonText: {
9 | color: colors.primary,
10 | marginHorizontal: 20,
11 | fontFamily: 'montserrat-semibold',
12 | fontSize: 15,
13 | },
14 | titles: {
15 | marginTop: '2%',
16 | color: colors.primary,
17 | fontFamily: 'montserrat-semibold',
18 | },
19 | images: {
20 | paddingBottom: '1%',
21 | },
22 | subtitle: {
23 | marginTop: 0,
24 | color: colors.dark,
25 | fontFamily: 'montserrat-semibold',
26 | },
27 | image: {
28 | width: (Dimensions.get('window').width * 100) / 100,
29 | height: (Dimensions.get('window').height * 40) / 100,
30 | resizeMode: 'contain',
31 | },
32 | });
33 |
34 | export default styles;
35 |
--------------------------------------------------------------------------------
/app/src/pages/Notification/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import colors from '../../../assets/styles/colorVariables';
3 | import fonts from '../../../assets/styles/fontVariable';
4 | import { Colors } from 'react-native/Libraries/NewAppScreen';
5 |
6 | const styles = StyleSheet.create({
7 | container: {
8 | flex: 1,
9 | },
10 |
11 | header: {
12 | backgroundColor: colors.primary,
13 | height: '13%',
14 | justifyContent: 'center',
15 | alignItems: 'center',
16 | },
17 |
18 | headerText: {
19 | marginTop: '8%',
20 | ...fonts.title,
21 | color: colors.light,
22 | fontSize: 24,
23 | },
24 |
25 | notificationList: {
26 | height: '100%',
27 | paddingHorizontal: 15,
28 | paddingBottom: 15,
29 | },
30 |
31 | noNotifications: {
32 | height: '100%',
33 | width: '100%',
34 | alignItems: 'center',
35 | paddingTop: '40%',
36 | padding: 20,
37 | },
38 |
39 | emptyListImage: {
40 | resizeMode: 'contain',
41 | width: 200,
42 | height: 200,
43 | },
44 |
45 | emptyListText: {
46 | ...fonts.title,
47 | color: Colors.primary,
48 | marginTop: 10,
49 | textAlign: 'center',
50 | fontSize: 22,
51 | },
52 | });
53 |
54 | export default styles;
55 |
--------------------------------------------------------------------------------
/app/src/pages/Splash/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View, Image, ActivityIndicator } from 'react-native';
3 | import colors from '../../../assets/styles/colorVariables';
4 | import styles from './styles';
5 |
6 | export default function Splash({ showLoading = false }) {
7 | return (
8 | <>
9 |
10 |
14 | {showLoading && (
15 |
16 |
17 |
18 | )}
19 |
20 | >
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/pages/Splash/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import colors from '../../../assets/styles/colorVariables';
3 |
4 | const styles = StyleSheet.create({
5 | container: {
6 | flex: 1,
7 | justifyContent: 'center',
8 | alignItems: 'center',
9 | backgroundColor: colors.primary,
10 | },
11 | image: {
12 | width: '100%',
13 | height: '100%',
14 | resizeMode: 'contain',
15 | },
16 | text: {
17 | fontFamily: 'montserrat-medium',
18 | marginTop: 20,
19 | color: '#fff',
20 | fontSize: 18,
21 | },
22 | footer: {
23 | marginBottom: 32,
24 | },
25 | });
26 |
27 | export default styles;
28 |
--------------------------------------------------------------------------------
/app/src/pages/UserList/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useCallback, useContext, useState } from 'react';
2 | import { View } from 'react-native';
3 | import ProfileList from '../../components/profileList';
4 | import { SocialNetworkProfileContext } from '../../store/contexts/socialNetworkProfileContext';
5 | import { LoadingContext } from '../../store/contexts/loadingContext';
6 | import { NotFound } from '../../components/organisms/NotFound';
7 | import { useFocusEffect } from '@react-navigation/core';
8 |
9 | export const UserList = ({ route, navigation }) => {
10 | const { userId, followType } = route.params;
11 | const { getFollows } = useContext(SocialNetworkProfileContext);
12 | const { setIsLoading } = useContext(LoadingContext);
13 | const [userList, setUserList] = useState([]);
14 |
15 | const notFoundMessages = {
16 | following: 'segue',
17 | followers: 'é seguido por',
18 | };
19 | const hasUsers = userList?.length > 0;
20 |
21 | const getUserList = async () => {
22 | setIsLoading(true);
23 | const response = await getFollows(followType, userId);
24 | setIsLoading(false);
25 | setUserList(response);
26 | };
27 |
28 | useFocusEffect(
29 | useCallback(() => {
30 | getUserList();
31 | }, [navigation]),
32 | );
33 |
34 | return (
35 |
36 | {hasUsers && }
37 | {!hasUsers && (
38 |
41 | )}
42 |
43 | );
44 | };
45 |
--------------------------------------------------------------------------------
/app/src/services/Activity.js:
--------------------------------------------------------------------------------
1 | import api from '../services/Api';
2 |
3 | class ActivityService {
4 | async getActivityList(id, coords, categoryId, activityId) {
5 | const { longitude, latitude } = coords;
6 | const queryParams = new URLSearchParams({
7 | id,
8 | coords: `${longitude},${latitude}`,
9 | ...(categoryId && { categoryId }),
10 | ...(activityId && { activityId }),
11 | });
12 | const url = `/activity/list?${queryParams.toString()}`;
13 |
14 | const activityList = await api.get(url);
15 | return activityList.data;
16 | }
17 | }
18 |
19 | const activityService = new ActivityService();
20 | Object.freeze(activityService);
21 |
22 | export default activityService;
23 |
--------------------------------------------------------------------------------
/app/src/services/Api.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import AsyncStorage from '@react-native-async-storage/async-storage';
3 | import ENV from '../config/envVariables';
4 | import firebaseService from './Firebase';
5 | import jwt_decode from 'jwt-decode';
6 |
7 | const api = axios.create({
8 | baseURL: ENV.apiUrl,
9 | });
10 |
11 | api.interceptors.request.use(
12 | async (config) => {
13 | let accessToken = await AsyncStorage.getItem('accessToken');
14 | const user = await firebaseService.getCurrentUser();
15 | if (user && accessToken) {
16 | const expireDate = jwt_decode(accessToken).exp;
17 | const now = Date.now() / 1000;
18 |
19 | if (now > expireDate) {
20 | const newToken = await firebaseService.getUserId();
21 | await AsyncStorage.setItem('accessToken', newToken);
22 | accessToken = newToken;
23 | }
24 | }
25 |
26 | config.headers.Authorization = `Bearer ${accessToken}`;
27 | return config;
28 | },
29 | (error) => {
30 | console.log(error);
31 | },
32 | );
33 |
34 | export default api;
35 |
--------------------------------------------------------------------------------
/app/src/services/Badge.js:
--------------------------------------------------------------------------------
1 | import api from '../services/Api';
2 |
3 | class BadgeService {
4 | async getUserBadges(userId) {
5 | const response = await api.get(`/badges?userId=${userId}`);
6 | return response.data;
7 | }
8 | async getBadgesHistory(userId) {
9 | const response = await api.get(`/badges/history?userId=${userId}`);
10 | return response.data;
11 | }
12 | async increaseUserBadge(userId, category) {
13 | const response = await api.post('/badges/', { userId, category });
14 | return response.data;
15 | }
16 | async getBadgeList(userId) {
17 | const response = await api.get(`/badges/list?userId=${userId}`);
18 | return response.data;
19 | }
20 |
21 | async viewBadge(badgeId) {
22 | const response = await api.put(`/badges/${badgeId}`);
23 | return response.data;
24 | }
25 | }
26 |
27 | const badgeService = new BadgeService();
28 | Object.freeze(badgeService);
29 |
30 | export default badgeService;
31 |
--------------------------------------------------------------------------------
/app/src/services/Campaign.js:
--------------------------------------------------------------------------------
1 | import api from './Api';
2 |
3 | class CampaignService {
4 | constructor() {}
5 |
6 | async getNearCampaign(coords, id) {
7 | const { longitude, latitude } = coords;
8 | const campaign = await api.get(
9 | `/campaign?id.except=${id}&near=true&coords=${longitude},${latitude}`,
10 | );
11 | return campaign.data;
12 | }
13 |
14 | async getCampaignMultipleStatus(userId, status) {
15 | const url = `/campaign/listbyStatus/${userId}?statusList=${status}`;
16 | const campaign = await api.get(url);
17 | return campaign.data;
18 | }
19 |
20 | async createCampaign(title, categoryId, description, ownerId, location) {
21 | const data = {
22 | title,
23 | categoryId,
24 | description,
25 | ownerId,
26 | location,
27 | };
28 | const createdCampaignResponse = await api.post('/campaign', data);
29 | return createdCampaignResponse.data;
30 | }
31 |
32 | async finishCampaign(campaignId) {
33 | const url = `/campaign/${campaignId}`;
34 | await api.put(url);
35 | return true;
36 | }
37 |
38 | async deleteCampaign(campaignId) {
39 | const deleteCampaign = await api.delete(`/campaign/${campaignId}`);
40 | return deleteCampaign;
41 | }
42 |
43 | async getCampaignById(campaignId) {
44 | const url = `/campaign/${campaignId}`;
45 | const campaign = await api.get(url);
46 | return campaign.data;
47 | }
48 | }
49 |
50 | const campaignService = new CampaignService();
51 | Object.freeze(campaignService);
52 | export default campaignService;
53 |
--------------------------------------------------------------------------------
/app/src/services/Category.js:
--------------------------------------------------------------------------------
1 | import api from '../services/Api';
2 |
3 | class CategoryService {
4 | constructor() {}
5 |
6 | async getAllCategories() {
7 | const categories = await api.get('/category');
8 | return categories.data;
9 | }
10 | }
11 |
12 | const categoryService = new CategoryService();
13 | Object.freeze(categoryService);
14 |
15 | export default categoryService;
16 |
--------------------------------------------------------------------------------
/app/src/services/Feedback.js:
--------------------------------------------------------------------------------
1 | import api from '../services/Api';
2 |
3 | class FeedbackService {
4 | async createFeedback(sender, receiver, message) {
5 | const response = await api.post('/feedback', {
6 | sender,
7 | receiver,
8 | message,
9 | });
10 | return response.data;
11 | }
12 |
13 | async getFeedbackByReceiverId(receiver) {
14 | const response = await api.get(`/feedback/${receiver}`);
15 | return response.data;
16 | }
17 | }
18 |
19 | const feedbackService = new FeedbackService();
20 | Object.freeze(feedbackService);
21 |
22 | export default feedbackService;
23 |
--------------------------------------------------------------------------------
/app/src/services/Notification.js:
--------------------------------------------------------------------------------
1 | import api from './Api';
2 |
3 | class NotificationService {
4 | async getAllNotifications(userId) {
5 | let url = `/notification/user/${userId}`;
6 |
7 | const allNotifications = await api.get(url);
8 | return allNotifications.data;
9 | }
10 | }
11 |
12 | const notificationService = new NotificationService();
13 | Object.freeze(notificationService);
14 | export default notificationService;
15 |
--------------------------------------------------------------------------------
/app/src/services/Session.js:
--------------------------------------------------------------------------------
1 | import firebaseService from './Firebase';
2 | import AsyncStorage from '@react-native-async-storage/async-storage';
3 | import UserService from './User';
4 | import EntityService from './Entity';
5 |
6 | import env from '../config/envVariables';
7 | import api from './Api';
8 |
9 | class SessionService {
10 | constructor() {}
11 | async setDeviceId() {
12 | const loggedUser = await firebaseService.getCurrentUser();
13 |
14 | const userType = loggedUser?.displayName.split('|')[1]?.trim();
15 |
16 | if (userType == 'PJ') EntityService.setEntityDeviceId();
17 | else UserService.setUserDeviceId();
18 | }
19 |
20 | async signIn(loginInfo) {
21 | await firebaseService.login(loginInfo.email, loginInfo.password);
22 | const isEmailVerified = firebaseService.isEmailVerified();
23 | const shouldVerifyEmail = env.production || env.staging;
24 |
25 | if (isEmailVerified == false && shouldVerifyEmail) {
26 | throw new Error('auth/email-not-verified');
27 | }
28 |
29 | await this.setDeviceId();
30 | }
31 |
32 | async signUp(data) {
33 | const isEntityUser = data.cnpj;
34 | const response = isEntityUser
35 | ? await api.post('/entity', data)
36 | : await api.post('/user', data);
37 |
38 | await firebaseService.login(data.email, data.password);
39 | await firebaseService.sendEmailVerification();
40 | await this.setDeviceId();
41 |
42 | return response;
43 | }
44 |
45 | async signOut() {
46 | await AsyncStorage.removeItem('accessToken');
47 | await firebaseService.signOut();
48 | return true;
49 | }
50 | }
51 | export default new SessionService();
52 |
--------------------------------------------------------------------------------
/app/src/services/Timeline.js:
--------------------------------------------------------------------------------
1 | import api from '../services/Api';
2 |
3 | class TimelineService {
4 | async getTimelineByUserId(userId) {
5 | const response = await api.get(`/timeline?userId=${userId}`);
6 | return response.data;
7 | }
8 | }
9 |
10 | const timelineService = new TimelineService();
11 | Object.freeze(timelineService);
12 |
13 | export default timelineService;
14 |
--------------------------------------------------------------------------------
/app/src/services/callService.js:
--------------------------------------------------------------------------------
1 | import { alertError, alertMessageEmailVerification } from '../utils/Alert';
2 |
3 | export default async function callService(service, functionName, params = []) {
4 | try {
5 | let functionReturn = await service[functionName](...params);
6 | return functionReturn;
7 | } catch (error) {
8 | if (error.code == 'auth/email-not-verified') {
9 | alertMessageEmailVerification(error.message);
10 | } else {
11 | alertError(error);
12 | }
13 | return { error: true, errorData: error };
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/services/socket.js:
--------------------------------------------------------------------------------
1 | import socketio from 'socket.io-client';
2 | import ENV from '../config/envVariables';
3 |
4 | const socket = socketio(ENV.socketUrl, {
5 | autoConnect: false,
6 | });
7 |
8 | function subscribeToNewHelps(subscribeFunction) {
9 | socket.off('new-help');
10 | socket.on('new-help', subscribeFunction);
11 | }
12 |
13 | function subscribeToDeleteHelp(subscribeFunction) {
14 | socket.off('delete-help');
15 | socket.on('delete-help', subscribeFunction);
16 | }
17 |
18 | function subscribeToDeleteHelpOffer(subscribeFunction) {
19 | socket.off('delete-help-offer');
20 | socket.on('delete-help-offer', subscribeFunction);
21 | }
22 |
23 | function connect(userPosition, userId) {
24 | socket.io.opts.query = {
25 | userPosition,
26 | userId,
27 | };
28 | socket.connect();
29 | }
30 |
31 | function changeCategories(categories) {
32 | socket.emit('change-categories', categories);
33 | }
34 |
35 | function disconnect() {
36 | if (socket.connected) {
37 | socket.disconnect();
38 | }
39 | }
40 |
41 | export {
42 | connect,
43 | disconnect,
44 | subscribeToNewHelps,
45 | subscribeToDeleteHelp,
46 | subscribeToDeleteHelpOffer,
47 | changeCategories,
48 | };
49 |
--------------------------------------------------------------------------------
/app/src/store/actions.js:
--------------------------------------------------------------------------------
1 | const actions = {
2 | user: {
3 | storeUserInfo: 'STORE_USER',
4 | removeUserInfo: 'REMOVE_USER',
5 | requestSignIn: 'SIGNIN',
6 | },
7 | help: {
8 | storeList: 'ADD_HELP',
9 | },
10 | category: {
11 | getCategories: 'GET_CATEGORIES',
12 | },
13 | };
14 |
15 | export default actions;
16 |
--------------------------------------------------------------------------------
/app/src/store/contexts/ScreenTemplateContext/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { createContext, useMemo, useState } from 'react';
2 | import { styles } from './styles';
3 | import { StatusBar, View } from 'react-native';
4 | import colors from '../../../../colors';
5 |
6 | export const ScreenTemplateContext = createContext({});
7 |
8 | export const ScreenTemplateContextProvider = ({ children }) => {
9 | const [useSafeAreaView, setUseSafeAreaView] = useState(true);
10 |
11 | const contextValue = useMemo(() => {
12 | return {
13 | setUseSafeAreaView,
14 | };
15 | }, [setUseSafeAreaView]);
16 |
17 | return (
18 |
19 |
24 |
31 | {children}
32 |
33 |
34 | );
35 | };
36 |
--------------------------------------------------------------------------------
/app/src/store/contexts/ScreenTemplateContext/styles.jsx:
--------------------------------------------------------------------------------
1 | import { Platform, StatusBar, StyleSheet } from 'react-native';
2 |
3 | export const styles = StyleSheet.create({
4 | templateContainerWithMargin: {
5 | width: '100%',
6 | height: '100%',
7 | marginTop: Platform.OS == 'android' ? StatusBar.currentHeight : 0,
8 | paddingBottom: Platform.OS == 'android' ? StatusBar.currentHeight : 0,
9 | },
10 | templateContainer: {
11 | width: '100%',
12 | height: '100%',
13 | },
14 | });
15 |
--------------------------------------------------------------------------------
/app/src/store/contexts/activityBottomSheetContext.jsx:
--------------------------------------------------------------------------------
1 | import React, { createContext, useEffect, useMemo, useState } from 'react';
2 |
3 | export const ActivityBottomSheetContext = createContext({});
4 |
5 | export const ActivityBottomSheetContextProvider = ({ children }) => {
6 | const [showActivityModal, setShowActivityModal] = useState(false);
7 | const [activityInfo, setActivityInfo] = useState();
8 |
9 | const handleShowModal = (id, ownerId, type) => {
10 | setActivityInfo({ id, ownerId, type });
11 | setShowActivityModal(true);
12 | };
13 |
14 | useEffect(() => {
15 | if (!showActivityModal) setActivityInfo();
16 | }, [showActivityModal]);
17 |
18 | const contextValue = useMemo(() => {
19 | return {
20 | handleShowModal,
21 | setShowActivityModal,
22 | showActivityModal,
23 | activityInfo,
24 | };
25 | }, [
26 | handleShowModal,
27 | setShowActivityModal,
28 | showActivityModal,
29 | activityInfo,
30 | ]);
31 |
32 | return (
33 |
34 | {children}
35 |
36 | );
37 | };
38 |
--------------------------------------------------------------------------------
/app/src/store/contexts/categoryContext.jsx:
--------------------------------------------------------------------------------
1 | import React, {
2 | createContext,
3 | useState,
4 | useEffect,
5 | useContext,
6 | useMemo,
7 | } from 'react';
8 | import Category from '../../services/Category';
9 | import { UserContext } from './userContext';
10 | import callService from '../../services/callService';
11 |
12 | export const CategoryContext = createContext();
13 |
14 | export default function CategoryContextProvider(props) {
15 | const [categories, setCategories] = useState([]);
16 | const { user } = useContext(UserContext);
17 |
18 | useEffect(() => {
19 | const isUserAuthenticated = user._id;
20 | if (isUserAuthenticated) fetchCategories();
21 | }, [user]);
22 |
23 | async function fetchCategories() {
24 | const categoriesArray = await callService(Category, 'getAllCategories');
25 | if (!categoriesArray.error) {
26 | setCategories(categoriesArray);
27 | }
28 | }
29 |
30 | const contextValue = useMemo(() => {
31 | return {
32 | categories,
33 | };
34 | }, [categories]);
35 |
36 | return (
37 |
38 | {props.children}
39 |
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/store/contexts/cepContext.jsx:
--------------------------------------------------------------------------------
1 | import React, { createContext, useMemo } from 'react';
2 | import callService from '../../services/callService';
3 | import ViaCep from '../../ExternalServices/ViaCep';
4 | export const CepContext = createContext();
5 |
6 | export default function CepContextProvider({ children }) {
7 | async function getCepInformation(cep) {
8 | return await callService(ViaCep, 'getCepInformation', [cep]);
9 | }
10 |
11 | const contextValue = useMemo(() => {
12 | return {
13 | getCepInformation,
14 | };
15 | }, [getCepInformation]);
16 |
17 | return (
18 |
19 | {children}
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/store/contexts/deviceInformationContext.js:
--------------------------------------------------------------------------------
1 | import React, { createContext, useEffect, useState } from 'react';
2 | import { Keyboard, Platform } from 'react-native';
3 |
4 | export const DeviceInformationContext = createContext();
5 |
6 | export default function DeviceInfoProvider({ children }) {
7 | const [keyboardInformation, setKeyboardInformation] = useState({
8 | visible: false,
9 | dismiss: Keyboard.dismiss,
10 | });
11 | const operationalSystem = Platform.OS;
12 |
13 | //Add keyboardListenters
14 | useEffect(() => {
15 | Keyboard.addListener('keyboardDidShow', keyboardVisible);
16 | Keyboard.addListener('keyboardDidHide', keyboardHidden);
17 |
18 | return () => {
19 | Keyboard.removeListener('keyboardDidShow', keyboardVisible);
20 | Keyboard.removeListener('keyboardDidHide', keyboardHidden);
21 | };
22 | }, []);
23 |
24 | const keyboardVisible = () => {
25 | setKeyboardInformation({ ...keyboardInformation, visible: true });
26 | };
27 | const keyboardHidden = () => {
28 | setKeyboardInformation({ ...keyboardInformation, visible: false });
29 | };
30 |
31 | return (
32 |
38 | {children}
39 |
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/store/contexts/feedbackContext.jsx:
--------------------------------------------------------------------------------
1 | import React, { createContext, useContext, useMemo } from 'react';
2 | import callService from '../../services/callService';
3 | import feedbackService from '../../services/Feedback';
4 | import { LoadingContext } from './loadingContext';
5 |
6 | export const FeedbackContext = createContext({});
7 |
8 | export const FeedbackContextProvider = ({ children }) => {
9 | const { setIsLoading } = useContext(LoadingContext);
10 | const createFeedback = async (senderId, receiverId, body) => {
11 | setIsLoading(true);
12 | const response = await callService(feedbackService, 'createFeedback', [
13 | senderId,
14 | receiverId,
15 | body,
16 | ]);
17 | setIsLoading(false);
18 | return response;
19 | };
20 |
21 | const getFeedbackByReceiverId = async (receiverId) => {
22 | setIsLoading(true);
23 | const response = await callService(
24 | feedbackService,
25 | 'getFeedbackByReceiverId',
26 | [receiverId],
27 | );
28 | setIsLoading(false);
29 | return response;
30 | };
31 |
32 | const contextValue = useMemo(() => {
33 | return {
34 | createFeedback,
35 | getFeedbackByReceiverId,
36 | };
37 | }, [createFeedback, getFeedbackByReceiverId]);
38 |
39 | return (
40 |
41 | {children}
42 |
43 | );
44 | };
45 |
--------------------------------------------------------------------------------
/app/src/store/contexts/helpContext.js:
--------------------------------------------------------------------------------
1 | import React, { createContext, useContext, useMemo } from 'react';
2 | import { UserContext } from './userContext';
3 | import callService from '../../services/callService';
4 | import HelpService from '../../services/Help';
5 |
6 | export const HelpContext = createContext();
7 |
8 | export default function HelpContextProvider(props) {
9 | const { user } = useContext(UserContext);
10 |
11 | async function finishHelpByOwner(helpId) {
12 | const finishHelpRequest = await callService(
13 | HelpService,
14 | 'finishHelpByOwner',
15 | [helpId, user._id],
16 | );
17 | if (!finishHelpRequest.error) {
18 | return true;
19 | }
20 | return false;
21 | }
22 |
23 | const contextValue = useMemo(() => {
24 | return {
25 | finishHelpByOwner,
26 | };
27 | }, [finishHelpByOwner]);
28 |
29 | return (
30 |
31 | {props.children}
32 |
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/store/contexts/loadingContext.jsx:
--------------------------------------------------------------------------------
1 | import React, { createContext, useMemo, useState } from 'react';
2 | import { LoadingIndicator } from '../../components/LoadingIndicator';
3 |
4 | export const LoadingContext = createContext({});
5 |
6 | export const LoadingContextProvider = ({ children }) => {
7 | const [isLoading, setIsLoading] = useState(false);
8 |
9 | const contextValue = useMemo(() => {
10 | return {
11 | isLoading,
12 | setIsLoading,
13 | };
14 | }, [isLoading]);
15 |
16 | return (
17 |
18 | {isLoading && }
19 | {children}
20 |
21 | );
22 | };
23 |
--------------------------------------------------------------------------------
/app/src/store/contexts/timelineContext.jsx:
--------------------------------------------------------------------------------
1 | import React, { createContext, useContext, useMemo } from 'react';
2 | import callService from '../../services/callService';
3 | import { LoadingContext } from './loadingContext';
4 | import { UserContext } from './userContext';
5 | import timelineService from '../../services/Timeline';
6 |
7 | export const TimelineContext = createContext({});
8 |
9 | export const TimelineContextProvider = ({ children }) => {
10 | const { setIsLoading } = useContext(LoadingContext);
11 | const { user } = useContext(UserContext);
12 |
13 | const getTimelineItems = async () => {
14 | setIsLoading(true);
15 | const response = await callService(
16 | timelineService,
17 | 'getTimelineByUserId',
18 | [user._id],
19 | );
20 | setIsLoading(false);
21 | return response;
22 | };
23 |
24 | const contextValue = useMemo(() => {
25 | return {
26 | getTimelineItems,
27 | };
28 | }, [getTimelineItems]);
29 |
30 | return (
31 |
32 | {children}
33 |
34 | );
35 | };
36 |
--------------------------------------------------------------------------------
/app/src/store/reducers/helpReducer.js:
--------------------------------------------------------------------------------
1 | import actions from '../actions';
2 |
3 | const helpReducer = (state, action) => {
4 | switch (action.type) {
5 | case actions.help.storeList:
6 | return action.helps;
7 | default:
8 | return state;
9 | }
10 | };
11 |
12 | export default helpReducer;
13 |
--------------------------------------------------------------------------------
/app/src/store/reducers/userReducer.js:
--------------------------------------------------------------------------------
1 | import actions from '../actions';
2 |
3 | export const userReducer = (state, action) => {
4 | switch (action.type) {
5 | case actions.user.storeUserInfo:
6 | return {
7 | showSplash: false,
8 | ...action.data,
9 | };
10 | case actions.user.requestSignIn:
11 | return {
12 | showSplash: false,
13 | };
14 | case actions.user.removeUserInfo:
15 | return {};
16 |
17 | default:
18 | return state;
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/app/src/utils/Alert.js:
--------------------------------------------------------------------------------
1 | import { Alert } from 'react-native';
2 | import translateFirebaseError from '../utils/translateFirebaseAuthError';
3 | import firebaseService from '../services/Firebase';
4 |
5 | function alertError(error, message = null) {
6 | let type = 'Ooops..';
7 | if (error) {
8 | if (error.message === 'Network Error') {
9 | message = 'Falha de conexão';
10 | } else if (error.code) {
11 | message = translateFirebaseError[error.code];
12 | }
13 | if (message == null) {
14 | try {
15 | message =
16 | error.response.data.error ||
17 | error.message ||
18 | 'Algo deu errado, tente novamente mais tarde';
19 | } catch (err) {
20 | message =
21 | error.message ||
22 | 'Algo deu errado, tente novamente mais tarde';
23 | }
24 | }
25 | }
26 | Alert.alert(type, message);
27 | }
28 |
29 | function alertSuccess(message) {
30 | Alert.alert('Sucesso', message);
31 | }
32 |
33 | function alertMessage(message) {
34 | Alert.alert(null, message);
35 | }
36 | function alertMessageEmailVerification(message) {
37 | Alert.alert('Email não verificado', message, [
38 | {
39 | text: 'Reenviar email',
40 | onPress: async () => {
41 | await firebaseService.sendEmailVerification();
42 | alertSuccess(
43 | 'Email enviado com sucesso! Verifique sua caixa de entrada e também sua caixa de spam.',
44 | );
45 | },
46 | style: 'cancel',
47 | },
48 | { text: 'OK', onPress: () => {} },
49 | ]);
50 | }
51 |
52 | export {
53 | alertSuccess,
54 | alertError,
55 | alertMessage,
56 | alertMessageEmailVerification,
57 | };
58 |
--------------------------------------------------------------------------------
/app/src/utils/ToastAndroid.js:
--------------------------------------------------------------------------------
1 | import { ToastAndroid } from 'react-native';
2 |
3 | export default function (message) {
4 | ToastAndroid.showWithGravityAndOffset(
5 | message,
6 | ToastAndroid.LONG,
7 | ToastAndroid.CENTER,
8 | 25,
9 | 50,
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/utils/callNumber.js:
--------------------------------------------------------------------------------
1 | import { Linking } from 'react-native';
2 |
3 | export default function callNumber(phoneNumber) {
4 | Linking.openURL(`tel:${phoneNumber}`);
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/utils/cnpjValidator.js:
--------------------------------------------------------------------------------
1 | import isAllEqual from './isAllEqual';
2 |
3 | const cnpjValidator = (rawCnpj) => {
4 | const findNonNumbers = /([^0-9])+/g;
5 |
6 | let cnpj = rawCnpj.replace(findNonNumbers, '');
7 | if (isAllEqual(cnpj) || cnpj.length != 14) return false;
8 | let digitPosition = 2;
9 | let multiplier = 5;
10 | while (digitPosition > 0) {
11 | let index = 0;
12 | let verifierDigit = 0;
13 | let repeatCycle = 0;
14 | while (repeatCycle < 2) {
15 | for (let i = multiplier; i > 1; i--, index++)
16 | verifierDigit += Number(cnpj[index]) * i;
17 | multiplier = 9;
18 | repeatCycle++;
19 | }
20 |
21 | verifierDigit = verifierDigit % 11;
22 | if (verifierDigit < 2) verifierDigit = 0;
23 | else verifierDigit = 11 - verifierDigit;
24 | if (verifierDigit != Number(cnpj[cnpj.length - digitPosition])) {
25 | return false;
26 | }
27 | multiplier = 6;
28 | digitPosition--;
29 | }
30 | return true;
31 | };
32 |
33 | export default cnpjValidator;
34 |
--------------------------------------------------------------------------------
/app/src/utils/cpfValidator.js:
--------------------------------------------------------------------------------
1 | import isAllEqual from './isAllEqual';
2 |
3 | function cpfValidator(cpf) {
4 | cpf = cpf.replace(/[^\d]+/g, '');
5 | if (cpf == '') return false;
6 | if (cpf.length != 11 || isAllEqual(cpf)) return false;
7 | let add = 0;
8 | let rev;
9 | for (let i = 0; i < 9; i++) add += parseInt(cpf.charAt(i)) * (10 - i);
10 | rev = 11 - (add % 11);
11 | if (rev == 10 || rev == 11) rev = 0;
12 | if (rev != parseInt(cpf.charAt(9))) return false;
13 | add = 0;
14 | for (let i = 0; i < 10; i++) add += parseInt(cpf.charAt(i)) * (11 - i);
15 | rev = 11 - (add % 11);
16 | if (rev == 10 || rev == 11) rev = 0;
17 | if (rev != parseInt(cpf.charAt(10))) return false;
18 | return true;
19 | }
20 |
21 | export default cpfValidator;
22 |
--------------------------------------------------------------------------------
/app/src/utils/createInteraction.js:
--------------------------------------------------------------------------------
1 | import verifyUserInfo from './verifyUserInfo';
2 |
3 | export default function createInteraction(user, navigation, nextPage) {
4 | if (verifyUserInfo(user)) {
5 | navigation.navigate(nextPage);
6 | } else {
7 | navigation.navigate('address', { nextPage });
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/utils/dateValidator.js:
--------------------------------------------------------------------------------
1 | import moment from 'moment';
2 | export default function dateValidator(date) {
3 | // 17/02/1999
4 | let currentYear = moment().format('YYYY');
5 | currentYear = parseInt(currentYear);
6 |
7 | const [day, month, year] = date.split('/').map((date) => parseInt(date)); // [17, 02, 1999]
8 |
9 | if (day < 1 || day > 31 || !day) return false;
10 | if (month < 1 || month > 12 || !month) return false;
11 |
12 | if (year < 1800 || year > currentYear || !year) {
13 | if (month == 2) {
14 | if (year % 4 == 0) {
15 | if (day < 1 || day > 29) {
16 | return false;
17 | }
18 | }
19 | }
20 | return false;
21 | }
22 |
23 | return true;
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/utils/emailValidator.js:
--------------------------------------------------------------------------------
1 | const validationEmail = (email) => {
2 | const expression = /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,4})+$/;
3 |
4 | return expression.test(String(email).toLowerCase());
5 | };
6 |
7 | export default validationEmail;
8 |
--------------------------------------------------------------------------------
/app/src/utils/formatCNPJ.js:
--------------------------------------------------------------------------------
1 | function formatCNPJ(cnpj) {
2 | if (cnpj.length !== 14) {
3 | return '';
4 | }
5 | return `${cnpj.slice(0, 2)}.${cnpj.slice(2, 5)}.${cnpj.slice(
6 | 5,
7 | 8,
8 | )}/${cnpj.slice(8, 12)}-${cnpj.slice(12, 14)}`;
9 | }
10 |
11 | export default formatCNPJ;
12 |
--------------------------------------------------------------------------------
/app/src/utils/formatCpf.js:
--------------------------------------------------------------------------------
1 | function formatCPF(cpf) {
2 | if (cpf.length !== 11) {
3 | return '';
4 | }
5 |
6 | return `${cpf.slice(0, 3)}.${cpf.slice(3, 6)}.${cpf.slice(
7 | 6,
8 | 9,
9 | )}-${cpf.slice(9, 11)}`;
10 | }
11 |
12 | export default formatCPF;
13 |
--------------------------------------------------------------------------------
/app/src/utils/formatDate.js:
--------------------------------------------------------------------------------
1 | const formatDate = (date, character = '/') => {
2 | const dateArray = date.split(character);
3 | const year = character == '-' ? dateArray[2].substring(0, 2) : dateArray[2];
4 | const month = dateArray[1];
5 | const day = dateArray[0];
6 | return `${year}-${month}-${day}`;
7 | };
8 |
9 | export default formatDate;
10 |
--------------------------------------------------------------------------------
/app/src/utils/formatPhone.js:
--------------------------------------------------------------------------------
1 | function formatPhone(phone) {
2 | if (phone.length === 13) {
3 | return `(${phone.slice(3, 5)}) ${phone.slice(5, 9)}-${phone.slice(
4 | 9,
5 | 14,
6 | )}`;
7 | }
8 |
9 | return `(${phone.slice(3, 5)}) ${phone.slice(5, 10)}-${phone.slice(
10 | 10,
11 | 14,
12 | )}`;
13 | }
14 | export default formatPhone;
15 |
--------------------------------------------------------------------------------
/app/src/utils/getActivityIcon.js:
--------------------------------------------------------------------------------
1 | function getActivityIcon(activityType) {
2 | const activitiesVariants = {
3 | help: {
4 | name: 'exclamation',
5 | type: 'font-awesome',
6 | },
7 | offer: {
8 | name: 'volunteer-activism',
9 | type: 'material',
10 | },
11 | campaign: {
12 | name: 'home',
13 | type: 'material',
14 | },
15 | };
16 | return activitiesVariants[activityType];
17 | }
18 |
19 | export default getActivityIcon;
20 |
--------------------------------------------------------------------------------
/app/src/utils/getPastTime.js:
--------------------------------------------------------------------------------
1 | export default function getPastDate(date) {
2 | let dateFormated = new Date(date);
3 | let dateNow = new Date();
4 | let interval = dateNow.getTime() - dateFormated.getTime();
5 | interval = new Date(interval);
6 | // Qualquer data registrada é contada a partir de 1970,
7 | //então para pegar a quantidade certa de anos que passaram substraísse 1970.
8 | let yearsPassed = interval.getUTCFullYear() - 1970;
9 | let monthsPassed = interval.getUTCMonth();
10 | // Dia começa em 1, então para pegar a quantidade certa de dias substraísse 1.
11 | let daysPassed = interval.getUTCDate() - 1;
12 | let hoursPassed = interval.getUTCHours();
13 | let minutesPassed = interval.getUTCMinutes();
14 |
15 | if (yearsPassed < 0) {
16 | return 'Agora';
17 | } else if (yearsPassed > 0) {
18 | return `${yearsPassed} ano(s) atrás`;
19 | } else if (monthsPassed > 0) {
20 | return `${monthsPassed} mês(es) atrás`;
21 | } else if (daysPassed > 0) {
22 | return `${daysPassed} dia(s) atrás`;
23 | } else if (hoursPassed > 0) {
24 | return `${hoursPassed} hora(s) atrás`;
25 | } else if (minutesPassed > 0) {
26 | return `${minutesPassed} minuto atrás`;
27 | } else {
28 | return 'Agora';
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/utils/getScreenTitle.js:
--------------------------------------------------------------------------------
1 | export const getScreenTtile = (screenName, hasTitle = true) => {
2 | if (!hasTitle) return '';
3 | const screenTitles = {
4 | notificationsDrawer: 'Notificações',
5 | notifications: 'Notificações',
6 | homeDrawer: 'Mapa',
7 | activitiesDrawer: 'Atividades',
8 | profileDrawer: 'Perfil',
9 | helpDrawer: 'Ajuda',
10 | findUserDrawer: 'Procurar Usuários',
11 | home: 'Mapa',
12 | activities: 'Atividades',
13 | createHelpRequest: 'Criar Pedido',
14 | createHelpOffer: 'Criar Oferta',
15 | createCampaign: 'Criar Campanha',
16 | profile: 'Perfil',
17 | searchUsers: 'Buscar Usuários',
18 | address: 'Endereço',
19 | photo: 'Foto',
20 | feedbacks: 'Feedbacks',
21 | timeline: 'Linha do Tempo',
22 | };
23 | return screenTitles[screenName] || 'Detalhes';
24 | };
25 |
--------------------------------------------------------------------------------
/app/src/utils/getSliderBody.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Step1 from '../../assets/images/TutorialImages/Step1.svg';
3 | import Step2 from '../../assets/images/TutorialImages/Step2.svg';
4 | import Step3 from '../../assets/images/TutorialImages/Step3.svg';
5 | import colors from '../../assets/styles/colorVariables';
6 | import { SliderDescription } from '../components/atoms/SliderDescription';
7 | import { SliderTitle } from '../components/atoms/SliderTitle';
8 |
9 | export const getSliderBody = (index, title, subtitle) => {
10 | const stepImages = {
11 | 1: ,
12 | 2: ,
13 | 3: ,
14 | };
15 | const image = stepImages[index];
16 | return {
17 | backgroundColor: colors.light,
18 | image,
19 | title: ,
20 | subtitle: ,
21 | };
22 | };
23 |
--------------------------------------------------------------------------------
/app/src/utils/getYearsSince.js:
--------------------------------------------------------------------------------
1 | import moment from 'moment';
2 |
3 | const getYearsSince = (date) => {
4 | return moment().diff(date, 'years');
5 | };
6 |
7 | export default getYearsSince;
8 |
--------------------------------------------------------------------------------
/app/src/utils/helpDistance.js:
--------------------------------------------------------------------------------
1 | function deg2rad(deg) {
2 | return deg * (Math.PI / 180);
3 | }
4 |
5 | export function calculateDistance(centerCoordinates, pointCoordinates) {
6 | const radius = 6371;
7 |
8 | const { latitude: lat1, longitude: lon1 } = centerCoordinates;
9 | const { latitude: lat2, longitude: lon2 } = pointCoordinates;
10 |
11 | const dLat = deg2rad(lat2 - lat1);
12 | const dLon = deg2rad(lon2 - lon1);
13 |
14 | const a =
15 | Math.sin(dLat / 2) * Math.sin(dLat / 2) +
16 | Math.cos(deg2rad(lat1)) *
17 | Math.cos(deg2rad(lat2)) *
18 | Math.sin(dLon / 2) *
19 | Math.sin(dLon / 2);
20 |
21 | const center = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
22 | return radius * center;
23 | }
24 |
25 | function getDistanceInKm(centerCoordinates, pointCoordinates) {
26 | let distance = calculateDistance(centerCoordinates, pointCoordinates);
27 | distance =
28 | distance > 1
29 | ? `${distance.toFixed(2)} km`
30 | : `${(distance * 1000).toFixed(0)} m`;
31 |
32 | return distance;
33 | }
34 |
35 | export default getDistanceInKm;
36 |
--------------------------------------------------------------------------------
/app/src/utils/isAllEqual.js:
--------------------------------------------------------------------------------
1 | const isAllEqual = (value) => {
2 | for (let i = 1; i < value.length; i++) {
3 | if (value[i] != value[i - 1]) return false;
4 | }
5 | return true;
6 | };
7 |
8 | export default isAllEqual;
9 |
--------------------------------------------------------------------------------
/app/src/utils/isRecentDate.js:
--------------------------------------------------------------------------------
1 | const isRecentDate = (date, recentDays = 15) => {
2 | if (!date) return;
3 | const today = new Date();
4 | const parsedDate = new Date(date);
5 | const daysDiff = (today - parsedDate) / (1000 * 60 * 60 * 24);
6 | return recentDays >= daysDiff;
7 | };
8 |
9 | export default isRecentDate;
10 |
--------------------------------------------------------------------------------
/app/src/utils/messageOperation.js:
--------------------------------------------------------------------------------
1 | class MessageOperation {
2 | offer(isMessage, callBackRemoveOffer) {
3 | if (isMessage) {
4 | callBackRemoveOffer();
5 | return 'Sua candidatura foi enviada com sucesso e estará no aguardo para ser aceita';
6 | }
7 | return 'participateHelpOffer';
8 | }
9 |
10 | help(isMessage, callBackRemoveHelp) {
11 | if (isMessage) {
12 | callBackRemoveHelp();
13 | return 'Oferta enviada com sucesso e estará no aguardo para ser aceita';
14 | }
15 | return 'offerHelp';
16 | }
17 | }
18 |
19 | const messageOperation = new MessageOperation();
20 | export default messageOperation;
21 |
--------------------------------------------------------------------------------
/app/src/utils/navigateToCreateFlow.js:
--------------------------------------------------------------------------------
1 | export default function navigateToCreateFlow(
2 | navigation,
3 | title,
4 | category,
5 | description,
6 | requestType,
7 | ) {
8 | navigation.navigate('location', {
9 | requestInfo: {
10 | title,
11 | category,
12 | description,
13 | },
14 | requestType,
15 | });
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/utils/navigateToDescription.js:
--------------------------------------------------------------------------------
1 | import verifyUserInfo from './verifyUserInfo';
2 |
3 | export default function navigateToDescription(
4 | user,
5 | navigation,
6 | id,
7 | ownerId,
8 | type,
9 | handleShowModal,
10 | ) {
11 | const isUserVerified = verifyUserInfo(user);
12 | const params = [id, ownerId, type, navigation];
13 |
14 | if (isUserVerified) {
15 | handleShowModal(...params);
16 | } else {
17 | navigation.navigate('address', {
18 | modalParams: params,
19 | });
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/utils/navigateToMyActivity.js:
--------------------------------------------------------------------------------
1 | export default function navigateToMyActivity(navigation, activity, type) {
2 | const helpNavigation = {
3 | offer: 'myOfferHelpDescription',
4 | help: 'myRequestHelpDescription',
5 | campaign: 'campaignDescription',
6 | };
7 |
8 | const helpParams = {
9 | offer: { routeId: 'HelpOffer', helpId: activity._id },
10 | help: { routeId: 'Help', helpId: activity._id },
11 | campaign: { campaign: activity },
12 | };
13 |
14 | navigation.navigate(helpNavigation[type], { ...helpParams[type] });
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/utils/openMaps.js:
--------------------------------------------------------------------------------
1 | import { Linking, Platform } from 'react-native';
2 |
3 | export const openMaps = (latitude, longitude, mapLabel) => {
4 | const scheme = Platform.select({
5 | ios: 'maps:0,0?q=',
6 | android: 'geo:0,0?q=',
7 | });
8 |
9 | const coordinates = `${latitude},${longitude}`;
10 | const url = Platform.select({
11 | ios: `${scheme}${mapLabel}@${coordinates}`,
12 | android: `${scheme}${coordinates}(${mapLabel})`,
13 | });
14 | Linking.openURL(url);
15 | };
16 |
--------------------------------------------------------------------------------
/app/src/utils/openWhatsapp.js:
--------------------------------------------------------------------------------
1 | import { Linking } from 'react-native';
2 | import { alertMessage } from './Alert';
3 |
4 | export default function openWhatsapp(
5 | phoneNumber,
6 | message = 'Olá, precisa de ajuda?',
7 | ) {
8 | Linking.openURL(
9 | `whatsapp://send?phone=${phoneNumber}&text=${message}`,
10 | ).catch(() => alertMessage('Não foi possível abrir o Whatsapp.'));
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/utils/parseDate.js:
--------------------------------------------------------------------------------
1 | function parseDate(date) {
2 | if (!date) return;
3 | const newDate = new Date(date);
4 | return `${('0' + (newDate.getDate() + 1)).slice(-2)}/${(
5 | '0' +
6 | (newDate.getMonth() + 1)
7 | ).slice(-2)}/${newDate.getFullYear()}`;
8 | }
9 |
10 | export default parseDate;
11 |
--------------------------------------------------------------------------------
/app/src/utils/passwordValidator.js:
--------------------------------------------------------------------------------
1 | const passwordValidator = (password) => {
2 | if (password == '' || password.length < 8) {
3 | return false;
4 | }
5 | return true;
6 | };
7 |
8 | export default passwordValidator;
9 |
--------------------------------------------------------------------------------
/app/src/utils/phoneValidator.js:
--------------------------------------------------------------------------------
1 | export default function phoneValidator(phone) {
2 | if (phone.length >= 14) {
3 | return true;
4 | } else {
5 | return false;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/utils/removeSpecialChars.js:
--------------------------------------------------------------------------------
1 | function extractNumbers(text) {
2 | return text.replace(/[^\d]+/g, '');
3 | }
4 |
5 | export default extractNumbers;
6 |
--------------------------------------------------------------------------------
/app/src/utils/riskGroupsObject.js:
--------------------------------------------------------------------------------
1 | const riskGroups = {
2 | dc: 'Doença respiratória',
3 | hiv: 'HIV',
4 | diab: 'Diabetes',
5 | hiperT: 'Hipertensão',
6 | doenCardio: 'Doenças cardiovasculares',
7 | };
8 |
9 | export default riskGroups;
10 |
--------------------------------------------------------------------------------
/app/src/utils/shortenName.js:
--------------------------------------------------------------------------------
1 | export default function shortenName(name) {
2 | if (!name) return;
3 | return name.split(' ').slice(0, 2).join(' ');
4 | }
5 |
6 | export function untilTwoLastNames(name) {
7 | return name.split(' ').slice(0, 3).join(' ');
8 | }
9 |
10 | export function firstName(name) {
11 | return name.split(' ').slice(0, 1).join(' ');
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/utils/showDrawerButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { DrawerButton } from '../components/atoms/DrawerButton';
3 |
4 | export const showDrawerButton = ({ navigation }) => ({
5 | headerLeft: () => ,
6 | });
7 |
--------------------------------------------------------------------------------
/app/src/utils/translateFirebaseAuthError.js:
--------------------------------------------------------------------------------
1 | const errorMessages = {
2 | 'auth/user-not-found': 'Email não encontrado.',
3 | 'auth/wrong-password': 'Senha inválida.',
4 | 'auth/invalid-email': 'Email inválido.',
5 | 'auth/too-many-requests':
6 | 'Foram feitas muitas tentativas de login com esse email. Tente novamente mais tarde.',
7 | ' auth/invalid-password': 'Senha inválida.',
8 | 'auth/email-not-verified':
9 | 'Se você não recebeu um email de verificação, tente reenviar o email e checar também em sua caixa de spam',
10 | };
11 |
12 | export default errorMessages;
13 |
--------------------------------------------------------------------------------
/app/src/utils/translatedActivities.js:
--------------------------------------------------------------------------------
1 | export const translatedActivities = {
2 | help: {
3 | translation: 'Pedido',
4 | },
5 | offer: {
6 | translation: 'Oferta',
7 | },
8 | campaign: {
9 | translation: 'Campanha',
10 | },
11 | };
12 |
--------------------------------------------------------------------------------
/app/src/utils/verifyUserInfo.js:
--------------------------------------------------------------------------------
1 | export default function verifyUserInfo(user) {
2 | return !!user.photo && !!user.address;
3 | }
4 |
--------------------------------------------------------------------------------
/app/src/utils/warningPopUp.js:
--------------------------------------------------------------------------------
1 | import { Alert } from 'react-native';
2 | import AsyncStorage from '@react-native-async-storage/async-storage';
3 |
4 | async function showWarning(warningType, message) {
5 | const dontShowAgainPressed = await AsyncStorage.getItem(warningType);
6 | if (dontShowAgainPressed) return;
7 |
8 | Alert.alert('Importante', message, [
9 | {
10 | text: 'Não mostrar novamente',
11 | onPress: async () =>
12 | await AsyncStorage.setItem(warningType, 'true'),
13 | },
14 | {
15 | text: 'Ok',
16 | onPress: () => {},
17 | },
18 | ]);
19 | }
20 |
21 | export default showWarning;
22 |
--------------------------------------------------------------------------------
/app/tailwind.config.js:
--------------------------------------------------------------------------------
1 | const colors = require('./colors');
2 |
3 | module.exports = {
4 | content: ['./App.{js,jsx,ts,tsx}', './src/**/*.{js,jsx,ts,tsx}'],
5 | theme: {
6 | extend: {
7 | colors: colors,
8 | spacing: {
9 | 38: '9.5rem',
10 | },
11 | fontSize: {
12 | xss: '10px',
13 | },
14 | },
15 | fontFamily: {
16 | 'ms-bold': ['montserrat-bold'],
17 | 'ms-semibold': ['montserrat-semibold'],
18 | 'ms-medium': ['montserrat-medium'],
19 | 'ms-regular': ['montserrat-regular'],
20 | 'ms-light': ['montserrat-light'],
21 | },
22 | },
23 | plugins: [],
24 | };
25 |
--------------------------------------------------------------------------------