Skip to content
jaysoncdev.com
Contact
All projects

Case study

PillTracker

Medication doesn't only mean your own. A prescription of your own running alongside a pet's course of treatment means two schedules, two supplies to reorder, and two histories worth keeping apart. PillTracker is a TypeScript React Native app that keeps each profile separate and works entirely offline, on iOS and Android from one codebase.

Role
Solo developer
Timeline
2025
Status
Shipped via Expo / EAS

The problem

One prescription is easy enough to hold in your head. Several at once is not — each with its own timing, its own supply running down at its own rate, and its own history worth keeping straight. And when a doctor or a vet asks what's actually been taken and when, memory isn't a good enough answer.

What I built

  • Separate profiles — your own, a pet's, anything else being tracked — each with its own medications, dosing schedule, and colour identity.
  • A calendar view of doses taken and missed, with a home screen showing what's due right now.
  • Local notifications scheduled per dose, so reminders work with no server and no account.
  • Refill tracking that warns before supply runs out, with a restock flow.
  • PDF adherence reports generated on-device and shared through the native share sheet, for handing to a doctor or a vet.
  • JSON backup and restore, so moving to a new phone doesn't lose a year of history.

Technical notes

Offline-first by default

There is no backend. Everything persists to AsyncStorage behind a typed storage layer, which means the app works on a plane, in a hospital basement, and without anyone handing their medical data to a server I'd have to secure.

Date handling is the whole app

Most of the real complexity lives in one dates module: recurring schedules, doses that span midnight, timezone shifts, and 'did they take the 8am one yet' questions. Isolating it into pure functions made it the only part of the app I could reason about confidently.

Shipping updates without the app stores

EAS Update pushes JavaScript changes over the air with a version bump script, so a fix reaches users in minutes instead of waiting on review.

By the numbers

4.7k
Lines of TypeScript
iOS + Android
Platforms
100% TS
Type coverage

Stack

App

React NativeExpoExpo RouterTypeScriptReact Navigation

Device

Expo NotificationsAsyncStorageExpo PrintExpo SharingHaptics

Delivery

EAS BuildEAS Update (OTA)

What I'd do differently

  • The date logic deserved unit tests before it deserved a UI. It's the one part of this app where a subtle bug has real consequences, and I tested it by hand for far too long.
  • Local-only storage was right for privacy and wrong for sharing — everything lives on one device, so there's no way to keep a second phone in step, or hand a profile to someone else, without a sync layer.