feat: детальное отображение параметров повторяющихся событий

Backend:
- Добавлено поле rule_data в EventSerializer
- get_rule_data() возвращает частоту, параметры и описание правила
- Использует rule.get_params() для получения распарсенных параметров

Frontend:
- Добавлены константы FREQUENCY_LABELS и WEEKDAY_LABELS для русификации
- Новый блок с детальной информацией о повторении в синем фоне
- Отображается частота (WEEKLY, MONTHLY и т.д.)
- Дни недели для еженедельных событий (ПН, ВТ, СР...)
- Количество повторений (count)
- Дата окончания повторения (end_recurring_period)
- Подсказка о невозможности редактирования параметров

Проблема: пользователь не видел детали повторяющихся событий.
Решение: красивый информационный блок с полной информацией о правиле.
This commit is contained in:
igor_nadein 2026-02-25 02:20:24 +03:00
parent bdfc0f247c
commit 4988f1eee7
2 changed files with 68 additions and 8 deletions

View File

@ -309,6 +309,7 @@ class EventSerializer(serializers.ModelSerializer):
calendar_name = serializers.CharField(source='calendar.name', read_only=True)
rule_description = serializers.CharField(source='rule.description', read_only=True, allow_null=True)
rule_data = serializers.SerializerMethodField()
class Meta:
model = Event
@ -322,6 +323,7 @@ class EventSerializer(serializers.ModelSerializer):
'calendar_name',
'rule',
'rule_description',
'rule_data',
'end_recurring_period',
'color_event',
'creator',
@ -330,6 +332,20 @@ class EventSerializer(serializers.ModelSerializer):
]
read_only_fields = ['id', 'created_on', 'updated_on']
def get_rule_data(self, obj):
"""Возвращает детальную информацию о правиле повторения."""
if not obj.rule:
return None
rule = obj.rule
params = rule.get_params()
return {
'frequency': rule.frequency,
'params': params,
'description': rule.description,
}
def validate(self, attrs):
"""Валидация start/end."""
start = attrs.get('start')

View File

@ -15,6 +15,28 @@ interface ViewEventDetailsModalProps {
showParticipants?: boolean;
}
// Маппинг частот на русский
const FREQUENCY_LABELS: Record<string, string> = {
YEARLY: "Каждый год",
MONTHLY: "Каждый месяц",
WEEKLY: "Каждую неделю",
DAILY: "Каждый день",
HOURLY: "Каждый час",
MINUTELY: "Каждую минуту",
SECONDLY: "Каждую секунду",
};
// Маппинг дней недели (0 = Monday в dateutil.rrule)
const WEEKDAY_LABELS: Record<number, string> = {
0: "ПН",
1: "ВТ",
2: "СР",
3: "ЧТ",
4: "ПТ",
5: "СБ",
6: "ВС",
};
export function ViewEventDetailsModal({
isOpen,
onClose,
@ -111,14 +133,36 @@ export function ViewEventDetailsModal({
</div>
{/* Recurring Info */}
{event.rule && event.end_recurring_period && (
<div className="flex items-start gap-2.5">
<Calendar size={18} className="text-gray-400 mt-0.5 flex-shrink-0" />
<div className="flex-1">
<p className="text-sm font-medium text-gray-700 mb-1">Повторение</p>
<p className="text-xs text-gray-600">
До {formatDate(event.end_recurring_period)}
</p>
{event.rule && event.rule_data && (
<div className="rounded-lg bg-blue-50 border border-blue-200 p-4 space-y-2">
<div className="flex items-center gap-2 text-blue-700 font-medium text-sm">
<Calendar size={16} />
<span>Повторяющееся событие</span>
</div>
<div className="text-sm text-blue-600 space-y-1">
<div>
Частота: <span className="font-medium">{FREQUENCY_LABELS[event.rule_data.frequency] || event.rule_data.frequency}</span>
</div>
{event.rule_data.params?.byweekday && (
<div>
Дни недели: <span className="font-medium">
{event.rule_data.params.byweekday.map((day: number) => WEEKDAY_LABELS[day]).join(", ")}
</span>
</div>
)}
{event.rule_data.params?.count && (
<div>
Повторений: <span className="font-medium">{event.rule_data.params.count}</span>
</div>
)}
{event.end_recurring_period && (
<div>
До: <span className="font-medium">{formatDate(event.end_recurring_period)}</span>
</div>
)}
</div>
<div className="text-xs text-blue-600 mt-2">
💡 Редактирование параметров повторения пока не поддерживается
</div>
</div>
)}