Kodax

مشروع عملي: Todo App متكامل — مقدمة React

مشروع Todo App متكامل

سنبني تطبيق مهام متكامل يجمع كل ما تعلمناه.

المميزات

- إضافة/حذف/تعديل المهام

- تصفية حسب الحالة

- حفظ في localStorage

- Dark/Light mode

- تصميم متجاوب

هيكل المشروع

src/
├── components/
│   ├── TodoForm.jsx
│   ├── TodoList.jsx
│   ├── TodoItem.jsx
│   └── FilterButtons.jsx
├── hooks/
│   └── useTodos.js
├── store/
│   └── todoStore.js
├── styles/
│   └── App.css
└── App.jsx

Store (Zustand)

// store/todoStore.js
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

const useTodoStore = create(
  persist(
    (set) => ({
      todos: [],
      filter: 'all', // all, active, completed
      
      addTodo: (text) => set((state) => ({
        todos: [
          ...state.todos,
          { id: Date.now(), text, completed: false }
        ]
      })),
      
      toggleTodo: (id) => set((state) => ({
        todos: state.todos.map(todo =>
          todo.id === id 
            ? { ...todo, completed: !todo.completed }
            : todo
        )
      })),
      
      deleteTodo: (id) => set((state) => ({
        todos: state.todos.filter(todo => todo.id !== id)
      })),
      
      editTodo: (id, text) => set((state) => ({
        todos: state.todos.map(todo =>
          todo.id === id ? { ...todo, text } : todo
        )
      })),
      
      setFilter: (filter) => set({ filter }),
      
      clearCompleted: () => set((state) => ({
        todos: state.todos.filter(todo => !todo.completed)
      })),
    }),
    { name: 'todo-storage' }
  )
);
// App.jsx الكامل
import { useMemo } from 'react';
import useTodoStore from './store/todoStore';
import TodoForm from './components/TodoForm';
import TodoList from './components/TodoList';
import FilterButtons from './components/FilterButtons';
import './styles/App.css';

function App() {
  const { todos, filter, addTodo, clearCompleted } = useTodoStore();
  
  const filteredTodos = useMemo(() => {
    switch (filter) {
      case 'active':
        return todos.filter(t => !t.completed);
      case 'completed':
        return todos.filter(t => t.completed);
      default:
        return todos;
    }
  }, [todos, filter]);
  
  const activeCount = todos.filter(t => !t.completed).length;
  
  return (
    <div className="app">
      <h1>قائمة المهام</h1>
      
      <TodoForm onAdd={addTodo} />
      
      <FilterButtons 
        current={filter} 
        counts={{
          all: todos.length,
          active: activeCount,
          completed: todos.length - activeCount
        }}
      />
      
      <TodoList todos={filteredTodos} />
      
      <footer>
        <span>{activeCount} مهام متبقية</span>
        <button onClick={clearCompleted}>
          حذف المكتملة
        </button>
      </footer>
    </div>
  );
}

export default App;
اختبر فهمك