TaskPlanner is a React Native mobile application designed to help users efficiently manage and organize their tasks with advanced filtering, sorting, and notification capabilities. The app supports both local storage and cloud-based data synchronization via Firebase.
Users often struggle with task organization across multiple devices and need timely reminders for upcoming deadlines. TaskPlanner solves this by providing:
- Flexible task storage (local or cloud-based)
- Automatic reminders with customizable advance notice
- Smart sorting and filtering by due date, completion status, category, and recurrence
- Dark mode support for comfortable all-day usage
- Students and professionals managing daily tasks
- Users who prefer simple, intuitive interfaces
- Power users who want advanced filtering and recurring task management
- Users who value both offline availability (local storage) and cloud synchronization options
- Task Management: Create, edit, delete, and mark tasks as complete
- Recurring Tasks: Set up tasks that repeat daily, weekly, monthly, or yearly with custom intervals
- Smart Notifications: Configurable push notifications (1–30 days in advance)
- Dual Storage Modes: Local AsyncStorage or cloud Firebase Firestore
- Advanced Filtering: Sort by All, Due Date, Completed, Category, or Repeating status
- Search Functionality: Quick search across task titles and categories
- ✅ Dark Mode: Theme toggle with persistent preference storage
- ✅ Date Picker UI: Native date pickers for iOS and Android
TaskPlanner/├── components/│ ├── SearchBar.js # Search input component│ ├── TaskManagement/│ │ ├── AddTaskButton.js # Floating action button│ │ ├── AddTaskModal.js # New task creation modal│ │ ├── EditTaskModal.js # Task editing modal│ │ ├── RepeatingModal.js # Recurring task configuration│ │ └── TaskItem.js # Individual task display card│ └── UI/│ ├── Button.js # Reusable button component│ ├── DatePickerButton.js # Date picker wrapper│ ├── InputField.js # Text input wrapper│ ├── InputPasswordField.js # Secure password input│ └── LabeledInput.js # Labeled input with date picker├── context/│ └── ThemeContext.js # Global theme (dark/light mode)├── hooks/│ ├── useModalDimensions.js # Modal sizing logic│ ├── useNotifications.js # Push notification management│ ├── useNotificationPreference.js # Notification settings│ ├── useLogout.js # Logout state and navigation│ ├── useSignup.js # Registration logic│ ├── useSortAndFilter.js # Task sorting/filtering│ ├── useStorageMethod.js # Storage method selection (local vs cloud)│ ├── useTaskForm.js # Task form state management│ └── useTasks.js # Core task CRUD operations├── screens/│ ├── FirstTimeScreen.js # App initialization/onboarding│ ├── LoginScreen.js # User authentication│ ├── MainScreen.js # Primary task list view│ ├── SettingScreen.js # Settings (theme, notifications, logout)│ ├── SignupScreen.js # User registration│ └── UserInfoScreen.js # User profile management├── services/│ └── NotificationService.js # Expo Notifications API wrapper├── util/│ ├── appUtil.js # App-level utilities (userId, reset)│ ├── dateUtil.js # Date formatting and validation│ ├── notificationUtil.js # Notification preference persistence│ └── taskUtil.js # Task sorting/filtering logic├── assets/│ └── images/ # App images and icons├── App.js # App entry point with ThemeProvider├── app.config.js # Expo configuration├── app.json # App metadata├── firebaseConfig.js # Firebase initialization├── google-services.json # Android Firebase config├── index.js # React Native entry point├── package.json # Dependencies and scripts└── README.md # This file
Technology
Version
Purpose
React Native
0.81.4
Core mobile app framework
Expo
~54.0.10
Development platform and build tools
React Navigation
^7.1.17
Screen navigation and routing
Firebase
^12.5.0
Cloud authentication, Firestore database, real-time sync
AsyncStorage
^2.2.0
Local data persistence
Expo Notifications
^0.28.0
Push notifications and scheduling
Expo Device
^6.0.2
Device capability detection
React Native Modal
^14.0.0-rc.1
Modal dialogs
React Native DateTimePicker
8.4.4
Native date/time selection
React Native Vector Icons
^10.3.0
Icon library (Ionicons)
Dotenv
^17.2.3
Environment variable management
- Node.js (v16 or higher) – Download
- npm (comes with Node.js)
- Expo CLI – Install globally:
npm install -g expo-cli - EAS CLI (for building) –
npm install -g eas-cli - Android Studio or Xcode (for emulators)
- Android: Install Android Studio and create an AVD (Android Virtual Device)
- iOS (macOS only): Install Xcode from App Store, then run
xcode-select --install
-
Clone the repository (or navigate to the project folder):
cd "path/to/TaskPlanner"
-
Install dependencies:
npm install
-
Set up environment variables:
-
Copy
.env.exampleto.env:cp .env.example .env
-
Update
.envwith your Firebase credentials (see Backend / Cloud Setup below)
-
-
Verify installation:
npm list expoexpo whoami
-
Install the Expo Go app on your physical iOS/Android device
-
Start the development server:
npm start
-
Scan the QR code with your device camera or Expo Go app
-
Open Android Studio and launch an AVD
-
Run:
npm run android
-
Start the development server:
npm start
-
Press
iin the terminal, or run:npm run ios
npm run webNote: Some native features (notifications, device APIs) won't work in web.
Create a .env file at the project root with the following structure:
# Firebase ConfigurationEXPO_PUBLIC_FIREBASE_API_KEY=your_api_key_hereEXPO_PUBLIC_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.comEXPO_PUBLIC_FIREBASE_PROJECT_ID=your_project_idEXPO_PUBLIC_FIREBASE_STORAGE_BUCKET=your_project.appspot.comEXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_sender_idEXPO_PUBLIC_FIREBASE_APP_ID=your_app_idEXPO_PUBLIC_FIREBASE_MEASUREMENT_ID=your_measurement_idRefer to .env.example in the repo for a complete template.
TaskPlanner uses Firebase for cloud storage and authentication. Follow these steps to set up your Firebase project:
- Go to Firebase Console
- Click "Add Project"
- Enter project name and enable/disable analytics as desired
- Create the project
- In Firebase Console, go to Build > Authentication
- Click "Get Started"
- Enable Email/Password authentication method:
- Enable "Email/Password"
- Save
- Go to Build > Firestore Database
- Click "Create Database"
- Choose region (e.g.,
us-central1) - Select "Start in test mode" (for development; use security rules for production)
- Create database
The following collections are used in TaskPlanner:
Collection: tasks
{ id: "doc_id", userId: "user_uid", title: "Task name", category: "Work/Personal/etc", completed: false, dueBy: "2025-12-25T00:00:00.000Z", // ISO string repeating: { type: "Day/Week/Month/Year", interval: 1, startDate: Timestamp, endDate: Timestamp // null if no end date }, createdAt: Timestamp}Collection: users (optional, for profile data)
{ uid: "user_uid", email: "user@example.com", displayName: "User Name", createdAt: Timestamp}Replace the default security rules with:
rules_version = '2';service cloud.firestore { match /databases/{database}/documents { // Allow read/write for tasks owned by authenticated users match /tasks/{document=**} { allow read, write: if request.auth != null && request.resource.data.userId == request.auth.uid; } // Allow read/write for user's own profile match /users/{uid} { allow read, write: if request.auth != null && request.auth.uid == uid; } }}- Go to Project Settings > Your Apps
- Select your app or create a new one
- Copy the config object
- Add values to your
.envfile
- Download
google-services.jsonfrom Firebase Console - Place it in the project root:
google-services.json
Manages all task CRUD operations with dual storage (local + Firebase).
-
Method: POST (conceptually)
-
Parameters:
{ title: string, category: string, completed: boolean, dueBy: ISO string | null, repeating: { type, interval, startDate, endDate } | null}
-
Response: Adds task to state and storage; returns void
-
Example Usage:
const { handleAddTask } = useTasks(userId);handleAddTask({ title: "Buy groceries", category: "Personal", completed: false, dueBy: "2025-12-20T00:00:00.000Z", repeating: null});
-
Method: PUT (conceptually)
-
Parameters: Complete task object with
id -
Response: Updates task in state and storage
-
Example Usage:
handleSaveTask({ id: "task_123", title: "Updated task", category: "Work", completed: true, dueBy: null, repeating: null, userId: "user_uid"});
-
Method: DELETE (conceptually)
-
Parameters: Task object with
idanduserId -
Response: Boolean (true = success, false = failure)
-
Error Handling: Logs errors to console; returns false on failure
-
Example Usage:
const success = await handleDeleteTask(taskObject);if (success) console.log("Task deleted");
Manages scheduling and rescheduling notifications.
- Method: Async function
- Parameters: None (uses internal tasks state)
- Response: Returns void; schedules notifications via Expo Notifications API
- Error Handling: Catches and logs errors
- Triggered on: App load, task changes, notification preference changes
-
Method: Async function
-
Parameters:
daysInAdvance(1–30) -
Response: Cancels all notifications and reschedules with new preference
-
Example Usage:
const { updateNotificationPreference } = useNotifications(tasks);await updateNotificationPreference(5); // Notify 5 days before
Filters and sorts tasks based on selected criteria.
- Method: Cycles through sort criteria
- Criteria Order: All → Due Date → Completed → Category → Repeating → All
- Returns: void; updates internal state
-
Type: Array of tasks
-
Filtering: Combines sort criteria + search query
-
Example Response:
[ { id: "task_1", title: "Buy milk", category: "Shopping", completed: false, dueBy: "2025-12-10T00:00:00.000Z", repeating: null }]
import { addDoc, collection, Timestamp } from "firebase/firestore";import { db } from "./firebaseConfig";const docRef = await addDoc(collection(db, "tasks"), { userId: "user_uid", title: "New Task", category: "Work", completed: false, dueBy: "2025-12-20T00:00:00.000Z", repeating: { type: "Day", interval: 1, startDate: Timestamp.now(), endDate: null }, createdAt: Timestamp.now()});console.log("Task added with ID:", docRef.id);import { getDocs, collection, query, where } from "firebase/firestore";const q = query(collection(db, "tasks"), where("userId", "==", "user_uid"));const snapshot = await getDocs(q);const tasks = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data()}));import { doc, updateDoc } from "firebase/firestore";const taskRef = doc(db, "tasks", "task_123");await updateDoc(taskRef, { title: "Updated title", completed: true});import { doc, deleteDoc } from "firebase/firestore";const taskRef = doc(db, "tasks", "task_123");await deleteDoc(taskRef);Purpose: Notify users of upcoming task deadlines
Implementation:
- File:
services/NotificationService.js,hooks/useNotifications.js - Libraries:
expo-notifications,expo-device - Features:
- Request user notification permissions
- Schedule notifications at specific times (8 AM on notification day)
- Cancel individual or all notifications
- Retrieve list of scheduled notifications
Integration Steps:
- Request notification permissions on first app load
- When a task is created/updated, schedule notification using
scheduleNotification() - When notification preference changes, reschedule all notifications
- When task is marked complete or deleted, cancel its notification
Testing:
- iOS: Use Xcode Simulator → Debug → Simulate Background Fetch
- Android: Use ADB to send test notifications or use logcat
- Real Device: Install app, create task with due date, wait for scheduled time
Limitations:
- Background notifications only work on physical devices (not simulators in some cases)
- iOS requires user to enable notifications in system settings
- Android 12+ requires app-specific permission
Purpose: Allow users to select dates for tasks and recurring patterns
Implementation:
- File:
components/UI/DatePickerButton.js,components/UI/LabeledInput.js - Library:
@react-native-community/datetimepicker - Features:
- Native iOS spinner and Android calendar UI
- Configurable date range
- Automatic timezone handling
Integration:
- Used in AddTaskModal, EditTaskModal, and RepeatingModal
- Displays formatted date string on button
- On selection, calls
onChange()callback with selected Date object
Testing:
- iOS Simulator: Tap date field → spinner appears
- Android Emulator: Tap date field → calendar appears
- Verify selected date is formatted and displayed correctly
Purpose: Store tasks and settings locally without internet
Implementation:
- File:
hooks/useTasks.js,hooks/useTheme.js, various utility files - Library:
@react-native-async-storage/async-storage - Stored Data:
tasks- JSON array of task objectsdarkMode- Boolean theme preferenceuserChoice- Storage method preference ("local" or "cloud")notificationPreference- Days in advance for notifications- Various authentication tokens
Integration:
import AsyncStorage from '@react-native-async-storage/async-storage';// Saveawait AsyncStorage.setItem('tasks', JSON.stringify(taskArray));// Loadconst storedTasks = await AsyncStorage.getItem('tasks');const parsedTasks = JSON.parse(storedTasks);Testing:
- Create/edit tasks in local storage mode
- Restart app → data persists
- Check device file system or Android Studio's Device File Explorer
Purpose: Provide comfortable viewing in low-light environments
Implementation:
- File:
context/ThemeContext.js - Features:
- Toggle between light and dark modes
- Persistent theme preference
- Global color scheme (background, text, surface, border colors)
Integration:
- ThemeProvider wraps entire app in
App.js - All components use
useTheme()hook for color values - Theme persists via AsyncStorage
Testing:
- Toggle dark mode in Settings screen
- Verify all UI elements change color appropriately
- Restart app → theme preference maintained
Purpose: Detect device capabilities (e.g., whether notifications work)
Implementation:
- File:
services/NotificationService.js - Library:
expo-device - Usage: Check if running on physical device vs simulator
Example:
import * as Device from 'expo-device';if (!Device.isDevice) { console.log('Notifications only work on physical devices'); return false;}Purpose: Handle Android back button and screen transitions
Implementation:
- Library:
@react-navigation/native - File: All screen components
- Features:
- Stack navigation for screen transitions
- Android back button handling
- Gesture-based back on iOS
Testing:
- Android: Press physical back button → previous screen
- iOS: Swipe from left edge → previous screen