A fully-featured, type-safe React Native app built with Expo SDK 54 and Expo Router. Designed for field teams and dealers to browse a live spare parts catalogue, raise enquiries, and manage their account - with enterprise-grade security features baked in.
- Features
- Tech Stack
- Architecture
- Project Structure
- Screens & Navigation
- Security Features
- Getting Started
- Environment Variables
- Build & Deploy
- Related Project
- 3-slide onboarding carousel with pagination dots and smooth snap scrolling
- Email + password login with show/hide toggle and client-side validation
- Forgot password flow with reset via email
- Dashboard - 4-card grid for quick access to all key features
- Product search - keyword-based spare parts search with results
- Product detail - full part info with image viewer
- Favorites - save and manage preferred parts
- Enquiry system - raise product enquiries and track history
- User profile - view and manage account details
- Silent token refresh - Axios interceptor silently renews expired JWTs without logging the user out
- Zustand auth store - persisted to AsyncStorage, rehydrated on app launch
- TanStack Query - caching, background refetch and stale-time configuration per query
- Offline detection -
NoInternetscreen shown instantly on connection loss, TanStack QueryonlineManagersynced with NetInfo
- Screenshot and screen recording blocked on Android
- Screen recording blocked on iOS (Apple policy prevents blocking screenshots)
- Custom native Expo plugins for Android
FLAG_SECUREand iOS secure layer - Portrait orientation locked to prevent layout exploits
UpdateManagercomponent checks for Expo OTA updates every hour- Animated modal with progress bar when an update is available
- One-tap download and apply - app reloads automatically
- Skipped safely in development mode
| Category | Technology | Purpose |
|---|---|---|
| Framework | React Native 0.81 + Expo SDK 54 | Cross-platform mobile |
| Language | TypeScript 5 | Full type safety |
| Routing | Expo Router v6 | File-based navigation |
| Styling | NativeWind v4 (Tailwind CSS) | Utility-first styling |
| State | Zustand v5 | Global auth state with persistence |
| Data Fetching | TanStack Query v5 | Server state, caching, background sync |
| HTTP | Axios | API calls + JWT interceptor |
| Storage | AsyncStorage | Token + auth state persistence |
| Updates | expo-updates | OTA update delivery |
| Security | expo-screen-capture | Screenshot/recording prevention |
| Network | @react-native-community/netinfo | Online/offline detection |
| Images | expo-image + react-native-image-viewing | Optimised image rendering + viewer |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β App Entry (_layout.tsx) β
β β
β SecureScreen β QueryClientProvider β AuthProvider β Stack β
β (screen protection) (TanStack Q) (auth state) (nav) β
ββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββΌβββββββββββββββββββ
βΌ βΌ βΌ
Public Screens ProtectedRoute UpdateManager
/index (onboarding) checks Zustand checks for OTA
/login store on mount every 1 hour
/forgot-password β redirects if
not authenticated
β
ββββββββββββββ΄βββββββββββββ
βΌ βΌ
Screen Component Custom Hook
(UI only) (TanStack Query)
β
βΌ
Service Function
(Axios typed call)
β
βΌ
axiosInstance
(base URL + JWT header
+ silent refresh on 401)
β
βΌ
REST API Backend
Key patterns:
- File-based routing via Expo Router - screens are just files in
/app - Zustand store initialized from AsyncStorage on first load (
onRehydrateStorage) - Service layer - typed Axios functions, never called directly from components
- Silent refresh - 401 response triggers token refresh, original request retried automatically
app/ # Expo Router screens (file = route)
βββ _layout.tsx # Root layout - providers, security wrappers, nav stack
βββ index.tsx # Onboarding (3-slide carousel)
βββ login.tsx # Email + password login
βββ forgot-password.tsx # Password reset flow
βββ dashboard.tsx # Home - 4-card grid (protected)
βββ search.tsx # Keyword product search (protected)
βββ seach-limited.tsx # Limited/guest search view
βββ product.tsx # Product detail + image viewer (protected)
βββ favorites.tsx # Saved parts list (protected)
βββ enquiries.tsx # Enquiry history (protected)
βββ enquiry-detail.tsx # Single enquiry detail (protected)
βββ profile.tsx # User profile (protected)
βββ help.tsx # Help & support (protected)
src/
βββ components/
β βββ AuthProvider.tsx # Auth state initializer on app start
β βββ ProtectedRoute.tsx # Route guard - redirects to /login if not authed
β βββ Button.tsx # Reusable button with variants
β βββ EnquiryBottomSheet.tsx # Bottom sheet for raising enquiries
β βββ NoInternet.tsx # Full-screen offline indicator
β βββ UpdateManager.tsx # OTA update checker + animated modal
β βββ SecureScreen.tsx # Blocks screenshots via expo-screen-capture
β βββ SecureScreenPass.tsx # Secondary screen protection layer
β βββ IOSScreenProtection.tsx
β βββ CompleteIOSProtection.tsx
β βββ icons/ # SVG icon components (Search, Save, Profile, etc.)
β
βββ hooks/ # TanStack Query custom hooks
β βββ useAuth.ts # Login, logout, profile fetch mutations
β βββ useProducts.ts # Product listing + search
β βββ useFavorites.ts # Add/remove/list favorites
β βββ useEnquiries.ts # Enquiry list + raise new
β βββ useForgotPassword.ts # Password reset flow
β
βββ services/ # Typed Axios API call functions
β βββ api.ts # Axios instance + JWT interceptor + silent refresh
β βββ userService.ts # Login, logout, profile
β βββ productService.ts # Product search + detail
β βββ favoriteService.ts # Favorites CRUD
β βββ enquiryService.ts # Enquiry list + create
β βββ passwordResetService.ts
β
βββ store/
β βββ authStore.ts # Zustand store - user, token, refreshToken (persisted)
β
βββ types/ # TypeScript interfaces
β βββ auth.ts
β βββ product.ts
β βββ enquiry.ts
β βββ favorite.ts
β βββ index.ts
β
βββ constants/
β βββ config.ts # API base URL
β βββ onboarding.ts # Onboarding slide data
β βββ color.ts # Brand color tokens
β βββ version.ts # App version constant
β
βββ plugins/
βββ withSecureFlag.js # Custom Expo plugin - Android FLAG_SECURE
βββ withSecureFlagiOS.js # Custom Expo plugin - iOS secure layer
| Screen | Route | Auth | Description |
|---|---|---|---|
| Onboarding | / |
β | 3-slide intro carousel with CTA |
| Login | /login |
β | Email + password, forgot password link |
| Forgot Password | /forgot-password |
β | Password reset via email |
| Dashboard | /dashboard |
π | 4-card home grid |
| Search | /search |
π | Keyword spare parts search |
| Product Detail | /product |
π | Full part info + image viewer |
| Favorites | /favorites |
π | Saved parts list |
| Enquiries | /enquiries |
π | Enquiry history |
| Enquiry Detail | /enquiry-detail |
π | Single enquiry view |
| Profile | /profile |
π | User account details |
| Help & Support | /help |
π | Support information |
π = Protected by
ProtectedRoutecomponent - unauthenticated users are redirected to/login
This app implements multiple layers of screen protection to prevent data leaks through screenshots or screen recording:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Security Stack β
β β
β 1. SecureScreen expo-screen-capture β
β ββ preventScreenCaptureAsync() on mount β
β β
β 2. SecureScreenPass Secondary protection layer β
β β
β 3. CompleteIOSProtection iOS-specific secure view β
β β
β 4. IOSScreenProtection Additional iOS layer β
β β
β 5. withSecureFlag.js Native plugin β Android β
β ββ Sets FLAG_SECURE WindowManager flag β
β β
β 6. withSecureFlagiOS.js Native plugin β iOS β
β ββ Secure UITextField layer β
β β
β 7. Portrait lock ScreenOrientation.lockAsync() β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Platform | Screenshots | Screen Recording |
|---|---|---|
| Android | β Blocked | β Blocked |
| iOS | β Blocked |
- Node.js v18+
- Expo CLI -
npm install -g expo-cli - Expo Go app on device or Android/iOS emulator
# 1. Clone the repository
git clone https://github.com/6ixline/react-native-product-catalogue.git
cd react-native-parts-catalogue
# 2. Install dependencies
npm install
# 3. Start the Expo development server
npx expo startThen press a for Android emulator or i for iOS simulator, or scan the QR code with Expo Go.
Update src/constants/config.ts with your API URL:
export const BASE_URL = "https://your-api-domain.com";
export const API_BASE_URL = 'https://your-api-domain.com/api';# Build for Android (APK preview)
eas build --platform android --profile preview
# Build for iOS
eas build --platform ios --profile preview
# OTA update (no store submission needed)
eas update --branch production --message "your update message"This app connects to the Product Catalog REST API for all data:
π§ nodejs-express-rest-api - Node.js + Express 5 + MySQL backend with multi-role JWT auth, product catalog, enquiry system and bulk Excel import.
This project is open source and available under the MIT License.
Built with β€οΈ using React Native & Expo