Selfie Plus: Loyalty Program Mobile App
Client
PT Intinya Technologi
My Role
Mobile App Owner (React Native)
Duration
July 2025 - Present
Tech Stack
React Native 0.79.6 (React 19), TypeScript, TanStack Query v5, Redux Toolkit + Persist, NativeWind, Firebase (FCM + Crashlytics), Notifee
Key Features
Auth + onboarding, points wallet, voucher marketplace + QR redemption, transaction gallery (download + share), queue monitoring, push + local notifications, feeds (news/IG/blog/YT), product catalog

Project Overview
Selfie Plus is a membership and loyalty mobile app for Selfie Time. It connects real-world outlet activity (transactions, queueing, photo delivery) with loyalty mechanics (points and vouchers) and engagement loops (feeds, reminders, and limited-time mini games).
The app is built with React Native 0.79.6 + React 19 and ships to both Android and iOS. Data fetching uses TanStack Query (v5) on top of an Axios client with auth handling; global app state uses Redux Toolkit with persisted user session.
At PT Intinya Technologi, I own the Selfie Time mobile application end to end: product delivery, architecture decisions, release readiness, and critical feature implementation.
Business Flows (End-to-End)
- Authentication & onboarding: email/password login, social login (Google; Apple on iOS; Facebook flow exists), OTP/email verification, then profile completion gating (e.g., DOB) before entering the main app.
- Loyalty wallet: users have a points balance; balance refresh is integrated into user/profile workflows.
- Voucher marketplace: browse redeemable vouchers (infinite list), view detail, and redeem with points; users then manage "My Vouchers" and redeem in-store using QR.
- Transactions: transaction history and detail, including paid items, status, and a photo/video gallery delivered from sessions.
- Queueing: users with active sessions receive live queue status polling; the app surfaces an always-on queue monitor when your turn is close.
- Engagement: news feed, Instagram feed, blog, YouTube viewer, plus a seasonal mini-game (THR Catcher) that can grant bonus points with a server-side daily claim limit.
Key Features
Vouchers + QR Redemption
Users can redeem vouchers with points, then present a QR code in outlet for redemption. Voucher detail supports rules and restrictions (valid dates, outlet/product/day constraints) and gracefully handles expired/used states.
Transaction Gallery
Transaction detail aggregates session metadata and gallery items (photos + videos). Users can preview, download to device, and open a web-based "unlock photos" flow when needed.
Queue Monitoring
The app polls queue status (per-user, per-outlet session) and shows a floating, dismissible monitor when the turn is near; it triggers haptics/vibration when the order becomes 1.
Share to Instagram Stories
From the gallery, users can share an image to Instagram Stories. The flow downloads the remote image, composes a branded 1080x1920 story image with a frame, then launches Instagram Stories sharing with platform-specific handling and cleanup.
THR Catcher Mini-Game
A seasonal, gamified campaign: users play a 3-level catching game and can claim a points reward upon completion. The claim flow is enforced server-side (max 1 reward per day) while the client handles the game loop, UI, and reward submission.
Game Mechanics:
- Level 1: Spawn 650ms, bomb 18%, speed 6.25
- Level 2: Spawn 450ms, bomb 28%, speed 7.5
- Level 3: Spawn 350ms, bomb 38%, speed 8.5
Tech Implementation:
useFrameCallbackfrom Reanimated for 60fps game loop- Pan gesture handler for catcher control
- React Query mutations with exponential backoff retry (4 retries, 1.5s base)
- Idempotency key (X-IDEMPOTENCY-KEY: session_id) for reward claim
- Server-side session tracking: POST /new/thr-catcher/session/start → play → POST /session/end → POST /claim-reward
Affiliate/Referral System
Full-featured referral program where users share codes to invite others, earning points and vouchers as rewards. Features fraud prevention and pending rewards activation on first paid transaction.
User Flow:
- User enters referral code during registration (4+ chars triggers validation)
- POST /affiliate/check → shows benefits preview (vouchers + points)
- Code saved to AsyncStorage as retry safety before submit
- POST /auth/register with affiliate_code and device_id
- Rewards held as "pending" until first paid transaction
Tech Implementation:
- Pending referral code persisted in AsyncStorage (@pending_referral_code)
- useAffiliateRetry hook auto-retries on mount if code pending but not applied
- Device-based cooldown: 3 uses → 30-day ban per device
- Duplicate phone block + self-referral prevention
- OnTransactionPaid event → activates pending vouchers + awards points
Content Feeds
In-app content distribution surfaces updates via news feed, Instagram feed, blog detail, and YouTube viewer screens to keep members engaged between visits.
Architecture (How It Works)
The app uses React Navigation (native stack + bottom tabs) with deep linking (custom scheme) for notifications and marketing links. Most server communication goes through a single Axios client that injects a bearer token and triggers a safe logout on 401/Unauthenticated.
- State: Redux Toolkit for app/global state; Redux Persist keeps the authenticated user session across restarts.
- Data: TanStack Query v5 for queries, infinite lists, and mutations; sensible defaults (retry + caching) configured at app root.
- Networking: Axios client under `/api` with auth header injection and centralized 401 handling.
- UI: NativeWind (Tailwind for React Native) plus reusable UI primitives (buttons, inputs, modals) and custom tab bar.
- Reliability: Error boundary + global error handler with Firebase Crashlytics (production) for crash capture.
Notifications & Deep Linking
- Push notifications: Firebase Cloud Messaging; foreground and background handlers display notifications via Notifee.
- Local notifications: scheduled voucher expiry reminders (1, 7, 14 days before expiration) using timestamp triggers.
- Deep links: notification payloads can include a `link` field; when pressed, the app opens the deep link and routes the user to the correct screen.
Technical Challenges & Solutions
React Native Upgrade + 16KB Page Size Compliance
Migrated the app across multiple major React Native versions to React Native 0.79.6 + React 19, modernizing Android build tooling for upcoming Play Store 16KB page size requirements.
- Android: AGP 8.6, JDK 17, SDK 35, NDK 27.x, Hermes
- Enabled New Architecture (TurboModules + Fabric) and Bridgeless mode
- Implementing support for Android 16KB page sizes
- Used patch-package to keep critical third-party libraries working during upgrades
Instagram Stories Sharing (Anti-Crop + Cross-Platform)
Built a deterministic share pipeline for Instagram Stories that is reliable on both platforms.
- Downloads remote images to local cache first for stable processing
- Composes a branded story image at 1080x1920 using ViewShot and tuned transforms (scale/rotate) to avoid unwanted cropping
- Uses Instagram Stories share integration with platform-specific behaviors (Android FileProvider/content URIs; iOS scheme checks)
- Cleans up temporary files after share to avoid cache bloat
Performance Optimization
Enhanced app performance through specific techniques:
- FasterImageView (@candlefinance/faster-image) replacing standard Image for cached image loading in SliderList, CatalogList, PopupList, InstagramFeed, PhotoHistory
- React Native Reanimated Carousel with windowSize: 5 virtualization, parallax scrolling (scale: 0.9, offset: 50), autoPlay at 3000ms interval
- Priority-based lazy loading strategy:
- Priority 1 (critical): Slider + Outlets - load immediately with 2min staleTime
- Priority 2 (secondary): Deferred 1.5s to spread API calls
- Priority 3 (below-fold): Load only on scroll (scrollY > 200px trigger)
- React.memo on GameItem component to prevent unnecessary re-renders
- useCallback wrappers on game state transitions (startGame, pauseGame, resumeGame, gameOver, nextLevel)
- TanStack Query caching + infinite queries for long lists (vouchers, transactions)
- Navigation: unmountOnBlur on ProductStack, lazy: false on ProfileStack
- Avoiding repeated side effects with explicit "run once" guards
Product Catalog Dynamic Refactor
Major refactor from hardcoded product data to dynamic server-driven catalog. Admin team can now manage products without developer intervention.
Before → After:
- Before: Hardcoded items.ts (1750+ lines), need developer for updates
- After: Dynamic API (GET /api/catalog-products), admin dashboard CRUD
Database Schema:
catalog_products- name, category, price_display, features, packetscatalog_locations- outlet display names for thematic productscatalog_product_locations- pivot table for product-location mapping
API (5-min cache):
- GET /api/catalog-products - public endpoint, eager loaded (4 queries total)
- Returns grouped by category: photobooth, thematic, studioPro, highAngle, wideAngle, professionalFoto, additional, retailProduct
- Thematic products include available_in array for location filtering
Admin Dashboard:
- Livewire CRUD for products and locations
- Feature management (add/remove with deferred deletion)
- Location mapping for thematic products
- Double cache invalidation pattern on save
Type Safety Implementation
Improved code quality and maintainability by:
- Migrating key components from JavaScript to TypeScript
- Implementing comprehensive type definitions for API responses and state management
- Creating reusable typed custom hooks for common functionality
- Establishing type-safe patterns for component props and state management
Results & Impact
The Selfie Plus app has delivered significant value to both users and the business:
- Modernized React Native stack (0.79.6 + React 19) and Android build toolchain to meet upcoming platform requirements
- Shipped media-heavy transaction gallery flows (images + videos) with download and sharing capabilities
- Improved engagement loops with notifications, feed content, and queue monitoring
- Increased maintainability via typed hooks, centralized networking, and consistent state/data boundaries
- Created a platform-ready application compliant with the latest Android and iOS requirements
My Key Contributions
- Delivered the end-to-end Instagram Stories sharing pipeline (download -> compose -> share -> cleanup)
- Led major framework/tooling upgrades (React Native 0.79.6, New Architecture, Bridgeless mode, Android build modernization)
- Implemented 16KB page size readiness work and coordinated related dependency migrations
- Migrated/typed key flows and hooks to improve type safety and reduce runtime errors
- Improved reliability of push + local notifications (FCM + Notifee) including deep link handling
- Created reusable components and custom hooks for common functionality
- Implemented comprehensive error handling and logging for development and production environments