105 lines
3.1 KiB
TypeScript
105 lines
3.1 KiB
TypeScript
"use client";
|
|
import {Card, Title} from "@tremor/react";
|
|
import {useEffect, useRef, useState} from "react";
|
|
import useSWR from "swr";
|
|
import {fetcher} from "@/app/utils";
|
|
import * as R from 'ramda';
|
|
import * as dFns from 'date-fns';
|
|
import CalendarHeatmap from 'react-calendar-heatmap';
|
|
// import CalendarHeatmap from '../heatmap';
|
|
import 'react-calendar-heatmap/dist/styles.css';
|
|
import './calendar-styles.css'
|
|
import { Tooltip } from 'react-tooltip';
|
|
import {MyHeatMap} from "@/heatmap/b";
|
|
|
|
const initialDate = dFns.parseISO('2023-12-15T00:00:00.000Z')
|
|
const endDate = dFns.parseISO('2024-01-25T00:00:00.000Z')
|
|
const projectIds = [
|
|
195482340,
|
|
195519024,
|
|
195518593,
|
|
195754611,
|
|
];
|
|
|
|
const dailyGoal = 4;
|
|
const granularity = 4;
|
|
|
|
function computeCompletionShade(value: number) {
|
|
const linearValue = Math.round((value / dailyGoal) * granularity);
|
|
if (linearValue == 0 && value > 0) return 1;
|
|
if (linearValue > granularity) return granularity;
|
|
return linearValue;
|
|
}
|
|
|
|
function useCalendarData() {
|
|
const {
|
|
data: timeEntries,
|
|
error,
|
|
isLoading,
|
|
} = useSWR<{
|
|
raw_json: {
|
|
start: string,
|
|
seconds: number,
|
|
}
|
|
}[]>(`/api/time_entry?select=raw_json&start=gt.${dFns.formatISO(initialDate)}&project_id=in.(${projectIds.join(',')})`, fetcher, {});
|
|
|
|
const [data, setData] = useState<{
|
|
date: Date,
|
|
count: number,
|
|
}[]>([]);
|
|
|
|
useEffect(() => {
|
|
if (timeEntries == undefined) return;
|
|
|
|
// Group by day, sum up seconds
|
|
const grouped = R.groupBy((entry) => {
|
|
return dFns.formatISO(dFns.startOfDay(dFns.parseISO(entry.raw_json.start)));
|
|
}, timeEntries);
|
|
|
|
const summed = R.mapObjIndexed((entries) => {
|
|
return R.sum((entries ?? []).map((entry) => entry.raw_json.seconds))
|
|
}, grouped);
|
|
|
|
// Fill in missing days, hacky
|
|
dFns.eachDayOfInterval({
|
|
start: initialDate,
|
|
end: endDate,
|
|
}).forEach((date) => {
|
|
const key = dFns.formatISO(date);
|
|
if (summed[key] == undefined) {
|
|
summed[key] = 0;
|
|
}
|
|
})
|
|
|
|
setData(Object.entries(summed)
|
|
.map(([key, value]) => ({
|
|
date: dFns.parseISO(key),
|
|
count: value / (60 * 60),
|
|
})));
|
|
}, [timeEntries]);
|
|
|
|
return data
|
|
}
|
|
|
|
export function CalendarOverviewCard() {
|
|
const data = useCalendarData();
|
|
|
|
return <Card className="col-span-1">
|
|
<Tooltip id="calendar-tooltip"/>
|
|
<Title>Overview</Title>
|
|
<CalendarHeatmap
|
|
showWeekdayLabels={true}
|
|
startDate={initialDate}
|
|
endDate={endDate}
|
|
values={data}
|
|
classForValue={value => `color-github-${computeCompletionShade(value?.count ?? 0)}`}
|
|
tooltipDataAttrs={(value: any) => {
|
|
return value.date ? {
|
|
'data-tooltip-id': `calendar-tooltip`,
|
|
'data-tooltip-content': value.count ?`${dFns.format(value.date, 'EEE do')}: ${value.count.toFixed(2)} hours` : `${dFns.format(value.date, 'EEE do')}`
|
|
} : undefined
|
|
}}
|
|
/>
|
|
</Card>
|
|
}
|