About & Purpose
Purpose: As said by the title this is just a simple web application for use of a SINGLE user. It has the features of calculating total hours, clocking in, and clocking out. It also has some functions that helps with the calculations. This is for OFFLINE USE ONLY.
This is by no means for commercial use.
List of Functions and their Purpose
Main Functions
initialize()
- Sole purpose is to make sure that the user is in the proper state. If they already started their shift, then it will lock the CLOCK IN
button and enable the CLOCK OUT
button and vice-versa. (TL;DR Check session state.)
populateTimeCard()
- Populates the template with datas in the timeCardDatas
(localStorage). This is done using Template-Engine
.
login()
- returns true
if the user types in the correct password. This is done by passing the input through the md5(input)
function. Afterwards compares it to the MD5 Hash that is hardcoded.
reset()
- Simply removes the startShift. This is triggered by pressing the Clock Out button.
calculateHours(single)
- Takes param single
. This is for calculating single values instead of an entire array. Ex: (mill1 - mill2) => 50hr. General purpose is to add up all the time and return that.
markTime()
- Gets the current time and marks it as start or end of shift depending on user session state.
Utility Functions:
militaryToStandard(time)
- Converts military time to standard time.
dowToWord(dow)
- Turns time.getDay()
to word. time.getDay()
returns day of the week as int.
padZero(number)
- As the function names says gives padding zeroes for number less than 9 (1 digit numbers).
constructTime(withDOW)
- Constructs date in a clear format. (MM / DD / YYYY [DAY_OF_THE_WEEK]). Takes a param that either adds in Day of the Week or not.
Codes
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Time Card</title>
<link rel="stylesheet" type="text/css" href="css/main.css"/>
<link rel="stylesheet" type="text/css" href="css/bootstrap.css"/>
<style>
html, body {
margin : 0;
height: 100%;
}
.container-fluid {
height: 100%;
}
.row {
height: 100%;
}
.box-header {
background-color: #6C7E8F;
text-align: center;
padding: 8px;
color: #FFF;
}
</style>
</head>
<body style="background-color: #2c3e50;">
<div class="container-fluid">
<div class="row">
<div class="col-sm-8" style="padding: 0; border-right: 1px solid black; height: 100%;">
<div class="card" style="margin: 16px; height: 95%; ">
<h3 class="card-header">Interface</h3>
<div class="card-block">
<h4 class="card-title">Instructions</h4>
<p class="card-text">Press the <b>Clock In</b> button when starting shift. This will get the current time and add it in your <i>Time Card</i>.</p>
<p class="card-text">Press the <b>Clock Out</b> button when ending shift. This will get the current time and add it in your <i>Time Card</i>.</p>
<!-- <hr>
<h4>Datas</h4>
<p>This is just showing all the datas available. Will be removed after final build. [For development purposes only.]</p>
<br>
<b style="color: blue">Date </b> <span id="clockInDate">N/A</span><br>
<b style="color: green">Clock In </b> <span id="clockInData">N/A</span><br>
<b style="color: red">Clock Out </b> <span id="clockOutData">N/A</span> -->
<hr>
<h4>Password</h4>
<p>Please enter your password before pressing either <b>Clock In</b> or <b>Clock Out</b>.
<div class="form-group" id="password-group">
<input class="form-control" type="password" id="password" required/>
</div>
</div>
<div class="card-footer text-muted">
<button id="clockIn" class="btn btn-primary btn-block">Clock In</button>
<button id="clockOut" class="btn btn-danger btn-block">Clock Out</button>
</div>
</div>
</div>
<div class="col-sm-4" style="background-color: #34495e; padding: 0;">
<!-- <div class="header-container">
<h4 class="box-header">Time Card</h4>
</div>
<div class="datas-container">
<span id="time"></span>
</div> -->
<div class="card" style="margin: 16px; height: 95%; ">
<h3 class="card-header">Time Card</h3>
<div class="card-block" style="padding: 0">
<div id="accordion" role="tablist" aria-multiselectable="true">
</div>
</div>
<div class="card-footer">
<b>Total Hours: </b> <span id="totalHours"></span>
</div>
</div>
<!-- <div class="card-footer text-muted">
<button id="clockIn" class="btn btn-primary btn-block">Clock In</button>
<button id="clockOut" class="btn btn-danger btn-block">Clock Out</button>
</div> -->
</div>
</div>
</div>
<script src="js/jquery.min.js"></script>
<script src="js/tether.js"></script>
<script src="js/bootstrap.js"></script>
<script src="js/en.js"></script>
<script src="js/tmpl.min.js"></script>
<script src="js/timecard.js"></script>
<!-- TEMPLATE -->
<script type="text/x-tmpl" id="tmpl-demo">
<div class="card">
<div class="card-header" role="tab" id="heading{%= o.id %}">
<h5 class="{%= o.id %}">
<a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#collapse{%= o.id %}" aria-expanded="true" aria-controls="collapse{%= o.id %}">
{%= o.title %}
</a>
</h5>
</div>
<div id="collapse{%= o.id %}" class="collapse" role="tabpanel" aria-labelledby="heading{%= o.id %}">
<div class="card-block">
<b>Date: </b> {%= o.title %}<br>
<b style="color: green">Clock In: </b> {%= o.clockIn %}<br>
<b style="color: red">Clock Out: </b> {%= o.clockOut %}<br>
<hr>
<b style="color: blue">Total: </b> {%= o.total %}<br>
</div>
</div>
</div>
</script>
<script type="text/javascript">
$(document).ready(function(){
if (localStorage.getItem("timeCardDatas") != null) {
populateTimeCard();
calculateHours();
}
$("#totalHours").text(localStorage.getItem("totalHours"));
});
$("#clockIn").on("click", function(){
if ($("#password").val().length > 0) {
if (login($("#password").val())) {
markTime("start");
$("#password").val("");
toggleClockIn();
} else {
triggerFormControl();
}
} else {
triggerFormControl();
}
});
$("#clockOut").on("click", function(){
if ($("#password").val().length > 0) {
if (login($("#password").val())) {
markTime("end");
$("#password").val("");
toggleClockOut();
/*-- Populate Base --*/
populateTimeCard();
} else {
triggerFormControl();
console.log("[DEBUG] Triggered Form Control");
}
} else {
triggerFormControl();
console.log("[DEBUG] Triggered Form Control");
}
});
</script>
</body>
</html>
timecard.js
/*
* Time Card web application.
* ------------------------------
* This program is not secure as it's only JS at work.
*/
initialize();
function initialize() {
if (localStorage.getItem("startShift") != null) {
toggleClockIn();
} else {
toggleClockOut();
}
}
function populateTimeCard() {
var tcDatas = JSON.parse(localStorage.getItem("timeCardDatas"));
for (var i = tcDatas.length - 1; i >= 0; i--) {
if (i >= 2) {
var datas = {
"id": i,
"title": tcDatas[i][0][2],
"clockIn": tcDatas[i][0][0],
"clockOut": tcDatas[i][1][0],
"total": calculateHours(tcDatas[i][0][1] - tcDatas[i][1][1])
};
$("#accordion").append(tmpl("tmpl-demo", datas));
}
}
}
function login(password) {
if (md5(password) == "<MD5 Hash Here>") {
return true;
} else {
return false;
}
}
function reset() {
localStorage.removeItem("startShift");
}
function calculateHours(single) {
var timeCardDatas = JSON.parse(localStorage.getItem("timeCardDatas")),
totalHour = 0;
single = (typeof single !== 'undefined') ? single : false;
if (!single) {
for (var i = timeCardDatas.length - 1; i >= 0; i--) {
if (i >= 2) {
var curHour = ((timeCardDatas[i][0][1] - timeCardDatas[i][1][1]) / 1000 / 60 / 60).toFixed(2);
if (curHour < 0) {
totalHour += parseFloat((curHour * -1).toFixed(2));
} else {
totalHour += parseFloat(curHour).toFixed(2);
}
}
}
localStorage.setItem("totalHours", totalHour.toFixed(2));
} else {
var tHour = ((parseFloat(single)) / 1000 / 60 / 60).toFixed(2);
if (tHour < 0) {
tHour = parseFloat((tHour * -1)).toFixed(2);
} else {
tHour = parseFloat(tHour).toFixed(2);
}
return tHour;
}
}
function markTime(shift) {
var curTime = new Date();
var h = curTime.getHours();
var m = curTime.getMinutes();
var s = curTime.getSeconds();
m = padZero(m);
s = padZero(s);
var shiftData = [militaryToStandard(h + ":" + m + ":" + s), curTime.getTime(), constructTime(true)];
if (shift == "start") {
localStorage.setItem("startShift", JSON.stringify(shiftData));
} else if (shift == "end") {
var tcDatas = [JSON.parse(localStorage.getItem("startShift")), shiftData];
if (localStorage.getItem("timeCardDatas") == null) {
var fillerDatas = [["FILLER", 0000000000], ["FILLER", 0000000000]];
localStorage.setItem("timeCardDatas", JSON.stringify(fillerDatas));
var oldItems = JSON.parse(localStorage.getItem("timeCardDatas"));
oldItems.push(tcDatas);
localStorage.setItem("timeCardDatas", JSON.stringify(oldItems));
reset();
} else {
var oldItems = JSON.parse(localStorage.getItem("timeCardDatas"));
oldItems.push(tcDatas);
localStorage.setItem("timeCardDatas", JSON.stringify(oldItems));
reset();
}
} else {
console.log("[Time Card] An error has occured.");
}
}
/*
* Error Controls
*/
function triggerFormControl() {
$("#password").addClass("form-control-danger");
$("#password-group").addClass("has-danger");
}
function toggleClockIn() {
$("#clockIn").addClass("disabled");
$("#clockOut").removeClass("disabled");
$('#clockIn').prop('disabled', true);
$('#clockOut').prop('disabled', false);
}
function toggleClockOut() {
$("#clockOut").addClass("disabled");
$("#clockIn").removeClass("disabled");
$('#clockIn').prop('disabled', false);
$('#clockOut').prop('disabled', true);
}
/*
* Utility
*/
function militaryToStandard(time) {
time = time.split(':');
var hours = Number(time[0]);
var minutes = Number(time[1]);
var seconds = Number(time[2]);
var timeValue;
if (hours > 0 && hours <= 12) {
timeValue= "" + hours;
} else if (hours > 12) {
timeValue= "" + (hours - 12);
} else if (hours == 0) {
timeValue= "12";
}
timeValue += (minutes < 10) ? ":0" + minutes : ":" + minutes;
timeValue += (seconds < 10) ? ":0" + seconds : ":" + seconds;
timeValue += (hours >= 12) ? " P.M." : " A.M.";
return timeValue;
}
function dowToWord(dow) {
switch (dow) {
case 0:
return "Sunday";
break
case 1:
return "Monday";
break;
case 2:
return "Tuesday";
break;
case 3:
return "Wednesday";
break;
case 4:
return "Thursday";
break;
case 5:
return "Friday";
break;
case 6:
return "Saturday";
break;
}
}
function padZero(number) {
if (number <= 9) {
number = "0" + number;
}
return number;
}
function constructTime(withDOW) {
var curTime = new Date();
var construct = padZero((curTime.getMonth() + 1)) + "/" +
curTime.getDate() + "/" +
curTime.getFullYear();
var a = (typeof withDOW !== 'undefined') ? true : false;
if (a) {
construct += " " + dowToWord(curTime.getDay());
}
return construct;
}
JS Libraries
Libraries that I installed.
Answer(s) I'm Looking For
- Code Improvements
- General Tips
- References to Guides (Naming Convention, etc.)
- AND any other meaningful and useful stuff.
If I am missing any other information do let me know what other information you need down in the comments. I will be sure to answer than as fast as I can.