nordabiz/templates/messages/conversations.html
Maciej Pienczyn 702ee90de8
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
fix(messages): readable link colors — light blue on dark bubbles, navy on light bubbles
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 17:22:07 +01:00

235 lines
10 KiB
HTML

{% extends "base.html" %}
{% block title %}Wiadomości - Norda Biznes Partner{% endblock %}
{% block container_class %}conversations-page{% endblock %}
{% block head_extra %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/quill.snow.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/conversations.css') }}?v=10">
<script src="{{ url_for('static', filename='js/vendor/quill.js') }}"></script>
<style>
footer { display: none !important; }
main { padding-bottom: 0 !important; margin-bottom: 0 !important; }
/* Hide floating buttons that overlap with chat input area */
.pwa-smart-banner, .staging-panel-toggle { display: none !important; }
</style>
{% endblock %}
{% block content %}
<div class="conversations-container" id="conversationsApp">
<!-- Left panel: Conversation list -->
<div class="conversations-panel" id="conversationsPanel">
<div class="conversations-header">
<h2>Wiadomości</h2>
<div class="conversations-search-row">
<div class="conversations-search">
<svg class="search-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="11" cy="11" r="8"></circle>
<path d="M21 21l-4.35-4.35"></path>
</svg>
<input type="text" id="searchInput" placeholder="Szukaj rozmów i wiadomości...">
</div>
<button class="btn-new-conversation" id="newMessageBtn" title="Nowa wiadomość">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 20h9"></path>
<path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"></path>
</svg>
</button>
</div>
</div>
<div class="conversation-list" id="conversationList">
<!-- Rendered by JS from __CONVERSATIONS__ data -->
</div>
<div class="archive-link" id="archiveLink" style="display:none">
<a href="#">Archiwum</a>
</div>
</div>
<!-- Right panel: Chat view -->
<div class="chat-panel" id="chatPanel">
<!-- Empty state (shown by default) -->
<div class="chat-empty" id="chatEmpty">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
</svg>
<p>Wybierz rozmowę lub rozpocznij nową</p>
</div>
<!-- Chat header (hidden until conversation selected) -->
<div class="chat-header" id="chatHeader" style="display:none">
<div class="chat-header-left">
<button class="back-btn" id="backBtn" title="Wróć">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M19 12H5"></path>
<path d="M12 19l-7-7 7-7"></path>
</svg>
</button>
<div class="chat-header-avatar" id="headerAvatar"></div>
<div class="chat-header-info">
<h3 id="headerName"></h3>
<div class="subtitle" id="headerSubtitle"></div>
</div>
</div>
<div class="chat-header-actions">
</div>
</div>
<!-- Pinned bar -->
<div class="pinned-bar" id="pinnedBar" style="display:none">
<span>📌 <span id="pinnedCount">0</span> przypiętych</span>
<button id="togglePins">Pokaż</button>
</div>
<!-- Messages area -->
<div class="chat-messages" id="chatMessages" style="display:none">
<!-- Rendered by JS -->
</div>
<!-- Typing indicator -->
<div class="typing-indicator" id="typingIndicator" style="display:none">
<span id="typingName"></span> pisze
<span class="typing-dots"><span>.</span><span>.</span><span>.</span></span>
</div>
<!-- Input area -->
<div class="chat-input-area" id="chatInputArea" style="display:none">
<!-- Reply quote (shown when replying to a message) -->
<div class="reply-preview" id="replyPreview" style="display:none">
<div class="reply-preview-content">
<span class="reply-preview-name" id="replyPreviewName"></span>
<span class="reply-preview-text" id="replyPreviewText"></span>
</div>
<button class="reply-preview-close" id="replyPreviewClose">&times;</button>
</div>
<div class="chat-input-wrapper">
<div id="quillEditor"></div>
<div class="input-actions">
<button id="attachBtn" title="Dołącz plik">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"></path>
</svg>
</button>
<button class="send-btn" id="sendBtn" title="Wyślij">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M22 2L11 13"></path>
<path d="M22 2l-7 20-4-9-9-4 20-7z"></path>
</svg>
</button>
</div>
</div>
<input type="file" id="fileInput" multiple style="display:none" accept=".jpg,.jpeg,.png,.gif,.pdf,.docx,.xlsx">
<div class="attachments-preview" id="attachmentsPreview" style="display:none"></div>
<div class="input-hint"><kbd>Enter</kbd> wyślij &nbsp;·&nbsp; <kbd>Shift</kbd>+<kbd>Enter</kbd> nowa linia</div>
</div>
</div>
<!-- Context menu (floating, positioned by JS) -->
<div class="message-context-menu" id="contextMenu" style="display:none">
<button data-action="reply" title="Odpowiedz">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M9 17l-5-5 5-5"></path>
<path d="M20 18v-2a4 4 0 0 0-4-4H4"></path>
</svg>
</button>
<button data-action="react" title="Reaguj">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<path d="M8 14s1.5 2 4 2 4-2 4-2"></path>
<line x1="9" y1="9" x2="9.01" y2="9"></line>
<line x1="15" y1="9" x2="15.01" y2="9"></line>
</svg>
</button>
<button data-action="forward" title="Przekaż">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M15 17l5-5-5-5"></path>
<path d="M4 18v-2a4 4 0 0 1 4-4h12"></path>
</svg>
</button>
<button data-action="pin" title="Przypnij">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 2l1.09 3.26L16 6l-2 2 .73 3.27L12 9.5l-2.73 1.77L10 8 8 6l2.91-.74L12 2z"></path>
<path d="M12 22v-8"></path>
</svg>
</button>
<button data-action="edit" title="Edytuj" class="owner-only">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
</svg>
</button>
<button data-action="delete" title="Usuń" class="owner-only">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="3 6 5 6 21 6"></polyline>
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
<line x1="10" y1="11" x2="10" y2="17"></line>
<line x1="14" y1="11" x2="14" y2="17"></line>
</svg>
</button>
</div>
<!-- Emoji picker -->
<div class="emoji-picker" id="emojiPicker" style="display:none">
<button data-emoji="👍">👍</button>
<button data-emoji="❤️">❤️</button>
<button data-emoji="😂">😂</button>
<button data-emoji="😮">😮</button>
<button data-emoji="😢">😢</button>
<button data-emoji="✅"></button>
</div>
<!-- New message modal -->
<div class="modal-overlay" id="newMessageModal" style="display:none">
<div class="modal-content">
<div class="modal-header">
<h3>Nowa wiadomość</h3>
<button class="modal-close" id="closeNewMessage">&times;</button>
</div>
<div class="modal-body">
<div class="recipient-input">
<label>Do:</label>
<input type="text" id="recipientSearch" placeholder="Wpisz imię lub nazwisko...">
<div class="recipient-suggestions" id="recipientSuggestions"></div>
<div class="selected-recipients" id="selectedRecipients"></div>
</div>
<div id="newMessageEditor"></div>
</div>
<div class="modal-footer">
<button class="btn-secondary" id="cancelNewMessage">Anuluj</button>
<button class="btn-primary" id="sendNewMessage">Wyślij</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
window.__CONVERSATIONS__ = {{ conversations_json|safe }};
window.__CURRENT_USER__ = {{ current_user_json|safe }};
window.__USERS__ = {{ users_json|default('[]')|safe }};
window.__CSRF_TOKEN__ = '{{ csrf_token() }}';
// Dynamically set container height based on actual position
(function() {
var container = document.getElementById('conversationsApp');
if (container) {
var top = container.getBoundingClientRect().top;
container.style.height = (window.innerHeight - top) + 'px';
window.addEventListener('resize', function() {
var t = container.getBoundingClientRect().top;
container.style.height = (window.innerHeight - t) + 'px';
});
}
})();
// Load conversations.js after data is set
(function() {
var s = document.createElement('script');
s.src = '{{ url_for("static", filename="js/conversations.js") }}?v=17';
document.body.appendChild(s);
})();
{% endblock %}