├── .watchmanconfig
├── .gitattributes
├── app.json
├── babel.config.js
├── src
├── assets
│ └── images
│ │ ├── Add.png
│ │ ├── close.zip
│ │ ├── logo.png
│ │ ├── AddIcon.png
│ │ ├── ChatIcon.png
│ │ ├── DenyIcon.png
│ │ ├── Eye-Off.png
│ │ ├── Eye-On.png
│ │ ├── EyeIcon.png
│ │ ├── GrayAdd.png
│ │ ├── HomeIcon.png
│ │ ├── LikeIcon.png
│ │ ├── MoreIcon.png
│ │ ├── People.png
│ │ ├── Success.png
│ │ ├── asianjim.jpg
│ │ ├── AcceptIcon.png
│ │ ├── BackArrow.png
│ │ ├── CameraIcon.png
│ │ ├── CloseIcon.png
│ │ ├── DeleteIcon.png
│ │ ├── EndOfPosts.png
│ │ ├── RightArrow.png
│ │ ├── checkmark.png
│ │ ├── pam-beesly.jpg
│ │ ├── AddMemberIcon.png
│ │ ├── GroupDefault.png
│ │ ├── MessageIcon.png
│ │ ├── NewGroupIcon.png
│ │ ├── NewPostIcon.png
│ │ ├── PeopleGreen.png
│ │ ├── RemovePhoto.png
│ │ ├── SettingsIcon.png
│ │ ├── orangeArrow.png
│ │ ├── BackArrowBlack.png
│ │ ├── EditIconPencil.png
│ │ ├── GroupAdminIcon.png
│ │ ├── HomeIconFilled.png
│ │ ├── LeaveGroupIcon.png
│ │ ├── MoreIconFilled.png
│ │ ├── SingleUserIcon.png
│ │ ├── SmallArrowDown.png
│ │ ├── arrowRightWhite.png
│ │ ├── AssignasAdminIcon.png
│ │ ├── EmptyResourceImage.png
│ │ ├── EmptyResourceLarge.png
│ │ ├── ImagePlaceholder.png
│ │ ├── MessageIconFilled.png
│ │ ├── MessageMemberIcon.png
│ │ ├── NotificationIcon.png
│ │ ├── PhotoLibraryIcon.png
│ │ ├── SuccessBlackRing.png
│ │ ├── ChatIconHighlighted.png
│ │ ├── LikeIconHighlighted.png
│ │ └── NotificationIconFilled.png
├── components
│ ├── LogoIcon.js
│ ├── Icon.js
│ ├── Global
│ │ └── colors.js
│ ├── Label.js
│ ├── Timestamp.js
│ ├── AboutCard.js
│ ├── TextButton.js
│ ├── SectionCard.js
│ ├── LoadMoreCard.js
│ ├── TransparentInput.js
│ ├── SectionCardCentered.js
│ ├── LargeButton.js
│ ├── ActionSheetItem.js
│ ├── BottomActionButton.js
│ ├── NewComment.js
│ ├── ImagePicker.js
│ ├── SearchBar.js
│ ├── NothingHereYetCard.js
│ ├── AllCaughtUpCard.js
│ ├── BottomOfPostsCard.js
│ ├── TextField.js
│ ├── ImagePreview.js
│ ├── ReactionTabBar.js
│ ├── CommentReactionItem.js
│ ├── Avatar.js
│ ├── LikeReactionItem.js
│ ├── SwitchCard.js
│ ├── AutoGrowTextField.js
│ ├── PagingView.js
│ ├── LayoutScrollViewWithHeader.js
│ ├── PickerItem.js
│ ├── FeedCardMainImage.js
│ ├── ActionSheet.js
│ ├── Header.js
│ ├── HeaderDetail.js
│ ├── ProfileItemCard.js
│ └── CommentCard.js
├── redux
│ ├── actions
│ │ ├── tabBar.actions.js
│ │ ├── loginType.actions.js
│ │ ├── messageIndicator.actions.js
│ │ ├── notificationIndicator.actions.js
│ │ ├── categories.actions.js
│ │ ├── resources.actions.js
│ │ └── organizations.actions.js
│ ├── reducers
│ │ ├── loginType.reducer.js
│ │ ├── tabBar.reducer.js
│ │ ├── messageIndicator.reducer.js
│ │ ├── notificationIndicator.reducer.js
│ │ ├── resources.reducer.js
│ │ ├── categories.reducer.js
│ │ ├── otherUsers.reducer.js
│ │ ├── organizations.reducer.js
│ │ ├── users.reducer.js
│ │ ├── conversations.reducer.js
│ │ ├── singlePost.reducer.js
│ │ ├── notifications.reducer.js
│ │ ├── index.js
│ │ ├── groups.reducer.js
│ │ └── posts.reducer.js
│ └── api
│ │ ├── resources.js
│ │ ├── categories.js
│ │ ├── organizations.js
│ │ ├── conversations.js
│ │ ├── notifications.js
│ │ ├── users.js
│ │ ├── groups.js
│ │ └── posts.js
├── navigation
│ ├── MainSwitchNavigator.js
│ ├── MainFeedStack.js
│ ├── SettingsStack.js
│ ├── MessagesStack.js
│ ├── AuthStack.js
│ └── TabNavigator.js
├── util
│ ├── helpers.js
│ └── data.js
├── screens
│ ├── MainScreen.js
│ ├── LaunchScreen.js
│ ├── ProfileScreen.js
│ └── ForgotPasswordScreen.js
└── constants
│ └── urls.js
├── android
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── values
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ └── mipmap-xxxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ ├── assets
│ │ │ │ └── fonts
│ │ │ │ │ ├── Entypo.ttf
│ │ │ │ │ ├── Feather.ttf
│ │ │ │ │ ├── Zocial.ttf
│ │ │ │ │ ├── AntDesign.ttf
│ │ │ │ │ ├── EvilIcons.ttf
│ │ │ │ │ ├── Ionicons.ttf
│ │ │ │ │ ├── Octicons.ttf
│ │ │ │ │ ├── FontAwesome.ttf
│ │ │ │ │ ├── Foundation.ttf
│ │ │ │ │ ├── MaterialIcons.ttf
│ │ │ │ │ ├── SimpleLineIcons.ttf
│ │ │ │ │ ├── FontAwesome5_Brands.ttf
│ │ │ │ │ ├── FontAwesome5_Solid.ttf
│ │ │ │ │ ├── FontAwesome5_Regular.ttf
│ │ │ │ │ └── MaterialCommunityIcons.ttf
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── reactnativetemplate
│ │ │ │ │ ├── MainActivity.java
│ │ │ │ │ └── MainApplication.java
│ │ │ └── AndroidManifest.xml
│ │ └── debug
│ │ │ └── AndroidManifest.xml
│ ├── build_defs.bzl
│ ├── proguard-rules.pro
│ └── BUCK
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── keystores
│ ├── debug.keystore.properties
│ └── BUCK
├── gradle.properties
├── settings.gradle
├── build.gradle
└── gradlew.bat
├── ios
├── ReactNativeTemplate
│ ├── Images.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── AppDelegate.h
│ ├── main.m
│ ├── AppDelegate.m
│ ├── Info.plist
│ └── Base.lproj
│ │ └── LaunchScreen.xib
├── ReactNativeTemplateTests
│ ├── Info.plist
│ └── ReactNativeTemplateTests.m
├── ReactNativeTemplate-tvOSTests
│ └── Info.plist
├── ReactNativeTemplate-tvOS
│ └── Info.plist
└── ReactNativeTemplate.xcodeproj
│ └── xcshareddata
│ └── xcschemes
│ ├── ReactNativeTemplate.xcscheme
│ └── ReactNativeTemplate-tvOS.xcscheme
├── .buckconfig
├── index.js
├── __tests__
└── App-test.js
├── .eslintrc.json
├── metro.config.js
├── App.js
├── .gitignore
├── README.MD
├── package.json
└── .flowconfig
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ReactNativeTemplate",
3 | "displayName": "ReactNativeTemplate"
4 | }
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset'],
3 | };
4 |
--------------------------------------------------------------------------------
/src/assets/images/Add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/Add.png
--------------------------------------------------------------------------------
/src/assets/images/close.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/close.zip
--------------------------------------------------------------------------------
/src/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/logo.png
--------------------------------------------------------------------------------
/src/assets/images/AddIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/AddIcon.png
--------------------------------------------------------------------------------
/src/assets/images/ChatIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/ChatIcon.png
--------------------------------------------------------------------------------
/src/assets/images/DenyIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/DenyIcon.png
--------------------------------------------------------------------------------
/src/assets/images/Eye-Off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/Eye-Off.png
--------------------------------------------------------------------------------
/src/assets/images/Eye-On.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/Eye-On.png
--------------------------------------------------------------------------------
/src/assets/images/EyeIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/EyeIcon.png
--------------------------------------------------------------------------------
/src/assets/images/GrayAdd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/GrayAdd.png
--------------------------------------------------------------------------------
/src/assets/images/HomeIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/HomeIcon.png
--------------------------------------------------------------------------------
/src/assets/images/LikeIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/LikeIcon.png
--------------------------------------------------------------------------------
/src/assets/images/MoreIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/MoreIcon.png
--------------------------------------------------------------------------------
/src/assets/images/People.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/People.png
--------------------------------------------------------------------------------
/src/assets/images/Success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/Success.png
--------------------------------------------------------------------------------
/src/assets/images/asianjim.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/asianjim.jpg
--------------------------------------------------------------------------------
/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ReactNativeTemplate
3 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/AcceptIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/AcceptIcon.png
--------------------------------------------------------------------------------
/src/assets/images/BackArrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/BackArrow.png
--------------------------------------------------------------------------------
/src/assets/images/CameraIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/CameraIcon.png
--------------------------------------------------------------------------------
/src/assets/images/CloseIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/CloseIcon.png
--------------------------------------------------------------------------------
/src/assets/images/DeleteIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/DeleteIcon.png
--------------------------------------------------------------------------------
/src/assets/images/EndOfPosts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/EndOfPosts.png
--------------------------------------------------------------------------------
/src/assets/images/RightArrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/RightArrow.png
--------------------------------------------------------------------------------
/src/assets/images/checkmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/checkmark.png
--------------------------------------------------------------------------------
/src/assets/images/pam-beesly.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/pam-beesly.jpg
--------------------------------------------------------------------------------
/ios/ReactNativeTemplate/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/assets/images/AddMemberIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/AddMemberIcon.png
--------------------------------------------------------------------------------
/src/assets/images/GroupDefault.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/GroupDefault.png
--------------------------------------------------------------------------------
/src/assets/images/MessageIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/MessageIcon.png
--------------------------------------------------------------------------------
/src/assets/images/NewGroupIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/NewGroupIcon.png
--------------------------------------------------------------------------------
/src/assets/images/NewPostIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/NewPostIcon.png
--------------------------------------------------------------------------------
/src/assets/images/PeopleGreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/PeopleGreen.png
--------------------------------------------------------------------------------
/src/assets/images/RemovePhoto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/RemovePhoto.png
--------------------------------------------------------------------------------
/src/assets/images/SettingsIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/SettingsIcon.png
--------------------------------------------------------------------------------
/src/assets/images/orangeArrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/orangeArrow.png
--------------------------------------------------------------------------------
/src/assets/images/BackArrowBlack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/BackArrowBlack.png
--------------------------------------------------------------------------------
/src/assets/images/EditIconPencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/EditIconPencil.png
--------------------------------------------------------------------------------
/src/assets/images/GroupAdminIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/GroupAdminIcon.png
--------------------------------------------------------------------------------
/src/assets/images/HomeIconFilled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/HomeIconFilled.png
--------------------------------------------------------------------------------
/src/assets/images/LeaveGroupIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/LeaveGroupIcon.png
--------------------------------------------------------------------------------
/src/assets/images/MoreIconFilled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/MoreIconFilled.png
--------------------------------------------------------------------------------
/src/assets/images/SingleUserIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/SingleUserIcon.png
--------------------------------------------------------------------------------
/src/assets/images/SmallArrowDown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/SmallArrowDown.png
--------------------------------------------------------------------------------
/src/assets/images/arrowRightWhite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/arrowRightWhite.png
--------------------------------------------------------------------------------
/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/src/assets/images/AssignasAdminIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/AssignasAdminIcon.png
--------------------------------------------------------------------------------
/src/assets/images/EmptyResourceImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/EmptyResourceImage.png
--------------------------------------------------------------------------------
/src/assets/images/EmptyResourceLarge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/EmptyResourceLarge.png
--------------------------------------------------------------------------------
/src/assets/images/ImagePlaceholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/ImagePlaceholder.png
--------------------------------------------------------------------------------
/src/assets/images/MessageIconFilled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/MessageIconFilled.png
--------------------------------------------------------------------------------
/src/assets/images/MessageMemberIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/MessageMemberIcon.png
--------------------------------------------------------------------------------
/src/assets/images/NotificationIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/NotificationIcon.png
--------------------------------------------------------------------------------
/src/assets/images/PhotoLibraryIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/PhotoLibraryIcon.png
--------------------------------------------------------------------------------
/src/assets/images/SuccessBlackRing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/SuccessBlackRing.png
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/src/assets/images/ChatIconHighlighted.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/ChatIconHighlighted.png
--------------------------------------------------------------------------------
/src/assets/images/LikeIconHighlighted.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/LikeIconHighlighted.png
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/Entypo.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/Entypo.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/Feather.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/Feather.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/Zocial.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/Zocial.ttf
--------------------------------------------------------------------------------
/src/assets/images/NotificationIconFilled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/src/assets/images/NotificationIconFilled.png
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/AntDesign.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/AntDesign.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/EvilIcons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/EvilIcons.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/Ionicons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/Ionicons.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/Octicons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/Octicons.ttf
--------------------------------------------------------------------------------
/android/keystores/debug.keystore.properties:
--------------------------------------------------------------------------------
1 | key.store=debug.keystore
2 | key.alias=androiddebugkey
3 | key.store.password=android
4 | key.alias.password=android
5 |
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/FontAwesome.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/FontAwesome.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/Foundation.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/Foundation.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/MaterialIcons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/MaterialIcons.ttf
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/SimpleLineIcons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/SimpleLineIcons.ttf
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/FontAwesome5_Brands.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/FontAwesome5_Brands.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/FontAwesome5_Solid.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/FontAwesome5_Solid.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/FontAwesome5_Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/FontAwesome5_Regular.ttf
--------------------------------------------------------------------------------
/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bekahlbaker/react-native-app-template/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/keystores/BUCK:
--------------------------------------------------------------------------------
1 | keystore(
2 | name = "debug",
3 | properties = "debug.keystore.properties",
4 | store = "debug.keystore",
5 | visibility = [
6 | "PUBLIC",
7 | ],
8 | )
9 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 |
5 | import {AppRegistry} from 'react-native';
6 | import App from './App';
7 | import {name as appName} from './app.json';
8 |
9 | AppRegistry.registerComponent(appName, () => App);
10 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
6 |
--------------------------------------------------------------------------------
/src/components/LogoIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Image } from 'react-native';
3 | import logo from '../assets/images/logo.png';
4 |
5 | const LogoIcon = props => {
6 | return ;
7 | };
8 |
9 | export default LogoIcon;
10 |
--------------------------------------------------------------------------------
/src/redux/actions/tabBar.actions.js:
--------------------------------------------------------------------------------
1 | export const SELECTED_TAB = 'SELECTED_TAB';
2 |
3 | export function setSelectedTab(tab) {
4 | return dispatch => {
5 | dispatch({
6 | type: SELECTED_TAB,
7 | payload: { selectedTab: tab, updatedAt: new Date() },
8 | });
9 | };
10 | }
11 |
--------------------------------------------------------------------------------
/src/redux/reducers/loginType.reducer.js:
--------------------------------------------------------------------------------
1 | import { SET_LOGIN_TYPE } from '../actions/loginType.actions';
2 |
3 | export default function(state = null, action) {
4 | switch (action.type) {
5 | default:
6 | return state;
7 | case SET_LOGIN_TYPE:
8 | return action.payload;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/Icon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components/native';
3 |
4 | const StyledIcon = styled.Image`
5 | width: ${props => props.size};
6 | height: ${props => props.size};
7 | `;
8 |
9 | export default (Icon = ({ source, size }) => (
10 |
11 | ));
12 |
--------------------------------------------------------------------------------
/__tests__/App-test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 |
5 | import 'react-native';
6 | import React from 'react';
7 | import App from '../App';
8 |
9 | // Note: test renderer must be required after react-native.
10 | import renderer from 'react-test-renderer';
11 |
12 | it('renders correctly', () => {
13 | renderer.create();
14 | });
15 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "rules": {
7 | "react/prop-types": 0,
8 | "react/jsx-filename-extension": 0,
9 | "class-methods-use-this": 0,
10 | "arrow-body-style": 0,
11 | "camelcase": 0
12 | },
13 | "parser": "babel-eslint",
14 | "extends": ["airbnb", "prettier"]
15 | }
16 |
--------------------------------------------------------------------------------
/src/redux/reducers/tabBar.reducer.js:
--------------------------------------------------------------------------------
1 | import { SELECTED_TAB } from '../actions/tabBar.actions';
2 |
3 | const initialState = { selectedTab: 'MainFeed' };
4 |
5 | export default function(state = initialState, action) {
6 | switch (action.type) {
7 | default:
8 | return state;
9 | case SELECTED_TAB:
10 | return action.payload;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/metro.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Metro configuration for React Native
3 | * https://github.com/facebook/react-native
4 | *
5 | * @format
6 | */
7 |
8 | module.exports = {
9 | transformer: {
10 | getTransformOptions: async () => ({
11 | transform: {
12 | experimentalImportSupport: false,
13 | inlineRequires: false,
14 | },
15 | }),
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/src/redux/reducers/messageIndicator.reducer.js:
--------------------------------------------------------------------------------
1 | import { MESSAGE_INDICATOR } from '../actions/messageIndicator.actions';
2 |
3 | const initialState = { shouldShow: false };
4 |
5 | export default function(state = initialState, action) {
6 | switch (action.type) {
7 | default:
8 | return state;
9 | case MESSAGE_INDICATOR:
10 | return action.payload;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/navigation/MainSwitchNavigator.js:
--------------------------------------------------------------------------------
1 | import { createSwitchNavigator, createAppContainer } from 'react-navigation';
2 |
3 | import AuthStack from './AuthStack';
4 | import TabNavigator from './TabNavigator';
5 |
6 | const MainSwitchNavigator = createSwitchNavigator({
7 | SignedOut: AuthStack,
8 | SignedIn: TabNavigator,
9 | });
10 |
11 | export default createAppContainer(MainSwitchNavigator);
12 |
--------------------------------------------------------------------------------
/src/redux/actions/loginType.actions.js:
--------------------------------------------------------------------------------
1 | export const SET_LOGIN_TYPE = 'SET_LOGIN_TYPE';
2 |
3 | // Need to set a login type when login action is sent
4 | // This prevents navigation from navigating to signed in several times
5 |
6 | export function setLoginType(type) {
7 | return dispatch => {
8 | dispatch({
9 | type: SET_LOGIN_TYPE,
10 | payload: type,
11 | });
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/src/redux/reducers/notificationIndicator.reducer.js:
--------------------------------------------------------------------------------
1 | import { NOTIFICATION_INDICATOR } from '../actions/notificationIndicator.actions';
2 |
3 | const initialState = { shouldShow: false };
4 |
5 | export default function(state = initialState, action) {
6 | switch (action.type) {
7 | default:
8 | return state;
9 | case NOTIFICATION_INDICATOR:
10 | return action.payload;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/redux/reducers/resources.reducer.js:
--------------------------------------------------------------------------------
1 | import { RESOURCES } from '../actions/resources.actions';
2 |
3 | // Initial state
4 | const initialState = { status: 'pending' };
5 |
6 | // Reducer
7 | export default function resources(state = initialState, action) {
8 | switch (action.type) {
9 | case RESOURCES:
10 | return { ...state, ...action.payload };
11 | default:
12 | return state;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/redux/reducers/categories.reducer.js:
--------------------------------------------------------------------------------
1 | import { CATEGORIES } from '../actions/categories.actions';
2 |
3 | // Initial state
4 | const initialState = { status: 'pending' };
5 |
6 | // Reducer
7 | export default function categories(state = initialState, action) {
8 | switch (action.type) {
9 | case CATEGORIES:
10 | return { ...state, ...action.payload };
11 | default:
12 | return state;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/redux/reducers/otherUsers.reducer.js:
--------------------------------------------------------------------------------
1 | import { OTHER_USER } from '../actions/users.actions';
2 |
3 | // Initial state
4 | const initialState = { auth: 'failed', error: '', message: '' };
5 |
6 | // Reducer
7 | export default function user(state = initialState, action) {
8 | switch (action.type) {
9 | case OTHER_USER:
10 | return { ...state, ...action.payload };
11 | default:
12 | return state;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/redux/reducers/organizations.reducer.js:
--------------------------------------------------------------------------------
1 | import { ORGANIZATIONS } from '../actions/organizations.actions';
2 |
3 | // Initial state
4 | const initialState = { status: 'pending' };
5 |
6 | // Reducer
7 | export default function organizations(state = initialState, action) {
8 | switch (action.type) {
9 | case ORGANIZATIONS:
10 | return { ...state, ...action.payload };
11 | default:
12 | return state;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/redux/actions/messageIndicator.actions.js:
--------------------------------------------------------------------------------
1 | export const MESSAGE_INDICATOR = 'MESSAGE_INDICATOR';
2 |
3 | // Need to set a login type when login action is sent
4 | // This prevents navigation from navigating to signed in several times
5 |
6 | export function setMessageIndicator(shouldShow) {
7 | return dispatch => {
8 | dispatch({
9 | type: MESSAGE_INDICATOR,
10 | payload: { shouldShow, updatedAt: new Date() },
11 | });
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/ios/ReactNativeTemplate/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (nonatomic, strong) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/ios/ReactNativeTemplate/main.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import
9 |
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/redux/actions/notificationIndicator.actions.js:
--------------------------------------------------------------------------------
1 | export const NOTIFICATION_INDICATOR = 'NOTIFICATION_INDICATOR';
2 |
3 | // Need to set a login type when login action is sent
4 | // This prevents navigation from navigating to signed in several times
5 |
6 | export function setNotificationIndicator(shouldShow) {
7 | return dispatch => {
8 | dispatch({
9 | type: NOTIFICATION_INDICATOR,
10 | payload: { shouldShow, updatedAt: new Date() },
11 | });
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/reactnativetemplate/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.reactnativetemplate;
2 |
3 | import com.facebook.react.ReactActivity;
4 |
5 | public class MainActivity extends ReactActivity {
6 |
7 | /**
8 | * Returns the name of the main component registered from JavaScript.
9 | * This is used to schedule rendering of the component.
10 | */
11 | @Override
12 | protected String getMainComponentName() {
13 | return "ReactNativeTemplate";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/components/Global/colors.js:
--------------------------------------------------------------------------------
1 | export default (colors = {
2 | primary: '#52b3d9',
3 | darkerBase: '#f3f1ef',
4 | highlightSoftRed: '#FF7D6B',
5 | darkAccent: '#E05037',
6 | mediumAccent: '#FF674C',
7 | lightAccent: '#FFAA80',
8 | extraLightAccent: '#FFE4D7',
9 | white: '#FFFFFF',
10 | offWhite: '#FAFAFA',
11 | black: '#1D1E21',
12 | darkNeutral: '#414447',
13 | mediumNeutral: '#959699',
14 | lightNeutral: '#E0E0E0',
15 | background: '#F2F3F4',
16 | error: '#D70E0E',
17 | });
18 |
--------------------------------------------------------------------------------
/src/redux/reducers/users.reducer.js:
--------------------------------------------------------------------------------
1 | import { AUTHORIZED_USER, LOGOUT_USER } from '../actions/users.actions';
2 |
3 | // Initial state
4 | const initialState = { auth: 'failed', error: '' };
5 |
6 | // Reducer
7 | export default function user(state = initialState, action) {
8 | switch (action.type) {
9 | case AUTHORIZED_USER:
10 | return { ...state, ...action.payload };
11 |
12 | case LOGOUT_USER:
13 | return initialState;
14 |
15 | default:
16 | return state;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/Label.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components/native';
3 | import colors from './Global/colors';
4 |
5 | const StyledLabel = styled.Text`
6 | color: ${colors.black};
7 | font-style: normal;
8 | font-weight: bold;
9 | line-height: 16px;
10 | font-size: 16px;
11 | letter-spacing: -0.0738462px;
12 | align-self: flex-start;
13 | margin-top: 19;
14 | margin-bottom: 17;
15 | `;
16 |
17 | export default (Label = ({ text }) => {text});
18 |
--------------------------------------------------------------------------------
/src/redux/reducers/conversations.reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | CONVERSATIONS,
3 | NEW_CONVERSATION,
4 | } from '../actions/conversations.actions';
5 |
6 | // Initial state
7 | const initialState = { status: 'pending' };
8 |
9 | // Reducer
10 | export default function conversations(state = initialState, action) {
11 | switch (action.type) {
12 | case CONVERSATIONS:
13 | return { ...state, ...action.payload };
14 | case NEW_CONVERSATION:
15 | return action.payload;
16 | default:
17 | return state;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/navigation/MainFeedStack.js:
--------------------------------------------------------------------------------
1 | import { createStackNavigator } from 'react-navigation';
2 | import MainFeedScreen from '../screens/MainFeedScreen';
3 | import CreatePostScreen from '../screens/CreatePostScreen';
4 | import PostShow from '../screens/PostShowScreen';
5 |
6 | const MainFeedStack = createStackNavigator(
7 | {
8 | MainFeed: MainFeedScreen,
9 | CreatePost: CreatePostScreen,
10 | PostDetail: PostShow,
11 | },
12 | {
13 | headerMode: 'none',
14 | gesturesEnabled: false,
15 | },
16 | );
17 |
18 | export default MainFeedStack;
19 |
--------------------------------------------------------------------------------
/src/navigation/SettingsStack.js:
--------------------------------------------------------------------------------
1 | import { createStackNavigator } from 'react-navigation';
2 | import SettingsScreen from '../screens/SettingsScreen';
3 | import ProfileScreen from '../screens/ProfileScreen';
4 | import EditProfileScreen from '../screens/EditProfileScreen';
5 |
6 | const MoreStack = createStackNavigator(
7 | {
8 | Profile: ProfileScreen,
9 | EditProfile: EditProfileScreen,
10 | Settings: SettingsScreen,
11 | },
12 | {
13 | headerMode: 'none',
14 | gesturesEnabled: false,
15 | },
16 | );
17 |
18 | export default MoreStack;
19 |
--------------------------------------------------------------------------------
/src/components/Timestamp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import moment from 'moment';
3 | import styled from 'styled-components/native';
4 |
5 | // checks for current date, subtracts 3 days
6 | // if timestamp is before 3 days, display date
7 | // if within last 3 days, use timeago to show time
8 | export default function createTimeStamp(date) {
9 | const StyledTimeStamp = styled.Text`
10 | text-align: right;
11 | color: gray;
12 | font-size: 13;
13 | padding-right: 8;
14 | `;
15 | return {moment(date).fromNow()};
16 | }
17 |
--------------------------------------------------------------------------------
/src/redux/api/resources.js:
--------------------------------------------------------------------------------
1 | // Add auth token to all authorization headers
2 | import { GET_ALL_RESOURCES } from '../../constants/urls';
3 | import SInfo from 'react-native-sensitive-info';
4 |
5 | export const getAll = async () => {
6 | const orgId = await SInfo.getItem('defaultOrgId', {});
7 | const token = await SInfo.getItem('authToken', {});
8 | const response = await fetch(GET_ALL_RESOURCES(parseInt(orgId)), {
9 | headers: {
10 | 'Content-Type': 'application/json',
11 | Authorization: token,
12 | },
13 | });
14 | return response.json();
15 | };
16 |
--------------------------------------------------------------------------------
/src/navigation/MessagesStack.js:
--------------------------------------------------------------------------------
1 | import { createStackNavigator } from 'react-navigation';
2 | import MessagesScreen from '../screens/MessagesScreen';
3 | import MessagesShowScreen from '../screens/MessageShowScreen';
4 | import CreateMessageScreen from '../screens/CreateMessageScreen';
5 |
6 | const MainFeedStack = createStackNavigator(
7 | {
8 | Messages: MessagesScreen,
9 | MessageDetail: MessagesShowScreen,
10 | CreateMessage: CreateMessageScreen,
11 | },
12 | {
13 | headerMode: 'none',
14 | gesturesEnabled: false,
15 | },
16 | );
17 |
18 | export default MainFeedStack;
19 |
--------------------------------------------------------------------------------
/src/redux/api/categories.js:
--------------------------------------------------------------------------------
1 | import { GET_ALL_CATEGORIES } from '../../constants/urls';
2 | import SInfo from 'react-native-sensitive-info';
3 |
4 | export const getAll = async () => {
5 | const orgId = await SInfo.getItem('defaultOrgId', {});
6 | const token = await SInfo.getItem('authToken', {});
7 | // console.log('GET ALL CATEGORIES URL ', GET_ALL_CATEGORIES(parseInt(orgId)));
8 | const response = await fetch(GET_ALL_CATEGORIES(parseInt(orgId)), {
9 | headers: {
10 | 'Content-Type': 'application/json',
11 | Authorization: token,
12 | },
13 | });
14 | return response.json();
15 | };
16 |
--------------------------------------------------------------------------------
/src/navigation/AuthStack.js:
--------------------------------------------------------------------------------
1 | import { createStackNavigator } from 'react-navigation';
2 | import SignInScreen from '../screens/SignInScreen';
3 | import SignUpScreen from '../screens/SignUpScreen';
4 | import LaunchScreen from '../screens/LaunchScreen';
5 | import ForgotPasswordScreen from '../screens/ForgotPasswordScreen';
6 |
7 | const AuthStack = createStackNavigator(
8 | {
9 | Launch: LaunchScreen,
10 | SignIn: SignInScreen,
11 | SignUp: SignUpScreen,
12 | ForgotPassword: ForgotPasswordScreen,
13 | },
14 | {
15 | headerMode: 'none',
16 | gesturesEnabled: false,
17 | },
18 | );
19 |
20 | export default AuthStack;
21 |
--------------------------------------------------------------------------------
/src/redux/api/organizations.js:
--------------------------------------------------------------------------------
1 | import {
2 | GET_ALL_ORGANIZATIONS,
3 | GET_SINGLE_ORGANIZATION,
4 | } from '../../constants/urls';
5 | import SInfo from 'react-native-sensitive-info';
6 |
7 | export const getAll = async () => {
8 | const response = await fetch(GET_ALL_ORGANIZATIONS());
9 | return response.json();
10 | };
11 |
12 | export const getSingle = async orgId => {
13 | const token = await SInfo.getItem('authToken', {});
14 | const response = await fetch(GET_SINGLE_ORGANIZATION(orgId), {
15 | headers: {
16 | 'Content-Type': 'application/json',
17 | Authorization: token,
18 | },
19 | });
20 | return response.json();
21 | };
22 |
--------------------------------------------------------------------------------
/android/app/build_defs.bzl:
--------------------------------------------------------------------------------
1 | """Helper definitions to glob .aar and .jar targets"""
2 |
3 | def create_aar_targets(aarfiles):
4 | for aarfile in aarfiles:
5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
6 | lib_deps.append(":" + name)
7 | android_prebuilt_aar(
8 | name = name,
9 | aar = aarfile,
10 | )
11 |
12 | def create_jar_targets(jarfiles):
13 | for jarfile in jarfiles:
14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
15 | lib_deps.append(":" + name)
16 | prebuilt_jar(
17 | name = name,
18 | binary_jar = jarfile,
19 | )
20 |
--------------------------------------------------------------------------------
/src/redux/reducers/singlePost.reducer.js:
--------------------------------------------------------------------------------
1 | import { SINGLE_POST } from '../actions/posts.actions';
2 |
3 | // Initial state
4 | const initialState = { status: 'pending' };
5 |
6 | // Reducer
7 | export default function singlePost(state = initialState, action) {
8 | switch (action.type) {
9 | case SINGLE_POST:
10 | return { ...state, ...action.payload };
11 | // case LIKE_POST:
12 | // const filteredPosts = state.results.filter(
13 | // post => post.id !== action.payload.results.id,
14 | // );
15 | // return {
16 | // ...state,
17 | // results: [action.payload.results, ...filteredPosts],
18 | // };
19 | default:
20 | return state;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // Redux
3 | import { Provider } from 'react-redux';
4 | import { createStore, applyMiddleware } from 'redux';
5 | import thunk from 'redux-thunk';
6 | import reducers from './src/redux/reducers';
7 |
8 | import LaunchScreen from './src/screens/LaunchScreen';
9 |
10 | import AppContainer from './src/navigation/MainSwitchNavigator';
11 |
12 | const createStoreWithMiddleWare = applyMiddleware(thunk)(createStore);
13 | // Create store here so there is not more than one store created
14 | export const store = createStoreWithMiddleWare(reducers);
15 |
16 | export default function App() {
17 | return (
18 |
19 |
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/ios/ReactNativeTemplate/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/src/components/AboutCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components/native';
3 | import colors from './Global/colors';
4 |
5 | const StyledMainView = styled.View`
6 | padding-left: 7;
7 | padding-bottom: 17;
8 | padding-right: 10;
9 | `;
10 |
11 | const StyledText = styled.Text`
12 | font-style: normal;
13 | font-weight: 600;
14 | line-height: 24px;
15 | font-size: 12px;
16 | letter-spacing: -0.0861539px;
17 | color: ${colors.mediumNeutral};
18 | `;
19 |
20 | export default (AboutCard = ({ info }) => {
21 | return (
22 |
23 | {info.map(
24 | (value, index) =>
25 | !!value &&
26 | value !== ', ' &&
27 | value !== ', , ' && {value},
28 | )}
29 |
30 | );
31 | });
32 |
--------------------------------------------------------------------------------
/src/components/TextButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components/native';
3 |
4 | const Button = styled.TouchableOpacity`
5 | padding: 10px 0;
6 | display: flex;
7 | `;
8 |
9 | const Text = styled.Text`
10 | font-style: normal;
11 | font-weight: 600;
12 | line-height: 14px;
13 | font-size: 12px;
14 | letter-spacing: -0.0738462px;
15 | color: #d2fbf8;
16 | text-decoration: underline;
17 | text-decoration-color: #d2fbf8;
18 | `;
19 |
20 | const TextButton = ({
21 | children,
22 | buttonStyle,
23 | textColor,
24 | textStyle,
25 | onPress,
26 | ...props
27 | }) => (
28 |
33 | );
34 |
35 | export default TextButton;
36 |
--------------------------------------------------------------------------------
/ios/ReactNativeTemplateTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ios/ReactNativeTemplate-tvOSTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/redux/actions/categories.actions.js:
--------------------------------------------------------------------------------
1 | import { getAll } from '../api/categories';
2 |
3 | // Action constants
4 | export const CATEGORIES = 'CATEGORIES';
5 |
6 | // actions
7 | export function getAllCategories() {
8 | return async dispatch => {
9 | try {
10 | const response = await getAll();
11 |
12 | // console.log('GET ALL CATEGORIES', response);
13 |
14 | if (response.categories) {
15 | dispatch({
16 | type: CATEGORIES,
17 | payload: {
18 | status: `complete ${new Date()}`,
19 | results: [...response.categories],
20 | },
21 | });
22 | } else if (response.error) {
23 | dispatch({
24 | type: CATEGORIES,
25 | payload: { status: 'failed', results: [] },
26 | });
27 | }
28 | } catch (error) {
29 | // console.log('Error getting categories', error);
30 | }
31 | };
32 | }
33 |
--------------------------------------------------------------------------------
/src/redux/actions/resources.actions.js:
--------------------------------------------------------------------------------
1 | import { getAll } from '../api/resources';
2 |
3 | // Action constants
4 | export const RESOURCES = 'RESOURCES';
5 |
6 | // actions
7 | export function getAllResources() {
8 | return async dispatch => {
9 | try {
10 | const response = await getAll();
11 |
12 | // console.log('GET ALL RESOURCES', response);
13 |
14 | //
15 |
16 | if (response.resources) {
17 | dispatch({
18 | type: RESOURCES,
19 | payload: {
20 | status: `allResources ${new Date()}`,
21 | results: response.resources,
22 | },
23 | });
24 | } else if (response.error) {
25 | dispatch({
26 | type: RESOURCES,
27 | payload: { status: 'failed', results: [] },
28 | });
29 | }
30 | } catch (error) {
31 | // console.log('Error getting resources', error);
32 | }
33 | };
34 | }
35 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
--------------------------------------------------------------------------------
/src/components/SectionCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import colors from './Global/colors';
5 |
6 | export const DEVICE_WIDTH = Dimensions.get('window').width;
7 |
8 | const Card = styled.View`
9 | width: ${DEVICE_WIDTH - 10};
10 | background-color: ${colors.white};
11 | padding-left: 10;
12 | border-radius: 3;
13 | margin-top: 10;
14 | align-self: flex-end;
15 | `;
16 |
17 | const CardTitle = styled.Text`
18 | color: ${colors.black};
19 | font-style: normal;
20 | font-weight: bold;
21 | line-height: 16px;
22 | font-size: 16px;
23 | letter-spacing: -0.0738462px;
24 | margin-bottom: 12;
25 | margin-top: 16;
26 | `;
27 |
28 | const SectionCard = ({ title, children, ...props }) => (
29 |
30 | {title && {title}}
31 | {children}
32 |
33 | );
34 |
35 | export default SectionCard;
36 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'ReactNativeTemplate'
2 | include ':react-native-gesture-handler'
3 | project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
4 | include ':react-native-vector-icons'
5 | project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
6 | include ':react-native-sensitive-info'
7 | project(':react-native-sensitive-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sensitive-info/android')
8 | include ':react-native-image-resizer'
9 | project(':react-native-image-resizer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-resizer/android')
10 | include ':react-native-image-picker'
11 | project(':react-native-image-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-picker/android')
12 |
13 | include ':app'
14 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext {
5 | buildToolsVersion = "28.0.3"
6 | minSdkVersion = 16
7 | compileSdkVersion = 28
8 | targetSdkVersion = 28
9 | supportLibVersion = "28.0.0"
10 | }
11 | repositories {
12 | google()
13 | jcenter()
14 | }
15 | dependencies {
16 | classpath 'com.android.tools.build:gradle:3.3.1'
17 |
18 | // NOTE: Do not place your application dependencies here; they belong
19 | // in the individual module build.gradle files
20 | }
21 | }
22 |
23 | allprojects {
24 | repositories {
25 | mavenLocal()
26 | google()
27 | jcenter()
28 | maven {
29 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
30 | url "$rootDir/../node_modules/react-native/android"
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/LoadMoreCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import colors from './Global/colors';
5 |
6 | const DEVICE_WIDTH = Dimensions.get('window').width;
7 |
8 | const StyledMainView = styled.View`
9 | width: ${DEVICE_WIDTH - 20};
10 | margin-top: 10;
11 | margin-bottom: 30;
12 | align-items: center;
13 | justify-content: center;
14 | `;
15 |
16 | const StyledTextLinkButton = styled.TouchableOpacity``;
17 |
18 | const StyledTextLink = styled.Text`
19 | font-weight: 600;
20 | line-height: 26px;
21 | font-size: 16px;
22 | text-align: center;
23 | letter-spacing: -0.0861539px;
24 | color: ${colors.mediumNeutral};
25 | text-decoration-line: underline;
26 | `;
27 |
28 | export default (LoadMoreCard = ({ onPress }) => (
29 |
30 |
31 | Load more.
32 |
33 |
34 | ));
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 |
33 | # node.js
34 | #
35 | node_modules/
36 | npm-debug.log
37 | yarn-error.log
38 |
39 | # BUCK
40 | buck-out/
41 | \.buckd/
42 | *.keystore
43 |
44 | # fastlane
45 | #
46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47 | # screenshots whenever they are needed.
48 | # For more information about the recommended setup visit:
49 | # https://docs.fastlane.tools/best-practices/source-control/
50 |
51 | */fastlane/report.xml
52 | */fastlane/Preview.html
53 | */fastlane/screenshots
54 |
55 | # Bundle artifact
56 | *.jsbundle
57 |
--------------------------------------------------------------------------------
/src/redux/reducers/notifications.reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | NOTIFICATIONS,
3 | MARK_READ,
4 | AVAILABLE_NOTIFICATIONS,
5 | REGISTERED_DEVICE,
6 | } from '../actions/notifications.actions';
7 |
8 | // Initial state
9 | const initialState = { status: 'pending' };
10 |
11 | // Reducer
12 | export default function notifications(state = initialState, action) {
13 | switch (action.type) {
14 | case NOTIFICATIONS:
15 | if (action.payload.currentPage !== 1) {
16 | return {
17 | status: action.payload.status,
18 | results: [...state.results, ...action.payload.results],
19 | currentPage: action.payload.currentPage,
20 | allPages: action.payload.allPages,
21 | };
22 | } else {
23 | return { ...state, ...action.payload };
24 | }
25 | case MARK_READ:
26 | return action.payload;
27 | case AVAILABLE_NOTIFICATIONS:
28 | return action.payload;
29 | case REGISTERED_DEVICE:
30 | return action.payload;
31 | default:
32 | return state;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/components/TransparentInput.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import TextField from './TextField';
3 | import colors from './Global/colors';
4 | import styled from 'styled-components/native';
5 | import EditIconPencil from '../assets/images/EditIconPencil.png';
6 |
7 | const StyledView = styled.View`
8 | justify-content: space-between;
9 | align-items: center;
10 | flex-direction: row;
11 | `;
12 |
13 | const StyledEditIcon = styled.Image`
14 | margin-right: 28;
15 | `;
16 |
17 | const transparentInputStyles = {
18 | borderBottomWidth: 0,
19 | fontStyle: 'normal',
20 | color: colors.darkNeutral,
21 | fontWeight: '600',
22 | marginTop: 0,
23 | paddingTop: 10,
24 | paddingBottom: 10,
25 | paddingLeft: 5,
26 | };
27 |
28 | const TransparentInput = props => (
29 |
30 |
35 |
36 |
37 | );
38 |
39 | export default TransparentInput;
40 |
--------------------------------------------------------------------------------
/src/components/SectionCardCentered.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import colors from './Global/colors';
5 |
6 | const DEVICE_WIDTH = Dimensions.get('window').width;
7 |
8 | const Card = styled.View`
9 | width: ${DEVICE_WIDTH - 20};
10 | background-color: ${colors.white};
11 | padding-left: 10;
12 | border-radius: 3;
13 | border-color: ${props => (props.hasError ? colors.error : colors.white)};
14 | border-width: 2;
15 | margin-top: 10;
16 | align-self: center;
17 | `;
18 |
19 | const CardTitle = styled.Text`
20 | color: ${colors.black};
21 | font-style: normal;
22 | font-weight: bold;
23 | line-height: 16px;
24 | font-size: 16px;
25 | letter-spacing: -0.0738462px;
26 | margin-bottom: 12;
27 | margin-top: 16;
28 | `;
29 |
30 | const SectionCardCentered = ({ title, children, ...props }) => (
31 |
32 | {title && {title}}
33 | {children}
34 |
35 | );
36 |
37 | export default SectionCardCentered;
38 |
--------------------------------------------------------------------------------
/src/components/LargeButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 |
5 | const DEVICE_WIDTH = Dimensions.get('window').width;
6 |
7 | const StyledLargeButton = styled.TouchableOpacity`
8 | width: ${DEVICE_WIDTH - 50};
9 | height: 53;
10 | background-color: ${props => props.background};
11 | justify-content: center;
12 | border-radius: 3;
13 | margin-top: 8;
14 | align-self: center;
15 | `;
16 |
17 | const StyledText = styled.Text`
18 | color: ${props => props.color || 'white'};
19 | align-self: center;
20 | font-style: normal;
21 | font-weight: bold;
22 | line-height: 19px;
23 | font-size: 16px;
24 | text-align: center;
25 | letter-spacing: -0.0984616px;
26 | `;
27 |
28 | export default (LargeButton = props => {
29 | const { onPress, background, title, color } = props;
30 | return (
31 |
32 | {title}
33 |
34 | );
35 | });
36 |
--------------------------------------------------------------------------------
/src/components/ActionSheetItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import colors from './Global/colors';
5 |
6 | const DEVICE_WIDTH = Dimensions.get('window').width;
7 |
8 | const StyledRowItem = styled.TouchableOpacity`
9 | width: ${DEVICE_WIDTH};
10 | background-color: white;
11 | padding-top: 12;
12 | padding-bottom: 12;
13 | border-bottom-width: 2;
14 | border-color: ${colors.background};
15 | flex-direction: row;
16 | align-items: center;
17 | justify-content: flex-start;
18 | margin-left: 20;
19 | height: 73;
20 | `;
21 |
22 | const StyledText = styled.Text`
23 | color: ${colors.darkNeutral};
24 | padding-left: 10;
25 | font-weight: 600;
26 | font-size: 18px;
27 | letter-spacing: -0.0861539px;
28 | `;
29 |
30 | const StyledIcon = styled.Image``;
31 |
32 | export default (actionSheetItem = ({ onPress, icon, title }) => (
33 | onPress()}>
34 |
35 | {title}
36 |
37 | ));
38 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
13 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/components/BottomActionButton.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Platform, Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import { DEVICE_WIDTH } from './HeaderDetail';
5 | import colors from '../components/Global/colors';
6 |
7 | const StyledLargeButton = styled.TouchableOpacity`
8 | width: ${DEVICE_WIDTH}
9 | height: 84;
10 | background-color: ${props => props.background};
11 | justify-content: center;
12 | position: absolute;
13 | bottom: 0;
14 | `;
15 |
16 | const StyledText = styled.Text`
17 | color: ${props => props.color || 'white'};
18 | align-self: center;
19 | font-style: normal;
20 | font-weight: 600;
21 | line-height: 18px;
22 | font-size: 18px;
23 | text-align: center;
24 | letter-spacing: -0.0861539px;
25 | `;
26 |
27 | export default (BottomActionButton = props => (
28 |
33 | {props.title}
34 |
35 | ));
36 |
--------------------------------------------------------------------------------
/src/redux/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import categories from './categories.reducer';
3 | import conversations from './conversations.reducer';
4 | import groups from './groups.reducer';
5 | import loginType from './loginType.reducer';
6 | import messageIndicator from './messageIndicator.reducer';
7 | import notifications from './notifications.reducer';
8 | import notificationIndicator from './notificationIndicator.reducer';
9 | import organizations from './organizations.reducer';
10 | import otherUsers from './otherUsers.reducer';
11 | import posts from './posts.reducer';
12 | import resources from './resources.reducer';
13 | import tabBar from './tabBar.reducer';
14 | import singlePost from './singlePost.reducer';
15 | import user from './users.reducer';
16 |
17 | const rootReducer = combineReducers({
18 | categories,
19 | conversations,
20 | groups,
21 | loginType,
22 | messageIndicator,
23 | notifications,
24 | notificationIndicator,
25 | organizations,
26 | otherUsers,
27 | posts,
28 | resources,
29 | tabBar,
30 | singlePost,
31 | user,
32 | });
33 |
34 | export default rootReducer;
35 |
--------------------------------------------------------------------------------
/src/util/helpers.js:
--------------------------------------------------------------------------------
1 | import { StackActions, NavigationActions } from 'react-navigation';
2 | import SInfo from 'react-native-sensitive-info';
3 |
4 | export function resetStack(navigation, routeName, delay) {
5 | setTimeout(() => {
6 | const resetAction = StackActions.reset({
7 | index: 0,
8 | key: null,
9 | actions: [NavigationActions.navigate({ routeName })],
10 | });
11 | navigation.dispatch(resetAction);
12 | }, delay);
13 | }
14 |
15 | export function truncateText(string, length) {
16 | if (string.length > length) {
17 | return string.substring(0, length) + '...';
18 | }
19 | return string;
20 | }
21 |
22 | export function saveInfo(authToken, password, email, defaultOrgId) {
23 | SInfo.setItem('authToken', authToken, {});
24 | SInfo.setItem('password', password, {});
25 | SInfo.setItem('email', email, {});
26 | SInfo.setItem('defaultOrgId', defaultOrgId, {});
27 | }
28 |
29 | export function saveDeviceInfo(deviceId, deviceToken) {
30 | SInfo.setItem('deviceId', `${deviceId}`, {});
31 | SInfo.setItem('deviceToken', deviceToken, {});
32 | SInfo.setItem('hasPostedDeviceToken', deviceToken, {});
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/NewComment.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import AutoGrowTextField from './AutoGrowTextField';
5 | import colors from './Global/colors';
6 |
7 | const DEVICE_WIDTH = Dimensions.get('window').width;
8 |
9 | const StyledRowView = styled.View`
10 | width: ${DEVICE_WIDTH - 48};
11 | flex-direction: row;
12 | align-items: flex-start;
13 | margin-top: 2;
14 | margin-bottom: 24;
15 | `;
16 |
17 | const StyledView = styled.View``;
18 |
19 | export default (NewComment = ({
20 | onChangeText,
21 | value,
22 | myRef,
23 | onFocus,
24 | onSubmit,
25 | }) => (
26 |
27 |
28 | onChangeText(commentValue)}
31 | value={value}
32 | myRef={myRef}
33 | viewWidth={DEVICE_WIDTH - 48}
34 | width={DEVICE_WIDTH - 80}
35 | onFocus={onFocus}
36 | onSubmit={onSubmit}
37 | textColor={colors.mediumNeutral}
38 | shouldHaveSendButton
39 | />
40 |
41 |
42 | ));
43 |
--------------------------------------------------------------------------------
/src/components/ImagePicker.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components/native';
3 | import ImagePlaceholder from '../assets/images/ImagePlaceholder.png';
4 | import GroupDefault from '../assets/images/GroupDefault.png';
5 | import GrayAdd from '../assets/images/GrayAdd.png';
6 |
7 | const StyledButton = styled.TouchableOpacity`
8 | width: 80;
9 | height: 80;
10 | border: 2px solid #e0e0e0;
11 | border-radius: 3px;
12 | margin: 10px;
13 | align-items: center;
14 | justify-content: center;
15 | `;
16 |
17 | const StyledImage = styled.Image`
18 | width: ${props => props.width};
19 | height: ${props => props.height};
20 | `;
21 |
22 | const StyledAdd = styled.Image`
23 | position: absolute;
24 | z-index: 100;
25 | bottom: -8;
26 | right: -8;
27 | height: 24;
28 | width: 24;
29 | `;
30 |
31 | export default (ImagePicker = props => (
32 |
33 |
38 |
39 |
40 | ));
41 |
--------------------------------------------------------------------------------
/src/screens/MainScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components/native';
3 | import colors from '../components/Global/colors';
4 | import LogoIcon from '../components/LogoIcon';
5 |
6 | const StyledView = styled.View`
7 | flex: 1;
8 | align-items: center;
9 | justify-content: center;
10 | background-color: ${colors.primary};
11 | `;
12 |
13 | const Heading = styled.Text`
14 | font-style: normal;
15 | font-weight: bold;
16 | line-height: 45px;
17 | font-size: 34px;
18 | letter-spacing: -0.233846px;
19 | color: ${colors.white};
20 | `;
21 |
22 | const StyledHeadingView = styled.View`
23 | flex-direction: row;
24 | align-items: center;
25 | align-self: center;
26 | height: 45;
27 | `;
28 |
29 | const StyledLogoView = styled.View`
30 | margin-right: 10;
31 | `;
32 |
33 | function MainScreen() {
34 | return (
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | Welcome!
43 |
44 |
45 |
46 | );
47 | }
48 |
49 | export default MainScreen;
50 |
--------------------------------------------------------------------------------
/src/redux/reducers/groups.reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | GROUPS,
3 | SINGLE_GROUP,
4 | CLEAR_GROUP,
5 | ADD_TO_GROUP,
6 | ASSIGN_ADMIN,
7 | CREATE_GROUP,
8 | LEAVE_GROUP,
9 | } from '../actions/groups.actions';
10 | // Initial state
11 | const initialState = { status: 'pending' };
12 |
13 | // Reducer
14 | export default function groups(state = initialState, action) {
15 | switch (action.type) {
16 | case GROUPS:
17 | if (action.payload.currentPage !== 1) {
18 | return {
19 | status: action.payload.status,
20 | results: [...state.results, ...action.payload.results],
21 | currentPage: action.payload.currentPage,
22 | allPages: action.payload.allPages,
23 | };
24 | } else {
25 | return { ...state, ...action.payload };
26 | }
27 | case LEAVE_GROUP:
28 | return action.payload;
29 | case CREATE_GROUP:
30 | return action.payload;
31 | case SINGLE_GROUP:
32 | return action.payload;
33 | case CLEAR_GROUP:
34 | return action.payload;
35 | case ADD_TO_GROUP:
36 | return action.payload;
37 | case ASSIGN_ADMIN:
38 | return action.payload;
39 | default:
40 | return state;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/SearchBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Ionicons from 'react-native-vector-icons/Ionicons';
3 | import styled from 'styled-components/native';
4 |
5 | const StyledView = styled.View`
6 | flex-direction: row;
7 | align-items: center;
8 | justify-content: space-between;
9 | background-color: ${props => props.backgroundColor};
10 | padding: 0 12px;
11 | color: black;
12 | padding-left: 8;
13 | border-radius: 8;
14 | width: ${props => props.width};
15 | `;
16 |
17 | const StyledInput = styled.TextInput`
18 | padding-left: 8;
19 | color: ${props => props.inputColor};
20 | font-style: normal;
21 | font-weight: 600;
22 | font-size: 13px;
23 | letter-spacing: -0.0738462px;
24 | flex: 1;
25 | `;
26 |
27 | export default (SearchBar = ({
28 | width,
29 | backgroundColor,
30 | inputColor,
31 | value,
32 | placeholder,
33 | onChangeText,
34 | placeholderTextColor,
35 | }) => (
36 |
37 |
44 |
45 |
46 | ));
47 |
--------------------------------------------------------------------------------
/src/components/NothingHereYetCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import colors from './Global/colors';
5 |
6 | const DEVICE_WIDTH = Dimensions.get('window').width;
7 |
8 | const StyledMainView = styled.View`
9 | width: ${DEVICE_WIDTH - 20};
10 | margin-top: 200;
11 | margin-bottom: 30;
12 | align-items: center;
13 | justify-content: center;
14 | `;
15 |
16 | const StyledText = styled.Text`
17 | font-weight: 600;
18 | line-height: 26px;
19 | font-size: 16px;
20 | text-align: center;
21 | letter-spacing: -0.0861539px;
22 | color: ${colors.mediumNeutral};
23 | margin-top: 10;
24 | `;
25 |
26 | const StyledTextLinkButton = styled.TouchableOpacity``;
27 |
28 | const StyledTextLink = styled.Text`
29 | font-weight: 600;
30 | line-height: 26px;
31 | font-size: 16px;
32 | text-align: center;
33 | letter-spacing: -0.0861539px;
34 | color: ${colors.mediumNeutral};
35 | text-decoration-line: underline;
36 | `;
37 |
38 | export default (NothingHereyetCard = ({ onPress }) => (
39 |
40 | No one has posted in this group yet!
41 |
42 | Get the conversation started.
43 |
44 |
45 | ));
46 |
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 | # React Native / Redux Template
2 |
3 | An app with some basic components to give a jumping off point for RN apps.
4 |
5 | * Splash Screen / Loading state (Auto Login)
6 | * Sign Up
7 | * Sign In
8 | * Profile & Edit Profile
9 | * Settings & Edit settings
10 | * Main screen / List of cards / Detail Screen
11 | * Navigation
12 |
13 | ## Requirements
14 |
15 | For development, you will only need Node.js installed on your environement.
16 |
17 | ---
18 |
19 | ## Install
20 |
21 | $ git clone https://git.cratebind.com/mobile-ios/react-native-template.git
22 | $ cd react-native-template
23 | $ npm install
24 | $ react-native link
25 |
26 | ## Start & watch
27 |
28 | $ react-native run-ios
29 |
30 | ---
31 |
32 | ## To Use
33 |
34 | Create new project with
35 |
36 | $ react-native init [new-project-name]
37 |
38 | You do need some dependencies -
39 |
40 | 1. react-navigation
41 | 2. react-native-gesture-handler
42 | 3. redux
43 | 4. react-redux
44 | 5. redux-thunk
45 | 6. styled-components
46 | 7. react-native-image-picker
47 | 8. react-native-image-resizer
48 | 9. react-native-sensitive-info
49 | 10. react-native-vector-icons
50 | 11. moment
51 | 12. react-native-masked-text
52 |
53 | Link up libraries
54 |
55 | $ react-native link
56 |
57 | #### Copy src folder over into new project & replace App.js.
58 |
59 | ## May the odds be ever in your favor.
60 |
61 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ReactNativeTemplate",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "start": "node node_modules/react-native/local-cli/cli.js start",
7 | "test": "jest"
8 | },
9 | "dependencies": {
10 | "moment": "^2.24.0",
11 | "react": "16.8.3",
12 | "react-native": "0.59.5",
13 | "react-native-gesture-handler": "^1.2.1",
14 | "react-native-image-picker": "^0.28.1",
15 | "react-native-image-resizer": "^1.0.1",
16 | "react-native-masked-text": "^1.12.2",
17 | "react-native-sensitive-info": "^5.4.1",
18 | "react-native-vector-icons": "^6.4.2",
19 | "react-navigation": "^3.9.1",
20 | "react-redux": "^7.0.3",
21 | "redux": "^4.0.1",
22 | "redux-thunk": "^2.3.0",
23 | "styled-components": "^4.2.0"
24 | },
25 | "devDependencies": {
26 | "babel-eslint": "^10.0.1",
27 | "eslint": "^5.16.0",
28 | "eslint-config-airbnb": "^17.1.0",
29 | "eslint-config-prettier": "^3.5.0",
30 | "eslint-plugin-import": "^2.14.0",
31 | "eslint-plugin-jsx-a11y": "^6.1.2",
32 | "eslint-plugin-prettier": "^3.0.1",
33 | "eslint-plugin-react": "^7.11.1",
34 | "@babel/core": "^7.4.4",
35 | "@babel/runtime": "^7.4.4",
36 | "babel-jest": "^24.8.0",
37 | "jest": "^24.8.0",
38 | "metro-react-native-babel-preset": "^0.54.0",
39 | "react-test-renderer": "16.8.3"
40 | },
41 | "jest": {
42 | "preset": "react-native"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/components/AllCaughtUpCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import colors from './Global/colors';
5 |
6 | const DEVICE_WIDTH = Dimensions.get('window').width;
7 |
8 | const StyledMainView = styled.View`
9 | width: ${DEVICE_WIDTH - 20};
10 | margin-top: 20;
11 | margin-bottom: 20;
12 | align-items: center;
13 | justify-content: center;
14 | `;
15 |
16 | const StyledRowView = styled.View`
17 | flex-direction: row;
18 | align-items: center;
19 | justify-content: space-between;
20 | `;
21 |
22 | const StyledLineView = styled.View`
23 | height: 2;
24 | background-color: ${colors.lightNeutral};
25 | flex: 1;
26 | margin-left: 10;
27 | margin-right: 10;
28 | `;
29 |
30 | const StyledText = styled.Text`
31 | font-weight: 600;
32 | line-height: 26px;
33 | font-size: 16px;
34 | text-align: center;
35 | letter-spacing: -0.0861539px;
36 | color: ${colors.mediumNeutral};
37 | margin-left: 10;
38 | margin-right: 10;
39 | `;
40 |
41 | export default (AllCaughtUpCard = ({ section, shouldShow }) => {
42 | if (section.title === 'allCaughtUp' && shouldShow) {
43 | return (
44 |
45 |
46 |
47 | You're all caught up!
48 |
49 |
50 |
51 | );
52 | }
53 | return null;
54 | });
55 |
--------------------------------------------------------------------------------
/src/components/BottomOfPostsCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import colors from './Global/colors';
5 | import EndOfPosts from '../assets/images/EndOfPosts.png';
6 |
7 | const DEVICE_WIDTH = Dimensions.get('window').width;
8 |
9 | const StyledMainView = styled.View`
10 | width: ${DEVICE_WIDTH - 20};
11 | margin-top: 10;
12 | margin-bottom: 30;
13 | align-items: center;
14 | justify-content: center;
15 | `;
16 |
17 | const StyledText = styled.Text`
18 | font-weight: 600;
19 | line-height: 26px;
20 | font-size: 16px;
21 | text-align: center;
22 | letter-spacing: -0.0861539px;
23 | color: ${colors.mediumNeutral};
24 | margin-top: 10;
25 | `;
26 |
27 | const StyledTextLinkButton = styled.TouchableOpacity``;
28 |
29 | const StyledTextLink = styled.Text`
30 | font-weight: 600;
31 | line-height: 26px;
32 | font-size: 16px;
33 | text-align: center;
34 | letter-spacing: -0.0861539px;
35 | color: ${colors.mediumNeutral};
36 | text-decoration-line: underline;
37 | `;
38 |
39 | const StyledImage = styled.Image``;
40 |
41 | export default (BottomOfPostsCard = ({ onPress }) => (
42 |
43 |
44 | You've reached the bottom of this feed!
45 |
46 | Scroll to top.
47 |
48 |
49 | ));
50 |
--------------------------------------------------------------------------------
/android/app/BUCK:
--------------------------------------------------------------------------------
1 | # To learn about Buck see [Docs](https://buckbuild.com/).
2 | # To run your application with Buck:
3 | # - install Buck
4 | # - `npm start` - to start the packager
5 | # - `cd android`
6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8 | # - `buck install -r android/app` - compile, install and run application
9 | #
10 |
11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
12 |
13 | lib_deps = []
14 |
15 | create_aar_targets(glob(["libs/*.aar"]))
16 |
17 | create_jar_targets(glob(["libs/*.jar"]))
18 |
19 | android_library(
20 | name = "all-libs",
21 | exported_deps = lib_deps,
22 | )
23 |
24 | android_library(
25 | name = "app-code",
26 | srcs = glob([
27 | "src/main/java/**/*.java",
28 | ]),
29 | deps = [
30 | ":all-libs",
31 | ":build_config",
32 | ":res",
33 | ],
34 | )
35 |
36 | android_build_config(
37 | name = "build_config",
38 | package = "com.reactnativetemplate",
39 | )
40 |
41 | android_resource(
42 | name = "res",
43 | package = "com.reactnativetemplate",
44 | res = "src/main/res",
45 | )
46 |
47 | android_binary(
48 | name = "app",
49 | keystore = "//android/keystores:debug",
50 | manifest = "src/main/AndroidManifest.xml",
51 | package_type = "debug",
52 | deps = [
53 | ":app-code",
54 | ],
55 | )
56 |
--------------------------------------------------------------------------------
/src/util/data.js:
--------------------------------------------------------------------------------
1 | const stateList = [
2 | { id: 1, name: 'AL' },
3 | { id: 2, name: 'AK' },
4 | { id: 3, name: 'AZ' },
5 | { id: 4, name: 'AR' },
6 | { id: 5, name: 'CA' },
7 | { id: 6, name: 'CO' },
8 | { id: 7, name: 'CT' },
9 | { id: 8, name: 'DE' },
10 | { id: 9, name: 'FL' },
11 | { id: 10, name: 'GA' },
12 | { id: 11, name: 'HI' },
13 | { id: 12, name: 'ID' },
14 | { id: 13, name: 'IL' },
15 | { id: 14, name: 'IN' },
16 | { id: 15, name: 'IA' },
17 | { id: 16, name: 'KS' },
18 | { id: 17, name: 'KY' },
19 | { id: 18, name: 'LA' },
20 | { id: 19, name: 'ME' },
21 | { id: 20, name: 'MD' },
22 | { id: 21, name: 'MA' },
23 | { id: 22, name: 'MI' },
24 | { id: 23, name: 'MN' },
25 | { id: 24, name: 'MS' },
26 | { id: 25, name: 'MO' },
27 | { id: 26, name: 'MT' },
28 | { id: 27, name: 'NE' },
29 | { id: 28, name: 'NV' },
30 | { id: 29, name: 'NH' },
31 | { id: 30, name: 'NJ' },
32 | { id: 31, name: 'NM' },
33 | { id: 32, name: 'NY' },
34 | { id: 33, name: 'NC' },
35 | { id: 34, name: 'ND' },
36 | { id: 35, name: 'OH' },
37 | { id: 36, name: 'OK' },
38 | { id: 37, name: 'OR' },
39 | { id: 38, name: 'PA' },
40 | { id: 39, name: 'RI' },
41 | { id: 40, name: 'SC' },
42 | { id: 41, name: 'SD' },
43 | { id: 42, name: 'TN' },
44 | { id: 43, name: 'TX' },
45 | { id: 44, name: 'UT' },
46 | { id: 45, name: 'VT' },
47 | { id: 46, name: 'VA' },
48 | { id: 47, name: 'WA' },
49 | { id: 48, name: 'WV' },
50 | { id: 49, name: 'WI' },
51 | { id: 50, name: 'WY' },
52 | ];
53 |
54 | export default stateList;
55 |
--------------------------------------------------------------------------------
/src/components/TextField.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components/native';
3 | import colors from './Global/colors';
4 | import { DEVICE_WIDTH } from './Header';
5 |
6 | const StyledInput = styled.TextInput`
7 | flex: 1;
8 | height: 53px;
9 | background-color: transparent;
10 | border-color: ${props => props.border};
11 | border-width: 1;
12 | color: ${colors.darkNeutral};
13 | padding-top: 10;
14 | padding-bottom: 6;
15 | padding-left: 8;
16 | margin-top: 8;
17 | border: 0;
18 | border-bottom-width: 1px;
19 | border-bottom-color: ${colors.darkerBase};
20 | font-style: normal;
21 | font-weight: 600;
22 | line-height: 19px;
23 | font-size: 14px;
24 | letter-spacing: -0.0984616px;
25 | width: ${DEVICE_WIDTH - 50};
26 | `;
27 |
28 | const StyledError = styled.Text`
29 | width: 300;
30 | margin-bottom: 2;
31 | color: red;
32 | padding-left: 6;
33 | padding-top: 4;
34 | padding-bottom: 4;
35 | align-self: flex-start;
36 | `;
37 |
38 | export default (TextField = props => (
39 |
53 | ));
54 |
--------------------------------------------------------------------------------
/ios/ReactNativeTemplate/AppDelegate.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import "AppDelegate.h"
9 |
10 | #import
11 | #import
12 | #import
13 |
14 | @implementation AppDelegate
15 |
16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
17 | {
18 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
19 | RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
20 | moduleName:@"ReactNativeTemplate"
21 | initialProperties:nil];
22 |
23 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
24 |
25 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
26 | UIViewController *rootViewController = [UIViewController new];
27 | rootViewController.view = rootView;
28 | self.window.rootViewController = rootViewController;
29 | [self.window makeKeyAndVisible];
30 | return YES;
31 | }
32 |
33 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
34 | {
35 | #if DEBUG
36 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
37 | #else
38 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
39 | #endif
40 | }
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/src/components/ImagePreview.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ScrollView } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import RemovePhoto from '../assets/images/RemovePhoto.png';
5 | import { DEVICE_WIDTH } from './HeaderDetail';
6 |
7 | const StyledView = styled.View`
8 | flex-direction: row;
9 | margin: 10px 4px;
10 | `;
11 |
12 | const StyledImageView = styled.View``;
13 |
14 | const StyledImage = styled.Image`
15 | width: 80;
16 | height: 80;
17 | border-radius: 3;
18 | margin: 0px 6px;
19 | `;
20 |
21 | const StyledRemovePhoto = styled.Image`
22 | height: 25;
23 | width: 25;
24 | `;
25 |
26 | const StyledRemoveButton = styled.TouchableOpacity`
27 | position: absolute;
28 | z-index: 100;
29 | bottom: -8;
30 | right: -6;
31 | `;
32 |
33 | export default (ImagePreview = props => {
34 | if (props.images.length > 0) {
35 | return (
36 |
37 |
38 | {props.images.length > 0 &&
39 | props.images.map((value, index) => (
40 |
41 | props.onPressRemove(value)}>
42 |
43 |
44 |
51 |
52 | ))}
53 |
54 |
55 | );
56 | }
57 | return null;
58 | });
59 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/reactnativetemplate/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.reactnativetemplate;
2 |
3 | import android.app.Application;
4 |
5 | import com.facebook.react.ReactApplication;
6 | import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;
7 | import com.oblador.vectoricons.VectorIconsPackage;
8 | import br.com.classapp.RNSensitiveInfo.RNSensitiveInfoPackage;
9 | import fr.bamlab.rnimageresizer.ImageResizerPackage;
10 | import com.imagepicker.ImagePickerPackage;
11 | import com.facebook.react.ReactNativeHost;
12 | import com.facebook.react.ReactPackage;
13 | import com.facebook.react.shell.MainReactPackage;
14 | import com.facebook.soloader.SoLoader;
15 |
16 | import java.util.Arrays;
17 | import java.util.List;
18 |
19 | public class MainApplication extends Application implements ReactApplication {
20 |
21 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
22 | @Override
23 | public boolean getUseDeveloperSupport() {
24 | return BuildConfig.DEBUG;
25 | }
26 |
27 | @Override
28 | protected List getPackages() {
29 | return Arrays.asList(
30 | new MainReactPackage(),
31 | new RNGestureHandlerPackage(),
32 | new VectorIconsPackage(),
33 | new RNSensitiveInfoPackage(),
34 | new ImageResizerPackage(),
35 | new ImagePickerPackage()
36 | );
37 | }
38 |
39 | @Override
40 | protected String getJSMainModuleName() {
41 | return "index";
42 | }
43 | };
44 |
45 | @Override
46 | public ReactNativeHost getReactNativeHost() {
47 | return mReactNativeHost;
48 | }
49 |
50 | @Override
51 | public void onCreate() {
52 | super.onCreate();
53 | SoLoader.init(this, /* native exopackage */ false);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/components/ReactionTabBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import colors from './Global/colors';
5 | import LikeReactionItem from './LikeReactionItem';
6 | import CommentReactionItem from './CommentReactionItem';
7 |
8 | const DEVICE_WIDTH = Dimensions.get('window').width;
9 |
10 | const StyledReactionTab = styled.View`
11 | width: ${DEVICE_WIDTH - 20};
12 | align-self: center;
13 | flex-direction: row;
14 | align-items: center;
15 | justify-content: center;
16 | border-top-width: 2;
17 | border-color: ${colors.background};
18 | background-color: ${colors.white};
19 | `;
20 |
21 | const StyledRowView = styled.View`
22 | flex-direction: row;
23 | align-items: center;
24 | justify-content: space-between;
25 | width: ${DEVICE_WIDTH - 48};
26 | margin-top: 6;
27 | margin-bottom: 6;
28 | `;
29 |
30 | export default (ReactionTabBar = ({
31 | likeCount,
32 | onPressLike,
33 | likesOpen,
34 | toggleLeftReaction,
35 | userLiked,
36 | commentCount,
37 | onPressComment,
38 | commentsOpen,
39 | toggleRightReaction,
40 | userCommented,
41 | }) => (
42 |
43 |
44 |
52 |
60 |
61 |
62 | ));
63 |
--------------------------------------------------------------------------------
/ios/ReactNativeTemplate-tvOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UIViewControllerBasedStatusBarAppearance
38 |
39 | NSLocationWhenInUseUsageDescription
40 |
41 | NSAppTransportSecurity
42 |
43 |
44 | NSExceptionDomains
45 |
46 | localhost
47 |
48 | NSExceptionAllowsInsecureHTTPLoads
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/src/components/CommentReactionItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components/native';
3 | import Ionicons from 'react-native-vector-icons/Ionicons';
4 | import ChatIcon from '../assets/images/ChatIcon.png';
5 | import ChatIconHighlighted from '../assets/images/ChatIconHighlighted.png';
6 | import Icon from './Icon';
7 | import colors from './Global/colors';
8 |
9 | const StyledRowView = styled.View`
10 | flex-direction: row;
11 | align-items: center;
12 | justify-content: center;
13 | `;
14 |
15 | const StyledReactionImage = styled.TouchableOpacity``;
16 |
17 | const StyledReactionTitle = styled.Text`
18 | color: ${colors.darkNeutral};
19 | text-align: right;
20 | font-weight: 600;
21 | line-height: 11px;
22 | font-size: 10px;
23 | letter-spacing: -0.0553846px;
24 | margin-left: 6;
25 | margin-right: 6;
26 | `;
27 |
28 | const StyledTouchableWithoutFeedback = styled.TouchableWithoutFeedback``;
29 |
30 | function determineString(count) {
31 | switch (count) {
32 | case 0:
33 | return 'Comment';
34 | case 1:
35 | return '1 comment';
36 | default:
37 | return `${count} comments`;
38 | }
39 | }
40 |
41 | export default (CommentReactionItem = ({
42 | toggleOpen,
43 | open,
44 | commentCount,
45 | onPressReaction,
46 | userCommented,
47 | }) => (
48 |
49 |
50 |
51 |
56 |
57 | {determineString(commentCount)}
58 |
59 |
60 |
61 |
62 |
63 | ));
64 |
--------------------------------------------------------------------------------
/src/components/Avatar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components/native';
3 | import colors from './Global/colors';
4 |
5 | const StyledTouchableAvatar = styled.TouchableOpacity``;
6 |
7 | const StyledAvatar = styled.Image`
8 | width: ${props => props.size};
9 | height: ${props => props.size};
10 | border-radius: ${props => props.size / 2};
11 | `;
12 |
13 | const StyledEmptyProfile = styled.View`
14 | width: ${props => props.size};
15 | height: ${props => props.size};
16 | border-radius: ${props => props.size / 2};
17 | background-color: ${colors.mediumNeutral};
18 | justify-content: center;
19 | align-items: center;
20 | `;
21 |
22 | const StyledInitials = styled.Text`
23 | font-weight: 600;
24 | line-height: 20px;
25 | font-size: 16px;
26 | text-align: center;
27 | letter-spacing: -0.0984616px;
28 | text-transform: uppercase;
29 | color: ${colors.background};
30 | padding-top: 1;
31 | `;
32 |
33 | export default (Avatar = props => {
34 | // console.log('AVATAR PROPS ', props);
35 | const { source, firstName, lastName, onSelectUser, size } = props;
36 | let useInitials = false;
37 | if (
38 | source ===
39 | 'https://church-groups.cratebind.com/avatars/original/missing.png'
40 | ) {
41 | useInitials = true;
42 | }
43 | if (
44 | source === 'https://church-groups.cratebind.com/logos/original/missing.png'
45 | ) {
46 | useInitials = true;
47 | }
48 | const firstInitial = firstName.substring(0, 1);
49 | const lastInitial = lastName.substring(0, 1);
50 | const avatar = useInitials ? (
51 |
52 |
53 | {`${firstInitial}${lastInitial}`}
54 |
55 |
56 | ) : (
57 |
58 |
59 |
60 | );
61 | return avatar;
62 | });
63 |
--------------------------------------------------------------------------------
/ios/ReactNativeTemplateTests/ReactNativeTemplateTests.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import
9 | #import
10 |
11 | #import
12 | #import
13 |
14 | #define TIMEOUT_SECONDS 600
15 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
16 |
17 | @interface ReactNativeTemplateTests : XCTestCase
18 |
19 | @end
20 |
21 | @implementation ReactNativeTemplateTests
22 |
23 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
24 | {
25 | if (test(view)) {
26 | return YES;
27 | }
28 | for (UIView *subview in [view subviews]) {
29 | if ([self findSubviewInView:subview matching:test]) {
30 | return YES;
31 | }
32 | }
33 | return NO;
34 | }
35 |
36 | - (void)testRendersWelcomeScreen
37 | {
38 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
39 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
40 | BOOL foundElement = NO;
41 |
42 | __block NSString *redboxError = nil;
43 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
44 | if (level >= RCTLogLevelError) {
45 | redboxError = message;
46 | }
47 | });
48 |
49 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
50 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
51 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
52 |
53 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
54 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
55 | return YES;
56 | }
57 | return NO;
58 | }];
59 | }
60 |
61 | RCTSetLogFunction(RCTDefaultLogFunction);
62 |
63 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
64 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
65 | }
66 |
67 |
68 | @end
69 |
--------------------------------------------------------------------------------
/src/redux/actions/organizations.actions.js:
--------------------------------------------------------------------------------
1 | import { getAll, getSingle } from '../api/organizations';
2 |
3 | // Action constants
4 | export const ORGANIZATIONS = 'ORGANIZATIONS';
5 |
6 | // actions
7 | export function getAllOrganizations() {
8 | return async dispatch => {
9 | try {
10 | const response = await getAll();
11 |
12 | // console.log('GET ALL ORGANIZATIONS', response);
13 |
14 | //
15 |
16 | if (response.organizations) {
17 | dispatch({
18 | type: ORGANIZATIONS,
19 | payload: {
20 | status: `allComplete${new Date()}`,
21 | results: [...response.organizations],
22 | },
23 | });
24 | } else if (response.error) {
25 | dispatch({
26 | type: ORGANIZATIONS,
27 | payload: { status: 'failed', results: [] },
28 | });
29 | }
30 | } catch (error) {
31 | // console.log('Error getting organizations', error);
32 | }
33 | };
34 | }
35 |
36 | export function getSingleOrganization(orgId) {
37 | return async dispatch => {
38 | try {
39 | const response = await getAll();
40 |
41 | // console.log('GET ALL RESPONSE ', response);
42 | if (response.organizations) {
43 | const filteredCurrentUserOrg = response.organizations.filter(
44 | org => org.id === orgId,
45 | )[0];
46 | // console.log('FILTERED ', filteredCurrentUserOrg);
47 | const singleResponse = await getSingle(orgId);
48 |
49 | if (singleResponse.public_organization) {
50 | console.log('SINGLE ORGANIZATION ', {
51 | ...filteredCurrentUserOrg,
52 | users: singleResponse.public_organization.users,
53 | });
54 |
55 | dispatch({
56 | type: ORGANIZATIONS,
57 | payload: {
58 | status: `singleComplete${new Date()}`,
59 | results: {
60 | ...filteredCurrentUserOrg,
61 | users: singleResponse.public_organization.users,
62 | },
63 | },
64 | });
65 | }
66 | } else if (response.error) {
67 | dispatch({
68 | type: ORGANIZATIONS,
69 | payload: { status: 'failed', results: [] },
70 | });
71 | }
72 | } catch (error) {
73 | // console.log('Error getting single organization', error);
74 | }
75 | };
76 | }
77 |
--------------------------------------------------------------------------------
/src/components/LikeReactionItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components/native';
3 | import Ionicons from 'react-native-vector-icons/Ionicons';
4 | import LikeIcon from '../assets/images/LikeIcon.png';
5 | import LikeIconHighlighted from '../assets/images/LikeIconHighlighted.png';
6 | import Icon from './Icon';
7 | import colors from './Global/colors';
8 |
9 | const StyledRowView = styled.View`
10 | flex-direction: row;
11 | align-items: center;
12 | justify-content: center;
13 | `;
14 |
15 | const StyledReactionImage = styled.TouchableOpacity``;
16 |
17 | const StyledReactionTitle = styled.Text`
18 | color: ${props => props.color};
19 | text-align: right;
20 | font-weight: 600;
21 | line-height: 11px;
22 | font-size: 10px;
23 | letter-spacing: -0.0553846px;
24 | margin-left: 6;
25 | margin-right: 6;
26 | `;
27 |
28 | const StyledTouchableWithoutFeedback = styled.TouchableWithoutFeedback``;
29 |
30 | const StyledArrow = styled.View`
31 | width: 0;
32 | height: 0;
33 | border-top-color: ${props => props.color};
34 | border-top-width: ${props => props.top};
35 | border-right-color: transparent;
36 | border-bottom-width: ${props => props.bottom};
37 | border-right-color: transparent;
38 | border-right-width: 6;
39 | border-left-color: transparent;
40 | border-left-width: 6;
41 | border-radius: 5;
42 | `;
43 |
44 | function determineString(count) {
45 | switch (count) {
46 | case 0:
47 | return 'Like';
48 | case 1:
49 | return '1 like';
50 | default:
51 | return `${count} likes`;
52 | }
53 | }
54 |
55 | export default (LikeReactionItem = ({
56 | onPressReaction,
57 | userLiked,
58 | isComment,
59 | likeCount,
60 | toggleOpen,
61 | open,
62 | }) => (
63 |
64 |
65 |
66 |
67 |
68 |
71 | {determineString(likeCount)}
72 |
73 |
74 |
79 |
80 |
81 |
82 | ));
83 |
--------------------------------------------------------------------------------
/ios/ReactNativeTemplate/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ReactNativeTemplate
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | NSLocationWhenInUseUsageDescription
28 |
29 | UILaunchStoryboardName
30 | LaunchScreen
31 | UIRequiredDeviceCapabilities
32 |
33 | armv7
34 |
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationLandscapeLeft
39 | UIInterfaceOrientationLandscapeRight
40 |
41 | UIViewControllerBasedStatusBarAppearance
42 |
43 | NSAppTransportSecurity
44 |
45 | NSAllowsArbitraryLoads
46 |
47 | NSExceptionDomains
48 |
49 | localhost
50 |
51 | NSExceptionAllowsInsecureHTTPLoads
52 |
53 |
54 |
55 |
56 | UIAppFonts
57 |
58 | AntDesign.ttf
59 | Entypo.ttf
60 | EvilIcons.ttf
61 | Feather.ttf
62 | FontAwesome.ttf
63 | FontAwesome5_Brands.ttf
64 | FontAwesome5_Regular.ttf
65 | FontAwesome5_Solid.ttf
66 | Foundation.ttf
67 | Ionicons.ttf
68 | MaterialCommunityIcons.ttf
69 | MaterialIcons.ttf
70 | Octicons.ttf
71 | SimpleLineIcons.ttf
72 | Zocial.ttf
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | ; We fork some components by platform
3 | .*/*[.]android.js
4 |
5 | ; Ignore "BUCK" generated dirs
6 | /\.buckd/
7 |
8 | ; Ignore unexpected extra "@providesModule"
9 | .*/node_modules/.*/node_modules/fbjs/.*
10 |
11 | ; Ignore duplicate module providers
12 | ; For RN Apps installed via npm, "Libraries" folder is inside
13 | ; "node_modules/react-native" but in the source repo it is in the root
14 | .*/Libraries/react-native/React.js
15 |
16 | ; Ignore polyfills
17 | .*/Libraries/polyfills/.*
18 |
19 | ; Ignore metro
20 | .*/node_modules/metro/.*
21 |
22 | [include]
23 |
24 | [libs]
25 | node_modules/react-native/Libraries/react-native/react-native-interface.js
26 | node_modules/react-native/flow/
27 |
28 | [options]
29 | emoji=true
30 |
31 | esproposal.optional_chaining=enable
32 | esproposal.nullish_coalescing=enable
33 |
34 | module.system=haste
35 | module.system.haste.use_name_reducers=true
36 | # get basename
37 | module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
38 | # strip .js or .js.flow suffix
39 | module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
40 | # strip .ios suffix
41 | module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
42 | module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
43 | module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
44 | module.system.haste.paths.blacklist=.*/__tests__/.*
45 | module.system.haste.paths.blacklist=.*/__mocks__/.*
46 | module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/Animated/src/polyfills/.*
47 | module.system.haste.paths.whitelist=/node_modules/react-native/Libraries/.*
48 |
49 | munge_underscores=true
50 |
51 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
52 |
53 | module.file_ext=.js
54 | module.file_ext=.jsx
55 | module.file_ext=.json
56 | module.file_ext=.native.js
57 |
58 | suppress_type=$FlowIssue
59 | suppress_type=$FlowFixMe
60 | suppress_type=$FlowFixMeProps
61 | suppress_type=$FlowFixMeState
62 |
63 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
64 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
65 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
66 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
67 |
68 | [version]
69 | ^0.92.0
70 |
--------------------------------------------------------------------------------
/src/components/SwitchCard.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Dimensions, Switch } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import colors from './Global/colors';
5 |
6 | const DEVICE_WIDTH = Dimensions.get('window').width;
7 |
8 | const StyledView = styled.View``;
9 |
10 | const StyledListItem = styled.View`
11 | flex-direction: row;
12 | align-items: center;
13 | justify-content: space-between;
14 | height: 85;
15 | `;
16 |
17 | const StyledListText = styled.Text`
18 | font-style: normal;
19 | font-weight: 600;
20 | line-height: 18px;
21 | font-size: 14px;
22 | letter-spacing: -0.0861539px;
23 | color: ${colors.black};
24 | width: 230;
25 | `;
26 |
27 | const StyledListSwitch = styled.View`
28 | margin-right: 20;
29 | `;
30 |
31 | const StyledSeparator = styled.View`
32 | height: 2;
33 | background-color: ${colors.background};
34 | width: ${DEVICE_WIDTH - 20};
35 | align-self: flex-end;
36 | `;
37 |
38 | class SwitchCard extends Component {
39 | constructor(props) {
40 | super(props);
41 |
42 | this.state = {
43 | isOn: false,
44 | };
45 | }
46 |
47 | componentDidMount() {
48 | this.determineIfOn();
49 | }
50 |
51 | determineIfOn = () => {
52 | const filtered = this.props.currentSettings.filter(
53 | el => el === this.props.value.key,
54 | );
55 | if (filtered.length > 0) {
56 | this.setState({ isOn: true });
57 | } else {
58 | this.setState({ isOn: false });
59 | }
60 | };
61 |
62 | handleSwitchChange = () => {
63 | this.props.onPress();
64 | this.setState({ isOn: !this.state.isOn });
65 | // Make call to toggle notification setting based on id/type/etc.
66 | };
67 |
68 | render() {
69 | return (
70 |
71 |
72 | {this.props.value.value}
73 |
74 | this.handleSwitchChange()}
83 | />
84 |
85 |
86 |
87 |
88 | );
89 | }
90 | }
91 |
92 | export default SwitchCard;
93 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/src/components/AutoGrowTextField.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Keyboard } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import colors from './Global/colors';
5 |
6 | const StyledView = styled.View`
7 | background-color: ${colors.white};
8 | padding: 15px 10px;
9 | align-self: center;
10 | justify-content: space-between;
11 | flex-direction: row;
12 | `;
13 |
14 | const StyledTextInput = styled.TextInput`
15 | height: ${props => props.height};
16 | flex: 1;
17 | color: ${colors.darkNeutral};
18 | font-style: normal;
19 | font-weight: 600;
20 | font-size: 14px;
21 | letter-spacing: -0.0984616px;
22 | margin-right: 4;
23 | `;
24 |
25 | const StyledIconView = styled.TouchableOpacity`
26 | align-self: flex-end;
27 | `;
28 |
29 | const StyledSendButton = styled.Text`
30 | font-style: normal;
31 | font-weight: bold;
32 | font-size: 14px;
33 | text-align: right;
34 | letter-spacing: -0.0861539px;
35 | text-decoration-line: underline;
36 | text-decoration-color: ${props => props.color};
37 | color: ${props => props.color};
38 | `;
39 |
40 | class AutoGrowTextField extends Component {
41 | constructor() {
42 | super();
43 |
44 | this.state = {
45 | height: 24,
46 | };
47 | }
48 |
49 | updateSize = height => {
50 | if (height > 24) {
51 | this.setState({
52 | height,
53 | });
54 | }
55 | };
56 |
57 | onSubmit = () => {
58 | Keyboard.dismiss();
59 | this.props.onSubmit();
60 | };
61 |
62 | render() {
63 | const {
64 | viewWidth,
65 | placeholder,
66 | onChangeText,
67 | value,
68 | myRef,
69 | onFocus,
70 | shouldHaveSendButton,
71 | textColor,
72 | buttonTitle,
73 | } = this.props;
74 | return (
75 |
76 |
85 | this.updateSize(e.nativeEvent.contentSize.height)
86 | }
87 | ref={myRef}
88 | onFocus={onFocus}
89 | blurOnSubmit
90 | />
91 | {shouldHaveSendButton && (
92 | this.onSubmit()}>
93 |
94 | {buttonTitle || 'Send'}
95 |
96 |
97 | )}
98 |
99 | );
100 | }
101 | }
102 |
103 | export default AutoGrowTextField;
104 |
--------------------------------------------------------------------------------
/src/redux/api/conversations.js:
--------------------------------------------------------------------------------
1 | // Add auth token to all authorization headers
2 | import {
3 | GET_ALL_CONVERSATIONS,
4 | CREATE_CONVERSATION,
5 | GET_SINGLE_CONVERSATION,
6 | MARK_CONVERSATION_READ,
7 | POST_MESSAGE_TO_CONVERSATION,
8 | DELETE_CONVERSATION,
9 | } from '../../constants/urls';
10 | import SInfo from 'react-native-sensitive-info';
11 |
12 | export const get = async page => {
13 | const orgId = await SInfo.getItem('defaultOrgId', {});
14 | const token = await SInfo.getItem('authToken', {});
15 | const response = await fetch(GET_ALL_CONVERSATIONS(orgId, page), {
16 | headers: {
17 | 'Content-Type': 'application/json',
18 | Authorization: token,
19 | },
20 | });
21 | return response.json();
22 | };
23 |
24 | export const create = async formdata => {
25 | const orgId = await SInfo.getItem('defaultOrgId', {});
26 | const token = await SInfo.getItem('authToken', {});
27 | formdata.append('organization_id', parseInt(orgId));
28 | // console.log(formdata);
29 |
30 | const response = await fetch(CREATE_CONVERSATION, {
31 | method: 'POST',
32 | headers: {
33 | 'Content-Type': 'application/json',
34 | Authorization: token,
35 | },
36 | body: formdata,
37 | });
38 | // console.log(response);
39 | return response.json();
40 | };
41 |
42 | export const getSingle = async convoId => {
43 | const token = await SInfo.getItem('authToken', {});
44 | const response = await fetch(GET_SINGLE_CONVERSATION(convoId), {
45 | headers: {
46 | 'Content-Type': 'application/json',
47 | Authorization: token,
48 | },
49 | });
50 | return response.json();
51 | };
52 |
53 | export const mark = async convoId => {
54 | const token = await SInfo.getItem('authToken', {});
55 | const response = await fetch(MARK_CONVERSATION_READ(convoId), {
56 | method: 'PUT',
57 | headers: {
58 | 'Content-Type': 'application/json',
59 | Authorization: token,
60 | },
61 | });
62 | // console.log(response);
63 | return response.json();
64 | };
65 |
66 | export const post = async (convoId, content) => {
67 | const token = await SInfo.getItem('authToken', {});
68 | const response = await fetch(POST_MESSAGE_TO_CONVERSATION(convoId), {
69 | method: 'POST',
70 | headers: {
71 | 'Content-Type': 'application/json',
72 | Authorization: token,
73 | },
74 | body: JSON.stringify({
75 | content,
76 | }),
77 | });
78 | // console.log(response);
79 | return response.json();
80 | };
81 |
82 | export const deleteConv = async convoId => {
83 | const token = await SInfo.getItem('authToken', {});
84 | const response = await fetch(DELETE_CONVERSATION(convoId), {
85 | method: 'DELETE',
86 | headers: {
87 | 'Content-Type': 'application/json',
88 | Authorization: token,
89 | },
90 | });
91 | return response.json();
92 | };
93 |
--------------------------------------------------------------------------------
/src/components/PagingView.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Modal, Dimensions, SafeAreaView, Image } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import BackArrow from '../assets/images/BackArrow.png';
5 | import colors from './Global/colors';
6 | import Avatar from './Avatar';
7 |
8 | const DEVICE_WIDTH = Dimensions.get('window').width;
9 | const IMAGE_WIDTH = Dimensions.get('window').width - 20;
10 | const IMAGE_HEIGHT = Dimensions.get('window').height / 2;
11 |
12 | const StyledHeader = styled.View`
13 | background-color: ${colors.black};
14 | width: ${DEVICE_WIDTH};
15 | flex-direction: column;
16 | align-items: flex-start;
17 | padding-left: 12;
18 | padding-top: 38;
19 | padding-bottom: 16;
20 | `;
21 |
22 | const StyledNameRowView = styled.View`
23 | flex-direction: row;
24 | align-items: center;
25 | `;
26 |
27 | const StyledName = styled.Text`
28 | margin-left: 8;
29 | line-height: 14px;
30 | font-size: 12px;
31 | letter-spacing: -0.0738462px;
32 | color: ${colors.white};
33 | `;
34 |
35 | const StyledGroupName = styled.Text`
36 | font-weight: 600;
37 | line-height: 14px;
38 | font-size: 12px;
39 | letter-spacing: -0.0738462px;
40 | color: ${colors.mediumNeutral};
41 | `;
42 |
43 | const StyledScrollView = styled.ScrollView`
44 | background-color: 'rgba(29, 30, 33, 0.85)';
45 | `;
46 |
47 | const StyledMainImage = styled.Image`
48 | width: ${IMAGE_WIDTH};
49 | height: ${IMAGE_HEIGHT};
50 | align-self: center;
51 | margin-top: 10;
52 | `;
53 |
54 | const StyledCloseButton = styled.TouchableOpacity`
55 | margin-bottom: 16;
56 | `;
57 |
58 | export default (PagingView = ({
59 | post,
60 | modalVisible,
61 | groupName,
62 | closeModal,
63 | }) => {
64 | const { images, user } = post;
65 | const { full_name } = user;
66 | return (
67 |
68 |
69 |
70 | closeModal()}>
71 |
72 |
73 |
74 |
78 | console.log('on select user from paging view')
79 | }
80 | firstName={user.first_name}
81 | lastName={user.last_name}
82 | />
83 | {`${full_name}, `}
84 | {groupName}
85 |
86 |
87 |
88 | {images.map((value, index) => (
89 |
90 | ))}
91 |
92 |
93 |
94 | );
95 | });
96 |
--------------------------------------------------------------------------------
/src/components/LayoutScrollViewWithHeader.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions, Platform, RefreshControl } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import Header from './Header';
5 | import colors from './Global/colors';
6 |
7 | const DEVICE_WIDTH = Dimensions.get('window').width;
8 | const DEVICE_HEIGHT = Dimensions.get('window').height;
9 |
10 | const StyledSafeAreaView = styled.SafeAreaView`
11 | flex: 1;
12 | background-color: ${colors.primary};
13 | `;
14 |
15 | const StyledScrollView = styled.ScrollView`
16 | padding-bottom: 30;
17 | `;
18 |
19 | const StyledOverlay = styled.View`
20 | height: ${DEVICE_HEIGHT};
21 | width: ${DEVICE_WIDTH};
22 | background-color: 'rgba(29, 30, 33,0.5)';
23 | z-index: 1;
24 | position: absolute;
25 | `;
26 |
27 | /*
28 | View for Screen with scrolling content
29 | With sticky header outside scroll
30 | If there are textfields on the screen, use LayoutKeyboardAvoidingView
31 | */
32 |
33 | const LayoutScrollView = ({
34 | overlay,
35 | hasBar,
36 | width,
37 | backgroundColor,
38 | inputColor,
39 | value,
40 | placeholder,
41 | onChangeText,
42 | headerTitle,
43 | leftHeaderIcon,
44 | leftHeaderButtonAction,
45 | leftHeaderButtonTitle,
46 | rightHeaderButtonAction,
47 | rightHeaderButtonTitle,
48 | rightHeaderIcon,
49 | myRef,
50 | canRefresh,
51 | refreshing,
52 | onRefresh,
53 | children,
54 | }) => (
55 |
56 | {overlay && }
57 |
73 | onRefresh()}
91 | />
92 | )
93 | }
94 | >
95 | {children}
96 |
97 |
98 | );
99 |
100 | export default LayoutScrollView;
101 |
--------------------------------------------------------------------------------
/src/components/PickerItem.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import SInfo from 'react-native-sensitive-info';
4 | import styled from 'styled-components/native';
5 | import colors from './Global/colors';
6 |
7 | const StyledOptionText = styled.Text`
8 | font-size: 18px;
9 | font-weight: 600;
10 |
11 | ${props =>
12 | props.active &&
13 | `
14 | color: ${colors.highlightSoftRed};
15 | `}
16 | `;
17 |
18 | const StyledOption = styled.TouchableOpacity`
19 | display: flex;
20 | justify-content: center;
21 | padding-left: 20px;
22 | height: 60;
23 | border-left-width: 4px;
24 | border-color: transparent;
25 |
26 | ${props =>
27 | props.active &&
28 | `
29 | border-left-width: 4px;
30 | border-color: ${colors.highlightSoftRed};
31 | `}
32 | `;
33 |
34 | const StyledIndicatorWrapper = styled.View`
35 | flex-direction: row;
36 | align-items: center;
37 | `;
38 |
39 | const StyledIndicator = styled.View`
40 | width: 10;
41 | height: 10;
42 | border-radius: 5;
43 | background-color: ${colors.mediumAccent};
44 | margin-right: 5;
45 | `;
46 |
47 | class PickerItem extends Component {
48 | constructor(props) {
49 | super(props);
50 |
51 | this.state = {
52 | unread: false,
53 | };
54 | }
55 |
56 | componentDidMount() {
57 | this.determineUnread(this.props.item);
58 | }
59 |
60 | determineItemTitle = (item, type) => {
61 | if (type === 'likes') {
62 | return item.user.full_name;
63 | } else if (type === 'messageRecipient') {
64 | return item.full_name;
65 | } else {
66 | return item.name;
67 | }
68 | };
69 |
70 | determineUnread = item => {
71 | // console.log('ITEM ID ', item.id);
72 | SInfo.getItem(`${item.id}`, {})
73 | .then(date => {
74 | // console.log('DATE ', date, item.name);
75 | if (date) {
76 | const unreadPosts = item.posts.filter(
77 | post => new Date(post.created_at) >= new Date(date),
78 | );
79 | this.setState({ unread: unreadPosts.length > 0 });
80 | }
81 | })
82 | .catch(err => console.log('Error getting date ', err));
83 | };
84 |
85 | render() {
86 | const { item, activeId, selectedId, selectOption, type } = this.props;
87 | return (
88 | {
90 | selectOption(item);
91 | }}
92 | active={(activeId && activeId === item.id) || selectedId === item.id}
93 | >
94 |
95 | {this.state.unread && }
96 |
101 | {this.determineItemTitle(item, type)}
102 |
103 |
104 |
105 | );
106 | }
107 | }
108 | export default PickerItem;
109 |
--------------------------------------------------------------------------------
/src/components/FeedCardMainImage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import colors from './Global/colors';
5 |
6 | const DEVICE_WIDTH = Dimensions.get('window').width;
7 | const thirds = Dimensions.get('window').height / 3;
8 | const IMAGE_HEIGHT = thirds - 50;
9 |
10 | // console.log('IMAGE HEIGHT ', IMAGE_HEIGHT);
11 |
12 | const StyledImageButton = styled.TouchableOpacity``;
13 |
14 | const StyledMainImage = styled.Image`
15 | width: ${DEVICE_WIDTH - 48};
16 | height: ${IMAGE_HEIGHT};
17 | align-self: center;
18 | margin-top: 13;
19 | margin-bottom: 16;
20 | `;
21 |
22 | const StyledHalfImageRowView = styled.View`
23 | flex-direction: row;
24 | align-items: center;
25 | justify-content: space-evenly;
26 | margin-top: 13;
27 | margin-bottom: 16;
28 | `;
29 |
30 | const StyledHalfImage = styled.Image`
31 | width: ${(DEVICE_WIDTH - 45) / 2};
32 | height: ${IMAGE_HEIGHT};
33 | `;
34 |
35 | const StyledHalfImageOverlay = styled.View`
36 | background-color: rgba(29, 30, 33, 0.5);
37 | width: ${(DEVICE_WIDTH - 45) / 2};
38 | height: ${IMAGE_HEIGHT};
39 | position: absolute;
40 | z-index: 1;
41 | justify-content: center;
42 | `;
43 |
44 | const StyledOverlayCount = styled.Text`
45 | color: ${colors.white};
46 | font-weight: 600;
47 | line-height: 37px;
48 | font-size: 32px;
49 | letter-spacing: -0.196923px;
50 | align-self: center;
51 | `;
52 |
53 | export default (FeedCardMainImage = ({ images, openModal }) => {
54 | //Should all be touchable view that opens paging with all images
55 |
56 | if (images.length === 0) {
57 | return null;
58 | } else if (images.length === 1) {
59 | return (
60 | openModal({ images: images, index: 0 })}
62 | >
63 |
64 |
65 | );
66 | } else if (images.length === 2) {
67 | return (
68 |
69 | openModal({ images: images, index: 0 })}
71 | >
72 |
73 |
74 | openModal({ images: images, index: 1 })}
76 | >
77 |
78 |
79 |
80 | );
81 | } else {
82 | return (
83 |
84 | openModal({ images: images, index: 0 })}
86 | >
87 |
88 |
89 | openModal({ images: images, index: 1 })}
91 | >
92 |
93 | {`+${images.length - 2}`}
94 |
95 |
96 |
97 |
98 | );
99 | }
100 | });
101 |
--------------------------------------------------------------------------------
/src/components/ActionSheet.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Modal, Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import ActionSheetItem from './ActionSheetItem';
5 |
6 | import colors from './Global/colors';
7 |
8 | const DEVICE_WIDTH = Dimensions.get('window').width;
9 | const DEVICE_HEIGHT = Dimensions.get('window').height;
10 |
11 | const StyledView = styled.View``;
12 |
13 | const StyledTopView = styled.TouchableOpacity`
14 | height: ${props => props.height};
15 | background-color: transparent;
16 | `;
17 |
18 | const StyledActionSheet = styled.View`
19 | background-color: ${colors.white};
20 | border-top-left-radius: 15;
21 | border-top-right-radius: 15;
22 | `;
23 |
24 | const StyledTitle = styled.Text`
25 | color: ${colors.black};
26 | line-height: 20px;
27 | font-size: 22px;
28 | letter-spacing: -0.0861539px;
29 | padding-top: 28;
30 | padding-bottom: 28;
31 | padding-left: 20;
32 | `;
33 |
34 | const StyledDescription = styled.Text`
35 | line-height: 26px;
36 | font-size: 16px;
37 | text-align: center;
38 | letter-spacing: -0.0861539px;
39 | padding-bottom: 8;
40 | `;
41 |
42 | const StyledCancelButton = styled.TouchableOpacity`
43 | width: ${DEVICE_WIDTH};
44 | background-color: white;
45 | padding-top: 24;
46 | padding-bottom: 34;
47 | `;
48 |
49 | const StyledCancel = styled.Text`
50 | align-self: center;
51 | color: ${colors.mediumAccent};
52 | font-weight: 600;
53 | line-height: 18px;
54 | font-size: 18px;
55 | letter-spacing: -0.0861539px;
56 | `;
57 |
58 | class ActionSheet extends Component {
59 | constructor() {
60 | super();
61 | this.state = {
62 | height: DEVICE_HEIGHT - 100,
63 | };
64 | }
65 |
66 | calculateHeight = e => {
67 | const height = e.nativeEvent.layout.height;
68 | this.setState({ height: DEVICE_HEIGHT - height });
69 | };
70 |
71 | render() {
72 | return (
73 |
78 |
79 | this.props.closeModal()}
82 | />
83 | (this.actionSheet = ref)}
85 | onLayout={e => {
86 | this.calculateHeight(e);
87 | }}
88 | >
89 | {this.props.title}
90 | {this.props.description && (
91 | {this.props.description}
92 | )}
93 | {this.props.actions.map((value, index) => (
94 |
100 | ))}
101 | this.props.closeModal()}>
102 | Cancel
103 |
104 |
105 |
106 |
107 | );
108 | }
109 | }
110 |
111 | export default ActionSheet;
112 |
--------------------------------------------------------------------------------
/src/navigation/TabNavigator.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Platform, View } from 'react-native';
3 | import { createBottomTabNavigator, TabBarBottom } from 'react-navigation';
4 |
5 | import styled from 'styled-components/native';
6 | import HomeIcon from '../assets/images/HomeIcon.png';
7 | import HomeIconFilled from '../assets/images/HomeIconFilled.png';
8 | // import MessageIcon from '../assets/images/MessageIcon.png';
9 | // import MessageIconFilled from '../assets/images/MessageIconFilled.png';
10 | // import NotificationIcon from '../assets/images/NotificationIcon.png';
11 | // import NotificationIconFilled from '../assets/images/NotificationIconFilled.png';
12 | import MoreIcon from '../assets/images/MoreIcon.png';
13 | import MoreIconFilled from '../assets/images/MoreIconFilled.png';
14 |
15 | import MainFeedStack from './MainFeedStack';
16 |
17 | import SettingsStack from './SettingsStack';
18 |
19 | import colors from '../components/Global/colors';
20 |
21 | // import NotificationIndicator from '../PushNotifications/NotificationIndicator';
22 | // import MessageIndicator from '../PushNotifications/MessageIndicator';
23 |
24 | const StyledIcon = styled.Image`
25 | height: ${props => props.height};
26 | width: ${props => props.width};
27 | `;
28 |
29 | const TabNavigator = createBottomTabNavigator(
30 | {
31 | MainFeedTab: {
32 | screen: MainFeedStack,
33 | navigationOptions: {
34 | tabBarIcon: ({ tintColor, focused }) => (
35 |
40 | ),
41 | },
42 | },
43 | // MessagesTab: {
44 | // screen: MessagesStack,
45 | // navigationOptions: {
46 | // tabBarIcon: ({ tintColor, focused }) => (
47 | //
48 | //
49 | //
54 | //
55 | // ),
56 | // },
57 | // },
58 | // NotificationsTab: {
59 | // screen: NotificationsScreen,
60 | // navigationOptions: {
61 | // tabBarIcon: ({ tintColor, focused }) => (
62 | //
63 | //
64 | //
69 | //
70 | // ),
71 | // },
72 | // },
73 | MoreTab: {
74 | screen: SettingsStack,
75 | navigationOptions: {
76 | tabBarIcon: ({ tintColor, focused }) => (
77 |
82 | ),
83 | },
84 | },
85 | },
86 | {
87 | tabBarOptions: {
88 | showLabel: false,
89 | activeTintColor: colors.primary,
90 | inactiveTintColor: 'gray',
91 | },
92 | tabBarComponent: Platform.OS === 'ios' ? TabBarBottom : TabBarAndroid,
93 | tabBarPosition: 'bottom',
94 | },
95 | );
96 |
97 | export default TabNavigator;
98 |
--------------------------------------------------------------------------------
/src/constants/urls.js:
--------------------------------------------------------------------------------
1 | export const BASE_URL = `https://cratebind.com/api/v1`;
2 |
3 | // CONVERSATIONS
4 | export const GET_ALL_CONVERSATIONS = (
5 | organizationId,
6 | page,
7 | ) => `${BASE_URL}/conversations?organization_id=${organizationId}&page=${page ||
8 | 1}&per=20
9 | `;
10 | export const CREATE_CONVERSATION = `${BASE_URL}/conversations`;
11 | export const GET_SINGLE_CONVERSATION = convoId =>
12 | `${BASE_URL}/conversations/${convoId}`;
13 | export const MARK_CONVERSATION_READ = id =>
14 | `${BASE_URL}/conversations/${id}/mark_read`;
15 | export const POST_MESSAGE_TO_CONVERSATION = convoId =>
16 | `${BASE_URL}/conversations/${convoId}/messages`;
17 | export const DELETE_CONVERSATION = convoId =>
18 | `${BASE_URL}/conversations/${convoId}`;
19 |
20 | // DEVICES
21 | export const REGISTER_DEVICE = `${BASE_URL}/devices`;
22 | export const EDIT_DEVICE = deviceId => `${BASE_URL}/devices/${deviceId}`;
23 | export const DELETE_DEVICE = deviceId => `${BASE_URL}/devices/${deviceId}`;
24 |
25 | // NOTIFICATIONS
26 | export const GET_ALL_NOTIFICATIONS = (userId, page) =>
27 | `${BASE_URL}/users/${userId}/notifications?page=${page || 1}&per=20`;
28 | export const GET_AVAILABLE_NOTIFICATIONS = `${BASE_URL}/notifications/available_notifications`;
29 | export const MARK_NOTIFICATION_READ = notifId =>
30 | `${BASE_URL}/notifications/${notifId}/mark_read`;
31 |
32 | // POSTS
33 | export const GET_ALL_POSTS_FROM_GROUP = (groupId, page) =>
34 | `${BASE_URL}/groups/${groupId}/posts?page=${page || 1}&per=20`;
35 | export const GET_ALL_POSTS = (organizationId, page) =>
36 | `${BASE_URL}/posts?organization_id=${organizationId}&page=${page ||
37 | 1}&per=20`;
38 | export const CREATE_POST = `${BASE_URL}/posts`;
39 | export const UNLIKE_POST = postId => `${BASE_URL}/posts/${postId}/unlike`;
40 | export const LIKE_POST = postId => `${BASE_URL}/posts/${postId}/like`;
41 | export const DELETE_POST = postId => `${BASE_URL}/posts/${postId}`;
42 | export const GET_SINGLE_POST = postId => `${BASE_URL}/posts/${postId}`;
43 | export const EDIT_POST = postId => `${BASE_URL}/posts/${postId}`;
44 | // comments on posts
45 | export const CREATE_COMMENT_ON_POST = postId =>
46 | `${BASE_URL}/posts/${postId}/comments`;
47 | export const UNLIKE_COMMENT_ON_POST = (postId, commentId) =>
48 | `${BASE_URL}/posts/${postId}/comments/${commentId}/unlike`;
49 | export const LIKE_COMMENT_ON_POST = (postId, commentId) =>
50 | `${BASE_URL}/posts/${postId}/comments/${commentId}/like`;
51 | export const DELETE_COMMENT_ON_POST = (postId, commentId) =>
52 | `${BASE_URL}/posts/${postId}/comments/${commentId}`;
53 | export const EDIT_COMMENT_ON_POST = (postId, commentId) =>
54 | `${BASE_URL}/posts/${postId}/comments/${commentId}`;
55 |
56 | // USERS
57 | export const SIGN_UP = `${BASE_URL}/users/sign_up`;
58 | export const SIGN_IN = `${BASE_URL}/users/sign_in`;
59 | export const SIGN_OUT = `${BASE_URL}/users/sign_out`;
60 | export const FORGOT_PASSWORD = `${BASE_URL}/users/forgot_password`;
61 | export const UPDATE_PROFILE = userId => `${BASE_URL}/users/${userId}`;
62 | export const GET_CURRENT_USER = `${BASE_URL}/users`;
63 | export const GET_SINGLE_USER = userId => `${BASE_URL}/users/${userId}`;
64 | export const GET_NOTIFICATIONS_FOR_USER = (userId, page) =>
65 | `${BASE_URL}/users/${userId}/notifications?page=${page || 1}&per=20`;
66 | export const TOGGLE_NOTIFICATION = userId =>
67 | `${BASE_URL}/users/${userId}/toggle_notifications`;
68 |
--------------------------------------------------------------------------------
/src/screens/LaunchScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { ActivityIndicator } from 'react-native';
3 | import SInfo from 'react-native-sensitive-info';
4 | import { connect } from 'react-redux';
5 | import styled from 'styled-components/native';
6 | import { signInUser } from '../redux/actions/users.actions';
7 | import { setLoginType } from '../redux/actions/loginType.actions';
8 | import { resetStack } from '../util/helpers';
9 | import colors from '../components/Global/colors';
10 | import LogoIcon from '../components/LogoIcon';
11 |
12 | const StyledView = styled.View`
13 | flex: 1;
14 | align-items: center;
15 | justify-content: center;
16 | background-color: ${colors.primary};
17 | `;
18 |
19 | const Heading = styled.Text`
20 | font-style: normal;
21 | font-weight: bold;
22 | line-height: 45px;
23 | font-size: 34px;
24 | letter-spacing: -0.233846px;
25 | color: ${colors.white};
26 | `;
27 |
28 | const StyledHeadingView = styled.View`
29 | flex-direction: row;
30 | align-items: center;
31 | align-self: center;
32 | height: 45;
33 | `;
34 |
35 | const StyledLogoView = styled.View`
36 | margin-right: 10;
37 | `;
38 |
39 | class LaunchScreen extends Component {
40 | componentDidMount() {
41 | this.attemptAutoLogin();
42 | }
43 |
44 | componentDidUpdate(prevProps) {
45 | const { loginType, user, navigation } = this.props;
46 | // Only handle login from here if login type is auto login
47 | if (loginType === 'AUTO_LOGIN') {
48 | // If the user auth property comes back as successfull, send to Signed In
49 | // Or send to the Sign In screen
50 | if (
51 | prevProps.user.auth !== user.auth &&
52 | user.auth.includes('emailAuthComplete')
53 | ) {
54 | navigation.navigate('SignedIn');
55 | } else if (user.auth === 'failed') {
56 | resetStack(navigation, 'SignIn', 1000);
57 | }
58 | }
59 | }
60 |
61 | attemptAutoLogin = async () => {
62 | // Get saved information and send to signInUser endpoint
63 | const email = await SInfo.getItem('email', {});
64 | const password = await SInfo.getItem('password', {});
65 |
66 | if (email && password) {
67 | // To simulate successfull login
68 | setTimeout(() => this.props.navigation.navigate('SignedIn'), 2000);
69 | } else {
70 | // To simulate failed login
71 | resetStack(this.props.navigation, 'SignIn', 2000);
72 | }
73 |
74 | // this.props.signInUser(email, password);
75 |
76 | // // Set login type of auto login
77 | // this.props.setLoginType('AUTO_LOGIN');
78 | };
79 |
80 | render() {
81 | return (
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | RNTemplate
90 |
91 |
92 |
97 |
98 | );
99 | }
100 | }
101 |
102 | const mapStateToProps = state => ({
103 | user: state.user,
104 | loginType: state.loginType,
105 | });
106 |
107 | export default connect(
108 | mapStateToProps,
109 | {
110 | signInUser,
111 | setLoginType,
112 | },
113 | )(LaunchScreen);
114 |
--------------------------------------------------------------------------------
/src/components/Header.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import SearchBar from './SearchBar';
5 | import colors from './Global/colors';
6 |
7 | export const DEVICE_WIDTH = Dimensions.get('window').width;
8 |
9 | export const StyledHeader = styled.View`
10 | width: ${DEVICE_WIDTH};
11 | height: 80;
12 | background-color: ${colors.primary};
13 | top: 0;
14 | left: 0;
15 | right: 0;
16 | display: flex;
17 | flex-direction: row;
18 | align-items: center;
19 | justify-content: space-between;
20 | `;
21 |
22 | export const StyledHeaderTitle = styled.Text`
23 | font-weight: bold;
24 | font-size: 22px;
25 | text-align: center;
26 | letter-spacing: -0.0861539px;
27 | color: ${colors.white};
28 | `;
29 |
30 | export const StyledButtonText = styled.Text`
31 | color: #fff;
32 | font-weight: bold;
33 | text-decoration: underline;
34 | text-decoration-color: #fff;
35 | `;
36 |
37 | export const StyledLeftButton = styled.TouchableOpacity`
38 | margin-left: 11;
39 | display: flex;
40 | flex-direction: row;
41 | align-items: center;
42 | justify-content: flex-start;
43 | `;
44 |
45 | const StyledRightButton = styled.TouchableOpacity`
46 | margin-right: 16;
47 | display: flex;
48 | flex-direction: row;
49 | align-items: center;
50 | justify-content: flex-end;
51 | `;
52 |
53 | const StyledSearchBarView = styled.View`
54 | border-radius: 8;
55 | align-self: center;
56 | align-self: center;
57 | justify-content: center;
58 | height: 30;
59 | background-color: ${props => props.backgroundColor};
60 | `;
61 |
62 | export const StyledIcon = styled.Image``;
63 |
64 | export default (Header = props => {
65 | const {
66 | leftHeaderIcon,
67 | leftHeaderButtonAction,
68 | leftHeaderButtonTitle,
69 | rightHeaderIcon,
70 | rightHeaderButtonAction,
71 | rightHeaderButtonTitle,
72 | hasBar,
73 | value,
74 | placeholder,
75 | onChangeText,
76 | headerTitle,
77 | width,
78 | backgroundColor,
79 | inputColor,
80 | } = props;
81 | const hasLeftIcon = leftHeaderIcon !== undefined && leftHeaderIcon !== '';
82 |
83 | const hasRightIcon = rightHeaderIcon !== undefined && rightHeaderIcon !== '';
84 |
85 | return (
86 |
87 |
88 | {hasLeftIcon && }
89 | {leftHeaderButtonTitle !== '' && (
90 | {leftHeaderButtonTitle}
91 | )}
92 |
93 | {hasBar ? (
94 |
95 |
103 |
104 | ) : (
105 | {headerTitle}
106 | )}
107 |
108 | {hasRightIcon && }
109 | {rightHeaderButtonTitle !== '' && (
110 | {rightHeaderButtonTitle}
111 | )}
112 |
113 |
114 | );
115 | });
116 |
--------------------------------------------------------------------------------
/src/redux/api/notifications.js:
--------------------------------------------------------------------------------
1 | // Add auth token to all authorization headers
2 | import {
3 | GET_ALL_NOTIFICATIONS,
4 | GET_AVAILABLE_NOTIFICATIONS,
5 | MARK_NOTIFICATION_READ,
6 | REGISTER_DEVICE,
7 | EDIT_DEVICE,
8 | DELETE_DEVICE,
9 | } from '../../constants/urls';
10 | import SInfo from 'react-native-sensitive-info';
11 |
12 | export const getAll = async (userId, page) => {
13 | const token = await SInfo.getItem('authToken', {});
14 | const response = await fetch(GET_ALL_NOTIFICATIONS(userId, page), {
15 | headers: {
16 | Authorization: token,
17 | },
18 | });
19 | // console.log(response);
20 | return response.json();
21 | };
22 |
23 | export const mark = async notifId => {
24 | const token = await SInfo.getItem('authToken', {});
25 | const response = await fetch(MARK_NOTIFICATION_READ(notifId), {
26 | method: 'PUT',
27 | headers: {
28 | Authorization: token,
29 | },
30 | });
31 | return response.json();
32 | };
33 |
34 | export const getAvailable = async () => {
35 | const token = await SInfo.getItem('authToken', {});
36 | const response = await fetch(GET_AVAILABLE_NOTIFICATIONS, {
37 | headers: {
38 | Authorization: token,
39 | },
40 | });
41 | return response.json();
42 | };
43 |
44 | // DEVICES
45 |
46 | export const register = async (type, deviceToken) => {
47 | const token = await SInfo.getItem('authToken', {});
48 | // console.log('AUTH TOKEN ', token);
49 | // console.log('URL ', REGISTER_DEVICE);
50 | const response = await fetch(REGISTER_DEVICE, {
51 | method: 'POST',
52 | headers: {
53 | 'Content-Type': 'application/json',
54 | Authorization: token,
55 | },
56 | body: JSON.stringify({
57 | is_type: type,
58 | device_token: deviceToken,
59 | }),
60 | });
61 | return response.json();
62 | };
63 |
64 | export const editBadge = async (type, badgeCount) => {
65 | const token = await SInfo.getItem('authToken', {});
66 | const deviceId = await SInfo.getItem('deviceId', {});
67 | const deviceToken = await SInfo.getItem('deviceToken', {});
68 | const response = await fetch(EDIT_DEVICE(parseInt(deviceId)), {
69 | method: 'PUT',
70 | headers: {
71 | 'Content-Type': 'application/json',
72 | Authorization: token,
73 | },
74 | body: JSON.stringify({
75 | is_type: type,
76 | device_token: deviceToken,
77 | notification_count: badgeCount,
78 | }),
79 | });
80 | return response.json();
81 | };
82 |
83 | export const editToken = async (type, deviceToken) => {
84 | const token = await SInfo.getItem('authToken', {});
85 | const deviceId = await SInfo.getItem('deviceId', {});
86 | // const deviceToken = await SInfo.getItem('deviceToken', {});
87 | const response = await fetch(EDIT_DEVICE(parseInt(deviceId)), {
88 | method: 'PUT',
89 | headers: {
90 | 'Content-Type': 'application/json',
91 | Authorization: token,
92 | },
93 | body: JSON.stringify({
94 | is_type: type,
95 | device_token: deviceToken,
96 | }),
97 | });
98 | return response.json();
99 | };
100 |
101 | export const deleteDevice = async () => {
102 | const token = await SInfo.getItem('authToken', {});
103 | const deviceId = await SInfo.getItem('deviceId', {});
104 | const response = await fetch(DELETE_DEVICE(parseInt(deviceId)), {
105 | method: 'DELETE',
106 | headers: {
107 | Authorization: token,
108 | },
109 | });
110 | return response.json();
111 | };
112 |
--------------------------------------------------------------------------------
/ios/ReactNativeTemplate/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/redux/api/users.js:
--------------------------------------------------------------------------------
1 | import {
2 | SIGN_UP,
3 | SIGN_IN,
4 | FORGOT_PASSWORD,
5 | SIGN_OUT,
6 | UPDATE_PROFILE,
7 | GET_CURRENT_USER,
8 | GET_SINGLE_USER,
9 | GET_NOTIFICATIONS_FOR_USER,
10 | TOGGLE_NOTIFICATION,
11 | } from '../../constants/urls';
12 | import SInfo from 'react-native-sensitive-info';
13 |
14 | export const signUp = async ({
15 | organization_id,
16 | organization_name,
17 | organization_url,
18 | organization_phone,
19 | first_name,
20 | last_name,
21 | email,
22 | password,
23 | }) => {
24 | const response = await fetch(SIGN_UP, {
25 | method: 'POST',
26 | headers: {
27 | 'Content-Type': 'application/json',
28 | },
29 | body: JSON.stringify({
30 | organization_id,
31 | organization_name,
32 | organization_url,
33 | organization_phone,
34 | first_name,
35 | last_name,
36 | email,
37 | password,
38 | }),
39 | });
40 | return response.json();
41 | };
42 |
43 | export const emailAuth = async (email, password) => {
44 | // console.log('CALLING SIGN IN ');
45 | const response = await fetch(SIGN_IN, {
46 | method: 'POST',
47 | headers: {
48 | 'Content-Type': 'application/json',
49 | },
50 | body: JSON.stringify({
51 | email,
52 | password,
53 | }),
54 | });
55 | return response.json();
56 | };
57 |
58 | export const signOut = async () => {
59 | const response = await fetch(SIGN_OUT, {
60 | method: 'POST',
61 | headers: {
62 | 'Content-Type': 'application/json',
63 | },
64 | });
65 | return response.json();
66 | };
67 |
68 | export const forgotPassword = async email => {
69 | const response = await fetch(FORGOT_PASSWORD, {
70 | method: 'POST',
71 | headers: {
72 | 'Content-Type': 'application/json',
73 | },
74 | body: JSON.stringify({
75 | email,
76 | }),
77 | });
78 | return response.json();
79 | };
80 |
81 | export const get = async () => {
82 | const token = await SInfo.getItem('authToken', {});
83 | const response = await fetch(GET_CURRENT_USER, {
84 | headers: {
85 | 'Content-Type': 'application/json',
86 | Authorization: token,
87 | },
88 | });
89 | return response.json();
90 | };
91 |
92 | export const getSingle = async userId => {
93 | const token = await SInfo.getItem('authToken', {});
94 | const response = await fetch(GET_SINGLE_USER(userId), {
95 | headers: {
96 | 'Content-Type': 'application/json',
97 | Authorization: token,
98 | },
99 | });
100 | return response.json();
101 | };
102 |
103 | export const getNotifications = async userId => {
104 | const token = await SInfo.getItem('authToken', {});
105 | const response = await fetch(GET_NOTIFICATIONS_FOR_USER(userId), {
106 | headers: {
107 | 'Content-Type': 'application/json',
108 | Authorization: token,
109 | },
110 | });
111 | return response.json();
112 | };
113 |
114 | export const toggle = async (userId, notification) => {
115 | const token = await SInfo.getItem('authToken', {});
116 | const response = await fetch(TOGGLE_NOTIFICATION(userId), {
117 | method: 'PUT',
118 | headers: {
119 | 'Content-Type': 'application/json',
120 | Authorization: token,
121 | },
122 | body: JSON.stringify({
123 | notification_name: `${notification}`,
124 | }),
125 | });
126 | return response.json();
127 | };
128 |
129 | export const update = async (userId, formData) => {
130 | const token = await SInfo.getItem('authToken', {});
131 | const response = await fetch(UPDATE_PROFILE(userId), {
132 | method: 'PUT',
133 | headers: {
134 | 'Content-Type': 'application/json',
135 | Authorization: token,
136 | },
137 | body: formData,
138 | });
139 | return response.json();
140 | };
141 |
--------------------------------------------------------------------------------
/src/components/HeaderDetail.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Dimensions } from 'react-native';
3 | import styled from 'styled-components/native';
4 | import colors from './Global/colors';
5 | import Avatar from './Avatar';
6 |
7 | export const DEVICE_WIDTH = Dimensions.get('window').width;
8 |
9 | const StyledHeader = styled.View`
10 | width: ${DEVICE_WIDTH};
11 | height: 120;
12 | background-color: ${colors.white};
13 | justify-content: center;
14 | padding-left: 10;
15 | `;
16 |
17 | const StyledBottomLine = styled.View`
18 | width: ${DEVICE_WIDTH};
19 | height: 2;
20 | background-color: ${colors.background};
21 | `;
22 |
23 | const StyledHeaderTitle = styled.Text`
24 | font-weight: bold;
25 | font-size: 22px;
26 | letter-spacing: -0.0861539px;
27 | color: ${colors.black};
28 | margin-top: 23;
29 | `;
30 |
31 | const StyledRowView = styled.View`
32 | flex-direction: row;
33 | align-items: flex-end;
34 | justify-content: space-between;
35 | `;
36 |
37 | const StyledButtonText = styled.Text`
38 | color: ${colors.darkNeutral};
39 | font-style: normal;
40 | font-weight: bold;
41 | line-height: 16px;
42 | font-size: 14px;
43 | letter-spacing: -0.0861539px;
44 | text-decoration: underline;
45 | text-decoration-color: ${colors.darkNeutral};
46 | `;
47 |
48 | export const StyledLeftButton = styled.TouchableOpacity`
49 | flex-direction: row;
50 | align-items: center;
51 | justify-content: flex-start;
52 | margin-top: 10;
53 | `;
54 |
55 | const StyledRightButton = styled.TouchableOpacity`
56 | margin-right: 16;
57 | flex-direction: row;
58 | align-items: center;
59 | justify-content: center;
60 | `;
61 |
62 | export const StyledIcon = styled.Image``;
63 |
64 | export default (HeaderDetail = props => {
65 | const {
66 | leftHeaderIcon,
67 | leftHeaderButtonAction,
68 | leftHeaderButtonTitle,
69 | rightHeaderIcon,
70 | rightHeaderButtonAction,
71 | rightHeaderButtonTitle,
72 | headerTitle,
73 | hasRightSingleAvatar,
74 | user,
75 | hasRightGroupAvatar,
76 | group,
77 | } = props;
78 | const hasLeftIcon = leftHeaderIcon !== undefined && leftHeaderIcon !== '';
79 |
80 | const hasRightIcon = rightHeaderIcon !== undefined && rightHeaderIcon !== '';
81 |
82 | return (
83 | <>
84 |
85 |
86 | {hasLeftIcon && }
87 | {leftHeaderButtonTitle !== '' && (
88 | {leftHeaderButtonTitle}
89 | )}
90 |
91 |
92 | {headerTitle}
93 |
94 | {hasRightIcon && }
95 | {rightHeaderButtonTitle !== '' && (
96 | {rightHeaderButtonTitle}
97 | )}
98 | {hasRightSingleAvatar && (
99 |
103 | props.navigation.navigate('Profile', {
104 | user,
105 | })
106 | }
107 | firstName={user.first_name}
108 | lastName={user.last_name}
109 | />
110 | )}
111 | {hasRightGroupAvatar && (
112 |
116 | console.log('on select user from paging view')
117 | }
118 | firstName={group.name}
119 | lastName=""
120 | />
121 | )}
122 |
123 |
124 |
125 |
126 | >
127 | );
128 | });
129 |
--------------------------------------------------------------------------------
/src/components/ProfileItemCard.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Dimensions } from 'react-native';
3 | import { TextInputMask } from 'react-native-masked-text';
4 | import styled from 'styled-components/native';
5 | import colors from './Global/colors';
6 |
7 | const DEVICE_WIDTH = Dimensions.get('window').width;
8 |
9 | const StyledView = styled.View`
10 | flex-direction: row;
11 | align-items: center;
12 | justify-content: space-between;
13 | width: ${DEVICE_WIDTH - 10};
14 | background-color: ${colors.white};
15 | margin-left: 10;
16 | padding-left: 10;
17 | border-radius: 3;
18 | margin-top: 10;
19 | align-self: flex-end;
20 | height: 53;
21 | `;
22 |
23 | const StyledIconView = styled.TouchableOpacity`
24 | margin-right: 24;
25 | `;
26 |
27 | const StyledImage = styled.Image``;
28 |
29 | const StyledInput = styled.TextInput`
30 | color: ${colors.darkNeutral};
31 | font-style: normal;
32 | font-weight: 600;
33 | line-height: 19px;
34 | font-size: 14px;
35 | letter-spacing: -0.0984616px;
36 | flex: 1;
37 | `;
38 |
39 | const StyledPickerButton = styled.TouchableOpacity`
40 | width: ${DEVICE_WIDTH - 70};
41 | `;
42 |
43 | const StyledLabel = styled.Text`
44 | color: ${colors.darkNeutral};
45 | font-style: normal;
46 | font-weight: 600;
47 | line-height: 19px;
48 | font-size: 14px;
49 | letter-spacing: -0.0984616px;
50 | `;
51 |
52 | const StyledPlaceholder = styled.Text`
53 | color: ${colors.mediumNeutral};
54 | font-style: normal;
55 | font-weight: 600;
56 | line-height: 19px;
57 | font-size: 14px;
58 | letter-spacing: -0.0984616px;
59 | `;
60 |
61 | const inputStyles = {
62 | color: colors.darkNeutral,
63 | fontStyle: 'normal',
64 | fontWeight: '600',
65 | lineHeight: 19,
66 | fontSize: 14,
67 | letterSpacing: -0.0984616,
68 | flex: 1,
69 | };
70 |
71 | class ProfileItemCard extends Component {
72 | onPressIcon = () => {
73 | if (this.props.isMasked) {
74 | const el = this.refs.textfield.getElement();
75 | // el.focus()
76 | el.focus();
77 | } else if (this.props.isPicker) {
78 | this.props.onSelectPicker();
79 | } else {
80 | this.textField.focus();
81 | }
82 | };
83 |
84 | handleEditIcon = () => {
85 | this.setState({ isEditable: true });
86 | };
87 | render() {
88 | let maskedValue;
89 | maskedValue = this.props.value === 'Invalid date' ? '' : this.props.value;
90 | maskedValue = this.props.value === 'null' ? '' : this.props.value;
91 | return (
92 |
93 | {this.props.isMasked && (
94 | this.props.onChangeText(value)}
101 | hasError={this.props.hasError}
102 | placeholderTextColor={colors.mediumNeutral}
103 | style={inputStyles}
104 | ref="textfield"
105 | />
106 | )}
107 |
108 | {!this.props.isMasked && !this.props.isPicker && (
109 | this.props.onChangeText(value)}
113 | hasError={this.props.hasError}
114 | placeholderTextColor={colors.mediumNeutral}
115 | ref={ref => (this.textField = ref)}
116 | />
117 | )}
118 | {this.props.isPicker && (
119 |
120 | {this.props.value && (
121 |
122 | {this.props.value === 'null' ? null : this.props.value}
123 |
124 | )}
125 | {(!this.props.value || this.props.value === 'null') && (
126 | {this.props.placeholder}
127 | )}
128 |
129 | )}
130 | this.onPressIcon()}>
131 |
132 |
133 |
134 | );
135 | }
136 | }
137 |
138 | export default ProfileItemCard;
139 |
--------------------------------------------------------------------------------
/src/components/CommentCard.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Dimensions } from 'react-native';
3 | import moment from 'moment';
4 | import styled from 'styled-components/native';
5 | import Ionicons from 'react-native-vector-icons/Ionicons';
6 | import Avatar from './Avatar';
7 | import colors from './Global/colors';
8 | import LikeReactionItem from './LikeReactionItem';
9 |
10 | const DEVICE_WIDTH = Dimensions.get('window').width;
11 |
12 | const StyledMainView = styled.View`
13 | width: ${DEVICE_WIDTH - 20};
14 | background-color: ${colors.offWhite};
15 | margin-top: 2;
16 | `;
17 |
18 | const StyledRowView = styled.View`
19 | flex-direction: row;
20 | align-items: center;
21 | padding-left: 14;
22 | padding-bottom: 9;
23 | `;
24 |
25 | const StyledName = styled.Text`
26 | margin-left: 9;
27 | color: ${colors.darkNeutral};
28 | font-weight: bold;
29 | line-height: 14px;
30 | font-size: 12px;
31 | letter-spacing: -0.0738462px;
32 | `;
33 |
34 | const StyledTime = styled.Text`
35 | text-align: right;
36 | font-size: 11;
37 | margin-top: 9;
38 | margin-right: 14;
39 | color: ${colors.mediumNeutral};
40 | font-weight: 600;
41 | line-height: 11px;
42 | font-size: 9px;
43 | letter-spacing: -0.0553846px;
44 | `;
45 |
46 | const StyledContent = styled.Text`
47 | width: ${DEVICE_WIDTH - 48};
48 | color: ${colors.darkNeutral};
49 | font-weight: 600;
50 | line-height: 18px;
51 | font-size: 11px;
52 | letter-spacing: -0.0738462px;
53 | align-self: center;
54 | `;
55 |
56 | const StyledLikeRowView = styled.View`
57 | flex-direction: row;
58 | align-items: center;
59 | justify-content: flex-start;
60 | padding-top: 8;
61 | padding-bottom: 8;
62 | padding-left: 14;
63 | background: ${colors.offWhite};
64 | width: ${DEVICE_WIDTH - 48};
65 | `;
66 |
67 | const StyledButton = styled.TouchableOpacity`
68 | right: 16;
69 | top: 24;
70 | position: absolute;
71 | `;
72 |
73 | class CommentCard extends Component {
74 | constructor(props) {
75 | super(props);
76 |
77 | this.state = {
78 | likesOpen: false,
79 | userLiked: false,
80 | };
81 | }
82 |
83 | componentDidMount() {
84 | this.determineIfUserLiked();
85 | }
86 |
87 | componentDidUpdate(prevProps, prevState) {
88 | // console.log('Comment Card Updating ', this.props);
89 | if (
90 | prevProps.comment.reactions.length !== this.props.comment.reactions.length
91 | ) {
92 | this.determineIfUserLiked();
93 | }
94 | }
95 |
96 | determineIfUserLiked = () => {
97 | // filter through likes, compare with currentUser Id and set accordingly
98 | if (this.props.currentUserId) {
99 | // console.log('CURRENT USER ID ', this.props.currentUserId);
100 | const filtered = this.props.comment.reactions.filter(
101 | reaction => reaction.user.id === this.props.currentUserId,
102 | );
103 | this.setState({ userLiked: filtered.length > 0 });
104 | }
105 | };
106 |
107 | onPressLike = () => {
108 | if (this.state.userLiked) {
109 | this.setState({
110 | userLiked: false,
111 | });
112 | this.props.onPressUnlike(this.props.comment);
113 | } else {
114 | this.setState({
115 | userLiked: true,
116 | });
117 | this.props.onPressLike(this.props.comment);
118 | }
119 | };
120 |
121 | render() {
122 | // console.log('Comment Card ', this.props);
123 | const {
124 | content,
125 | created_at,
126 | post_id,
127 | reactions,
128 | user,
129 | } = this.props.comment;
130 | const timeAgo = moment(created_at).fromNow();
131 | return (
132 |
133 | {timeAgo}
134 |
135 |
141 | console.log('selected profile from comment card')
142 | }
143 | />
144 | {user.full_name}
145 |
146 | {user.id === this.props.currentUserId && (
147 |
149 | this.props.showCommentOptionModal(this.props.comment)
150 | }
151 | >
152 |
153 |
154 | )}
155 | {content}
156 |
157 | this.onPressLike()}
162 | open={this.props.likesOpen}
163 | toggleOpen={() => this.props.onPressViewLikes()}
164 | userLiked={this.state.userLiked}
165 | />
166 |
167 |
168 | );
169 | }
170 | }
171 |
172 | export default CommentCard;
173 |
--------------------------------------------------------------------------------
/src/redux/reducers/posts.reducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | POSTS,
3 | SINGLE_POST,
4 | LIKE_POST,
5 | UNLIKE_POST,
6 | COMMENT_POST,
7 | LIKE_COMMENT,
8 | UNLIKE_COMMENT,
9 | NEW_POST,
10 | EDIT_POST,
11 | DELETE_POST,
12 | EDIT_COMMENT,
13 | DELETE_COMMENT,
14 | } from '../actions/posts.actions';
15 |
16 | // Initial state
17 | const initialState = { status: 'pending', currentPage: 1, allPages: 1 };
18 |
19 | // Reducer
20 | export default function posts(state = initialState, action) {
21 | switch (action.type) {
22 | case POSTS:
23 | // console.log('STATE ', state.results);
24 | // console.log('PAYLOAD ', action.payload.results);
25 | if (action.payload.currentPage !== 1) {
26 | return {
27 | status: action.payload.status,
28 | results: [...state.results, ...action.payload.results],
29 | currentPage: action.payload.currentPage,
30 | allPages: action.payload.allPages,
31 | };
32 | } else {
33 | return { ...state, ...action.payload };
34 | }
35 | case SINGLE_POST:
36 | return { status: action.payload.status, results: action.payload.results };
37 | case NEW_POST:
38 | return {
39 | ...state,
40 | status: action.payload.status,
41 | results: action.payload.results,
42 | };
43 | case EDIT_POST:
44 | return {
45 | ...state,
46 | status: action.payload.status,
47 | results: action.payload.results,
48 | };
49 | case DELETE_POST:
50 | return {
51 | ...state,
52 | status: action.payload.status,
53 | results: action.payload.results,
54 | };
55 | case LIKE_POST:
56 | // const likedElementPos = state.results
57 | // .map(x => {
58 | // return x.id;
59 | // })
60 | // .indexOf(action.payload.results.id);
61 |
62 | // const updatedFromLike = state.results;
63 | // Updated post is in action.payload.results
64 | // updatedFromLike.splice(likedElementPos, 1, action.payload.results);
65 |
66 | // Return updated post
67 | return {
68 | ...state,
69 | status: action.payload.status,
70 | results: action.payload.results,
71 | };
72 | case UNLIKE_POST:
73 | // const unlikedElementPos = state.results
74 | // .map(x => {
75 | // return x.id;
76 | // })
77 | // .indexOf(action.payload.results.id);
78 |
79 | // Remove reaction from current user from posts reactions array
80 | const filteredReactions = action.payload.results.reactions.filter(
81 | reaction => reaction.user.id !== action.payload.userId,
82 | );
83 | // Create new post with updated reactions
84 | const updatedPost = {
85 | ...action.payload.results,
86 | reactions: filteredReactions,
87 | };
88 |
89 | // const updatedFromUnliked = state.results;
90 | // updatedFromUnliked.splice(unlikedElementPos, 1, updatedPost);
91 | // // Create new posts array with other posts and updated post
92 | return {
93 | ...state,
94 | status: action.payload.status,
95 | results: updatedPost,
96 | };
97 | case COMMENT_POST:
98 | // // Get other posts that didn't have the reaction added
99 | // const filteredCommentPosts = state.results.filter(
100 | // post => post.id !== action.payload.results.id,
101 | // );
102 | // Return posts array with updated post added (new comment is added in action created from response)
103 | return {
104 | ...state,
105 | status: action.payload.status,
106 | results: action.payload.results,
107 | };
108 | case LIKE_COMMENT:
109 | // Add new reaction to comments array on post, return post and comment
110 | return {
111 | ...state,
112 | status: action.payload.status,
113 | results: action.payload.results,
114 | comment: {
115 | ...action.payload.comment,
116 | reactions: [
117 | ...action.payload.comment.reactions,
118 | action.payload.newReaction,
119 | ],
120 | },
121 | };
122 | case UNLIKE_COMMENT:
123 | // console.log('Payload ', action.payload);
124 | // Remove reaction from current user from comments reactions array
125 | const filteredReactionsToComment = action.payload.comment.reactions.filter(
126 | reaction => reaction.user.id !== action.payload.userId,
127 | );
128 | return {
129 | ...state,
130 | status: action.payload.status,
131 | results: action.payload.results,
132 | comment: {
133 | ...action.payload.comment,
134 | reactions: filteredReactionsToComment,
135 | },
136 | };
137 | case EDIT_COMMENT:
138 | return {
139 | ...state,
140 | status: action.payload.status,
141 | results: action.payload.results,
142 | };
143 | case DELETE_COMMENT:
144 | return {
145 | ...state,
146 | status: action.payload.status,
147 | results: action.payload.results,
148 | };
149 | default:
150 | return state;
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/redux/api/groups.js:
--------------------------------------------------------------------------------
1 | import {
2 | GET_ALL_GROUPS,
3 | CREATE_GROUP,
4 | LEAVE_GROUP,
5 | ADD_TO_GROUP,
6 | REQUEST_TO_JOIN_GROUP,
7 | GET_SINGLE_GROUP,
8 | EDIT_GROUP,
9 | ASSIGN_GROUP_ADMIN,
10 | ACCEPT_REQUEST,
11 | REMOVE_USER,
12 | REQUEST_TO_ADD_USER_TO_GROUP,
13 | } from '../../constants/urls';
14 | import SInfo from 'react-native-sensitive-info';
15 |
16 | export const getAll = async page => {
17 | const orgId = await SInfo.getItem('defaultOrgId', {});
18 | const token = await SInfo.getItem('authToken', {});
19 | const response = await fetch(GET_ALL_GROUPS(parseInt(orgId), page), {
20 | headers: {
21 | 'Content-Type': 'application/json',
22 | Authorization: token,
23 | },
24 | });
25 | return response.json();
26 | };
27 |
28 | export const getSingle = async groupId => {
29 | const token = await SInfo.getItem('authToken', {});
30 | const response = await fetch(GET_SINGLE_GROUP(groupId), {
31 | headers: {
32 | 'Content-Type': 'application/json',
33 | Authorization: token,
34 | },
35 | });
36 | return response.json();
37 | };
38 |
39 | export const create = async (formdata, users) => {
40 | const orgId = await SInfo.getItem('defaultOrgId', {});
41 | const token = await SInfo.getItem('authToken', {});
42 | formdata.append('organization_id', parseInt(orgId));
43 | // console.log('CREATE GROUP WITH USERS URL ', CREATE_GROUP(users));
44 | const response = await fetch(CREATE_GROUP(users), {
45 | method: 'POST',
46 | headers: {
47 | Authorization: token,
48 | },
49 | body: formdata,
50 | });
51 | // console.log('form data ', formdata);
52 | console.log('response ', response);
53 | return response.json();
54 | };
55 |
56 | export const leave = async groupId => {
57 | const token = await SInfo.getItem('authToken', {});
58 | const response = await fetch(LEAVE_GROUP(groupId), {
59 | method: 'PUT',
60 | headers: {
61 | 'Content-Type': 'application/json',
62 | Authorization: token,
63 | },
64 | });
65 | return response.json();
66 | };
67 |
68 | export const add = async (groupId, userId, isAdmin) => {
69 | // console.log(groupId, userId, isAdmin);
70 | // console.log(ADD_TO_GROUP(groupId));
71 | const token = await SInfo.getItem('authToken', {});
72 | const response = await fetch(ADD_TO_GROUP(groupId), {
73 | method: 'PUT',
74 | headers: {
75 | 'Content-Type': 'application/json',
76 | Authorization: token,
77 | },
78 | body: JSON.stringify({
79 | user_id: userId,
80 | is_admin: isAdmin,
81 | }),
82 | });
83 | // console.log(response);
84 | return response.json();
85 | };
86 |
87 | export const request = async groupId => {
88 | const token = await SInfo.getItem('authToken', {});
89 | const response = await fetch(REQUEST_TO_JOIN_GROUP(groupId), {
90 | headers: {
91 | 'Content-Type': 'application/json',
92 | Authorization: token,
93 | },
94 | });
95 | // console.log(response);
96 | return response.json();
97 | };
98 |
99 | export const requestOtherUser = async (groupId, userId) => {
100 | const token = await SInfo.getItem('authToken', {});
101 | const response = await fetch(REQUEST_TO_ADD_USER_TO_GROUP(groupId, userId), {
102 | headers: {
103 | 'Content-Type': 'application/json',
104 | Authorization: token,
105 | },
106 | });
107 | // console.log(response);
108 | return response.json();
109 | };
110 |
111 | export const accept = async (groupId, userId) => {
112 | const token = await SInfo.getItem('authToken', {});
113 | const response = await fetch(ACCEPT_REQUEST(groupId), {
114 | method: 'PUT',
115 | headers: {
116 | 'Content-Type': 'application/json',
117 | Authorization: token,
118 | },
119 | body: JSON.stringify({
120 | user_id: userId,
121 | }),
122 | });
123 | return response.json();
124 | };
125 |
126 | export const remove = async (groupId, userId) => {
127 | const token = await SInfo.getItem('authToken', {});
128 | const response = await fetch(REMOVE_USER(groupId), {
129 | method: 'PUT',
130 | headers: {
131 | 'Content-Type': 'application/json',
132 | Authorization: token,
133 | },
134 | body: JSON.stringify({
135 | user_id: userId,
136 | }),
137 | });
138 | return response.json();
139 | };
140 |
141 | export const assign = async (groupId, userId) => {
142 | const token = await SInfo.getItem('authToken', {});
143 | // console.log('URL ', ASSIGN_GROUP_ADMIN(groupId));
144 | const response = await fetch(ASSIGN_GROUP_ADMIN(groupId), {
145 | method: 'PUT',
146 | headers: {
147 | 'Content-Type': 'application/json',
148 | Authorization: token,
149 | },
150 | body: JSON.stringify({
151 | user_id: userId,
152 | }),
153 | });
154 | // console.log(response);
155 | return response.json();
156 | };
157 |
158 | export const edit = async (groupId, formdata) => {
159 | const token = await SInfo.getItem('authToken', {});
160 | const response = await fetch(EDIT_GROUP(groupId), {
161 | method: 'PUT',
162 | headers: {
163 | 'Content-Type': 'application/json',
164 | Authorization: token,
165 | },
166 | body: formdata,
167 | });
168 | return response.json();
169 | };
170 |
--------------------------------------------------------------------------------
/src/screens/ProfileScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import moment from 'moment';
3 | import styled from 'styled-components/native';
4 | import LayoutScrollViewWithHeader from '../components/LayoutScrollViewWithHeader';
5 | import Avatar from '../components/Avatar';
6 | import Label from '../components/Label';
7 | import colors from '../components/Global/colors';
8 | import AboutCard from '../components/AboutCard';
9 | import SectionCard from '../components/SectionCard';
10 | import SettingsIcon from '../assets/images/SettingsIcon.png';
11 | import Profile from '../assets/images/pam-beesly.jpg'
12 |
13 | const fakeUser = {
14 | avatar_url: Profile,
15 | city: 'Scranton',
16 | created_at: '2019-02-28T16:21:31.390Z',
17 | date_of_birth: '1078-01-01T00:00:00.000Z',
18 | email: 'pam@scc.com',
19 | first_name: 'Pam',
20 | full_name: 'Pam Halpert',
21 | gender: 'Female',
22 | id: 84,
23 | is_super_admin: false,
24 | last_name: 'Halpert',
25 | organization_ids: [44],
26 | phone: '5555555532',
27 | state: 'PA',
28 | zip: '18503',
29 | };
30 |
31 | const StyledColumnView = styled.View`
32 | flex-direction: column;
33 | margin-left: 10;
34 | `;
35 |
36 | const StyledRowView = styled.View`
37 | flex-direction: row;
38 | align-items: center;
39 | padding-top: 15;
40 | padding-bottom: 15;
41 | `;
42 |
43 | const StyledName = styled.Text`
44 | color: ${colors.black};
45 | font-style: normal;
46 | font-weight: bold;
47 | font-size: 20px;
48 | letter-spacing: -0.0738462px;
49 | margin-bottom: 8;
50 | `;
51 |
52 | const StyledOrganization = styled.Text`
53 | color: ${colors.mediumNeutral};
54 | font-weight: 600;
55 | line-height: 16px;
56 | font-size: 12px;
57 | letter-spacing: -0.0861539px;
58 | `;
59 |
60 | const StyledInfoView = styled.View``;
61 |
62 | const StyledButton = styled.TouchableOpacity`
63 | height: 35;
64 | display: flex;
65 | margin-left: -10;
66 | justify-content: center;
67 | background-color: ${colors.primary};
68 | `;
69 |
70 | const StyledButtonText = styled.Text`
71 | font-style: normal;
72 | font-weight: 600;
73 | line-height: 18px;
74 | font-size: 12px;
75 | text-align: center;
76 | letter-spacing: -0.0861539px;
77 | color: ${colors.white};
78 | `;
79 |
80 | class ProfileScreen extends Component {
81 | constructor(props) {
82 | super(props);
83 |
84 | this.state = {
85 | user: fakeUser,
86 | };
87 | }
88 |
89 | handleFirstLargeButton = () => {
90 | this.props.navigation.navigate('EditProfile', { user: this.state.user });
91 | };
92 |
93 | verifyContent = val => {
94 | if (val !== null && val !== 'null' && val !== '') {
95 | return true;
96 | }
97 | return false;
98 | };
99 |
100 | createInfoArray = (date_of_birth, city, state, zip, gender) => {
101 | // Get age
102 | const age = date_of_birth ? moment().diff(date_of_birth, 'years') : null;
103 | // Create location array
104 | const locArr = [city, state, zip];
105 | const location = locArr
106 | .filter(loc => {
107 | return this.verifyContent(loc);
108 | })
109 | .join(', ');
110 | // Create gender, age array
111 | const ageGenArr = [gender, age];
112 | const ageGen = ageGenArr
113 | .filter(item => {
114 | return this.verifyContent(item);
115 | })
116 | .join(', ');
117 | return [ageGen, location];
118 | };
119 |
120 | render() {
121 | const {
122 | first_name,
123 | last_name,
124 | full_name,
125 | avatar_url,
126 | date_of_birth,
127 | gender,
128 | city,
129 | state,
130 | zip,
131 | } = this.state.user;
132 | return (
133 |
138 | this.props.navigation.navigate('Settings')
139 | }
140 | >
141 |
142 |
143 | console.log('selected user')}
149 | />
150 |
151 | {full_name}
152 | Member since 2015
153 |
154 |
155 | this.handleFirstLargeButton()}>
156 | Edit My Profile
157 |
158 |
159 |
160 |
161 |
162 |
163 |
172 |
173 |
174 |
175 | );
176 | }
177 | }
178 |
179 | export default ProfileScreen;
180 |
--------------------------------------------------------------------------------
/src/redux/api/posts.js:
--------------------------------------------------------------------------------
1 | // Add auth token to all authorization headers
2 | import {
3 | GET_ALL_POSTS_FROM_GROUP,
4 | GET_ALL_POSTS,
5 | CREATE_POST,
6 | UNLIKE_POST,
7 | LIKE_POST,
8 | DELETE_POST,
9 | GET_SINGLE_POST,
10 | EDIT_POST,
11 | CREATE_COMMENT_ON_POST,
12 | UNLIKE_COMMENT_ON_POST,
13 | LIKE_COMMENT_ON_POST,
14 | DELETE_COMMENT_ON_POST,
15 | EDIT_COMMENT_ON_POST,
16 | } from '../../constants/urls';
17 | import SInfo from 'react-native-sensitive-info';
18 |
19 | export const postGetAll = async page => {
20 | const orgId = await SInfo.getItem('defaultOrgId', {});
21 | const token = await SInfo.getItem('authToken', {});
22 | const response = await fetch(GET_ALL_POSTS(parseInt(orgId), page), {
23 | headers: {
24 | 'Content-Type': 'application/json',
25 | Authorization: token,
26 | },
27 | });
28 | // console.log(response);
29 | return response.json();
30 | };
31 |
32 | export const postGetSingle = async postId => {
33 | const token = await SInfo.getItem('authToken', {});
34 | const response = await fetch(GET_SINGLE_POST(postId), {
35 | headers: {
36 | 'Content-Type': 'application/json',
37 | Authorization: token,
38 | },
39 | });
40 | // console.log(response);
41 | return response.json();
42 | };
43 |
44 | export const postCreate = async formdata => {
45 | const orgId = await SInfo.getItem('defaultOrgId', {});
46 | const token = await SInfo.getItem('authToken', {});
47 | formdata.append('organization_id', parseInt(orgId));
48 |
49 | const response = await fetch(CREATE_POST, {
50 | method: 'POST',
51 | headers: {
52 | Authorization: token,
53 | },
54 | body: formdata,
55 | });
56 | // console.log(response);
57 | return response.json();
58 | };
59 |
60 | export const postEdit = async (postId, formdata) => {
61 | // console.log('EDIT POST', postId, formdata);
62 | const token = await SInfo.getItem('authToken', {});
63 | const response = await fetch(EDIT_POST(postId), {
64 | method: 'PUT',
65 | headers: {
66 | Authorization: token,
67 | },
68 | body: formdata,
69 | });
70 | // console.log(response);
71 | return response.json();
72 | };
73 |
74 | export const postLike = async postId => {
75 | const token = await SInfo.getItem('authToken', {});
76 | const response = await fetch(LIKE_POST(postId), {
77 | method: 'PUT',
78 | headers: {
79 | 'Content-Type': 'application/json',
80 | Authorization: token,
81 | },
82 | });
83 | return response.json();
84 | };
85 |
86 | export const postUnlike = async postId => {
87 | const token = await SInfo.getItem('authToken', {});
88 | const response = await fetch(UNLIKE_POST(postId), {
89 | method: 'PUT',
90 | headers: {
91 | 'Content-Type': 'application/json',
92 | Authorization: token,
93 | },
94 | });
95 | return response.json();
96 | };
97 |
98 | export const postDestroy = async postId => {
99 | const token = await SInfo.getItem('authToken', {});
100 | const response = await fetch(DELETE_POST(postId), {
101 | method: 'DELETE',
102 | headers: {
103 | 'Content-Type': 'application/json',
104 | Authorization: token,
105 | },
106 | });
107 | // console.log(response);
108 | return response.json();
109 | };
110 |
111 | // COMMENTS
112 |
113 | export const commentCreate = async (postId, content) => {
114 | const token = await SInfo.getItem('authToken', {});
115 | const response = await fetch(CREATE_COMMENT_ON_POST(postId), {
116 | method: 'POST',
117 | headers: {
118 | 'Content-Type': 'application/json',
119 | Authorization: token,
120 | },
121 | body: JSON.stringify({
122 | content,
123 | }),
124 | });
125 | return response.json();
126 | };
127 |
128 | export const commentEdit = async (postId, commentId, content) => {
129 | const token = await SInfo.getItem('authToken', {});
130 | const response = await fetch(EDIT_COMMENT_ON_POST(postId, commentId), {
131 | method: 'PUT',
132 | headers: {
133 | 'Content-Type': 'application/json',
134 | Authorization: token,
135 | },
136 | body: JSON.stringify({
137 | content,
138 | }),
139 | });
140 | return response.json();
141 | };
142 |
143 | export const commentLike = async (postId, commentId) => {
144 | const token = await SInfo.getItem('authToken', {});
145 | const response = await fetch(LIKE_COMMENT_ON_POST(postId, commentId), {
146 | method: 'PUT',
147 | headers: {
148 | 'Content-Type': 'application/json',
149 | Authorization: token,
150 | },
151 | });
152 | return response.json();
153 | };
154 |
155 | export const commentUnlike = async (postId, commentId) => {
156 | const token = await SInfo.getItem('authToken', {});
157 | const response = await fetch(UNLIKE_COMMENT_ON_POST(postId, commentId), {
158 | method: 'PUT',
159 | headers: {
160 | 'Content-Type': 'application/json',
161 | Authorization: token,
162 | },
163 | });
164 | return response.json();
165 | };
166 |
167 | export const commentDestroy = async (postId, commentId) => {
168 | const token = await SInfo.getItem('authToken', {});
169 | const response = await fetch(DELETE_COMMENT_ON_POST(postId, commentId), {
170 | method: 'DELETE',
171 | headers: {
172 | 'Content-Type': 'application/json',
173 | Authorization: token,
174 | },
175 | });
176 | return response.json();
177 | };
178 |
--------------------------------------------------------------------------------
/src/screens/ForgotPasswordScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import {
3 | KeyboardAvoidingView,
4 | SafeAreaView,
5 | Dimensions,
6 | Platform,
7 | } from 'react-native';
8 | import { connect } from 'react-redux';
9 | import styled from 'styled-components/native';
10 | import LargeButton from '../components/LargeButton';
11 | import colors from '../components/Global/colors';
12 | import Success from '../assets/images/Success.png';
13 | import { sendPassword } from '../redux/actions/users.actions';
14 | import { StyledInput } from './SignInScreen';
15 | import BackArrow from '../assets/images/BackArrow.png';
16 | import { StyledLeftButton, StyledIcon } from '../components/HeaderDetail';
17 |
18 | const DEVICE_WIDTH = Dimensions.get('window').width;
19 | const StyledError = styled.Text`
20 | color: ${colors.error};
21 | font-style: normal;
22 | font-weight: 600;
23 | line-height: 14px;
24 | font-size: 12px;
25 | letter-spacing: -0.0738462px;
26 | margin-top: 20;
27 | `;
28 |
29 | const Heading = styled.Text`
30 | font-weight: 600;
31 | line-height: 26px;
32 | font-size: 16px;
33 | letter-spacing: -0.0861539px;
34 | color: ${colors.white};
35 | margin-top: 75;
36 | margin-bottom: 60;
37 | `;
38 |
39 | const StyledSuccessImage = styled.Image`
40 | align-self: center;
41 | margin-top: 50;
42 | `;
43 |
44 | const StyledHeader = styled.View`
45 | width: ${DEVICE_WIDTH};
46 | height: 120;
47 | background-color: ${colors.darkerBase};
48 | justify-content: center;
49 | padding-left: 10;
50 | `;
51 |
52 | const StyledContainer = styled.View`
53 | background-color: ${colors.primary};
54 | align-self: stretch;
55 | height: 100%;
56 | padding-left: 10px;
57 | padding-right: 10px;
58 | align-items: center;
59 | `;
60 |
61 | const StyledHeaderTitle = styled.Text`
62 | font-weight: bold;
63 | font-size: 22px;
64 | letter-spacing: -0.0861539px;
65 | color: ${colors.white};
66 | margin-top: 23;
67 | `;
68 |
69 | class ForgotPasswordScreen extends Component {
70 | constructor() {
71 | super();
72 |
73 | this.state = {
74 | email: '',
75 | error: '',
76 | emailSent: false,
77 | };
78 | }
79 |
80 | componentDidUpdate(prevProps) {
81 | const { user } = this.props;
82 | if (prevProps.user.auth === 'pending' && user.auth === 'complete') {
83 | this.setState({ emailSent: true });
84 | } else if (
85 | user.auth === 'failed' &&
86 | user.error === 'not found' &&
87 | prevProps.user.error !== 'not found'
88 | ) {
89 | this.handleError('Email not found. Do you need to sign up?');
90 | }
91 | }
92 |
93 | handleLeftHeaderButton = () => {
94 | this.props.navigation.goBack();
95 | };
96 |
97 | handleError = error => {
98 | this.setState({ error });
99 | };
100 |
101 | handleSendPassword = () => {
102 | this.setState({ error: '' }, () => {
103 | if (!this.state.email) {
104 | this.setState({ error: 'Please enter an email' });
105 | }
106 | if (this.state.email) {
107 | this.props.sendPassword(this.state.email);
108 | }
109 | });
110 | };
111 |
112 | render() {
113 | return (
114 |
115 |
116 |
117 |
118 |
119 |
120 | Forgot Your Password?
121 |
122 |
123 | {this.state.emailSent && }
124 |
125 | {this.state.emailSent
126 | ? 'Email sent! Check your email and follow the password reset instructions.'
127 | : 'Enter your email below to receive your password reset instructions.'}
128 |
129 | {!this.state.emailSent && (
130 |
135 | this.setState({ email })}
140 | placeholderTextColor={colors.white}
141 | autoCapitalize="none"
142 | />
143 |
156 | {this.state.error !== '' && (
157 | {this.state.error}
158 | )}
159 |
160 | )}
161 |
162 |
163 | );
164 | }
165 | }
166 |
167 | const mapStateToProps = state => ({
168 | user: state.user,
169 | });
170 |
171 | export default connect(
172 | mapStateToProps,
173 | { sendPassword },
174 | )(ForgotPasswordScreen);
175 |
--------------------------------------------------------------------------------
/ios/ReactNativeTemplate.xcodeproj/xcshareddata/xcschemes/ReactNativeTemplate.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
52 |
53 |
58 |
59 |
61 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
79 |
80 |
81 |
82 |
92 |
94 |
100 |
101 |
102 |
103 |
104 |
105 |
111 |
113 |
119 |
120 |
121 |
122 |
124 |
125 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/ios/ReactNativeTemplate.xcodeproj/xcshareddata/xcschemes/ReactNativeTemplate-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
52 |
53 |
58 |
59 |
61 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
79 |
80 |
81 |
82 |
92 |
94 |
100 |
101 |
102 |
103 |
104 |
105 |
111 |
113 |
119 |
120 |
121 |
122 |
124 |
125 |
128 |
129 |
130 |
--------------------------------------------------------------------------------