feat: ticket reply improvements + priority + templates + Telegram

Reply form:
- Mailbox/sender selection dropdown (choose which email to reply from)
- CC field (auto-filled from incoming email CC, editable)
- Reply templates dropdown (quick insert pre-made responses)

Priority system:
- Three levels: normaali, tärkeä, urgent
- Priority dropdown in ticket detail view
- Priority-based sorting (urgent/tärkeä always on top)
- Visual indicators in ticket list (colored rows, emoji badges)
- Priority emails: per-company email list that auto-sets "tärkeä"

Response templates:
- CRUD management in Settings tab
- Dropdown selector in reply form
- Templates insert into textarea

Telegram alerts:
- Bot token + chat ID configuration in Settings
- Test button to verify connection
- Auto-alert on urgent tickets (both manual and from email fetch)
- Alert on priority email matches

Database changes:
- New tables: reply_templates, customer_priority_emails
- New columns: tickets.cc, tickets.priority
- ALTER TABLE migration in initDatabase()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 17:42:05 +02:00
parent 3b7def1186
commit 8485da8cbf
5 changed files with 591 additions and 23 deletions

View File

@@ -328,9 +328,24 @@
<div id="ticket-thread" class="ticket-thread"></div>
<!-- Vastauslomake -->
<div class="ticket-reply-form">
<div style="display:flex;gap:0.5rem;margin-bottom:0.75rem;">
<div style="display:flex;gap:0.5rem;margin-bottom:0.75rem;align-items:center;">
<button class="btn-reply-tab active" data-reply-type="reply">&#9993; Vastaa</button>
<button class="btn-reply-tab" data-reply-type="note">&#128221; Muistiinpano</button>
<div id="reply-template-select-wrap" style="margin-left:auto;">
<select id="reply-template-select" style="padding:5px 10px;border:1px solid #ddd;border-radius:6px;font-size:0.82rem;color:#555;">
<option value="">📝 Vastauspohjat...</option>
</select>
</div>
</div>
<div id="reply-meta-fields" style="display:flex;flex-direction:column;gap:0.4rem;margin-bottom:0.5rem;">
<div style="display:flex;align-items:center;gap:0.5rem;">
<label style="font-size:0.8rem;color:#888;min-width:60px;">Lähettäjä:</label>
<select id="reply-mailbox-select" style="flex:1;padding:5px 10px;border:1px solid #ddd;border-radius:6px;font-size:0.85rem;"></select>
</div>
<div style="display:flex;align-items:center;gap:0.5rem;">
<label style="font-size:0.8rem;color:#888;min-width:60px;">CC:</label>
<input type="text" id="reply-cc" placeholder="email1@example.com, email2@example.com" style="flex:1;padding:5px 10px;border:1px solid #ddd;border-radius:6px;font-size:0.85rem;">
</div>
</div>
<textarea id="ticket-reply-body" rows="5" placeholder="Kirjoita vastaus..."></textarea>
<div id="signature-preview" style="display:none;padding:0.5rem 0.75rem;margin-top:0.25rem;border-left:3px solid #d0d5dd;color:#888;font-size:0.82rem;white-space:pre-line;"></div>
@@ -484,6 +499,61 @@
</div>
<pre id="test-api-result" style="margin-top:0.75rem;background:#f8f9fb;padding:1rem;border-radius:8px;font-size:0.85rem;display:none;overflow-x:auto;"></pre>
</div>
<!-- Vastauspohjat -->
<div class="table-card" style="padding:1.5rem;margin-top:1rem;">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;">
<h3 style="color:#0f3460;margin:0;border-bottom:none;">Vastauspohjat</h3>
<button class="btn-primary" id="btn-add-template" style="font-size:0.85rem;">+ Uusi pohja</button>
</div>
<p style="color:#666;font-size:0.85rem;margin-bottom:1rem;">Nopeat vastauspohjat tiketteihin. Valittavissa vastauslomakkeen valikosta.</p>
<div id="templates-list"></div>
<div id="template-form" style="display:none;margin-top:1rem;padding:1rem;background:#f8f9fb;border-radius:8px;">
<input type="hidden" id="template-edit-id">
<div class="form-group" style="margin-bottom:0.5rem;">
<label style="font-size:0.85rem;">Nimi</label>
<input type="text" id="template-edit-name" placeholder="esim. Kuittaus vastaanotettu">
</div>
<div class="form-group" style="margin-bottom:0.5rem;">
<label style="font-size:0.85rem;">Sisältö</label>
<textarea id="template-edit-body" rows="4" placeholder="Kiitos viestistäsi! Olemme vastaanottaneet asiasi ja palaamme siihen mahdollisimman pian."></textarea>
</div>
<div style="display:flex;gap:0.5rem;">
<button class="btn-primary" id="btn-save-template">Tallenna</button>
<button class="btn-secondary" id="btn-cancel-template">Peruuta</button>
</div>
</div>
</div>
<!-- Priority-sähköpostit -->
<div class="table-card" style="padding:1.5rem;margin-top:1rem;">
<h3 style="color:#0f3460;margin-bottom:0.5rem;border-bottom:2px solid #f0f2f5;padding-bottom:0.5rem;">Priority-sähköpostiosoitteet</h3>
<p style="color:#666;font-size:0.85rem;margin-bottom:1rem;">Näiltä osoitteilta saapuvat tiketit saavat automaattisesti "Tärkeä"-prioriteetin.</p>
<textarea id="priority-emails-textarea" rows="4" style="width:100%;max-width:500px;font-family:monospace;font-size:0.85rem;" placeholder="vip@yritys.fi&#10;toimitusjohtaja@firma.fi"></textarea>
<div style="margin-top:0.5rem;">
<button class="btn-primary" id="btn-save-priority-emails">Tallenna</button>
</div>
</div>
<!-- Telegram-asetukset -->
<div class="table-card" style="padding:1.5rem;margin-top:1rem;">
<h3 style="color:#0f3460;margin-bottom:0.5rem;border-bottom:2px solid #f0f2f5;padding-bottom:0.5rem;">Telegram-hälytykset</h3>
<p style="color:#666;font-size:0.85rem;margin-bottom:1rem;">URGENT-prioriteetin tiketit lähettävät hälytyksen Telegram-bottiin.</p>
<div class="form-grid" style="max-width:500px;">
<div class="form-group full-width">
<label>Bot Token</label>
<input type="text" id="settings-telegram-token" placeholder="123456:ABC-DEF..." style="font-family:monospace;">
</div>
<div class="form-group full-width">
<label>Chat ID</label>
<input type="text" id="settings-telegram-chat" placeholder="-1001234567890" style="font-family:monospace;">
</div>
<div class="form-group full-width" style="display:flex;gap:0.5rem;">
<button class="btn-primary" id="btn-save-telegram">Tallenna</button>
<button class="btn-secondary" id="btn-test-telegram">Testaa</button>
</div>
</div>
</div>
</div>
</div>