fix/appoiments #67
@ -121,6 +121,40 @@ export default function AgendamentoPage() {
|
||||
}
|
||||
};
|
||||
|
||||
// Mapeia cor do calendário -> status da API
|
||||
const statusFromColor = (color?: string) => {
|
||||
switch ((color || "").toLowerCase()) {
|
||||
case "green": return "confirmed";
|
||||
case "orange": return "pending";
|
||||
case "red": return "canceled";
|
||||
default: return "requested";
|
||||
}
|
||||
};
|
||||
|
||||
// Envia atualização para a API e atualiza UI
|
||||
const handleEventUpdate = async (id: string, partial: Partial<Event>) => {
|
||||
try {
|
||||
const payload: any = {};
|
||||
if (partial.startTime) payload.scheduled_at = partial.startTime.toISOString();
|
||||
if (partial.startTime && partial.endTime) {
|
||||
const minutes = Math.max(1, Math.round((partial.endTime.getTime() - partial.startTime.getTime()) / 60000));
|
||||
payload.duration_minutes = minutes;
|
||||
}
|
||||
if (partial.color) payload.status = statusFromColor(partial.color);
|
||||
if (typeof partial.description === "string") payload.notes = partial.description;
|
||||
|
||||
if (Object.keys(payload).length) {
|
||||
const api = await import('@/lib/api');
|
||||
await api.atualizarAgendamento(id, payload);
|
||||
}
|
||||
|
||||
// Otimista: reflete mudanças locais
|
||||
setManagerEvents((prev) => prev.map((e) => (e.id === id ? { ...e, ...partial } : e)));
|
||||
} catch (e) {
|
||||
console.warn("[Calendário] Falha ao atualizar agendamento na API:", e);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-row bg-background">
|
||||
<div className="flex w-full flex-col">
|
||||
@ -164,7 +198,11 @@ export default function AgendamentoPage() {
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-full min-h-[70vh]">
|
||||
<EventManager events={managerEvents} className="compact-event-manager" />
|
||||
<EventManager
|
||||
events={managerEvents}
|
||||
className="compact-event-manager"
|
||||
onEventUpdate={handleEventUpdate}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -515,7 +515,7 @@ export function EventManager({
|
||||
|
||||
{/* Event Dialog */}
|
||||
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
|
||||
<DialogContent className="max-w-md max-h[90vh] overflow-y-auto">
|
||||
<DialogContent className="max-w-md max-h-[90vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{isCreating ? "Criar Evento" : "Detalhes do Evento"}</DialogTitle>
|
||||
<DialogDescription>
|
||||
@ -528,7 +528,7 @@ export function EventManager({
|
||||
<Label htmlFor="title">Título</Label>
|
||||
<Input
|
||||
id="title"
|
||||
value={isCreating ? newEvent.title : selectedEvent?.title}
|
||||
value={isCreating ? (newEvent.title ?? "") : (selectedEvent?.title ?? "")}
|
||||
onChange={(e) =>
|
||||
isCreating
|
||||
? setNewEvent((prev) => ({ ...prev, title: e.target.value }))
|
||||
@ -542,7 +542,7 @@ export function EventManager({
|
||||
<Label htmlFor="description">Descrição</Label>
|
||||
<Textarea
|
||||
id="description"
|
||||
value={isCreating ? newEvent.description : selectedEvent?.description}
|
||||
value={isCreating ? (newEvent.description ?? "") : (selectedEvent?.description ?? "")}
|
||||
onChange={(e) =>
|
||||
isCreating
|
||||
? setNewEvent((prev) => ({
|
||||
@ -972,7 +972,7 @@ function WeekView({
|
||||
getColorClasses: (color: string) => { bg: string; text: string }
|
||||
}) {
|
||||
const startOfWeek = new Date(currentDate)
|
||||
startOfWeek.setDate(currentDate.getDay())
|
||||
startOfWeek.setDate(currentDate.getDate() - currentDate.getDay())
|
||||
|
||||
const weekDays = Array.from({ length: 7 }, (_, i) => {
|
||||
const day = new Date(startOfWeek)
|
||||
@ -980,7 +980,30 @@ function WeekView({
|
||||
return day
|
||||
})
|
||||
|
||||
const hours = Array.from({ length: 24 }, (_, i) => i)
|
||||
// NOVO: limita intervalo de horas ao 1º e último evento da semana
|
||||
const [startHour, endHour] = React.useMemo(() => {
|
||||
let minH = Infinity
|
||||
let maxH = -Infinity
|
||||
for (const ev of events) {
|
||||
const d = ev.startTime
|
||||
const sameWeekDay = weekDays.some(wd =>
|
||||
d.getFullYear() === wd.getFullYear() &&
|
||||
d.getMonth() === wd.getMonth() &&
|
||||
d.getDate() === wd.getDate()
|
||||
)
|
||||
if (!sameWeekDay) continue
|
||||
minH = Math.min(minH, d.getHours())
|
||||
maxH = Math.max(maxH, ev.endTime.getHours())
|
||||
}
|
||||
if (!isFinite(minH) || !isFinite(maxH)) return [0, 23] as const
|
||||
if (maxH < minH) maxH = minH
|
||||
return [minH, maxH] as const
|
||||
}, [events, weekDays])
|
||||
|
||||
const hours = React.useMemo(
|
||||
() => Array.from({ length: (endHour - startHour + 1) }, (_, i) => startHour + i),
|
||||
[startHour, endHour]
|
||||
)
|
||||
|
||||
const getEventsForDayAndHour = (date: Date, hour: number) => {
|
||||
return events.filter((event) => {
|
||||
@ -1071,7 +1094,26 @@ function DayView({
|
||||
onDrop: (date: Date, hour: number) => void
|
||||
getColorClasses: (color: string) => { bg: string; text: string }
|
||||
}) {
|
||||
const hours = Array.from({ length: 24 }, (_, i) => i)
|
||||
// NOVO: calcula intervalo de horas do 1º ao último evento do dia
|
||||
const [startHour, endHour] = React.useMemo(() => {
|
||||
const sameDayEvents = events.filter((ev) => {
|
||||
const d = ev.startTime
|
||||
return (
|
||||
d.getDate() === currentDate.getDate() &&
|
||||
d.getMonth() === currentDate.getMonth() &&
|
||||
d.getFullYear() === currentDate.getFullYear()
|
||||
)
|
||||
})
|
||||
if (!sameDayEvents.length) return [0, 23] as const
|
||||
const minH = Math.min(...sameDayEvents.map((e) => e.startTime.getHours()))
|
||||
const maxH = Math.max(...sameDayEvents.map((e) => e.endTime.getHours()))
|
||||
return [minH, Math.max(maxH, minH)] as const
|
||||
}, [events, currentDate])
|
||||
|
||||
const hours = React.useMemo(
|
||||
() => Array.from({ length: (endHour - startHour + 1) }, (_, i) => startHour + i),
|
||||
[startHour, endHour]
|
||||
)
|
||||
|
||||
const getEventsForHour = (hour: number) => {
|
||||
return events.filter((event) => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user