|
@@ -0,0 +1,522 @@
|
|
|
|
|
+@php
|
|
|
|
|
+ /** @var \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Collection $messages */
|
|
|
|
|
+ $messages = $messages ?? collect();
|
|
|
|
|
+ $users = $users ?? collect();
|
|
|
|
|
+ $responsibleUserIds = array_map('intval', $responsibleUserIds ?? []);
|
|
|
|
|
+ $contextKey = $contextKey ?? 'chat';
|
|
|
|
|
+ $title = $title ?? 'Чат';
|
|
|
|
|
+ $submitLabel = $submitLabel ?? 'Отправить';
|
|
|
|
|
+ $canSendNotifications = hasRole('admin,manager');
|
|
|
|
|
+ $notificationValue = old('notification_type', \App\Models\ChatMessage::NOTIFICATION_NONE);
|
|
|
|
|
+ $selectedTargetUserIds = collect(old('target_user_ids', []))
|
|
|
|
|
+ ->map(static fn ($id) => (int) $id)
|
|
|
|
|
+ ->filter()
|
|
|
|
|
+ ->unique()
|
|
|
|
|
+ ->values()
|
|
|
|
|
+ ->all();
|
|
|
|
|
+@endphp
|
|
|
|
|
+
|
|
|
|
|
+@once
|
|
|
|
|
+ <style>
|
|
|
|
|
+ .chat-block {
|
|
|
|
|
+ --chat-height: 420px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chat-card {
|
|
|
|
|
+ border: 1px solid var(--bs-border-color);
|
|
|
|
|
+ border-radius: 0.75rem;
|
|
|
|
|
+ background: var(--bs-light-bg-subtle, #f8f9fa);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chat-messages-wrap {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ padding: 0.75rem;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chat-messages {
|
|
|
|
|
+ max-height: var(--chat-height);
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+ padding-right: 0.35rem;
|
|
|
|
|
+ scroll-behavior: smooth;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chat-message {
|
|
|
|
|
+ border: 1px solid rgba(0, 0, 0, 0.08);
|
|
|
|
|
+ border-radius: 0.75rem;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ padding: 0.75rem 0.875rem;
|
|
|
|
|
+ margin-bottom: 0.625rem;
|
|
|
|
|
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chat-message:last-child {
|
|
|
|
|
+ margin-bottom: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chat-message-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ gap: 0.75rem;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ font-size: 0.875rem;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chat-message-text {
|
|
|
|
|
+ margin-top: 0.5rem;
|
|
|
|
|
+ white-space: pre-wrap;
|
|
|
|
|
+ line-height: 1.35;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chat-message-files {
|
|
|
|
|
+ margin-top: 0.625rem;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 0.5rem;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chat-message-files img {
|
|
|
|
|
+ width: 84px;
|
|
|
|
|
+ height: 84px;
|
|
|
|
|
+ object-fit: cover;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chat-scroll-bottom {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ right: 1rem;
|
|
|
|
|
+ bottom: 1rem;
|
|
|
|
|
+ z-index: 2;
|
|
|
|
|
+ border-radius: 999px;
|
|
|
|
|
+ box-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.18);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chat-recipient-list {
|
|
|
|
|
+ max-height: 320px;
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+ border: 1px solid var(--bs-border-color);
|
|
|
|
|
+ border-radius: 0.5rem;
|
|
|
|
|
+ padding: 0.5rem 0.75rem;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chat-recipient-item[hidden] {
|
|
|
|
|
+ display: none !important;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chat-recipient-summary {
|
|
|
|
|
+ min-height: 1.25rem;
|
|
|
|
|
+ }
|
|
|
|
|
+ </style>
|
|
|
|
|
+@endonce
|
|
|
|
|
+
|
|
|
|
|
+<div class="chat-block mt-3" data-chat-block data-context-key="{{ $contextKey }}">
|
|
|
|
|
+ <hr>
|
|
|
|
|
+ <h5>{{ $title }}</h5>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="chat-card">
|
|
|
|
|
+ <div class="chat-messages-wrap">
|
|
|
|
|
+ <div class="chat-messages" data-chat-messages>
|
|
|
|
|
+ @forelse($messages as $message)
|
|
|
|
|
+ <div class="chat-message">
|
|
|
|
|
+ <div class="chat-message-header">
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <strong>{{ $message->user?->name ?? 'Пользователь' }}</strong>
|
|
|
|
|
+ @if($message->notification_type === \App\Models\ChatMessage::NOTIFICATION_USER && $message->targetUser)
|
|
|
|
|
+ <span class="text-muted">для {{ $message->targetUser->name }}</span>
|
|
|
|
|
+ @elseif($message->notification_type === \App\Models\ChatMessage::NOTIFICATION_RESPONSIBLES)
|
|
|
|
|
+ <span class="badge text-bg-light border">Уведомления: админы/менеджер/бригадир</span>
|
|
|
|
|
+ @elseif($message->notification_type === \App\Models\ChatMessage::NOTIFICATION_ALL)
|
|
|
|
|
+ <span class="badge text-bg-light border">Уведомления: выбранные получатели</span>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <small class="text-muted">{{ $message->created_at?->format('d.m.Y H:i') }}</small>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ @if(!empty($message->message))
|
|
|
|
|
+ <div class="chat-message-text">{{ $message->message }}</div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+
|
|
|
|
|
+ @if($message->files->isNotEmpty())
|
|
|
|
|
+ <div class="chat-message-files">
|
|
|
|
|
+ @foreach($message->files as $file)
|
|
|
|
|
+ @if(\Illuminate\Support\Str::startsWith((string) $file->mime_type, 'image/'))
|
|
|
|
|
+ <a href="{{ $file->link }}" target="_blank" data-toggle="lightbox" data-gallery="chat-{{ $contextKey }}" data-size="fullscreen">
|
|
|
|
|
+ <img src="{{ $file->link }}" alt="{{ $file->original_name }}" class="img-thumbnail">
|
|
|
|
|
+ </a>
|
|
|
|
|
+ @else
|
|
|
|
|
+ <a href="{{ $file->link }}" target="_blank" class="btn btn-sm btn-outline-secondary">
|
|
|
|
|
+ <i class="bi bi-paperclip"></i> {{ $file->original_name }}
|
|
|
|
|
+ </a>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ @endforeach
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @empty
|
|
|
|
|
+ <div class="text-muted px-1">Сообщений пока нет.</div>
|
|
|
|
|
+ @endforelse
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <button type="button" class="btn btn-primary btn-sm chat-scroll-bottom d-none" data-chat-scroll-bottom>
|
|
|
|
|
+ <i class="bi bi-arrow-down"></i>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <form action="{{ $action }}" method="post" enctype="multipart/form-data" class="mt-3" data-chat-form>
|
|
|
|
|
+ @csrf
|
|
|
|
|
+
|
|
|
|
|
+ <div class="row g-2 align-items-start">
|
|
|
|
|
+ <div class="col-12 col-lg-5">
|
|
|
|
|
+ <label class="form-label" for="chat-message-{{ $contextKey }}">Сообщение</label>
|
|
|
|
|
+ <textarea
|
|
|
|
|
+ class="form-control"
|
|
|
|
|
+ id="chat-message-{{ $contextKey }}"
|
|
|
|
|
+ name="message"
|
|
|
|
|
+ rows="3"
|
|
|
|
|
+ placeholder="Введите сообщение"
|
|
|
|
|
+ >{{ old('message') }}</textarea>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="col-12 col-md-4 col-lg-3">
|
|
|
|
|
+ <label class="form-label" for="chat-notification-{{ $contextKey }}">Уведомление</label>
|
|
|
|
|
+ <select
|
|
|
|
|
+ class="form-select chat-notification-type"
|
|
|
|
|
+ id="chat-notification-{{ $contextKey }}"
|
|
|
|
|
+ name="notification_type"
|
|
|
|
|
+ data-chat-context-key="{{ $contextKey }}"
|
|
|
|
|
+ @disabled(!$canSendNotifications)
|
|
|
|
|
+ >
|
|
|
|
|
+ <option value="{{ \App\Models\ChatMessage::NOTIFICATION_NONE }}" @selected($notificationValue === \App\Models\ChatMessage::NOTIFICATION_NONE)>Нет</option>
|
|
|
|
|
+ @if($canSendNotifications)
|
|
|
|
|
+ <option value="{{ \App\Models\ChatMessage::NOTIFICATION_RESPONSIBLES }}" @selected($notificationValue === \App\Models\ChatMessage::NOTIFICATION_RESPONSIBLES)>Админы, менеджер, бригадир</option>
|
|
|
|
|
+ <option value="{{ \App\Models\ChatMessage::NOTIFICATION_ALL }}" @selected($notificationValue === \App\Models\ChatMessage::NOTIFICATION_ALL)>Все</option>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </select>
|
|
|
|
|
+ @if(!$canSendNotifications)
|
|
|
|
|
+ <input type="hidden" name="notification_type" value="{{ \App\Models\ChatMessage::NOTIFICATION_NONE }}">
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="col-12 col-md-4 col-lg-2">
|
|
|
|
|
+ <label class="form-label" for="chat-attachments-{{ $contextKey }}">Файлы</label>
|
|
|
|
|
+ <input class="form-control" id="chat-attachments-{{ $contextKey }}" type="file" name="attachments[]" multiple>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="col-12">
|
|
|
|
|
+ <div class="row g-2 align-items-center {{ $canSendNotifications && $notificationValue !== \App\Models\ChatMessage::NOTIFICATION_NONE ? '' : 'd-none' }}"
|
|
|
|
|
+ data-chat-recipient-picker-wrap>
|
|
|
|
|
+ <div class="col-12 col-md-auto">
|
|
|
|
|
+ <button
|
|
|
|
|
+ type="button"
|
|
|
|
|
+ class="btn btn-outline-secondary btn-sm"
|
|
|
|
|
+ data-chat-open-recipient-modal
|
|
|
|
|
+ data-bs-toggle="modal"
|
|
|
|
|
+ data-bs-target="#chatRecipientsModal-{{ $contextKey }}"
|
|
|
|
|
+ >
|
|
|
|
|
+ Выбрать получателей
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="col-12 col-md">
|
|
|
|
|
+ <div class="small text-muted chat-recipient-summary" data-chat-recipient-summary>
|
|
|
|
|
+ Получатели не выбраны
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div data-chat-hidden-targets>
|
|
|
|
|
+ @foreach($selectedTargetUserIds as $selectedTargetUserId)
|
|
|
|
|
+ <input type="hidden" name="target_user_ids[]" value="{{ $selectedTargetUserId }}">
|
|
|
|
|
+ @endforeach
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="col-12 text-end">
|
|
|
|
|
+ <button class="btn btn-primary btn-sm" type="submit">{{ $submitLabel }}</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </form>
|
|
|
|
|
+
|
|
|
|
|
+ @if($canSendNotifications)
|
|
|
|
|
+ <div class="modal fade" id="chatRecipientsModal-{{ $contextKey }}" tabindex="-1" aria-labelledby="chatRecipientsModalLabel-{{ $contextKey }}" aria-hidden="true">
|
|
|
|
|
+ <div class="modal-dialog modal-dialog-scrollable">
|
|
|
|
|
+ <div class="modal-content">
|
|
|
|
|
+ <div class="modal-header">
|
|
|
|
|
+ <h1 class="modal-title fs-5" id="chatRecipientsModalLabel-{{ $contextKey }}">Получатели уведомления</h1>
|
|
|
|
|
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="modal-body" data-chat-recipient-modal-body>
|
|
|
|
|
+ <div class="d-flex justify-content-between align-items-center gap-2 mb-2 flex-wrap">
|
|
|
|
|
+ <div class="small text-muted" data-chat-recipient-hint></div>
|
|
|
|
|
+ <div class="d-flex gap-2">
|
|
|
|
|
+ <button type="button" class="btn btn-sm btn-outline-primary" data-chat-check-visible>Выбрать видимых</button>
|
|
|
|
|
+ <button type="button" class="btn btn-sm btn-outline-secondary" data-chat-uncheck-visible>Снять видимые</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="chat-recipient-list">
|
|
|
|
|
+ @foreach($users as $userId => $userName)
|
|
|
|
|
+ <label class="form-check mb-2 chat-recipient-item"
|
|
|
|
|
+ data-chat-recipient-item
|
|
|
|
|
+ data-user-id="{{ $userId }}"
|
|
|
|
|
+ data-user-name="{{ $userName }}"
|
|
|
|
|
+ data-chat-responsible="{{ in_array((int) $userId, $responsibleUserIds, true) ? '1' : '0' }}">
|
|
|
|
|
+ <input
|
|
|
|
|
+ class="form-check-input"
|
|
|
|
|
+ type="checkbox"
|
|
|
|
|
+ value="{{ $userId }}"
|
|
|
|
|
+ data-chat-recipient-checkbox
|
|
|
|
|
+ @checked(in_array((int) $userId, $selectedTargetUserIds, true))
|
|
|
|
|
+ >
|
|
|
|
|
+ <span class="form-check-label">{{ $userName }}</span>
|
|
|
|
|
+ </label>
|
|
|
|
|
+ @endforeach
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="modal-footer">
|
|
|
|
|
+ <button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="modal">Закрыть</button>
|
|
|
|
|
+ <button type="button" class="btn btn-primary btn-sm" data-chat-apply-recipients data-bs-dismiss="modal">Применить</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
|
|
+@once
|
|
|
|
|
+ @push('scripts')
|
|
|
|
|
+ <script type="module">
|
|
|
|
|
+ function initChatBlock(block) {
|
|
|
|
|
+ const messages = block.querySelector('[data-chat-messages]');
|
|
|
|
|
+ const scrollButton = block.querySelector('[data-chat-scroll-bottom]');
|
|
|
|
|
+ const form = block.querySelector('[data-chat-form]');
|
|
|
|
|
+ const notificationType = block.querySelector('.chat-notification-type');
|
|
|
|
|
+ const recipientPickerWrap = block.querySelector('[data-chat-recipient-picker-wrap]');
|
|
|
|
|
+ const hiddenTargets = block.querySelector('[data-chat-hidden-targets]');
|
|
|
|
|
+ const summary = block.querySelector('[data-chat-recipient-summary]');
|
|
|
|
|
+ const modal = block.querySelector('.modal');
|
|
|
|
|
+
|
|
|
|
|
+ const scrollToBottom = (force = false) => {
|
|
|
|
|
+ if (!messages) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const isNearBottom = messages.scrollHeight - messages.scrollTop - messages.clientHeight < 48;
|
|
|
|
|
+ if (force || isNearBottom) {
|
|
|
|
|
+ messages.scrollTop = messages.scrollHeight;
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const syncScrollButton = () => {
|
|
|
|
|
+ if (!messages || !scrollButton) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const shouldShow = messages.scrollHeight - messages.scrollTop - messages.clientHeight > 80;
|
|
|
|
|
+ scrollButton.classList.toggle('d-none', !shouldShow);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const getSelectedIds = () => Array.from(hiddenTargets.querySelectorAll('input[name="target_user_ids[]"]'))
|
|
|
|
|
+ .map((input) => Number(input.value))
|
|
|
|
|
+ .filter((value) => value > 0);
|
|
|
|
|
+
|
|
|
|
|
+ const setSelectedIds = (ids) => {
|
|
|
|
|
+ hiddenTargets.innerHTML = '';
|
|
|
|
|
+ ids.forEach((id) => {
|
|
|
|
|
+ const input = document.createElement('input');
|
|
|
|
|
+ input.type = 'hidden';
|
|
|
|
|
+ input.name = 'target_user_ids[]';
|
|
|
|
|
+ input.value = String(id);
|
|
|
|
|
+ hiddenTargets.appendChild(input);
|
|
|
|
|
+ });
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const visibleRecipientItems = () => Array.from(block.querySelectorAll('[data-chat-recipient-item]'))
|
|
|
|
|
+ .filter((item) => !item.hidden);
|
|
|
|
|
+
|
|
|
|
|
+ const syncRecipientSummary = () => {
|
|
|
|
|
+ if (!summary || !notificationType) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (notificationType.value === 'none') {
|
|
|
|
|
+ summary.textContent = 'Уведомления выключены';
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const selectedIds = getSelectedIds();
|
|
|
|
|
+ if (!selectedIds.length) {
|
|
|
|
|
+ summary.textContent = 'Получатели не выбраны';
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const names = selectedIds
|
|
|
|
|
+ .map((id) => block.querySelector('[data-chat-recipient-item][data-user-id="' + id + '"]'))
|
|
|
|
|
+ .filter(Boolean)
|
|
|
|
|
+ .map((item) => item.dataset.userName);
|
|
|
|
|
+
|
|
|
|
|
+ summary.textContent = 'Выбрано: ' + names.join(', ');
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const applyRecipientFilter = (preserveSelection = true) => {
|
|
|
|
|
+ if (!notificationType || !modal) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const isResponsibles = notificationType.value === 'responsibles';
|
|
|
|
|
+ const isAll = notificationType.value === 'all';
|
|
|
|
|
+ const recipientItems = Array.from(block.querySelectorAll('[data-chat-recipient-item]'));
|
|
|
|
|
+ const selectedIds = new Set(getSelectedIds());
|
|
|
|
|
+ const visibleIds = [];
|
|
|
|
|
+
|
|
|
|
|
+ recipientItems.forEach((item) => {
|
|
|
|
|
+ const isResponsible = item.dataset.chatResponsible === '1';
|
|
|
|
|
+ const visible = isAll || (isResponsibles && isResponsible);
|
|
|
|
|
+ const checkbox = item.querySelector('[data-chat-recipient-checkbox]');
|
|
|
|
|
+
|
|
|
|
|
+ item.hidden = !visible;
|
|
|
|
|
+ checkbox.disabled = !visible;
|
|
|
|
|
+
|
|
|
|
|
+ if (visible) {
|
|
|
|
|
+ visibleIds.push(Number(item.dataset.userId));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ checkbox.checked = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (!preserveSelection) {
|
|
|
|
|
+ recipientItems.forEach((item) => {
|
|
|
|
|
+ const checkbox = item.querySelector('[data-chat-recipient-checkbox]');
|
|
|
|
|
+ if (!checkbox.disabled) {
|
|
|
|
|
+ checkbox.checked = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ recipientItems.forEach((item) => {
|
|
|
|
|
+ const checkbox = item.querySelector('[data-chat-recipient-checkbox]');
|
|
|
|
|
+ checkbox.checked = !checkbox.disabled && selectedIds.has(Number(item.dataset.userId));
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const hasVisibleSelected = recipientItems.some((item) => {
|
|
|
|
|
+ const checkbox = item.querySelector('[data-chat-recipient-checkbox]');
|
|
|
|
|
+ return !checkbox.disabled && checkbox.checked;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (!hasVisibleSelected && visibleIds.length) {
|
|
|
|
|
+ recipientItems.forEach((item) => {
|
|
|
|
|
+ const checkbox = item.querySelector('[data-chat-recipient-checkbox]');
|
|
|
|
|
+ if (!checkbox.disabled) {
|
|
|
|
|
+ checkbox.checked = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const hint = block.querySelector('[data-chat-recipient-hint]');
|
|
|
|
|
+ if (hint) {
|
|
|
|
|
+ hint.textContent = isResponsibles
|
|
|
|
|
+ ? 'Доступны только админы, менеджер и бригадир текущей сущности.'
|
|
|
|
|
+ : 'Доступны все пользователи.';
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const commitRecipientSelection = () => {
|
|
|
|
|
+ if (!notificationType || notificationType.value === 'none') {
|
|
|
|
|
+ setSelectedIds([]);
|
|
|
|
|
+ syncRecipientSummary();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const ids = visibleRecipientItems()
|
|
|
|
|
+ .map((item) => item.querySelector('[data-chat-recipient-checkbox]'))
|
|
|
|
|
+ .filter((checkbox) => checkbox && checkbox.checked)
|
|
|
|
|
+ .map((checkbox) => Number(checkbox.value))
|
|
|
|
|
+ .filter((value) => value > 0);
|
|
|
|
|
+
|
|
|
|
|
+ setSelectedIds(ids);
|
|
|
|
|
+ syncRecipientSummary();
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if (messages) {
|
|
|
|
|
+ requestAnimationFrame(() => {
|
|
|
|
|
+ scrollToBottom(true);
|
|
|
|
|
+ syncScrollButton();
|
|
|
|
|
+ });
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ scrollToBottom(true);
|
|
|
|
|
+ syncScrollButton();
|
|
|
|
|
+ }, 150);
|
|
|
|
|
+ messages.addEventListener('scroll', syncScrollButton);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (scrollButton) {
|
|
|
|
|
+ scrollButton.addEventListener('click', () => scrollToBottom(true));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (notificationType) {
|
|
|
|
|
+ notificationType.addEventListener('change', (event) => {
|
|
|
|
|
+ const enabled = event.target.value !== 'none';
|
|
|
|
|
+
|
|
|
|
|
+ if (recipientPickerWrap) {
|
|
|
|
|
+ recipientPickerWrap.classList.toggle('d-none', !enabled);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!enabled) {
|
|
|
|
|
+ setSelectedIds([]);
|
|
|
|
|
+ syncRecipientSummary();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ applyRecipientFilter(false);
|
|
|
|
|
+ commitRecipientSelection();
|
|
|
|
|
+
|
|
|
|
|
+ if (modal) {
|
|
|
|
|
+ bootstrap.Modal.getOrCreateInstance(modal).show();
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ block.querySelector('[data-chat-open-recipient-modal]')?.addEventListener('click', () => {
|
|
|
|
|
+ applyRecipientFilter(true);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ block.querySelector('[data-chat-check-visible]')?.addEventListener('click', () => {
|
|
|
|
|
+ visibleRecipientItems().forEach((item) => {
|
|
|
|
|
+ const checkbox = item.querySelector('[data-chat-recipient-checkbox]');
|
|
|
|
|
+ if (checkbox) {
|
|
|
|
|
+ checkbox.checked = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ block.querySelector('[data-chat-uncheck-visible]')?.addEventListener('click', () => {
|
|
|
|
|
+ visibleRecipientItems().forEach((item) => {
|
|
|
|
|
+ const checkbox = item.querySelector('[data-chat-recipient-checkbox]');
|
|
|
|
|
+ if (checkbox) {
|
|
|
|
|
+ checkbox.checked = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ block.querySelector('[data-chat-apply-recipients]')?.addEventListener('click', commitRecipientSelection);
|
|
|
|
|
+ modal?.addEventListener('hidden.bs.modal', () => {
|
|
|
|
|
+ if (notificationType && notificationType.value !== 'none') {
|
|
|
|
|
+ commitRecipientSelection();
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ form?.addEventListener('submit', () => {
|
|
|
|
|
+ if (notificationType && notificationType.value !== 'none') {
|
|
|
|
|
+ commitRecipientSelection();
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ applyRecipientFilter(true);
|
|
|
|
|
+ if (notificationType && notificationType.value !== 'none') {
|
|
|
|
|
+ commitRecipientSelection();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ syncRecipientSummary();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ document.querySelectorAll('[data-chat-block]').forEach(initChatBlock);
|
|
|
|
|
+ </script>
|
|
|
|
|
+ @endpush
|
|
|
|
|
+@endonce
|