We help IT Professionals succeed at work.

How to calculate cleaning turns if every flatmate is doing a two weeks turn dynamically?

ltpitt
ltpitt used Ask the Experts™
on
Hi all,

I am building a table that automatically shows who is the person that is in charge of cleaning the kitchen in plain Javascript.

This is what I have so far:
<style>
th, td {
  padding: 15px;
  text-align: left;
}

tr:hover {background-color: #f5f5f5;}

table {
  width: 100%;
}
</style>

<div id="cleaningTableDiv">
</div>


<script>

Date.prototype.getWeek = function() {
    var onejan = new Date(this.getFullYear(), 0, 1);
    return Math.ceil((((this - onejan) / 86400000) + onejan.getDay() + 1) / 7);
}

function plainTableCreate(currentWeekNumber) {
    // Table variables
    var teamMembers = ["Flatmate1", "Flatmate2", "Flatmate3", "Flatmate4", "Flatmate5", "Flatmate6"];
    var rowNumber = 7;
    var colNumber = teamMembers.length * 2 + 1;
    var headings = ["Week number"]
    for (var i = 0; i < colNumber - 1; i++) {
        headings.push(currentWeekNumber + i);
    }

    // Creating table
    var body = document.getElementById('cleaningTableDiv');
    var tbl = document.createElement('table');
    tbl.setAttribute("id", "cleaningTable");
    var tbdy = document.createElement('tbody');
    for (var i = 0; i < rowNumber; i++) {
        var tr = document.createElement('tr');
        for (var j = 0; j < colNumber; j++) {
            var td = document.createElement('td');
            td.appendChild(document.createTextNode(""));
            tr.appendChild(td);
        }
        tbdy.appendChild(tr);
    }
    tbl.appendChild(tbdy);
    body.appendChild(tbl);

    // Populating headings
    for (var i=0; i < headings.length; i++){
        document.getElementById("cleaningTable").rows[0].cells[i].innerHTML = headings[i];
    }

    // Populating 1st column with Team Members
    for (var i=1; i < rowNumber; i++){
        document.getElementById("cleaningTable").rows[i].cells[0].innerHTML = teamMembers[i-1];
    }

    // Populating X
    for (var i=1; i < rowNumber; i++){
        for (var j=1; j < colNumber; j++){
            if (i == 4) {
                // Flatmate 4 started cleaning week 1 and 2, next rotation will happen every 2
                // weeks, for example flatmate 5 will clean week 3 and 4, flatmate 6 will clean
                // week 5 and 6, flatmate 6 will clean week 7 and 8, flatmate 1 will clean
                // week 9 and 10 and so on...
                document.getElementById("cleaningTable").rows[i].cells[j].innerHTML = "X";                  
            }
            console.log(document.getElementById("cleaningTable").rows[0].cells[j].innerHTML);

        }
    }

}


var currentWeekNumber = (new Date()).getWeek();
plainTableCreate(currentWeekNumber);

</script>

Open in new window


I cannot think how to populate dynamically the turns, given the fact that the flatmate4 started cleaning week 1 and 2 of the year.

How can I be able to make the script perpetually work?

Thanks for your help.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
ste5anSenior Developer

Commented:
Well, I would start by separating the table creation from the doing the calculus first.

Author

Commented:
Ok, I see your point.

I have 6 flatmates and 52 weeks per year.
Flatmate 4 started the cleaning on the 1st week of the year, every cleaning turn lasts 2 weeks.

Now we are, for example, in week 23.

Who should clean?
23 / 2 = 11
11 users after flatmate 4?
But if I do the calculations it doesn't always work and I am a bit puzzled...
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Something like this
<style>
th, td {
  padding: 15px;
  text-align: left;
}

tr:hover {background-color: #f5f5f5;}

table {
  width: 100%;
}
</style>

<div id="cleaningTableDiv">
</div>


<script>
var teamMembers = ["Flatmate1", "Flatmate2", "Flatmate3", "Flatmate4", "Flatmate5", "Flatmate6"];

createCleaningTable(document.getElementById('cleaningTableDiv'), teamMembers, 3);

function createCleaningTable(parent, teamMembers, currentTeamMember) {
  var data = [];
  
  for(var i = 0; i < teamMembers.length; i++) {
    var tm = teamMembers[currentTeamMember % teamMembers.length];
    var entry = {
      member: tm,
      weeks: []
    }
    for(var wk = i; wk <= 52; wk+= teamMembers.length) {
      entry.weeks.push(wk*2+1);
      entry.weeks.push(wk*2+2);
    }
    data.push(entry);
    currentTeamMember++;
  }
  var table = document.createElement('table');
  var thead = table.createTHead();
  var trow = thead.insertRow();
  var th = document.createElement('th');
  th.innerHTML = 'Member';
  trow.appendChild(th);
  for(var i = 1; i <= 52; i++){ 
    th = document.createElement('th');
    th.innerHTML = i;
    trow.appendChild(th);
  }
  table.appendChild(thead);
  var tbody = table.createTBody();
  data.forEach(function(item) {
    var row = tbody.insertRow();
    var cell = row.insertCell();
    cell.innerHTML = item.member;
    for(var wk = 1; wk <= 52; wk++) {
      cell = row.insertCell();
      if (item.weeks.includes(wk)) {
        cell.innerHTML = 'x';
      }
    }
  });
  
  parent.appendChild(table);
}
</script>

Open in new window

You can see it working here
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Updated with comments and added a sort to put the table in flat mate order
<style>
th, td {
  padding: 15px;
  text-align: left;
}

tr:hover {background-color: #f5f5f5;}

table {
  width: 100%;
}
</style>

<div id="cleaningTableDiv">
</div>


<script>
var teamMembers = ["Flatmate1", "Flatmate2", "Flatmate3", "Flatmate4", "Flatmate5", "Flatmate6"];

createCleaningTable(document.getElementById('cleaningTableDiv'), teamMembers, 3);

function createCleaningTable(parent, teamMembers, currentTeamMember) {
  var data = [];
  
  // Create our cleaning data first
  // Iterate over the flatmates and create the weeks for them. We do this
  // by starting with the currentTeamMember and then incrementing using the Mod to get 
  // the actual Team Member we are working with
  // We then work out all the weeks that person will be cleaning which is jumping by 2 each time
  // and then by the number of team members
  for(var i = 0; i < teamMembers.length; i++) {
    var tm = teamMembers[currentTeamMember % teamMembers.length];
    var entry = {
      member: tm,
      weeks: []
    }
    for(var wk = i; wk <= 52; wk+= teamMembers.length) {
      entry.weeks.push(wk*2+1);
      entry.weeks.push(wk*2+2);
    }
    data.push(entry);
    currentTeamMember++;
  }
  
  // Sort the data in flatmate order
  data.sort(function(a,b) {
	return a.member === b.member ? 0 : a.member < b.member ? -1 : 1; 
  });
  
  // Data organised now we create the table
  var table = document.createElement('table');
  var thead = table.createTHead();
  var trow = thead.insertRow();
  var th = document.createElement('th');
  th.innerHTML = '';
  trow.appendChild(th);
  
  // Build the THEAD section
  for(var i = 1; i <= 52; i++){ 
    th = document.createElement('th');
    th.innerHTML = i;
    trow.appendChild(th);
  }
  table.appendChild(thead);
  
  // Now the body ...
  var tbody = table.createTBody();
  data.forEach(function(item) {
    var row = tbody.insertRow();
    var cell = row.insertCell();
    cell.innerHTML = item.member;
    for(var wk = 1; wk <= 52; wk++) {
      cell = row.insertCell();
      if (item.weeks.includes(wk)) {
        cell.innerHTML = 'x';
      }
    }
  });
  
  parent.appendChild(table);
}
</script>

Open in new window

Working sample here

Author

Commented:
Hi Julian and thanks for your input.

Your solution draws a very big table containing all the data, I wanted to make just a small list of the coming weeks and show very easily which is the current one (the 1st).

Populating the data in your case is easier because it just becomes mark two, next, mark two, next etc.

But thanks for your contribution!
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Then simply change the parameters to draw from the start week to the week you want.
<style>
th, td {
  padding: 15px;
  text-align: left;
}

tr:hover {background-color: #f5f5f5;}

table {
  width: 100%;
}
</style>

<div id="cleaningTableDiv">
</div>


<script>
var teamMembers = ["Flatmate1", "Flatmate2", "Flatmate3", "Flatmate4", "Flatmate5", "Flatmate6"];

createCleaningTable(document.getElementById('cleaningTableDiv'), teamMembers, 3, 1,13);

function createCleaningTable(parent, teamMembers, currentTeamMember, from, to) {
  var data = [];
  
  // Create our cleaning data first
  // Iterate over the flatmates and create the weeks for them. We do this
  // by starting with the currentTeamMember and then incrementing using the Mod to get 
  // the actual Team Member we are working with
  // We then work out all the weeks that person will be cleaning which is jumping by 2 each time
  // and then by the number of team members
  for(var i = 0; i < teamMembers.length; i++) {
    var tm = teamMembers[currentTeamMember % teamMembers.length];
    var entry = {
      member: tm,
      weeks: []
    }
    for(var wk = i; wk <= 52; wk+= teamMembers.length) {
      entry.weeks.push(wk*2+1);
      entry.weeks.push(wk*2+2);
    }
    data.push(entry);
    currentTeamMember++;
  }
  
  // Sort the data in flatmate order
  data.sort(function(a,b) {
	return a.member === b.member ? 0 : a.member < b.member ? -1 : 1; 
  });
  
  // Data organised now we create the table
  var table = document.createElement('table');
  var thead = table.createTHead();
  var trow = thead.insertRow();
  var th = document.createElement('th');
  th.innerHTML = '';
  trow.appendChild(th);
  
  // Build the THEAD section
  for(var i = from; i <= to; i++){ 
    th = document.createElement('th');
    th.innerHTML = i;
    trow.appendChild(th);
  }
  table.appendChild(thead);
  
  // Now the body ...
  var tbody = table.createTBody();
  data.forEach(function(item) {
    var row = tbody.insertRow();
    var cell = row.insertCell();
    cell.innerHTML = item.member;
    for(var wk = from; wk <= to; wk++) {
      cell = row.insertCell();
      if (item.weeks.includes(wk)) {
        cell.innerHTML = 'x';
      }
    }
  });
  
  parent.appendChild(table);
}
</script>

Open in new window

You call the createCleaningTable with two additional parameters (from and to) and it will render the table for that set of weeks.
Most Valuable Expert 2017
Distinguished Expert 2018
Commented:
I have changed the online sample to allow for a dynamic selection of weeks.

You can try it out here
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Corrected a minor issue in the render code.

Original : https://www.marcorpsa.com/ee/t3785.html
Dynamic: https//www.marcorpsa.com/ee/t3785-a.html