2026-05-19 18:14:39 -04:00
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html>
|
2026-05-29 10:55:56 -04:00
|
|
|
|
2026-05-19 18:14:39 -04:00
|
|
|
<head>
|
|
|
|
|
<title>Time Clock</title>
|
|
|
|
|
</head>
|
|
|
|
|
|
|
|
|
|
<body>
|
|
|
|
|
|
|
|
|
|
<h1>Simple Time Clock</h1>
|
|
|
|
|
|
2026-05-20 17:09:45 -04:00
|
|
|
<h2>Currently Clocked In</h2>
|
|
|
|
|
|
|
|
|
|
{% if clocked_in_users %}
|
|
|
|
|
<ul>
|
|
|
|
|
{% for user in clocked_in_users %}
|
2026-05-29 10:55:56 -04:00
|
|
|
<li>
|
|
|
|
|
{{ user.name }} —
|
|
|
|
|
since
|
|
|
|
|
<span class="tztime" data-ts="{{ user.since }}">
|
|
|
|
|
{{ user.since }}
|
|
|
|
|
</span>
|
|
|
|
|
</li>
|
2026-05-20 17:09:45 -04:00
|
|
|
{% endfor %}
|
|
|
|
|
</ul>
|
|
|
|
|
{% else %}
|
|
|
|
|
<p>No users are currently clocked in.</p>
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
|
|
<br/>
|
2026-05-29 10:55:56 -04:00
|
|
|
|
|
|
|
|
{% if all_user_reports %}
|
|
|
|
|
|
|
|
|
|
<h2>Last 7 Days Report</h2>
|
|
|
|
|
|
|
|
|
|
<table border="1" cellpadding="5">
|
|
|
|
|
|
|
|
|
|
<tr>
|
|
|
|
|
<th>User</th>
|
|
|
|
|
<th>Total Hours Worked</th>
|
|
|
|
|
</tr>
|
|
|
|
|
|
|
|
|
|
{% for report in all_user_reports %}
|
|
|
|
|
<tr>
|
|
|
|
|
<td>{{ report.name }}</td>
|
|
|
|
|
<td>{{ report.hours }}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
{% endfor %}
|
|
|
|
|
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
<br>
|
|
|
|
|
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
2026-05-20 17:09:45 -04:00
|
|
|
<hr/>
|
|
|
|
|
<br/>
|
|
|
|
|
|
2026-05-29 10:55:56 -04:00
|
|
|
<form method="POST" id="timeclock-form">
|
|
|
|
|
|
|
|
|
|
<input
|
|
|
|
|
type="hidden"
|
|
|
|
|
name="client_timestamp"
|
|
|
|
|
id="client_timestamp"
|
|
|
|
|
>
|
2026-05-19 18:14:39 -04:00
|
|
|
|
|
|
|
|
<table border="1" cellpadding="5">
|
|
|
|
|
|
|
|
|
|
<tr>
|
|
|
|
|
<td>User</td>
|
2026-05-29 10:55:56 -04:00
|
|
|
|
2026-05-19 18:14:39 -04:00
|
|
|
<td>
|
|
|
|
|
<select name="user_id">
|
|
|
|
|
|
|
|
|
|
{% for user in users %}
|
2026-05-29 10:55:56 -04:00
|
|
|
<option
|
|
|
|
|
value="{{ user.id }}"
|
|
|
|
|
{% if selected_user_id == user.id %}
|
|
|
|
|
selected
|
|
|
|
|
{% endif %}
|
|
|
|
|
>
|
|
|
|
|
{{ user.name }}
|
2026-05-19 18:14:39 -04:00
|
|
|
</option>
|
|
|
|
|
{% endfor %}
|
|
|
|
|
|
|
|
|
|
</select>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
|
|
|
|
|
<tr>
|
|
|
|
|
<td>Clock Actions</td>
|
|
|
|
|
|
|
|
|
|
<td>
|
2026-05-29 10:55:56 -04:00
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
type="submit"
|
|
|
|
|
name="action"
|
|
|
|
|
value="clock_in"
|
|
|
|
|
onclick="setCurrentTimestamp()"
|
|
|
|
|
>
|
2026-05-19 18:14:39 -04:00
|
|
|
Clock In
|
|
|
|
|
</button>
|
|
|
|
|
|
2026-05-29 10:55:56 -04:00
|
|
|
<button
|
|
|
|
|
type="submit"
|
|
|
|
|
name="action"
|
|
|
|
|
value="clock_out"
|
|
|
|
|
onclick="setCurrentTimestamp()"
|
|
|
|
|
>
|
2026-05-19 18:14:39 -04:00
|
|
|
Clock Out
|
|
|
|
|
</button>
|
2026-05-29 10:55:56 -04:00
|
|
|
|
2026-05-19 18:14:39 -04:00
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
|
|
|
|
|
<tr>
|
|
|
|
|
<td>Begin Date</td>
|
|
|
|
|
|
|
|
|
|
<td>
|
|
|
|
|
<input
|
|
|
|
|
type="datetime-local"
|
|
|
|
|
name="begin_date"
|
2026-05-29 10:55:56 -04:00
|
|
|
id="begin_date"
|
2026-05-19 18:14:39 -04:00
|
|
|
value=""
|
|
|
|
|
>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
|
|
|
|
|
<tr>
|
|
|
|
|
<td>End Date</td>
|
|
|
|
|
|
|
|
|
|
<td>
|
|
|
|
|
<input
|
|
|
|
|
type="datetime-local"
|
|
|
|
|
name="end_date"
|
2026-05-29 10:55:56 -04:00
|
|
|
id="end_date"
|
2026-05-19 18:14:39 -04:00
|
|
|
value=""
|
|
|
|
|
>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
|
|
|
|
|
<tr>
|
|
|
|
|
<td>Report</td>
|
|
|
|
|
|
|
|
|
|
<td>
|
2026-05-29 10:55:56 -04:00
|
|
|
<button
|
|
|
|
|
type="submit"
|
|
|
|
|
name="action"
|
|
|
|
|
value="report"
|
|
|
|
|
>
|
2026-05-19 18:14:39 -04:00
|
|
|
Generate Report
|
|
|
|
|
</button>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
</form>
|
|
|
|
|
|
|
|
|
|
<br>
|
|
|
|
|
|
|
|
|
|
{% if report_hours is not none %}
|
|
|
|
|
|
2026-05-29 10:55:56 -04:00
|
|
|
<h2>Custom Report</h2>
|
|
|
|
|
|
2026-05-19 18:14:39 -04:00
|
|
|
<table border="1" cellpadding="5">
|
|
|
|
|
|
|
|
|
|
<tr>
|
|
|
|
|
<th>Total Hours Worked</th>
|
|
|
|
|
</tr>
|
|
|
|
|
|
|
|
|
|
<tr>
|
|
|
|
|
<td>{{ report_hours }}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
2026-05-29 10:55:56 -04:00
|
|
|
<script>
|
|
|
|
|
|
|
|
|
|
function localDatetimeValue(date) {
|
|
|
|
|
|
|
|
|
|
const pad = (v) => String(v).padStart(2, "0");
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
date.getFullYear() + "-" +
|
|
|
|
|
pad(date.getMonth() + 1) + "-" +
|
|
|
|
|
pad(date.getDate()) + "T" +
|
|
|
|
|
pad(date.getHours()) + ":" +
|
|
|
|
|
pad(date.getMinutes())
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setCurrentTimestamp() {
|
|
|
|
|
|
|
|
|
|
document.getElementById("client_timestamp").value =
|
|
|
|
|
new Date().toISOString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
window.addEventListener("load", () => {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Populate default report range
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
const now = new Date();
|
|
|
|
|
|
|
|
|
|
const weekAgo = new Date();
|
|
|
|
|
|
|
|
|
|
weekAgo.setDate(now.getDate() - 7);
|
|
|
|
|
|
|
|
|
|
document.getElementById("begin_date").value =
|
|
|
|
|
localDatetimeValue(weekAgo);
|
|
|
|
|
|
|
|
|
|
document.getElementById("end_date").value =
|
|
|
|
|
localDatetimeValue(now);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Convert displayed timestamps to local timezone
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
document.querySelectorAll(".tztime").forEach((el) => {
|
|
|
|
|
|
|
|
|
|
const ts = el.dataset.ts;
|
|
|
|
|
|
|
|
|
|
const d = new Date(ts);
|
|
|
|
|
|
|
|
|
|
el.textContent = d.toLocaleString();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
2026-05-19 18:14:39 -04:00
|
|
|
</body>
|
|
|
|
|
</html>
|