Corp/frontend/src/components/ViewDayEventsModal.tsx
2026-09-07 19:43:48 +03:00

141 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { Plus, Clock, Calendar } from "lucide-react";
import { Modal } from "@/components/ui";
import { resolveEventColor } from "@/lib/calendar-event-colors";
import { format } from "date-fns";
import { ru } from "date-fns/locale";
import type { CalendarListEvent } from "@/types/api";
interface ViewDayEventsModalProps {
isOpen: boolean;
onClose: () => void;
date: Date | null;
events: CalendarListEvent[];
onEventClick: (event: CalendarListEvent) => void;
onCreateEvent: () => void;
}
export function ViewDayEventsModal({
isOpen,
onClose,
date,
events,
onEventClick,
onCreateEvent,
}: ViewDayEventsModalProps) {
if (!isOpen || !date) return null;
const formattedDate = format(date, "d MMMM yyyy, EEEE", { locale: ru });
const capitalizedDate =
formattedDate.charAt(0).toUpperCase() + formattedDate.slice(1);
const dayEvents = events.filter((event) => {
const eventStart = new Date(event.start);
const eventEnd = new Date(event.end);
const selectedDay = new Date(date);
// Сбрасываем время для корректного сравнения дат
eventStart.setHours(0, 0, 0, 0);
eventEnd.setHours(0, 0, 0, 0);
selectedDay.setHours(0, 0, 0, 0);
// Проверяем, попадает ли selectedDay в диапазон [eventStart, eventEnd]
return selectedDay >= eventStart && selectedDay <= eventEnd;
});
// Сортируем события по времени начала
const sortedEvents = [...dayEvents].sort((a, b) => {
return new Date(a.start).getTime() - new Date(b.start).getTime();
});
const formatTime = (dateStr: string) => {
const date = new Date(dateStr);
return format(date, "HH:mm", { locale: ru });
};
return (
<Modal
isOpen={isOpen}
onClose={onClose}
title={`События на ${capitalizedDate}`}
size="sm"
footer={
<button
onClick={onCreateEvent}
className="app-action-primary flex w-full items-center justify-center gap-2 rounded-lg px-4 py-2.5 text-sm font-medium"
>
<Plus size={16} />
Создать событие
</button>
}
>
<div className="space-y-4">
<p className="app-text-muted text-xs">
{sortedEvents.length === 0
? "Нет событий"
: `${sortedEvents.length} ${sortedEvents.length === 1 ? "событие" : "событий"}`}
</p>
{sortedEvents.length === 0 ? (
<div className="flex flex-col items-center justify-center py-8 text-center">
<Calendar size={40} className="app-text-muted mb-2 opacity-40" />
<p className="app-text-muted mb-1 text-sm">
Нет событий в этот день
</p>
<p className="app-text-muted text-xs">Создайте новое событие</p>
</div>
) : (
<div className="space-y-2">
{sortedEvents.map((event) => (
<button
key={event.id}
onClick={() => onEventClick(event)}
className="app-surface w-full rounded-lg p-3 text-left transition hover:bg-[var(--surface-secondary)]"
>
<div className="flex items-start gap-2">
{/* Color Indicator */}
<div
className="mt-1 h-8 w-1 rounded-full flex-shrink-0"
style={{
backgroundColor: resolveEventColor(event.color_event),
}}
/>
<div className="flex-1 min-w-0">
{/* Title with recurring indicator */}
<div className="flex items-center gap-1.5 mb-1">
<h4 className="truncate text-sm font-medium text-[var(--foreground)]">
{event.title}
</h4>
{event.rule && (
<span className="app-badge app-badge-accent shrink-0 rounded px-1.5 py-0.5 text-xs">
⟲
</span>
)}
</div>
{/* Time */}
<div className="app-text-muted flex items-center gap-1 text-xs">
<Clock size={12} />
<span>
{formatTime(event.start)} - {formatTime(event.end)}
</span>
</div>
{/* Description preview */}
{event.description && (
<p className="app-text-wrap app-text-muted mt-1.5 line-clamp-2 text-xs">
{event.description}
</p>
)}
</div>
</div>
</button>
))}
</div>
)}
</div>
</Modal>
);
}