Dyota's blog

JavaScript: Chore sheet for the home

I used to work an oil company, where we managed a small offshore oil platform that sucked up crude oil from the sea, and an onshore oil separation plant separates the oil and water.

For managing the assets, we had a computerised maintenance management system that told us what preventive maintenance tasks needed to be done, and at what intervals, to make sure that everything is in good repair.

I find that running a household requires the same thing. Some things need to be cleaned every week, but other things don't need to be cleaned so often. To make sure that these things get done, I set up a HTML file with some JavaScript that distributes household chores into lists. Each list has a date on it (representing a weekend) and the chores that need to be completed in that weekend. Then, periodically, I will print off these lists so that we have written chore sheets to direct us.

The first thing to do is generate dates for the next three months or so. I was most comfortable doing this in PowerShell, so here is a PS script to generate dates. It copies the result straight into a line of JavaScript that I can paste into the main file.

# generates Saturdays for the next X days

$reach = 120 # days

$today = (Get-Date -Year 2024 -Month 05 -Day 06).Date

# pick all the Saturdays in the next X days
$dates = @(0..$reach) | 
    ForEach-Object { $today.AddDays($_) } | 
    Where-Object { $_.DayOfWeek -eq 'Saturday' }

# figure out in what position in the month each Saturday is
$rows = $dates | 
    ForEach-Object {
        
        $thisMonth = $_.Month
        $daysThisMonth = $dates | Where-Object { $_.Month -eq $thisMonth }
        
        $isStartMonth = $_.Date -eq $daysThisMonth[0]
        $isMidMonth = $_.Date -eq $daysThisMonth[$([math]::Ceiling($daysThisMonth.Count / 2) - 1)] # mid-month, round up
        $isEndMonth = $_.Date -eq $daysThisMonth[-1]

        $startOfSeason = ($isStartMonth) -and ($thisMonth -in @(3, 6, 9, 12))

        $position = if ($isStartMonth) { 'start' } 
        elseif ($isMidMonth) { 'mid' } 
        elseif ($isEndMonth) { 'end' } 
        else { 'normal' }

        if ($startOfSeason) {
            return @{ date = $_.ToString('dd/MM/yyyy') ; position = $position ; season = $true }
        }
        else {
            return @{ date = $_.ToString('dd/MM/yyyy') ; position = $position }
        }
    } |
    # select only 16 so that it fits 2x2 on 4 pages
    Select-Object -First 16
    

# Generate JSON
$jsarray = $rows | ConvertTo-Json -Compress 


# make up the whole line in javascript to paste into html file
"const dates = " + $jsarray | Set-Clipboard

The main file is here.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Saturday chores</title>
    <style>
        section {
            page-break-after: always;
        }

        body {
            font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
            font-size: large;
        }
    </style>
</head>

<body>
    <div id="main">
        <!-- Content goes here -->
    </div>


    <script>

        const dates = [{"position":"start","date":"11/05/2024"},{"position":"mid","date":"18/05/2024"},{"position":"end","date":"25/05/2024"},{"date":"01/06/2024","position":"start","season":true},{"position":"normal","date":"08/06/2024"},{"position":"mid","date":"15/06/2024"},{"position":"normal","date":"22/06/2024"},{"position":"end","date":"29/06/2024"},{"position":"start","date":"06/07/2024"},{"position":"mid","date":"13/07/2024"},{"position":"normal","date":"20/07/2024"},{"position":"end","date":"27/07/2024"},{"position":"start","date":"03/08/2024"},{"position":"normal","date":"10/08/2024"},{"position":"mid","date":"17/08/2024"},{"position":"normal","date":"24/08/2024"}]
        const chores = {
            normal: [],
            season: [],
            start: [],
            mid: [],
            end: [],
        };

        dates.forEach(weekend => {
            const splitDate = weekend.date.split('/');
            const date = new Date(
                splitDate[2], // year
                splitDate[1] - 1, // month, zero index
                splitDate[0]  // date
            );

            const heading = `<h2>${date.toDateString()}</h2>`;
            
            choresSpecialArray = chores[weekend.position];

            weekend.season != undefined
                ? seasonalChores = `<h4>Seasonal chores</h4>` + makeChoresList('season')
                : seasonalChores = '';

            const normalChores = `<h4>Normal chores</h4>` + makeChoresList('normal');

            if (weekend.position != 'normal') {
                specialChores = `<h4>Special chores</h4>` + makeChoresList(weekend.position);
                position = `<h3>${capitalise(weekend.position)} of month</h3>`;
            } else {
                specialChores = '';
                position = `<h3>Normal week</h3>`
            }

            const fullChoresList = normalChores + specialChores + seasonalChores;

            const fulltext = '<section>' + heading + position + fullChoresList + '</section>';

            $$('main').innerHTML += fulltext;
        });

        function makeChoresList(weekendPosition) {
            let choresArray = [];
            choresArray = chores[weekendPosition];
            let choresList = '';
            choresArray.forEach(chore => {
                choresList += `<li><input type="checkbox">&nbsp&nbsp${chore}</input>`;
            });
            return choresList = '<ul style="list-style-type:none;">' + choresList + '</ul>';
        }

        function $(selector) {
            return document.querySelectorAll(selector);
        }

        function $$(selector) {
            return document.getElementById(selector);
        }

        function capitalise(text) {
            firstLetter = text.slice(0, 1),
                rest = text.slice(1);
            return firstLetter.toUpperCase() + rest;
        }


    </script>
</body>

</html>

#javascript #taskmanagement