Files
chronus/src/components/ClientChart.vue
Atridad Lahiji df82a02f41
All checks were successful
Docker Deploy / build-and-push (push) Successful in 4m3s
2.2.1 - Misc improvements and cleanup
2026-01-19 21:08:46 -07:00

98 lines
1.9 KiB
Vue

<template>
<div style="position: relative; height: 100%; width: 100%">
<Bar :data="chartData" :options="chartOptions" />
</div>
</template>
<script setup lang="ts">
import { computed } from "vue";
import { Bar } from "vue-chartjs";
import {
Chart as ChartJS,
BarElement,
CategoryScale,
LinearScale,
Tooltip,
Legend,
BarController,
type ChartOptions,
} from "chart.js";
ChartJS.register(
BarElement,
CategoryScale,
LinearScale,
Tooltip,
Legend,
BarController,
);
interface ClientData {
name: string;
totalTime: number;
}
const props = defineProps<{
clients: ClientData[];
}>();
const chartData = computed(() => ({
labels: props.clients.map((c) => c.name),
datasets: [
{
label: "Time Tracked",
data: props.clients.map((c) => c.totalTime / (1000 * 60)), // Convert to minutes
backgroundColor: "#6366f1",
borderColor: "#4f46e5",
borderWidth: 1,
},
],
}));
const chartOptions: ChartOptions<"bar"> = {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true,
ticks: {
color: "#e2e8f0",
callback: function (value: string | number) {
const numValue =
typeof value === "string" ? parseFloat(value) : value;
const hours = Math.floor(numValue / 60);
const mins = Math.round(numValue % 60);
return hours > 0 ? `${hours}h ${mins}m` : `${mins}m`;
},
},
grid: {
color: "#334155",
},
},
x: {
ticks: {
color: "#e2e8f0",
},
grid: {
display: false,
},
},
},
plugins: {
legend: {
display: false,
},
tooltip: {
callbacks: {
label: function (context) {
const minutes = Math.round(context.raw as number);
const hours = Math.floor(minutes / 60);
const mins = minutes % 60;
return ` ${hours}h ${mins}m`;
},
},
},
},
};
</script>