Skip to content

Commit

Permalink
Add UI components + bug fixes + refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
GeorgianSorinMaxim committed Aug 25, 2022
1 parent 9e0a023 commit de0f6e6
Show file tree
Hide file tree
Showing 146 changed files with 47,114 additions and 45,343 deletions.
4 changes: 3 additions & 1 deletion .eslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@
"no-prototype-builtins": "off",
"arrow-body-style": "off",
"@typescript-eslint/ban-types": "off",
"react/jsx-closing-bracket-location": "off"
"react/jsx-closing-bracket-location": "off",
"function-paren-newline": "off",
"guard-for-in": "off"
}
}
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
bin/*
coverage/*
src/global.d.ts
5 changes: 2 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ DerivedData
*.xcuserstate
project.xcworkspace
ios/.xcode.env.local
ios/Pods

# Android/IntelliJ
#
Expand Down Expand Up @@ -50,8 +51,6 @@ buck-out/
*.vscode/

# Ruby / CocoaPods
/ios/Pods/
/vendor/bundle/

vendor/bundle/

.env
66 changes: 36 additions & 30 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -17,49 +17,51 @@

### Install the app

`$ yarn`
$ `yarn`

`$ react-native link`
$ `react-native link`

`$ cd ios && pod install`
$ `cd ios && pod install`

### Run the app in an iOS / Android simulator

`$ yarn start`
$ `yarn start`

`$ yarn ios`
$ `yarn ios`

`$ yarn android`
$ `yarn android`

### Run TypeScript checks

`$ yarn tsc`
$ `yarn tsc`

### Run the tests

`$ yarn test`
$ `yarn test`

### Run the linter

`$ yarn lint`
$ `yarn lint`

### Run Prettier

`$ yarn prettier --write`
$ `yarn prettier --write`

### Architecture

- The application state is stored using Redux.
- Login / registration using the Firebase Web SDK.
- redux-saga is used as the Redux middleware for managing the side effects (e.g. data fetching).
- The Redux store is persisted with redux-persist (not necessary the current funcionality of the app, but useful as the application would grow).
- The navigation is done using react-navigation. This library has been added since as the app would grow, there would be a need for navigation fairly quickly.
- Unit tests are written with Jest.
- Reselect (https://github.com/reduxjs/reselect) is used because in a production app because we could compute derived data, allowing Redux to store the minimal possible state.
- Eslint (for TypeScript) is used in the project for checking the JS/TS errors.
- TypeScript is used in the project.
- react-native-vector-icons has been used to improve the UI apprerance using icons in the navigator and in other UI elements.
- Icons: https://infinitered.github.io/ionicons-version-3-search/
- `redux-saga` is used as the Redux middleware for managing the side effects (e.g. data fetching, login flow, etc).
- The Redux store is persisted with `redux-persist`. This capability is not necessary for the current functionality of the app, but useful as the application would grow.
- The login / registration flow is implemented with `react-native-firebase`.
- The navigation is done using `react-navigation`. This library has been added since as the app would grow, there would be a need for navigation fairly quickly.
- TypeScript is used in the project with strict rules and no usage for `@ts-ignore`.
- ESLint (for TypeScript) is used in the project for checking the JS/TS errors.
- `react-native-vector-icons` is used for improving the UI look-and-feel using icons in the navigator and in other UI elements.
- Icons used: https://infinitered.github.io/ionicons-version-3-search/
- Environment variables are managed with `react-native-config`.
- The device info is managed with `react-native-device-info` and `react-native-uuid`.
- Images are cached in the app with `react-native-fast-image`.
- Reselect (https://github.com/reduxjs/reselect) should used because in a production app because we could compute derived data, allowing Redux to store the minimal possible state.

### Components

Expand All @@ -74,39 +76,43 @@
- Divider for elements
- Multi-purpose modal
- Screen container
- WebView container with `react-native-webview` and `uri-js`

### Changelog

- DONE in July 2022

- Upgraded `react`, `react-native` & other dependencies
- Enabled Hermes
- Refactored `/screens` and `/components` to use hooks and functional components
- Added `react-native-firebase`
- Made the TS rules strict (e.g. turn on rules like `noImplicitAny`, no `@ts-ignroe` or `: any` types) and fixed all TS issues
- Added auto-login with token verification with `jwt-decode`
- Refactored `/screens` and `/components` to use hooks and functional components
- Improved and extended the types and transformed `networkingApi.js` into `.ts`
- Added progress indicators and spinners with `react-native-progress`
- Added `react-native-config`
- Added logging with Crashlytics

### WIP features and improvements

- Add logging and tracking service: Bugsnag, Analytics (GA) and Crashlytics with `react-native-firebase`, `react-native-device-info` and `react-native-uuid`
- Create a design system with small component for Text, Heading, Subheading, Divider, Loader, etc
- Test logging service
- Login / Register screen: Add image on background like on Harrods's app and validation
- UI improvements with `react-native-keyboard-aware-scroll-view`
- Add feature flagging + A/B testing capabilities with Firebase Remote Config + Firebase Realtime Database using with `react-native-firebase`
- Build a CI with AppCenter CI to build and sign the app
- Add CodePush for over-the-air updates
- Create a design system with small components for Text, Heading, Subheading, Divider, Loader, etc
- Use `TextAreaWithLabel` + `PhoneNumberPrefix` + `OptionSwitch` + `HyperLink` + `GenericModal` + `Dropdown`
- Add a WebView container with `react-native-webview` and `uri-js`
- Run the app in different environments: dev, prod, uat with `react-native-config`
- Add feature flagging + A/B testing capabilities with Firebase Remote Config + Firebase Realtime Database using with `react-native-firebase`
- Render SVGs with `react-native-svg` and `react-native-svg-transformer`
- Animate UI elements with `react-native-reanimated`
- Ask your users to rate the app with `react-native-rate`
- Add push notifications with Firebase / Azure / Iterable
- Replace `Jest` with `react-native-testing-library` and write tests (e.g. for /components, networkingApi.js and for the navigator)
- Build a CI with AppCenter CI to build and sign the app
- Add CodePush for over-the-air updates
- Add `pre-commit` hooks
- Auto-login with token verification with `jwt-decode`
- Add tracking service with Analytics (GA) and `react-native-firebase`

- Use biometric authentication and store user credentials in the KeyChain and KeyStore with `react-native-secure-key-store`
- Animate UI elements with `react-native-reanimated`
- Ask your users to rate the app with `react-native-rate`
- Allow to natively share urls with `react-native-share`
- Create gradients with `react-native-linear-gradient`
- Take pictures with `react-native-camera`
Expand Down
7 changes: 7 additions & 0 deletions __mocks__/@react-native-firebase/analytics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const analytics = jest.fn().mockReturnValue({
logEvent: jest.fn(),
logScreenView: jest.fn(),
getAppInstanceId: jest.fn(),
});

export default analytics;
8 changes: 8 additions & 0 deletions __mocks__/@react-native-firebase/crashlytics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const analytics = () => ({
log: jest.fn(),
recordError: jest.fn(),
setUserId: jest.fn(),
setAttributes: jest.fn(),
});

export default analytics;
4 changes: 2 additions & 2 deletions android/app/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ android_library(

android_build_config(
name = "build_config",
package = "com.hurt",
package = "com.apply",
)

android_resource(
name = "res",
package = "com.hurt",
package = "com.apply",
res = "src/main/res",
)

Expand Down
14 changes: 11 additions & 3 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ android {
compileSdkVersion rootProject.ext.compileSdkVersion

defaultConfig {
applicationId "com.rndiffapp"
applicationId "com.apply"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
Expand All @@ -164,7 +164,7 @@ android {
cppFlags "-std=c++17"
// Make sure this target name is the same you specify inside the
// src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
targets "rndiffapp_appmodules"
targets "apply_appmodules"
}
}
if (!enableSeparateBuildPerCPUArchitecture) {
Expand Down Expand Up @@ -270,6 +270,11 @@ dependencies {

implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"

implementation platform('com.google.firebase:firebase-bom:30.3.2')

implementation 'com.google.firebase:firebase-crashlytics'
implementation 'com.google.firebase:firebase-analytics'

debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
Expand Down Expand Up @@ -325,4 +330,7 @@ def isNewArchitectureEnabled() {
// - Invoke gradle with `-newArchEnabled=true`
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
}
}

apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
46 changes: 46 additions & 0 deletions android/app/google-services.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"project_info": {
"project_number": "1035690501200",
"project_id": "apply-rn",
"storage_bucket": "apply-rn.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:1035690501200:android:37610028d2251cb6dd9d55",
"android_client_info": {
"package_name": "com.apply"
}
},
"oauth_client": [
{
"client_id": "1035690501200-q2n5b4ri0pn3q26jt8qen7vl4u2h9j5m.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCySNkIkHbwR2-5vR3JSLVam9yiK3-WFE0"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "1035690501200-q2n5b4ri0pn3q26jt8qen7vl4u2h9j5m.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "1035690501200-dbc7vu6aljpsfuvplkji67qn25du6npt.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "com.apply"
}
}
]
}
}
}
],
"configuration_version": "1"
}
96 changes: 37 additions & 59 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,59 +1,37 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.hurt">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

<!-- OPTIONAL PERMISSIONS, REMOVE WHATEVER YOU DO NOT NEED -->
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

<!-- These require runtime permissions on M -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!-- END OPTIONAL PERMISSIONS -->

<application
android:usesCleartextTraffic="true"
android:name=".MainApplication"
tools:targetApi="31"
tools:ignore="GoogleAppIndexingWarning"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher"
android:allowBackup="false"
android:theme="@style/AppTheme">
<activity
android:name="com.facebook.react.devsupport.DevSettingsActivity"
android:exported="true"
/>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.apply">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/>
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<application android:usesCleartextTraffic="true" android:name=".MainApplication" tools:targetApi="31" tools:ignore="GoogleAppIndexingWarning" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher" android:allowBackup="false" android:theme="@style/AppTheme">
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="true"/>
<activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="bankapp"/>
<data android:scheme="https" android:host="www.devxldn.com" />
<data android:scheme="http" android:host="www.devxldn.com" />
</intent-filter>
</activity>
</application>
</manifest>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

1 comment on commit de0f6e6

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ts-ignore's: 0 (unchanged)

Please sign in to comment.