Files
mmm-chores/MMM-chores.js
Parnic 67305ad084 Fix manually-checked chores un-checking on refresh
I forgot to account for saving the data on the frontend, so it was only
ever using whatever the last data passed to us from the backend was,
which only happens once on initial load.
2021-04-23 08:00:07 -05:00

219 lines
7.7 KiB
JavaScript

// pulled from https://stackoverflow.com/a/6117889/897869
Date.prototype.getWeekNumber = function() {
let d = new Date(Date.UTC(this.getFullYear(), this.getMonth(), this.getDate()));
const dayNum = d.getUTCDay() || 7;
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
return Math.ceil((((d - yearStart) / (24 * 60 * 60 * 1000)) + 1) / 7)
};
Module.register("MMM-chores", {
defaults: {
chores: [],
cheers: ['YEA!', 'AWESOME!', 'YES!', 'DONE!'],
id: "chore",
showConfetti: true
},
start() {
this.doUpdate()
this.sendSocketNotification("CHORES_READY")
},
doUpdate() {
this.updateDom()
setTimeout(() => {
this.doUpdate()
}, 5 * 60 * 1000)
},
getDom() {
let str
var today = new Date()
var wrapper = document.createElement("div")
this.config.chores.forEach((element, idx) => {
if (!element.weekly) {
str = "day-" + this.getDateString(today)
} else {
str = "week-" + this.getWeekString(today)
}
let elemId = element.id
if (!elemId) {
elemId = String(idx)
}
var id = this.config.id + "_" + elemId + "_" + str
wrapper.appendChild(this.getCheckbox(element.label, id))
});
return wrapper
},
socketNotificationReceived(notification, payload) {
if (notification === "CHORES_DATA_READ") {
this.saved_data = payload
this.updateDom()
}
},
getDateString(date) {
var td = String(date.getDate()).padStart(2, '0')
var tm = String(date.getMonth() + 1).padStart(2, '0')
var ty = date.getFullYear()
return ty + tm + td
},
getWeekString(date) {
return date.getFullYear() + String(date.getWeekNumber()).padStart(2, '0')
},
getCheckbox(label, id) {
var container = document.createElement("label")
container.className = "chores-container"
container.innerText = label
var cb = document.createElement("input")
cb.type = "checkbox"
if (id !== undefined) {
cb.id = id
}
cb.checked = this.saved_data && this.saved_data[cb.id] === 1
cb.onclick = (ev) => {
let targetId = ev.target.id
let val = cb.checked ? 1 : 0
if (!this.saved_data) {
this.saved_data = {}
}
this.saved_data[targetId] = val
this.sendSocketNotification("CHORES_ADD_DATA", { "key": targetId, "val": val })
const numItems = 2
const randVal = Math.floor(Math.random() * 1000)
if (this.config.showConfetti && cb.checked) {
if (randVal % numItems == 0) {
this.createConfetti(ev.clientX, ev.clientY, 20)
} else {
this.createCheer(ev.clientX, ev.clientY, this.config.cheers[Math.floor(Math.random() * this.config.cheers.length)])
}
}
}
var cm = document.createElement("span")
cm.className = "checkmark"
container.appendChild(cb)
container.appendChild(cm)
return container
},
getStyles() {
return [this.file("MMM-chores.css")]
},
randomId(length) {
var result = [];
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result.push(characters.charAt(Math.floor(Math.random() * charactersLength)));
}
return result.join('');
},
createConfetti(x, y, confettiItems) {
let createElement = document.createElement('div');
createElement.classList.add('MMM-chores', 'confetti');
let makeId = this.randomId(10);
createElement.setAttribute('data-mmm-chores-id', makeId);
let confettiHTML = '';
let colors = ['#2162ff', '#9e21ff', '#21a9ff', '#a9ff21', '#ff2184']
for (var i = 0; i < confettiItems; ++i) {
let color = Math.floor(Math.random() * (colors.length));
confettiHTML += `<div class="confetti-item" style="background-color: ${colors[color]};" data-angle="${Math.random()}" data-speed="${Math.random()}"></div>`;
confettiHTML += `<div class="confetti-item reverse" style="background-color: ${colors[color]};" data-angle="${Math.random()}" data-speed="${Math.random()}"></div>`;
}
createElement.style.position = `fixed`;
createElement.style.top = `${y}px`;
createElement.style.left = `${x}px`;
createElement.innerHTML = confettiHTML;
document.body.appendChild(createElement);
let gravity = 50;
let maxSpeed = 105000;
let minSpeed = 65000;
let t = 0;
let maxAngle = 1500;
let minAngle = 400;
let opacity = 1;
let rotateAngle = 0;
let interval = setInterval(function() {
document.querySelectorAll(`[data-mmm-chores-id="${makeId}"] .confetti-item`).forEach(function(item) {
let modifierX = 1;
let modifierY = 1;
if (item.classList.contains('reverse')) {
modifierX = -1;
}
item.style.opacity = opacity;
let randomNumber = parseFloat(item.getAttribute('data-angle'));
let otherRandom = parseFloat(item.getAttribute('data-speed'));
let newRotateAngle = randomNumber * rotateAngle;
let angle = (randomNumber * (maxAngle - minAngle) + minAngle) / 1000;
let speed = (randomNumber * (maxSpeed - minSpeed) + minSpeed) / 1000;
let x = speed * t * Math.cos(angle) + (50 * otherRandom * t);
let y = speed * t * Math.sin(angle) - (0.5 * gravity * Math.pow(t, 2)) + (50 * otherRandom * t);
item.style.transform = `translateX(${x * modifierX}px) translateY(${y * -1 * modifierY}px) rotateY(${newRotateAngle}deg) scale(${1})`;
})
t += 0.1;
rotateAngle += 3;
opacity -= 0.02;
if (t >= 6) {
t = 0.1;
if (document.querySelector(`[data-mmm-chores-id="${makeId}"]`) !== null) {
document.querySelector(`[data-mmm-chores-id="${makeId}"]`).remove();
}
clearInterval(interval);
}
}, 33.33);
},
createCheer(x, y, word) {
let createElement = document.createElement('div')
createElement.classList.add('MMM-chores', 'confetti')
let makeId = this.randomId(10)
createElement.setAttribute('data-mmm-chores-id', makeId)
let cheerHTML = ''
let colors = ['#2162ff', '#9e21ff', '#21a9ff', '#a9ff21', '#ff2184']
for (var i = 0; i < word.length; ++i) {
let color = Math.floor(Math.random() * (colors.length))
cheerHTML += `<span class="cheer-item" style="color: ${colors[color]}">${word[i]}</span>`
}
createElement.style.position = `fixed`
createElement.style.top = `${y - 20}px`
createElement.style.left = `${x}px`
createElement.innerHTML = cheerHTML
document.body.appendChild(createElement)
let opacity = 1
let t = 0
let interval = setInterval(function() {
createElement.style.transform = `translateY(${t * -35}px)`
createElement.style.opacity = opacity
t += 0.1
opacity -= 0.02
if (t >= 6) {
t = 0.1
createElement.remove()
clearInterval(interval)
}
}, 33.33)
}
})