# Finote

> A React Native app for tracking spending across multiple wallets

A React Native finance app with multiple wallets, weekly, monthly and yearly spending charts, and receipt photos stored on Cloudinary.

- Type: Mobile App
- Role: Mobile Developer
- Tech: react-native, expo, typescript, firebase, zod, cloudinary, reanimated, gifted-charts
- Published: 2025-10-01
- Updated: 2026-10-04
- Live: https://github.com/AayushBharti/finote-app/releases/
- Repo: https://github.com/aayushbharti/finote-app
- URL: https://aayushbharti.in/projects/finote

**TL;DR:** Finote is a personal finance app built with React Native, Expo and TypeScript, using Firebase Firestore and Auth for data and login and Cloudinary for receipt images. Each wallet stores its own balance, income and expense totals, so the hard part is keeping those totals correct when a transaction is edited or moved to another wallet.

## Highlights

- Create and manage multiple wallets for organizing your finances
- View spending trends in weekly, monthly and yearly charts
- Attach receipt photos (stored on Cloudinary) with data synced live from Firestore
- List and screen entry animations built with Reanimated
- Login, sign-up and password reset with Firebase Auth

---
## What it is

Finote is a personal finance app built with React Native and Expo, released as an Android APK. You create wallets like Salary, Freelance or Cash, log income and expenses against them with a category, notes and an optional receipt photo, and see spending trends in weekly, monthly and yearly charts.

Finote was also how I learned React Native. I wanted to understand the mobile-specific constraints the web never made me think about: gesture handling, 60fps animations on lower-end devices, and keeping data consistent across several documents.

---

![Three Finote screens: home with a $683 total balance and recent transactions, a monthly statistics bar chart, and a list of three wallets](https://raw.githubusercontent.com/AayushBharti/finote-app/main/.github/images/img1.jpeg)

---

## Editing a transaction means undoing it first

Each wallet document in Firestore stores its own `amount`, `totalIncome` and `totalExpenses`, so reading a balance is one document read, with no summing over transactions. The catch: every write has to keep those three numbers correct.

A new transaction is the easy case: Finote checks the wallet, rejects an expense that would take the balance below zero, then adds the amount to `totalIncome` or `totalExpenses`. Editing is harder, because the old transaction already moved money. If the type, amount or wallet changed, `revertAndUpdateWallets` first reverses the old transaction on its original wallet, then applies the new values to the target wallet. It re-reads the target wallet in between, because when you edit within one wallet, that wallet was just updated. Turning an income into an expense on the same wallet, for example, has to undo the income before checking whether the balance can cover the expense.

Receipt photos go to Cloudinary as multipart `FormData` that points at the photo's file URI. My first version sent base64 strings, which bloated the payloads and blocked the JS thread while encoding.

---

![Three Finote screens: transaction search, the More menu with features and utilities, and a USD exchange-rate converter](https://raw.githubusercontent.com/AayushBharti/finote-app/main/.github/images/img2.jpeg)

---

## What I'd change

These updates are separate network calls: the wallet writes, then the Cloudinary upload, then the transaction document. If the receipt upload fails, the wallet balance has already changed but no transaction is saved. I'd upload the receipt first and wrap the wallet and transaction writes in a single Firestore transaction (`runTransaction`), so they succeed or fail together.

---

## Frequently asked questions

### What is Finote?

Finote is a personal finance mobile app built with React Native and Expo. It lets you create multiple wallets such as Salary, Freelance or Cash, log transactions with a category, amount, notes and optional receipt photo, and view spending trends in weekly, monthly and yearly charts.

### What tech stack does Finote use?

Finote is built with React Native, Expo and TypeScript, using Firebase Firestore for data, Firebase Auth for login, Cloudinary for receipt images, Zod for sign-up validation, Reanimated for animations and react-native-gifted-charts for spending charts.

### How does Finote keep wallet balances correct when a transaction is edited?

When a Finote transaction's type, amount or wallet changes, Finote first reverses the old transaction's effect on its original wallet, then applies the new values to the target wallet. An expense that would push a wallet's balance below zero is rejected.

### How does Finote upload receipt photos?

Finote uploads receipts to Cloudinary as multipart FormData that points at the photo's file URI, and Cloudinary optimizes them and serves them from a CDN. An earlier version sent base64 strings, which bloated payloads and blocked the main thread during encoding.

### How does Finote build its spending charts?

Finote's statistics screen has Weekly, Monthly and Yearly tabs. Each one queries the user's transactions from Firestore for that range (the last 7 days, the last 12 months, or every year since the first transaction), sums income and expenses per bucket, and draws them as paired bars with react-native-gifted-charts.
