fp/packages/next/app/components/cal.tsx

125 lines
3.3 KiB
TypeScript

'use client';
// greets https://github.com/wa0x6e/cal-heatmap-react-starter/blob/main/src/components/cal-heatmap.tsx
import CalHeatmap from 'cal-heatmap';
// @ts-ignore cal-heatmap is jenk
import Legend from 'cal-heatmap/plugins/Legend';
// @ts-ignore cal-heatmap is jenk
import Tooltip from 'cal-heatmap/plugins/Tooltip';
import { DataRecord } from 'cal-heatmap/src/options/Options';
import 'cal-heatmap/cal-heatmap.css';
import dayjs from 'dayjs';
import { useEffect, useState, useRef } from 'react';
import { useRouter } from 'next/navigation';
import { getSafeDate } from '@/lib/dates';
export interface ICalProps {
data: DataRecord[];
slug: string;
}
export function Cal({ data, slug }: ICalProps) {
const router = useRouter();
const [cellSize, setCellSize] = useState(13);
const [targetElementId, setTargetElementId] = useState('');
const generateUniqueId = () => {
return `cal-${Math.random().toString(36).substring(2, 9)}`;
};
useEffect(() => {
const updateCellSize = () => {
const windowWidth = window.innerWidth;
if (windowWidth > 1400) {
setCellSize(15); // Adjust the cell size for width > 1400px
} else if (windowWidth > 730) {
setCellSize(10); // Adjust the cell size for width > 730px
} else {
setCellSize(3); // Adjust the cell size for width <= 730px
}
}
updateCellSize();
// Event listener to update cell size on window resize
window.addEventListener('resize', updateCellSize);
return () => {
window.removeEventListener('resize', updateCellSize);
};
}, [])
useEffect(() => {
setTargetElementId(generateUniqueId());
}, []);
useEffect(() => {
if (!targetElementId) return;
const cal = new CalHeatmap();
// @ts-ignore
cal.on('click', (
event: string,
timestamp: number,
value: number
) => {
router.push(`/vt/${slug}/stream/${getSafeDate(new Date(timestamp))}`);
// console.log(`slug=${slug} safeDate=${getSafeDate(new Date(timestamp))}`);
});
cal.paint(
{
itemSelector: `#${targetElementId}`,
scale: {
color: {
// @ts-ignore this shit is straight from the example website
domain: ['missing', 'issue', 'good'],
type: 'ordinal',
range: ['red', 'yellow', 'green']
}
},
theme: 'dark',
verticalOrientation: false,
data: {
source: data,
x: 'date',
y: 'value',
// @ts-ignore this shit is straight from the example website
groupY: d => d[0]
},
range: 12,
date: { start: data[0].date },
domain: {
type: 'month',
gutter: 4,
label: { text: 'MMM', textAlign: 'start', position: 'top' }
},
subDomain: {
type: 'ghDay',
radius: 2,
width: cellSize,
height: cellSize,
gutter: 4,
}
}, [
[
Tooltip,
{
text: ((ts: number, value: string, dayjsDate: dayjs.Dayjs) => {
return `${!!value ? value+' - '+dayjsDate.toString() : dayjsDate.toString() }`;
})
}
]
]);
}, [targetElementId, data, cellSize, router, slug]);
return (
<>
<div id={targetElementId}></div>
</>
)
}