An offline group expense splitter, migrated to Expo SDK 58, React 19, React Native 0.88, TypeScript, and Expo Router. No backend or sign-in is required.
Use Node.js 24 LTS or newer supported LTS. Install dependencies with npm ci, then:
npm startThe project includes expo-dev-client. For a local iPhone development build, install and configure Xcode, connect the phone, enable Developer Mode, and configure Apple signing, then run:
npx expo run:ios --deviceAfter that first build, use npm start for JavaScript/TypeScript changes. Rebuild after changing native dependencies or native app configuration. Alternatively, use an Expo development build produced by EAS; no cloud build or store submission has been performed as part of this migration.
For a browser preview:
npm run webExpo Go can only open the project if the installed Expo Go supports SDK 58 and all required native modules. Use npx expo start --go in that case. A development build is the supported path when the App Store version of Expo Go has not caught up to this SDK.
- Create groups and save equal or custom expense splits.
- Add members to existing groups; remove and restore members.
- Tap a saved expense to edit its description, payer, amount, participants, or split method.
- View spending, individual paid/share/net balances, and suggested settlement transfers.
- Share a PNG report containing the settlements and all expense splits on iOS/Android. Browser previews copy the same details as text.
- Light/dark appearance, keyboard-aware forms, accessible labels, and native stack navigation.
Removing a member archives their membership. It never deletes their expenses or changes past splits or debts. Removed members are excluded from new expenses. They remain available in their original role when editing an expense they already participated in, and can be restored later. A group needs two members when created and must retain at least one active member.
Adding a member affects future expenses only. Editing starts from the saved participant subset, not the current group roster. Each expense has a stable ID, so editing updates the original entry rather than creating a duplicate. Changes are shown only after the storage write succeeds.
Amounts use integer cents. Equal splits distribute remainder cents in participant order so they add up exactly. Custom totals are the sum of the entered shares. Use the same currency throughout a group; the app does not perform currency conversion. Settlement transfers are suggestions, not records of money sent.
On first load, the app looks for the old AsyncStorage keys outingData and outing-<id> in its own storage sandbox. It validates all old groups, assigns stable IDs, reconciles fractional cents, and writes one versioned snapshot to splitsquad:data:v2. Original keys are retained. Invalid data or a failed write displays an error and does not overwrite the old data. Future loads use the new snapshot, so deleted groups are not resurrected from the retained legacy keys.
A new Expo Go project or a separately installed application cannot read another app's private storage automatically. This migration moves the code; copying source folders does not transfer phone data. An Android in-place upgrade requires the original application ID (com.dashroshan.splitsquad) and signing key. The old source did not declare an iOS bundle ID; verify your existing app identity and provisioning before any release if an iOS app was previously distributed. Back up old data before replacing an installation.
The original source directory has not been modified. The new project reuses the original branding and privacy policy.
src/app/: typed routes for groups, members, and new/edit expense screens.src/components/: shared UI, expense editor, platform-specific report capture.src/domain/: money, balances, settlements, validation, and legacy conversion.src/store/: serialized persistence repository and React context.tests/: money, membership, edit, migration, concurrency, and storage failure tests.
npm run typecheck
npm run lint
npm test
npx expo-doctor
npx expo export --platform allThe unit tests use Node's built-in runner and TypeScript stripping. Expo generates typed routes in .expo/types when the development server starts. If typecheck is run immediately after a fresh clone before route generation, Expo Router falls back to its generic route types until the server is started.
Before shipping, test a development build on a physical iPhone: keyboard layout, long image reports, share-sheet cancellation, background/relaunch persistence, and the migration against a backup from an actual old installation. Web previews do not exercise native image capture, signing, or device storage migration.