diff --git a/src/components/common/BottomSheetModal.jsx b/src/components/common/BottomSheetModal.jsx
index 2bd3884..e67ab4a 100644
--- a/src/components/common/BottomSheetModal.jsx
+++ b/src/components/common/BottomSheetModal.jsx
@@ -63,7 +63,10 @@ const BottomSheetModal = forwardRef(
if (internalOpen) {
document.addEventListener('keydown', handleEscape)
// Prevent body scroll when modal is open
- document.body.style.overflow = 'hidden'
+ // document.body.style.overflow = 'hidden'
+ } else {
+ // Restore scroll immediately when modal starts closing
+ // document.body.style.overflow = 'unset'
}
return () => {
@@ -95,6 +98,7 @@ const BottomSheetModal = forwardRef(
ref={ref}
sx={{
zIndex: Z_INDEX.MODAL_CONTENT,
+ minHeight: '30%',
width: '100%',
height: currentHeight,
maxHeight: isExpanded ? expandedHeight : maxHeight,
@@ -185,7 +189,9 @@ const BottomSheetModal = forwardRef(
style={{
display: 'flex',
alignItems: 'center',
- padding: showHandle ? '0 20px 16px 20px' : '16px 20px 16px 20px',
+ padding: showHandle
+ ? '0 20px 16px 20px'
+ : '16px 20px 16px 20px',
paddingRight: showCloseButton ? '60px' : '20px', // Add space for close button
minHeight: 24,
}}
diff --git a/src/hooks/useConfirmationModal.js b/src/hooks/useConfirmationModal.js
new file mode 100644
index 0000000..674ef47
--- /dev/null
+++ b/src/hooks/useConfirmationModal.js
@@ -0,0 +1,41 @@
+import { useState } from 'react'
+
+const useConfirmationModal = () => {
+ const [confirmModalConfig, setConfirmModalConfig] = useState({})
+
+ const showConfirmation = (
+ message,
+ title,
+ onConfirm,
+ confirmText = 'Confirm',
+ cancelText = 'Cancel',
+ color = 'primary',
+ ) => {
+ setConfirmModalConfig({
+ isOpen: true,
+ message,
+ title,
+ confirmText,
+ cancelText,
+ color,
+ onClose: isConfirmed => {
+ if (isConfirmed) {
+ onConfirm()
+ }
+ setConfirmModalConfig({})
+ },
+ })
+ }
+
+ const hideConfirmation = () => {
+ setConfirmModalConfig({})
+ }
+
+ return {
+ confirmModalConfig,
+ showConfirmation,
+ hideConfirmation,
+ }
+}
+
+export default useConfirmationModal
\ No newline at end of file
diff --git a/src/hooks/useResponsiveModal.js b/src/hooks/useResponsiveModal.js
new file mode 100644
index 0000000..297f5fa
--- /dev/null
+++ b/src/hooks/useResponsiveModal.js
@@ -0,0 +1,18 @@
+import BottomSheetModal from '../components/common/BottomSheetModal'
+import FadeModal from '../components/common/FadeModal'
+import useWindowWidth from './useWindowWidth'
+
+/**
+ * Hook that returns the appropriate modal component based on screen size
+ * @param {number} breakpoint - Screen width breakpoint to switch between modals (default: 768px)
+ * @returns {Object} - { Modal: Component, isMobile: boolean }
+ */
+export const useResponsiveModal = (breakpoint = 768) => {
+ const windowWidth = useWindowWidth()
+ const isMobile = windowWidth <= breakpoint
+
+ return {
+ ResponsiveModal: isMobile ? BottomSheetModal : FadeModal,
+ isMobile,
+ }
+}
diff --git a/src/views/Modals/EditHistoryModal.jsx b/src/views/Modals/EditHistoryModal.jsx
index 0795c99..c53d160 100644
--- a/src/views/Modals/EditHistoryModal.jsx
+++ b/src/views/Modals/EditHistoryModal.jsx
@@ -1,10 +1,13 @@
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 { useResponsiveModal } from '../../hooks/useResponsiveModal'
import ConfirmationModal from './Inputs/ConfirmationModal'
function EditHistoryModal({ config, historyRecord }) {
+ const { ResponsiveModal } = useResponsiveModal()
+
useEffect(() => {
setCompletedDate(
moment(historyRecord.performedAt).format('YYYY-MM-DDTHH:mm'),
@@ -22,7 +25,7 @@ function EditHistoryModal({ config, historyRecord }) {
const [notes, setNotes] = useState(historyRecord.notes)
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false)
return (
-
+
Edit History
@@ -106,7 +109,7 @@ function EditHistoryModal({ config, historyRecord }) {
cancelText: 'Cancel',
}}
/>
-
+
)
}
export default EditHistoryModal
diff --git a/src/views/Modals/Inputs/BackupRestoreModal.jsx b/src/views/Modals/Inputs/BackupRestoreModal.jsx
new file mode 100644
index 0000000..aa72b9f
--- /dev/null
+++ b/src/views/Modals/Inputs/BackupRestoreModal.jsx
@@ -0,0 +1,358 @@
+import {
+ Box,
+ Button,
+ Checkbox,
+ CircularProgress,
+ FormControl,
+ FormLabel,
+ Input,
+ Tab,
+ TabList,
+ TabPanel,
+ Tabs,
+ Typography,
+} from '@mui/joy'
+import { useCallback, useEffect, useRef, useState } from 'react'
+import { useResponsiveModal } from '../../../hooks/useResponsiveModal'
+import { CreateBackup, RestoreBackup } from '../../../utils/Fetcher'
+
+function BackupRestoreModal({ isOpen, onClose, showNotification }) {
+ const { ResponsiveModal } = useResponsiveModal()
+
+ const [activeTab, setActiveTab] = useState(0)
+ const [loading, setLoading] = useState(false)
+ const [error, setError] = useState('')
+
+ // Backup state
+ const [encryptionKey, setEncryptionKey] = useState('')
+ const [backupName, setBackupName] = useState('')
+ const [includeAssets, setIncludeAssets] = useState(true)
+
+ // Restore state
+ const [restoreEncryptionKey, setRestoreEncryptionKey] = useState('')
+ const [backupFile, setBackupFile] = useState(null)
+ const fileInputRef = useRef(null)
+
+ const resetModal = useCallback(() => {
+ setActiveTab(0)
+ setEncryptionKey('')
+ setBackupName('')
+ setIncludeAssets(true)
+ setRestoreEncryptionKey('')
+ setBackupFile(null)
+ setError('')
+ setLoading(false)
+ if (fileInputRef.current) {
+ fileInputRef.current.value = ''
+ }
+ }, [])
+
+ const handleClose = useCallback(() => {
+ resetModal()
+ onClose()
+ }, [onClose, resetModal])
+
+ const downloadFile = (data, filename) => {
+ const blob = new Blob([data], { type: 'application/octet-stream' })
+ const url = window.URL.createObjectURL(blob)
+ const link = document.createElement('a')
+ link.href = url
+ link.download = filename
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+ window.URL.revokeObjectURL(url)
+ }
+
+ const handleCreateBackup = async () => {
+ if (!encryptionKey.trim()) {
+ setError('Encryption key is required')
+ return
+ }
+
+ setLoading(true)
+ setError('')
+
+ try {
+ const response = await CreateBackup(
+ encryptionKey,
+ includeAssets,
+ backupName,
+ )
+
+ if (response.ok) {
+ const data = await response.json()
+ const timestamp = new Date()
+ .toISOString()
+ .slice(0, 19)
+ .replace(/:/g, '-')
+ const filename = backupName
+ ? `${backupName}-${timestamp}.backup`
+ : `donetick-backup-${timestamp}.backup`
+
+ // Download the backup file
+ downloadFile(data.backup_data, filename)
+
+ showNotification({
+ type: 'success',
+ message: 'Backup created and downloaded successfully',
+ })
+
+ handleClose()
+ } else {
+ const errorData = await response.json()
+ setError(errorData.message || 'Failed to create backup')
+ }
+ } catch (err) {
+ setError('Failed to create backup')
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ const handleFileUpload = event => {
+ const file = event.target.files[0]
+ if (file) {
+ setBackupFile(file)
+ setError('')
+ }
+ }
+
+ const handleRestore = async () => {
+ if (!restoreEncryptionKey.trim()) {
+ setError('Encryption key is required')
+ return
+ }
+
+ if (!backupFile) {
+ setError('Please select a backup file')
+ return
+ }
+
+ setLoading(true)
+ setError('')
+
+ try {
+ const reader = new FileReader()
+ reader.onload = async e => {
+ try {
+ const backupData = e.target.result
+ const response = await RestoreBackup(restoreEncryptionKey, backupData)
+
+ if (response.ok) {
+ const data = await response.json()
+ showNotification({
+ type: 'success',
+ message: 'Backup restored successfully. Please refresh the page.',
+ })
+
+ // Refresh the page after a short delay to allow user to see the message
+ setTimeout(() => {
+ window.location.reload()
+ }, 2000)
+
+ handleClose()
+ } else {
+ const errorData = await response.json()
+ setError(errorData.message || 'Failed to restore backup')
+ }
+ } catch (err) {
+ setError('Failed to restore backup')
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ reader.onerror = () => {
+ setError('Failed to read backup file')
+ setLoading(false)
+ }
+
+ reader.readAsText(backupFile)
+ } catch (err) {
+ setError('Failed to restore backup')
+ setLoading(false)
+ }
+ }
+
+ // Keyboard shortcuts
+ useEffect(() => {
+ const handleKeyDown = event => {
+ if (!isOpen) return
+
+ if (event.key === 'Escape') {
+ event.preventDefault()
+ handleClose()
+ return
+ }
+ }
+
+ if (isOpen) {
+ document.addEventListener('keydown', handleKeyDown)
+ }
+
+ return () => {
+ document.removeEventListener('keydown', handleKeyDown)
+ }
+ }, [isOpen, handleClose])
+
+ const renderBackupTab = () => (
+
+
+ Create an encrypted backup of your data. This backup will include all
+ your chores, history, settings, and optionally your uploaded files.
+
+
+
+ Encryption Key *
+ setEncryptionKey(e.target.value)}
+ placeholder='Enter a strong encryption key'
+ />
+
+ Keep this key safe - you'll need it to restore your backup
+
+
+
+
+ Backup Name (Optional)
+ setBackupName(e.target.value)}
+ placeholder='e.g., weekly-backup'
+ />
+
+
+
+ setIncludeAssets(e.target.checked)}
+ label='Include uploaded files and assets'
+ />
+
+
+ {error && (
+
+ {error}
+
+ )}
+
+
+
+
+
+
+ )
+
+ const renderRestoreTab = () => (
+
+
+ Warning: Restoring a backup will replace all your
+ current data. This action cannot be undone.
+
+
+
+ Backup File *
+
+ {backupFile && (
+
+ Selected: {backupFile.name}
+
+ )}
+
+
+
+ Encryption Key *
+ setRestoreEncryptionKey(e.target.value)}
+ placeholder='Enter the encryption key used for this backup'
+ />
+
+
+ {error && (
+
+ {error}
+
+ )}
+
+
+
+
+
+
+ )
+
+ return (
+
+ {loading ? (
+
+
+
+ {activeTab === 0 ? 'Creating backup...' : 'Restoring backup...'}
+
+
+ ) : (
+ <>
+
+ 🔄 Backup & Restore
+
+
+ setActiveTab(newValue)}
+ >
+
+ Create Backup
+ Restore Backup
+
+
+ {renderBackupTab()}
+
+ {renderRestoreTab()}
+
+ >
+ )}
+
+ )
+}
+
+export default BackupRestoreModal
diff --git a/src/views/Modals/Inputs/ConfirmationModal.jsx b/src/views/Modals/Inputs/ConfirmationModal.jsx
index 2e0b318..e5a8483 100644
--- a/src/views/Modals/Inputs/ConfirmationModal.jsx
+++ b/src/views/Modals/Inputs/ConfirmationModal.jsx
@@ -1,9 +1,10 @@
import { Box, Button, Typography } from '@mui/joy'
import { useCallback, useEffect, useState } from 'react'
-import FadeModal from '../../../components/common/FadeModal'
import KeyboardShortcutHint from '../../../components/common/KeyboardShortcutHint'
+import { useResponsiveModal } from '../../../hooks/useResponsiveModal'
function ConfirmationModal({ config }) {
+ const { ResponsiveModal } = useResponsiveModal()
const [showKeyboardShortcuts, setShowKeyboardShortcuts] = useState(false)
const handleAction = useCallback(
@@ -70,7 +71,7 @@ function ConfirmationModal({ config }) {
}, [config?.isOpen, handleAction])
return (
-
{config?.title}
-
{config?.message}
@@ -90,7 +90,7 @@ function ConfirmationModal({ config }) {
handleAction(true)
}}
fullWidth
- color={config.color ? config.color : 'primary'}
+ color={config?.color || 'primary'}
endDecorator={
}
@@ -110,7 +110,7 @@ function ConfirmationModal({ config }) {
{config?.cancelText}
-
+
)
}
export default ConfirmationModal
diff --git a/src/views/Modals/Inputs/CreateThingModal.jsx b/src/views/Modals/Inputs/CreateThingModal.jsx
index a4863f7..c2a7329 100644
--- a/src/views/Modals/Inputs/CreateThingModal.jsx
+++ b/src/views/Modals/Inputs/CreateThingModal.jsx
@@ -10,9 +10,10 @@ import {
Typography,
} from '@mui/joy'
import { useEffect, useState } from 'react'
-import FadeModal from '../../../components/common/FadeModal'
function CreateThingModal({ isOpen, onClose, onSave, currentThing }) {
+ const { ResponsiveModal } = useResponsiveModal()
+
const [name, setName] = useState(currentThing?.name || '')
const [type, setType] = useState(currentThing?.type || 'number')
const [state, setState] = useState(currentThing?.state || '')
@@ -58,7 +59,7 @@ function CreateThingModal({ isOpen, onClose, onSave, currentThing }) {
}
return (
-
+
{currentThing?.id ? 'Edit' : 'Create'} Thing
@@ -131,7 +132,7 @@ function CreateThingModal({ isOpen, onClose, onSave, currentThing }) {
{currentThing?.id ? 'Cancel' : 'Close'}
-
+
)
}
export default CreateThingModal
diff --git a/src/views/Modals/Inputs/DateModal.jsx b/src/views/Modals/Inputs/DateModal.jsx
index 27dbf6e..45db330 100644
--- a/src/views/Modals/Inputs/DateModal.jsx
+++ b/src/views/Modals/Inputs/DateModal.jsx
@@ -1,8 +1,10 @@
import { Box, Button, Input, Typography } from '@mui/joy'
import { useState } from 'react'
-import FadeModal from '../../../components/common/FadeModal'
+import { useResponsiveModal } from '../../../hooks/useResponsiveModal'
function DateModal({ isOpen, onClose, onSave, current, title }) {
+ const { ResponsiveModal } = useResponsiveModal()
+
const [date, setDate] = useState(
current ? new Date(current).toISOString().split('T')[0] : null,
)
@@ -13,7 +15,7 @@ function DateModal({ isOpen, onClose, onSave, current, title }) {
}
return (
-
+
{title}
-
+
)
}
export default DateModal
diff --git a/src/views/Modals/Inputs/LabelModal.jsx b/src/views/Modals/Inputs/LabelModal.jsx
index df631dd..f6f675e 100644
--- a/src/views/Modals/Inputs/LabelModal.jsx
+++ b/src/views/Modals/Inputs/LabelModal.jsx
@@ -8,15 +8,17 @@ import {
Typography,
} from '@mui/joy'
import { useEffect, useState } from 'react'
-import FadeModal from '../../../components/common/FadeModal'
import { useQueryClient } from '@tanstack/react-query'
+import { useResponsiveModal } from '../../../hooks/useResponsiveModal.js'
import { useNotification } from '../../../service/NotificationProvider.jsx'
import LABEL_COLORS from '../../../utils/Colors.jsx'
import { CreateLabel, UpdateLabel } from '../../../utils/Fetcher'
import { useLabels } from '../../Labels/LabelQueries'
function LabelModal({ isOpen, onClose, label }) {
+ const { ResponsiveModal } = useResponsiveModal()
+
const [labelName, setLabelName] = useState('')
const [color, setColor] = useState('')
const [error, setError] = useState('')
@@ -89,7 +91,7 @@ function LabelModal({ isOpen, onClose, label }) {
}
return (
-
+
{label ? 'Edit Label' : 'Add Label'}
@@ -159,7 +161,7 @@ function LabelModal({ isOpen, onClose, label }) {
Cancel
-
+
)
}
diff --git a/src/views/Modals/Inputs/PasswordChangeModal.jsx b/src/views/Modals/Inputs/PasswordChangeModal.jsx
index 793cbdd..106c073 100644
--- a/src/views/Modals/Inputs/PasswordChangeModal.jsx
+++ b/src/views/Modals/Inputs/PasswordChangeModal.jsx
@@ -7,9 +7,11 @@ import {
Typography,
} from '@mui/joy'
import React, { useEffect } from 'react'
-import FadeModal from '../../../components/common/FadeModal'
+import { useResponsiveModal } from '../../../hooks/useResponsiveModal'
function PassowrdChangeModal({ isOpen, onClose }) {
+ const { ResponsiveModal } = useResponsiveModal()
+
const [password, setPassword] = React.useState('')
const [confirmPassword, setConfirmPassword] = React.useState('')
const [passwordError, setPasswordError] = React.useState(false)
@@ -39,7 +41,7 @@ function PassowrdChangeModal({ isOpen, onClose }) {
}
return (
-
+
Change Password
@@ -108,7 +110,7 @@ function PassowrdChangeModal({ isOpen, onClose }) {
Cancel
-
+
)
}
export default PassowrdChangeModal
diff --git a/src/views/Modals/Inputs/SelectModal.jsx b/src/views/Modals/Inputs/SelectModal.jsx
index 7f5936d..d595b9a 100644
--- a/src/views/Modals/Inputs/SelectModal.jsx
+++ b/src/views/Modals/Inputs/SelectModal.jsx
@@ -1,6 +1,6 @@
import { Box, Button, Option, Select, Typography } from '@mui/joy'
import React from 'react'
-import FadeModal from '../../../components/common/FadeModal'
+import { useResponsiveModal } from '../../../hooks/useResponsiveModal'
function SelectModal({
isOpen,
@@ -11,6 +11,8 @@ function SelectModal({
displayKey,
placeholder,
}) {
+ const { ResponsiveModal } = useResponsiveModal()
+
const [selected, setSelected] = React.useState(null)
const handleSave = () => {
onSave(options.find(item => item.id === selected))
@@ -18,7 +20,7 @@ function SelectModal({
}
return (
-
+
{title}
+
)
}
export default SelectModal
diff --git a/src/views/Modals/Inputs/TextModal.jsx b/src/views/Modals/Inputs/TextModal.jsx
index 6e2f739..d682ad3 100644
--- a/src/views/Modals/Inputs/TextModal.jsx
+++ b/src/views/Modals/Inputs/TextModal.jsx
@@ -1,6 +1,6 @@
import { Box, Button, Textarea, Typography } from '@mui/joy'
import { useState } from 'react'
-import FadeModal from '../../../components/common/FadeModal'
+import { useResponsiveModal } from '../../../hooks/useResponsiveModal'
function TextModal({
isOpen,
@@ -11,6 +11,8 @@ function TextModal({
okText,
cancelText,
}) {
+ const { ResponsiveModal } = useResponsiveModal()
+
const [text, setText] = useState(current)
const handleSave = () => {
@@ -19,7 +21,7 @@ function TextModal({
}
return (
-
+
{title}
+
)
}
export default TextModal
diff --git a/src/views/Modals/Inputs/TimerEditModal.jsx b/src/views/Modals/Inputs/TimerEditModal.jsx
index 40b85ea..fa27ec8 100644
--- a/src/views/Modals/Inputs/TimerEditModal.jsx
+++ b/src/views/Modals/Inputs/TimerEditModal.jsx
@@ -12,7 +12,7 @@ import {
} from '@mui/joy'
import moment from 'moment'
import { useEffect, useState } from 'react'
-import FadeModal from '../../../components/common/FadeModal'
+import { useResponsiveModal } from '../../../hooks/useResponsiveModal'
import { useNotification } from '../../../service/NotificationProvider'
import {
DeleteTimeSession,
@@ -22,6 +22,8 @@ import {
import ConfirmationModal from './ConfirmationModal'
const TimerEditModal = ({ isOpen, onClose, choreId, onTimerUpdate }) => {
+ const { ResponsiveModal } = useResponsiveModal()
+
const [timerData, setTimerData] = useState(null)
const [loading, setLoading] = useState(false)
const [editingSessions, setEditingSessions] = useState({})
@@ -310,7 +312,12 @@ const TimerEditModal = ({ isOpen, onClose, choreId, onTimerUpdate }) => {
return (
<>
-
+
Timer Details
{loading && (
@@ -976,7 +983,7 @@ const TimerEditModal = ({ isOpen, onClose, choreId, onTimerUpdate }) => {
)}
-
+
>
diff --git a/src/views/Modals/Inputs/UserDeletionModal.jsx b/src/views/Modals/Inputs/UserDeletionModal.jsx
index b48e14f..b568a6d 100644
--- a/src/views/Modals/Inputs/UserDeletionModal.jsx
+++ b/src/views/Modals/Inputs/UserDeletionModal.jsx
@@ -13,10 +13,11 @@ import {
import { data } from 'autoprefixer'
import { useCallback, useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
-import FadeModal from '../../../components/common/FadeModal'
+import { useResponsiveModal } from '../../../hooks/useResponsiveModal'
import { CheckUserDeletion, DeleteUser } from '../../../utils/Fetcher'
function UserDeletionModal({ isOpen, onClose, userProfile }) {
+ const { ResponsiveModal } = useResponsiveModal()
const Navigate = useNavigate()
const [step, setStep] = useState(1) // 1: Warning, 2: Transfer, 3: Confirm
const [password, setPassword] = useState('')
@@ -340,11 +341,11 @@ function UserDeletionModal({ isOpen, onClose, userProfile }) {
}
return (
- handleClose(false)}
size='md'
- unmountDelay={250}
+ title='Delete Account'
>
{loading && step === 1 ? (
+
)
}
diff --git a/src/views/Modals/Inputs/UserModal.jsx b/src/views/Modals/Inputs/UserModal.jsx
index e37a28a..6009267 100644
--- a/src/views/Modals/Inputs/UserModal.jsx
+++ b/src/views/Modals/Inputs/UserModal.jsx
@@ -1,9 +1,11 @@
import { Avatar, Box, Button, List, ListItem, Typography } from '@mui/joy'
-import FadeModal from '../../../components/common/FadeModal'
+import { useResponsiveModal } from '../../../hooks/useResponsiveModal'
const UserModal = ({ isOpen, performers = [], onSelect, onClose }) => {
+ const { ResponsiveModal } = useResponsiveModal()
+
return (
-
+
Select User
@@ -38,7 +40,7 @@ const UserModal = ({ isOpen, performers = [], onSelect, onClose }) => {
Cancel
-
+
)
}
diff --git a/src/views/Modals/Inputs/WriteNFCModal.jsx b/src/views/Modals/Inputs/WriteNFCModal.jsx
index 164cce9..691b5d3 100644
--- a/src/views/Modals/Inputs/WriteNFCModal.jsx
+++ b/src/views/Modals/Inputs/WriteNFCModal.jsx
@@ -1,9 +1,11 @@
import { CopyAll } from '@mui/icons-material'
import { Box, Button, Checkbox, Input, ListItem, Typography } from '@mui/joy'
import { useState } from 'react'
-import FadeModal from '../../../components/common/FadeModal'
+import { useResponsiveModal } from '../../../hooks/useResponsiveModal'
function WriteNFCModal({ config }) {
+ const { ResponsiveModal } = useResponsiveModal()
+
const [nfcStatus, setNfcStatus] = useState('idle') // 'idle', 'writing', 'success', 'error'
const [errorMessage, setErrorMessage] = useState('')
const [isAutoCompleteWhenScan, setIsAutoCompleteWhenScan] = useState(false)
@@ -52,7 +54,7 @@ function WriteNFCModal({ config }) {
return url
}
return (
-
+
{nfcStatus === 'success' ? 'Success!' : 'Write to NFC'}
@@ -106,7 +108,7 @@ function WriteNFCModal({ config }) {
>
)}
-
+
)
}
diff --git a/src/views/Modals/RedeemPointsModal.jsx b/src/views/Modals/RedeemPointsModal.jsx
index dd92d6a..17ac2fc 100644
--- a/src/views/Modals/RedeemPointsModal.jsx
+++ b/src/views/Modals/RedeemPointsModal.jsx
@@ -14,10 +14,12 @@ import {
Typography,
} from '@mui/joy'
import { useEffect, useState } from 'react'
-import FadeModal from '../../components/common/FadeModal'
+
import { resolvePhotoURL } from '../../utils/Helpers.jsx'
function RedeemPointsModal({ config }) {
+ const { ResponsiveModal } = useResponsiveModal()
+
const [points, setPoints] = useState(0)
const predefinedPoints = [1, 5, 10, 25, 50]
@@ -50,7 +52,7 @@ function RedeemPointsModal({ config }) {
const canRedeem = points > 0 && points <= config.available
return (
-
+
{/* Header Section */}
@@ -242,7 +244,7 @@ function RedeemPointsModal({ config }) {
-
+
)
}
diff --git a/src/views/components/AddTaskModal.jsx b/src/views/components/AddTaskModal.jsx
index 8d3b159..f0c022c 100644
--- a/src/views/components/AddTaskModal.jsx
+++ b/src/views/components/AddTaskModal.jsx
@@ -4,12 +4,13 @@ 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 { useResponsiveModal } from '../../hooks/useResponsiveModal'
import { useCreateChore } from '../../queries/ChoreQueries'
import { useCircleMembers, useUserProfile } from '../../queries/UserQueries'
import { isPlusAccount } from '../../utils/Helpers'
import { useLabels } from '../Labels/LabelQueries'
import {
+ parseAssignees,
parseDueDate,
parseLabels,
parsePriority,
@@ -41,6 +42,7 @@ const getDefaultNotification = () => {
}
const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
+ const { ResponsiveModal } = useResponsiveModal()
const { data: userLabels, isLoading: userLabelsLoading } = useLabels()
const { data: circleMembers, isLoading: isCircleMembersLoading } =
useCircleMembers()
@@ -69,7 +71,7 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
const [hasDescription, setHasDescription] = useState(false)
const [hasSubTasks, setHasSubTasks] = useState(false)
const [hasNotifications, setHasNotifications] = useState(false)
- const [showKeyboardShortcuts, setShowKeyboardShortcuts] = useState(true)
+ const [showKeyboardShortcuts, setShowKeyboardShortcuts] = useState(false)
// set showKeyboardShortcuts true as soon as the user hold ctrl or cmd key:
useEffect(() => {
@@ -301,32 +303,34 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
cleanedSentence = repeat.cleanedSentence
}
// Parse assignees using circle members
- // const circleMembersList = circleMembers?.res || []
- // const assigneesForParsing = circleMembersList.map(member => ({
- // userId: member.userId,
- // username:
- // member.username ||
- // member.displayName?.toLowerCase().replace(/\s+/g, ''),
- // displayName: member.displayName,
- // name: member.displayName,
- // id: member.userId,
- // }))
+ const circleMembersList = circleMembers?.res || []
+ const assigneesForParsing = circleMembersList.map(member => ({
+ userId: member.userId,
+ username:
+ member.username ||
+ member.displayName?.toLowerCase().replace(/\s+/g, ''),
+ displayName: member.displayName,
+ name: member.displayName,
+ id: member.userId,
+ }))
- // const assigneesResult = parseAssignees(sentence, assigneesForParsing)
- // if (assigneesResult.result) {
- // cleanedSentence = assigneesResult.cleanedSentence
- // setAssignees(
- // assigneesResult.result.map(assignee => ({
- // userId: assignee.userId,
- // })),
- // )
- // } else {
- // setAssignees([
- // {
- // userId: userProfile.id,
- // },
- // ])
- // }
+ const assigneesResult = parseAssignees(sentence, assigneesForParsing)
+ if (assigneesResult.result) {
+ cleanedSentence = assigneesResult.cleanedSentence
+ console.log('CLEANED', cleanedSentence)
+
+ setAssignees(
+ assigneesResult.result.map(assignee => ({
+ userId: assignee.userId,
+ })),
+ )
+ } else {
+ setAssignees([
+ {
+ userId: userProfile.id,
+ },
+ ])
+ }
// Parse due date
const dueDateParsed = parseDueDate(sentence, chrono)
let dueDateHighlight = null
@@ -462,13 +466,13 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
}
return (
-
- Create new task
Experimental Feature
@@ -772,7 +776,7 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
)}
-
+
)
}