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

Selfie Plus App Screenshot

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
Items: ketupat (10pts), amplop (15pts), nastar (20pts), bintang (50pts), bomb (game over)

Tech Implementation:

  • useFrameCallback from 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:

  1. User enters referral code during registration (4+ chars triggers validation)
  2. POST /affiliate/check → shows benefits preview (vouchers + points)
  3. Code saved to AsyncStorage as retry safety before submit
  4. POST /auth/register with affiliate_code and device_id
  5. 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, packets
  • catalog_locations - outlet display names for thematic products
  • catalog_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