Link to home
Create AccountLog in
Avatar of ltpitt
ltpitt

asked on

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

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.
Avatar of ste5an
ste5an
Flag of Germany image

Well, I would start by separating the table creation from the doing the calculus first.
Avatar of ltpitt
ltpitt

ASKER

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...
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
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
Avatar of ltpitt

ASKER

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!
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.
ASKER CERTIFIED SOLUTION
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
See answer
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