Files
gallery/crmDashboard/src/features/sessions/ScheduleMessageModal.jsx
T
2026-06-16 22:55:10 -06:00

234 lines
7.1 KiB
React

import { useState } from 'react'
import {
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Button,
TextField,
Box,
Typography,
Alert,
IconButton,
Divider,
CircularProgress,
} from '@mui/material'
import EditIcon from '@mui/icons-material/Edit'
import DeleteIcon from '@mui/icons-material/Delete'
import { LocalizationProvider, DateTimePicker } from '@mui/x-date-pickers'
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'
import dayjs from 'dayjs'
import {
useScheduledMessages,
useCreateScheduledMessage,
useUpdateScheduledMessage,
useDeleteScheduledMessage,
} from './api'
function formatDate(d) {
try {
return new Date(d).toLocaleString()
} catch {
return d
}
}
export default function ScheduleMessageModal({ session, onClose }) {
const [message, setMessage] = useState('')
const [scheduledAt, setScheduledAt] = useState(() => dayjs().add(1, 'hour'))
const [editingId, setEditingId] = useState(null)
const [error, setError] = useState('')
const [success, setSuccess] = useState('')
const { data: scheduledMessages, isLoading } = useScheduledMessages(session?.id)
const createMutation = useCreateScheduledMessage()
const updateMutation = useUpdateScheduledMessage()
const deleteMutation = useDeleteScheduledMessage()
const handleClose = () => {
setMessage('')
setScheduledAt(dayjs().add(1, 'hour'))
setEditingId(null)
setError('')
setSuccess('')
onClose()
}
const handleEdit = (msg) => {
setMessage(msg.message)
setScheduledAt(dayjs(msg.scheduled_at))
setEditingId(msg.id)
setError('')
setSuccess('')
}
const handleCancelEdit = () => {
setMessage('')
setScheduledAt(dayjs().add(1, 'hour'))
setEditingId(null)
setError('')
setSuccess('')
}
const handleSave = async () => {
setError('')
setSuccess('')
if (!message.trim()) {
setError('El mensaje no puede estar vacío')
return
}
if (!session) return
const isoDate = scheduledAt.toISOString()
try {
if (editingId) {
await updateMutation.mutateAsync({
id: editingId,
sessionId: session.id,
message: message.trim(),
scheduledAt: isoDate,
})
setSuccess('Mensaje programado actualizado')
} else {
await createMutation.mutateAsync({
sessionId: session.id,
message: message.trim(),
scheduledAt: isoDate,
})
setSuccess('Mensaje programado creado')
}
setMessage('')
setScheduledAt(dayjs().add(1, 'hour'))
setEditingId(null)
} catch (err) {
setError(err.message)
}
}
const handleDelete = async (id) => {
if (!session) return
if (!window.confirm('¿Eliminar este mensaje programado?')) return
setError('')
setSuccess('')
try {
await deleteMutation.mutateAsync({ id, sessionId: session.id })
setSuccess('Mensaje programado eliminado')
} catch (err) {
setError(err.message)
}
}
return (
<Dialog open={!!session} onClose={handleClose} maxWidth="sm" fullWidth>
<DialogTitle>
Programar mensaje: {session?.name || session?.phone || session?.id}
</DialogTitle>
<DialogContent>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, mt: 1 }}>
<DateTimePicker
label="Fecha y hora"
value={scheduledAt}
onChange={(v) => setScheduledAt(v)}
ampm={false}
slotProps={{
textField: {
fullWidth: true,
size: 'small',
readOnly: true,
},
}}
disablePast
/>
<TextField
fullWidth
size="small"
label="Mensaje"
multiline
minRows={3}
maxRows={6}
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Escribe el mensaje a programar..."
/>
{error && <Alert severity="error">{error}</Alert>}
{success && <Alert severity="success">{success}</Alert>}
<Box sx={{ display: 'flex', gap: 1, justifyContent: 'flex-end' }}>
{editingId && (
<Button onClick={handleCancelEdit} color="inherit">
Cancelar edición
</Button>
)}
<Button
variant="contained"
onClick={handleSave}
disabled={!message.trim() || createMutation.isPending || updateMutation.isPending}
>
{createMutation.isPending || updateMutation.isPending ? (
<CircularProgress size={20} color="inherit" />
) : editingId ? (
'Guardar'
) : (
'Programar'
)}
</Button>
</Box>
</Box>
</LocalizationProvider>
<Divider sx={{ my: 2 }} />
<Typography variant="subtitle2" gutterBottom>
Mensajes programados pendientes
</Typography>
{isLoading ? (
<Box sx={{ display: 'flex', justifyContent: 'center', py: 2 }}>
<CircularProgress size={24} />
</Box>
) : scheduledMessages?.length === 0 ? (
<Typography variant="body2" color="text.secondary">
No hay mensajes programados pendientes.
</Typography>
) : (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
{scheduledMessages?.map((msg) => (
<Box
key={msg.id}
sx={{
p: 1.5,
border: '1px solid',
borderColor: 'divider',
borderRadius: 1,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'flex-start',
gap: 1,
}}
>
<Box sx={{ flex: 1, minWidth: 0 }}>
<Typography variant="body2" sx={{ wordBreak: 'break-word' }}>
{msg.message}
</Typography>
<Typography variant="caption" color="text.secondary">
{formatDate(msg.scheduled_at)}
</Typography>
</Box>
<Box sx={{ display: 'flex', gap: 0.5 }}>
<IconButton size="small" onClick={() => handleEdit(msg)} disabled={deleteMutation.isPending}>
<EditIcon fontSize="small" />
</IconButton>
<IconButton size="small" onClick={() => handleDelete(msg.id)} disabled={deleteMutation.isPending}>
<DeleteIcon fontSize="small" color="error" />
</IconButton>
</Box>
</Box>
))}
</Box>
)}
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cerrar</Button>
</DialogActions>
</Dialog>
)
}