Project: StudyHub — Peer-to-Peer Study Material Sharing App
StudyHub addresses a real and relatable problem — study material at the college level is scattered across WhatsApp groups, expiring Drive links, and random Telegram channels. The app brings everything into one searchable, community-driven library where students earn coins by uploading and spend them to download, which neatly solves the cold-start problem without relying on pure altruism.
Effort is clearly demonstrated across 11 major versions, 7 EAS build attempts before a clean APK, 23 third-party dependencies audited and removed from a broken scaffold, and 8 critical bugs fixed in a single audit session. The entire journey — including what went wrong and exactly why — is documented honestly. Approximately 3,000 lines of TypeScript were written across screens, services, and contexts, with four AdMob ad unit types integrated and a full Firestore coin transaction audit trail implemented.
Three meaningful Quality of Life improvements were made:
Stats refresh accuracy — Home screen stats (uploads, groups joined, bookmarks) were fetched once on mount and went stale immediately after any user action. Replacing useEffect with useFocusEffect means counts re-fetch every time the screen comes into focus, so what the user sees always reflects what they just did.
Member count race condition fixed — When two users tapped “Join Group” simultaneously, both reads returned the same count and one increment was silently lost. Wrapping joinGroup() and leaveGroup() in Firestore runTransaction() makes the read-modify-write atomic, so the count can never drift, go negative, or miss an update regardless of concurrency.
Null-safe auth context eliminates the LoginScreen crash — The original build crashed in production with a TypeError at LoginScreen@1:2447207, traced via adb logcat to a web-only Firebase method (signInWithPopup) being called in a native Android context. The fix replaced it with the correct native Google Sign-In SDK and made login.tsx null-safe throughout — the context is read first, every value accessed with optional chaining, and each handler guards against null before calling — so the screen can never reach a render-time crash due to a timing issue at startup.
All three improvements target reliability for real users, not cosmetic polish, which is exactly the right place to spend effort before a public release.
- 7 devlogs
- 10h
- Frictionless