From 32aad802b96362d5b8fe81d9009ee8f32dd1fa9c Mon Sep 17 00:00:00 2001
From: Primakov Alexandr Alexandrovich <primakov.pro@yandex.ru>
Date: Wed, 26 Mar 2025 23:20:25 +0300
Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?=
 =?UTF-8?q?=D0=BD=D1=8B=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B5=20=D0=B2=D1=80?=
 =?UTF-8?q?=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD=D1=8B=D0=B5=20=D1=81=D0=BB=D0=BE?=
 =?UTF-8?q?=D1=82=D1=8B=20=D0=B8=20=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B5?=
 =?UTF-8?q?=D0=BD=D0=B0=20=D1=84=D0=BE=D1=80=D0=BC=D0=B0=20=D0=B2=D1=8B?=
 =?UTF-8?q?=D0=B1=D0=BE=D1=80=D0=B0=20=D0=B4=D0=B0=D1=82=D1=8B=20=D0=B8=20?=
 =?UTF-8?q?=D0=B2=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=B8=20=D0=B4=D0=BB=D1=8F?=
 =?UTF-8?q?=20=D1=83=D1=80=D0=BE=D0=BA=D0=BE=D0=B2.=20=D0=A0=D0=B5=D0=B0?=
 =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D1=8B=20=D1=84=D1=83?=
 =?UTF-8?q?=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D0=B3?=
 =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B2=D1=80?=
 =?UTF-8?q?=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD=D1=8B=D1=85=20=D1=81=D0=BB=D0=BE?=
 =?UTF-8?q?=D1=82=D0=BE=D0=B2=20=D0=B8=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87?=
 =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=81=D0=BB=D0=B5=D0=B4=D1=83=D1=8E?=
 =?UTF-8?q?=D1=89=D0=B5=D0=B3=D0=BE=20=D0=B4=D0=BE=D1=81=D1=82=D1=83=D0=BF?=
 =?UTF-8?q?=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B2=D1=80=D0=B5=D0=BC=D0=B5=D0=BD?=
 =?UTF-8?q?=D0=B8.=20=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD?=
 =?UTF-8?q?=D1=8B=20=D0=BB=D0=BE=D0=BA=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86?=
 =?UTF-8?q?=D0=B8=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D0=BD=D0=BE=D0=B2=D1=8B?=
 =?UTF-8?q?=D1=85=20=D1=81=D1=82=D1=80=D0=BE=D0=BA.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 locales/en.json                               |   9 +-
 locales/ru.json                               |   9 +-
 .../lesson-list/components/lessons-form.tsx   | 170 ++++++++++++++++--
 3 files changed, 168 insertions(+), 20 deletions(-)

diff --git a/locales/en.json b/locales/en.json
index 97c4950..e086347 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -210,5 +210,12 @@
     "journal.pl.overview.new": "new",
     "journal.pl.overview.pastLessonsStats": "Statistics of past lessons",
     "journal.pl.overview.dayOfWeekHelp": "Only statistics for completed lessons are shown",
-    "journal.pl.overview.attendanceHelp": "Attendance is calculated based on past lessons only"
+    "journal.pl.overview.attendanceHelp": "Attendance is calculated based on past lessons only",
+    "journal.pl.today": "Today",
+    "journal.pl.tomorrow": "Tomorrow",
+    "journal.pl.dayAfterTomorrow": "Day after tomorrow",
+    "journal.pl.days.morning": "Morning",
+    "journal.pl.days.day": "Day",
+    "journal.pl.days.evening": "Evening",
+    "journal.pl.lesson.form.selectTime": "Select time"
 }
\ No newline at end of file
diff --git a/locales/ru.json b/locales/ru.json
index bcb7d40..0e36fd4 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -207,5 +207,12 @@
   "journal.pl.overview.new": "новых",
   "journal.pl.overview.pastLessonsStats": "Статистика проведённых занятий",
   "journal.pl.overview.dayOfWeekHelp": "Показана статистика только состоявшихся занятий",
-  "journal.pl.overview.attendanceHelp": "Посещаемость рассчитана только по прошедшим занятиям"
+  "journal.pl.overview.attendanceHelp": "Посещаемость рассчитана только по прошедшим занятиям",
+  "journal.pl.today": "Сегодня",
+  "journal.pl.tomorrow": "Завтра",
+  "journal.pl.dayAfterTomorrow": "Послезавтра",
+  "journal.pl.days.morning": "Утро",
+  "journal.pl.days.day": "День",
+  "journal.pl.days.evening": "Вечер",
+  "journal.pl.lesson.form.selectTime": "Выберите время"
 }
\ No newline at end of file
diff --git a/src/pages/lesson-list/components/lessons-form.tsx b/src/pages/lesson-list/components/lessons-form.tsx
index acdf034..6363a4b 100644
--- a/src/pages/lesson-list/components/lessons-form.tsx
+++ b/src/pages/lesson-list/components/lessons-form.tsx
@@ -24,7 +24,10 @@ import {
   SimpleGrid,
   Skeleton,
   SkeletonText,
-  useStyleConfig
+  useStyleConfig,
+  Select,
+  Wrap,
+  WrapItem
 } from '@chakra-ui/react'
 import { AddIcon, CheckIcon, WarningIcon, RepeatIcon } from '@chakra-ui/icons'
 import { useTranslation } from 'react-i18next'
@@ -39,6 +42,7 @@ import { ErrorSpan } from '../style'
 interface NewLessonForm {
   name: string
   date: string
+  time: string
 }
 
 interface LessonFormProps {
@@ -131,6 +135,66 @@ export const LessonForm = ({
     onSelectAiSuggestion(suggestion)
   }
 
+  // Добавляем новые вспомогательные функции
+  const generateTimeSlots = () => {
+    const slots = [];
+    for (let hour = 8; hour <= 21; hour++) {
+      slots.push(`${hour.toString().padStart(2, '0')}:00`);
+      slots.push(`${hour.toString().padStart(2, '0')}:30`);
+    }
+    return slots;
+  };
+
+  const getNextTimeSlots = (date: string, count: number = 3) => {
+    const currentDate = new Date();
+    const selectedDate = new Date(date);
+    const isToday = selectedDate.toDateString() === currentDate.toDateString();
+    
+    if (!isToday) return [];
+
+    const currentMinutes = currentDate.getHours() * 60 + currentDate.getMinutes();
+    const slots = generateTimeSlots();
+    
+    return slots
+      .map(slot => {
+        const [hours, minutes] = slot.split(':').map(Number);
+        const slotMinutes = hours * 60 + minutes;
+        return { slot, minutes: slotMinutes };
+      })
+      .filter(({ minutes }) => minutes > currentMinutes)
+      .slice(0, count)
+      .map(({ slot }) => slot);
+  };
+
+  const timeGroups = {
+    [`${t('journal.pl.days.morning')} (8-12)`]: generateTimeSlots().filter(slot => {
+      const hour = parseInt(slot.split(':')[0]);
+      return hour >= 8 && hour < 12;
+    }),
+    [`${t('journal.pl.days.day')} (12-17)`]: generateTimeSlots().filter(slot => {
+      const hour = parseInt(slot.split(':')[0]);
+      return hour >= 12 && hour < 17;
+    }),
+    [`${t('journal.pl.days.evening')} (17-21)`]: generateTimeSlots().filter(slot => {
+      const hour = parseInt(slot.split(':')[0]);
+      return hour >= 17 && hour <= 21;
+    })
+  };
+
+  // Добавляем функцию для получения дня недели
+  const getDayOfWeek = (date: Date) => {
+    const days = [
+      t('journal.pl.days.sunday'),
+      t('journal.pl.days.monday'),
+      t('journal.pl.days.tuesday'),
+      t('journal.pl.days.wednesday'),
+      t('journal.pl.days.thursday'),
+      t('journal.pl.days.friday'),
+      t('journal.pl.days.saturday')
+    ];
+    return days[date.getDay()];
+  };
+
   return (
     <Card align="left" bg={isAiSuggested ? aiHighlightColor : undefined}>
       <CardHeader display="flex">
@@ -160,23 +224,93 @@ export const LessonForm = ({
               control={control}
               name="date"
               rules={{ required: t('journal.pl.common.required') }}
-              render={({ field }) => (
-                <FormControl>
-                  <FormLabel>{t('journal.pl.lesson.form.date')}</FormLabel>
-                  <Input
-                    {...field}
-                    required={false}
-                    placeholder={t('journal.pl.lesson.form.datePlaceholder')}
-                    size="md"
-                    type="datetime-local"
-                  />
-                  {errors.date ? (
-                    <FormErrorMessage>{errors.date?.message}</FormErrorMessage>
-                  ) : (
-                    <FormHelperText>{t('journal.pl.lesson.form.dateTime')}</FormHelperText>
-                  )}
-                </FormControl>
-              )}
+              render={({ field }) => {
+                // Разделяем текущее значение на дату и время
+                const [currentDate = '', currentTime = '00:00:00'] = field.value.split('T');
+                // Получаем часы и минуты без секунд для сравнения
+                const currentTimeShort = currentTime.split(':').slice(0, 2).join(':');
+                
+                return (
+                  <FormControl>
+                    <FormLabel>{t('journal.pl.lesson.form.date')}</FormLabel>
+                    <VStack align="stretch" spacing={4}>
+                      <HStack spacing={2}>
+                        {[0, 1, 2].map(daysToAdd => {
+                          const date = new Date();
+                          date.setDate(date.getDate() + daysToAdd);
+                          const formattedDate = dateToCalendarFormat(date.toISOString()).split('T')[0];
+                          const dayOfWeek = getDayOfWeek(date);
+                          
+                          return (
+                            <Button
+                              key={daysToAdd}
+                              size="sm"
+                              variant={currentDate === formattedDate ? "solid" : "outline"}
+                              colorScheme="blue"
+                              onClick={() => {
+                                // Сохраняем текущее время при смене даты
+                                field.onChange(`${formattedDate}T${currentTime}:00`);
+                              }}
+                            >
+                              {daysToAdd === 0 ? t('journal.pl.today') :
+                               daysToAdd === 1 ? t('journal.pl.tomorrow') :
+                               t('journal.pl.dayAfterTomorrow')}
+                              <Text as="span" fontSize="xs" ml={1} color="gray.500">
+                                ({dayOfWeek})
+                              </Text>
+                            </Button>
+                          );
+                        })}
+                      </HStack>
+                      
+                      <Input
+                        value={currentDate}
+                        onChange={(e) => {
+                          // При ручном изменении даты сохраняем текущее время
+                          field.onChange(`${e.target.value}T${currentTime}:00`);
+                        }}
+                        type="date"
+                        size="sm"
+                      />
+
+                      <Box>
+                        <Text fontSize="sm" mb={2}>{t('journal.pl.lesson.form.selectTime')}:</Text>
+                        <SimpleGrid columns={{ base: 1, md: 3 }} spacing={4}>
+                          {Object.entries(timeGroups).map(([groupName, slots]) => (
+                            <Box key={groupName}>
+                              <Text fontSize="xs" color="gray.500" mb={1}>
+                                {groupName}
+                              </Text>
+                              <Wrap spacing={1}>
+                                {slots.map(slot => {
+                                  const isSelected = currentTimeShort === slot;
+                                  
+                                  return (
+                                    <WrapItem key={slot}>
+                                      <Button
+                                        size="xs"
+                                        variant={isSelected ? "solid" : "outline"}
+                                        colorScheme="blue"
+                                        onClick={() => {
+                                          field.onChange(`${currentDate}T${slot}:00`);
+                                        }}
+                                        h="24px"
+                                        minW="54px"
+                                      >
+                                        {slot}
+                                      </Button>
+                                    </WrapItem>
+                                  );
+                                })}
+                              </Wrap>
+                            </Box>
+                          ))}
+                        </SimpleGrid>
+                      </Box>
+                    </VStack>
+                  </FormControl>
+                );
+              }}
             />
 
             <Controller