brf/client/public/components/account_page.tsx
2026-06-15 14:09:28 +02:00

91 lines
2.2 KiB
TypeScript

import { h, type FunctionComponent } from 'preact'
import { useEffect, useRef } from 'preact/hooks'
import * as d3 from 'd3'
import rek from 'rek'
import Head from './head.ts'
import usePromise from '../../shared/hooks/use_promise.ts'
type AccountPageProps = {
number: number
}
function empty(element: HTMLElement) {
while (element.lastElementChild) {
element.removeChild(element.lastElementChild)
}
}
const AccountPage: FunctionComponent<AccountPageProps> = ({ number }) => {
const graphRef = useRef<HTMLDivElement>(null)
const sums = usePromise<{ month: string; totalAmount: number }[]>(() => rek(`/api/accounts/month-sum/${number}`))
useEffect(() => {
empty(graphRef.current!)
const width = 1000
const height = 1000
const margin = { left: 50, bottom: 40 }
const stageWidth = 1000 - margin.left
const stageHeight = 1000 - margin.bottom
const svg = d3
.select(graphRef.current)
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', `translate(${margin.left}, 0)`)
const x = d3.scaleBand(
sums.map(({ month }) => month),
[0, stageWidth],
)
svg.append('g').attr('transform', `translate(0, ${stageHeight})`).call(d3.axisBottom(x))
const y = d3.scaleLinear([0, d3.max(sums, (d) => Math.abs(d.totalAmount))], [stageHeight, 0])
svg.append('g').call(d3.axisLeft(y))
svg
.append('path')
.datum(sums)
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 1.5)
.attr(
'd',
d3
.line()
.x((d) => x(d.month))
.y((d) => y(Math.abs(d.totalAmount))),
)
}, [])
return (
<section>
<Head>
<title> : Konto</title>
</Head>
<h1>Konto {number}</h1>
<div ref={graphRef} />
<table className='grid'>
<thead>
<th>Månad</th>
<th>Summa</th>
</thead>
<tbody>
{sums.map((sum) => (
<tr>
<td>{sum.month}</td>
<td>{sum.totalAmount}</td>
</tr>
))}
</tbody>
</table>
</section>
)
}
export default AccountPage