Skip to content

Commit 95eece5

Browse files
add task dialog added
1 parent 12b59c4 commit 95eece5

File tree

3 files changed

+170
-78
lines changed

3 files changed

+170
-78
lines changed

src/app/page.tsx

Lines changed: 158 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
IconButton,
1313
Checkbox,
1414
CircularProgress,
15+
DialogContent,
16+
Stack,
1517
} from "@mui/material";
1618
import DeleteIcon from "@mui/icons-material/Delete";
1719
import Snackbar, { SnackbarCloseReason } from "@mui/material/Snackbar";
@@ -21,7 +23,10 @@ import Select from "@mui/material/Select";
2123
import MenuItem from "@mui/material/MenuItem";
2224
import Box from "@mui/material/Box";
2325
import Grid from "@mui/material/Grid2";
24-
import Divider from '@mui/material/Divider';
26+
import Divider from "@mui/material/Divider";
27+
import Dialog from "@mui/material/Dialog";
28+
import DialogTitle from "@mui/material/DialogTitle";
29+
import { format, formatDistance, formatRelative, subDays } from "date-fns";
2530

2631
interface Task {
2732
_id: string;
@@ -31,15 +36,136 @@ interface Task {
3136
priority: "Low" | "Medium" | "High";
3237
}
3338

34-
export default function Home() {
35-
const [tasks, setTasks] = useState<Task[]>([]);
36-
const [newTask, setNewTask] = useState({
39+
export interface SimpleDialogProps {
40+
open: boolean;
41+
selectedValue?: Task;
42+
onClose: (value: string) => void;
43+
}
44+
45+
function AddTaskDialog(props: SimpleDialogProps) {
46+
const { onClose, selectedValue, open } = props;
47+
48+
const newTaskProp = {
3749
title: "",
38-
dueDate: "",
50+
dueDate: new Date(),
3951
priority: "Medium",
40-
});
41-
52+
};
4253
const [loadingState, setLoadingState] = useState(false);
54+
const [newTask, setNewTask] = useState(newTaskProp);
55+
56+
const handleClose = () => {
57+
onClose("");
58+
};
59+
60+
const handleListItemClick = (value: string) => {
61+
onClose(value);
62+
};
63+
const addTask = async () => {
64+
if (!newTask.title || !newTask.dueDate) {
65+
console.error("Validation error");
66+
return;
67+
}
68+
setLoadingState(true);
69+
const res = await axios.post<Task>("/api/tasks", newTask);
70+
// setTasks([...tasks, res.data]);
71+
setNewTask(newTaskProp);
72+
// showSnackBar("Task added!");
73+
setLoadingState(false);
74+
onClose("Task added!");
75+
};
76+
return (
77+
<Dialog onClose={handleClose} open={open} maxWidth="sm" fullWidth>
78+
<DialogTitle>Add Task</DialogTitle>
79+
<Divider />
80+
<DialogContent>
81+
<TextField
82+
fullWidth
83+
label="New Task"
84+
variant="standard"
85+
value={newTask.title}
86+
onChange={(e) => setNewTask({ ...newTask, title: e.target.value })}
87+
// sx={{ mb: 2 }}
88+
/>
89+
90+
<Grid container spacing={2} mb={2}>
91+
<Grid size={6}>
92+
<TextField
93+
fullWidth
94+
type="date"
95+
size="small"
96+
value={newTask.dueDate}
97+
onChange={(e) =>
98+
setNewTask({ ...newTask, dueDate: e.target.value })
99+
}
100+
sx={{ mt: 2 }}
101+
/>
102+
</Grid>
103+
<Grid size={6}>
104+
<Select
105+
fullWidth
106+
size="small"
107+
value={newTask.priority}
108+
onChange={(e) =>
109+
setNewTask({
110+
...newTask,
111+
priority: e.target.value as "Low" | "Medium" | "High",
112+
})
113+
}
114+
sx={{ mt: 2 }}
115+
>
116+
<MenuItem value="Low">Low</MenuItem>
117+
<MenuItem value="Medium">Medium</MenuItem>
118+
<MenuItem value="High">High</MenuItem>
119+
</Select>
120+
</Grid>
121+
</Grid>
122+
123+
<Button variant="contained" onClick={addTask} loading={loadingState}>
124+
Add Task
125+
</Button>
126+
</DialogContent>
127+
</Dialog>
128+
);
129+
}
130+
131+
export function TaskHeader(props) {
132+
const [open, setOpen] = useState(false);
133+
const [selectedValue, setSelectedValue] = useState();
134+
135+
const handleClickOpen = () => {
136+
setOpen(true);
137+
};
138+
139+
const handleClose = (value: string) => {
140+
setOpen(false);
141+
props.onClose(value);
142+
};
143+
144+
return (
145+
<Stack direction="row" alignItems="center" justifyContent="space-between">
146+
<Typography variant="h5" gutterBottom>
147+
Tasks
148+
<Badge
149+
badgeContent={props?.tasks?.length}
150+
color="info"
151+
sx={{ ml: 2 }}
152+
></Badge>
153+
</Typography>
154+
<Button variant="contained" onClick={handleClickOpen}>
155+
Add Task
156+
</Button>
157+
<AddTaskDialog
158+
selectedValue={selectedValue}
159+
open={open}
160+
onClose={handleClose}
161+
/>
162+
</Stack>
163+
);
164+
}
165+
166+
export default function Home() {
167+
const [tasks, setTasks] = useState<Task[]>([]);
168+
43169
const [initialLoading, setInitialLoading] = useState(true); // Add initial loading state
44170
const [openSnackBar, setOpenSnackBar] = useState(false);
45171
const [snackBarMsg, setSnackBarMsg] = useState("");
@@ -54,25 +180,29 @@ export default function Home() {
54180
setOpenSnackBar(false);
55181
};
56182

57-
useEffect(() => {
183+
const loadList = () => {
58184
axios.get("/api/tasks").then((res) => {
59185
setTasks(res.data);
60186
setInitialLoading(false); // Set initial loading to false after tasks are loaded
61187
});
188+
}
189+
190+
useEffect(() => {
191+
loadList();
62192
}, []);
63193

64-
const addTask = async () => {
65-
if (!newTask.title || !newTask.dueDate) {
66-
console.error("Validation error");
67-
return;
68-
}
69-
setLoadingState(true);
70-
const res = await axios.post<Task>("/api/tasks", newTask);
71-
setTasks([...tasks, res.data]);
72-
setNewTask({ title: "", dueDate: "", priority: "Medium" });
73-
showSnackBar("Task added!");
74-
setLoadingState(false);
75-
};
194+
// const addTask = async () => {
195+
// if (!newTask.title || !newTask.dueDate) {
196+
// console.error("Validation error");
197+
// return;
198+
// }
199+
// setLoadingState(true);
200+
// const res = await axios.post<Task>("/api/tasks", newTask);
201+
// setTasks([...tasks, res.data]);
202+
// setNewTask({ title: "", dueDate: "", priority: "Medium" });
203+
// showSnackBar("Task added!");
204+
// setLoadingState(false);
205+
// };
76206

77207
const toggleTask = async (task: Task) => {
78208
const res = await axios.put<Task>(`/api/task?id=${task._id}`, {
@@ -100,70 +230,20 @@ export default function Home() {
100230
hideSnackBar();
101231
};
102232

233+
const onDialogClose = (msg: string) => {
234+
showSnackBar(msg);
235+
loadList();
236+
};
103237
return (
104238
<Container maxWidth="md" sx={{ mt: 1 }}>
105239
<Paper elevation={3} sx={{ p: 4 }}>
106-
<Typography variant="h5" gutterBottom>
107-
Tasks
108-
<Badge
109-
badgeContent={tasks?.length}
110-
color="info"
111-
sx={{ ml: 2 }}
112-
></Badge>
113-
</Typography>
114-
<TextField
115-
fullWidth
116-
label="New Task"
117-
variant="standard"
118-
value={newTask.title}
119-
onChange={(e) => setNewTask({ ...newTask, title: e.target.value })}
120-
// sx={{ mb: 2 }}
121-
/>
122-
<Box sx={{ flexGrow: 1, mb: 2 }}>
123-
<Grid container spacing={2}>
124-
<Grid size={3}>
125-
<TextField
126-
fullWidth
127-
type="date"
128-
size="small"
129-
value={newTask.dueDate}
130-
onChange={(e) =>
131-
setNewTask({ ...newTask, dueDate: e.target.value })
132-
}
133-
sx={{ mt: 2 }}
134-
/>
135-
</Grid>
136-
<Grid size={3}>
137-
<Select
138-
fullWidth
139-
size="small"
140-
value={newTask.priority}
141-
onChange={(e) =>
142-
setNewTask({
143-
...newTask,
144-
priority: e.target.value as "Low" | "Medium" | "High",
145-
})
146-
}
147-
sx={{ mt: 2 }}
148-
>
149-
<MenuItem value="Low">Low</MenuItem>
150-
<MenuItem value="Medium">Medium</MenuItem>
151-
<MenuItem value="High">High</MenuItem>
152-
</Select>
153-
</Grid>
154-
</Grid>
155-
</Box>
156-
157-
<Button variant="contained" onClick={addTask} loading={loadingState}>
158-
Add Task
159-
</Button>
160-
{/* <Divider sx={{mt:2}}/> */}
240+
<TaskHeader {...{ tasks, onClose: onDialogClose }} />
161241

162242
{initialLoading ? ( // Show loading icon if initial loading is true
163243
<Box display="flex" justifyContent="center" sx={{ mt: 2 }}>
164244
<CircularProgress />
165-
</Box>
166-
) : (
245+
</Box>
246+
) : (
167247
<List sx={{ mt: 1, mx: -3 }}>
168248
{tasks.map((task) => (
169249
<ListItem
@@ -179,7 +259,7 @@ export default function Home() {
179259
onChange={() => toggleTask(task)}
180260
/>
181261
<ListItemText
182-
primary={`${task.title} (Due: ${task.dueDate})`}
262+
primary={`${task.title} (Due: ${format(task.dueDate ?? new Date(), "dd MMM")})`}
183263
secondary={`Priority: ${task.priority}`}
184264
sx={{
185265
textDecoration: task.completed ? "line-through" : "none",

src/package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"@mui/material-nextjs": "^6.4.3",
1818
"@next-auth/mongodb-adapter": "^1.1.3",
1919
"axios": "^1.7.9",
20+
"date-fns": "^4.1.0",
2021
"mongoose": "^8.10.1",
2122
"next": "15.1.7",
2223
"next-auth": "^4.24.11",

0 commit comments

Comments
 (0)