0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TodoApp

Posted at
Todo.tsx
import { useState } from 'react';
import { Container, Button, Grid, Typography } from '@mui/material';
import ModalComponent from './Modal';
import ListComponent from './List';
import { TodoItem } from './types';
import AddIcon from '@mui/icons-material/Add';

const TodoApp = () => {
  const [todos, setTodos] = useState<TodoItem[]>([]);
  const [modalOpen, setModalOpen] = useState(false);
  const [modalData, setModalData] = useState<Partial<TodoItem>>({});

  const handleOpenModal = (item?: TodoItem) => {
    setModalData(item || {});
    setModalOpen(true);
  };

  const handleCloseModal = () => {
    setModalOpen(false);
  };

  const addTodo = (newTodo: TodoItem) => {
    setTodos([...todos, { ...newTodo, id: Date.now(), type: 'Todo' }]);
    handleCloseModal();
  };

  const updateTodo = (updatedTodo: TodoItem) => {
    setTodos(todos.map(todo => todo.id === updatedTodo.id ? updatedTodo : todo));
    handleCloseModal();
  };

  const moveTodo = (id: number, toType: 'Todo'|'Start' | 'End') => {
    setTodos(todos.map(todo => todo.id === id ? { ...todo, type: toType } : todo));
  };

  const getTodosByType = (type: 'Todo' | 'Start' | 'End') => {
    return todos.filter(todo => todo.type === type);
  };

  return (
    <Container>
      <Typography variant="h4" align="center">Todo App</Typography>
      <Button startIcon={<AddIcon />} onClick={() => handleOpenModal()}>Add Todo</Button>
      <Grid container spacing={2}>
        <Grid item xs={4}>
          <ListComponent title="Todo" items={getTodosByType('Todo')} onMove={moveTodo} onEdit={handleOpenModal} />
        </Grid>
        <Grid item xs={4}>
          <ListComponent title="Start" items={getTodosByType('Start')} onMove={moveTodo} onEdit={handleOpenModal} />
        </Grid>
        <Grid item xs={4}>
          <ListComponent title="End" items={getTodosByType('End')} onMove={moveTodo} onEdit={handleOpenModal} />
        </Grid>
      </Grid>
      <ModalComponent
        open={modalOpen}
        handleClose={handleCloseModal}
        onAdd={addTodo}
        onUpdate={updateTodo}
        modalData={modalData as TodoItem}
      />
    </Container>
  );
};

export default TodoApp;
Modal.tsx
import React, { useState, useEffect } from 'react';
import { Dialog, DialogActions, DialogContent, DialogTitle, TextField, Button } from '@mui/material';
import { TodoItem } from './types';

interface ModalComponentProps {
  open: boolean;
  handleClose: () => void;
  onAdd: (newTodo: TodoItem) => void;
  onUpdate: (updatedTodo: TodoItem) => void;
  modalData: TodoItem;
}

const ModalComponent: React.FC<ModalComponentProps> = ({ open, handleClose, onAdd, onUpdate, modalData }) => {
  const [title, setTitle] = useState<string>(modalData.title || '');
  const [details, setDetails] = useState<string>(modalData.details || '');

  useEffect(() => {
    setTitle(modalData.title || '');
    setDetails(modalData.details || '');
  }, [modalData]);

  const handleSave = () => {
    const todo = { ...modalData, title, details };
    if (modalData.id) {
      onUpdate(todo as TodoItem);
    } else {
      onAdd(todo as TodoItem);
    }
  };

  return (
    <Dialog open={open} onClose={handleClose}>
      <DialogTitle>{modalData.id ? 'Edit Todo' : 'Add Todo'}</DialogTitle>
      <DialogContent>
        <TextField
          autoFocus
          margin="dense"
          label="Title"
          type="text"
          fullWidth
          variant="standard"
          value={title}
          onChange={(e) => setTitle(e.target.value)}
        />
        <TextField
          margin="dense"
          label="Details"
          type="text"
          fullWidth
          variant="standard"
          value={details}
          onChange={(e) => setDetails(e.target.value)}
        />
      </DialogContent>
      <DialogActions>
        <Button onClick={handleClose}>Cancel</Button>
        <Button onClick={handleSave}>{modalData.id ? 'Update' : 'Add'}</Button>
      </DialogActions>
    </Dialog>
  );
};

export default ModalComponent;
List.tsx
import React from 'react';
import { List, ListItem, ListItemText, IconButton, Typography } from '@mui/material';
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import EditIcon from '@mui/icons-material/Edit';
import { TodoItem } from './types';

interface ListComponentProps {
  title: string;
  items: TodoItem[];
  onMove: (id: number, toType:'Todo' |'Start' | 'End') => void;
  onEdit: (item: TodoItem) => void;
}

const ListComponent: React.FC<ListComponentProps> = ({ title, items, onMove, onEdit }) => {
  return (
    <div>
      <Typography variant="h6">{title}</Typography>
      <List>
        {items.map(item => (
          <ListItem key={item.id} secondaryAction={
            <>
              {title === 'Todo' && <IconButton edge="end" onClick={() => onMove(item.id, 'Start')}><ArrowForwardIcon /></IconButton>}
              {title === 'Start' && (
                <>
                  <IconButton edge="end" onClick={() => onMove(item.id, 'End')}><ArrowForwardIcon /></IconButton>
                  <IconButton edge="end" onClick={() => onMove(item.id, 'Todo')}><ArrowBackIcon /></IconButton>
                </>
              )}
              {title === 'End' && <IconButton edge="end" onClick={() => onMove(item.id, 'Start')}><ArrowBackIcon /></IconButton>}
              <IconButton edge="end" onClick={() => onEdit(item)}><EditIcon /></IconButton>
            </>
          }>
            <ListItemText primary={item.title} secondary={item.details} />
          </ListItem>
        ))}
      </List>
    </div>
  );
};

export default ListComponent;
types.ts
export interface TodoItem {
  id: number;
  title: string;
  details: string;
  type: 'Todo' | 'Start' | 'End';
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?