A React Native Android app with Firebase Cloud Messaging, multi-language support (English/Tamil), voice-to-text input, and context-based authentication. Currently features Function Categories CRUD as a foundation for larger Feature development.
src/
├── App.js # Entry point, navigation setup
├── components/ # Reusable UI components
├── context/ # Global state (Auth, Language)
├── hooks/ # Custom React hooks (currently empty)
├── navigation/ # Navigation configuration (currently empty)
├── screens/ # Screen components
├── services/ # External service integrations (Firebase)
└── utils/ # Utility functions (i18n, storage)
screens/
├── HomeScreen.js # Dashboard with navigation grid
├── LoginScreen.js
├── FunctionCategories/ # FEATURE FOLDER TEMPLATE
│ ├── index.js # List screen with CRUD operations
│ └── Form.js # Form for add/edit
└── Notifications/
├── NotificationsScreen.js
└── NotificationDetailScreen.js
Pattern: Each feature has:
index.js→ List/view screenForm.js→ Add/edit form- State management via route params (no Redux/Zustand)
components/
├── FormInputs/
│ └── Input.js # 🎯 REUSABLE: Voice + Password + Validation
├── Icons/
│ ├── MicIcon.js # SVG Icons
│ ├── EyeIcon.js
│ └── EyeOffIcon.js
├── AppLoader.js # Loading screen during auth check
└── HeaderUserMenu.js # Header user menu
Location: src/components/FormInputs/Input.js
Features:
- Wraps
react-hook-formController - Voice-to-text input (with MicIcon toggle)
- Password visibility toggle (with EyeIcon)
- Built-in error display
- Custom validation rules support
- Optional multi-line support
Usage Pattern:
<Input
name="fieldName"
label="Label Text"
control={control} // from useForm()
required={true}
rules={{ required: 'Error msg' }}
password={false} // shows eye icon
voice={true} // shows mic icon (default)
handleChange={callback} // optional onChange handler
/>Current State: src/hooks/index.js is empty
Opportunity: Could create custom hooks like:
useAsyncStorage(key)- wrapper for AsyncStorageuseFunctionCRUD()- generic CRUD hook for reuse
Location: src/App.js
Stack.Navigator
├── [Authenticated Routes]
│ ├── Home (default)
│ ├── Notifications + NotificationDetail
│ ├── FunctionCategories (list)
│ └── FunctionCategoryForm (add/edit)
└── [Unauthenticated]
└── Login- List → Form:
navigation.navigate('FunctionCategoryForm', { category: item }) - Form → List:
navigation.navigate('FunctionCategories', { category: data, isEdit: bool }) - Passing data via route params:
route?.params?.category - Navigation ref available: src/navigation/navigationRef.js for imperative navigation
Key Observation: No modal/side stack for nested flows - all screens are in main stack.
Location: src/screens/FunctionCategories/Form.js
Pattern:
const { control, handleSubmit, formState: { isSubmitting } } = useForm({
defaultValues: {
name: editingCategory?.name || '',
tamilName: editingCategory?.tamilName || '',
description: editingCategory?.description || '',
},
});
// Wrapped Input components with validation
<Input name="name" control={control} rules={{ required: 'Required' }} />
// Submit handler with fake delay
const onSubmit = async data => {
await new Promise(resolve => setTimeout(resolve, 2000));
// Pass data via navigation
navigation.navigate('FunctionCategories', { category: categoryData, isEdit: !!editingCategory });
};required: 'message'- custom message- Built-in error display in Input component
- No complex validations yet (min/max, patterns, etc.)
- Current: Route params only (volatile - lost on app restart)
- Available: AsyncStorage (used for auth only)
- Opportunity: Create AsyncStorage persistence layer for CRUD data
Location: src/context/AuthContext.js
Pattern:
const AuthContext = createContext(null);
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
// Hydrate from AsyncStorage on app start
useEffect(() => {
const storedUser = await getUser();
setUser(storedUser);
}, []);
}- Mock login:
admin/admin(2000ms delay) - Persistence: AsyncStorage (key:
AUTH_USER)
Location: src/context/LanguageContext.js
Pattern:
export function LanguageProvider({ children }) {
const [language, setLanguage] = useState('en'); // 'en' | 'ta'
const toggleLanguage = () => {
setLanguage(prev => (prev === 'en' ? 'ta' : 'en'));
};
}
export function useLanguage() {
return useContext(LanguageContext); // { language, toggleLanguage, translations }
}- i18n Location: src/utils/i18n.js
- Flat object structure:
translations['en'],translations['ta']
Location: src/screens/FunctionCategories/index.js
Current Implementation:
- useState for categories array
- setCategories for CRUD operations
- Alert for confirmations (delete)
- Toast notifications for feedback
Data Flow:
- User fills form → submits
- Form navigates back with
{ category, isEdit } - List screen receives params via
route.params - useEffect merges new/updated category into state
- Colors: Material Blue (#1976D2), gray (#9E9E9E), red (#E53935)
- Background: Light gray (#F6F8FA)
- Spacing: 16px padding, 12px gaps
- StyleSheet.create(): All components use StyleSheet
- Elevation: Used for cards (elevation: 2-4)
- Responsive: Card width calculation for grid layout
Example:
const { width } = Dimensions.get('window');
const CARD_SIZE = (width - PADDING * 2 - GAP * 2) / 3;Location: src/services/firebaseService.js
✅ requestUserPermission() // Ask notification permission
✅ getFcmToken() // Get device token
✅ onMessageListener() // Foreground notifications
✅ onNotificationOpenedAppListener() // Background tap
✅ getInitialNotificationListener() // Quit state tap- App.js: Initializes FCM on app start
- Toast notifications: Integrated for UX feedback
SVG Icons via react-native-svg (not vector icon font)
Available:
MicIcon- voice inputEyeIcon- show passwordEyeOffIcon- hide password
HomeScreen emojis: 📂, 📋, 🔔, ➕
Location: src/utils/i18n.js
export const translations = {
en: { functionCategories: 'Function Categories', ... },
ta: { functionCategories: 'நிகழ்ச்சி வகைகள்', ... },
};
// In component
const { translations } = useLanguage();
<Text>{translations.functionCategories}</Text>Current Keys:
functionCategories,viewFunctions,notifications,morename,tamilName,descriptionsave,cancel,deleteCategory
| Area | Pattern | File(s) |
|---|---|---|
| Feature Structure | Feature folder with List + Form | FunctionCategories/ |
| Forms | react-hook-form + Input component | FormInputs/Input.js |
| Validation | Rules in useForm() + error display | Form.js |
| State Management | Context API for global (Auth, Language) | context/ |
| Data CRUD | useState + route params (can scale to AsyncStorage) | screens/ |
| Notifications | Toast for feedback, Alert for confirmation | All screens |
| Storage | AsyncStorage wrapper functions | utils/authStorage.js |
| Navigation | Stack navigator, route params passing | App.js, navigationRef.js |
| Styling | StyleSheet.create(), responsive via Dimensions | All components |
| i18n | Flat translation objects by language | utils/i18n.js |
| Icons | SVG via react-native-svg | components/Icons/ |
screens/
├── FunctionCategories/ ✅ Already exists
│ ├── index.js
│ └── Form.js
├── Functions/ 🆕 New feature
│ ├── index.js (List all functions)
│ └── Form.js (Add/edit function)
└── Events/ 🆕 New feature
├── index.js (List all events)
└── Form.js (Add/edit event)
screens/
├── Events/ 🆕 New feature
│ ├── index.js (List + filter by type)
│ ├── Form.js (Create function/event)
│ └── Detail.js (View details, linked functions)
└── FunctionCategories/ ✅ Unchanged
-
Create storage utility:
utils/functionStorage.jssaveFunctions(functions)→ AsyncStoragegetFunctions()→ AsyncStoragesaveEvents(events)→ AsyncStoragegetEvents()→ AsyncStorage
-
Create custom hook:
hooks/useFunctionCRUD.js- Generic CRUD hook with AsyncStorage persistence
- Hydrate on mount, auto-save on change
-
Add i18n keys in src/utils/i18n.js
functionName,eventName,date,time,location, etc.
-
Add routes in src/App.js
<Stack.Screen name="Functions" component={FunctionsScreen} /> <Stack.Screen name="FunctionForm" component={FunctionForm} />
-
Add home buttons in src/screens/HomeScreen.js
{ id: 'functions', label: 'Functions', onPress: () => navigate('Functions') } { id: 'events', label: 'Events', onPress: () => navigate('Events') }
-
Extend Input.js for new field types
- Date picker
- Time picker
- Dropdown/select
- Checkbox for multi-selection
-
Create new form screens (follow FunctionCategoryForm pattern)
-
Create list screens (follow FunctionCategoriesScreen pattern with filtering/sorting)
- Link Functions to Categories (dropdown selector)
- Link Events to Functions (multi-select or referenced)
- Add search/filter functionality
❌ Don't modify existing setup/config files ❌ Don't change authentication implementation ❌ Don't move components around ❌ Don't change navigation ref implementation ❌ Don't add complex state library (Zustand, Redux) - use Context + AsyncStorage hooks ❌ Don't hardcode translations - always use i18n ❌ Don't use different styling patterns - follow StyleSheet.create()
✅ Create new feature folders under screens/
✅ Extend utils/ with storage helpers
✅ Create custom hooks in hooks/
✅ Extend translations in utils/i18n.js
✅ Add more Input field types to FormInputs/Input.js
✅ Add more icons to components/Icons/
✅ Create new context if needed (but prefer AsyncStorage + hooks)
✅ Add new screens to navigation stack in App.js
- src/screens/FunctionCategories/index.js - List pattern
- src/screens/FunctionCategories/Form.js - Form pattern
- src/components/FormInputs/Input.js - Input component
- src/utils/authStorage.js - Storage pattern
- src/utils/i18n.js - i18n pattern
- src/context/LanguageContext.js - Context pattern
- src/App.js - Add new routes
- src/screens/HomeScreen.js - Add navigation items
- src/utils/i18n.js - Add new translations
The project is well-structured for scaling. Follow the FunctionCategories pattern as your template, create storage utilities using AsyncStorage, and leverage the existing Input component + useForm pattern for all new features.
Next Steps:
- Create storage utilities for Functions and Events
- Create custom CRUD hooks
- Add new screens following FunctionCategories pattern
- Integrate with navigation
- Add UI enhancements (date/time pickers, filtering, search)