ltx/lifetracker-vue/src/views/TableView.vue

264 lines
7.6 KiB
Vue

<script setup>
import { useDatabaseStore } from "@/stores/database"
import Api from "@/services/Api"
import appwrite from '@/services/appwrite';
import { DateTime } from "luxon";
</script>
<script>
import { defineComponent, toRaw, reactive } from 'vue';
import { HotTable } from '@handsontable/vue3';
import { registerAllModules } from 'handsontable/registry';
import 'handsontable/dist/handsontable.full.css';
import '../assets/colors.css';
import Handsontable from 'handsontable/base';
// register Handsontable's modules
registerAllModules();
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
function getHourClass(i) {
const colorMapping = {
0: "black",
1: "red",
2: "cyan",
3: "pink",
4: "blue",
5: "green",
6: "yellow",
7: "orange",
8: "purple",
9: "darkred",
10: "lime"
}
if(i > 10){
i = Math.round(i/10) - 1
}
if (i == null) {
return "";
}
else {
return "color-" + colorMapping[i];
}
}
function hourCol(t) {
return {
data: "hours." + t,
type: 'numeric',
renderer(instance, td, row, col, prop, value) {
td.className = getHourClass(value);
td.innerText = value == null ? value : parseFloat(value);
return td;
}
}
}
const colHeaders = ["DATE", "DAY", "12 AM"]
.concat(Array.from(new Array(11), (x, y) => y+1 + " AM") )
.concat(Array.from(new Array(12), (x, y) => y+1 + " PM") )
.concat(["Mood", "Comments"])
const ExampleComponent = defineComponent({
data() {
return {
entries: [],
numEntries: 25,
offset: 0,
hotSettings: {
autoRowSize: true,
columns: [
{
readOnly: true,
data: "date",
renderer(instance, td, row, col, prop, value) {
var date = DateTime.fromISO(value).toUTC().toFormat("MM/dd");
var today = DateTime.now().toFormat("MM/dd");
if(today == date){
td.className = "color-black invert";
}
else{td.className = "color-black";}
td.innerText = date;
return td;
}
},
{
readOnly: true,
data: "date",
renderer(instance, td, row, col, prop, value) {
var date = DateTime.fromISO(value).toUTC();
var today = DateTime.now().toFormat("MM/dd");
if(date.toFormat("MM/dd") == today){
td.className = "color-black invert day-of-week";
}
else{td.className = "color-black day-of-week";}
td.innerText = date.toFormat("EEE");
return td;
}
},
Array.from(new Array(24), (_, t) => hourCol(t)),
{ data: "mood", type: "numeric" },
{ data: "comments", className: "align-left" }
].flat(),
colHeaders: colHeaders,
rowHeaders: false,
readOnly: false,
width: '100%',
height: 'auto',
rowHeights: '22px',
colWidths(i) {
if((i > 1) && (i < 26)){
return "50px";
}
else if(i == 27){
return "1000px";
}
else{
return "50px";
}
},
afterSelection: (row, column, row2, column2, preventScrolling, selectionLayerLevel) => {
},
afterChange: (changes) => {
this.fixSelectionBug();
//this.setActiveHourHeader();
if (changes != null) {
var entry = this.entries[changes[0][0]];
entry.date = entry.date.replace(/T.*/, "");
appwrite.updateEntry(entry);
}
},
licenseKey: 'non-commercial-and-evaluation'
},
hotRef: null
}
},
async mounted(){
this.user = await appwrite.getUser();
this.entries = await appwrite.getEntries(null,5);
this.updateTable();
this.subscribe();
this.fixSelectionBug();
},
created () {
window.addEventListener('wheel', debounce(this.handleScroll, 300, true));
},
unmounted () {
window.removeEventListener('wheel', debounce(this.handleScroll, 300, true));
},
methods: {
setActiveHourHeader(){
var timeString = DateTime.now().toFormat("hh a");
var currentTimeHeader = Array.from(document.querySelectorAll("th"))
.find(el => el.innerText == timeString);
currentTimeHeader.className = "invert";
},
async handleScroll(e){
var offset;
if(e.deltaY > 0){
var lastDate = DateTime.fromISO(
this.entries[
this.hotRef
.getPlugin('autoRowSize')
.getLastVisibleRow()
].date).toUTC().plus({ days: 1 });
console.log("Grabbing 5 more entries starting at " + lastDate.toISO());
var newEntries = await appwrite.getEntries(
lastDate.plus({ days: 1 })
, 5);
newEntries.forEach((e) => {
this.entries.push(e);
})
}
else{
var firstDate = DateTime.fromISO(
this.entries[
this.hotRef
.getPlugin('autoRowSize')
.getFirstVisibleRow()
].date).toUTC().minus({ days: 1 });
console.log("Grabbing 5 previous entries ending at " + firstDate.toISO());
var newEntries = await appwrite.getEntries(
firstDate.minus({ days: 6 })
, 5);
var entries = this.entries;
newEntries.reverse().forEach((e) => {
entries.unshift(e);
})
this.entries = entries;
}
},
fixSelectionBug(){
if(this.hotRef){
var offset = (this.hotRef.getRowHeight()) * (this.entries.length + 1) + 2;//document.querySelector(".wtHider").clientHeight;
document.querySelector(".htBorders div").style.top = "-" + offset + "px";
}
},
subscribe(){
appwrite.subscribe((payload) => {
var event = payload.events.filter((e) =>
e.match(/databases\.\*\.collections\.\*\.documents\.\*\.\w+/)
)[0].replace(/.+\./,"");
switch (event) {
case 'create':
this.entries.push(payload.payload)
this.entries = this.entries
break
case 'update':
this.entries = this.entries.map((day) => {
if (day.$id === payload.payload.$id) {
return payload.payload
} else {
return day
}
})
break
case 'delete':
this.entries = this.entries.filter((day) => day.$id !== payload.payload.$id)
break
}
})
},
updateTable(){
this.hotRef = this.$refs.wrapper.hotInstance;
this.hotRef.loadData(this.entries);
}
},
components: {
HotTable,
}
});
export default ExampleComponent;
</script>
<template>
<button @click="concatEntries">Fuck</button>
<!-- <div>{{ entries }}</div>
<ul>
<li v-for="e in entries" :key="e">
{{ e }}
</li>
</ul> -->
<hot-table ref="wrapper" :settings="hotSettings" :data="entries"></hot-table>
</template>
<style>
</style>