Browse Source

Have dinos, subtodos, migrate to react 17

master
Maya Herrscher 3 years ago
parent
commit
096502e80e
  1. 4395
      package-lock.json
  2. 10
      package.json
  3. 32
      src/components/Dinos.tsx
  4. 148
      src/components/Todos.tsx
  5. 11
      src/index.tsx

4395
package-lock.json

File diff suppressed because it is too large

10
package.json

@ -10,16 +10,16 @@
"@mui/material": "^5.6.2", "@mui/material": "^5.6.2",
"@mui/x-date-pickers": "^5.0.0-alpha.1", "@mui/x-date-pickers": "^5.0.0-alpha.1",
"@testing-library/jest-dom": "^5.16.4", "@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.1.1", "@testing-library/react": "^12.1.1",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^12.5.0",
"@types/jest": "^27.4.1", "@types/jest": "^27.4.1",
"@types/node": "^16.11.27", "@types/node": "^16.11.27",
"@types/react": "^18.0.6", "@types/react": "^18.0.6",
"@types/react-dom": "^18.0.2", "@types/react-dom": "^18.0.2",
"date-fns": "^2.28.0", "date-fns": "^2.28.0",
"dayjs": "^1.11.1", "react": "^17.0.0",
"react": "^18.0.0", "react-beautiful-dnd": "^13.1.0",
"react-dom": "^18.0.0", "react-dom": "^17.0.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"typescript": "^4.6.3", "typescript": "^4.6.3",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"

32
src/components/Dinos.tsx

@ -1,5 +1,5 @@
import React, {useState } from 'react'; import React, {useState } from 'react';
import { Box, Button, Card, CardActions, CardContent, Dialog, DialogActions, DialogContent, DialogTitle, Tab, Tabs, TextField, Typography } from '@mui/material'; import { Box, Button, Card, CardActions, CardContent, Dialog, DialogActions, DialogContent, DialogTitle, Tab, Tabs, TextField, Tooltip, Typography } from '@mui/material';
import { DatePicker } from '@mui/x-date-pickers'; import { DatePicker } from '@mui/x-date-pickers';
import DeleteOutlineRoundedIcon from '@mui/icons-material/DeleteOutlineRounded'; import DeleteOutlineRoundedIcon from '@mui/icons-material/DeleteOutlineRounded';
import EditRoundedIcon from '@mui/icons-material/EditRounded'; import EditRoundedIcon from '@mui/icons-material/EditRounded';
@ -47,8 +47,8 @@ function ShowDino({dino}: {dino: Dino}){
<Box sx={{display: "flex", flexDirection: "column", lineHeight: "2"}}> <Box sx={{display: "flex", flexDirection: "column", lineHeight: "2"}}>
<Typography variant='h3'>{dino.name} {dino.snames && dino.snames} {dino.surname}</Typography> <Typography variant='h3'>{dino.name} {dino.snames && dino.snames} {dino.surname}</Typography>
{dino.description && <span>{dino.description}</span>} {dino.description && <span>{dino.description}</span>}
{dino.birthday && <span><CakeRoundedIcon fontSize="small"/> {(new Date(dino.birthday)).toLocaleDateString()}</span>} {dino.birthday && <span><Tooltip title="Birthday"><CakeRoundedIcon fontSize="small"/></Tooltip> {(new Date(dino.birthday)).toLocaleDateString()}</span>}
{dino.last && <span><EventRoundedIcon fontSize="small"/> {(new Date(dino.last)).toLocaleDateString()}</span>} {dino.last && <span><Tooltip title="Last Met"><EventRoundedIcon fontSize="small"/></Tooltip> {(new Date(dino.last)).toLocaleDateString()}</span>}
</Box> </Box>
</CardContent> </CardContent>
) )
@ -63,7 +63,7 @@ function ChangeDino({dino, setDino, handleCancel}: {dino: Dino, setDino: (dino:
const [birthday, setBirthday] = React.useState<Date | null>(dino.birthday ? new Date(dino.birthday) : null); const [birthday, setBirthday] = React.useState<Date | null>(dino.birthday ? new Date(dino.birthday) : null);
const [last, setLast] = React.useState<Date | null>(dino.last ? new Date(dino.last) : null); const [last, setLast] = React.useState<Date | null>(dino.last ? new Date(dino.last) : null);
const saveTodo=() => { const saveDino=() => {
const newdino = { const newdino = {
name: name, name: name,
snames: snames, snames: snames,
@ -77,9 +77,8 @@ function ChangeDino({dino, setDino, handleCancel}: {dino: Dino, setDino: (dino:
} }
return ( return (
<> <Box component="form" onSubmit={(e: any) => {e.preventDefault(); saveDino();}}>
<DialogContent> <DialogContent
<Box component="form"
sx={{ sx={{
'& > :not(style)': { m: 2, width: '50ch' }, '& > :not(style)': { m: 2, width: '50ch' },
}}> }}>
@ -122,13 +121,12 @@ function ChangeDino({dino, setDino, handleCancel}: {dino: Dino, setDino: (dino:
onChange={e =>setLast(e)} onChange={e =>setLast(e)}
renderInput={(params: any) => <TextField {...params} />} renderInput={(params: any) => <TextField {...params} />}
/> />
</Box>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={handleCancel}>Cancel</Button> <Button onClick={handleCancel}>Cancel</Button>
<Button onClick={saveTodo}>Save</Button> <Button type="submit">Save</Button>
</DialogActions> </DialogActions>
</> </Box>
) )
} }
export function Dinos(){ export function Dinos(){
@ -195,20 +193,24 @@ return(
<Card sx={{minHeight: "500px", minWidth: "1000px"}}> <Card sx={{minHeight: "500px", minWidth: "1000px"}}>
<ShowDino dino={dino}/> <ShowDino dino={dino}/>
<CardActions> <CardActions>
<Button onClick={() => handleClickOpen2(dino, i)}><EditRoundedIcon/></Button> <Tooltip title="Edit Dino">
<Button onClick={() => deleteDino(i)}><DeleteOutlineRoundedIcon/></Button> <Button onClick={() => handleClickOpen2(dino, i)}><EditRoundedIcon/></Button>
</Tooltip>
<Tooltip title="Delete Dino">
<Button onClick={() => deleteDino(i)}><DeleteOutlineRoundedIcon/></Button>
</Tooltip>
</CardActions> </CardActions>
</Card> </Card>
</Box> </Box>
</TabPanel> </TabPanel>
)} )}
<Dialog open={open} onClose={handleClose}> <Dialog open={open} onClose={handleClose} disableRestoreFocus>
<DialogTitle>New Dino</DialogTitle> <DialogTitle>New Dino</DialogTitle>
<ChangeDino dino={{id: "", name: "", surname: "", description: "", snames: ""}} setDino={setDino} handleCancel={handleClose}></ChangeDino> <ChangeDino dino={{id: "", name: "", surname: "", description: "", snames: ""}} setDino={setDino} handleCancel={handleClose}></ChangeDino>
</Dialog> </Dialog>
<Dialog open={open2} onClose={handleClose2}> <Dialog open={open2} onClose={handleClose2} disableRestoreFocus>
<DialogTitle>Edit Dino</DialogTitle> <DialogTitle>Edit Dino</DialogTitle>
<ChangeDino dino={edit} setDino={editDino} handleCancel={handleClose2}></ChangeDino> <ChangeDino dino={edit} setDino={editDino} handleCancel={handleClose2}></ChangeDino>
</Dialog> </Dialog>
</Box> </Box>
</div> </div>

148
src/components/Todos.tsx

@ -1,10 +1,20 @@
import React, {useState } from 'react'; import React, {useState } from 'react';
import { Box, Button, Checkbox, Dialog, DialogActions, DialogContent, DialogTitle, Divider, List, ListItem, TextField, Typography } from '@mui/material'; import { Box, Button, Checkbox, Dialog, DialogActions, DialogContent, DialogTitle, Divider, List, ListItem, TextField, Tooltip, Typography } from '@mui/material';
import { DatePicker } from '@mui/x-date-pickers'; import { DatePicker } from '@mui/x-date-pickers';
import DeleteOutlineRoundedIcon from '@mui/icons-material/DeleteOutlineRounded'; import DeleteOutlineRoundedIcon from '@mui/icons-material/DeleteOutlineRounded';
import EditRoundedIcon from '@mui/icons-material/EditRounded'; import EditRoundedIcon from '@mui/icons-material/EditRounded';
import AddTaskRoundedIcon from '@mui/icons-material/AddTaskRounded';
import { useLocalStorage } from '../hooks/useLocalStorage'; import { useLocalStorage } from '../hooks/useLocalStorage';
type Subtodo = {
id: string,
name: string,
done: boolean,
description: string,
from?: string,
to?: string,
}
type Todo = { type Todo = {
id: string, id: string,
name: string, name: string,
@ -12,15 +22,27 @@ type Todo = {
description: string, description: string,
from?: string, from?: string,
to?: string, to?: string,
subs?: Subtodo[]
} }
function todoToSubtodo({todo}: {todo: Todo}) {
const subtodo = {
name: todo.name,
id: todo.id,
done: todo.done,
description: todo.description,
from: todo.from,
to: todo.to
};
return (subtodo)
}
function TodoItem({todo}: {todo: Todo}){ function TodoItem({todo}: {todo: Subtodo}){
return ( return (
<ListItem> <ListItem>
<Box sx={{display: "flex", flexDirection: "column"}}> <Box sx={{display: "flex", flexDirection: "column"}}>
<Typography variant="h5">{todo.name}</Typography> <Typography variant="h5">{todo.name}</Typography>
{todo.description && <span>Description: {todo.description}</span>} {todo.description && <span>{todo.description}</span>}
{todo.from && <span>From: {(new Date(todo.from)).toLocaleDateString()}</span>} {todo.from && <span>From: {(new Date(todo.from)).toLocaleDateString()}</span>}
{todo.to && <span>To: {(new Date(todo.to)).toLocaleDateString()}</span>} {todo.to && <span>To: {(new Date(todo.to)).toLocaleDateString()}</span>}
</Box> </Box>
@ -58,21 +80,21 @@ function ChangeTodo({todo, setTodo, handleCancel}: {todo: Todo, setTodo: (todo:
done: todo.done, done: todo.done,
description: description, description: description,
to: to?.toISOString(), to: to?.toISOString(),
from: from?.toISOString() from: from?.toISOString(),
subs: []
}; };
setTodo(newtodo); setTodo(newtodo);
} }
return ( return (
<> <Box component="form" onSubmit={(e: any) => {e.preventDefault(); saveTodo();}}>
<DialogContent> <DialogContent
<Box component="form"
sx={{ sx={{
'& > :not(style)': { m: 2, width: '50ch' }, '& > :not(style)': { m: 2, width: '50ch' },
}}> }}>
<TextField <TextField
autoFocus autoFocus
id="name" id={`name ${todo.id}`}
value={name} value={name}
label="Name" label="Name"
onChange={handleNameChange} onChange={handleNameChange}
@ -97,13 +119,12 @@ function ChangeTodo({todo, setTodo, handleCancel}: {todo: Todo, setTodo: (todo:
onChange={handleTo} onChange={handleTo}
renderInput={(params: any) => <TextField {...params} />} renderInput={(params: any) => <TextField {...params} />}
/> />
</Box>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={handleCancel}>Cancel</Button> <Button onClick={handleCancel}>Cancel</Button>
<Button onClick={saveTodo}>Save</Button> <Button type="submit">Save</Button>
</DialogActions> </DialogActions>
</> </Box>
) )
} }
@ -111,9 +132,25 @@ export function Todos({style}: {style?: any}) {
const [todos, setTodos] = useLocalStorage<Todo[]>("todos",[]); const [todos, setTodos] = useLocalStorage<Todo[]>("todos",[]);
const setDone=(i: number,todo: Todo, done: boolean) => const setDone=(i: number,todo: Todo, done: boolean) =>
setTodos([...todos.slice(0,i), setTodos([...todos.slice(0,i),
{name: todo.name, id: todo.id, done: done, description: todo.description, to: todo.to, from: todo.from}, {name: todo.name, id: todo.id, done: done, description: todo.description, to: todo.to, from: todo.from, subs: todo.subs},
...todos.slice(i+1)]); ...todos.slice(i+1)]);
const setDoneSub=(i: number, j: number, stodo: Subtodo, done: boolean) => {
const todo = todos[i];
setTodos([...todos.slice(0,i),
{name: todo.name, id: todo.id, done: todo.done, description: todo.description, to: todo.to, from: todo.from,
subs: [...todo.subs!.slice(0,j),
{name: stodo.name, id: stodo.id, done: done, description: stodo.description, to: stodo.to, from: stodo.from,}
, ...todo.subs!.slice(j+1)]},
...todos.slice(i+1)]);}
const deleteSubtodo=(i: number, j: number) => {
const todo = todos[i];
setTodos([...todos.slice(0,i),
{name: todo.name, id: todo.id, done: todo.done, description: todo.description, to: todo.to, from: todo.from,
subs: [...todo.subs!.slice(0,j), ...todo.subs!.slice(j+1)]},
...todos.slice(i+1)]);}
const deleteTodo=(i: number) => const deleteTodo=(i: number) =>
setTodos([...todos.slice(0,i), setTodos([...todos.slice(0,i),
...todos.slice(i+1)]); ...todos.slice(i+1)]);
@ -132,7 +169,7 @@ const handleClose = () => {
}; };
const [open2, setOpen2] = useState(false); const [open2, setOpen2] = useState(false);
const [edit, setEdit] = useState<Todo>({name: "", description: "", done: false, id: ""}); const [edit, setEdit] = useState<Todo>({name: "", description: "", done: false, id: "", subs: []});
const [editI, setEditI] = useState<number>(0); const [editI, setEditI] = useState<number>(0);
const handleClickOpen2 = (todo: Todo, i: number) => { const handleClickOpen2 = (todo: Todo, i: number) => {
setOpen2(true); setOpen2(true);
@ -143,6 +180,30 @@ const handleClose2 = () => {
setOpen2(false); setOpen2(false);
}; };
const [open3, setOpen3] = useState(false);
const [editSub, setEditSub] = useState<Subtodo>({name: "", description: "", done: false, id: ""});
const [editJ, setEditJ] = useState<number>(0);
const handleClickOpenSubtodo = (todo: Subtodo, i: number, j: number) => {
setOpen3(true);
setEditSub(todo);
setEditI(i);
setEditJ(j > -1 ? j : todos[i].subs!.length);
};
const handleCloseSubtodo = () => {
setOpen3(false);
};
const [open4, setOpen4] = useState(false);
const handleClickOpenSubtodo2 = (todo: Subtodo, i: number, j: number) => {
setOpen4(true);
setEditSub(todo);
setEditI(i);
setEditJ(j > -1 ? j : todos[i].subs!.length);
};
const handleCloseSubtodo2 = () => {
setOpen4(false);
};
const editTodo= (todo: Todo) => { const editTodo= (todo: Todo) => {
handleClose2(); handleClose2();
setTodos([...todos.slice(0,editI), setTodos([...todos.slice(0,editI),
@ -150,6 +211,23 @@ const editTodo= (todo: Todo) => {
...todos.slice(editI+1)]); ...todos.slice(editI+1)]);
} }
const editSubtodo= (todo: Subtodo) => {
const subtodos = (typeof todos[editI].subs !== 'undefined') ? [...todos[editI].subs!.slice(0, editJ), todo, ...todos[editI].subs!.slice(editJ+1)] : [todo];
// VERY HACKY
handleCloseSubtodo();
handleCloseSubtodo2();
setTodos([...todos.slice(0,editI),
{name: todos[editI].name,
id: todos[editI].id,
description: todos[editI].description,
from: todos[editI].from,
to: todos[editI].to,
done: todos[editI].done,
subs: subtodos
},
...todos.slice(editI+1)]);
}
return ( return (
<div style={{...style, textAlign: "left"}}> <div style={{...style, textAlign: "left"}}>
<Typography variant="h3">ToDo's</Typography> <Typography variant="h3">ToDo's</Typography>
@ -160,21 +238,55 @@ const editTodo= (todo: Todo) => {
<Box sx={{display: "flex", flexDirection: "columns"}}> <Box sx={{display: "flex", flexDirection: "columns"}}>
<TodoItem key={todo.id} todo={todo}/> <TodoItem key={todo.id} todo={todo}/>
<Checkbox checked={todo.done} onChange={(e) => setDone(i, todo,e.target.checked)}></Checkbox> <Checkbox checked={todo.done} onChange={(e) => setDone(i, todo,e.target.checked)}></Checkbox>
<Button onClick={() => handleClickOpen2(todo, i)}><EditRoundedIcon/></Button> <Tooltip title="Add Subtodo">
<Button onClick={() => deleteTodo(i)}><DeleteOutlineRoundedIcon/></Button> <Button onClick={() => handleClickOpenSubtodo(todo, i,-1)}><AddTaskRoundedIcon/></Button>
</Tooltip>
<Tooltip title="Edit Todo">
<Button onClick={() => handleClickOpen2(todo, i)}><EditRoundedIcon/></Button>
</Tooltip>
<Tooltip title="Delete Todo">
<Button onClick={() => deleteTodo(i)}><DeleteOutlineRoundedIcon/></Button>
</Tooltip>
</Box> </Box>
{(todo.subs && todo.subs.length > 0) &&
<List sx={{marginLeft: "20px"}}>
<Divider/>
{todo.subs.map((stodo, j) =>
<div key={stodo.id}>
<Box sx={{display: "flex", flexDirection: "columns"}}>
<TodoItem key={todo.id} todo={stodo}/>
<Checkbox checked={stodo.done} onChange={(e) => setDoneSub(i, j, stodo,e.target.checked)}></Checkbox>
<Tooltip title="Edit Subtodo">
<Button onClick={() => handleClickOpenSubtodo2(stodo, i, j)}><EditRoundedIcon/></Button>
</Tooltip>
<Tooltip title="Delete Subtodo">
<Button onClick={() => deleteSubtodo(i,j)}><DeleteOutlineRoundedIcon/></Button>
</Tooltip>
</Box>
{(j + 1) < todo.subs!.length && <Divider/>}
</div>
)}
</List>}
{(i + 1) < todos.length && <Divider/>} {(i + 1) < todos.length && <Divider/>}
</div> </div>
)} )}
</List> </List>
<Dialog open={open} onClose={handleClose}> <Dialog open={open} onClose={handleClose} disableRestoreFocus>
<DialogTitle>New Todo</DialogTitle> <DialogTitle>New Todo</DialogTitle>
<ChangeTodo todo={{id: "", name: "", done: false, description: ""}} setTodo={setTodo} handleCancel={handleClose}></ChangeTodo> <ChangeTodo todo={{id: "", name: "", done: false, description: "", subs: []}} setTodo={setTodo} handleCancel={handleClose}></ChangeTodo>
</Dialog> </Dialog>
<Dialog open={open2} onClose={handleClose2}> <Dialog open={open2} onClose={handleClose2} disableRestoreFocus>
<DialogTitle>Edit Todo</DialogTitle> <DialogTitle>Edit Todo</DialogTitle>
<ChangeTodo todo={edit} setTodo={editTodo} handleCancel={handleClose2}></ChangeTodo> <ChangeTodo todo={edit} setTodo={editTodo} handleCancel={handleClose2}></ChangeTodo>
</Dialog> </Dialog>
<Dialog open={open3} onClose={handleCloseSubtodo} disableRestoreFocus>
<DialogTitle>New Subtodo</DialogTitle>
<ChangeTodo todo={{id: "", name: "", done: false, description: ""}} setTodo={editSubtodo} handleCancel={handleCloseSubtodo}></ChangeTodo>
</Dialog>
<Dialog open={open4} onClose={handleCloseSubtodo2} disableRestoreFocus>
<DialogTitle>Edit Subtodo</DialogTitle>
<ChangeTodo todo={{...editSub}} setTodo={editSubtodo} handleCancel={handleCloseSubtodo2}></ChangeTodo>
</Dialog>
</div> </div>
) )
} }

11
src/index.tsx

@ -1,16 +1,15 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom';
import './index.css'; import './index.css';
import App from './App'; import App from './App';
import reportWebVitals from './reportWebVitals'; import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot( const root = document.getElementById('root') as HTMLElement;
document.getElementById('root') as HTMLElement ReactDOM.render(
);
root.render(
<React.StrictMode> <React.StrictMode>
<App /> <App />
</React.StrictMode> </React.StrictMode>,
root
); );
// If you want to start measuring performance in your app, pass a function // If you want to start measuring performance in your app, pass a function

Loading…
Cancel
Save