mirror of
https://github.com/itflow-org/itflow
synced 2026-03-06 13:54:51 +00:00
Timer - Record time even if closed
This commit is contained in:
@@ -1,146 +1,136 @@
|
|||||||
// Description: This file contains the javascript for the ticket time tracking feature
|
// Description: This file contains the JavaScript for the ticket time tracking feature
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
(function() {
|
||||||
// Initialize variables
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
var timerInterval = null;
|
// Initialize variables
|
||||||
var isPaused = false;
|
var timerInterval = null;
|
||||||
var ticketID = getCurrentTicketID();
|
var isPaused = false;
|
||||||
var elapsedSecs = getElapsedSeconds();
|
var ticketID = getCurrentTicketID();
|
||||||
|
var elapsedSecs = getElapsedSeconds();
|
||||||
// Get the ticket ID from the URL
|
|
||||||
// Inputs: None
|
|
||||||
// Outputs: The ticket ID from the URL
|
|
||||||
// Document Interactions: None
|
|
||||||
|
|
||||||
function getCurrentTicketID() {
|
function getCurrentTicketID() {
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
return urlParams.get('ticket_id');
|
return urlParams.get('ticket_id');
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Get the local storage key for the ticket
|
|
||||||
// Inputs: The suffix to append to the key
|
|
||||||
// Outputs: The local storage key for the ticket
|
|
||||||
// Document Interactions: None
|
|
||||||
|
|
||||||
function getLocalStorageKey(suffix) {
|
|
||||||
return ticketID + "-" + suffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Get the elapsed seconds from local storage
|
|
||||||
// Inputs: None
|
|
||||||
// Outputs: The elapsed seconds from local storage
|
|
||||||
// Document Interactions: None
|
|
||||||
|
|
||||||
function getElapsedSeconds() {
|
|
||||||
let storedStartTime = localStorage.getItem(getLocalStorageKey("startTime"));
|
|
||||||
let pausedTime = parseInt(localStorage.getItem(getLocalStorageKey("pausedTime")) || "0");
|
|
||||||
// If there is no start time, return the paused time
|
|
||||||
if (!storedStartTime) return pausedTime;
|
|
||||||
// Otherwise, return the paused time plus the time since the start time
|
|
||||||
let timeSinceStart = Math.floor((Date.now() - parseInt(storedStartTime)) / 1000);
|
|
||||||
return pausedTime + timeSinceStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display the elapsed time
|
|
||||||
// Inputs: None
|
|
||||||
// Outputs: None
|
|
||||||
// Document Interactions: Updates the time worked input
|
|
||||||
|
|
||||||
function displayTime() {
|
|
||||||
let totalSeconds = elapsedSecs;
|
|
||||||
let hours = Math.floor(totalSeconds / 3600);
|
|
||||||
totalSeconds %= 3600;
|
|
||||||
let minutes = Math.floor(totalSeconds / 60);
|
|
||||||
let seconds = totalSeconds % 60;
|
|
||||||
// Update the time worked input
|
|
||||||
document.getElementById("time_worked").value = `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pad a number with a leading zero if it is less than 10
|
|
||||||
// Inputs: The number to pad
|
|
||||||
// Outputs: The padded number
|
|
||||||
// Document Interactions: None
|
|
||||||
|
|
||||||
function pad(val) {
|
|
||||||
return val < 10 ? "0" + val : val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count the time
|
|
||||||
// Inputs: None
|
|
||||||
// Outputs: None
|
|
||||||
// Document Interactions: Updates the elapsed time
|
|
||||||
|
|
||||||
function countTime() {
|
|
||||||
elapsedSecs++;
|
|
||||||
displayTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Start the timer
|
|
||||||
// Inputs: None
|
|
||||||
// Outputs: None
|
|
||||||
// Document Interactions: None
|
|
||||||
|
|
||||||
function startTimer() {
|
|
||||||
if (!localStorage.getItem(getLocalStorageKey("startTime"))) {
|
|
||||||
localStorage.setItem(getLocalStorageKey("startTime"), Date.now().toString());
|
|
||||||
}
|
}
|
||||||
if (!isPaused && timerInterval === null) {
|
|
||||||
|
function getLocalStorageKey(suffix) {
|
||||||
|
return ticketID + "-" + suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getElapsedSeconds() {
|
||||||
|
let storedStartTime = parseInt(localStorage.getItem(getLocalStorageKey("startTime")) || "0");
|
||||||
|
let pausedTime = parseInt(localStorage.getItem(getLocalStorageKey("pausedTime")) || "0");
|
||||||
|
if (!storedStartTime) return pausedTime;
|
||||||
|
let timeSinceStart = Math.floor((Date.now() - storedStartTime) / 1000);
|
||||||
|
return pausedTime + timeSinceStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayTime() {
|
||||||
|
let totalSeconds = elapsedSecs;
|
||||||
|
let hours = Math.floor(totalSeconds / 3600);
|
||||||
|
totalSeconds %= 3600;
|
||||||
|
let minutes = Math.floor(totalSeconds / 60);
|
||||||
|
let seconds = totalSeconds % 60;
|
||||||
|
|
||||||
|
document.getElementById("hours").value = pad(hours);
|
||||||
|
document.getElementById("minutes").value = pad(minutes);
|
||||||
|
document.getElementById("seconds").value = pad(seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pad(val) {
|
||||||
|
return val < 10 ? "0" + val : val;
|
||||||
|
}
|
||||||
|
|
||||||
|
function countTime() {
|
||||||
|
elapsedSecs++;
|
||||||
|
displayTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
function startTimer() {
|
||||||
|
if (!localStorage.getItem(getLocalStorageKey("startTime"))) {
|
||||||
|
localStorage.setItem(getLocalStorageKey("startTime"), Date.now().toString());
|
||||||
|
}
|
||||||
timerInterval = setInterval(countTime, 1000);
|
timerInterval = setInterval(countTime, 1000);
|
||||||
|
isPaused = false;
|
||||||
|
document.getElementById("startStopTimer").innerText = "Pause";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Pause the timer
|
function pauseTimer() {
|
||||||
// Inputs: None
|
if (timerInterval) {
|
||||||
// Outputs: None
|
clearInterval(timerInterval);
|
||||||
// Document Interactions: None
|
timerInterval = null;
|
||||||
|
}
|
||||||
|
let currentElapsed = getElapsedSeconds();
|
||||||
|
localStorage.setItem(getLocalStorageKey("pausedTime"), currentElapsed.toString());
|
||||||
|
localStorage.removeItem(getLocalStorageKey("startTime"));
|
||||||
|
isPaused = true;
|
||||||
|
document.getElementById("startStopTimer").innerText = "Start";
|
||||||
|
}
|
||||||
|
|
||||||
function pauseTimer() {
|
function clearTimeStorage() {
|
||||||
if (timerInterval) {
|
localStorage.removeItem(getLocalStorageKey("startTime"));
|
||||||
|
localStorage.removeItem(getLocalStorageKey("pausedTime"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetTimer() {
|
||||||
|
if (confirm("Are you sure you want to reset the timer?")) {
|
||||||
|
clearInterval(timerInterval);
|
||||||
|
timerInterval = null;
|
||||||
|
elapsedSecs = 0;
|
||||||
|
clearTimeStorage();
|
||||||
|
displayTime();
|
||||||
|
document.getElementById("startStopTimer").innerText = "Start";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function forceResetTimer() {
|
||||||
clearInterval(timerInterval);
|
clearInterval(timerInterval);
|
||||||
timerInterval = null;
|
timerInterval = null;
|
||||||
|
elapsedSecs = 0;
|
||||||
|
clearTimeStorage();
|
||||||
|
displayTime();
|
||||||
|
document.getElementById("startStopTimer").innerText = "Start";
|
||||||
}
|
}
|
||||||
let currentElapsed = getElapsedSeconds();
|
|
||||||
localStorage.setItem(getLocalStorageKey("pausedTime"), currentElapsed.toString());
|
|
||||||
localStorage.removeItem(getLocalStorageKey("startTime"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the time storage
|
function handleInputFocus() {
|
||||||
// Inputs: None
|
if (!isPaused) {
|
||||||
// Outputs: None
|
pauseTimer();
|
||||||
// Document Interactions: None
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function clearTimeStorage() {
|
document.getElementById("hours").addEventListener('focus', handleInputFocus);
|
||||||
localStorage.removeItem(getLocalStorageKey("startTime"));
|
document.getElementById("minutes").addEventListener('focus', handleInputFocus);
|
||||||
localStorage.removeItem(getLocalStorageKey("pausedTime"));
|
document.getElementById("seconds").addEventListener('focus', handleInputFocus);
|
||||||
}
|
|
||||||
|
|
||||||
// Add event listeners
|
document.getElementById("startStopTimer").addEventListener('click', function() {
|
||||||
|
if (timerInterval === null) {
|
||||||
|
startTimer();
|
||||||
|
} else {
|
||||||
|
pauseTimer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// When toggleTimer is clicked, toggle the timer
|
document.getElementById("resetTimer").addEventListener('click', function() {
|
||||||
document.getElementById("toggleTimer").addEventListener('click', function() {
|
resetTimer();
|
||||||
if (isPaused) {
|
});
|
||||||
// If the timer is paused, start it
|
|
||||||
startTimer();
|
document.getElementById("ticket_add_reply").addEventListener('click', function() {
|
||||||
isPaused = false;
|
// Wait for other synchronous actions (if any) to complete before resetting the timer.
|
||||||
} else {
|
setTimeout(forceResetTimer, 100); // 100ms delay should suffice, but you can adjust as needed.
|
||||||
// If the timer is running, pause it
|
});
|
||||||
pauseTimer();
|
|
||||||
isPaused = true;
|
try {
|
||||||
|
displayTime();
|
||||||
|
if (!localStorage.getItem(getLocalStorageKey("startTime")) && !localStorage.getItem(getLocalStorageKey("pausedTime"))) {
|
||||||
|
// If first time, start the timer automatically
|
||||||
|
startTimer();
|
||||||
|
} else if (localStorage.getItem(getLocalStorageKey("startTime"))) {
|
||||||
|
// Continue timer if it was running before
|
||||||
|
startTimer();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an issue initializing the timer:", error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
})();
|
||||||
// When the ticket is submitted, clear the time storage
|
|
||||||
document.getElementById("ticket_add_reply").addEventListener('click', function() {
|
|
||||||
pauseTimer();
|
|
||||||
clearTimeStorage();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize on page load
|
|
||||||
// If the timer is paused, start it
|
|
||||||
displayTime();
|
|
||||||
startTimer();
|
|
||||||
|
|
||||||
});
|
|
||||||
@@ -459,8 +459,17 @@ if (isset($_POST['add_ticket_reply'])) {
|
|||||||
$ticket_reply = $_POST['ticket_reply'];
|
$ticket_reply = $_POST['ticket_reply'];
|
||||||
$ticket_status_escaped = sanitizeInput($_POST['status']);
|
$ticket_status_escaped = sanitizeInput($_POST['status']);
|
||||||
$ticket_status = $_POST['status'];
|
$ticket_status = $_POST['status'];
|
||||||
$ticket_reply_time_worked_escaped = sanitizeInput($_POST['time']);
|
// Handle the time inputs for hours, minutes, and seconds
|
||||||
$ticket_reply_time_worked = $_POST['time'];
|
$hours = intval($_POST['hours']);
|
||||||
|
$minutes = intval($_POST['minutes']);
|
||||||
|
$seconds = intval($_POST['seconds']);
|
||||||
|
|
||||||
|
//var_dump($_POST);
|
||||||
|
//exit;
|
||||||
|
|
||||||
|
// Combine into a single time string
|
||||||
|
$ticket_reply_time_worked = sprintf("%02d:%02d:%02d", $hours, $minutes, $seconds);
|
||||||
|
$ticket_reply_time_worked_escaped = sanitizeInput($ticket_reply_time_worked);
|
||||||
|
|
||||||
$client_id = intval($_POST['client_id']);
|
$client_id = intval($_POST['client_id']);
|
||||||
|
|
||||||
|
|||||||
44
ticket.php
44
ticket.php
@@ -315,20 +315,44 @@ if (isset($_GET['ticket_id'])) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-4">
|
<!-- Time Tracking: Hours -->
|
||||||
<div class="form-group">
|
<div class="col-md-2">
|
||||||
<div class="input-group">
|
<div class="input-group mb-3">
|
||||||
<div class="input-group-prepend">
|
<input type="number" class="form-control" id="hours" name="hours" placeholder="Hours" min="0" max="23">
|
||||||
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
|
<div class="input-group-append">
|
||||||
</div>
|
<span class="input-group-text">Hrs</span>
|
||||||
<input class="form-control timepicker" id="time_worked" name="time" type="text" value="00:00:00" onchange="setTime()"/>
|
|
||||||
<div class="input-group-append">
|
|
||||||
<button type="button" class="btn btn-dark" id="toggleTimer"><i class="fas fa-pause"></i></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Time Tracking: Minutes -->
|
||||||
|
<div class="col-md-2">
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input type="number" class="form-control" id="minutes" name="minutes" placeholder="Minutes" min="0" max="59">
|
||||||
|
<div class="input-group-append">
|
||||||
|
<span class="input-group-text">Mins</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Time Tracking: Seconds -->
|
||||||
|
<div class="col-md-2">
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input type="number" class="form-control" id="seconds" name="seconds" placeholder="Seconds" min="0" max="59">
|
||||||
|
<div class="input-group-append">
|
||||||
|
<span class="input-group-text">Secs</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Timer Controls -->
|
||||||
|
<div class="col-md-2">
|
||||||
|
<div class="btn-group mt-2" role="group">
|
||||||
|
<button type="button" class="btn btn-success" id="startStopTimer">Pause</button>
|
||||||
|
<button type="button" class="btn btn-danger" id="resetTimer">Reset</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<?php if(!empty($contact_email && $contact_email !== $session_email)){ ?>
|
<?php if(!empty($contact_email && $contact_email !== $session_email)){ ?>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user