diff --git a/assets/css/dashboard.css b/assets/css/dashboard.css
index d68e1f0..a1e2de4 100644
--- a/assets/css/dashboard.css
+++ b/assets/css/dashboard.css
@@ -139,6 +139,61 @@ body {
background: rgba(239, 68, 68, 0.1);
}
+.status-dropdown {
+ position: relative;
+ display: inline-block;
+ margin-right: 15px;
+}
+
+.dropdown-header {
+ padding: 8px 15px;
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ border-radius: 4px;
+ cursor: pointer;
+ min-width: 120px;
+}
+
+.dropdown-content {
+ display: none;
+ position: absolute;
+ top: 100%;
+ left: 0;
+ background: var(--bg-secondary);
+ min-width: 160px;
+ box-shadow: var(--shadow);
+ border-radius: 4px;
+ padding: 10px;
+ z-index: 100;
+ border: 1px solid var(--border-color);
+}
+
+.status-dropdown.active .dropdown-content {
+ display: block;
+}
+
+.dropdown-content label {
+ display: block;
+ padding: 8px;
+ cursor: pointer;
+ transition: background 0.2s;
+}
+
+.dropdown-content label:hover {
+ background: var(--hover-bg);
+}
+
+.dropdown-content .save-filter {
+ margin-top: 10px;
+ width: 100%;
+ padding: 8px;
+ background: #3b82f6;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+}
+
/*UNCHECKED BELOW*/
body.menu-open {
diff --git a/assets/js/dashboard.js b/assets/js/dashboard.js
index b1ebc23..0372d52 100644
--- a/assets/js/dashboard.js
+++ b/assets/js/dashboard.js
@@ -291,25 +291,62 @@ function initSearch() {
// Filter by status
function initStatusFilter() {
- const filter = document.createElement('select');
- filter.innerHTML = `
-
-
-
- `;
- filter.className = 'status-filter';
- filter.onchange = (e) => {
- const status = e.target.value;
- const rows = document.querySelectorAll('tbody tr');
- rows.forEach(row => {
- if (!status || row.querySelector('.status-' + status)) {
- row.style.display = '';
- } else {
- row.style.display = 'none';
- }
- });
+ const filterContainer = document.createElement('div');
+ filterContainer.className = 'status-filter-container';
+
+ // Create dropdown container
+ const dropdown = document.createElement('div');
+ dropdown.className = 'status-dropdown';
+
+ // Create dropdown header
+ const dropdownHeader = document.createElement('div');
+ dropdownHeader.className = 'dropdown-header';
+ dropdownHeader.textContent = 'Status Filter';
+
+ // Create dropdown content
+ const dropdownContent = document.createElement('div');
+ dropdownContent.className = 'dropdown-content';
+
+ const statuses = ['Open', 'Closed'];
+ statuses.forEach(status => {
+ const label = document.createElement('label');
+ const checkbox = document.createElement('input');
+ checkbox.type = 'checkbox';
+ checkbox.value = status;
+ checkbox.id = `status-${status.toLowerCase()}`;
+
+ const urlParams = new URLSearchParams(window.location.search);
+ const currentStatuses = urlParams.get('status') ? urlParams.get('status').split(',') : [];
+ checkbox.checked = currentStatuses.includes(status);
+
+ label.appendChild(checkbox);
+ label.appendChild(document.createTextNode(status));
+ dropdownContent.appendChild(label);
+ });
+
+ const saveButton = document.createElement('button');
+ saveButton.className = 'btn save-filter';
+ saveButton.textContent = 'Apply Filter';
+
+ saveButton.onclick = () => {
+ const checkedBoxes = dropdownContent.querySelectorAll('input:checked');
+ const selectedStatuses = Array.from(checkedBoxes).map(cb => cb.value);
+ localStorage.setItem('statusFilter', selectedStatuses.join(','));
+ window.location.href = selectedStatuses.length ? `?status=${selectedStatuses.join(',')}` : '?';
+ dropdown.classList.remove('active');
};
- document.querySelector('.table-controls .table-actions').prepend(filter);
+
+ // Toggle dropdown on header click
+ dropdownHeader.onclick = () => {
+ dropdown.classList.toggle('active');
+ };
+
+ dropdown.appendChild(dropdownHeader);
+ dropdown.appendChild(dropdownContent);
+ dropdownContent.appendChild(saveButton);
+ filterContainer.appendChild(dropdown);
+
+ document.querySelector('.table-controls .table-actions').prepend(filterContainer);
}
function sortTable(table, column) {
diff --git a/create_ticket_api.php b/create_ticket_api.php
index d956e25..f845208 100644
--- a/create_ticket_api.php
+++ b/create_ticket_api.php
@@ -1,6 +1,11 @@
connect_error) {
@@ -36,8 +41,17 @@ if ($conn->connect_error) {
exit;
}
-// Get POST data
-$data = json_decode(file_get_contents('php://input'), true);
+// Force JSON content type for all incoming requests
+header('Content-Type: application/json');
+
+// Parse input regardless of content-type header
+$rawInput = file_get_contents('php://input');
+$data = json_decode($rawInput, true);
+
+if (!$data) {
+ // Try parsing as URL-encoded data
+ parse_str($rawInput, $data);
+}
// Generate ticket ID (9-digit format with leading zeros)
$ticket_id = sprintf('%09d', mt_rand(1, 999999999));
@@ -82,3 +96,37 @@ if ($stmt->execute()) {
$stmt->close();
$conn->close();
+
+// Discord webhook
+$discord_webhook_url = $envVars['DISCORD_WEBHOOK_URL'];
+
+// Map priorities to Discord colors (decimal format)
+$priorityColors = [
+ "1" => 16736589, // --priority-1: #ff4d4d
+ "2" => 16753958, // --priority-2: #ffa726
+ "3" => 4363509, // --priority-3: #42a5f5
+ "4" => 6736490 // --priority-4: #66bb6a
+];
+
+$discord_data = [
+ "content" => "",
+ "embeds" => [[
+ "title" => "New Ticket Created: #" . $ticket_id,
+ "description" => $title,
+ "url" => "http://10.10.10.45/ticket.php?id=" . $ticket_id,
+ "color" => $priorityColors[$priority],
+ "fields" => [
+ ["name" => "Priority", "value" => $priority, "inline" => true],
+ ["name" => "Category", "value" => $category, "inline" => true],
+ ["name" => "Type", "value" => $type, "inline" => true]
+ ]
+ ]]
+];
+
+$ch = curl_init($discord_webhook_url);
+curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
+curl_setopt($ch, CURLOPT_POST, 1);
+curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($discord_data));
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_exec($ch);
+curl_close($ch);
diff --git a/dashboard.php b/dashboard.php
index 3103531..8ec4758 100644
--- a/dashboard.php
+++ b/dashboard.php
@@ -26,14 +26,21 @@ $defaultSortColumn = isset($_COOKIE['defaultSortColumn']) ? $_COOKIE['defaultSor
$sortDirection = isset($_COOKIE['sortDirection']) ? $_COOKIE['sortDirection'] : 'desc';
$offset = ($page - 1) * $limit;
-// Get total number of tickets
-$totalTicketsQuery = "SELECT COUNT(*) as total FROM tickets";
+// Get total number of tickets based on current filter
+$status = isset($_GET['status']) ? $_GET['status'] : 'Open';
+$statuses = explode(',', $status);
+$whereClause = "";
+if (isset($_GET['status']) && !empty($_GET['status'])) {
+ $statuses = explode(',', $_GET['status']);
+ $whereClause = "WHERE status IN ('" . implode("','", $statuses) . "')";
+}
+$totalTicketsQuery = "SELECT COUNT(*) as total FROM tickets $whereClause";
$totalTicketsResult = $conn->query($totalTicketsQuery);
$totalTickets = $totalTicketsResult->fetch_assoc()['total'];
$totalPages = ceil($totalTickets / $limit);
-// Modify SQL to use these settings
-$sql = "SELECT * FROM tickets ORDER BY $defaultSortColumn $sortDirection LIMIT $limit OFFSET $offset";
+// Modify SQL to use these settings and filter
+$sql = "SELECT * FROM tickets $whereClause ORDER BY $defaultSortColumn $sortDirection LIMIT $limit OFFSET $offset";
$result = $conn->query($sql);
?>
@@ -62,18 +69,18 @@ $result = $conn->query($sql);
1) {
- echo "";
+ echo "";
}
// Page number buttons
for ($i = 1; $i <= $totalPages; $i++) {
$activeClass = ($i === $page) ? 'active' : '';
- echo "";
+ echo "";
}
// Next page button
if ($page < $totalPages) {
- echo "";
+ echo "";
}
?>