
run the following SQL commands
CREATE TABLE IF NOT EXISTS `ost_ticket_time_log` (
`ticket_id` INT NOT NULL,
`staff_id` INT NOT NULL,
`log_date` DATE NOT NULL,
`seconds_spent` INT DEFAULT 0,
PRIMARY KEY (`ticket_id`, `staff_id`, `log_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
in the root of SCP folder create a php file named ajax.time_tracker.php
Copy the following code into that file
<?php
require('staff.inc.php');
if (!$thisstaff || !isset($_POST['ticket_id'])) {
header('HTTP/1.1 403 Forbidden');
echo "Access Denied";
exit;
}
$ticket_id = (int)$_POST['ticket_id'];
$staff_id = $thisstaff->getId();
$increment = 30; // Seconds
// Include CURDATE() to log time specific to the day it occurred
$sql = "INSERT INTO ost_ticket_time_log (ticket_id, staff_id, log_date, seconds_spent)
VALUES ($ticket_id, $staff_id, CURDATE(), $increment)
ON DUPLICATE KEY UPDATE seconds_spent = seconds_spent + $increment";
if (db_query($sql)) {
echo "Time successfully logged for Staff ID: " . $staff_id;
} else {
header('HTTP/1.1 500 Internal Server Error');
echo "Database Error";
}
?>
Now open include / staff /ticket-view.inc.php
find the following code in that file
<td><?php echo Format::datetime($ticket->getLastRespDate())
add the following code directly under the above code
<?php
// start of time spent script
?>
<?php
// Query the time log, joining with staff, sorted by date (newest first)
$time_sql = "
SELECT s.firstname, s.lastname, l.log_date, l.seconds_spent
FROM ost_ticket_time_log l
JOIN ost_staff s ON (l.staff_id = s.staff_id)
WHERE l.ticket_id = " . db_input($ticket->getId()) . "
ORDER BY l.log_date DESC, l.seconds_spent DESC";
$time_res = db_query($time_sql);
$total_seconds = 0;
$breakdown_array = [];
// Organize the data by date
while ($row = db_fetch_array($time_res)) {
$total_seconds += $row['seconds_spent'];
$minutes = round($row['seconds_spent'] / 60, 1);
// Format the date (e.g., Jul 21, 2026)
$date_formatted = date('M j, Y', strtotime($row['log_date']));
$breakdown_array[$date_formatted][] = "{$row['firstname']} {$row['lastname']}: <strong>{$minutes}</strong> min";
}
$total_minutes = round($total_seconds / 60, 1);
?>
<div class="flush-right" style="margin-right:10px; padding:8px 12px; background:#fdfdfd; border: 1px solid #ddd; border-radius:4px; min-width: 170px; box-shadow: 0 1px 3px rgba(0,0,0,0.05);">
<!-- Clickable Header -->
<div id="toggle-time-details" style="border-bottom: 1px solid #ccc; margin-bottom: 5px; padding-bottom: 5px; font-size: 1.05em; cursor: pointer; user-select: none;">
<strong>Grand Total:</strong> <?php echo $total_minutes; ?> min
<span style="font-size: 0.8em; color: #777; float: right; margin-top: 3px;">▼</span>
</div>
<!-- Hidden Details Wrapper -->
<div id="time-details-list" style="display: none;">
<?php
if (empty($breakdown_array)) {
echo "<div style='font-size: 0.9em; color: #999; font-style: italic;'>No time logged</div>";
} else {
// Loop through dates and print the staff members under each date
foreach ($breakdown_array as $date => $staff_logs) {
echo "<div style='margin-top: 8px; font-weight: bold; font-size: 0.9em; color: #2a6496; border-bottom: 1px dotted #eee;'>{$date}</div>";
foreach ($staff_logs as $log) {
echo "<div style='font-size: 0.9em; color: #555; padding-top: 3px; padding-left: 5px;'>• {$log}</div>";
}
}
}
?>
</div>
</div>
<!-- jQuery to handle the toggle animation -->
<script type="text/javascript">
$(document).ready(function() {
$('#toggle-time-details').on('click', function() {
$('#time-details-list').slideToggle(200); // 200ms slide animation
});
});
</script>
<?php
// end of time spent script
?>
in the same file add the following code to very bottom
<?php
// start of timer script
?>
<script type="text/javascript">
$(document).ready(function() {
var ticketId = <?php echo $ticket->getId(); ?>;
var csrfToken = $('meta[name=csrf_token]').attr('content');
var idleSeconds = 0;
var maxIdleSeconds = 300; // 5 minutes (300 seconds) of grace period
// 1. Reset the idle timer whenever the staff member interacts with the page
function resetIdleTime() {
idleSeconds = 0;
}
// Listen for mouse movement, clicking, scrolling, or typing
$(window).on('mousemove keydown scroll click', resetIdleTime);
// 2. The Heartbeat Timer
setInterval(function() {
idleSeconds += 30; // Add 30 seconds to the idle counter
// Log time as long as the 5-minute idle limit hasn't been breached
if (idleSeconds <= maxIdleSeconds) {
$.ajax({
url: '<?php echo ROOT_PATH; ?>scp/ajax.time_tracker.php',
type: 'POST',
data: {
ticket_id: ticketId,
__CSRFToken__: csrfToken
},
success: function(data) {
console.log('Time Tracker: +30s. (Idle for: ' + idleSeconds + 's)');
},
error: function(xhr, status, error) {
console.error('Time Tracker Failed: ' + error);
}
});
} else {
console.log('Idle limit reached. Timer paused until activity resumes.');
}
}, 30000); // 30 seconds
});
</script>