Add cross-company ticket viewing and move Yritykset button to header
- tickets endpoint supports ?all=1 to fetch from all user's companies - ticket_detail/reply/status/etc support ?company_id= for cross-company ops - Support tab shows all companies' tickets with company badge on subject - Yritykset button moved from tab bar to header (next to Käyttäjät) - requireCompanyOrParam() helper for ticket endpoints Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
154
api.php
154
api.php
@@ -105,6 +105,22 @@ function requireCompany(): string {
|
|||||||
return $companyId;
|
return $companyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Kuten requireCompany(), mutta sallii company_id:n overriden GET-parametrista
|
||||||
|
// Käytetään tiketti-endpointeissa jotta toisen yrityksen tikettejä voi avata
|
||||||
|
function requireCompanyOrParam(): string {
|
||||||
|
$paramCompany = $_GET['company_id'] ?? '';
|
||||||
|
if (!empty($paramCompany)) {
|
||||||
|
$userCompanies = $_SESSION['companies'] ?? [];
|
||||||
|
if (!in_array($paramCompany, $userCompanies)) {
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode(['error' => 'Ei oikeutta tähän yritykseen']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$_SESSION['company_id'] = $paramCompany;
|
||||||
|
}
|
||||||
|
return requireCompany();
|
||||||
|
}
|
||||||
|
|
||||||
function companyFile(string $filename): string {
|
function companyFile(string $filename): string {
|
||||||
return getCompanyDir() . '/' . $filename;
|
return getCompanyDir() . '/' . $filename;
|
||||||
}
|
}
|
||||||
@@ -1663,62 +1679,86 @@ switch ($action) {
|
|||||||
// ---------- TICKETS ----------
|
// ---------- TICKETS ----------
|
||||||
case 'tickets':
|
case 'tickets':
|
||||||
requireAuth();
|
requireAuth();
|
||||||
requireCompany();
|
$allCompanies = !empty($_GET['all']);
|
||||||
$tickets = loadTickets();
|
$userCompanyIds = $_SESSION['companies'] ?? [];
|
||||||
// Palauta ilman viestisisältöjä (lista-näkymä)
|
|
||||||
// Auto-close tarkistus: sulje tiketit joiden auto_close_at on ohitettu
|
// Kerää yritykset joista haetaan
|
||||||
$now = date('Y-m-d H:i:s');
|
$companiesToQuery = [];
|
||||||
$autoCloseCount = 0;
|
if ($allCompanies && count($userCompanyIds) > 1) {
|
||||||
foreach ($tickets as &$tc) {
|
$allComps = loadCompanies();
|
||||||
if (!empty($tc['auto_close_at']) && $tc['auto_close_at'] <= $now && !in_array($tc['status'], ['suljettu'])) {
|
foreach ($allComps as $c) {
|
||||||
$tc['status'] = 'suljettu';
|
if (in_array($c['id'], $userCompanyIds)) {
|
||||||
$tc['updated'] = $now;
|
$companiesToQuery[] = $c;
|
||||||
$autoCloseCount++;
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requireCompany();
|
||||||
|
$companiesToQuery[] = ['id' => $_SESSION['company_id'], 'nimi' => ''];
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = [];
|
||||||
|
foreach ($companiesToQuery as $comp) {
|
||||||
|
$cDir = DATA_DIR . '/companies/' . $comp['id'];
|
||||||
|
$ticketsFile = $cDir . '/tickets.json';
|
||||||
|
if (!file_exists($ticketsFile)) continue;
|
||||||
|
$tickets = json_decode(file_get_contents($ticketsFile), true) ?: [];
|
||||||
|
|
||||||
|
// Auto-close tarkistus
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
$autoCloseCount = 0;
|
||||||
|
foreach ($tickets as &$tc) {
|
||||||
|
if (!empty($tc['auto_close_at']) && $tc['auto_close_at'] <= $now && !in_array($tc['status'], ['suljettu'])) {
|
||||||
|
$tc['status'] = 'suljettu';
|
||||||
|
$tc['updated'] = $now;
|
||||||
|
$autoCloseCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($tc);
|
||||||
|
if ($autoCloseCount > 0) {
|
||||||
|
file_put_contents($ticketsFile, json_encode($tickets, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve mailbox names for this company
|
||||||
|
$confFile = $cDir . '/config.json';
|
||||||
|
$companyConf = file_exists($confFile) ? (json_decode(file_get_contents($confFile), true) ?: []) : [];
|
||||||
|
$mailboxNames = [];
|
||||||
|
foreach ($companyConf['mailboxes'] ?? [] as $mb) {
|
||||||
|
$mailboxNames[$mb['id']] = $mb['nimi'];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($tickets as $t) {
|
||||||
|
$msgCount = count($t['messages'] ?? []);
|
||||||
|
$lastMsg = $msgCount > 0 ? $t['messages'][$msgCount - 1] : null;
|
||||||
|
$list[] = [
|
||||||
|
'id' => $t['id'],
|
||||||
|
'subject' => $t['subject'],
|
||||||
|
'from_email' => $t['from_email'],
|
||||||
|
'from_name' => $t['from_name'],
|
||||||
|
'status' => $t['status'],
|
||||||
|
'type' => $t['type'] ?? 'muu',
|
||||||
|
'assigned_to' => $t['assigned_to'] ?? '',
|
||||||
|
'customer_id' => $t['customer_id'] ?? '',
|
||||||
|
'customer_name' => $t['customer_name'] ?? '',
|
||||||
|
'tags' => $t['tags'] ?? [],
|
||||||
|
'auto_close_at' => $t['auto_close_at'] ?? '',
|
||||||
|
'mailbox_id' => $t['mailbox_id'] ?? '',
|
||||||
|
'mailbox_name' => $mailboxNames[$t['mailbox_id'] ?? ''] ?? '',
|
||||||
|
'company_id' => $comp['id'],
|
||||||
|
'company_name' => $comp['nimi'] ?? '',
|
||||||
|
'created' => $t['created'],
|
||||||
|
'updated' => $t['updated'],
|
||||||
|
'message_count' => $msgCount,
|
||||||
|
'last_message_type' => $lastMsg ? ($lastMsg['type'] ?? '') : '',
|
||||||
|
'last_message_time' => $lastMsg ? ($lastMsg['timestamp'] ?? '') : '',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unset($tc);
|
|
||||||
if ($autoCloseCount > 0) {
|
|
||||||
saveTickets($tickets);
|
|
||||||
addLog('ticket_auto_close', '', '', "Automaattisulku: $autoCloseCount tikettiä");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve mailbox names
|
|
||||||
$companyConf = loadCompanyConfig();
|
|
||||||
$mailboxNames = [];
|
|
||||||
foreach ($companyConf['mailboxes'] ?? [] as $mb) {
|
|
||||||
$mailboxNames[$mb['id']] = $mb['nimi'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$list = array_map(function($t) use ($mailboxNames) {
|
|
||||||
$msgCount = count($t['messages'] ?? []);
|
|
||||||
$lastMsg = $msgCount > 0 ? $t['messages'][$msgCount - 1] : null;
|
|
||||||
return [
|
|
||||||
'id' => $t['id'],
|
|
||||||
'subject' => $t['subject'],
|
|
||||||
'from_email' => $t['from_email'],
|
|
||||||
'from_name' => $t['from_name'],
|
|
||||||
'status' => $t['status'],
|
|
||||||
'type' => $t['type'] ?? 'muu',
|
|
||||||
'assigned_to' => $t['assigned_to'] ?? '',
|
|
||||||
'customer_id' => $t['customer_id'] ?? '',
|
|
||||||
'customer_name' => $t['customer_name'] ?? '',
|
|
||||||
'tags' => $t['tags'] ?? [],
|
|
||||||
'auto_close_at' => $t['auto_close_at'] ?? '',
|
|
||||||
'mailbox_id' => $t['mailbox_id'] ?? '',
|
|
||||||
'mailbox_name' => $mailboxNames[$t['mailbox_id'] ?? ''] ?? '',
|
|
||||||
'created' => $t['created'],
|
|
||||||
'updated' => $t['updated'],
|
|
||||||
'message_count' => $msgCount,
|
|
||||||
'last_message_type' => $lastMsg ? ($lastMsg['type'] ?? '') : '',
|
|
||||||
'last_message_time' => $lastMsg ? ($lastMsg['timestamp'] ?? '') : '',
|
|
||||||
];
|
|
||||||
}, $tickets);
|
|
||||||
echo json_encode($list);
|
echo json_encode($list);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'ticket_detail':
|
case 'ticket_detail':
|
||||||
requireAuth();
|
requireAuth();
|
||||||
requireCompany();
|
requireCompanyOrParam();
|
||||||
$id = $_GET['id'] ?? '';
|
$id = $_GET['id'] ?? '';
|
||||||
$tickets = loadTickets();
|
$tickets = loadTickets();
|
||||||
$ticket = null;
|
$ticket = null;
|
||||||
@@ -1880,7 +1920,7 @@ switch ($action) {
|
|||||||
|
|
||||||
case 'ticket_reply':
|
case 'ticket_reply':
|
||||||
requireAuth();
|
requireAuth();
|
||||||
requireCompany();
|
requireCompanyOrParam();
|
||||||
if ($method !== 'POST') break;
|
if ($method !== 'POST') break;
|
||||||
$input = json_decode(file_get_contents('php://input'), true);
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
$id = $input['id'] ?? '';
|
$id = $input['id'] ?? '';
|
||||||
@@ -1955,7 +1995,7 @@ switch ($action) {
|
|||||||
|
|
||||||
case 'ticket_status':
|
case 'ticket_status':
|
||||||
requireAuth();
|
requireAuth();
|
||||||
requireCompany();
|
requireCompanyOrParam();
|
||||||
if ($method !== 'POST') break;
|
if ($method !== 'POST') break;
|
||||||
$input = json_decode(file_get_contents('php://input'), true);
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
$id = $input['id'] ?? '';
|
$id = $input['id'] ?? '';
|
||||||
@@ -1990,7 +2030,7 @@ switch ($action) {
|
|||||||
|
|
||||||
case 'ticket_type':
|
case 'ticket_type':
|
||||||
requireAuth();
|
requireAuth();
|
||||||
requireCompany();
|
requireCompanyOrParam();
|
||||||
if ($method !== 'POST') break;
|
if ($method !== 'POST') break;
|
||||||
$input = json_decode(file_get_contents('php://input'), true);
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
$id = $input['id'] ?? '';
|
$id = $input['id'] ?? '';
|
||||||
@@ -2025,7 +2065,7 @@ switch ($action) {
|
|||||||
|
|
||||||
case 'ticket_customer':
|
case 'ticket_customer':
|
||||||
requireAuth();
|
requireAuth();
|
||||||
requireCompany();
|
requireCompanyOrParam();
|
||||||
if ($method !== 'POST') break;
|
if ($method !== 'POST') break;
|
||||||
$input = json_decode(file_get_contents('php://input'), true);
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
$id = $input['id'] ?? '';
|
$id = $input['id'] ?? '';
|
||||||
@@ -2055,7 +2095,7 @@ switch ($action) {
|
|||||||
|
|
||||||
case 'ticket_assign':
|
case 'ticket_assign':
|
||||||
requireAuth();
|
requireAuth();
|
||||||
requireCompany();
|
requireCompanyOrParam();
|
||||||
if ($method !== 'POST') break;
|
if ($method !== 'POST') break;
|
||||||
$input = json_decode(file_get_contents('php://input'), true);
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
$id = $input['id'] ?? '';
|
$id = $input['id'] ?? '';
|
||||||
@@ -2083,7 +2123,7 @@ switch ($action) {
|
|||||||
|
|
||||||
case 'ticket_note':
|
case 'ticket_note':
|
||||||
requireAuth();
|
requireAuth();
|
||||||
requireCompany();
|
requireCompanyOrParam();
|
||||||
if ($method !== 'POST') break;
|
if ($method !== 'POST') break;
|
||||||
$input = json_decode(file_get_contents('php://input'), true);
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
$id = $input['id'] ?? '';
|
$id = $input['id'] ?? '';
|
||||||
@@ -2125,7 +2165,7 @@ switch ($action) {
|
|||||||
|
|
||||||
case 'ticket_delete':
|
case 'ticket_delete':
|
||||||
requireAuth();
|
requireAuth();
|
||||||
requireCompany();
|
requireCompanyOrParam();
|
||||||
if ($method !== 'POST') break;
|
if ($method !== 'POST') break;
|
||||||
$input = json_decode(file_get_contents('php://input'), true);
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
$id = $input['id'] ?? '';
|
$id = $input['id'] ?? '';
|
||||||
@@ -2142,7 +2182,7 @@ switch ($action) {
|
|||||||
|
|
||||||
case 'ticket_tags':
|
case 'ticket_tags':
|
||||||
requireAuth();
|
requireAuth();
|
||||||
requireCompany();
|
requireCompanyOrParam();
|
||||||
if ($method !== 'POST') break;
|
if ($method !== 'POST') break;
|
||||||
$input = json_decode(file_get_contents('php://input'), true);
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
$id = $input['id'] ?? '';
|
$id = $input['id'] ?? '';
|
||||||
|
|||||||
@@ -66,6 +66,7 @@
|
|||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<span id="user-info" class="user-info"></span>
|
<span id="user-info" class="user-info"></span>
|
||||||
<button id="btn-users" class="btn-secondary" style="display:none">Käyttäjät</button>
|
<button id="btn-users" class="btn-secondary" style="display:none">Käyttäjät</button>
|
||||||
|
<button id="btn-companies" class="btn-secondary" style="display:none">Yritykset</button>
|
||||||
<button id="btn-add" class="btn-primary">+ Lisää asiakas</button>
|
<button id="btn-add" class="btn-primary">+ Lisää asiakas</button>
|
||||||
<button id="btn-logout" class="btn-secondary">Kirjaudu ulos</button>
|
<button id="btn-logout" class="btn-secondary">Kirjaudu ulos</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -78,7 +79,6 @@
|
|||||||
<button class="tab" data-tab="leads">Liidit</button>
|
<button class="tab" data-tab="leads">Liidit</button>
|
||||||
<button class="tab" data-tab="archive">Arkisto</button>
|
<button class="tab" data-tab="archive">Arkisto</button>
|
||||||
<button class="tab" data-tab="changelog">Muutosloki</button>
|
<button class="tab" data-tab="changelog">Muutosloki</button>
|
||||||
<button class="tab" data-tab="companies" id="tab-companies" style="display:none">Yritykset</button>
|
|
||||||
<button class="tab" data-tab="settings" id="tab-settings" style="display:none">API</button>
|
<button class="tab" data-tab="settings" id="tab-settings" style="display:none">API</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
55
script.js
55
script.js
@@ -6,6 +6,7 @@ let currentDetailId = null;
|
|||||||
let currentUser = { username: '', nimi: '', role: '' };
|
let currentUser = { username: '', nimi: '', role: '' };
|
||||||
let currentCompany = null; // {id, nimi}
|
let currentCompany = null; // {id, nimi}
|
||||||
let availableCompanies = []; // [{id, nimi}, ...]
|
let availableCompanies = []; // [{id, nimi}, ...]
|
||||||
|
let currentTicketCompanyId = ''; // Avatun tiketin yritys (cross-company tuki)
|
||||||
|
|
||||||
// Elements
|
// Elements
|
||||||
const loginScreen = document.getElementById('login-screen');
|
const loginScreen = document.getElementById('login-screen');
|
||||||
@@ -176,7 +177,7 @@ async function showDashboard() {
|
|||||||
// Näytä admin-toiminnot vain adminille
|
// Näytä admin-toiminnot vain adminille
|
||||||
document.getElementById('btn-users').style.display = currentUser.role === 'admin' ? '' : 'none';
|
document.getElementById('btn-users').style.display = currentUser.role === 'admin' ? '' : 'none';
|
||||||
document.getElementById('tab-settings').style.display = currentUser.role === 'admin' ? '' : 'none';
|
document.getElementById('tab-settings').style.display = currentUser.role === 'admin' ? '' : 'none';
|
||||||
document.getElementById('tab-companies').style.display = currentUser.role === 'admin' ? '' : 'none';
|
document.getElementById('btn-companies').style.display = currentUser.role === 'admin' ? '' : 'none';
|
||||||
// Yritysvalitsin
|
// Yritysvalitsin
|
||||||
populateCompanySelector();
|
populateCompanySelector();
|
||||||
// Avaa oikea tabi URL-hashin perusteella (tai customers oletuks)
|
// Avaa oikea tabi URL-hashin perusteella (tai customers oletuks)
|
||||||
@@ -249,6 +250,14 @@ document.getElementById('btn-users').addEventListener('click', () => {
|
|||||||
loadUsers();
|
loadUsers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById('btn-companies').addEventListener('click', () => {
|
||||||
|
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
||||||
|
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
|
||||||
|
document.getElementById('tab-content-companies').classList.add('active');
|
||||||
|
window.location.hash = 'companies';
|
||||||
|
loadCompaniesTab();
|
||||||
|
});
|
||||||
|
|
||||||
// ==================== CUSTOMERS ====================
|
// ==================== CUSTOMERS ====================
|
||||||
|
|
||||||
async function loadCustomers() {
|
async function loadCustomers() {
|
||||||
@@ -1031,7 +1040,9 @@ const ticketTypeLabels = {
|
|||||||
|
|
||||||
async function loadTickets() {
|
async function loadTickets() {
|
||||||
try {
|
try {
|
||||||
tickets = await apiCall('tickets');
|
// Hae kaikkien yritysten tiketit jos useampi yritys
|
||||||
|
const allParam = availableCompanies.length > 1 ? '&all=1' : '';
|
||||||
|
tickets = await apiCall('tickets' + allParam);
|
||||||
renderTickets();
|
renderTickets();
|
||||||
} catch (e) { console.error(e); }
|
} catch (e) { console.error(e); }
|
||||||
}
|
}
|
||||||
@@ -1081,16 +1092,18 @@ function renderTickets() {
|
|||||||
} else {
|
} else {
|
||||||
noTickets.style.display = 'none';
|
noTickets.style.display = 'none';
|
||||||
document.getElementById('tickets-table').style.display = 'table';
|
document.getElementById('tickets-table').style.display = 'table';
|
||||||
|
const multiCompany = availableCompanies.length > 1;
|
||||||
ttbody.innerHTML = filtered.map(t => {
|
ttbody.innerHTML = filtered.map(t => {
|
||||||
const lastType = t.last_message_type === 'reply_out' ? '→' : (t.last_message_type === 'note' ? '📝' : '←');
|
const lastType = t.last_message_type === 'reply_out' ? '→' : (t.last_message_type === 'note' ? '📝' : '←');
|
||||||
const typeLabel = ticketTypeLabels[t.type] || 'Muu';
|
const typeLabel = ticketTypeLabels[t.type] || 'Muu';
|
||||||
const rowClass = t.status === 'kasittelyssa' ? 'ticket-row-active' : '';
|
const rowClass = t.status === 'kasittelyssa' ? 'ticket-row-active' : '';
|
||||||
const checked = bulkSelectedIds.has(t.id) ? 'checked' : '';
|
const checked = bulkSelectedIds.has(t.id) ? 'checked' : '';
|
||||||
return `<tr data-ticket-id="${t.id}" class="${rowClass}">
|
const companyBadge = multiCompany && t.company_name ? `<span class="company-badge">${esc(t.company_name)}</span> ` : '';
|
||||||
|
return `<tr data-ticket-id="${t.id}" data-company-id="${t.company_id || ''}" class="${rowClass}">
|
||||||
<td onclick="event.stopPropagation()"><input type="checkbox" class="ticket-checkbox" data-ticket-id="${t.id}" ${checked}></td>
|
<td onclick="event.stopPropagation()"><input type="checkbox" class="ticket-checkbox" data-ticket-id="${t.id}" ${checked}></td>
|
||||||
<td><span class="ticket-status ticket-status-${t.status}">${ticketStatusLabels[t.status] || t.status}</span></td>
|
<td><span class="ticket-status ticket-status-${t.status}">${ticketStatusLabels[t.status] || t.status}</span></td>
|
||||||
<td><span class="ticket-type ticket-type-${t.type || 'muu'}">${typeLabel}</span></td>
|
<td><span class="ticket-type ticket-type-${t.type || 'muu'}">${typeLabel}</span></td>
|
||||||
<td><strong>${esc(t.subject)}</strong></td>
|
<td>${companyBadge}<strong>${esc(t.subject)}</strong></td>
|
||||||
<td>${esc(t.mailbox_name || t.from_name || t.from_email)}</td>
|
<td>${esc(t.mailbox_name || t.from_name || t.from_email)}</td>
|
||||||
<td>${t.customer_name ? esc(t.customer_name) : '<span style="color:#ccc;">-</span>'}</td>
|
<td>${t.customer_name ? esc(t.customer_name) : '<span style="color:#ccc;">-</span>'}</td>
|
||||||
<td>${(t.tags || []).length > 0 ? (t.tags || []).map(tag => '<span class="ticket-tag">#' + esc(tag) + '</span>').join(' ') : '<span style="color:#ccc;">-</span>'}</td>
|
<td>${(t.tags || []).length > 0 ? (t.tags || []).map(tag => '<span class="ticket-tag">#' + esc(tag) + '</span>').join(' ') : '<span style="color:#ccc;">-</span>'}</td>
|
||||||
@@ -1138,12 +1151,18 @@ document.getElementById('bulk-select-all').addEventListener('change', function()
|
|||||||
|
|
||||||
document.getElementById('tickets-tbody').addEventListener('click', (e) => {
|
document.getElementById('tickets-tbody').addEventListener('click', (e) => {
|
||||||
const row = e.target.closest('tr');
|
const row = e.target.closest('tr');
|
||||||
if (row && row.dataset.ticketId) showTicketDetail(row.dataset.ticketId);
|
if (row && row.dataset.ticketId) showTicketDetail(row.dataset.ticketId, row.dataset.companyId || '');
|
||||||
});
|
});
|
||||||
|
|
||||||
async function showTicketDetail(id) {
|
// Helper: lisää company_id query parametri tiketti-kutsuihin
|
||||||
|
function ticketCompanyParam() {
|
||||||
|
return currentTicketCompanyId ? '&company_id=' + encodeURIComponent(currentTicketCompanyId) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function showTicketDetail(id, companyId = '') {
|
||||||
try {
|
try {
|
||||||
const ticket = await apiCall('ticket_detail&id=' + encodeURIComponent(id));
|
currentTicketCompanyId = companyId;
|
||||||
|
const ticket = await apiCall('ticket_detail&id=' + encodeURIComponent(id) + ticketCompanyParam());
|
||||||
currentTicketId = id;
|
currentTicketId = id;
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
@@ -1205,21 +1224,21 @@ async function showTicketDetail(id) {
|
|||||||
// Type change handler
|
// Type change handler
|
||||||
document.getElementById('ticket-type-select').addEventListener('change', async function() {
|
document.getElementById('ticket-type-select').addEventListener('change', async function() {
|
||||||
try {
|
try {
|
||||||
await apiCall('ticket_type', 'POST', { id: currentTicketId, type: this.value });
|
await apiCall('ticket_type' + ticketCompanyParam(), 'POST', { id: currentTicketId, type: this.value });
|
||||||
} catch (e) { alert(e.message); }
|
} catch (e) { alert(e.message); }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Status change handler
|
// Status change handler
|
||||||
document.getElementById('ticket-status-select').addEventListener('change', async function() {
|
document.getElementById('ticket-status-select').addEventListener('change', async function() {
|
||||||
try {
|
try {
|
||||||
await apiCall('ticket_status', 'POST', { id: currentTicketId, status: this.value });
|
await apiCall('ticket_status' + ticketCompanyParam(), 'POST', { id: currentTicketId, status: this.value });
|
||||||
} catch (e) { alert(e.message); }
|
} catch (e) { alert(e.message); }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assign handler
|
// Assign handler
|
||||||
document.getElementById('ticket-assign-select').addEventListener('change', async function() {
|
document.getElementById('ticket-assign-select').addEventListener('change', async function() {
|
||||||
try {
|
try {
|
||||||
await apiCall('ticket_assign', 'POST', { id: currentTicketId, assigned_to: this.value });
|
await apiCall('ticket_assign' + ticketCompanyParam(), 'POST', { id: currentTicketId, assigned_to: this.value });
|
||||||
} catch (e) { alert(e.message); }
|
} catch (e) { alert(e.message); }
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1239,7 +1258,7 @@ async function showTicketDetail(id) {
|
|||||||
const selOpt = this.options[this.selectedIndex];
|
const selOpt = this.options[this.selectedIndex];
|
||||||
const custName = this.value ? selOpt.textContent : '';
|
const custName = this.value ? selOpt.textContent : '';
|
||||||
try {
|
try {
|
||||||
await apiCall('ticket_customer', 'POST', { id: currentTicketId, customer_id: this.value, customer_name: custName });
|
await apiCall('ticket_customer' + ticketCompanyParam(), 'POST', { id: currentTicketId, customer_id: this.value, customer_name: custName });
|
||||||
} catch (e) { alert(e.message); }
|
} catch (e) { alert(e.message); }
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1247,7 +1266,7 @@ async function showTicketDetail(id) {
|
|||||||
document.getElementById('btn-ticket-delete').addEventListener('click', async () => {
|
document.getElementById('btn-ticket-delete').addEventListener('click', async () => {
|
||||||
if (!confirm('Poistetaanko tiketti "' + ticket.subject + '"?')) return;
|
if (!confirm('Poistetaanko tiketti "' + ticket.subject + '"?')) return;
|
||||||
try {
|
try {
|
||||||
await apiCall('ticket_delete', 'POST', { id: currentTicketId });
|
await apiCall('ticket_delete' + ticketCompanyParam(), 'POST', { id: currentTicketId });
|
||||||
showTicketListView();
|
showTicketListView();
|
||||||
loadTickets();
|
loadTickets();
|
||||||
} catch (e) { alert(e.message); }
|
} catch (e) { alert(e.message); }
|
||||||
@@ -1264,8 +1283,8 @@ async function showTicketDetail(id) {
|
|||||||
if (!currentTags.includes(newTag)) currentTags.push(newTag);
|
if (!currentTags.includes(newTag)) currentTags.push(newTag);
|
||||||
input.value = '';
|
input.value = '';
|
||||||
try {
|
try {
|
||||||
await apiCall('ticket_tags', 'POST', { id: currentTicketId, tags: currentTags });
|
await apiCall('ticket_tags' + ticketCompanyParam(), 'POST', { id: currentTicketId, tags: currentTags });
|
||||||
await showTicketDetail(currentTicketId);
|
await showTicketDetail(currentTicketId, currentTicketCompanyId);
|
||||||
} catch (e2) { alert(e2.message); }
|
} catch (e2) { alert(e2.message); }
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1277,8 +1296,8 @@ async function showTicketDetail(id) {
|
|||||||
const tagToRemove = tagEl.dataset.tag;
|
const tagToRemove = tagEl.dataset.tag;
|
||||||
const currentTags = (ticket.tags || []).filter(t => t !== tagToRemove);
|
const currentTags = (ticket.tags || []).filter(t => t !== tagToRemove);
|
||||||
try {
|
try {
|
||||||
await apiCall('ticket_tags', 'POST', { id: currentTicketId, tags: currentTags });
|
await apiCall('ticket_tags' + ticketCompanyParam(), 'POST', { id: currentTicketId, tags: currentTags });
|
||||||
await showTicketDetail(currentTicketId);
|
await showTicketDetail(currentTicketId, currentTicketCompanyId);
|
||||||
} catch (e2) { alert(e2.message); }
|
} catch (e2) { alert(e2.message); }
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1362,9 +1381,9 @@ document.getElementById('btn-send-reply').addEventListener('click', async () =>
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const action = ticketReplyType === 'note' ? 'ticket_note' : 'ticket_reply';
|
const action = ticketReplyType === 'note' ? 'ticket_note' : 'ticket_reply';
|
||||||
await apiCall(action, 'POST', { id: currentTicketId, body });
|
await apiCall(action + ticketCompanyParam(), 'POST', { id: currentTicketId, body });
|
||||||
// Reload the detail view
|
// Reload the detail view
|
||||||
await showTicketDetail(currentTicketId);
|
await showTicketDetail(currentTicketId, currentTicketCompanyId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
alert(e.message);
|
alert(e.message);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user