diff --git a/src/components/common/FadeModal.jsx b/src/components/common/FadeModal.jsx
new file mode 100644
index 0000000..745cada
--- /dev/null
+++ b/src/components/common/FadeModal.jsx
@@ -0,0 +1,82 @@
+import { Modal, ModalDialog, ModalOverflow } from '@mui/joy'
+
+/**
+ * FadeModal component with consistent fade-in/out animations
+ * Can be used as a drop-in replacement for Joy UI's Modal component
+ */
+const FadeModal = ({
+ open,
+ onClose,
+ children,
+ size = 'md',
+ fullWidth = false,
+ backdropBlur = true,
+ ...props
+}) => {
+ return (
+
+
+ *': {
+ opacity: 0,
+ animation: open
+ ? 'contentFadeIn 0.35s forwards'
+ : 'contentFadeOut 0.2s forwards',
+ },
+ // Stagger child animations
+ '& > *:nth-of-type(1)': { animationDelay: '0.05s' },
+ '& > *:nth-of-type(2)': { animationDelay: '0.1s' },
+ '& > *:nth-of-type(3)': { animationDelay: '0.15s' },
+ '& > *:nth-of-type(4)': { animationDelay: '0.2s' },
+ '& > *:nth-of-type(5)': { animationDelay: '0.25s' },
+ '@keyframes contentFadeIn': {
+ to: { opacity: 1 },
+ },
+ '@keyframes contentFadeOut': {
+ to: { opacity: 0 },
+ },
+ }}
+ >
+ {children}
+
+
+
+ )
+}
+
+export default FadeModal
diff --git a/src/views/Authorization/LoginView.jsx b/src/views/Authorization/LoginView.jsx
index 2ffcdaf..36e1655 100644
--- a/src/views/Authorization/LoginView.jsx
+++ b/src/views/Authorization/LoginView.jsx
@@ -14,6 +14,7 @@ import {
Sheet,
Typography,
} from '@mui/joy'
+import { useQueryClient } from '@tanstack/react-query'
import Cookies from 'js-cookie'
import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
@@ -27,8 +28,8 @@ import { apiManager, isTokenValid } from '../../utils/TokenManager'
import MFAVerificationModal from './MFAVerificationModal'
const LoginView = () => {
- // Only fetch user profile if token is valid to prevent unnecessary queries
- // const { data: userProfileData } = useUserProfile()
+ // Use React Query client directly to invalidate the user profile query
+ const queryClient = useQueryClient()
const [userProfile, setUserProfile] = useState(null)
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
@@ -78,11 +79,19 @@ const LoginView = () => {
// Normal login without MFA
localStorage.setItem('ca_token', data.token)
localStorage.setItem('ca_expiration', data.expire)
+
+ // Refetch user profile after successful login
+ queryClient.refetchQueries(['userProfile'])
+
const redirectUrl = Cookies.get('ca_redirect')
- if (redirectUrl) {
+
+ if (redirectUrl && redirectUrl !== '/') {
+ console.log('Redirecting to', redirectUrl)
+
Cookies.remove('ca_redirect')
Navigate(redirectUrl)
} else {
+ Cookies.remove('ca_redirect')
Navigate('/my/chores')
}
})
@@ -143,6 +152,9 @@ const LoginView = () => {
localStorage.setItem('ca_token', data.token)
localStorage.setItem('ca_expiration', data.expire)
+ // Refetch user profile after successful OAuth login
+ queryClient.invalidateQueries(['userProfile'])
+
const redirectUrl = Cookies.get('ca_redirect')
if (redirectUrl) {
Cookies.remove('ca_redirect')
@@ -161,17 +173,17 @@ const LoginView = () => {
})
}
const getUserProfileAndNavigateToHome = () => {
- // Refetch user profile after login
- // refetchUserProfile().then(() => {
- // // check if redirect url is set in cookie:
- const redirectUrl = Cookies.get('ca_redirect')
- if (redirectUrl) {
- Cookies.remove('ca_redirect')
- Navigate(redirectUrl)
- } else {
- Navigate('/my/chores')
- }
- // })
+ // Refetch user profile after login using React Query
+ queryClient.invalidateQueries(['userProfile']).then(() => {
+ // check if redirect url is set in cookie:
+ const redirectUrl = Cookies.get('ca_redirect')
+ if (redirectUrl) {
+ Cookies.remove('ca_redirect')
+ Navigate(redirectUrl)
+ } else {
+ Navigate('/my/chores')
+ }
+ })
}
const handleMFASuccess = data => {
@@ -180,6 +192,9 @@ const LoginView = () => {
setMfaModalOpen(false)
setMfaSessionToken('')
+ // Refetch user profile after MFA success
+ queryClient.invalidateQueries(['userProfile'])
+
const redirectUrl = Cookies.get('ca_redirect')
if (redirectUrl) {
Cookies.remove('ca_redirect')
diff --git a/src/views/Authorization/MFAVerificationModal.jsx b/src/views/Authorization/MFAVerificationModal.jsx
index 5f76e98..991df11 100644
--- a/src/views/Authorization/MFAVerificationModal.jsx
+++ b/src/views/Authorization/MFAVerificationModal.jsx
@@ -5,13 +5,12 @@ import {
Button,
Input,
Link,
- Modal,
ModalClose,
- ModalDialog,
Stack,
Typography,
} from '@mui/joy'
import { useState } from 'react'
+import FadeModal from '../../components/common/FadeModal'
import { VerifyMFA } from '../../utils/Fetcher'
const MFAVerificationModal = ({
@@ -70,90 +69,88 @@ const MFAVerificationModal = ({
}
return (
-
-
-
+
+
-
-
-
- Two-Factor Authentication
-
-
- Enter the verification code from your authenticator app
+
+
+
+ Two-Factor Authentication
+
+
+ Enter the verification code from your authenticator app
+
+
+
+
+
+
+ {isBackupCode ? 'Backup Code' : 'Verification Code'}
+ setVerificationCode(e.target.value)}
+ onKeyPress={handleKeyPress}
+ sx={{
+ textAlign: 'center',
+ fontSize: '1.1em',
+ letterSpacing: isBackupCode ? 'normal' : '0.1em',
+ }}
+ slotProps={{
+ input: {
+ maxLength: isBackupCode ? 50 : 6,
+ pattern: isBackupCode ? undefined : '[0-9]*',
+ },
+ }}
+ startDecorator={}
+ autoFocus
+ />
-
-
-
- {isBackupCode ? 'Backup Code' : 'Verification Code'}
-
- setVerificationCode(e.target.value)}
- onKeyPress={handleKeyPress}
- sx={{
- textAlign: 'center',
- fontSize: '1.1em',
- letterSpacing: isBackupCode ? 'normal' : '0.1em',
- }}
- slotProps={{
- input: {
- maxLength: isBackupCode ? 50 : 6,
- pattern: isBackupCode ? undefined : '[0-9]*',
- },
- }}
- startDecorator={}
- autoFocus
- />
-
-
- {error && (
-
- {error}
-
- )}
-
-
-
-
- {
- setIsBackupCode(!isBackupCode)
- setVerificationCode('')
- setError('')
- }}
- sx={{ fontSize: 'sm' }}
- >
- {isBackupCode
- ? 'Use authenticator app instead'
- : "Can't access your authenticator? Use a backup code"}
-
-
-
-
-
- Having trouble? Make sure your authenticator app is synced and try
- again. Each backup code can only be used once.
-
+ {error && (
+
+ {error}
-
-
-
+ )}
+
+
+
+
+ {
+ setIsBackupCode(!isBackupCode)
+ setVerificationCode('')
+ setError('')
+ }}
+ sx={{ fontSize: 'sm' }}
+ >
+ {isBackupCode
+ ? 'Use authenticator app instead'
+ : "Can't access your authenticator? Use a backup code"}
+
+
+
+
+
+ Having trouble? Make sure your authenticator app is synced and try
+ again. Each backup code can only be used once.
+
+
+
+
)
}
diff --git a/src/views/Modals/EditHistoryModal.jsx b/src/views/Modals/EditHistoryModal.jsx
index 2450759..0795c99 100644
--- a/src/views/Modals/EditHistoryModal.jsx
+++ b/src/views/Modals/EditHistoryModal.jsx
@@ -1,14 +1,7 @@
-import {
- Box,
- Button,
- FormLabel,
- Input,
- Modal,
- ModalDialog,
- Typography,
-} from '@mui/joy'
+import { Box, Button, FormLabel, Input, Typography } from '@mui/joy'
import moment from 'moment'
import { useEffect, useState } from 'react'
+import FadeModal from '../../components/common/FadeModal'
import ConfirmationModal from './Inputs/ConfirmationModal'
function EditHistoryModal({ config, historyRecord }) {
@@ -29,93 +22,91 @@ function EditHistoryModal({ config, historyRecord }) {
const [notes, setNotes] = useState(historyRecord.notes)
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false)
return (
-
-
-
- Edit History
-
- Due Date
- {
- setDueDate(e.target.value)
- }}
- />
- Completed Date
- {
- setCompletedDate(e.target.value)
- }}
- />
- Note
- {
- if (e.target.value.trim() === '') {
- setNotes(null)
- return
- }
- setNotes(e.target.value)
- }}
- size='md'
- sx={{
- mb: 1,
- }}
- />
+
+
+ Edit History
+
+ Due Date
+ {
+ setDueDate(e.target.value)
+ }}
+ />
+ Completed Date
+ {
+ setCompletedDate(e.target.value)
+ }}
+ />
+ Note
+ {
+ if (e.target.value.trim() === '') {
+ setNotes(null)
+ return
+ }
+ setNotes(e.target.value)
+ }}
+ size='md'
+ sx={{
+ mb: 1,
+ }}
+ />
- {/* 3 button save , cancel and delete */}
-
-
-
-
-
- {
- if (isConfirm) {
- config.onDelete(historyRecord.id)
- }
- setIsDeleteModalOpen(false)
- },
- title: 'Delete History',
- message: 'Are you sure you want to delete this history?',
- confirmText: 'Delete',
- cancelText: 'Cancel',
+ {/* 3 button save , cancel and delete */}
+
+
+
+
-
+ variant='outlined'
+ color='danger'
+ >
+ Delete
+
+
+ {
+ if (isConfirm) {
+ config.onDelete(historyRecord.id)
+ }
+ setIsDeleteModalOpen(false)
+ },
+ title: 'Delete History',
+ message: 'Are you sure you want to delete this history?',
+ confirmText: 'Delete',
+ cancelText: 'Cancel',
+ }}
+ />
+
)
}
export default EditHistoryModal
diff --git a/src/views/Modals/Inputs/ConfirmationModal.jsx b/src/views/Modals/Inputs/ConfirmationModal.jsx
index 882522e..f81a303 100644
--- a/src/views/Modals/Inputs/ConfirmationModal.jsx
+++ b/src/views/Modals/Inputs/ConfirmationModal.jsx
@@ -1,5 +1,5 @@
-import { Box, Button, Modal, ModalDialog, Typography } from '@mui/joy'
-import React from 'react'
+import { Box, Button, Typography } from '@mui/joy'
+import FadeModal from '../../../components/common/FadeModal'
function ConfirmationModal({ config }) {
const handleAction = isConfirmed => {
@@ -7,38 +7,41 @@ function ConfirmationModal({ config }) {
}
return (
-
-
-
- {config?.title}
-
+
+
+ {config?.title}
+
-
- {config?.message}
-
+
+ {config?.message}
+
-
-
-
-
-
-
+
+
+
+
+
)
}
export default ConfirmationModal
diff --git a/src/views/Modals/Inputs/CreateThingModal.jsx b/src/views/Modals/Inputs/CreateThingModal.jsx
index 96b7954..a4863f7 100644
--- a/src/views/Modals/Inputs/CreateThingModal.jsx
+++ b/src/views/Modals/Inputs/CreateThingModal.jsx
@@ -4,14 +4,13 @@ import {
FormControl,
FormHelperText,
Input,
- Modal,
- ModalDialog,
Option,
Select,
Textarea,
Typography,
} from '@mui/joy'
import { useEffect, useState } from 'react'
+import FadeModal from '../../../components/common/FadeModal'
function CreateThingModal({ isOpen, onClose, onSave, currentThing }) {
const [name, setName] = useState(currentThing?.name || '')
@@ -59,87 +58,80 @@ function CreateThingModal({ isOpen, onClose, onSave, currentThing }) {
}
return (
-
-
- {/* */}
-
- {currentThing?.id ? 'Edit' : 'Create'} Thing
-
+
+
+ {currentThing?.id ? 'Edit' : 'Create'} Thing
+
+
+ Name
+
+
+ Type
+
+
+ {errors.type}
+
+ {type === 'text' && (
- Name
-
+ )}
+ {type === 'number' && (
- Type
-
+ )}
+ {type === 'boolean' && (
+
+ Value
+
-
- {errors.type}
- {type === 'text' && (
-
- Value
- setState(e.target.value)}
- sx={{ minWidth: 300 }}
- />
- {errors.state}
-
- )}
- {type === 'number' && (
-
- Value
- {
- setState(e.target.value)
- }}
- sx={{ minWidth: 300 }}
- />
-
- )}
- {type === 'boolean' && (
-
- Value
-
-
- )}
+ )}
-
-
-
-
-
-
+
+
+
+
+
)
}
export default CreateThingModal
diff --git a/src/views/Modals/Inputs/LabelModal.jsx b/src/views/Modals/Inputs/LabelModal.jsx
index 9430209..df631dd 100644
--- a/src/views/Modals/Inputs/LabelModal.jsx
+++ b/src/views/Modals/Inputs/LabelModal.jsx
@@ -3,13 +3,12 @@ import {
Button,
FormControl,
Input,
- Modal,
- ModalDialog,
Option,
Select,
Typography,
} from '@mui/joy'
import { useEffect, useState } from 'react'
+import FadeModal from '../../../components/common/FadeModal'
import { useQueryClient } from '@tanstack/react-query'
import { useNotification } from '../../../service/NotificationProvider.jsx'
@@ -58,29 +57,9 @@ function LabelModal({ isOpen, onClose, label }) {
return true
}
- // Mutation for saving labels
- // const saveLabelMutation = useMutation(
- // newLabel =>
- // label
- // ? UpdateLabel({ id: label.id, ...newLabel })
- // : CreateLabel(newLabel),
- // {
- // onSuccess: () => {
- // queryClient.invalidateQueries('labels')
- // onClose()
- // },
- // onError: () => {
- // setError('Failed to save label. Please try again.')
- // },
- // },
- // )
-
const handleSave = () => {
if (!validateLabel()) return
const saveLabel = label?.id && label.id !== -1 ? UpdateLabel : CreateLabel
- // ? { id: label.id, name: labelName, color }
- // : { name: labelName, color }
- // saveLabelMutation.mutate({ name: labelName, color })
saveLabel({
id: label?.id,
name: labelName,
@@ -110,79 +89,77 @@ function LabelModal({ isOpen, onClose, label }) {
}
return (
-
-
-
- {label ? 'Edit Label' : 'Add Label'}
+
+
+ {label ? 'Edit Label' : 'Add Label'}
+
+
+
+
+ Name
+ setLabelName(e.target.value)}
+ />
+
-
-
- Name
-
- setLabelName(e.target.value)}
- />
-
+
+
+ Color
+
+
+ )}
+ >
+ {LABEL_COLORS.map(val => (
+
+ ))}
+
+
-
-
- Color
-
-
-
+ {error && (
+
+ {error}
+
+ )}
- {error && (
-
- {error}
-
- )}
-
-
-
-
-
-
-
+
+
+
+
+
)
}
diff --git a/src/views/Modals/Inputs/PasswordChangeModal.jsx b/src/views/Modals/Inputs/PasswordChangeModal.jsx
index 581b2f9..793cbdd 100644
--- a/src/views/Modals/Inputs/PasswordChangeModal.jsx
+++ b/src/views/Modals/Inputs/PasswordChangeModal.jsx
@@ -4,11 +4,10 @@ import {
FormControl,
FormHelperText,
Input,
- Modal,
- ModalDialog,
Typography,
} from '@mui/joy'
import React, { useEffect } from 'react'
+import FadeModal from '../../../components/common/FadeModal'
function PassowrdChangeModal({ isOpen, onClose }) {
const [password, setPassword] = React.useState('')
@@ -40,78 +39,76 @@ function PassowrdChangeModal({ isOpen, onClose }) {
}
return (
-
-
-
+
+
+ Change Password
+
+
+
+ Please enter your new password.
+
+
+
+ New Password
+
+ {
+ setPasswordTouched(true)
+ setPassword(e.target.value)
+ }}
+ />
+
+
+
+
+ Confirm Password
+
+ {
+ setConfirmPasswordTouched(true)
+ setConfirmPassword(e.target.value)
+ }}
+ />
+
+ {passwordError}
+
+
+
-
-
- Please enter your new password.
-
-
-
- New Password
-
- {
- setPasswordTouched(true)
- setPassword(e.target.value)
- }}
- />
-
-
-
-
- Confirm Password
-
- {
- setConfirmPasswordTouched(true)
- setConfirmPassword(e.target.value)
- }}
- />
-
- {passwordError}
-
-
-
-
-
-
-
+
+
+
+
)
}
export default PassowrdChangeModal
diff --git a/src/views/Modals/Inputs/SelectModal.jsx b/src/views/Modals/Inputs/SelectModal.jsx
index f879bf0..7f5936d 100644
--- a/src/views/Modals/Inputs/SelectModal.jsx
+++ b/src/views/Modals/Inputs/SelectModal.jsx
@@ -1,15 +1,16 @@
-import {
- Box,
- Button,
- Modal,
- ModalDialog,
- Option,
- Select,
- Typography,
-} from '@mui/joy'
+import { Box, Button, Option, Select, Typography } from '@mui/joy'
import React from 'react'
+import FadeModal from '../../../components/common/FadeModal'
-function SelectModal({ isOpen, onClose, onSave, options, title, displayKey,placeholder }) {
+function SelectModal({
+ isOpen,
+ onClose,
+ onSave,
+ options,
+ title,
+ displayKey,
+ placeholder,
+}) {
const [selected, setSelected] = React.useState(null)
const handleSave = () => {
onSave(options.find(item => item.id === selected))
@@ -17,33 +18,31 @@ function SelectModal({ isOpen, onClose, onSave, options, title, displayKey,place
}
return (
-
-
- {title}
-
+
+ {title}
+
-
-
-
-
-
-
+
+
+
+
+
)
}
export default SelectModal
diff --git a/src/views/Modals/Inputs/TextModal.jsx b/src/views/Modals/Inputs/TextModal.jsx
index 2b44f78..6e2f739 100644
--- a/src/views/Modals/Inputs/TextModal.jsx
+++ b/src/views/Modals/Inputs/TextModal.jsx
@@ -1,5 +1,6 @@
-import { Box, Button, Modal, ModalDialog, Textarea, Typography } from '@mui/joy'
+import { Box, Button, Textarea, Typography } from '@mui/joy'
import { useState } from 'react'
+import FadeModal from '../../../components/common/FadeModal'
function TextModal({
isOpen,
@@ -18,29 +19,26 @@ function TextModal({
}
return (
-
-
- {/* */}
- {title}
-
-
+
+
+
+
+
)
}
export default TextModal
diff --git a/src/views/Modals/Inputs/UserModal.jsx b/src/views/Modals/Inputs/UserModal.jsx
index f617307..e37a28a 100644
--- a/src/views/Modals/Inputs/UserModal.jsx
+++ b/src/views/Modals/Inputs/UserModal.jsx
@@ -1,57 +1,44 @@
-import {
- Avatar,
- Box,
- Button,
- List,
- ListItem,
- Modal,
- ModalDialog,
- ModalOverflow,
- Typography,
-} from '@mui/joy'
+import { Avatar, Box, Button, List, ListItem, Typography } from '@mui/joy'
+import FadeModal from '../../../components/common/FadeModal'
const UserModal = ({ isOpen, performers = [], onSelect, onClose }) => {
return (
-
-
-
-
- Select User
-
-
- {performers.map(user => (
- {
- onSelect(user)
- onClose()
- }}
- >
-
-
- {user.displayName || user.name}
-
-
- ))}
-
-
-
-
-
-
-
+
+
+ Select User
+
+
+ {performers.map(user => (
+ {
+ onSelect(user)
+ onClose()
+ }}
+ >
+
+
+ {user.displayName || user.name}
+
+
+ ))}
+
+
+
+
+
)
}
diff --git a/src/views/Modals/Inputs/WriteNFCModal.jsx b/src/views/Modals/Inputs/WriteNFCModal.jsx
index 2aad366..164cce9 100644
--- a/src/views/Modals/Inputs/WriteNFCModal.jsx
+++ b/src/views/Modals/Inputs/WriteNFCModal.jsx
@@ -1,15 +1,7 @@
import { CopyAll } from '@mui/icons-material'
-import {
- Box,
- Button,
- Checkbox,
- Input,
- ListItem,
- Modal,
- ModalDialog,
- Typography,
-} from '@mui/joy'
-import React, { useState } from 'react'
+import { Box, Button, Checkbox, Input, ListItem, Typography } from '@mui/joy'
+import { useState } from 'react'
+import FadeModal from '../../../components/common/FadeModal'
function WriteNFCModal({ config }) {
const [nfcStatus, setNfcStatus] = useState('idle') // 'idle', 'writing', 'success', 'error'
@@ -60,63 +52,61 @@ function WriteNFCModal({ config }) {
return url
}
return (
-
-
-
- {nfcStatus === 'success' ? 'Success!' : 'Write to NFC'}
-
+
+
+ {nfcStatus === 'success' ? 'Success!' : 'Write to NFC'}
+
- {nfcStatus === 'success' ? (
+ {nfcStatus === 'success' ? (
+
+ URL written to NFC tag successfully!
+
+ ) : (
+ <>
- URL written to NFC tag successfully!
+ {nfcStatus === 'error'
+ ? errorMessage
+ : 'Press the button below to write to NFC.'}
- ) : (
- <>
-
- {nfcStatus === 'error'
- ? errorMessage
- : 'Press the button below to write to NFC.'}
-
- {
- navigator.clipboard.writeText(getURL())
- alert('URL copied to clipboard!')
- }}
- />
- }
- />
-
- setIsAutoCompleteWhenScan(e.target.checked)}
- label='Auto-complete when scanned'
+ {
+ navigator.clipboard.writeText(getURL())
+ alert('URL copied to clipboard!')
+ }}
/>
-
-
-
-
-
- >
- )}
-
-
+ }
+ />
+
+ setIsAutoCompleteWhenScan(e.target.checked)}
+ label='Auto-complete when scanned'
+ />
+
+
+
+
+
+ >
+ )}
+
)
}
diff --git a/src/views/Modals/RedeemPointsModal.jsx b/src/views/Modals/RedeemPointsModal.jsx
index 2c21636..59527ac 100644
--- a/src/views/Modals/RedeemPointsModal.jsx
+++ b/src/views/Modals/RedeemPointsModal.jsx
@@ -1,14 +1,6 @@
-import {
- Box,
- Button,
- FormLabel,
- IconButton,
- Input,
- Modal,
- ModalDialog,
- Typography,
-} from '@mui/joy'
+import { Box, Button, FormLabel, IconButton, Input, Typography } from '@mui/joy'
import { useEffect, useState } from 'react'
+import FadeModal from '../../components/common/FadeModal'
function RedeemPointsModal({ config }) {
useEffect(() => {
@@ -20,71 +12,69 @@ function RedeemPointsModal({ config }) {
const predefinedPoints = [1, 5, 10, 25]
return (
-
-
-
- Redeem Points
-
-
- Points to Redeem ({config.available ? config.available : 0} points
- available)
-
- {
- if (e.target.value > config.available) {
- setPoints(config.available)
- return
- }
- setPoints(e.target.value)
- }}
- />
- Or select from predefined points:
-
- {predefinedPoints.map(point => (
- config.available}
- sx={{ borderRadius: '50%' }}
- key={point}
- onClick={() => {
- const newPoints = points + point
- if (newPoints > config.available) {
- setPoints(config.available)
- return
- }
- setPoints(newPoints)
- }}
- >
- {point}
-
- ))}
-
-
- {/* 3 button save , cancel and delete */}
-
-
-
-
-
-
+ {point}
+
+ ))}
+
+
+ {/* 3 button save , cancel and delete */}
+
+
+
+
+
)
}
export default RedeemPointsModal
diff --git a/src/views/components/AddTaskModal.jsx b/src/views/components/AddTaskModal.jsx
index 1408401..3d5ddb5 100644
--- a/src/views/components/AddTaskModal.jsx
+++ b/src/views/components/AddTaskModal.jsx
@@ -1,20 +1,10 @@
import { Add, EditNotifications } from '@mui/icons-material'
-import {
- Box,
- Button,
- Chip,
- Input,
- Modal,
- ModalDialog,
- ModalOverflow,
- Option,
- Select,
- Typography,
-} from '@mui/joy'
+import { Box, Button, Chip, Input, Option, Select, Typography } from '@mui/joy'
import { FormControl } from '@mui/material'
import * as chrono from 'chrono-node'
import moment from 'moment'
import { useCallback, useEffect, useRef, useState } from 'react'
+import FadeModal from '../../components/common/FadeModal'
import { useCreateChore } from '../../queries/ChoreQueries'
import { useCircleMembers, useUserProfile } from '../../queries/UserQueries'
import { isPlusAccount } from '../../utils/Helpers'
@@ -399,101 +389,100 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
}
return (
-
-
-
- Create new task
-
- Experimental Feature
-
-
-
- Task in a sentence:
-
-
- This feature lets you create a task simply by typing a
- sentence. It attempt parses the sentence to identify the
- task's due date, priority, and frequency.
-
+
+ Create new task
+
+ Experimental Feature
+
+
+
+ Task in a sentence:
+
+
+ This feature lets you create a task simply by typing a
+ sentence. It attempt parses the sentence to identify the
+ task's due date, priority, and frequency.
+
-
- Examples:
-
+
+ Examples:
+
-
-
- Priority:For highest priority any of
- the following keyword P1, Urgent,{' '}
- Important, or ASAP. For lower
- priorities, use P2, P3, or P4
- .
-
-
- Due date: Specify dates with phrases
- like tomorrow, next week,{' '}
- Monday, or August 1st at 12pm.
-
-
- Frequency: Set recurring tasks with
- terms like daily, weekly,{' '}
- monthly, yearly, or patterns such as{' '}
- every Tuesday and Thursday.
-
-
- >
- }
- />
-
+
+
+ Priority:For highest priority any of the
+ following keyword P1, Urgent,{' '}
+ Important, or ASAP. For lower priorities,
+ use P2, P3, or P4.
+
+
+ Due date: Specify dates with phrases like{' '}
+ tomorrow, next week, Monday, or{' '}
+ August 1st at 12pm.
+
+
+ Frequency: Set recurring tasks with terms
+ like daily, weekly, monthly,{' '}
+ yearly, or patterns such as{' '}
+ every Tuesday and Thursday.
+
+
+ >
+ }
+ />
+
- {
- setTaskText(text)
- }}
- customRenderer={renderedParts}
- onEnterPressed={handleEnterPressed}
- suggestions={{
- '#': {
- value: 'id',
- display: 'name',
- options: userLabels ? userLabels : [],
- },
- '!': {
- value: 'id',
- display: 'name',
- options: [
- { id: '1', name: 'P1' },
- { id: '2', name: 'P2' },
- { id: '3', name: 'P3' },
- { id: '4', name: 'P4' },
- ],
- },
- '@': {
- value: 'userId',
- display: 'displayName',
- options: circleMembers?.res || [],
- },
- }}
- />
-
- {/*
+ {
+ setTaskText(text)
+ }}
+ customRenderer={renderedParts}
+ onEnterPressed={handleEnterPressed}
+ suggestions={{
+ '#': {
+ value: 'id',
+ display: 'name',
+ options: userLabels ? userLabels : [],
+ },
+ '!': {
+ value: 'id',
+ display: 'name',
+ options: [
+ { id: '1', name: 'P1' },
+ { id: '2', name: 'P2' },
+ { id: '3', name: 'P3' },
+ { id: '4', name: 'P4' },
+ ],
+ },
+ '@': {
+ value: 'userId',
+ display: 'displayName',
+ options: circleMembers?.res || [],
+ },
+ }}
+ />
+
+ {/*
Title:
{
sx={{ width: '100%', fontSize: '16px' }}
/>
*/}
-
- {!hasDescription && (
- }
- variant='plain'
- size='sm'
- onClick={() => setHasDescription(true)}
- >
- Description
-
- )}
- {!hasSubTasks && (
- }
- variant='plain'
- size='sm'
- onClick={() => setHasSubTasks(true)}
- >
- Subtasks
-
- )}
- {!dueDate && (
- }
- variant='plain'
- size='sm'
- onClick={() => {
- setDueDate(
- moment().add(1, 'day').format('YYYY-MM-DDTHH:00:00'),
- )
- }}
- >
- Due Date
-
- )}
- {!hasNotifications && dueDate && (
- }
- variant='plain'
- size='sm'
- onClick={() => {
- setHasNotifications(true)
- setFrequencyHumanReadable('Once')
- setFrequency(null)
- setDueDate(
- moment().add(1, 'day').format('YYYY-MM-DDTHH:00:00'),
- )
- }}
- >
- Edit Notifications
-
- )}
-
-
- {hasDescription && (
-
- Description:
-
-
-
-
- )}
- {hasSubTasks && (
-
- Subtasks:
-
-
- )}
-
-
+ {!hasDescription && (
+ }
+ variant='plain'
+ size='sm'
+ onClick={() => setHasDescription(true)}
+ >
+ Description
+
+ )}
+ {!hasSubTasks && (
+ }
+ variant='plain'
+ size='sm'
+ onClick={() => setHasSubTasks(true)}
+ >
+ Subtasks
+
+ )}
+ {!dueDate && (
+ }
+ variant='plain'
+ size='sm'
+ onClick={() => {
+ setDueDate(moment().add(1, 'day').format('YYYY-MM-DDTHH:00:00'))
}}
>
-
- Priority
-
-
- {dueDate && (
-
- Due Date
- setDueDate(e.target.value)}
- sx={{ width: '100%', fontSize: '16px' }}
- />
-
- )}
-
-
+ )}
+ {!hasNotifications && dueDate && (
+ }
+ variant='plain'
+ size='sm'
+ onClick={() => {
+ setHasNotifications(true)
+ setFrequencyHumanReadable('Once')
+ setFrequency(null)
+ setDueDate(moment().add(1, 'day').format('YYYY-MM-DDTHH:00:00'))
}}
>
- {/*
+ Edit Notifications
+
+ )}
+
+
+ {hasDescription && (
+
+ Description:
+
+
+
+
+ )}
+ {hasSubTasks && (
+
+ Subtasks:
+
+
+ )}
+
+
+
+ Priority
+
+
+ {dueDate && (
+
+ Due Date
+ setDueDate(e.target.value)}
+ sx={{ width: '100%', fontSize: '16px' }}
+ />
+
+ )}
+
+
+ {/*
Assignees
{assignees.length > 0 ? (
@@ -641,58 +626,51 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
)}
*/}
- {hasNotifications && dueDate && (
-
- Notification Schedule
-
- {
- if (
- metadata.notifications !==
- notificationMetadata.templates
- ) {
- const newNotificaitonMetadata = {
- ...notificationMetadata,
- templates: metadata.notifications,
- }
- setNotificationMetadata(newNotificaitonMetadata)
- }
- }}
- value={notificationMetadata}
- showTimeline={false}
- />
-
-
- )}
-
+ {hasNotifications && dueDate && (
-
-
+ Notification Schedule
+
+ {
+ if (
+ metadata.notifications !== notificationMetadata.templates
+ ) {
+ const newNotificaitonMetadata = {
+ ...notificationMetadata,
+ templates: metadata.notifications,
+ }
+ setNotificationMetadata(newNotificaitonMetadata)
+ }
+ }}
+ value={notificationMetadata}
+ showTimeline={false}
+ />
+
-
-
-
+ )}
+
+
+
+
+
+
)
}