From 068258bdc79184dae8973519d1e39c58c9697650 Mon Sep 17 00:00:00 2001 From: Phil Stubbs Date: Tue, 24 Sep 2024 19:21:01 -0500 Subject: [PATCH] cleanup --- components/app-logo/AppLogo.stories.tsx | 2 +- components/auth/Auth.stories.tsx | 2 +- components/avatar/Avatar.stories.tsx | 2 +- .../charts/chart-card/ChartCard.stories.tsx | 27 +++ .../charts/chart-card/ChartCard.test.tsx | 20 +++ components/charts/chart-card/ChartCard.tsx | 35 ++++ .../DistanceComparisonChart.stories.tsx | 2 +- .../DistanceComparisonChart.tsx | 66 +++---- .../PerformanceOverTimeChart.tsx | 161 ++++++++---------- .../RaceDistributionByCityChart.tsx | 114 ++++++------- components/no-results/NoResults.stories.tsx | 2 +- components/no-results/NoResults.tsx | 8 +- 12 files changed, 244 insertions(+), 197 deletions(-) create mode 100644 components/charts/chart-card/ChartCard.stories.tsx create mode 100644 components/charts/chart-card/ChartCard.test.tsx create mode 100644 components/charts/chart-card/ChartCard.tsx diff --git a/components/app-logo/AppLogo.stories.tsx b/components/app-logo/AppLogo.stories.tsx index 6135141..1c6b605 100644 --- a/components/app-logo/AppLogo.stories.tsx +++ b/components/app-logo/AppLogo.stories.tsx @@ -24,7 +24,7 @@ export const Small: Story = { }, }; -export const DarkBackground: Story = { +export const WithLightBackground: Story = { args: { backgroundColor: "#fff", }, diff --git a/components/auth/Auth.stories.tsx b/components/auth/Auth.stories.tsx index 40783e3..aa587fb 100644 --- a/components/auth/Auth.stories.tsx +++ b/components/auth/Auth.stories.tsx @@ -3,7 +3,7 @@ import type { Meta, StoryObj } from "@storybook/react"; import { Auth } from "./Auth"; /** - * The Auth component provides a user interface for authentication. It displays available sign-in options + * The `Auth` component provides a user interface for authentication. It displays available sign-in options * from different authentication providers, allowing users to log in or create an account. */ const meta = { diff --git a/components/avatar/Avatar.stories.tsx b/components/avatar/Avatar.stories.tsx index cc8b268..0990681 100644 --- a/components/avatar/Avatar.stories.tsx +++ b/components/avatar/Avatar.stories.tsx @@ -3,7 +3,7 @@ import type { Meta, StoryObj } from "@storybook/react"; import { Avatar } from "./Avatar"; /** - * The Avatar component is used to display a user's profile image. + * The `Avatar` component is used to display a user's profile image. * If no image is provided, it falls back to displaying the initials of the user’s name. */ const meta = { diff --git a/components/charts/chart-card/ChartCard.stories.tsx b/components/charts/chart-card/ChartCard.stories.tsx new file mode 100644 index 0000000..882c670 --- /dev/null +++ b/components/charts/chart-card/ChartCard.stories.tsx @@ -0,0 +1,27 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { ChartCard } from "./ChartCard"; + +/** + * The `ChartCard` component is a flexible card layout designed to display chart-related information. + * It features a title, description, and a content area where charts or other visualizations can be placed. + * This component can be used as a container for any kind of data representation, making it a versatile + * choice for dashboards or analytics pages. + */ +const meta = { + component: ChartCard, + tags: ["autodocs"], + title: "Components/Charts/Chart Card", +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Basic: Story = { + args: { + children: "Chart Content", + description: + "Compare your average times (HH:MM:SS) across different race distances", + title: "Average Time By Distance", + }, +}; diff --git a/components/charts/chart-card/ChartCard.test.tsx b/components/charts/chart-card/ChartCard.test.tsx new file mode 100644 index 0000000..268be78 --- /dev/null +++ b/components/charts/chart-card/ChartCard.test.tsx @@ -0,0 +1,20 @@ +import { describe, expect, test } from "vitest"; +import { render, screen } from "@testing-library/react"; +import { ChartCard } from "./ChartCard"; +import { ComponentProps } from "react"; + +describe("ChartCard", () => { + const defaultProps: ComponentProps = { + children: "chart children", + description: "chart description", + title: "chart title", + }; + + test("should render with default props", () => { + render(); + + expect(screen.getByText(defaultProps.description)).toBeInTheDocument(); + expect(screen.getByText(defaultProps.title)).toBeInTheDocument(); + expect(screen.getByText("chart children")).toBeInTheDocument(); + }); +}); diff --git a/components/charts/chart-card/ChartCard.tsx b/components/charts/chart-card/ChartCard.tsx new file mode 100644 index 0000000..e4b79a5 --- /dev/null +++ b/components/charts/chart-card/ChartCard.tsx @@ -0,0 +1,35 @@ +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { PropsWithChildren, ReactNode } from "react"; + +interface IProps { + /** + * The content of the card, often used to display charts, tables, or other visual elements. + */ + children: ReactNode; + /** + * A brief explanation or context for the chart or data. + */ + description: string; + /** + * The main heading of the card, typically used to describe the chart or data displayed. + */ + title: string; +} + +export const ChartCard = (props: PropsWithChildren) => { + return ( + + + {props.title} + {props.description} + + {props.children} + + ); +}; diff --git a/components/charts/distance-comparison-chart/DistanceComparisonChart.stories.tsx b/components/charts/distance-comparison-chart/DistanceComparisonChart.stories.tsx index dbf7ebf..23a62a5 100644 --- a/components/charts/distance-comparison-chart/DistanceComparisonChart.stories.tsx +++ b/components/charts/distance-comparison-chart/DistanceComparisonChart.stories.tsx @@ -5,7 +5,7 @@ import { IDistanceComparisonChartData } from "./DistanceComparisonChart.types"; /** * The `DistanceComparisonChart` component is a bar chart that visualizes the average time taken - * (in minutes) across different race distances. It's built using the `recharts` library and styled + * across different race distances. It's built using the `recharts` library and styled * within a card layout, making it suitable for dashboards or performance tracking interfaces. */ const meta = { diff --git a/components/charts/distance-comparison-chart/DistanceComparisonChart.tsx b/components/charts/distance-comparison-chart/DistanceComparisonChart.tsx index fbb0e7f..b6f811a 100644 --- a/components/charts/distance-comparison-chart/DistanceComparisonChart.tsx +++ b/components/charts/distance-comparison-chart/DistanceComparisonChart.tsx @@ -1,14 +1,6 @@ "use client"; import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts"; - -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; import { ChartConfig, ChartContainer, @@ -17,8 +9,9 @@ import { ChartTooltip, ChartTooltipContent, } from "@/components/ui/chart"; -import { IDistanceComparisonChartData } from "./DistanceComparisonChart.types"; +import { IDistanceComparisonChartData } from "@/components/charts/distance-comparison-chart/DistanceComparisonChart.types"; import { minutesToTime } from "@/utils/timeToMinutes"; +import { ChartCard } from "@/components/charts/chart-card/ChartCard"; const chartConfig = { averageTime: { @@ -29,41 +22,36 @@ const chartConfig = { interface IProps { /** - * An array of data objects where each object contains `distance` (race distance) and `averageTime` (time in minutes). + * An array of data objects where each object contains `distance` (race distance) and `averageTime`. */ distanceComparisonData: IDistanceComparisonChartData[]; } export const DistanceComparisonChart = (props: IProps) => { return ( - - - Average Time By Distance - - Compare your average times (HH:MM:SS) across different race distances - - - - - - - - minutesToTime(value)} /> - } - formatter={(value) => minutesToTime(Number(value))} - /> - } /> - - - - - + + + + + + minutesToTime(value)} /> + } + formatter={(value) => minutesToTime(Number(value))} + /> + } /> + + + + ); }; diff --git a/components/charts/performance-over-time-chart/PerformanceOverTimeChart.tsx b/components/charts/performance-over-time-chart/PerformanceOverTimeChart.tsx index 8d82515..3b41c70 100644 --- a/components/charts/performance-over-time-chart/PerformanceOverTimeChart.tsx +++ b/components/charts/performance-over-time-chart/PerformanceOverTimeChart.tsx @@ -1,14 +1,6 @@ "use client"; import { CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts"; - -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; import { ChartConfig, ChartContainer, @@ -17,7 +9,7 @@ import { ChartTooltip, ChartTooltipContent, } from "@/components/ui/chart"; -import { IPerformanceOverTimeChartData } from "./PerformanceOverTimeChart.types"; +import { IPerformanceOverTimeChartData } from "@/components/charts/performance-over-time-chart/PerformanceOverTimeChart.types"; import { Select, SelectContent, @@ -27,6 +19,7 @@ import { } from "@/components/ui/select"; import { useEffect, useState } from "react"; import { minutesToTime } from "@/utils/timeToMinutes"; +import { ChartCard } from "@/components/charts/chart-card/ChartCard"; const chartConfig = { time: { @@ -62,86 +55,76 @@ export const PerformanceOverTimeChart = (props: IProps) => { }, [selectedDistance, props.performanceData]); return ( - - - {selectedDistance} Performance Over Time - - Track your {selectedDistance} race times throughout the year - - - -
- -
- - +
+ +
+ + + + { + const date = new Date(value); + return date.toLocaleDateString("en-US", { + month: "short", + day: "numeric", + year: "numeric", + }); }} - > - - { - const date = new Date(value); - return date.toLocaleDateString("en-US", { - month: "short", - day: "numeric", - year: "numeric", - }); - }} - /> - minutesToTime(value)} - /> - { - return new Date(value).toLocaleDateString("en-US", { - month: "short", - day: "numeric", - year: "numeric", - }); - }} - /> - } - formatter={(value) => minutesToTime(Number(value))} - /> - } /> - - - -
-
+ /> + minutesToTime(value)} + /> + { + return new Date(value).toLocaleDateString("en-US", { + month: "short", + day: "numeric", + year: "numeric", + }); + }} + /> + } + formatter={(value) => minutesToTime(Number(value))} + /> + } /> + + + +
); }; diff --git a/components/charts/race-distribution-by-city-chart/RaceDistributionByCityChart.tsx b/components/charts/race-distribution-by-city-chart/RaceDistributionByCityChart.tsx index 043eb2e..dd2e993 100644 --- a/components/charts/race-distribution-by-city-chart/RaceDistributionByCityChart.tsx +++ b/components/charts/race-distribution-by-city-chart/RaceDistributionByCityChart.tsx @@ -2,21 +2,14 @@ import * as React from "react"; import { Label, Pie, PieChart } from "recharts"; - -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, } from "@/components/ui/chart"; -import { IRaceDistributionByCityChartData } from "./RaceDistributionByCityChart.types"; +import { IRaceDistributionByCityChartData } from "@/components/charts/race-distribution-by-city-chart/RaceDistributionByCityChart.types"; +import { ChartCard } from "@/components/charts/chart-card/ChartCard"; interface IProps { /** @@ -33,61 +26,58 @@ const chartConfig = { export const RaceDistributionByCityChart = (props: IProps) => { return ( - - - Race Distribution By City - See where you've raced the most - - - - - } - /> - - - + {props.raceDistributionData.length} + + + Total Cities + + + ); + } + }} + /> + + + + ); }; diff --git a/components/no-results/NoResults.stories.tsx b/components/no-results/NoResults.stories.tsx index c4ccdaf..a8fdf93 100644 --- a/components/no-results/NoResults.stories.tsx +++ b/components/no-results/NoResults.stories.tsx @@ -51,7 +51,7 @@ export const StatsTab: Story = { args: { Icon: BarChartIcon, description: "Add some race results to see your performance statistics.", - tab: Tab.Results, + tab: Tab.Stats, title: "No Statistics Available", }, }; diff --git a/components/no-results/NoResults.tsx b/components/no-results/NoResults.tsx index 8a08f02..2a465b4 100644 --- a/components/no-results/NoResults.tsx +++ b/components/no-results/NoResults.tsx @@ -13,9 +13,9 @@ interface IProps { // eslint-disable-next-line Icon: ComponentType; /** - * Indicates which tab is active; can be either `Tab.Results` or `Tab.Gallery`. + * Indicates which tab is active. */ - tab: Tab.Results | Tab.Gallery | Tab.Settings; + tab: Tab.Results | Tab.Gallery | Tab.Settings | Tab.Stats; /** * The title or heading for the no results message. */ @@ -32,6 +32,7 @@ export const NoResults = (props: IProps) => { "text-center py-10 rounded-lg w-full": true, "bg-blue-50": props.tab === Tab.Results || props.tab === Tab.Settings, "bg-pink-50": props.tab === Tab.Gallery, + "bg-purple-50": props.tab === Tab.Stats, })} > { "text-blue-300": props.tab === Tab.Results || props.tab === Tab.Settings, "text-pink-300": props.tab === Tab.Gallery, + "text-purple-300": props.tab === Tab.Stats, })} />

{ "text-blue-700": props.tab === Tab.Results || props.tab === Tab.Settings, "text-pink-700": props.tab === Tab.Gallery, + "text-purple-700": props.tab === Tab.Stats, })} > {props.title} @@ -57,6 +60,7 @@ export const NoResults = (props: IProps) => { "text-blue-600": props.tab === Tab.Results || props.tab === Tab.Settings, "text-pink-600": props.tab === Tab.Gallery, + "text-purple-700": props.tab === Tab.Stats, })} > {props.description}