A cross-platform (iOS & Android) mobile app for managing loan applications, built with React Native (Expo), TypeScript, and Firebase/Firestore. The app supports authentication, loan application, loan status tracking, offline-first features, push notifications, and a modern, accessible UI.
-
Authentication: Email/password, Google sign-in, email verification, and biometric login (Face ID/Touch ID). Forgot/Reset Password (firebase)
-
Logging/Analytics: A simple logging utility is used to track offline login and password reset attempts. In production, this can be replaced with a full analytics solution (e.g., Firebase Analytics, Sentry).
-
Loan Management: View, apply for, and track the status of loans (pending, approved, rejected, flagged for review).
-
Offline Support: Create loans offline, cache them locally, and sync to Firestore when back online. Displays both cached and mock/sample loans when offline. Offline Mock login.
-
Push Notifications: Integrated with Expo Notifications for real-time updates.
-
UI/UX: Modern, responsive, accessible design with dark mode, color-coded status badges, and clear feedback (snackbar/toast).
-
Automated Tests: Example tests for validation and offline features.
myloanapp/
├── app/ # Not found expo router component
├── src/
│ ├── components/ # Reusable UI components (no components for now)
│ ├── screens/ # App screens (Login, Signup, Home, ApplyLoan, etc.)
│ ├── navigation/ # Navigation setup
│ ├── services/ # Firebase, notifications, offline, and mock data logic
│ ├── hooks/ # Custom React hooks (ThemeContext)
│ ├── contexts/ # React context providers (no contexts for now)
│ ├── utils/ # Utility functions (no utility functions for now)
│ ├── theme/ # App theming (light/dark)
│ ├── tests/ # Automated tests
│ └── ...
├── App.tsx # App entry point
├── app.config.ts # Expo config with env variables
├── .env # Environment variables (Firebase config)
└── ...
-
src/services/firebase.ts: Firebase/Firestore initialization and export.
-
src/services/offlineLoans.ts: Handles caching of offline loan applications and syncing them to Firestore when online.
-
src/services/mockLoans.ts: Provides mock/sample loan data for offline demo mode.
-
src/screens/HomeScreen.tsx: Displays the user's loans. When offline, shows both cached offline loans and mock loans. Syncs cached loans when back online.
-
src/screens/ApplyLoanScreen.tsx: Lets users apply for a new loan. If offline, uses
addLoanOfflineto cache the loan locally. -
src/screens/LoginScreen.tsx, SignupScreen.tsx: Authentication flows, including validation, Google sign-in, and biometrics.
-
src/services/notifications.ts: Push notification registration and listeners.
-
src/theme/AppTheme.ts: Light/dark theme and color palette.
-
Are loans created offline cached and synced to Firestore when back online?
Yes. When a loan is created offline (via ApplyLoanScreen.tsx), it is cached locally usingaddLoanOffline. In HomeScreen.tsx, when the app detects it is back online, it callssyncLoansWithFirestoreto upload any cached (unsynced) loans to Firestore. -
Does the app fetch and display a list of loans from a mock/local JSON file when offline?
Yes. When offline, HomeScreen.tsx sets the loan list to the mock data from mockLoans.ts, so users see a sample list even without network connectivity. It also displays cached user-created offline loans. -
Does app uses native feature?
several native features of mobile devices through Expo and React Native libraries. Here are the main native features integrated:
1. Biometric Authentication:
- Uses Expo’s expo-local-authentication to access Face ID and Touch ID (native device biometrics).
2. Push Notifications:
- Uses Expo’s expo-notifications to register for and receive native push notifications.
3. Secure Storage:
- Uses @react-native-async-storage/async-storage for local data caching (native storage API). - (You can also use expo-secure-store for even more secure token storage if needed.)
4. Network Status Detection:
- Uses @react-native-community/netinfo to detect online/offline status (native network info).
5. Google Sign-In:
- Uses @react-native-google-signin/google-signin for native Google authentication.
All these features are accessed via cross-platform APIs, so the loan app works natively on both iOS and Android without writing separate native code.
✅ Login screen with email/password fields, login button, and validation.
✅ Registration (sign up) with email/password, Google sign-in, and email verification.
✅ Secure token storage via Firebase Auth (Firebase SDK handles token management securely).
✅ Navigation to the home screen after login.
✅ When online fetches loans from Firestore (per user). When offline fetches and displays both cached user-created offline loans and mock loans in the loan list.
- This ensures users see their own offline loan applications as well as example data for a complete experience
✅ Displays loan amount, status (pending, approved, rejected, flagged), and date applied.
✅ Color-coded status badges for clear visibility. Also visually distinguishes loan list by:
- Cached user-created offline loans with a bold orange (Offline) label.
- Mock/sample loans with a gray italic (Sample) label.
✅ Tapping a loan navigates to a details screen with full info.
✅ “Apply for Loan” screen with input fields for amount and purpose.
- when offline: Loans created offline are cached and synced to Firestore when back online.
✅ Input validation and error/success messages.
✅ Submits to Firestore (simulates POST).
✅ Snackbar/toast feedback is shown after loan submission (success, error, or offline save).
✅ Clean, modern, and responsive layout using React Native Paper.
✅ Color-coded badges/icons for loan status.
✅ Smooth navigation with React Navigation.
✅ Pull-to-refresh on the loan list.
✅ Dark mode support via theming.
✅ TypeScript used throughout.
✅ Modular, scalable, and maintainable code structure.
✅ Firebase/Firestore integration for authentication and data.
✅ Biometric login (Face ID/Touch ID).
✅ Push notification integration.
✅ Offline support (basic, with NetInfo).
✅ Automated tests (example for login validation).
-
Node.js (LTS recommended)
-
Expo CLI (
npm install -g expo-cli) -
A Firebase project (see below)
-
Clone this repository
git clone https://github.com/certsoftt/loan-app.git-
Rename
eas.jsontoeas.js -
Create
.env.localfile
- Go to Firebase Console and create a new project.
- Register a web app and Update your
.env.localwith the config values appropriately - Create a new project and register for android, enable firestore database and authentication for email/password and google, then download the
google-services.json. Update your.env.localwith the config values appropriately. - Create a new project and register for ios, enable firestore database and authentication for email/password and google, then download the
googleservice-info.plist. Update your.env.localwith the config values appropriately. - Enable Authentication (Email/Password, Google) and Firestore Database for web platform.
Note: For enabling google authentication with android platform you have to provide SHA fingerprint. Do the following:
-
Install the JDK:
- Download and install the latest JDK from: https://adoptopenjdk.net/ or https://www.oracle.com/java/technologies/downloads/
-
Add keytool to your PATH:
- Find where Java is installed (e.g., C:\Program Files\Java\jdk-XX.X.X\bin). - Add that bin directory to your system’s PATH environment variable.
To add to PATH on Windows: - Open Start Menu, search for “Environment Variables”, and open “Edit the system environment variables”. - Click “Environment Variables…” - Under “System variables”, find and select “Path”, then click “Edit”. - Click “New” and add the path to your JDK’s bin folder (e.g., C:\Program Files\Java\jdk-XX.X.X\bin). - Click OK to save.
- Open a new terminal and run:
keytool -versionIf you see the version, keytool is now available.
- Run the command on terminal:
keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass androidYou should see output with lines like:
SHA1: 12:34:56:78:9A:BC:DE:F0:12:34:56:78:9A:BC:DE:F0:12:34:56:78
SHA256: 12:34:56:78:9A:BC:DE:F0:12:34:56:78:9A:BC:DE:F0:12:34:56:78:12:34:56:78:9A:BC:DE:F0:12:34:56:78- Copy the SHA1 value and use it in the Firebase Console for Google Sign-In.
This project is configured to support Google authentication on both Android and iOS using Firebase. Here’s how it works and how to maintain it:
- Android: Place your
google-services.jsonfile (downloaded from the Firebase Console) in the project root. - iOS: Place your
GoogleService-Info.plistfile (downloaded from the Firebase Console) in the project root.
- In
app.config.ts, the following fields are set:ios: { googleServicesFile: "./GoogleService-Info.plist", // ...other iOS config }, android: { googleServicesFile: "./google-services.json", // ...other Android config },
- This ensures EAS Build includes the correct files for each platform.
- The
.env.localfile contains platform-specific Firebase credentials:FIREBASE_API_KEY_ANDROID,FIREBASE_APP_ID_ANDROID, etc. for AndroidFIREBASE_API_KEY_IOS,FIREBASE_APP_ID_IOS, etc. for iOSFIREBASE_API_KEY,FIREBASE_APP_ID, etc. for web/other
- In
src/services/firebase.ts, the app dynamically selects the correct credentials based on the platform:import { Platform } from 'react-native'; import Constants from 'expo-constants'; // ... const firebaseConfig = { apiKey: Platform.OS === 'android' ? Constants.expoConfig?.extra?.FIREBASE_API_KEY_ANDROID : Platform.OS === 'ios' ? Constants.expoConfig?.extra?.FIREBASE_API_KEY_IOS : Constants.expoConfig?.extra?.FIREBASE_API_KEY, // ...other fields };
- In the Firebase Console, register both your Android and iOS apps and download the respective config files.
- For Android, add your SHA1 fingerprint for Google Sign-In support.
- For iOS, use the correct bundle identifier. e.g
com.makemorer.myloanapp - Set up OAuth client IDs for both platforms as instructed by Firebase by doing the following:
- iOS: Set Up OAuth Client ID
- Go to the Firebase Console, select your project.
- In the left menu, click the gear icon > Project settings.
- Under Your apps, select your iOS app.
- Make sure your app’s bundle identifier matches your Expo config.
- Scroll to Your apps > iOS app > App nickname and App Store ID (optional, but recommended).
- Download the updated GoogleService-Info.plist and place it in your project as required.
- Android: Set Up OAuth Client ID
- In the Firebase Console, under Project settings, select your Android app.
- Make sure your app’s package name matches your Expo config.
- Under SHA certificate fingerprints, add your app’s SHA-1 and SHA-256 fingerprints (see how to get these in README note-for-enabling-google-authentication-with-android-platform-you-have-to-provide-sha-fingerprint-do-the-following).
- Under OAuth 2.0 client IDs, you should see an entry for your Android app. If not:
- Click Add fingerprint or Add OAuth client.
- Enter your app’s package name and SHA-1.
- Download the updated google-services.json and place it in your project as required.
- Google Cloud Console: Verify OAuth Consent Screen
- Go to the Google Cloud Console.
- Make sure you’re in the same project as your Firebase app. You can find all your projects in
All TabAll Tabs image - Under OAuth 2.0 Client IDs, you should see entries for both iOS and Android.
- If needed, configure the OAuth consent screen (add app name, support email, and authorized domains).
- Expo/React Native Configuration Ensure your app.config.ts contains the correct bundle identifier (iOS) and package name (Android). For Google sign-in, use the correct client IDs in your app’s code (see how to do this in README google-authentication-setup-android--ios).
-
Go to the Google Cloud Console for your Firebase web platform project.
-
Find the OAuth 2.0 Client IDs section.
-
Look for a client with the type "Web client". - If you don’t see one, you may need to create it: - Click Create Credentials > OAuth client ID. - Choose Web application. - Name it (e.g., "Expo Go Client"). - Under Authorized redirect URIs, add: - https://auth.expo.io/@your-username/your-app-slug - Replace
your-usernameandyour-app-slugwith your Expo account and project slug. -
After creating, copy the Client ID (it ends with
.apps.googleusercontent.com). -
Paste this value into your .env.local as
EXPO_PUBLIC_GOOGLE_EXPO_CLIENT_ID.
- Ensure the config files are present in the project root and referenced correctly in
app.config.ts. - Make sure your
.env.localvalues match the credentials in the config files. - If you change your Firebase project or credentials, update both the config files and environment variables.
-
Register on Expo Dev
-
Install EAS CLI(if not already):
npm install -g eas-cli- Log in to Expo using your expo.dev account details
In your project directory, run:
eas login- Initialize EAS in Your Project
In your project directory, run:
eas init- Give your project a name. Then visit the project using the provided url. You can find them at
https://expo.dev/accounts/[account]/projects/[project]. Copy yourslug,project_id, andownerand use them as values toPROJECT_SLUG,EAS_PROJECT_ID, andOWNER. - This process will create an
eas.jsonfile and register your project with Expo. - During this process, Expo will generate a new EAS project ID and link it to your project.
-
Copy the content of
eas.jsand replace it with the content of your generatedeas.jsonfile.- Update your
envproperty object in theeas.jsonto your own project setting.
"env": { EXPO_PUBLIC_FIREBASE_API_KEY= EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN= EXPO_PUBLIC_FIREBASE_PROJECT_ID= EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET= EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID= EXPO_PUBLIC_FIREBASE_APP_ID= APP_ENV=development EXPO_PUBLIC_API_URL=https://development.api EAS_PROJECT_ID= PROJECT_SLUG= OWNER= # your expo dev project name is your APP_NAME value. APP_NAME= # use com.[account username].[project name] e.g: com.makemorer.myloanapp. BUNDLE_IDENTIFIER= # use com.[account username].[project name] e.g: com.makemorer.myloanapp. PACKAGE_NAME= #create a new firebase project and register platform as android, then fill up the following below: EXPO_PUBLIC_FIREBASE_APP_ID_ANDROID= EXPO_PUBLIC_FIREBASE_PROJECT_NUMBER= EXPO_PUBLIC_FIREBASE_PROJECT_ID_ANDROID= EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET_ANDROID= EXPO_PUBLIC_FIREBASE_API_KEY_ANDROID= EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN_ANDROID= #create a new firebase project and register platform as ios, then fill up the following below: EXPO_PUBLIC_FIREBASE_API_KEY_IOS= EXPO_PUBLIC_FIREBASE_APP_ID_IOS= EXPO_PUBLIC_FIREBASE_GCM_SENDER_ID= EXPO_PUBLIC_FIREBASE_PROJECT_ID_IOS= EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET_IOS= EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN_IOS= #using the README get the below following config EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID= EXPO_PUBLIC_GOOGLE_ANDROID_CLIENT_ID= EXPO_PUBLIC_GOOGLE_EXPO_CLIENT_ID= },
- Update your
-
Setup your Environment variables for
production,preview, anddevelopemntenvironments on Expo Dev Using your.env.local.exampleto create theName(s) of the variables. You can find the environment variables page athttps://expo.dev/accounts/[account]/projects/[project]/environment-variables.
yarn install
or
npm installeas build --profile development --platform android
or
eas build --profile development --platform iosScan the QR code To run the app on real device.
npx expo startScan the QR code with the real device where the app had been installed in order to launch the app.
To test on android emulator or device you use: http://yourcomputeripaddress:metro-provided-port-number
To find your computer’s IP address on Windows:
- Press
Win + R, typecmd, and press Enter to open the Command Prompt. - Type the following command and press Enter:
ipconfig- Look for the line labeled IPv4 Address under your active network adapter. That is your computer’s local IP address.
eas submit --platform android
eas submit --platform iosnpm testFor questions or contributions, open an issue or pull request!