Files
donetick/src/views/Modals/Inputs/LabelModal.jsx

157 lines
4.4 KiB
JavaScript

import { Box, Button, FormControl, Input, Typography } from '@mui/joy'
import { useEffect, useState } from 'react'
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('')
const { data: userLabels = [] } = useLabels()
const queryClient = useQueryClient()
const { showError } = useNotification()
// Populate the form fields when editing
useEffect(() => {
if (label) {
setLabelName(label.name)
setColor(label.color)
} else {
setLabelName('')
setColor('')
}
setError('')
}, [label])
// Validation logic
const validateLabel = () => {
if (!labelName.trim()) {
setError('Name cannot be empty')
return false
}
if (
userLabels.some(
userLabel => userLabel.name === labelName && userLabel.id !== label?.id,
)
) {
setError('Label with this name already exists')
return false
}
if (!color) {
setError('Please select a color')
return false
}
return true
}
const handleSave = () => {
if (!validateLabel()) return
const saveLabel = label?.id && label.id !== -1 ? UpdateLabel : CreateLabel
saveLabel({
id: label?.id,
name: labelName,
color,
})
.then(res => {
if (res?.error) {
setError(res.error)
} else {
queryClient.invalidateQueries('labels')
onClose()
}
})
.catch(err => {
if (err.queued) {
showError({
title: 'Failed to save label',
message: 'Unable to save label. Please try again.',
})
} else {
showError({
title: 'Failed to save label',
message: 'Unable to save label. Please try again.',
})
}
})
}
return (
<ResponsiveModal
open={isOpen}
onClose={onClose}
size='lg'
fullWidth={true}
title={label ? 'Edit Label' : 'Add Label'}
footer={
<Box display='flex' justifyContent='space-around' mt={1}>
<Button size='lg' onClick={handleSave} fullWidth sx={{ mr: 1 }}>
{label ? 'Save Changes' : 'Add Label'}
</Button>
<Button size='lg' onClick={onClose} variant='outlined'>
Cancel
</Button>
</Box>
}
>
<Box>
<FormControl>
<Typography gutterBottom level='body-sm' alignSelf='start'>
Name
</Typography>
<Input
fullWidth
id='labelName'
value={labelName}
onChange={e => setLabelName(e.target.value)}
/>
</FormControl>
<FormControl>
<Typography gutterBottom level='body-sm' alignSelf='start'>
Color
</Typography>
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1 }}>
{LABEL_COLORS.map(colorOption => (
<Box
key={colorOption.value}
title={colorOption.name}
onClick={() => setColor(colorOption.value)}
sx={{
width: 26,
height: 26,
borderRadius: '50%',
background: colorOption.value,
cursor: 'pointer',
outline:
color === colorOption.value
? '3px solid var(--joy-palette-primary-500)'
: '2px solid transparent',
outlineOffset: '2px',
transition: 'all 0.15s ease',
flexShrink: 0,
'&:hover': { transform: 'scale(1.2)' },
}}
/>
))}
</Box>
</FormControl>
{error && (
<Typography color='warning' level='body-sm'>
{error}
</Typography>
)}
</Box>
</ResponsiveModal>
)
}
export default LabelModal