- Создан модуль calendarEventDragDrop.js с классами DragDropState и CalendarUtils
- Реализовано перетаскивание событий между календарями через модальное окно
- Добавлена кнопка 'Переместить все' для массового перемещения
- Модальное окно отображает источник и цель перемещения
- Поддержка legacy-календарей (company/department/personal)
- Добавлены стили для подсветки drop-target (папки и календари)
- Backend: исправлена обработка null значений в serializer
- Backend: добавлен endpoint list_raw для получения немодерируемых событий
- Использованы стандартные Bootstrap стили для модалов
- Исправлено всплытие событий dragover/drop (stopPropagation)
- Эмодзи иконки для типов календарей (����)
- Toast уведомления об успехе/ошибках перемещения
Реализовано:
1. Множественный выбор календарей через чекбоксы
- Заменил <select> на чекбоксы для выбора нескольких календарей
- События создаются одновременно во всех выбранных календарях
- При редактировании - обновляется только первый выбранный
- Цветовые индикаторы для каждого календаря
2. Современный дизайн событий
- Двухцветная схема: левая граница = цвет календаря, фон = цвет события
- Полупрозрачный фон события (80%) для лучшей видимости
- Тени и hover эффекты для объёма
- Закругленные углы (4px)
- Плавные анимации (transform + transition)
3. Улучшенное отображение накладывающихся событий
- dayMaxEvents: автоматически показывать '+N еще'
- dayMaxEventRows: 4 - максимум 4 строки на день
- moreLinkClick: 'popover' - красивый popover для остальных
- eventMaxStack: 3 - до 3 событий в стеке
- eventOrder: сортировка по началу, длительности, алфавиту
4. Новый CSS файл calendar-improvements.css
- Современные стили для FullCalendar
- Улучшенный popover с градиентом
- Стили для выходных дней (розоватый фон)
- Hover эффекты на события
- Анимация fadeInEvent при загрузке
- Улучшенная читаемость текущего дня
- Адаптивность для мобильных устройств
- Кастомные scrollbar для списков
5. Передача цвета календаря в события
- calendar_color добавляется в extendedProps
- Используется __calendar из интеграции
- Отдельная обработка eventColor и calendarColor
6. Визуальные улучшения
- Текст события: font-weight 500, line-height 1.3
- Отступы: paddingLeft 6px (с цветом календаря)
- Тень текста для читаемости на любом фоне
- Паттерн для ежегодных событий (диагональные полосы)
- Индикатор текущего дня: синий круг с белым текстом
Результат:
✅ События визуально различимы по календарям (левая граница)
✅ Сохранён индивидуальный цвет события (основной фон)
✅ Множество событий в день отображается компактно (+N еще)
✅ Современный Material Design стиль
✅ Плавные анимации и hover эффекты
✅ Улучшенная читаемость и UX
Реализовано:
1. Селектор календаря в форме создания события
- Заменил статический текст 'Календарь: Компания' на <select>
- Показывает legacy календари (Компания, Личный, Отделы)
- Показывает новые Calendar записи из БД
- Разделитель между legacy и новыми календарями
2. Функция populateCalendarSelector()
- Динамическое заполнение селектора при открытии формы
- Использует window.calendarIntegration.calendars
- Фильтрует legacy календари (startsWith('legacy-'))
- Устанавливает значение по умолчанию по state.type
3. Обновлена логика создания/редактирования событий
- Убран старый код с state.type (personal/dept/company)
- Новая логика читает target_calendar из формы:
* 'company' → без доп. параметров (общие события)
* 'personal' → employee_id из meta[name='user-id']
* 'dept-{id}' → department_id
* numeric ID → calendar_id (новые календари)
- Поддержка смешанных ID (string для legacy, int для новых)
- Работает как для POST (создание), так и для PATCH (редактирование)
4. При редактировании события
- Автоматическое определение календаря из data:
* data.calendar_id → numeric ID
* data.employee_id → 'personal'
* data.department_id → 'dept-{id}'
* иначе → 'company'
- Селектор устанавливается в правильное положение
Результат:
✅ События можно создавать в любом календаре (legacy + новые)
✅ События можно редактировать и перемещать между календарями
✅ Сохранение calendar_id в БД для новых календарей
✅ Обратная совместимость с legacy системой (employee_id/department_id)
✅ UI с иконками � для новых календарей
- calendarManager.js: добавлена функция createLegacyCalendars() для создания pseudo-calendar объектов
- loadCalendars() теперь объединяет legacy (Компания, Личный, Отделы) и новые календари в единый массив
- calendarWidgetIntegration.js: обновлена логика fetchEventsForVisibleCalendars для работы с legacy ID
- legacy-company: все события без фильтров
- legacy-personal: события текущего сотрудника (employee_id)
- legacy-dept-{id}: события конкретного отдела (department_id)
- calendar_desktop.html: удален старый dropdown, оставлен только унифицированный список с чекбоксами
- Все календари теперь в одном списке с возможностью выбора через чекбоксы
- Цвета: Компания (красный), Личный (синий), Отделы (зеленый), новые календари (свои цвета)
- Restored original dropdown for Company/Department/Personal selection
- Added new 'My Calendars' collapsible list as ADDITIONAL feature
- Legacy dropdown remains primary navigation
- New calendar list is collapsed by default, accessed via list-check icon
- Two systems work in parallel: legacy (dropdown) + new (multi-calendar)
This fixes the broken calendar type selection functionality.
- Fixed calendar_scripts.html to wait for DOM ready before initialization
- Added retry logic if widget not found on first attempt
- Changed integration fallback: show ALL events when no calendars configured
- Changed behavior: if no calendars selected, show all events (legacy mode)
- This ensures backward compatibility with existing events
User feedback: Integration wasn't initializing on page load, button '+' didn't work.
Solution: Auto-init with retry + always show events (no empty state).
- Removed duplicate modal opening via data-bs-toggle attribute
- Changed to programmatic opening via openForCreate() only
- Added calendar:edit event listener for edit functionality
- Updated button selector from data-bs-target to data-action
Issue: Button had both Bootstrap modal trigger and JS event listener,
causing double initialization and infinite loading state.
Solution: Use only programmatic modal opening through calendarManageModal API.
- Created calendarWidgetIntegration.js as integration layer
- Modified calendarWidget.js to use new calendar filtering system
- Added fallback to legacy mode for backward compatibility
- Updated calendar_scripts.html to initialize integration
- Implemented fetchEventsForVisibleCalendars with calendar_id filtering
- Added event deduplication and color override from calendars
- Exposed window.calendarIntegration for global access
- Added comprehensive logging for debugging
Technical decisions:
- Non-invasive integration via optional chaining
- Callback-based synchronization (onCalendarToggle, onCalendarsChange)
- Parallel event loading with Promise.all()
- Automatic legacy mode when no calendars configured
Проблема:
- Аватары деформировались из-за object-fit на контейнере
- Аватары выравнивались по верху сообщения вместо низа
- Неконсистентная HTML структура: <img class="mini-ava"> vs <div class="mini-ava"><i></i></div>
Решение:
SCSS (_common.scss):
- object-fit: cover перемещен с контейнера на вложенный img
- Добавлен display: block для img элементов
SCSS (_chat-detail.scss):
- Добавлен align-items: flex-end к .d-flex.msg для выравнивания по низу
- .mini-ava рефакторинг: display: flex (было grid), border-radius: 50% (было 9999px)
- Добавлен background и border для контейнера
- Добавлен font-size: 20px для fallback иконки
- object-fit остается только на img тегах
JavaScript (messageRendererV2.js):
- Всегда создавать <div class="mini-ava"> как контейнер
- Вложенный <img> или <i class="bi bi-person-circle"> внутри
- Устранена несогласованность разметки
Рефакторинг архитектуры SCSS (бонус):
- Создан Design System: abstracts/_variables.scss (200+ токенов)
- Создано abstracts/_mixins.scss (40+ миксинов)
- Реорганизована файловая структура: layout/, components/, components/chat/
- Централизованы стили аватаров в _common.scss
- Устранены дубликаты (avatar определялся в 3 файлах)
- Применены design tokens к navbar, page-header
- Создана документация: SCSS_NAMING_CONVENTIONS.md
- Удалено 9 дублирующихся CSS файлов
Компиляция: 280KB, 0 ошибок, production ready
- Created comprehensive badges-telegram-style.css (240 lines) based on Telegram Web K
- Updated all badge markup in templates (navbar, sidebar, chat_list, chat_detail, chat_title)
- Replaced Bootstrap badge classes with .badge-telegram classes
- Implemented Telegram specifications: 20px height, 10px radius, 11px font, 600 weight
- Added smooth animations: pulse (on update), animate-in (on mount), animate-out (on unmount)
- Updated JavaScript: replaced .d-none with style.display for badge visibility
- Updated 5 JS files: bottom-navbar, notification-manager, chatBadgeHandler, chatBadgeManager, chatListRealtime
- Added pulse animation on badge value increase
- Improved shadows and transitions with cubic-bezier easing
- Added badges-telegram-style.css to base.html for global availability
- Created documentation: TELEGRAM_BADGES_GUIDE.md, TELEGRAM_BADGES_UPDATE.md
Technical details:
- Research: Analyzed 50+ files from Telegram Web K GitHub repository
- Perfect circles: border-radius: 10px (not 50%)
- Spring animation: cubic-bezier(0.175, 0.885, 0.32, 1.275)
- Auto-hide: :empty and [data-count='0'] selectors
- Responsive design + dark theme support
- Removed badge showing total message count (chat.messages.count)
- Keep only unread messages counter for cleaner UI
- Users can still see unread count which is more important
- Added smart positioning logic to keep menu within viewport bounds
- Menu now adjusts horizontal position if it would overflow right edge
- Menu moves above cursor if it would overflow bottom edge
- Changed position from absolute to fixed for consistent behavior
- Added 10px safety margins from all edges
- Menu is temporarily hidden during position calculation for smooth appearance
- Removed floating action button (FAB) for calendar
- Added calendar icon in navbar next to notification bell
- Calendar button only visible on mobile devices (d-lg-none)
- Fixed issue where FAB could overlap message send button
- Commented out calendar-fab CSS in all relevant files
- Заменен лишний div.container на стандартный container для единообразия
- Заменен класс .card на .ios-card в секции активности для устранения конфликтов стилей
- Добавлен card-list.css в base.html для корректного отображения карточек новостей
- Добавлены CSS правила для правильного поведения .row и колонок в grid-layout
- Исправлена проблема с выходом календаря за границы страницы
- Убраны видимые скроллбары у modal-body и modal-content для чистого UI
- ApiClient теперь обрабатывает 401 и 403 ошибки для обновления токена
- Добавлен JWTRefreshMiddleware для проактивного обновления токенов за 5 минут до истечения
- Добавлена настройка JWT_REFRESH_THRESHOLD_MINUTES (по умолчанию 5)
- Исправлена проблема с периодическими 403 ошибками после истечения access token
- Добавлен фильтр created_at__gte в EmployeeViewSet API
- Исправлен параметр is_active -> active в запросе к API
- Добавлено центрирование карусели новых сотрудников (justify-content: center)
- Обновлена документация API endpoints
- Add 'border-0 bg-transparent' classes to create_url link
- Now both create_modal (button) and create_url (link) have identical styling
- Fixes visual inconsistency between employees list (modal) and departments list (link)
- Fix bug in page_header.html: add # to data-bs-target for card create button
- Integrate page_header in department_list.html with search and create card
- Integrate page_header in feed_list.html (no search, staff-only create button)
- Integrate page_header in document_list.html with Mine/All scope toggle
- Integrate page_header in request_list_full.html with filters and scope toggle
- Integrate page_header in chat_list.html with search
- Create _filters.html template for requests_app
- Add page-header.css to all integrated templates for consistent styling