Build a Employee Timesheet Web App

Web Development

About this project

In this web development project you will learn how to create a timesheet calculator web application using HTML CSS and JavaScript.

The web application will calculate the amount of worked hours, the amount of break time and then by substracting from the work time the break time the application will calculate the amount of hours worked in one day.

You can add multiple day to this application, or even multiple weeks, or moths. At the end the application will calculate the total amount of hours worked in the specified time span.

Resource:

1. Create the Project HTML CSS and JS files.

Create a empty folder for the project on your machine and drag and drop it in to your code editor of chose.
I am using Visual Studio Code as a code editor (check out the complete free course).

Now create your index.html file with a html5 boilerplate and add the link for css, then a title of the project and in the body tags the script.js file for the source.

[img]

2. Create a time sheet table in html.

The timesheet table will be created in a general div with a class of container.

The table will not be a html table tag because of conflicts that can result in the code. You will crate it using sections.

The table will consist of section, each of them heaving different class for “tableHead”, “tableBody”,’tableFooter’.

In the top part of the table you can add a header that contains information of the person, like avatar and name

    <div class="container">
      <header class="person">
        <div class="person-avatar"></div>
        <h1 class="person-name">Jane Doe</h1>
      </header>
      <section class="tableHead">
        <input type="text" class="orange" value="Days" disabled />
        <input type="text" class="blue" value="Start Work" disabled />
        <input type="text" class="green" value="Start Break" disabled />
        <input type="text" class="green" value="End Break" disabled />
        <input type="text" class="blue" value="End Work" disabled />
        <input type="text" class="purple" value="Hours / Days" disabled />
      </section>
      <section class="tableBody">
        <!-- <div class="tr">
          <form>
            <th>
              <input type="text" class="orange" placeholder="Enter day" />
            </th>
            <td>
              <input type="time" class="green" id="start-work" />
            </td>
            <td>
              <input type="time" class="blue" id="start-break" />
            </td>
            <td>
              <input type="time" class="blue" id="end-break" />
            </td>
            <td>
              <input type="time" class="green" id="end-work" />
            </td>
            <td>
              <input class="workedHourse purple" value="00:00" disabled />
            </td>
            <td><button class="btn" type="submit">add</button></td>
          </form>
        </div> -->
        <div class="tr"></div>
        <div class="tr"></div>
        <div class="tr"></div>
        <div class="tr"></div>
        <div class="tr"></div>
      </section>
      <section class="tableFooter">
        <input class="red" value="Total" disabled />

        <input id="totalWorkedHours" class="red" value="Work Hours" disabled />
      </section>
    </div>

3. Style the time sheet table.

In the CSS file we can now start styling out table.

You will need to add a custom font from Google Fonts and use it by importing it.
I chose to use custom css variables for this project as I almost alys to, this not only makes my life easear but also yours if you wish to change color later on.

Now you can create some custom classes for color, adding to them a background color and text color.

3.1 CSS Custom Fonts, general reset and css variables and style the body and project container.

I am using the “Roboto” font for the font family of the complete project.

@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@100;400;500;700;900&display=swap");

* {
  font-family: "Roboto", sans-serif;
  margin: 0;
  padding: 0;
}

:root {
  --dark-green: #0ca614;
  --light-green: #effbf0;
  --dark-purple: #6a52ff;
  --light-purple: #f3f1ff;
  --dark-orange: #d2781a;
  --light-orange: #fdf5eb;
  --dark-blue: #2998ff;
  --light-blue: #f0f7ff;
  --dark-red: #cf2e2e;
  --light-red: #f5efef;
  --dark-gray: #676b6e;
  --light-gray: #f6f6f6;
}
.blue {
  background-color: var(--light-blue);
  color: var(--dark-blue);
}
.green {
  background-color: var(--light-green);
  color: var(--dark-green);
}
.purple {
  background-color: var(--light-purple);
  color: var(--dark-purple);
}
.orange {
  background-color: var(--light-orange);
  color: var(--dark-orange);
}
.red {
  background-color: var(--light-red);
  color: var(--dark-red);
}
body {
  background-color: var(--light-purple);
}

.container {
  width: 1000px;
  position: relative;
  margin: auto;
  margin-top: 200px;
  background-color: var(--dark-purple);
  padding: 1rem;
  padding-top: 6rem;
  padding-left: 6rem;
  border-radius: 1rem;
  border: 1px solid rgba(0, 0, 0, 0.2);
  box-shadow: 5px 5px 15px 3px rgba(0, 0, 0, 0.3);
}





3.2 Generate a random Avatar using API and style it.

/* Person */

.person {
  /* background-color: red; */
  position: absolute;
  top: -70px;
  left: -1px;
  display: flex;
  align-items: flex-end;
}

.person-avatar {
  height: 150px;
  width: 150px;
  border-radius: 50%;
  background-color: var(--dark-purple);
  background: url("https://avatars.dicebear.com/api/open-peeps/:seed.svg");
}
.person-name {
  color: #fff;
  text-shadow: 1px 2px 2px rgba(0, 0, 0, 0.4);
  font-size: 2.5rem;
}
.week {
  color: #fff;
  text-shadow: 1px 2px 2px rgba(0, 0, 0, 0.4);
}


section,
form {
  display: flex;
  gap: 15px;
}
section.tableBody {
  margin-top: 1rem;
  flex-direction: column;
}
input {
  max-width: 115px;
  outline: none;
  border: none;
  border-radius: 10px;
  height: 30px;
  font-size: 1.1rem;
  font-weight: 500;
  padding: 0.15rem 0.75rem;
  text-align: center;
}
.tableHead input {
  height: 50px;
}
.tableFooter {
  margin-top: 1rem;
  display: flex;
  justify-content: space-between;
}
.tableFooter #totalWorkedHours {
  margin-right: 90px;
}

3.4 Style the add button

.btn {
  background-color: inherit;
  border: 1px solid --light-gray;
  color: #fff;
  cursor: pointer;
  font-size: 1.1rem;
  font-weight: 500;
  padding: 0.15rem 0.75rem;
  border-radius: 5px;
  box-shadow: 0 2px 3px rgba(0, 0, 0, 0.3);
  transition: all 0.3s ease;
}
.btn:hover {
  background-color: var(--light-green);
  color: var(--dark-green);
}

.btn:active {
  transform: calc(0.95);
}
.btn-green {
  background-color: var(--dark-green);
  color: #eee;
}

4. Calculate working hours using javascript

Create a script.js file, link it up to your html file and add a console.log(“test”) to test it.

4.1 Get all table rows from the DOM

const tableBodyTrs = document
  .querySelector(".tableBody")
  .querySelectorAll(".tr");
// console.log(tableBodyTrs);

4.2 Create a function that creates a html form element

function createForm() {
let form = document.createElement("form");
form.innerHTML = `
  <th>  <input type="text" class="orange"  placeholder="Enter day" /></th>
  <td>
    <input type="time" id="start-work" class="blue"/>
  </td>
  <td>
    <input type="time" id="start-break" class="green" />
  </td>
  <td>
    <input type="time" id="end-break" class="green"/>
  </td>
  <td>
    <input type="time" id="end-work" class="blue"/>
  </td>

  <td>
    <input  class="workedHours purple" value="00:00" disabled />
  </td>
  <td>
    <button class="btn" type="submit">add</button>
  </td>
  `;

return form;
}

4.3 Add all form elements to the DOM using async and IIFE (Immediately Invoked Function Expression)

(async () => {
  // …
  tableBodyTrs.forEach((tr) => {
    // console.log(tr);

    tr.appendChild(createForm());
  });
  //   console.log(tableBodyTrs);
})();

4.4 Get all forms elements from the DOM

const forms = document.querySelectorAll("form");

4.4.1 Add submit event listeners to all forms

forms.forEach((form) => {
  // console.log(form[0].value);

  // const day = e.target.children[0].value;
  form.onsubmit = (e) => {
    e.preventDefault();


    // TODO: 4.1.1 Validate form submission



    //TODO: [ ] 5. Calculate the daily hours worked



    // todo: [ ] 6.Calculate total amount of worked hours

  };
});

4.4.1.1 Validate form submission


// todo: Create a function to validate the form submission

function validateSubmission(day, startWork, endWork, submitBtn) {
  // todo: [ ] Change button class after form submion
  if (day === "" || startWork === "" || endWork === "") {
    alert("Complete the start & end work hours");
  } else {
    submitBtn.classList.add("btn-green");
    submitBtn.innerHTML = "&#10004;";
    return true;
  }
}

4.4.2 Get input elements from the submitted form

// in the form

    // console.log(e.target.children);

    // TODO: [ ] 4.2 Get input elements from the submitted form
    const day = e.target.children[0].value;

    const startWork = e.target.children[1].value;
    const startBreak = e.target.children[2].value;
    const endBreak = e.target.children[3].value;
    const endWork = e.target.children[4].value;
    let worked = e.target.children[5];
    let submitBtn = e.target.children[6];
    console.log(submitBtn);
    // console.log(worked.value);

4.5. Calculate the daily hours worked

In order to calculate the daily worked hours you need follow tha code.

4.5.1 Create a function that calculates the amount of hours

   worked.value = calcDailyWorkedHours(
      startWork,
      endWork,
      startBreak,
      endBreak,
    );

4.5.1.1 Covert string to time
4.5.1.2 Calculate work time
4.5.1.3 Calculate break time
4.5.1.4 Calculate the final difference work – break time
4.5.1.5 Covert back to time
function calcDailyWorkedHours(
  startWork,
  endWork,
  startBreak,
  endBreak,
  // regularHours,
  e
) {
  // TODO: [ ] 5.1.1 Covert string to time
  startWork = startWork.split(":");
  endWork = endWork.split(":");
  startBreak = startBreak.split(":");
  endBreak = endBreak.split(":");

  // TODO: [ ] 5.1.1 Get Dates

  // TODO: [ ] 5.1.2  Calculate work time

  const startWorkDate = new Date(0, 0, 0, startWork[0], startWork[1], 0);
  const endWorkDate = new Date(0, 0, 0, endWork[0], endWork[1], 0);
  const diffWork = endWorkDate.getTime() - startWorkDate.getTime();

  //   console.log(diffWork);
  // TODO: [ ] 5.1.3 Calculate break time
  const startBreakDate = new Date(0, 0, 0, startBreak[0], startBreak[1], 0);
  const endBreakDate = new Date(0, 0, 0, endBreak[0], endBreak[1], 0);
  const diffBreak = endBreakDate.getTime() - startBreakDate.getTime();

  //   console.log(isNaN(diffBreak));
  // TODO: [ ] 5.1.4 Calculate the final difference work - break time
  let diffFinal =
    (isNaN(diffWork) ? 0 : diffWork) - (isNaN(diffBreak) ? 0 : diffBreak);
  //   console.log(diffFinal);

  // TODO: [ ] 5.1.5 Covert back to time
  let hours = Math.floor(diffFinal / 1000 / 60 / 60);
  diffFinal -= hours * 1000 * 60 * 60;
  const minutes = Math.floor(diffFinal / 1000 / 60);

  //[ ] Calculate overtime per word day
  // regularHours = regularHours.split(":");

  // const regularHoursDate = new Date(
  //   0,
  //   0,
  //   0,
  //   regularHours[0],
  //   regularHours[1],
  //   0
  // );

  // overtimeFinal = diffFinal - regularHoursDate.getTime();
  // overtimeFinal > 7 ? overtimeFinal : 0;

  // const overtime = e.target.children[5];

  // overtime.value = overtimeFinal;

  return (
    (hours < 9 ? "0" : "") + hours + ":" + (minutes < 9 ? "0" : "") + minutes
  );
}

4.6 Calculate total amount of worked hours

4.6.1 Create a function to calculate total amount of worked hours

4.6.1.2 Convert NodeList to array
4.6.1.3 Create a empty array and add elements to it.
4.6.1.4 Covert time strings to minutes
4.6.1.5 Return only work hours that exist
4.6.1.6 Output for Total Worked Hours
4.6.1.7 Create a function that converts minutes to minutes and hours

5. Refactoring the javascript code

// console.log("refactored");

// TODO [ ] 1. Get all table rows from the DOM
const tableBodyTrs = document
  .querySelector(".tableBody")
  .querySelectorAll(".tr");

// TODO [ ] 2. Create a function that creates a html form element
function createForm() {
  let form = document.createElement("form");

  form.innerHTML = `
    <th>  <input type="text" class="orange"  placeholder="Enter day" /></th>
    <td>
      <input type="time" id="start-work" class="blue"/>
    </td>
    <td>
      <input type="time" id="start-break" class="green" />
    </td>
    <td>
      <input type="time" id="end-break" class="green"/>
    </td>
    <td>
      <input type="time" id="end-work" class="blue"/>
    </td>
   
    <td>
      <input  class="workedHours purple" value="00:00" disabled />
    </td>
    <td>
      <button class="btn" type="submit" 
      ">add</button>
    </td>
    `;
  form.onsubmit = (e) => handleFormSubmission(e);
  return form;
}
// TODO [ ] 3. Add all form elements to the DOM using async and IIFE (Immediately Invoked Function Expression)
(async () => {
  tableBodyTrs.forEach((tr) => {
    tr.appendChild(createForm());
  });
})();

// TODO: [ ] 4. Get all forms elements from the DOM
const forms = document.querySelectorAll("form");

// TODO: [ ] 4.1 Add submit event listeners to all forms

function handleFormSubmission(e) {
  e.preventDefault();

  // TODO: [ ] 4.2 Get input elements from the submitted form
  const day = e.target.children[0].value,
    startWork = e.target.children[1].value,
    startBreak = e.target.children[2].value,
    endBreak = e.target.children[3].value,
    endWork = e.target.children[4].value;
  let worked = e.target.children[5];
  let submitBtn = e.target.children[6];

  // TODO: 4.1.1 Validate form submission
  if (validateSubmission(day, startWork, endWork, submitBtn)) {
    //TODO: [ ] 5. Calculate the daily hours worked

    //? Elements for overtime?

    worked.value = calcDailyWorkedHours(
      startWork,
      endWork,
      startBreak,
      endBreak,

      e
    );

    // todo: [ ] 6.Calculate total amount of worked hours
    calculateTotalWorkedHours();
  } else {
    return;
  }
}

// TODO: [ ] 5.1Create a function that calculates the amount of hours worked
function calcDailyWorkedHours(startWork, endWork, startBreak, endBreak) {
  // TODO: [ ] 5.1.1 Covert string to time
  startWork = startWork.split(":");
  endWork = endWork.split(":");
  startBreak = startBreak.split(":");
  endBreak = endBreak.split(":");

  // TODO: [ ] 5.1.1 Get Dates

  // TODO: [ ] 5.1.2  Calculate work time

  const startWorkDate = new Date(0, 0, 0, startWork[0], startWork[1], 0);
  const endWorkDate = new Date(0, 0, 0, endWork[0], endWork[1], 0);
  const diffWork = endWorkDate.getTime() - startWorkDate.getTime();

  // TODO: [ ] 5.1.3 Calculate break time
  const startBreakDate = new Date(0, 0, 0, startBreak[0], startBreak[1], 0);
  const endBreakDate = new Date(0, 0, 0, endBreak[0], endBreak[1], 0);
  const diffBreak = endBreakDate.getTime() - startBreakDate.getTime();

  // TODO: [ ] 5.1.4 Calculate the final difference work - break time
  let diffFinal =
    (isNaN(diffWork) ? 0 : diffWork) - (isNaN(diffBreak) ? 0 : diffBreak);

  // TODO: [ ] 5.1.5 covert back to time
  let hours = Math.floor(diffFinal / 1000 / 60 / 60);
  // substraction assigment
  diffFinal -= hours * 1000 * 60 * 60;
  const minutes = Math.floor(diffFinal / 1000 / 60);

  return (
    (hours < 9 ? "0" : "") + hours + ":" + (minutes < 9 ? "0" : "") + minutes
  );
}
// todo: [ ] 6.1 Create a function to calculate total amount of worked hours
function calculateTotalWorkedHours() {
  const allWorkedHours = document.querySelectorAll(".workedHours");

  // todo: [ ] 6.1.2 Convert NodeList to array

  let arrayOfWorkedHours = Array.from(allWorkedHours);

  let newWorkHours = arrayOfWorkedHours.map((workedHour) => {
    return workedHour.value;
  });

  // todo: [ ] 6.1.3 Create a empty array and add elements to it.
  let arr = [];
  arr.push(newWorkHours);

  // todo: [ ] 6.1.4 Covert time strings to minutes
  let subArr = arr[0].map((el) => {
    const [hours, minutes] = el.split(":");
    console.log(hours * 60 + minutes);
    return parseInt(hours) * 60 + parseInt(minutes);
  });

  console.log(subArr);

  // todo: [ ] 6.1.5  Return only work hours that exist

  let calculateTotalHoursWorked = subArr.reduce(
    (partialSum, a) => parseInt(partialSum + a),
    0
  );

  // todo: [ ] 6.1.6 Output for Total Worked Hours
  let outputWorkedHours = document.getElementById("totalWorkedHours");
  outputWorkedHours.value = minutesToHoursAndMinutes(calculateTotalHoursWorked);
}

// todo: [ ] Create a function to validate the form submission

function validateSubmission(day, startWork, endWork, submitBtn) {
  // todo: [ ] Change button class after form submion

  // ! [ ] Transform if else to turnary operator
  if (day === "" || startWork === "" || endWork === "") {
    console.log(day);
    alert("Enter the work day, start & end work hours");
  } else {
    submitBtn.classList.add("btn-green");
    submitBtn.innerHTML = "&#10004;";
    return true;
  }
}

// todo: [ ] 6.1.7 Create a function that converts minutes to minutes and hours
function minutesToHoursAndMinutes(minutes) {
  const hours = Math.floor(minutes / 60);
  const mins = minutes % 60;
  return (hours + "").padStart(2, "0") + ":" + (mins + "").padStart(2, "0");
}

6. Deployed Web application to website

Link to the website

For more information check out the video tutorial on YouTube.

Watch the full tutorial on YouTube and get step by step excellent education information about this project.

Coming out today!


Want to become a web developer ?

Get complete web development courses on HTML, CSS , JavaScript, Bootstrap, Visual Studio Code, Responsive design and much more…

Love Podcast about web development?

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.