diff --git a/package-lock.json b/package-lock.json
index 1217ac7..7dac78c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,8 @@
"@fontsource/roboto": "^5.1.0",
"@mui/icons-material": "^6.1.6",
"@mui/material": "^6.1.6",
+ "@mui/x-date-pickers": "^7.22.1",
+ "dayjs": "^1.11.13",
"firebase": "^11.0.1",
"react": "^18.3.1",
"react-calendar": "^5.1.0",
@@ -2083,6 +2085,92 @@
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
"license": "MIT"
},
+ "node_modules/@mui/x-date-pickers": {
+ "version": "7.22.1",
+ "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.22.1.tgz",
+ "integrity": "sha512-VBgicE+7PvJrdHSL6HyieHT6a/0dENH8RaMIM2VwUFrGoZzvik50WNwY5U+Hip1BwZLIEvlqtNRQIIj6kgBR6Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.25.7",
+ "@mui/utils": "^5.16.6 || ^6.0.0",
+ "@mui/x-internals": "7.21.0",
+ "@types/react-transition-group": "^4.4.11",
+ "clsx": "^2.1.1",
+ "prop-types": "^15.8.1",
+ "react-transition-group": "^4.4.5"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.9.0",
+ "@emotion/styled": "^11.8.1",
+ "@mui/material": "^5.15.14 || ^6.0.0",
+ "@mui/system": "^5.15.14 || ^6.0.0",
+ "date-fns": "^2.25.0 || ^3.2.0 || ^4.0.0",
+ "date-fns-jalali": "^2.13.0-0 || ^3.2.0-0",
+ "dayjs": "^1.10.7",
+ "luxon": "^3.0.2",
+ "moment": "^2.29.4",
+ "moment-hijri": "^2.1.2",
+ "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0",
+ "react": "^17.0.0 || ^18.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "date-fns": {
+ "optional": true
+ },
+ "date-fns-jalali": {
+ "optional": true
+ },
+ "dayjs": {
+ "optional": true
+ },
+ "luxon": {
+ "optional": true
+ },
+ "moment": {
+ "optional": true
+ },
+ "moment-hijri": {
+ "optional": true
+ },
+ "moment-jalaali": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/x-internals": {
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.21.0.tgz",
+ "integrity": "sha512-94YNyZ0BhK5Z+Tkr90RKf47IVCW8R/1MvdUhh6MCQg6sZa74jsX+x+gEZ4kzuCqOsuyTyxikeQ8vVuCIQiP7UQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.25.7",
+ "@mui/utils": "^5.16.6 || ^6.0.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "react": "^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -3493,6 +3581,24 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/date-fns": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
+ "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
+ "license": "MIT",
+ "optional": true,
+ "peer": true,
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/kossnocorp"
+ }
+ },
+ "node_modules/dayjs": {
+ "version": "1.11.13",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
+ "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
+ "license": "MIT"
+ },
"node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
diff --git a/package.json b/package.json
index 9b110ea..d579c37 100644
--- a/package.json
+++ b/package.json
@@ -28,6 +28,8 @@
"@fontsource/roboto": "^5.1.0",
"@mui/icons-material": "^6.1.6",
"@mui/material": "^6.1.6",
+ "@mui/x-date-pickers": "^7.22.1",
+ "dayjs": "^1.11.13",
"firebase": "^11.0.1",
"react": "^18.3.1",
"react-calendar": "^5.1.0",
diff --git a/src/components/Home/AddItem.jsx b/src/components/Home/AddItem.jsx
index 43c4451..d80bc42 100644
--- a/src/components/Home/AddItem.jsx
+++ b/src/components/Home/AddItem.jsx
@@ -1,33 +1,47 @@
// @ts-check
import CategoryPicker from '@/components/Home/CategoryPicker'
+import { DateTimePicker } from '@/components/Home/DateTimePickers'
import AddIcon from '@mui/icons-material/Add'
import { IconButton, InputAdornment, TextField } from '@mui/material'
import { useState } from 'react'
const AddItem = ({ label, onAdd }) => {
const [inputValue, setInputValue] = useState('')
- const [selectedCategory, setSelectedCategory] = useState('#000000')
+ const [selectedCategory, setSelectedCategory] = useState('#000000') // For 'New Goal'
+ const [dueDate, setDueDate] = useState(null) // For 'New Task'
const handleAdd = async () => {
if (inputValue.trim()) {
- await onAdd(
- inputValue.trim(),
- label === 'New Goal' ? selectedCategory : null
- )
+ let attributes = null
+
+ if (label === 'New Goal') {
+ attributes = selectedCategory
+ } else if (label === 'New Task') {
+ attributes = dueDate
+ }
+
+ await onAdd(inputValue.trim(), attributes ?? null)
setInputValue('')
setSelectedCategory('#000000')
+ setDueDate(null)
}
}
// Conditionally render the category picker
- const startAdornment =
- label === 'New Goal' ? (
-
- ) : null
+ const getStartAdornment = () => {
+ if (label === 'New Goal') {
+ return (
+
+ )
+ } else if (label === 'New Task') {
+ return
+ }
+ return null
+ }
return (
{
fullWidth
slotProps={{
input: {
- startAdornment,
+ startAdornment: getStartAdornment(),
endAdornment: (
setOpen((prev) => !prev) // Toggle the open state
+
+ return (
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/components/Home/MicroGoal.jsx b/src/components/Home/MicroGoal.jsx
index 7f5a355..d67c14e 100644
--- a/src/components/Home/MicroGoal.jsx
+++ b/src/components/Home/MicroGoal.jsx
@@ -59,8 +59,8 @@ const MicroGoal = ({ microGoal, macroGoalIndex, microGoalIndex }) => {
- addTask(macroGoalIndex, microGoalIndex, taskName)
+ onAdd={(taskName, dueDate) =>
+ addTask(macroGoalIndex, microGoalIndex, taskName, dueDate)
}
/>
diff --git a/src/components/Home/Task.jsx b/src/components/Home/Task.jsx
index c3d3ece..066022e 100644
--- a/src/components/Home/Task.jsx
+++ b/src/components/Home/Task.jsx
@@ -1,5 +1,13 @@
+// @ts-check
+
import DeleteItem from '@/components/Home/DeleteItem'
-import { Checkbox, ListItem, ListItemText } from '@mui/material'
+import AccessTimeIcon from '@mui/icons-material/AccessTime'
+import { Box, Checkbox, Chip, ListItem, ListItemText } from '@mui/material'
+import { useTheme } from '@mui/material/styles'
+import dayjs from 'dayjs'
+import calendar from 'dayjs/plugin/calendar'
+
+dayjs.extend(calendar)
const Task = ({
task,
@@ -8,17 +16,32 @@ const Task = ({
microGoalIndex,
taskIndex,
}) => {
+ const renderDueDateChip = () => {
+ const theme = useTheme()
+ const isOverdue =
+ dayjs().isAfter(dayjs(task.due.toMillis())) && !task.completed
+
+ return (
+ }
+ size='small'
+ label={`${isOverdue ? 'Past' : 'Due'}: ${dayjs(task.due.toMillis()).calendar()}`}
+ sx={{
+ ...(isOverdue && {
+ bgcolor: theme.palette.error.main,
+ color: theme.palette.error.contrastText,
+ }),
+ }}
+ />
+ )
+ }
+
return (
+ {task.name}
+ {task.due ? renderDueDateChip() : null}
+
+ }
primaryTypographyProps={{
- sx: {
- textDecoration: task.completed ? 'line-through' : 'none',
- color: task.completed ? 'text.disabled' : 'text.primary',
- },
+ sx: task.completed ? styles.primaryTextCompleted : {},
}}
/>