React Native Mobile App Build Prompt
Use this prompt when building the FishingLog React Native mobile application.
Project Overview
FishingLog Mobile App is a comprehensive fishing log and social platform mobile app built with React Native. Users can track fishing trips, catches, gear, participate in tournaments, connect with other anglers, and access fishing regulations on iOS and Android devices.
Backend API
- Base URL:
https://api.fishinglog.com/api(or configured via environment variable) - Authentication: AWS Cognito JWT Bearer tokens
- User Pool ID:
us-east-2_TZtGx1T3X - Client ID:
6i1opt39o2n5h5ihq471l1ev07 - Swagger Docs: Available at
/swaggerendpoint
Authentication Flow
- User authenticates via AWS Cognito (use
amazon-cognito-identity-jsor@aws-amplify/auth) - Receive JWT token from Cognito
- Include token in all API requests:
Authorization: Bearer {token} - Token expires - refresh using Cognito refresh token
Recommended Tech Stack
Core
- React Native (latest stable)
- TypeScript (strongly recommended)
- React Navigation (v6+) - Navigation
- React Query / TanStack Query - API state management
- Zustand / Redux Toolkit - Global state (if needed)
Authentication
- @aws-amplify/auth or amazon-cognito-identity-js
- @react-native-async-storage/async-storage - Token storage
- react-native-keychain - Secure storage (optional, recommended)
API Client
- axios - HTTP client
- Create API service layer with interceptors for auth
- Handle token refresh automatically
UI Components
- TamaGUI (Pro version) - Primary component library with theming support
- react-native-maps - Map integration
- react-native-image-picker - Photo selection
- react-native-image-crop-picker - Image editing
- @react-native-community/datetimepicker - Date/time pickers
Forms & Validation
- react-hook-form - Form management
- zod or yup - Validation
Location
- @react-native-community/geolocation - Location services
- react-native-maps - Map display
Media
- react-native-image-picker - Photo/video selection
- react-native-video - Video playback
- react-native-fast-image - Optimized images
Payments
- @stripe/stripe-react-native - Stripe integration
- See
stripe-integration.mdfor implementation details
Feature Flags
- Feature flag hooks for conditional rendering
- See
feature-flags.mdfor implementation guide
Notifications
- @react-native-firebase/messaging or expo-notifications - Push notifications
Project Structure
src/
├── api/
│ ├── client.ts # Axios instance with auth
│ ├── endpoints/
│ │ ├── auth.ts
│ │ ├── fishingLog.ts
│ │ ├── gear.ts
│ │ ├── social.ts
│ │ ├── tournaments.ts
│ │ └── payments.ts
│ └── types.ts # API response types
├── components/
│ ├── common/ # Reusable components
│ ├── fishing/ # Fishing-specific components
│ ├── social/ # Social components
│ ├── payments/ # Payment components
│ └── feature-gates/ # Feature flag components
├── screens/
│ ├── Auth/
│ │ ├── LoginScreen.tsx
│ │ ├── RegisterScreen.tsx
│ │ └── ForgotPasswordScreen.tsx
│ ├── FishingLog/
│ │ ├── FishingLogListScreen.tsx
│ │ ├── FishingLogEntryScreen.tsx
│ │ └── CreateEntryScreen.tsx
│ ├── Social/
│ │ ├── FeedScreen.tsx
│ │ ├── PostDetailScreen.tsx
│ │ └── CirclesScreen.tsx
│ ├── Tournaments/
│ │ ├── TournamentListScreen.tsx
│ │ ├── TournamentDetailScreen.tsx
│ │ └── TournamentRegistrationScreen.tsx
│ └── Profile/
│ └── ProfileScreen.tsx
├── navigation/
│ ├── AppNavigator.tsx
│ ├── AuthNavigator.tsx
│ └── TabNavigator.tsx
├── hooks/
│ ├── useAuth.ts
│ ├── useFeatureFlags.ts
│ ├── useFishingLog.ts
│ └── usePayments.ts
├── store/
│ ├── authStore.ts
│ └── uiStore.ts
├── utils/
│ ├── storage.ts
│ └── permissions.ts
└── types/
└── index.ts
Core Features & Implementation
1. Authentication & User Profile
Screens:
- LoginScreen
- RegisterScreen
- ForgotPasswordScreen
- ProfileScreen
Endpoints:
GET /api/userprofile/me- Get current user profilePUT /api/userprofile/me- Update profileGET /api/userprofile/{userId}- Get public profile
Key Data:
- User info, avatar, bio, location
- Privacy settings (
ProfileVisibility) - Subscription tier (
Free,Basic,Pro) - Personal bests, achievements
Implementation Notes:
- Store JWT token securely (use
react-native-keychainor@react-native-async-storage/async-storage) - Handle token refresh automatically
- Show subscription tier badge
- Respect privacy settings when viewing profiles
Example:
// hooks/useAuth.ts
import { useQuery, useMutation } from '@tanstack/react-query';
import AsyncStorage from '@react-native-async-storage/async-storage';
export function useAuth() {
const [token, setToken] = useState<string | null>(null);
useEffect(() => {
AsyncStorage.getItem('authToken').then(setToken);
}, []);
const login = async (email: string, password: string) => {
// Cognito login logic
const cognitoToken = await cognitoLogin(email, password);
await AsyncStorage.setItem('authToken', cognitoToken);
setToken(cognitoToken);
};
const logout = async () => {
await AsyncStorage.removeItem('authToken');
setToken(null);
};
return { token, login, logout };
}
2. Fishing Log Entries
Screens:
- FishingLogListScreen
- FishingLogEntryScreen
- CreateEntryScreen
Endpoints:
GET /api/fishinglog/entries- Get entries (respects privacy)GET /api/fishinglog/entries/{id}- Get specific entryPOST /api/fishinglog/entries- Create entryPUT /api/fishinglog/entries/{id}- Update entryDELETE /api/fishinglog/entries/{id}- Delete entryGET /api/fishinglog/sessions- Get fishing sessionsPOST /api/fishinglog/sessions- Create sessionPOST /api/fishinglog/entries/{entryId}/catches- Add catch
Key Data:
FishingLogEntry: Date, location, weather, notes, visibilityCatchDetail: Species, length, weight, photos, gear usedFishingSession: Start/end time, location, conditions
Implementation Notes:
- Use location services for automatic location
- Support photo uploads (use
react-native-image-picker) - Privacy controls:
Public,Private,Friends,Circle - Filter by date range, species, location
- Show map view of fishing locations
- Link catches to gear setups
Example:
// screens/FishingLog/CreateEntryScreen.tsx
import { useForm } from 'react-hook-form';
import ImagePicker from 'react-native-image-picker';
import Geolocation from '@react-native-community/geolocation';
function CreateEntryScreen() {
const { control, handleSubmit } = useForm();
const [location, setLocation] = useState<Location | null>(null);
useEffect(() => {
Geolocation.getCurrentPosition(
(position) => {
setLocation({
latitude: position.coords.latitude,
longitude: position.coords.longitude
});
}
);
}, []);
const pickImage = () => {
ImagePicker.launchImageLibrary({}, (response) => {
if (response.uri) {
// Upload image and add to form
}
});
};
const onSubmit = async (data: FishingLogEntryForm) => {
await createFishingLogEntry({
...data,
latitude: location?.latitude,
longitude: location?.longitude
});
};
return (
<Form>
{/* Form fields */}
</Form>
);
}
3. Social Features
Screens:
- FeedScreen
- PostDetailScreen
- CirclesScreen (if Circles feature enabled)
Endpoints:
GET /api/social/posts- Get feedPOST /api/social/posts- Create postPOST /api/social/posts/{id}/like- Like postPOST /api/social/posts/{id}/comments- Add commentGET /api/circle- Get circles (if enabled)GET /api/circle/discover- Discover circles (if enabled)
Feature Flag Check:
// screens/Social/CirclesScreen.tsx
import { useFeatureFlag } from '@/hooks/useFeatureFlags';
import { FeatureGate } from '@/components/FeatureGate';
function CirclesScreen() {
const circlesEnabled = useFeatureFlag('Circles');
if (!circlesEnabled) {
return (
<View>
<Text>This feature is not available.</Text>
</View>
);
}
return <CirclesContent />;
}
4. Tournaments
Screens:
- TournamentListScreen
- TournamentDetailScreen
- TournamentRegistrationScreen (with payment)
Endpoints:
GET /api/tournament- List tournamentsGET /api/tournament/{id}- Tournament detailsPOST /api/tournament/{id}/register- Register (creates payment intent)
Stripe Payment Integration:
// screens/Tournaments/TournamentRegistrationScreen.tsx
import { useStripe } from '@stripe/stripe-react-native';
import { initStripe } from '@stripe/stripe-react-native';
// Initialize Stripe
initStripe({
publishableKey: process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY!,
merchantIdentifier: 'merchant.com.fishinglog', // iOS only
});
function TournamentRegistrationScreen({ tournamentId }: { tournamentId: number }) {
const { initPaymentSheet, presentPaymentSheet } = useStripe();
const [clientSecret, setClientSecret] = useState<string | null>(null);
const handleRegister = async () => {
// Create registration and payment intent
const response = await fetch(`/api/tournament/${tournamentId}/register`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` },
body: JSON.stringify({ /* registration data */ })
});
const data = await response.json();
setClientSecret(data.stripeClientSecret);
// Initialize payment sheet
const { error } = await initPaymentSheet({
paymentIntentClientSecret: data.stripeClientSecret,
merchantDisplayName: 'FishingLog',
});
if (error) {
Alert.alert('Error', error.message);
}
};
const handlePay = async () => {
const { error } = await presentPaymentSheet();
if (error) {
Alert.alert('Error', error.message);
} else {
Alert.alert('Success', 'Registration confirmed!');
// Navigate to tournament detail
}
};
return (
<View>
{!clientSecret ? (
<Button onPress={handleRegister}>Register</Button>
) : (
<Button onPress={handlePay}>Pay Entry Fee</Button>
)}
</View>
);
}
5. Charter Bookings
Screens:
- CharterListScreen
- CharterDetailScreen
- CharterBookingScreen (with payment)
Endpoints:
GET /api/charter/listings- List chartersPOST /api/charter/listings/{id}/book- Create booking (creates payment intent)
Feature Flag Check:
<FeatureGate feature="Charters">
<CharterListScreen />
</FeatureGate>
6. Gear Management
Screens:
- GearCatalogScreen
- GearSetupScreen
- CreateSetupScreen
Endpoints:
GET /api/gear/rods- Get rod catalogGET /api/gear/reels- Get reel catalogGET /api/gear/setups- Get setupsPOST /api/gear/setups- Create setup
Implementation Notes:
- Search/filter gear catalog
- Create custom gear setups
- Link setups to catches
- Track gear usage statistics
Feature Flags Implementation
Feature Flag Hook
// hooks/useFeatureFlags.ts
import { useQuery } from '@tanstack/react-query';
import { useAuth } from './useAuth';
export function useFeatureFlags() {
const { token } = useAuth();
return useQuery({
queryKey: ['featureFlags'],
queryFn: async () => {
const response = await fetch(
'https://api.fishinglog.com/api/admin/feature-flags/current-environment',
{
headers: { 'Authorization': `Bearer ${token}` }
}
);
const data = await response.json();
return data.featureFlags;
},
staleTime: 5 * 60 * 1000,
enabled: !!token, // Only fetch if authenticated
});
}
export function useFeatureFlag(featureKey: string) {
const { data: flags } = useFeatureFlags();
return flags?.[featureKey] ?? false;
}
Feature Gate Component
// components/FeatureGate.tsx
import { useFeatureFlag } from '@/hooks/useFeatureFlags';
import { View, Text } from 'react-native';
interface FeatureGateProps {
feature: string;
children: React.ReactNode;
fallback?: React.ReactNode;
}
export function FeatureGate({ feature, children, fallback }: FeatureGateProps) {
const isEnabled = useFeatureFlag(feature);
if (!isEnabled) {
return fallback ? <>{fallback}</> : null;
}
return <>{children}</>;
}
Usage in Navigation
// navigation/TabNavigator.tsx
import { useFeatureFlag } from '@/hooks/useFeatureFlags';
function TabNavigator() {
const circlesEnabled = useFeatureFlag('Circles');
const tournamentsEnabled = useFeatureFlag('Tournaments');
return (
<Tab.Navigator>
<Tab.Screen name="Feed" component={FeedScreen} />
<Tab.Screen name="FishingLog" component={FishingLogScreen} />
{circlesEnabled && (
<Tab.Screen name="Circles" component={CirclesScreen} />
)}
{tournamentsEnabled && (
<Tab.Screen name="Tournaments" component={TournamentsScreen} />
)}
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
);
}
API Client Setup
// api/client.ts
import axios from 'axios';
import AsyncStorage from '@react-native-async-storage/async-storage';
export const apiClient = axios.create({
baseURL: process.env.REACT_APP_API_URL || 'https://api.fishinglog.com/api',
});
apiClient.interceptors.request.use(async (config) => {
const token = await AsyncStorage.getItem('authToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
apiClient.interceptors.response.use(
(response) => response,
async (error) => {
if (error.response?.status === 401) {
// Handle token refresh or redirect to login
await AsyncStorage.removeItem('authToken');
// Navigate to login screen
}
return Promise.reject(error);
}
);
Environment Variables
REACT_APP_API_URL=https://api.fishinglog.com/api
REACT_APP_STRIPE_PUBLISHABLE_KEY=pk_test_...
REACT_APP_COGNITO_USER_POOL_ID=us-east-2_TZtGx1T3X
REACT_APP_COGNITO_CLIENT_ID=6i1opt39o2n5h5ihq471l1ev07
Implementation Checklist
Phase 1: Foundation
- Initialize React Native project with TypeScript
- Set up React Navigation
- Configure API client with auth interceptors
- Set up TanStack Query
- Create auth context/store
- Implement secure token storage
- Set up error handling
Phase 2: Core Features
- Implement authentication flow
- Build fishing log entry screens
- Create social feed
- Implement feature flag hooks/components
- Add conditional navigation based on flags
- Build gear management screens
Phase 3: Payments & Advanced Features
- Integrate Stripe payments (payment sheet)
- Implement tournament registration with payment
- Build charter booking flow
- Add location services
- Implement photo uploads
- Build user profiles
Phase 4: Polish
- Add loading states
- Implement error boundaries
- Add toast notifications
- Optimize performance
- Add push notifications
- Implement offline support (if needed)
Critical Implementation Notes
Feature Flags
- Always check flags before rendering features
- Use FeatureGate component for conditional rendering
- Cache flags for 5 minutes (matches backend)
- Handle loading/error states gracefully
- Hide disabled features from navigation
Stripe Payments
- Initialize Stripe before using payment sheet
- Use payment sheet (not card input) for better UX
- Handle payment errors gracefully
- Use test cards during development
- Show clear success/error messages
Authentication
- Store tokens securely (use Keychain on iOS, Keystore on Android)
- Implement automatic token refresh
- Handle 401 errors by redirecting to login
- Clear tokens on logout
- Validate token expiration before API calls
Permissions
- Request location permission before using location
- Request camera permission before taking photos
- Handle permission denials gracefully
- Show permission rationale to users
Testing
Feature Flags
- Test with flags enabled/disabled
- Test flag loading states
- Verify features are hidden when disabled
- Test navigation updates when flags change
Stripe Payments
- Use test cards:
4242 4242 4242 4242(success) - Test payment failures
- Test on both iOS and Android
- Verify webhook updates (check backend logs)
Location Services
- Test location permission flow
- Test location accuracy
- Handle location errors gracefully
Platform-Specific Considerations
iOS
- Configure Info.plist for location permissions
- Set up Stripe merchant identifier
- Handle App Store review requirements
Android
- Configure AndroidManifest.xml for permissions
- Handle runtime permissions (Android 6+)
- Set up Stripe merchant configuration
Documentation References
- React Native Guide:
docs/frontend/react-native.md - Stripe Integration:
docs/frontend/stripe-integration.md - Feature Flags:
docs/frontend/feature-flags.md - Backend API:
docs/api/README.md
Success Criteria
A successful mobile app implementation should:
- ✅ Handle authentication and token management securely
- ✅ Respect feature flags for all features
- ✅ Integrate Stripe payments correctly (payment sheet)
- ✅ Handle errors gracefully
- ✅ Provide good user feedback
- ✅ Work on both iOS and Android
- ✅ Handle permissions correctly
- ✅ Be performant and responsive
- ✅ Follow platform-specific guidelines