diff --git a/api.php b/api.php
index c844418..1e66173 100644
--- a/api.php
+++ b/api.php
@@ -1655,6 +1655,40 @@ switch ($action) {
saveTickets($tickets);
break;
+ case 'ticket_type':
+ requireAuth();
+ if ($method !== 'POST') break;
+ $input = json_decode(file_get_contents('php://input'), true);
+ $id = $input['id'] ?? '';
+ $type = $input['type'] ?? '';
+ $validTypes = ['laskutus', 'tekniikka', 'vika', 'muu'];
+ if (!in_array($type, $validTypes)) {
+ http_response_code(400);
+ echo json_encode(['error' => 'Virheellinen tyyppi']);
+ break;
+ }
+ $tickets = loadTickets();
+ $found = false;
+ foreach ($tickets as &$t) {
+ if ($t['id'] === $id) {
+ $oldType = $t['type'] ?? 'muu';
+ $t['type'] = $type;
+ $t['updated'] = date('Y-m-d H:i:s');
+ $found = true;
+ addLog('ticket_type', $t['id'], $t['subject'], "Tyyppi: {$oldType} → {$type}");
+ echo json_encode($t);
+ break;
+ }
+ }
+ unset($t);
+ if (!$found) {
+ http_response_code(404);
+ echo json_encode(['error' => 'Tikettiä ei löydy']);
+ break;
+ }
+ saveTickets($tickets);
+ break;
+
case 'ticket_assign':
requireAuth();
if ($method !== 'POST') break;
diff --git a/index.html b/index.html
index 744e2df..bbb4aaa 100644
--- a/index.html
+++ b/index.html
@@ -72,11 +72,11 @@
+
-
@@ -241,19 +241,27 @@
-
+
@@ -262,6 +270,7 @@
| Tila |
+ Tyyppi |
Aihe |
Lähettäjä |
Viestejä |
diff --git a/script.js b/script.js
index 970c2ba..e746ee1 100644
--- a/script.js
+++ b/script.js
@@ -958,6 +958,13 @@ const ticketStatusLabels = {
suljettu: 'Suljettu',
};
+const ticketTypeLabels = {
+ laskutus: 'Laskutus',
+ tekniikka: 'Tekniikka',
+ vika: 'Vika',
+ muu: 'Muu',
+};
+
async function loadTickets() {
try {
tickets = await apiCall('tickets');
@@ -968,7 +975,20 @@ async function loadTickets() {
function renderTickets() {
const query = document.getElementById('ticket-search-input').value.toLowerCase().trim();
const statusFilter = document.getElementById('ticket-status-filter').value;
+ const typeFilter = document.getElementById('ticket-type-filter').value;
let filtered = tickets;
+
+ // Default: hide closed tickets unless explicitly selected or "kaikki"
+ if (!statusFilter || statusFilter === '') {
+ filtered = filtered.filter(t => t.status !== 'suljettu');
+ } else if (statusFilter !== 'kaikki') {
+ filtered = filtered.filter(t => t.status === statusFilter);
+ }
+
+ if (typeFilter) {
+ filtered = filtered.filter(t => (t.type || 'muu') === typeFilter);
+ }
+
if (query) {
filtered = filtered.filter(t =>
(t.subject || '').toLowerCase().includes(query) ||
@@ -976,9 +996,6 @@ function renderTickets() {
(t.from_email || '').toLowerCase().includes(query)
);
}
- if (statusFilter) {
- filtered = filtered.filter(t => t.status === statusFilter);
- }
const ttbody = document.getElementById('tickets-tbody');
const noTickets = document.getElementById('no-tickets');
@@ -991,8 +1008,11 @@ function renderTickets() {
document.getElementById('tickets-table').style.display = 'table';
ttbody.innerHTML = filtered.map(t => {
const lastType = t.last_message_type === 'reply_out' ? '→' : (t.last_message_type === 'note' ? '📝' : '←');
- return `
+ const typeLabel = ticketTypeLabels[t.type] || 'Muu';
+ const rowClass = t.status === 'kasittelyssa' ? 'ticket-row-active' : '';
+ return `
| ${ticketStatusLabels[t.status] || t.status} |
+ ${typeLabel} |
${esc(t.subject)} |
${esc(t.from_name || t.from_email)} |
${lastType} ${t.message_count} |
@@ -1001,7 +1021,9 @@ function renderTickets() {
`;
}).join('');
}
- document.getElementById('ticket-count').textContent = `${tickets.length} tikettiä`;
+
+ const openCount = tickets.filter(t => t.status !== 'suljettu').length;
+ document.getElementById('ticket-count').textContent = `${openCount} avointa tikettiä (${tickets.length} yht.)`;
// Status summary
const counts = {};
@@ -1015,6 +1037,7 @@ function renderTickets() {
document.getElementById('ticket-search-input').addEventListener('input', () => renderTickets());
document.getElementById('ticket-status-filter').addEventListener('change', () => renderTickets());
+document.getElementById('ticket-type-filter').addEventListener('change', () => renderTickets());
document.getElementById('tickets-tbody').addEventListener('click', (e) => {
const row = e.target.closest('tr');
@@ -1036,6 +1059,12 @@ async function showTicketDetail(id) {
+