6 changed files with 302 additions and 165 deletions
@ -0,0 +1,183 @@ |
|||
import React, {useState } from 'react'; |
|||
import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Divider, List, ListItem, TextField, Typography } from '@mui/material'; |
|||
import { DatePicker } from '@mui/x-date-pickers'; |
|||
import DeleteOutlineRoundedIcon from '@mui/icons-material/DeleteOutlineRounded'; |
|||
import EditRoundedIcon from '@mui/icons-material/EditRounded'; |
|||
import { useLocalStorage } from '../hooks/useLocalStorage'; |
|||
|
|||
type Todo = { |
|||
id: string, |
|||
name: string, |
|||
done: boolean, |
|||
description: string, |
|||
from?: string, |
|||
to?: string, |
|||
} |
|||
|
|||
|
|||
function TodoItem({todo}: {todo: Todo}){ |
|||
return ( |
|||
<ListItem> |
|||
<Box sx={{display: "flex", flexDirection: "column"}}> |
|||
<Typography variant="h5">{todo.name}</Typography> |
|||
{todo.description && <span>Description: {todo.description}</span>} |
|||
{todo.from && <span>From: {(new Date(todo.from)).toLocaleDateString()}</span>} |
|||
{todo.to && <span>To: {(new Date(todo.to)).toLocaleDateString()}</span>} |
|||
</Box> |
|||
</ListItem> |
|||
) |
|||
} |
|||
|
|||
function ChangeTodo({todo, setTodo, handleCancel}: {todo: Todo, setTodo: (todo: Todo) => void, handleCancel: () => void}){ |
|||
|
|||
const [name, setName] = React.useState<string>(todo.name) |
|||
const handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => { |
|||
setName(event.target.value); |
|||
}; |
|||
|
|||
const [id, setId] = React.useState<string>(todo.id) |
|||
|
|||
const [description, setDescription] = React.useState<string>(todo.description) |
|||
const handleDescChange = (event: React.ChangeEvent<HTMLInputElement>) => { |
|||
setDescription(event.target.value); |
|||
}; |
|||
|
|||
const [done, setDone] = React.useState<boolean>(todo.done) |
|||
|
|||
const [from, setFrom] = React.useState<Date | null>(todo.from ? new Date(todo.from) : null); |
|||
const handleFrom = (newValue: Date | null) => { |
|||
setFrom(newValue); |
|||
}; |
|||
|
|||
const [to, setTo] = React.useState<Date | null>(todo.to ? new Date(todo.to) : null); |
|||
|
|||
const handleTo = (newValue: Date | null) => { |
|||
setTo(newValue); |
|||
}; |
|||
|
|||
const saveTodo=() => { |
|||
const newtodo = { |
|||
name: name, |
|||
id: id === "" ? Math.random().toString() : id, |
|||
done: done, |
|||
description: description, |
|||
to: to?.toISOString(), |
|||
from: from?.toISOString() |
|||
}; |
|||
setTodo(newtodo); |
|||
} |
|||
|
|||
return ( |
|||
<> |
|||
<DialogContent> |
|||
<Box component="form" |
|||
sx={{ |
|||
'& > :not(style)': { m: 2, width: '50ch' }, |
|||
}}> |
|||
<TextField |
|||
id="name" |
|||
value={name} |
|||
label="Name" |
|||
onChange={handleNameChange} |
|||
/> |
|||
<TextField |
|||
id="description" |
|||
value={description} |
|||
label="Description" |
|||
onChange={handleDescChange} |
|||
/> |
|||
<DatePicker |
|||
mask={'__.__.____'} |
|||
label="From:" |
|||
value={from} |
|||
onChange={handleFrom} |
|||
renderInput={(params: any) => <TextField {...params} />} |
|||
/> |
|||
<DatePicker |
|||
mask={'__.__.____'} |
|||
label="To:" |
|||
value={to} |
|||
onChange={handleTo} |
|||
renderInput={(params: any) => <TextField {...params} />} |
|||
/> |
|||
</Box> |
|||
</DialogContent> |
|||
<DialogActions> |
|||
<Button onClick={handleCancel}>Cancel</Button> |
|||
<Button onClick={saveTodo}>Save</Button> |
|||
</DialogActions> |
|||
</> |
|||
) |
|||
} |
|||
|
|||
export function Todos({style}: {style?: any}) { |
|||
const [todos, setTodos] = useLocalStorage<Todo[]>("todos",[]); |
|||
const setDone=(i: number,todo: Todo, done: boolean) => |
|||
setTodos([...todos.slice(0,i), |
|||
{name: todo.name, id: todo.id, done: done, description: todo.description, to: todo.to, from: todo.from}, |
|||
...todos.slice(i+1)]); |
|||
|
|||
const deleteTodo=(i: number,todo: Todo) => |
|||
setTodos([...todos.slice(0,i), |
|||
...todos.slice(i+1)]); |
|||
|
|||
const setTodo= (todo: Todo) => { |
|||
handleClose(); |
|||
setTodos([...todos, todo]); |
|||
} |
|||
|
|||
const [open, setOpen] = useState(false); |
|||
const handleClickOpen = () => { |
|||
setOpen(true); |
|||
}; |
|||
const handleClose = () => { |
|||
setOpen(false); |
|||
}; |
|||
|
|||
const [open2, setOpen2] = useState(false); |
|||
const [edit, setEdit] = useState<Todo>({name: "", description: "", done: false, id: ""}); |
|||
const [editI, setEditI] = useState<number>(0); |
|||
const handleClickOpen2 = (todo: Todo, i: number) => { |
|||
setOpen2(true); |
|||
setEdit(todo); |
|||
setEditI(i); |
|||
}; |
|||
const handleClose2 = () => { |
|||
setOpen2(false); |
|||
}; |
|||
|
|||
const editTodo= (todo: Todo) => { |
|||
handleClose2(); |
|||
setTodos([...todos.slice(0,editI), |
|||
todo, |
|||
...todos.slice(editI+1)]); |
|||
} |
|||
|
|||
return ( |
|||
<div style={{...style, textAlign: "left"}}> |
|||
<Typography variant="h3">ToDo's</Typography> |
|||
<Button onClick={handleClickOpen}>Add Todo</Button> |
|||
<List> |
|||
{todos.map((todo, i) => |
|||
<> |
|||
<Box sx={{display: "flex", flexDirection: "columns"}}> |
|||
<TodoItem key={todo.id} todo={todo}/> |
|||
<input type="checkbox" checked={todo.done} onChange={(e) => setDone(i, todo,e.target.checked)}></input> |
|||
<Button onClick={() => handleClickOpen2(todo, i)}><EditRoundedIcon/></Button> |
|||
<Button onClick={() => deleteTodo}><DeleteOutlineRoundedIcon/></Button> |
|||
</Box> |
|||
{(i + 1) < todos.length && <Divider/>} |
|||
</> |
|||
)} |
|||
</List> |
|||
<Dialog open={open} onClose={handleClose}> |
|||
<DialogTitle>New Todo</DialogTitle> |
|||
<ChangeTodo todo={{id: "", name: "", done: false, description: ""}} setTodo={setTodo} handleCancel={handleClose}></ChangeTodo> |
|||
</Dialog> |
|||
<Dialog open={open2} onClose={handleClose2}> |
|||
<DialogTitle>Edit Todo</DialogTitle> |
|||
<ChangeTodo todo={edit} setTodo={editTodo} handleCancel={handleClose2}></ChangeTodo> |
|||
</Dialog> |
|||
</div> |
|||
) |
|||
} |
@ -0,0 +1,15 @@ |
|||
import React, { useEffect, useState } from 'react'; |
|||
|
|||
function useLocalStorage<T>(storageKey: string, fallbackState: T): [T, (val: T) => void] { |
|||
const [value, setValue] = useState( |
|||
JSON.parse(localStorage.getItem(storageKey)!) ?? fallbackState |
|||
); |
|||
|
|||
useEffect(() => { |
|||
localStorage.setItem(storageKey, JSON.stringify(value)) |
|||
}, [value, storageKey]); |
|||
|
|||
return [value, setValue]; |
|||
} |
|||
|
|||
export {useLocalStorage} |
Loading…
Reference in new issue