Skip to content

Commit

Permalink
feat(mobile): refactor burndown chart and add tooltip (#343)
Browse files Browse the repository at this point in the history
  • Loading branch information
bkdev98 authored Sep 21, 2024
1 parent 256e0c8 commit eeb7b18
Show file tree
Hide file tree
Showing 14 changed files with 472 additions and 315 deletions.
4 changes: 2 additions & 2 deletions apps/mobile/app/(app)/(tabs)/budgets.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BudgetItem } from '@/components/budget/budget-item'
import { BudgetStatistic } from '@/components/budget/budget-statistic'
import { BurndownChart } from '@/components/budget/burndown-chart'
import { BurndownChart } from '@/components/common/burndown-chart'
import { FooterGradient } from '@/components/common/footer-gradient'
import { Button } from '@/components/ui/button'
// import { Toolbar } from '@/components/common/toolbar'
Expand Down Expand Up @@ -200,7 +200,7 @@ export default function BudgetsScreen() {
return (
<View className="flex-1 bg-background">
<View
className="absolute w-full"
className="absolute z-50 w-full"
onLayout={(ev) => {
if (headerHeight.value === ev.nativeEvent.layout.height) {
return
Expand Down
4 changes: 2 additions & 2 deletions apps/mobile/app/(app)/budget/[budgetId]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BudgetStatistic } from '@/components/budget/budget-statistic'
import { BurndownChart } from '@/components/budget/burndown-chart'
import { PeriodControl } from '@/components/budget/period-control'
import { AmountFormat } from '@/components/common/amount-format'
import { BurndownChart } from '@/components/common/burndown-chart'
import { FooterGradient } from '@/components/common/footer-gradient'
import { TransactionItem } from '@/components/transaction/transaction-item'
import { Button } from '@/components/ui/button'
Expand Down Expand Up @@ -205,7 +205,7 @@ export default function BudgetDetailScreen() {
onChange={setCurrentPeriodIndex}
/>
<View
className="absolute top-12 w-full"
className="absolute top-12 z-50 w-full"
onLayout={(ev) => {
if (headerHeight.value === ev.nativeEvent.layout.height) {
return
Expand Down
6 changes: 0 additions & 6 deletions apps/mobile/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ import { isRunningInExpoGo } from 'expo'

import { tokenCache } from '@/lib/cache'
import { ClerkLoaded, ClerkProvider } from '@clerk/clerk-expo'
import {
SpaceMono_400Regular,
SpaceMono_700Bold,
} from '@expo-google-fonts/space-mono'
import { useFonts } from 'expo-font'
import * as Notifications from 'expo-notifications'
import { SplashScreen, Stack, useNavigationContainerRef } from 'expo-router'
Expand Down Expand Up @@ -116,8 +112,6 @@ function RootLayout() {
useWarmUpBrowser()
const { colorScheme } = useColorScheme()
const [fontsLoaded] = useFonts({
SpaceMono_400Regular,
SpaceMono_700Bold,
'Haskoy-Regular': require('../assets/fonts/Haskoy-Regular.ttf'),
'Haskoy-Medium': require('../assets/fonts/Haskoy-Medium.ttf'),
'Haskoy-SemiBold': require('../assets/fonts/Haskoy-SemiBold.ttf'),
Expand Down
227 changes: 0 additions & 227 deletions apps/mobile/components/budget/burndown-chart.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { useColorPalette } from '@/hooks/use-color-palette'
import { useDefaultCurrency } from '@/stores/user-settings/hooks'
import { nFormatter } from '@6pm/currency'
import { dayjsExtended } from '@6pm/utilities'
import { useState } from 'react'
import { runOnJS, useDerivedValue } from 'react-native-reanimated'
import type { ChartPressState } from 'victory-native'

import {
Circle,
Line as SkiaLine,
Text as SkiaText,
useFont,
vec,
} from '@shopify/react-native-skia'
import { DiffBadge } from './diff-badge'

type ActiveValueIndicatorProps = {
bottom: number
top: number
pressState: ChartPressState<{
x: number
y: {
average: number
amount: number
accumulated: number
}
}>
}

export function ActiveValueIndicator({
bottom,
top,
pressState,
}: ActiveValueIndicatorProps) {
const { getColor } = useColorPalette()
const tooltipFont = useFont(
require('../../../assets/fonts/Haskoy-Medium.ttf'),
12,
)
const x = pressState.x.position
const y = pressState.y.accumulated.position
const activeValue = pressState.y.amount.value
const date = pressState.x.value
const start = useDerivedValue(() => vec(x.value, bottom - 12))
const end = useDerivedValue(() => vec(x.value, top + 1.5 * 12))
const defaultCurrency = useDefaultCurrency()
const [value, setValue] = useState<string>('')

function formatDate(value: number, date: number) {
const result = `
${nFormatter(value, 0)} ${defaultCurrency} on ${dayjsExtended(
dayjsExtended().set('date', date),
).format('MMM D')}
`
setValue(result)
}
const activeValueDisplay = useDerivedValue(() => {
runOnJS(formatDate)(activeValue.value, date.value)
return value!
})
const activeValueWidth = useDerivedValue(
() =>
tooltipFont
?.getGlyphWidths?.(tooltipFont.getGlyphIDs(activeValueDisplay.value))
.reduce((sum, value) => sum + value, 0) || 0,
)
const activeValueX = useDerivedValue(() => {
if (date.value < 5) {
return date.value
}
if (date.value > 26) {
return x.value - activeValueWidth.value
}
return x.value - activeValueWidth.value / 2
})

const diffAmount = Math.round(
(pressState.y.average.value.value || 0) -
(pressState.y.accumulated.value.value || 0),
)

return (
<>
<SkiaLine
p1={start}
p2={end}
opacity={0.3}
color={getColor('--muted-foreground')}
strokeWidth={1}
/>
<Circle cx={x} cy={y} r={7} color={getColor('--foreground')} />
<Circle cx={x} cy={y} r={4.5} color={getColor('--muted')} />
<SkiaText
color={getColor('--muted-foreground')}
font={tooltipFont}
text={activeValueDisplay}
x={activeValueX}
y={top + 12}
/>
<DiffBadge
anchorDay={date.value}
diffAmount={diffAmount}
point={{ x: x.value, y: y.value }}
/>
</>
)
}
Loading

0 comments on commit eeb7b18

Please sign in to comment.