iPhone-flux.mp4
android-flux.mp4
The objective was to build the foundation of a React Native app that includes authentication (PIN and biometric), a home screen to list investment campaigns, navigation, and local state management for user interactions (follow/hide campaigns). The application was developed focusing on code quality and scalable architecture.
-
Project Setup:
- Built with Expo using
expo-dev-clientfor access to native layer. - Developed with TypeScript.
- Built with Expo using
-
Mock API Server:
json-serverconfigured to simulate a REST API with data provided indb.json.- Custom server implementation with the following endpoints:
/auth/login- Stubbed authentication endpoint/api/campaigns- Fetching campaigns with pagination and category filtering/api/campaigns/:id/follow- Follow a campaign/api/campaigns/:id/unfollow- Unfollow a campaign
- Start the server with:
node server.js
-
Splash Screen:
- Configured using
expo-splash-screen. - App icon and splash assets can be customized as needed.
- Configured using
-
Authentication Flow:
- First Access:
- Prompts the user to create a 4-6 digit PIN.
- Offers the option to enable biometric authentication (Face ID/Fingerprint) if available and configured on the device.
- Subsequent Access:
- Attempts biometric authentication automatically if enabled.
- Falls back to PIN entry if biometrics fail, are not enabled, or not configured.
- Secure Storage: Credentials (PIN and biometric preference) are securely stored using
expo-secure-store.
- First Access:
-
Navigation:
- Uses
react-navigation. - Main Navigation (AppNavigator): Controls the flow between authentication and the main app.
- Authentication Stack (AuthStackNavigator):
PinCreateScreen: For PIN creation and biometric activation.PinLoginScreen: For login with PIN or biometrics.
- Main App Navigation (MainTabNavigator):
- Invest (Home): Main tab, implemented as a stack (
InvestStackNavigator) containing:HomeScreen: Displays the list of campaigns.FollowedCampaignsScreen: Displays followed campaigns.HiddenCampaignsScreen: Displays hidden campaigns.
- Discussions: Placeholder tab.
- Notifications: Placeholder tab with a button to simulate push notification permission request.
- Invest (Home): Main tab, implemented as a stack (
- Uses
-
Home Screen (Invest Tab):
- Displays a list of campaigns with pagination (infinite scroll) and "pull to refresh".
- Campaign Card:
- Cover image, logo, name, description, percentage raised, days remaining, and valuation.
- Long-press on card: Opens a Bottom Sheet (
@gorhom/bottom-sheet) with more campaign information (equity, tax eligibility, city/country, investment goal). - Swipe right: Follows/Unfollows a campaign (with animation and visual feedback).
- Swipe left: Hides the campaign (with shrinking animation and removal from the main list).
- Local State Management (Zustand):
authStore: Manages authentication state, PIN, and biometric preference.campaignStore: Manages the IDs of followed and hidden campaigns, persisting this data withAsyncStorage.
- Additional Screens: Access via icons in the
HomeScreenheader to view lists of followed and hidden campaigns.
-
Tech Stack:
- React Native (Expo with dev-client)
- TypeScript
- React Navigation for navigation.
- React Query for data fetching and caching (campaign list).
- Zustand for global and local state management.
expo-secure-storefor secure storage.expo-local-authenticationfor biometrics.react-native-gesture-handlerandreact-native-reanimatedfor gestures and animations.@gorhom/bottom-sheetfor the campaign details modal.json-serverfor the API mock.expo-hapticsfor tactile feedback.- ESLint and Prettier for code quality and consistent formatting.
The directory structure follows a common pattern for React Native projects, aiming for modularity and organization:
/republic-challenge-app
/assets # (For icons, fonts, images)
/src
/api # json-server configuration and React Query hooks
/components # Reusable components (auth, campaigns, common)
/auth
/campaigns
/common
/config # Constants, application configurations
/hooks # Custom hooks
/navigation # Navigators (Stack, Tab) and route configurations
/screens # Screen components (auth, main)
/auth
/main
/services # Service logic (e.g.: biometricAuthService)
/store # Zustand stores (authStore, campaignStore)
/styles # Global styles, theme
/types # TypeScript type definitions (Campaign, etc.)
/utils # General utility functions
App.tsx # Main application entry point
babel.config.js
db.json # Data file for json-server
package.json
tsconfig.json
.eslintrc.js # ESLint configuration
.prettierrc # Prettier configuration
# ... other configuration files (eas.json, app.json)
Prerequisites:
- Node.js (LTS recommended)
- npm or Yarn
- Expo CLI (global or via npx):
npm install -g expo-cli(if opting for global) - A physical device or Android/iOS emulator/simulator.
- For
expo-dev-client, you'll need to build the development client app.
1. Clone the Repository (if applicable) or Extract the Files:
# git clone <repository-url>
# cd republic-challenge-app2. Install Dependencies:
npm install
# or
# yarn install3. Configure the Mock Server:
The db.json file is already in the project root and correctly formatted.
In a separate terminal, at the project root (/republic-challenge-app), run:
# Start the custom server with all required endpoints
node server.jsThis will start the server on port 3000 with the following endpoints:
/auth/login- Authentication (stubbed)/api/campaigns- Campaigns with pagination and category filtering/api/campaigns/:id/follow- Follow a campaign/api/campaigns/:id/unfollow- Unfollow a campaign
Important Network Configuration Notes:
- For iOS: The app will connect to the server using
localhost:3000 - For Android: The app will connect to the server using
10.0.2.2:3000(special IP that Android emulators use to access the host machine) - Network Security: The Android app includes a network security configuration to allow cleartext (HTTP) traffic for development purposes
If you encounter network issues:
- Make sure the JSON server is running with
--host 0.0.0.0to accept connections from all interfaces - For Android, if using a physical device or non-standard emulator, you may need to update the API base URL in
src/config/api.tswith your computer's actual IP address
4. Run the React Native Application:
-
Build the Dev Client (if you don't have one yet): To use native features like
expo-secure-storeandexpo-local-authenticationin a development environment other than Expo Go, you need a development client.# For Android npx expo run:android # For iOS npx expo run:ios
This will build and install the client app on your device/emulator. Follow the instructions in the terminal.
-
Start the Expo Development Server: After the dev client is installed on the device/emulator, start the development server:
npm start # or # yarn start # or # npx expo start --dev-client
This will open the Metro Bundler. You can then open the development client app on your device/emulator, and it should connect to the Metro server.
Note: If you encounter a port conflict (e.g., "Port 8081 is already in use"), you can:
- Accept the prompt to use an alternative port (e.g., 8082)
- Or kill the process using port 8081 before starting:
# On macOS/Linux lsof -i :8081 | grep LISTEN | awk '{print $2}' | xargs kill -9 # On Windows netstat -ano | findstr :8081 # Then use the PID to kill the process taskkill /F /PID <PID>
5. Linting and Formatting:
The project includes ESLint and Prettier for code quality and consistent formatting.
-
Run ESLint:
# Check for linting issues npm run lint # Fix auto-fixable linting issues npm run lint:fix
-
Run Prettier:
# Format all files npm run format # Check if files are correctly formatted npm run format:check
Expected Flow:
- When opening the app for the first time, you'll be directed to the
PinCreateScreen. - Create a PIN and opt in (or not) for biometrics.
- In subsequent accesses, the app will try biometrics (if enabled) or ask for the PIN in the
PinLoginScreen. - After authentication, you'll see the
HomeScreenwith the campaign list.
- Expo with Dev Client vs. Bare React Native: Chose Expo with
expo-dev-clientto facilitate initial configuration and access to libraries from the Expo ecosystem that handle native functionalities (expo-secure-store,expo-local-authentication), while also allowing the inclusion of any native code if necessary, as required for biometrics. json-server: Selected for the simplicity in quickly setting up a REST API mock. For more complex API functionalities (advanced filters, complex write logic), MirageJS or MSW would be more robust alternatives, butjson-serverserves the requirements for simple reading and pagination well.- Platform-Specific Network Configuration: The app uses different API base URLs depending on the platform:
- iOS uses
localhost:3000to connect to the JSON server - Android uses
10.0.2.2:3000(special IP that Android emulators use to access the host machine) - Android also includes a network security configuration to allow cleartext (HTTP) traffic for development
- iOS uses
- Zustand: Selected for its simplicity, minimal API, and good performance for state management. The persistence of
campaignStorewas done withAsyncStoragethrough Zustand'spersistmiddleware, which is suitable for non-sensitive data such as IDs of followed/hidden campaigns. - React Query: Used for campaign data fetching, offering caching, background updates, and simplifying loading/error state management.
- PIN Storage:
expo-secure-storewas used for the PIN, which is the recommendation for sensitive data in Expo. - Animations:
react-native-reanimatedwas used for swipe animations on cards, providing smoother animations executed on the UI thread. - Navigation to List Screens (Followed/Hidden): Chose to add icons in the
HomeScreenheader for access to these lists, instead of dedicated tabs, to keep theBottomTabNavigatormore streamlined with the three main requested tabs. - Haptic Feedback: Used
expo-hapticsto provide tactile feedback when the user interacts with elements like cards and the bottom sheet. - ESLint & Prettier: Used for code quality and consistent formatting across the project, with customized configurations to fit React Native and TypeScript best practices.
- Tests: Add unit and integration tests (Jest, React Native Testing Library).
- Complete Design System: Implement a more robust design system with theme (colors, typography, spacing) for greater visual consistency.
- Error Handling: Improve API error handling and visual feedback for the user.
- Performance Optimizations: For very large lists, investigate additional optimizations (e.g.,
react-native-largelistorrecyclerlistview), althoughFlatListwithuseMemoandReact.memo(if applicable to cards) is generally sufficient for many cases. - Real Assets: Integrate real brand splash screen and icons.
- Internationalization (i18n).
- Accessibility (a11y): Review and improvements to ensure greater accessibility.
- API endpoints:
- Authentication:
http://localhost:3000/auth/login(iOS) orhttp://10.0.2.2:3000/auth/login(Android) - Campaigns:
http://localhost:3000/api/campaigns(iOS) orhttp://10.0.2.2:3000/api/campaigns(Android) - Follow/Unfollow:
http://localhost:3000/api/campaigns/:id/followand/unfollow(iOS) or equivalent Android URLs
- Authentication:
- Pagination in the
HomeScreenis configured to load 5 items per page. - Troubleshooting Network Issues:
- If you encounter "Network request failed" errors:
- Make sure the server is running with
node server.js - For Android emulators, verify that
10.0.2.2:3000is used in the API configuration - For Android physical devices, update the API base URL in
src/config/api.tswith your computer's actual IP address - For iOS, ensure that
localhost:3000is used in the API configuration
- Make sure the server is running with
- If you encounter port conflicts with Metro bundler:
- Accept the prompt to use an alternative port (e.g., 8082)
- Or kill the process using port 8081 before starting the app
- If you encounter "Network request failed" errors: