135 lines
3.2 KiB
TypeScript
135 lines
3.2 KiB
TypeScript
import React from "react";
|
|
import { View, Text, StyleSheet, Dimensions } from "react-native";
|
|
import { LineChart } from "react-native-chart-kit";
|
|
import { useTheme } from "../contexts/ThemeContext";
|
|
import type { WeeklyTrendData } from "../api/types";
|
|
|
|
interface WeeklyProgressChartProps {
|
|
weeklyData: WeeklyTrendData[];
|
|
title?: string;
|
|
}
|
|
|
|
export function WeeklyProgressChart({
|
|
weeklyData,
|
|
title = "Weekly Progress",
|
|
}: WeeklyProgressChartProps) {
|
|
const { colors, typography } = useTheme();
|
|
const screenWidth = Dimensions.get("window").width;
|
|
|
|
const labels = weeklyData.map((week: WeeklyTrendData) => week.weekLabel);
|
|
const checkInsData = weeklyData.map((week: WeeklyTrendData) => week.checkIns);
|
|
const goalsCompletedData = weeklyData.map(
|
|
(week: WeeklyTrendData) => week.goalsCompleted,
|
|
);
|
|
|
|
const chartConfig = {
|
|
backgroundColor: colors.surface,
|
|
backgroundGradientFrom: colors.surface,
|
|
backgroundGradientTo: colors.surface,
|
|
decimalPlaces: 0,
|
|
color: (opacity = 1) => `rgba(0, 102, 255, ${opacity})`,
|
|
labelColor: (opacity = 1) => colors.textTertiary,
|
|
propsForDots: {
|
|
r: "5",
|
|
strokeWidth: "2",
|
|
stroke: colors.primary,
|
|
},
|
|
};
|
|
|
|
const data = {
|
|
labels,
|
|
datasets: [
|
|
{
|
|
data: checkInsData,
|
|
color: () => colors.primary,
|
|
strokeWidth: 3,
|
|
},
|
|
{
|
|
data: goalsCompletedData,
|
|
color: () => colors.success,
|
|
strokeWidth: 3,
|
|
},
|
|
],
|
|
legend: ["Check-ins", "Goals"],
|
|
};
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
{title && (
|
|
<Text
|
|
style={[
|
|
typography.h4,
|
|
{ color: colors.textPrimary, marginBottom: 16 },
|
|
]}
|
|
>
|
|
{title}
|
|
</Text>
|
|
)}
|
|
<View style={styles.chartContainer}>
|
|
<LineChart
|
|
data={data}
|
|
width={screenWidth - 80}
|
|
height={180}
|
|
chartConfig={chartConfig}
|
|
bezier
|
|
style={styles.chart}
|
|
withInnerLines={true}
|
|
withOuterLines={false}
|
|
withVerticalLabels={true}
|
|
withHorizontalLabels={true}
|
|
fromZero={true}
|
|
/>
|
|
</View>
|
|
<View style={styles.legend}>
|
|
<View style={styles.legendItem}>
|
|
<View
|
|
style={[styles.legendDot, { backgroundColor: colors.primary }]}
|
|
/>
|
|
<Text style={[typography.caption, { color: colors.textSecondary }]}>
|
|
Check-ins
|
|
</Text>
|
|
</View>
|
|
<View style={styles.legendItem}>
|
|
<View
|
|
style={[styles.legendDot, { backgroundColor: colors.success }]}
|
|
/>
|
|
<Text style={[typography.caption, { color: colors.textSecondary }]}>
|
|
Goals
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
borderRadius: 16,
|
|
padding: 4,
|
|
},
|
|
chartContainer: {
|
|
alignItems: "center",
|
|
marginBottom: 12,
|
|
},
|
|
chart: {
|
|
marginVertical: 8,
|
|
borderRadius: 12,
|
|
},
|
|
legend: {
|
|
flexDirection: "row",
|
|
justifyContent: "center",
|
|
gap: 24,
|
|
paddingTop: 8,
|
|
},
|
|
legendItem: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
gap: 8,
|
|
},
|
|
legendDot: {
|
|
width: 10,
|
|
height: 10,
|
|
borderRadius: 5,
|
|
},
|
|
});
|