Last active
January 1, 2025 17:12
-
-
Save nahidmbstu/2e85c2c61396b5374f959e76c03d9b9a to your computer and use it in GitHub Desktop.
react native muti-level task app.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import React, { useState } from "react"; | |
| import { | |
| View, | |
| Text, | |
| TextInput, | |
| Button, | |
| FlatList, | |
| TouchableOpacity, | |
| StyleSheet, | |
| } from "react-native"; | |
| import { MaterialIcons } from "@expo/vector-icons"; // Install via `expo install @expo/vector-icons` | |
| export default function App() { | |
| const [tasks, setTasks] = useState([]); // Stores tasks | |
| const [inputValue, setInputValue] = useState(""); // Stores text input | |
| const [selectedTask, setSelectedTask] = useState(null); // Tracks selected parent task | |
| // Function to add a task or subtask | |
| const addTask = () => { | |
| if (inputValue.trim() === "") return; // Prevent empty tasks | |
| if (selectedTask) { | |
| // Add as a subtask to the selected task | |
| const addSubtask = (taskList) => | |
| taskList.map((task) => { | |
| if (task.id === selectedTask) { | |
| return { | |
| ...task, | |
| subtasks: [ | |
| ...task.subtasks, | |
| { id: Date.now(), title: inputValue, subtasks: [], done: false }, | |
| ], | |
| }; | |
| } | |
| return { | |
| ...task, | |
| subtasks: addSubtask(task.subtasks), | |
| }; | |
| }); | |
| setTasks(addSubtask(tasks)); | |
| setSelectedTask(null); // Clear selection | |
| } else { | |
| // Add as a root-level task | |
| setTasks([ | |
| ...tasks, | |
| { id: Date.now(), title: inputValue, subtasks: [], done: false }, | |
| ]); | |
| } | |
| setInputValue(""); // Clear input | |
| }; | |
| // Function to toggle task as done | |
| const toggleDone = (id) => { | |
| const toggleTaskStatus = (taskList) => | |
| taskList.map((task) => { | |
| if (task.id === id) { | |
| return { ...task, done: !task.done }; | |
| } | |
| return { | |
| ...task, | |
| subtasks: toggleTaskStatus(task.subtasks), | |
| }; | |
| }); | |
| setTasks(toggleTaskStatus(tasks)); | |
| }; | |
| // Recursive component to render tasks and subtasks | |
| const TaskItem = ({ task }) => { | |
| return ( | |
| <View style={styles.taskContainer}> | |
| <TouchableOpacity | |
| onPress={() => setSelectedTask(task.id)} | |
| style={[ | |
| styles.task, | |
| selectedTask === task.id && styles.selectedTask, | |
| task.done && styles.doneTask, // Apply "done" style if task is completed | |
| ]} | |
| > | |
| <Text style={task.done ? styles.doneText : undefined}>{task.title}</Text> | |
| <TouchableOpacity onPress={() => toggleDone(task.id)}> | |
| <MaterialIcons | |
| name={task.done ? "check-box" : "check-box-outline-blank"} | |
| size={24} | |
| color="green" | |
| style={styles.doneIcon} | |
| /> | |
| </TouchableOpacity> | |
| </TouchableOpacity> | |
| {/* Render subtasks */} | |
| <FlatList | |
| data={task.subtasks} | |
| keyExtractor={(item) => item.id.toString()} | |
| renderItem={({ item }) => <TaskItem task={item} />} | |
| /> | |
| </View> | |
| ); | |
| }; | |
| return ( | |
| <View style={styles.container}> | |
| {/* Input and Add Button */} | |
| <View style={styles.inputContainer}> | |
| <TextInput | |
| style={styles.input} | |
| placeholder="Enter task or subtask" | |
| value={inputValue} | |
| onChangeText={setInputValue} | |
| /> | |
| <Button title="Add" onPress={addTask} /> | |
| </View> | |
| {/* Task List */} | |
| <FlatList | |
| data={tasks} | |
| keyExtractor={(item) => item.id.toString()} | |
| renderItem={({ item }) => <TaskItem task={item} />} | |
| /> | |
| </View> | |
| ); | |
| } | |
| const styles = StyleSheet.create({ | |
| container: { | |
| flex: 1, | |
| padding: 20, | |
| }, | |
| inputContainer: { | |
| flexDirection: "row", | |
| marginBottom: 20, | |
| }, | |
| input: { | |
| flex: 1, | |
| borderWidth: 1, | |
| borderColor: "#ccc", | |
| padding: 10, | |
| marginRight: 10, | |
| borderRadius: 5, | |
| }, | |
| taskContainer: { | |
| marginLeft: 20, | |
| marginTop: 10, | |
| flexDirection: "column", | |
| }, | |
| task: { | |
| padding: 10, | |
| backgroundColor: "#f9f9f9", | |
| borderRadius: 5, | |
| borderWidth: 1, | |
| borderColor: "#ddd", | |
| flexDirection: "row", | |
| justifyContent: "space-between", | |
| alignItems: "center", | |
| }, | |
| selectedTask: { | |
| backgroundColor: "#d3f4ff", | |
| borderColor: "#87ceeb", | |
| }, | |
| doneTask: { | |
| backgroundColor: "#e0ffe0", | |
| borderColor: "#87ff87", | |
| }, | |
| doneText: { | |
| textDecorationLine: "line-through", | |
| color: "#888", | |
| }, | |
| doneIcon: { | |
| marginLeft: 10, | |
| }, | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment

very useful for understanding recursion and its application in real apps.