feat: complete TDS v1.2 redesign across all views
Full application redesign using Terminal Design System v1.2 (lt-* class system). Introduces shared layout_header/footer partials, upgrades base.css/base.js to TDS v1.2, and rewrites all views (Dashboard, Ticket, CreateTicket, and all 7 admin views) with lt-frame, lt-table, lt-modal, lt-stats-grid, lt-kv-grid, and data-action event delegation patterns. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,346 +1,297 @@
|
||||
<?php
|
||||
// Admin view for managing recurring tickets
|
||||
// Receives $recurringTickets from controller
|
||||
require_once __DIR__ . '/../../middleware/SecurityHeadersMiddleware.php';
|
||||
require_once __DIR__ . '/../../middleware/CsrfMiddleware.php';
|
||||
$nonce = SecurityHeadersMiddleware::getNonce();
|
||||
$nonce = SecurityHeadersMiddleware::getNonce();
|
||||
$pageTitle = 'Recurring Tickets';
|
||||
$activeNav = 'admin-recurring';
|
||||
$pageStyles = ['/assets/css/dashboard.css?v=20260327'];
|
||||
$pageScripts = [];
|
||||
include __DIR__ . '/../../views/layout_header.php';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Recurring Tickets - Admin</title>
|
||||
<link rel="icon" type="image/png" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/images/favicon.png">
|
||||
<link rel="stylesheet" href="/assets/css/base.css">
|
||||
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/dashboard.css?v=20260320">
|
||||
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/ticket.css?v=20260320">
|
||||
<script nonce="<?php echo $nonce; ?>" src="/assets/js/base.js"></script>
|
||||
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/utils.js?v=20260320"></script>
|
||||
<script nonce="<?php echo $nonce; ?>">
|
||||
window.CSRF_TOKEN = '<?php echo CsrfMiddleware::getToken(); ?>';
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="user-header">
|
||||
<div class="user-header-left">
|
||||
<a href="/" class="back-link">[ ← DASHBOARD ]</a>
|
||||
<span class="admin-page-title">Admin: Recurring Tickets</span>
|
||||
</div>
|
||||
<div class="user-header-right">
|
||||
<?php if (isset($GLOBALS['currentUser'])): ?>
|
||||
<span class="user-name">[ <?php echo htmlspecialchars(strtoupper($GLOBALS['currentUser']['display_name'] ?? $GLOBALS['currentUser']['username'])); ?> ]</span>
|
||||
<span class="admin-badge">[ ADMIN ]</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ascii-frame-outer admin-container">
|
||||
<span class="bottom-left-corner">╚</span>
|
||||
<span class="bottom-right-corner">╝</span>
|
||||
<div class="lt-page-header">
|
||||
<div class="lt-flex lt-flex-gap-sm lt-flex-align-center">
|
||||
<a href="/" class="lt-btn lt-btn-ghost lt-btn-sm">← Dashboard</a>
|
||||
<span class="lt-text-muted lt-text-xs">/</span>
|
||||
<span class="lt-text-muted lt-text-xs">Admin: Recurring Tickets</span>
|
||||
</div>
|
||||
<button type="button" class="lt-btn lt-btn-primary" data-action="show-create-modal">+ NEW RECURRING TICKET</button>
|
||||
</div>
|
||||
|
||||
<div class="ascii-section-header">Recurring Tickets Management</div>
|
||||
<div class="ascii-content">
|
||||
<div class="ascii-frame-inner">
|
||||
<div class="admin-header-row">
|
||||
<h2>Scheduled Tickets</h2>
|
||||
<button data-action="show-create-modal" class="btn">+ NEW RECURRING TICKET</button>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Title Template</th>
|
||||
<th>Schedule</th>
|
||||
<th>Category</th>
|
||||
<th>Assigned To</th>
|
||||
<th>Next Run</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($recurringTickets)): ?>
|
||||
<tr>
|
||||
<td colspan="8" class="empty-state">No recurring tickets configured.</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($recurringTickets as $rt): ?>
|
||||
<tr>
|
||||
<td><?php echo $rt['recurring_id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($rt['title_template']); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$schedule = ucfirst($rt['schedule_type']);
|
||||
if ($rt['schedule_type'] === 'weekly') {
|
||||
$days = ['', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
|
||||
$schedule .= ' (' . ($days[$rt['schedule_day']] ?? '?') . ')';
|
||||
} elseif ($rt['schedule_type'] === 'monthly') {
|
||||
$schedule .= ' (Day ' . $rt['schedule_day'] . ')';
|
||||
}
|
||||
$schedule .= ' @ ' . substr($rt['schedule_time'], 0, 5);
|
||||
echo htmlspecialchars($schedule);
|
||||
?>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($rt['category']); ?></td>
|
||||
<td><?php echo htmlspecialchars($rt['assigned_name'] ?? $rt['assigned_username'] ?? 'Unassigned'); ?></td>
|
||||
<td class="nowrap"><?php echo date('M d, Y H:i', strtotime($rt['next_run_at'])); ?></td>
|
||||
<td>
|
||||
<span class="<?php echo $rt['is_active'] ? 'text-open' : 'text-closed'; ?>">
|
||||
<?php echo $rt['is_active'] ? 'Active' : 'Inactive'; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<button data-action="edit-recurring" data-id="<?php echo $rt['recurring_id']; ?>" class="btn btn-small">EDIT</button>
|
||||
<button data-action="toggle-recurring" data-id="<?php echo $rt['recurring_id']; ?>" class="btn btn-small">
|
||||
<?php echo $rt['is_active'] ? 'DISABLE' : 'ENABLE'; ?>
|
||||
</button>
|
||||
<button data-action="delete-recurring" data-id="<?php echo $rt['recurring_id']; ?>" class="btn btn-small btn-danger">DELETE</button>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Create/Edit Modal -->
|
||||
<div class="lt-modal-overlay" id="recurringModal" aria-hidden="true" role="dialog" aria-modal="true" aria-labelledby="modalTitle">
|
||||
<div class="lt-modal lt-modal-lg">
|
||||
<div class="lt-modal-header">
|
||||
<span class="lt-modal-title" id="modalTitle">Create Recurring Ticket</span>
|
||||
<button class="lt-modal-close" data-modal-close aria-label="Close">✕</button>
|
||||
</div>
|
||||
<form id="recurringForm">
|
||||
<input type="hidden" id="recurring_id" name="recurring_id">
|
||||
<div class="lt-modal-body">
|
||||
<div class="setting-row">
|
||||
<label for="title_template">Title Template *</label>
|
||||
<input type="text" id="title_template" name="title_template" required placeholder="Use {{date}}, {{month}}, etc.">
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<label for="description_template">Description Template</label>
|
||||
<textarea id="description_template" name="description_template" rows="8"></textarea>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<label for="schedule_type">Schedule Type *</label>
|
||||
<select id="schedule_type" name="schedule_type" required data-action="update-schedule-options">
|
||||
<option value="daily">Daily</option>
|
||||
<option value="weekly">Weekly</option>
|
||||
<option value="monthly">Monthly</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="setting-row is-hidden" id="schedule_day_row">
|
||||
<label for="schedule_day">Schedule Day</label>
|
||||
<select id="schedule_day" name="schedule_day"></select>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<label for="schedule_time">Schedule Time *</label>
|
||||
<input type="time" id="schedule_time" name="schedule_time" value="09:00" required>
|
||||
</div>
|
||||
<div class="setting-grid-2">
|
||||
<div class="setting-row setting-row-compact">
|
||||
<label for="category">Category</label>
|
||||
<select id="category" name="category">
|
||||
<option value="General">General</option>
|
||||
<option value="Hardware">Hardware</option>
|
||||
<option value="Software">Software</option>
|
||||
<option value="Network">Network</option>
|
||||
<option value="Security">Security</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="setting-row setting-row-compact">
|
||||
<label for="type">Type</label>
|
||||
<select id="type" name="type">
|
||||
<option value="Issue">Issue</option>
|
||||
<option value="Maintenance">Maintenance</option>
|
||||
<option value="Install">Install</option>
|
||||
<option value="Task">Task</option>
|
||||
<option value="Upgrade">Upgrade</option>
|
||||
<option value="Problem">Problem</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="setting-row setting-row-compact">
|
||||
<label for="priority">Priority</label>
|
||||
<select id="priority" name="priority">
|
||||
<option value="1">P1 - Critical</option>
|
||||
<option value="2">P2 - High</option>
|
||||
<option value="3">P3 - Medium</option>
|
||||
<option value="4" selected>P4 - Low</option>
|
||||
<option value="5">P5 - Lowest</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="setting-row setting-row-compact">
|
||||
<label for="assigned_to">Assign To</label>
|
||||
<select id="assigned_to" name="assigned_to">
|
||||
<option value="">Unassigned</option>
|
||||
<!-- Populated by JavaScript -->
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lt-modal-footer">
|
||||
<button type="submit" class="lt-btn lt-btn-primary">SAVE</button>
|
||||
<button type="button" class="lt-btn lt-btn-ghost" data-modal-close>CANCEL</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script nonce="<?php echo $nonce; ?>">
|
||||
function showCreateModal() {
|
||||
document.getElementById('modalTitle').textContent = 'Create Recurring Ticket';
|
||||
document.getElementById('recurringForm').reset();
|
||||
document.getElementById('recurring_id').value = '';
|
||||
updateScheduleOptions();
|
||||
lt.modal.open('recurringModal');
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
lt.modal.close('recurringModal');
|
||||
}
|
||||
|
||||
// Event delegation for data-action handlers
|
||||
document.addEventListener('click', function(event) {
|
||||
const target = event.target.closest('[data-action]');
|
||||
if (!target) return;
|
||||
|
||||
const action = target.dataset.action;
|
||||
switch (action) {
|
||||
case 'show-create-modal':
|
||||
showCreateModal();
|
||||
break;
|
||||
case 'edit-recurring':
|
||||
editRecurring(target.dataset.id);
|
||||
break;
|
||||
case 'toggle-recurring':
|
||||
toggleRecurring(target.dataset.id);
|
||||
break;
|
||||
case 'delete-recurring':
|
||||
deleteRecurring(target.dataset.id);
|
||||
break;
|
||||
<div class="lt-frame">
|
||||
<span class="lt-frame-bl">╚</span><span class="lt-frame-br">╝</span>
|
||||
<div class="lt-section-header">Scheduled Tickets</div>
|
||||
<div class="lt-section-body">
|
||||
<p class="lt-text-sm lt-text-muted" style="margin-bottom:0.75rem">
|
||||
Recurring tickets are automatically created on a schedule. Use <code>{{date}}</code>, <code>{{month}}</code>, <code>{{year}}</code> in title templates.
|
||||
</p>
|
||||
<div class="lt-table-wrap">
|
||||
<table class="lt-table lt-table-responsive" aria-label="Recurring tickets">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Title Template</th>
|
||||
<th scope="col">Schedule</th>
|
||||
<th scope="col">Category</th>
|
||||
<th scope="col">Assigned To</th>
|
||||
<th scope="col">Next Run</th>
|
||||
<th scope="col">Status</th>
|
||||
<th scope="col">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($recurringTickets)): ?>
|
||||
<tr><td colspan="7" class="lt-empty">No recurring tickets configured. Create schedules to auto-generate tickets.</td></tr>
|
||||
<?php else: foreach ($recurringTickets as $rt): ?>
|
||||
<?php
|
||||
$schedule = ucfirst($rt['schedule_type']);
|
||||
if ($rt['schedule_type'] === 'weekly') {
|
||||
$days = ['', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
|
||||
$schedule .= ' (' . ($days[$rt['schedule_day']] ?? '?') . ')';
|
||||
} elseif ($rt['schedule_type'] === 'monthly') {
|
||||
$schedule .= ' (Day ' . $rt['schedule_day'] . ')';
|
||||
}
|
||||
$schedule .= ' @ ' . substr($rt['schedule_time'], 0, 5);
|
||||
?>
|
||||
<tr>
|
||||
<td data-label="Title"><strong><?= htmlspecialchars($rt['title_template']) ?></strong></td>
|
||||
<td data-label="Schedule" class="lt-text-xs lt-text-cyan"><?= htmlspecialchars($schedule) ?></td>
|
||||
<td data-label="Category" class="lt-text-xs"><?= htmlspecialchars($rt['category']) ?></td>
|
||||
<td data-label="Assigned To" class="lt-text-xs">
|
||||
<?= htmlspecialchars($rt['assigned_name'] ?? $rt['assigned_username'] ?? 'Unassigned') ?>
|
||||
</td>
|
||||
<td data-label="Next Run" class="lt-text-xs lt-text-muted">
|
||||
<?= date('M d, Y H:i', strtotime($rt['next_run_at'])) ?>
|
||||
</td>
|
||||
<td data-label="Status">
|
||||
<span class="lt-status <?= $rt['is_active'] ? 'lt-status-open' : 'lt-status-closed' ?>">
|
||||
<?= $rt['is_active'] ? 'Active' : 'Inactive' ?>
|
||||
</span>
|
||||
</td>
|
||||
<td data-label="Actions">
|
||||
<div class="lt-btn-group">
|
||||
<button type="button" class="lt-btn lt-btn-sm"
|
||||
data-action="edit-recurring" data-id="<?= $rt['recurring_id'] ?>">EDIT</button>
|
||||
<button type="button" class="lt-btn lt-btn-sm"
|
||||
data-action="toggle-recurring" data-id="<?= $rt['recurring_id'] ?>">
|
||||
<?= $rt['is_active'] ? 'PAUSE' : 'RESUME' ?>
|
||||
</button>
|
||||
<button type="button" class="lt-btn lt-btn-sm lt-btn-danger"
|
||||
data-action="delete-recurring" data-id="<?= $rt['recurring_id'] ?>">DEL</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; endif ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Create/Edit Modal -->
|
||||
<div class="lt-modal-overlay" id="recurringModal" aria-hidden="true" role="dialog"
|
||||
aria-modal="true" aria-labelledby="recModalTitle">
|
||||
<div class="lt-modal">
|
||||
<div class="lt-modal-header">
|
||||
<span class="lt-modal-title" id="recModalTitle">Create Recurring Ticket</span>
|
||||
<button type="button" class="lt-modal-close" data-modal-close aria-label="Close">✕</button>
|
||||
</div>
|
||||
<form id="recurringForm">
|
||||
<input type="hidden" id="recurring_id" name="recurring_id">
|
||||
<div class="lt-modal-body">
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label" for="rec_title_template">Title Template *</label>
|
||||
<input type="text" id="rec_title_template" name="title_template" class="lt-input" required
|
||||
placeholder="Use {{date}}, {{month}}, {{year}}">
|
||||
</div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label" for="rec_description_template">Description Template</label>
|
||||
<textarea id="rec_description_template" name="description_template"
|
||||
class="lt-input lt-textarea" rows="6"></textarea>
|
||||
</div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label" for="schedule_type">Schedule Type *</label>
|
||||
<select id="schedule_type" name="schedule_type" class="lt-select" required
|
||||
data-action="update-schedule-options">
|
||||
<option value="daily">Daily</option>
|
||||
<option value="weekly">Weekly</option>
|
||||
<option value="monthly">Monthly</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="lt-form-group is-hidden" id="schedule_day_row">
|
||||
<label class="lt-label" for="schedule_day">Schedule Day</label>
|
||||
<select id="schedule_day" name="schedule_day" class="lt-select"></select>
|
||||
</div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label" for="schedule_time">Schedule Time *</label>
|
||||
<input type="time" id="schedule_time" name="schedule_time" class="lt-input"
|
||||
value="09:00" required style="max-width:12rem">
|
||||
</div>
|
||||
<div class="create-ticket-meta-grid">
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label" for="rec-category">Category</label>
|
||||
<select id="rec-category" name="category" class="lt-select">
|
||||
<?php foreach (['General','Hardware','Software','Network','Security'] as $c): ?>
|
||||
<option value="<?= $c ?>"><?= $c ?></option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label" for="rec-type">Type</label>
|
||||
<select id="rec-type" name="type" class="lt-select">
|
||||
<?php foreach (['Issue','Maintenance','Install','Task','Upgrade','Problem'] as $t): ?>
|
||||
<option value="<?= $t ?>"><?= $t ?></option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label" for="rec-priority">Priority</label>
|
||||
<select id="rec-priority" name="priority" class="lt-select">
|
||||
<option value="1">P1 — Critical</option>
|
||||
<option value="2">P2 — High</option>
|
||||
<option value="3">P3 — Medium</option>
|
||||
<option value="4" selected>P4 — Low</option>
|
||||
<option value="5">P5 — Lowest</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label" for="assigned_to">Assign To</label>
|
||||
<select id="assigned_to" name="assigned_to" class="lt-select">
|
||||
<option value="">Unassigned</option>
|
||||
<!-- Populated by JS -->
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lt-modal-footer">
|
||||
<button type="submit" class="lt-btn lt-btn-primary">SAVE</button>
|
||||
<button type="button" class="lt-btn lt-btn-ghost" data-modal-close>CANCEL</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script nonce="<?= $nonce ?>">
|
||||
document.addEventListener('click', function (e) {
|
||||
var target = e.target.closest('[data-action]');
|
||||
if (!target) return;
|
||||
switch (target.getAttribute('data-action')) {
|
||||
case 'show-create-modal': showCreateModal(); break;
|
||||
case 'edit-recurring': editRecurring(target.getAttribute('data-id')); break;
|
||||
case 'toggle-recurring': toggleRecurring(target.getAttribute('data-id')); break;
|
||||
case 'delete-recurring': deleteRecurring(target.getAttribute('data-id')); break;
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('change', function (e) {
|
||||
var target = e.target.closest('[data-action]');
|
||||
if (!target) return;
|
||||
if (target.getAttribute('data-action') === 'update-schedule-options') updateScheduleOptions();
|
||||
});
|
||||
|
||||
document.getElementById('recurringForm').addEventListener('submit', function (e) {
|
||||
saveRecurring(e);
|
||||
});
|
||||
|
||||
if (window.lt) lt.keys.initDefaults();
|
||||
|
||||
function updateScheduleOptions() {
|
||||
var type = document.getElementById('schedule_type').value;
|
||||
var dayRow = document.getElementById('schedule_day_row');
|
||||
var daySelect = document.getElementById('schedule_day');
|
||||
daySelect.innerHTML = '';
|
||||
if (type === 'daily') {
|
||||
dayRow.classList.add('is-hidden');
|
||||
} else if (type === 'weekly') {
|
||||
dayRow.classList.remove('is-hidden');
|
||||
['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'].forEach(function (day, i) {
|
||||
daySelect.innerHTML += '<option value="' + (i + 1) + '">' + day + '</option>';
|
||||
});
|
||||
} else if (type === 'monthly') {
|
||||
dayRow.classList.remove('is-hidden');
|
||||
for (var i = 1; i <= 28; i++) {
|
||||
daySelect.innerHTML += '<option value="' + i + '">Day ' + i + '</option>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('change', function(event) {
|
||||
const target = event.target.closest('[data-action]');
|
||||
if (!target) return;
|
||||
function showCreateModal() {
|
||||
document.getElementById('recModalTitle').textContent = 'Create Recurring Ticket';
|
||||
document.getElementById('recurringForm').reset();
|
||||
document.getElementById('recurring_id').value = '';
|
||||
updateScheduleOptions();
|
||||
lt.modal.open('recurringModal');
|
||||
}
|
||||
|
||||
if (target.dataset.action === 'update-schedule-options') {
|
||||
function editRecurring(id) {
|
||||
lt.api.get('/api/manage_recurring.php?id=' + id)
|
||||
.then(function (data) {
|
||||
if (data.success && data.recurring) {
|
||||
var rt = data.recurring;
|
||||
document.getElementById('recurring_id').value = rt.recurring_id;
|
||||
document.getElementById('rec_title_template').value = rt.title_template;
|
||||
document.getElementById('rec_description_template').value = rt.description_template || '';
|
||||
document.getElementById('schedule_type').value = rt.schedule_type;
|
||||
updateScheduleOptions();
|
||||
document.getElementById('schedule_day').value = rt.schedule_day || '';
|
||||
document.getElementById('schedule_time').value = rt.schedule_time ? rt.schedule_time.substring(0, 5) : '09:00';
|
||||
document.getElementById('rec-category').value = rt.category || 'General';
|
||||
document.getElementById('rec-type').value = rt.type || 'Issue';
|
||||
document.getElementById('rec-priority').value = rt.priority || 4;
|
||||
document.getElementById('assigned_to').value = rt.assigned_to || '';
|
||||
document.getElementById('recModalTitle').textContent = 'Edit Recurring Ticket';
|
||||
lt.modal.open('recurringModal');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Form submit handler
|
||||
document.getElementById('recurringForm').addEventListener('submit', function(e) {
|
||||
saveRecurring(e);
|
||||
});
|
||||
function toggleRecurring(id) {
|
||||
lt.api.post('/api/manage_recurring.php?action=toggle&id=' + id)
|
||||
.then(function (data) {
|
||||
if (data.success) window.location.reload();
|
||||
else lt.toast.error(data.error || 'Failed to toggle');
|
||||
}).catch(function () { lt.toast.error('Failed to toggle'); });
|
||||
}
|
||||
|
||||
if (window.lt) lt.keys.initDefaults();
|
||||
|
||||
function updateScheduleOptions() {
|
||||
const type = document.getElementById('schedule_type').value;
|
||||
const dayRow = document.getElementById('schedule_day_row');
|
||||
const daySelect = document.getElementById('schedule_day');
|
||||
|
||||
daySelect.innerHTML = '';
|
||||
|
||||
if (type === 'daily') {
|
||||
dayRow.classList.add('is-hidden');
|
||||
} else if (type === 'weekly') {
|
||||
dayRow.classList.remove('is-hidden');
|
||||
const days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
|
||||
days.forEach((day, i) => {
|
||||
daySelect.innerHTML += `<option value="${i + 1}">${day}</option>`;
|
||||
});
|
||||
} else if (type === 'monthly') {
|
||||
dayRow.classList.remove('is-hidden');
|
||||
for (let i = 1; i <= 28; i++) {
|
||||
daySelect.innerHTML += `<option value="${i}">Day ${i}</option>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function saveRecurring(e) {
|
||||
e.preventDefault();
|
||||
const form = new FormData(document.getElementById('recurringForm'));
|
||||
const data = Object.fromEntries(form);
|
||||
|
||||
const url = '/api/manage_recurring.php' + (data.recurring_id ? '?id=' + data.recurring_id : '');
|
||||
const apiCall = data.recurring_id ? lt.api.put(url, data) : lt.api.post(url, data);
|
||||
apiCall.then(result => {
|
||||
if (result.success) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
lt.toast.error(result.error || 'Failed to save');
|
||||
}
|
||||
}).catch(err => lt.toast.error('Failed to save'));
|
||||
}
|
||||
|
||||
function toggleRecurring(id) {
|
||||
lt.api.post('/api/manage_recurring.php?action=toggle&id=' + id)
|
||||
.then(data => {
|
||||
function deleteRecurring(id) {
|
||||
showConfirmModal('Delete Schedule', 'Delete this recurring ticket schedule? This cannot be undone.', 'error', function () {
|
||||
lt.api.delete('/api/manage_recurring.php?id=' + id)
|
||||
.then(function (data) {
|
||||
if (data.success) window.location.reload();
|
||||
else lt.toast.error(data.error || 'Failed to toggle');
|
||||
}).catch(err => lt.toast.error('Failed to toggle'));
|
||||
}
|
||||
else lt.toast.error(data.error || 'Failed to delete');
|
||||
}).catch(function () { lt.toast.error('Failed to delete'); });
|
||||
});
|
||||
}
|
||||
|
||||
function deleteRecurring(id) {
|
||||
showConfirmModal('Delete Schedule', 'Delete this recurring ticket schedule?', 'error', function() {
|
||||
lt.api.delete('/api/manage_recurring.php?id=' + id)
|
||||
.then(data => {
|
||||
if (data.success) window.location.reload();
|
||||
else lt.toast.error(data.error || 'Failed to delete');
|
||||
}).catch(err => lt.toast.error('Failed to delete'));
|
||||
});
|
||||
}
|
||||
function saveRecurring(e) {
|
||||
e.preventDefault();
|
||||
var form = new FormData(document.getElementById('recurringForm'));
|
||||
var data = {};
|
||||
form.forEach(function (v, k) { data[k] = v; });
|
||||
var url = '/api/manage_recurring.php' + (data.recurring_id ? '?id=' + data.recurring_id : '');
|
||||
var apiCall = data.recurring_id ? lt.api.put(url, data) : lt.api.post(url, data);
|
||||
apiCall.then(function (result) {
|
||||
if (result.success) window.location.reload();
|
||||
else lt.toast.error(result.error || 'Failed to save');
|
||||
}).catch(function () { lt.toast.error('Failed to save'); });
|
||||
}
|
||||
|
||||
function editRecurring(id) {
|
||||
lt.api.get('/api/manage_recurring.php?id=' + id)
|
||||
.then(data => {
|
||||
if (data.success && data.recurring) {
|
||||
const rt = data.recurring;
|
||||
document.getElementById('recurring_id').value = rt.recurring_id;
|
||||
document.getElementById('title_template').value = rt.title_template;
|
||||
document.getElementById('description_template').value = rt.description_template || '';
|
||||
document.getElementById('schedule_type').value = rt.schedule_type;
|
||||
updateScheduleOptions();
|
||||
document.getElementById('schedule_day').value = rt.schedule_day || '';
|
||||
document.getElementById('schedule_time').value = rt.schedule_time ? rt.schedule_time.substring(0, 5) : '09:00';
|
||||
document.getElementById('category').value = rt.category || 'General';
|
||||
document.getElementById('type').value = rt.type || 'Issue';
|
||||
document.getElementById('priority').value = rt.priority || 4;
|
||||
document.getElementById('assigned_to').value = rt.assigned_to || '';
|
||||
document.getElementById('modalTitle').textContent = 'Edit Recurring Ticket';
|
||||
lt.modal.open('recurringModal');
|
||||
}
|
||||
function loadUsers() {
|
||||
lt.api.get('/api/get_users.php')
|
||||
.then(function (data) {
|
||||
if (data.success && data.users) {
|
||||
var select = document.getElementById('assigned_to');
|
||||
data.users.forEach(function (user) {
|
||||
var opt = document.createElement('option');
|
||||
opt.value = user.user_id;
|
||||
opt.textContent = user.display_name || user.username;
|
||||
select.appendChild(opt);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Load users for assignee dropdown
|
||||
function loadUsers() {
|
||||
lt.api.get('/api/get_users.php')
|
||||
.then(data => {
|
||||
if (data.success && data.users) {
|
||||
const select = document.getElementById('assigned_to');
|
||||
data.users.forEach(user => {
|
||||
const option = document.createElement('option');
|
||||
option.value = user.user_id;
|
||||
option.textContent = user.display_name || user.username;
|
||||
select.appendChild(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
updateScheduleOptions();
|
||||
loadUsers();
|
||||
</script>
|
||||
|
||||
// Initialize
|
||||
updateScheduleOptions();
|
||||
loadUsers();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<?php include __DIR__ . '/../../views/layout_footer.php'; ?>
|
||||
|
||||
Reference in New Issue
Block a user