Skip to content

Repository files navigation

Flo — Modern Fintech Wallet

A production-architected React Native wallet app with biometric auth, gesture-driven payments, real-time spending analytics, and push notifications — built as a portfolio demonstration of senior-level mobile engineering patterns.

Tech Stack: React Native (Expo) · TypeScript · Redux Toolkit · React Navigation · Reanimated · Expo Camera · Expo Notifications


Overview

Flo is a CRED/PhonePe-style digital wallet covering the full core loop of a consumer fintech app — authentication, sending money, tracking spend, and staying informed — built with the same architectural discipline I apply to production work: normalized Redux state, memoized selectors, gesture-based interactions, and a clean separation between UI, business logic, and services.

Note: All data — balances, transactions, contacts — is mock data generated locally. No real payment gateway, bank, or UPI integration is connected. This is a portfolio and architecture demonstration, not a functioning financial product.


Screenshots


Features

  • Biometric Authentication — Face ID / fingerprint gate on app launch via expo-local-authentication, with graceful fallback on devices without biometric hardware
  • Animated Onboarding — Reanimated-driven swipeable slides with interpolated scale/opacity transitions synced to scroll position
  • Home Dashboard — Balance card with show/hide toggle, animated reveal, quick actions, 7-day spending sparkline, and pull-to-refresh
  • Send Money Flow — Contact search → custom numpad amount entry with real-time balance validation → gesture-based slide-to-confirm → success state, all backed by live Redux state updates
  • QR Code Scanner — Camera-based QR scanning with animated scan overlay, permission handling, and a mocked payment resolution flow
  • Transaction History — Search, type/category filtering, and automatic date-based grouping (Today / Yesterday / Earlier)
  • Spending Analytics — Category breakdown (hand-rolled SVG donut chart) and monthly spending trend (SVG bar chart), both derived live from transaction data — no hardcoded chart values
  • Push Notifications — Local notifications for payment confirmations and budget threshold alerts, with a full in-app notification center (unread badge, mark-as-read)
  • Profile & Settings — Biometric toggle wired to Redux, KYC status display, and a logout flow that resets navigation state cleanly

Architecture

State Management — Redux Toolkit, Normalized

Transactions, wallet balance, user, and notifications each live in their own slice. Transaction data is stored as an ID-keyed dictionary (byId + allIds) rather than a flat array — the same normalization pattern used in the AMPA Admin Portal — so a single record update never forces every list-consuming component to re-render.

store/
├── slices/
│   ├── walletSlice.ts         # balance, visibility toggle
│   ├── transactionSlice.ts    # normalized transaction store
│   ├── userSlice.ts           # auth state, biometric preference
│   └── notificationSlice.ts   # in-app notification history
└── selectors/
    └── index.ts                # Reselect memoized selectors

All derived data — recent transactions, category totals, monthly trends, unread counts — goes through memoized Reselect selectors, not inline .filter()/.map() in components.

Custom Hooks as the Logic Layer

Screens stay presentational. Business logic lives in hooks:

hooks/
├── useBalance.ts               # wallet balance + visibility
├── useTransactions.ts          # transaction list access
├── useTransactionFilter.ts     # search + type + category filtering
└── useBiometric.ts             # biometric auth flow wrapper

Nested Navigation, Deliberately

Each bottom tab that needs to push a detail screen on top of it gets its own stack navigator, rather than fighting React Navigation's cross-stack limitations:

RootStack
├── Splash → Onboarding → Biometric
└── Main (Bottom Tabs)
    ├── HomeStack        (Home → Notifications)
    ├── TransactionsStack (History → Detail)
    ├── Analytics
    └── Profile
    + SendMoneyFlow (sibling stack: Contacts → Amount → Confirm → QR Scan)

This keeps the bottom tab bar visible while browsing, and lets payment/detail flows take over the full screen without needing awkward workarounds.

Charts — Plain SVG, Deliberately

The analytics charts (donut + bar) are built with react-native-svg directly rather than a charting library. Victory Native's current major version renders through React Native Skia, which is a heavier dependency for what is, here, a small and fixed set of visualizations. Hand-rolled SVG keeps the bundle lean, avoids an extra native dependency, and gives full control over styling — the same trade-off reasoning I'd apply on a real production feature decision, not just a convenience shortcut.

Gesture-Driven Payment Confirmation

The Send Money confirmation screen uses react-native-gesture-handler + react-native-reanimated for a slide-to-confirm interaction (the same UX pattern used by PhonePe/GPay for payment authorization) rather than a plain button — including:

  • Gesture disabled during processing and after completion (prevents double-submission)
  • Hardware back button blocked mid-transaction via BackHandler
  • Threshold-based release detection (85% of track width) with spring-back on incomplete gestures

Project Structure

FloFresh/
├── App.tsx                     # Root providers + navigation container
├── app/                        # Screens, organized by flow
│   ├── auth/                   # Splash, Onboarding, Biometric
│   ├── main/                   # Tab screens + their nested stacks
│   └── shared/                 # Screens used across multiple flows
├── src/
│   ├── components/             # Reusable, presentation-only UI
│   ├── hooks/                  # Business logic layer
│   ├── store/                  # Redux slices + selectors
│   ├── services/                # notificationService, etc.
│   ├── theme/                  # Design tokens (colors, type, spacing)
│   ├── types/                  # Shared TypeScript interfaces
│   ├── constants/               # Mock data, category config
│   └── utils/                  # currency, date formatting/grouping

Getting Started

git clone https://github.com/rishabhdeotyagi/flo-wallet-app.git
cd flo-wallet-app
npm install --legacy-peer-deps
npx expo start --clear

Scan the QR code with Expo Go, or run on a physical device — camera-based QR scanning and biometric auth require a physical device; neither works in a simulator without additional configuration.


Known Trade-offs & What's Mocked

Being transparent about scope, since this is a portfolio project:

  • QR scanning is mocked — it detects any valid QR code and resolves to a random contact rather than parsing real UPI payload data (upi://pay?pa=...)
  • Biometric preference doesn't persist across app restarts — stored in Redux only, not MMKV; a real app would persist this
  • Budget check is simplified — a single hardcoded threshold check on payment completion rather than a full budgeting engine
  • No real payment gateway — Razorpay SDK was scoped out in favor of depth on the core UX patterns (gestures, state architecture, navigation) over breadth of integrations

What I'd Add for Production

  • Persist biometric/theme preferences via MMKV
  • Real UPI QR payload parsing and validation
  • Razorpay integration for actual wallet top-up
  • React Query for any real backend-synced data (currently everything is local mock state)
  • Detox E2E tests for the payment and auth flows specifically — the highest-stakes user journeys

License

MIT

About

React Native fintech wallet — biometric auth, gesture-based payments, real-time analytics, push notifications. Normalized Redux, custom hooks, nested navigation.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages