feat: implement push notification registration and nudge feature; enhance user settings and notification handling
This commit is contained in:
158
src/views/Modals/Inputs/NudgeModal.jsx
Normal file
158
src/views/Modals/Inputs/NudgeModal.jsx
Normal file
@@ -0,0 +1,158 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
Switch,
|
||||
Textarea,
|
||||
Typography,
|
||||
} from '@mui/joy'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import KeyboardShortcutHint from '../../../components/common/KeyboardShortcutHint'
|
||||
import { useResponsiveModal } from '../../../hooks/useResponsiveModal'
|
||||
|
||||
function NudgeModal({ config }) {
|
||||
const { ResponsiveModal } = useResponsiveModal()
|
||||
const [showKeyboardShortcuts, setShowKeyboardShortcuts] = useState(false)
|
||||
const [message, setMessage] = useState('')
|
||||
const [notifyAllAssignees, setNotifyAllAssignees] = useState(false)
|
||||
|
||||
const handleAction = useCallback(
|
||||
isConfirmed => {
|
||||
if (isConfirmed) {
|
||||
config.onConfirm({ choreId: config.choreId, message, notifyAllAssignees })
|
||||
} else {
|
||||
config.onClose()
|
||||
}
|
||||
},
|
||||
[config, message, notifyAllAssignees],
|
||||
)
|
||||
|
||||
// Reset form when modal opens
|
||||
useEffect(() => {
|
||||
if (config?.isOpen) {
|
||||
setMessage('')
|
||||
setNotifyAllAssignees(false)
|
||||
}
|
||||
}, [config?.isOpen])
|
||||
|
||||
// Keyboard shortcuts for nudge modal
|
||||
useEffect(() => {
|
||||
const handleKeyDown = event => {
|
||||
if (!config?.isOpen) return
|
||||
|
||||
// Show keyboard shortcuts when Ctrl/Cmd is pressed
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
setShowKeyboardShortcuts(true)
|
||||
}
|
||||
|
||||
// Ctrl/Cmd + Y for confirm
|
||||
if ((event.ctrlKey || event.metaKey) && event.key === 'y') {
|
||||
event.preventDefault()
|
||||
handleAction(true)
|
||||
return
|
||||
}
|
||||
|
||||
// Ctrl/Cmd + X for cancel
|
||||
if ((event.ctrlKey || event.metaKey) && event.key === 'x') {
|
||||
event.preventDefault()
|
||||
handleAction(false)
|
||||
return
|
||||
}
|
||||
|
||||
// Escape key for cancel
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault()
|
||||
handleAction(false)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyUp = event => {
|
||||
if (!event.ctrlKey && !event.metaKey) {
|
||||
setShowKeyboardShortcuts(false)
|
||||
}
|
||||
}
|
||||
|
||||
if (config?.isOpen) {
|
||||
document.addEventListener('keydown', handleKeyDown)
|
||||
document.addEventListener('keyup', handleKeyUp)
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleKeyDown)
|
||||
document.removeEventListener('keyup', handleKeyUp)
|
||||
}
|
||||
}, [config?.isOpen, handleAction])
|
||||
|
||||
return (
|
||||
<ResponsiveModal
|
||||
open={config?.isOpen}
|
||||
onClose={config?.onClose}
|
||||
size='md'
|
||||
unmountDelay={250}
|
||||
>
|
||||
<Typography level='h4' mb={2}>
|
||||
Send Nudge
|
||||
</Typography>
|
||||
|
||||
<Typography level='body-md' mb={2}>
|
||||
Send a gentle reminder to the assignee about this task. You can
|
||||
customize the message and choose who gets notified.
|
||||
</Typography>
|
||||
|
||||
<FormControl mb={2}>
|
||||
<FormLabel>Custom Message (optional)</FormLabel>
|
||||
<Textarea
|
||||
placeholder='Add a personal message with your nudge...'
|
||||
value={message}
|
||||
onChange={e => setMessage(e.target.value)}
|
||||
minRows={3}
|
||||
maxRows={5}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormControl orientation='horizontal' sx={{ mb: 3 }}>
|
||||
<Box sx={{ flex: 1 }}>
|
||||
<FormLabel>Notify All Assignees</FormLabel>
|
||||
<Typography level='body-sm' color='text.secondary'>
|
||||
If enabled, all members who can see this task will be notified.
|
||||
Otherwise, only the assigned person will receive the nudge.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Switch
|
||||
checked={notifyAllAssignees}
|
||||
onChange={e => setNotifyAllAssignees(e.target.checked)}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<Box display={'flex'} justifyContent={'space-around'} gap={1}>
|
||||
<Button
|
||||
size='lg'
|
||||
onClick={() => handleAction(true)}
|
||||
fullWidth
|
||||
color='primary'
|
||||
endDecorator={
|
||||
<KeyboardShortcutHint shortcut='Y' show={showKeyboardShortcuts} />
|
||||
}
|
||||
>
|
||||
Send Nudge
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
size='lg'
|
||||
onClick={() => handleAction(false)}
|
||||
variant='outlined'
|
||||
fullWidth
|
||||
endDecorator={
|
||||
<KeyboardShortcutHint shortcut='X' show={showKeyboardShortcuts} />
|
||||
}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</Box>
|
||||
</ResponsiveModal>
|
||||
)
|
||||
}
|
||||
|
||||
export default NudgeModal
|
||||
@@ -12,7 +12,7 @@ const UserModal = ({ isOpen, performers = [], onSelect, onClose }) => {
|
||||
<List sx={{ mb: 2 }}>
|
||||
{performers.map(user => (
|
||||
<ListItem
|
||||
key={user.id}
|
||||
key={user.userId}
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
'&:hover': {
|
||||
|
||||
Reference in New Issue
Block a user