diff --git a/static/css/conversations.css b/static/css/conversations.css
index c961dbb..c93cdd6 100644
--- a/static/css/conversations.css
+++ b/static/css/conversations.css
@@ -160,6 +160,15 @@
background: var(--conv-primary-hover);
}
+.btn-new-group {
+ background: var(--conv-surface);
+ color: var(--conv-primary);
+ border: 1.5px solid var(--conv-primary);
+}
+.btn-new-group:hover {
+ background: var(--conv-primary-light);
+}
+
@media (max-width: 768px) {
.btn-new-text { display: none; }
.btn-new-conversation { width: 36px; padding: 0; }
diff --git a/static/js/conversations.js b/static/js/conversations.js
index fd3e791..50d60d8 100644
--- a/static/js/conversations.js
+++ b/static/js/conversations.js
@@ -2201,6 +2201,246 @@
},
};
+ // ============================================================
+ // 10b. NEW GROUP MODAL
+ // ============================================================
+
+ var NewGroupModal = {
+ _quill: null,
+ _selectedMembers: [],
+ _debounceTimer: null,
+
+ init: function () {
+ var btn = document.getElementById('newGroupBtn');
+ var modal = document.getElementById('newGroupModal');
+ if (!btn || !modal) return;
+
+ btn.addEventListener('click', function () {
+ NewGroupModal.open();
+ });
+
+ var closeBtn = document.getElementById('closeNewGroup');
+ var cancelBtn = document.getElementById('cancelNewGroup');
+ if (closeBtn) closeBtn.addEventListener('click', function () { modal.style.display = 'none'; });
+ if (cancelBtn) cancelBtn.addEventListener('click', function () { modal.style.display = 'none'; });
+
+ var sendBtn = document.getElementById('sendNewGroup');
+ if (sendBtn) sendBtn.addEventListener('click', function () { NewGroupModal.send(); });
+
+ var searchInput = document.getElementById('groupRecipientSearch');
+ if (searchInput) {
+ searchInput.addEventListener('input', function () {
+ clearTimeout(NewGroupModal._debounceTimer);
+ NewGroupModal._debounceTimer = setTimeout(function () {
+ NewGroupModal.filterRecipients(searchInput.value);
+ }, 200);
+ });
+ }
+ },
+
+ open: function () {
+ NewGroupModal._selectedMembers = [];
+ var nameInput = document.getElementById('groupNameInput');
+ if (nameInput) nameInput.value = '';
+ var searchInput = document.getElementById('groupRecipientSearch');
+ if (searchInput) searchInput.value = '';
+ var suggestions = document.getElementById('groupRecipientSuggestions');
+ if (suggestions) suggestions.innerHTML = '';
+ var selected = document.getElementById('groupSelectedRecipients');
+ if (selected) selected.innerHTML = '';
+
+ var editorEl = document.getElementById('groupMessageEditor');
+ if (editorEl) {
+ editorEl.innerHTML = '';
+ NewGroupModal._quill = new Quill('#groupMessageEditor', {
+ theme: 'snow',
+ placeholder: 'Pierwsza wiadomość (opcjonalna)...',
+ modules: {
+ toolbar: [['bold', 'italic'], ['link'], ['clean']],
+ },
+ });
+ }
+
+ var modal = document.getElementById('newGroupModal');
+ if (modal) modal.style.display = 'flex';
+ if (nameInput) nameInput.focus();
+ },
+
+ filterRecipients: async function (query) {
+ var suggestions = document.getElementById('groupRecipientSuggestions');
+ if (!suggestions) return;
+ suggestions.innerHTML = '';
+
+ query = (query || '').trim();
+ if (query.length < 2) return;
+
+ suggestions.innerHTML = '
Szukam...
';
+
+ try {
+ var resp = await fetch('/api/users/search?q=' + encodeURIComponent(query), {
+ headers: { 'X-CSRFToken': window.__CSRF_TOKEN__ },
+ });
+ if (!resp.ok) throw new Error('search failed');
+ var users = await resp.json();
+
+ suggestions.innerHTML = '';
+ var selectedIds = NewGroupModal._selectedMembers.map(function (r) { return r.id; });
+ var matches = users.filter(function (u) {
+ return selectedIds.indexOf(u.id) === -1;
+ });
+
+ if (!matches.length) {
+ suggestions.innerHTML = 'Brak wyników
';
+ return;
+ }
+
+ matches.forEach(function (u) {
+ var item = el('div', 'suggestion-item');
+ item.style.padding = '8px 12px';
+ item.style.cursor = 'pointer';
+ item.style.display = 'flex';
+ item.style.alignItems = 'center';
+ item.style.gap = '8px';
+ item.style.borderBottom = '1px solid var(--conv-border)';
+
+ var avatar = el('div', 'conv-avatar ' + avatarColor(u.name));
+ avatar.style.width = '30px';
+ avatar.style.height = '30px';
+ avatar.style.minWidth = '30px';
+ avatar.style.fontSize = '11px';
+ avatar.textContent = initials(u.name);
+
+ var info = el('div', '');
+ var nameEl = el('div', '', u.name || u.email);
+ nameEl.style.fontSize = '14px';
+ nameEl.style.fontWeight = '500';
+ if (u.company_name) {
+ var companyEl = el('div', '', u.company_name);
+ companyEl.style.fontSize = '12px';
+ companyEl.style.color = 'var(--conv-text-muted)';
+ info.appendChild(nameEl);
+ info.appendChild(companyEl);
+ } else {
+ info.appendChild(nameEl);
+ }
+
+ item.appendChild(avatar);
+ item.appendChild(info);
+
+ item.addEventListener('click', function () {
+ NewGroupModal.selectMember(u);
+ });
+ item.addEventListener('mouseenter', function () {
+ item.style.background = 'var(--conv-surface-secondary)';
+ });
+ item.addEventListener('mouseleave', function () {
+ item.style.background = '';
+ });
+
+ suggestions.appendChild(item);
+ });
+ } catch (e) {
+ suggestions.innerHTML = 'Błąd wyszukiwania
';
+ }
+ },
+
+ selectMember: function (user) {
+ NewGroupModal._selectedMembers.push(user);
+
+ var container = document.getElementById('groupSelectedRecipients');
+ if (container) {
+ var pill = el('span', '');
+ pill.style.display = 'inline-flex';
+ pill.style.alignItems = 'center';
+ pill.style.gap = '4px';
+ pill.style.padding = '4px 10px';
+ pill.style.borderRadius = '16px';
+ pill.style.background = 'var(--conv-primary-light)';
+ pill.style.fontSize = '13px';
+ pill.style.color = 'var(--conv-text-primary)';
+ pill.style.margin = '2px';
+
+ pill.textContent = user.name || user.email;
+ var removeBtn = el('button', '', '\u00d7');
+ removeBtn.style.border = 'none';
+ removeBtn.style.background = 'transparent';
+ removeBtn.style.cursor = 'pointer';
+ removeBtn.style.fontSize = '14px';
+ removeBtn.style.color = 'var(--conv-text-muted)';
+ removeBtn.style.padding = '0';
+ removeBtn.style.lineHeight = '1';
+ removeBtn.addEventListener('click', function () {
+ NewGroupModal._selectedMembers = NewGroupModal._selectedMembers.filter(function (r) {
+ return r.id !== user.id;
+ });
+ pill.remove();
+ });
+ pill.appendChild(removeBtn);
+ container.appendChild(pill);
+ }
+
+ var searchInput = document.getElementById('groupRecipientSearch');
+ if (searchInput) searchInput.value = '';
+ var suggestions = document.getElementById('groupRecipientSuggestions');
+ if (suggestions) suggestions.innerHTML = '';
+ if (searchInput) searchInput.focus();
+ },
+
+ send: async function () {
+ var nameInput = document.getElementById('groupNameInput');
+ var groupName = (nameInput ? nameInput.value : '').trim();
+
+ if (NewGroupModal._selectedMembers.length < 2) {
+ alert('Wybierz co najmniej dwóch członków grupy');
+ return;
+ }
+
+ if (state._isCreating) return;
+ state._isCreating = true;
+
+ var messageContent = '';
+ if (NewGroupModal._quill) {
+ var text = NewGroupModal._quill.getText().trim();
+ if (text) {
+ messageContent = NewGroupModal._quill.root.innerHTML;
+ }
+ }
+
+ var memberIds = NewGroupModal._selectedMembers.map(function (r) { return r.id; });
+
+ // Auto-generate name if not provided
+ if (!groupName) {
+ var names = NewGroupModal._selectedMembers.map(function (r) { return r.name || r.email; });
+ names.push(window.__CURRENT_USER__.name);
+ groupName = names.join(', ');
+ }
+
+ try {
+ var result = await api('/api/conversations', 'POST', {
+ member_ids: memberIds,
+ name: groupName,
+ message: messageContent,
+ });
+
+ var modal = document.getElementById('newGroupModal');
+ if (modal) modal.style.display = 'none';
+
+ var existing = state.conversations.find(function (c) { return c.id === result.id; });
+ if (!existing) {
+ state.conversations.unshift(result);
+ } else {
+ Object.assign(existing, result);
+ }
+ ConversationList.renderList();
+ ConversationList.selectConversation(result.id);
+ } catch (e) {
+ alert('Nie udało się utworzyć grupy: ' + e.message);
+ } finally {
+ state._isCreating = false;
+ }
+ },
+ };
+
// ============================================================
// 11. SEARCH
// ============================================================
@@ -2571,6 +2811,7 @@
ConversationList.renderList();
Composer.init();
NewMessageModal.init();
+ NewGroupModal.init();
Search.init();
Pins.init();
initContextMenu();
diff --git a/templates/messages/conversations.html b/templates/messages/conversations.html
index 0f8388a..f96a37e 100644
--- a/templates/messages/conversations.html
+++ b/templates/messages/conversations.html
@@ -5,7 +5,7 @@
{% block head_extra %}
-
+