feat: recordatorios periódicos; supervisor invita auxiliares; owner edita usuarios; precios planes y MSI
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { DashboardShell } from '@/components/layouts/dashboard-shell';
|
||||
import { Card, CardContent, CardHeader, CardTitle, Button, Input, Label } from '@horux/shared-ui';
|
||||
import { Card, CardContent, CardHeader, CardTitle, Button, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@horux/shared-ui';
|
||||
import { useEventos, useCreateEvento, useUpdateEvento, useDeleteEvento } from '@/lib/hooks/use-calendario';
|
||||
import { useAuthStore } from '@/stores/auth-store';
|
||||
import {
|
||||
@@ -42,6 +42,8 @@ interface RecordatorioForm {
|
||||
fechaLimite: string;
|
||||
notas: string;
|
||||
privado: boolean;
|
||||
recurrencia: 'unica' | 'mensual' | 'bimestral' | 'trimestral' | 'anual';
|
||||
fechaFin: string;
|
||||
}
|
||||
|
||||
const emptyForm: RecordatorioForm = {
|
||||
@@ -50,6 +52,8 @@ const emptyForm: RecordatorioForm = {
|
||||
fechaLimite: '',
|
||||
notas: '',
|
||||
privado: false,
|
||||
recurrencia: 'unica',
|
||||
fechaFin: '',
|
||||
};
|
||||
|
||||
export default function CalendarioPage() {
|
||||
@@ -100,6 +104,8 @@ export default function CalendarioPage() {
|
||||
fechaLimite: evento.fechaLimite,
|
||||
notas: evento.notas || '',
|
||||
privado: (evento as any).privado ?? false,
|
||||
recurrencia: (evento.recurrencia as RecordatorioForm['recurrencia']) || 'unica',
|
||||
fechaFin: '', // La fecha fin no se edita desde el calendario; se mantiene la original
|
||||
});
|
||||
setShowForm(true);
|
||||
};
|
||||
@@ -113,15 +119,19 @@ export default function CalendarioPage() {
|
||||
data: { titulo: form.titulo, descripcion: form.descripcion, fechaLimite: form.fechaLimite, notas: form.notas, privado: form.privado } as any,
|
||||
});
|
||||
} else {
|
||||
await createEvento.mutateAsync({
|
||||
const payload: any = {
|
||||
titulo: form.titulo,
|
||||
descripcion: form.descripcion,
|
||||
tipo: 'custom',
|
||||
fechaLimite: form.fechaLimite,
|
||||
recurrencia: 'unica',
|
||||
recurrencia: form.recurrencia,
|
||||
notas: form.notas,
|
||||
privado: form.privado,
|
||||
} as any);
|
||||
};
|
||||
if (form.recurrencia !== 'unica' && form.fechaFin) {
|
||||
payload.fechaFin = form.fechaFin;
|
||||
}
|
||||
await createEvento.mutateAsync(payload);
|
||||
}
|
||||
setShowForm(false);
|
||||
setForm(emptyForm);
|
||||
@@ -131,10 +141,15 @@ export default function CalendarioPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async (id: number) => {
|
||||
if (!confirm('¿Eliminar este recordatorio?')) return;
|
||||
const handleDelete = async (evento: EventoFiscal) => {
|
||||
if (!evento.id) return;
|
||||
const esPeriodico = evento.recurrencia && evento.recurrencia !== 'unica';
|
||||
const mensaje = esPeriodico
|
||||
? 'Esto cancelará todas las ocurrencias futuras de esta serie. ¿Continuar?'
|
||||
: '¿Eliminar este recordatorio?';
|
||||
if (!confirm(mensaje)) return;
|
||||
try {
|
||||
await deleteEvento.mutateAsync(id);
|
||||
await deleteEvento.mutateAsync(evento.id);
|
||||
} catch {
|
||||
alert('Error al eliminar');
|
||||
}
|
||||
@@ -206,6 +221,44 @@ export default function CalendarioPage() {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{!editingId && (
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="recurrencia">Recurrencia</Label>
|
||||
<Select
|
||||
value={form.recurrencia}
|
||||
onValueChange={(v) => setForm({ ...form, recurrencia: v as RecordatorioForm['recurrencia'] })}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="unica">Única</SelectItem>
|
||||
<SelectItem value="mensual">Mensual</SelectItem>
|
||||
<SelectItem value="bimestral">Bimestral</SelectItem>
|
||||
<SelectItem value="trimestral">Trimestral</SelectItem>
|
||||
<SelectItem value="anual">Anual</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
{form.recurrencia !== 'unica' && (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="fechaFin">Fecha fin (opcional)</Label>
|
||||
<Input
|
||||
id="fechaFin"
|
||||
type="date"
|
||||
value={form.fechaFin}
|
||||
onChange={e => setForm({ ...form, fechaFin: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{editingId && form.recurrencia !== 'unica' && (
|
||||
<div className="text-sm text-amber-700 bg-amber-50 border border-amber-200 rounded-lg px-3 py-2">
|
||||
Este es un recordatorio periódico. Los cambios se aplicarán a todas las ocurrencias futuras.
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="descripcion">Descripción (opcional)</Label>
|
||||
<Input
|
||||
@@ -417,7 +470,7 @@ export default function CalendarioPage() {
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost" size="icon" className="h-7 w-7 text-destructive"
|
||||
onClick={() => evento.id && handleDelete(evento.id)}
|
||||
onClick={() => handleDelete(evento)}
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user