Skip to content

Commit

Permalink
feat(gluwave): 💄 Rework carbs graph #75
Browse files Browse the repository at this point in the history
  • Loading branch information
Kalhama committed Sep 23, 2024
1 parent 4604d9e commit 1e3864f
Show file tree
Hide file tree
Showing 11 changed files with 461 additions and 382 deletions.
6 changes: 4 additions & 2 deletions gluwave/src/app/(app-menu)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { validateRequest } from '@/auth'
import BloodGlucose from '@/components/blood-glucose'
import CarbsOnBoard from '@/components/carbs-on-board'
import CarbsRate from '@/components/carbohydrate-rate'
import { CarbohydratesOnBoard } from '@/components/carbohydrates-on-board'
import InsulinOnBoard from '@/components/insulin-on-board'
import { db } from '@/db'
import { glucose } from '@/schema'
Expand Down Expand Up @@ -40,7 +41,8 @@ export default async function App() {
<div className="mt-2 grid gap-2 mx-auto sm:grid-cols-2 max-w-5xl min-[420px]:px-2 md:px-4">
<BloodGlucose />
<InsulinOnBoard />
<CarbsOnBoard />
{/* <CarbsRate /> */}
<CarbohydratesOnBoard />
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,12 @@ export const GlucoseChartContent = ({ glucose, prediction, now }: Props) => {
/>
<VictoryLine
style={{
/* tailwind slate-900 */
data: { stroke: '#0f172a', strokeDasharray: '2 2' },
/* tailwind sky-600 */
data: {
stroke: '#0284c7aa',
strokeDasharray: '3 3',
strokeWidth: 3,
},
parent: { border: '1px solid #ccc', padding: 0 },
}}
data={prediction}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
'use client'

import { addHours } from 'date-fns'
import { DomainTuple, Tuple, VictoryArea, VictoryLine } from 'victory'

import { GraphContent } from '../graph-container'

type ChartData = {
x: Date
y: number
}[]

interface Props {
now: Date
observed: ChartData
reported: ChartData
domain: {
x: Tuple<Date>
y: DomainTuple
}
}

export const CarbsRateGraph = ({ now, observed, reported, domain }: Props) => {
// for visual purposes
observed.push({
y: 0,
x: addHours(now, 6),
})

const initialZoomDomain = {
x: [addHours(now, -6), addHours(now, 1)] as Tuple<Date>,
}

return (
<GraphContent
initialZoomDomain={initialZoomDomain}
domain={domain}
now={now}
>
<VictoryLine
style={{
data: {
strokeDasharray: '2 2',
strokeWidth: 1,
stroke: '#c43a31',
},
}}
data={[
{ x: now, y: -5000 },
{ x: now, y: 5000 },
]}
/>
<VictoryArea
style={{
/* tailwind green-700 */
data: { fill: '#15803d88' },
}}
interpolation="stepAfter"
data={observed}
/>
(
<VictoryArea
style={{
/* tailwind slate-700 */
data: { fill: '#33415588' },
}}
interpolation="stepAfter"
data={reported}
/>
)
</GraphContent>
)
}
78 changes: 78 additions & 0 deletions gluwave/src/components/carbohydrate-rate/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { validateRequest } from '@/auth'
import { Statistics } from '@/lib/sql_utils'
import { addHours, addMinutes, setHours, startOfDay, subHours } from 'date-fns'
import { redirect } from 'next/navigation'
import { Tuple } from 'victory'

import { GraphContainer, GraphTitle } from '../graph-container'
import { CarbsRateGraph } from './carbohydrate-rate-graph'

export default async function CarbsRate() {
const { user } = await validateRequest()
if (!user) {
redirect('/login')
}

const now = new Date()
const start = setHours(startOfDay(subHours(now, 4)), 4) // previous 4AM
const end = addHours(now, 12)

const tf = Statistics.approximate_timeframe(user.id, start, end)

const observed = await Statistics.execute(
Statistics.observedCarbs(
tf,
user.id,
user.carbohydrateRatio,
user.correctionRatio
)
)

const reported = await Statistics.execute(
Statistics.reported_carb_rate(tf, user.id)
)

const observedRate = observed.map((o) => {
return {
x: o.timestamp,
y: (o.observedCarbs / (o.interval ?? 1)) * (15 * 60),
}
})

const reportedRate = reported.map((o) => {
return {
x: o.timestamp,
y: o.rate * 15,
}
})

const domain = {
y: [
Math.min(
...observedRate.map((c) => c.y),
...reportedRate.map((c) => c.y)
) - 1,
Math.max(
...observedRate.map((c) => c.y),
...reportedRate.map((c) => c.y)
) + 1,
] as Tuple<number>,
x: [start, end] as Tuple<Date>,
}

return (
<GraphContainer>
<GraphTitle href="/carbs/list" className="flex justify-between">
<div>
<h2 className="font-semibold">Carbohydrate absorption rate</h2>
</div>
</GraphTitle>
<CarbsRateGraph
now={now}
observed={observedRate}
reported={reportedRate}
domain={domain}
/>
</GraphContainer>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use client'

import { addHours } from 'date-fns'
import { DomainTuple, Tuple, VictoryArea, VictoryLine } from 'victory'

import { GraphContent } from '../graph-container'

interface Props {
now: Date
data: {
x: Date
y: number
}[]
domain: {
x: DomainTuple
y: DomainTuple
}
}

export const CarbohydratesOnBoardGraph = ({ now, data, domain }: Props) => {
const initialZoomDomain = {
x: [addHours(now, -6), addHours(now, 1)] as Tuple<Date>,
}

return (
<GraphContent
initialZoomDomain={initialZoomDomain}
domain={domain}
now={now}
>
<VictoryLine
style={{
data: {
strokeDasharray: '2 2',
strokeWidth: 1,
stroke: '#c43a31',
},
}}
data={[
{ x: now, y: -5000 },
{ x: now, y: 5000 },
]}
/>
<VictoryArea
style={{
/* tailwind green-700 */
data: { fill: '#15803d88' },
}}
interpolation="stepAfter"
data={data}
/>
</GraphContent>
)
}
65 changes: 65 additions & 0 deletions gluwave/src/components/carbohydrates-on-board/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { validateRequest } from '@/auth'
import { Statistics } from '@/lib/sql_utils'
import { addHours } from 'date-fns'
import { redirect } from 'next/navigation'

import { GraphContainer, GraphTitle } from '../graph-container'
import { CarbohydratesOnBoardGraph } from './carbohydrates-on-board-graph'

export const CarbohydratesOnBoard = async () => {
const { user } = await validateRequest()
if (!user) {
redirect('/login')
}
const now = new Date()
const start = addHours(now, -8)
const end = addHours(now, 0.2)
const tf = Statistics.range_timeframe(start, end)
const carbs_on_board = await Statistics.execute(
Statistics.observed_carbs_on_board(
tf,
user.id,
user.carbohydrateRatio,
user.correctionRatio
)
)

const current = carbs_on_board.find(
(d) => Math.abs(d.timestamp.getTime() - now.getTime()) < 1000 * 60 * 1
)

return (
<GraphContainer>
<GraphTitle href="/carbs/list" className="flex justify-between">
<div>
<h2 className="font-semibold">Carbohydrates on board</h2>
<span className="text-xs">
Current{' '}
{current?.observed_carbs_on_board.toLocaleString([], {
maximumFractionDigits: 0,
})}{' '}
g
</span>
</div>
</GraphTitle>
<CarbohydratesOnBoardGraph
domain={{
x: [start, end],
y: [
0,
Math.max(
...carbs_on_board.map((d) => d.observed_carbs_on_board + 10)
),
],
}}
now={now}
data={carbs_on_board.map((d) => {
return {
x: d.timestamp,
y: d.observed_carbs_on_board,
}
})}
/>
</GraphContainer>
)
}
75 changes: 0 additions & 75 deletions gluwave/src/components/carbs-on-board/carbs-on-board-content.tsx

This file was deleted.

Loading

0 comments on commit 1e3864f

Please sign in to comment.