From 2f33b7fd862561f0a85ff12ff1d0328a799489d9 Mon Sep 17 00:00:00 2001 From: Loewy Date: Thu, 15 Feb 2024 11:44:15 -0800 Subject: [PATCH] bargraph now can be called from chart container, add chartType to chartcomponents, conditional xaxis props, remove bar graph test and test from chart-container --- src/component/charts/bar-graph/bar-graph.tsx | 146 ++++-------------- .../charts/container/chart-container.tsx | 26 +++- src/component/charts/graph-types.ts | 23 ++- .../charts/line-graph/line-graph.tsx | 6 +- test/component/bar-graph.test.tsx | 20 --- test/component/chart-container.test.tsx | 16 +- 6 files changed, 88 insertions(+), 149 deletions(-) delete mode 100644 test/component/bar-graph.test.tsx diff --git a/src/component/charts/bar-graph/bar-graph.tsx b/src/component/charts/bar-graph/bar-graph.tsx index f0cd6ff..deffe93 100644 --- a/src/component/charts/bar-graph/bar-graph.tsx +++ b/src/component/charts/bar-graph/bar-graph.tsx @@ -1,137 +1,45 @@ -import * as scale from "d3-scale"; import React from "react"; -import { View } from "react-native"; -import { BarChart, XAxis, YAxis } from "react-native-svg-charts"; +import { BarChart } from "react-native-svg-charts"; -import { GraphData, YAxisProps } from "../graph-types"; -import { useGraphData } from "../use-graph-data"; +import { CommonProps, withChartType } from "../graph-types"; -import ChartLabel from "../chart-label/chart-label"; import { graphStyles } from "../chart-styles"; -import ChartView from "../chart-view"; import { CustomBars } from "../custom-bars"; import { CustomGrid } from "../custom-grid"; -interface Props { - data: GraphData; - height?: number; - spacingInner?: number; - spacingOuter?: number; - contentInset?: { top: number; bottom: number }; - min?: number; - numberOfTicks?: number; - barColors?: Array; - useCommonScale?: boolean; - yAxisProps?: YAxisProps; - testID?: string; -} - // TODO: #43 #31 separate PR will update useGraphData to take into account useCommonScale // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars -export const BarGraph: React.FC = ({ - data, - useCommonScale = false, - testID, - ...props -}) => { - if (!data) { - return null; - } // TODO:#38 +const BarGraphBase: React.FC = ({ ...chartComponentProps }) => { const { - xValues, yData, - yAxisRightLabels, - yAxisLeftLabels, - defaultProps: { - height, - spacingInner, - spacingOuter, - contentInset, - min, - numberOfTicks, - barColors, - yAxisProps: { - maxLeftYAxisValue, - maxRightYAxisValue, - formatRightYAxisLabel, - formatLeftYAxisLabel, - }, - }, - // Proper error/loading handling from useQueryHandler can work with this rule #38 - // eslint-disable-next-line react-hooks/rules-of-hooks - } = useGraphData(data, { includeColors: false, ...props }); - - // TODO: Will come from BE & destructured / color assigned in useGraphData - const yLabels = [ - { displayName: "Shots Taken", axis: "LEFT" as "LEFT", color: barColors[0] }, - { - displayName: "Make Percentage", - axis: "RIGHT" as "RIGHT", - color: barColors[1], - }, - ]; - const title = "Shots Taken / Make Percentage by Cut Angle"; + xValues, + min, + contentInset, + numberOfTicks, + spacingInner, + spacingOuter, + barColors, + } = chartComponentProps; return ( - - - + (item as unknown as { value: number }).value} + contentInset={contentInset} + spacingInner={spacingInner} + spacingOuter={spacingOuter} > - - - - - (item as unknown as { value: number }).value - } - contentInset={contentInset} - spacingInner={spacingInner} - spacingOuter={spacingOuter} - > - - - - index)} - formatLabel={(_, index) => xValues[index]} - style={graphStyles.xAxisMarginTop} - svg={graphStyles.xAxisFontStyle} - scale={scale.scaleBand} - /> - - - - - + + + + ); }; +const BarGraph = withChartType(BarGraphBase, "bar"); + export default BarGraph; diff --git a/src/component/charts/container/chart-container.tsx b/src/component/charts/container/chart-container.tsx index 59c393c..94aa5f4 100644 --- a/src/component/charts/container/chart-container.tsx +++ b/src/component/charts/container/chart-container.tsx @@ -1,3 +1,4 @@ +import * as scale from "d3-scale"; import React from "react"; import { View } from "react-native"; import { XAxis, YAxis } from "react-native-svg-charts"; @@ -29,6 +30,9 @@ const ChartContainer: React.FC = ({ min, numberOfTicks, lineStrokeWidth, + spacingInner, + spacingOuter, + barColors, yAxisProps: { maxLeftYAxisValue, maxRightYAxisValue, @@ -38,9 +42,12 @@ const ChartContainer: React.FC = ({ }, // Proper error/loading handling from useQueryHandler can work with this rule #38 // eslint-disable-next-line react-hooks/rules-of-hooks - } = useGraphData(data, props); + } = useGraphData(data, { + includeColors: ChartComponent.chartType === "bar" ? false : true, + ...props, + }); - // TODO: This could be done by the hook since it already handles spreading props. + // TODO: #31 This could be done by the hook since it already handles spreading props. // Depending on if we want a context provider for Charts, that could be another way to handle it const chartComponentProps = { yData, @@ -49,6 +56,9 @@ const ChartContainer: React.FC = ({ min, contentInset, numberOfTicks, + spacingInner, + spacingOuter, + barColors, }; return ( @@ -69,13 +79,17 @@ const ChartContainer: React.FC = ({ index)} // TODO: update when useGraphHook returns explicit display values + data={xValues.map((_, index: number) => index)} // TODO: #31 update when useGraphHook returns explicit display values formatLabel={(_, index) => xValues[index]} style={[graphStyles.xAxisMarginTop]} svg={graphStyles.xAxisFontStyle} - numberOfTicks={numberOfTicks} // need a dynamic way of setting number of ticks - contentInset={graphStyles.horizontalInset} - // scale={scale.scaleBand} // Need to know the type of ChartComponent + {...(ChartComponent.chartType === "bar" && { + scale: scale.scaleBand, + })} + {...(ChartComponent.chartType === "line" && { + numberOfTicks: numberOfTicks, + contentInset: graphStyles.horizontalInset, + })} /> & { + chartType?: string; +}; + /** * Common properties for graph render components. * @@ -84,6 +89,22 @@ export interface CommonProps { * @property {React.ComponentType} ChartComponent - The graph component to render */ export interface ChartContainerProps extends CommonProps { - ChartComponent: React.ComponentType; + ChartComponent: ChartComponentWithStatic; data: GraphData; } + +/** + * Enhances a component with a `chartType` property. + * + * @param Component - The component to enhance. + * @param chartType - The type of chart. + * @returns The enhanced component. + */ +export function withChartType>( + Component: T, + chartType: string, +): T { + (Component as React.ComponentType & { chartType?: string }).chartType = + chartType; + return Component; +} diff --git a/src/component/charts/line-graph/line-graph.tsx b/src/component/charts/line-graph/line-graph.tsx index 011a970..44f7e58 100644 --- a/src/component/charts/line-graph/line-graph.tsx +++ b/src/component/charts/line-graph/line-graph.tsx @@ -3,11 +3,11 @@ import React from "react"; import { LineChart } from "react-native-svg-charts"; import { graphStyles } from "../chart-styles"; import { CustomGrid } from "../custom-grid"; -import { CommonProps } from "../graph-types"; +import { CommonProps, withChartType } from "../graph-types"; // TODO: #43 #31 separate PR will update useGraphData to take into account useCommonScale // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars -const LineGraph: React.FC = ({ ...chartComponentProps }) => { +const LineGraphBase: React.FC = ({ ...chartComponentProps }) => { const { yData, xValues, lineStrokeWidth, min, contentInset, numberOfTicks } = chartComponentProps; return ( @@ -29,4 +29,6 @@ const LineGraph: React.FC = ({ ...chartComponentProps }) => { ); }; +const LineGraph = withChartType(LineGraphBase, "line"); + export default LineGraph; diff --git a/test/component/bar-graph.test.tsx b/test/component/bar-graph.test.tsx deleted file mode 100644 index 5391154..0000000 --- a/test/component/bar-graph.test.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { render } from "@testing-library/react-native"; -import React from "react"; -import BarGraph from "../../src/component/charts/bar-graph/bar-graph"; -import { graph_data_two_measures } from "../mock/charts/mock-data"; - -describe("BarGraph Component Tests", () => { - it("renders correctly with data", () => { - const { getByTestId } = render( - , - ); - expect(getByTestId(`bar-graph-1`)).toBeTruthy(); - }); - - it("does not render without data", () => { - // Have to ts-ignore to test null data conditions - // @ts-ignore - const { queryByTestId } = render(); - expect(queryByTestId(`bar-graph-2`)).toBeNull(); - }); -}); diff --git a/test/component/chart-container.test.tsx b/test/component/chart-container.test.tsx index 3b62ef1..fd38f5f 100644 --- a/test/component/chart-container.test.tsx +++ b/test/component/chart-container.test.tsx @@ -1,8 +1,12 @@ import { render } from "@testing-library/react-native"; import React from "react"; +import BarGraph from "../../src/component/charts/bar-graph/bar-graph"; import ChartContainer from "../../src/component/charts/container/chart-container"; import LineGraph from "../../src/component/charts/line-graph/line-graph"; -import { line_chart_two_y_data } from "../mock/charts/mock-data"; +import { + graph_data_two_measures, + line_chart_two_y_data, +} from "../mock/charts/mock-data"; describe("ChartContainer Component Tests", () => { it("renders correctly with data -- line graph", () => { const { getByTestId } = render( @@ -14,6 +18,16 @@ describe("ChartContainer Component Tests", () => { ); expect(getByTestId(`chart-container-1`)).toBeTruthy(); }); + it("renders correctly with data -- bar graph", () => { + const { getByTestId } = render( + , + ); + expect(getByTestId(`chart-container-1`)).toBeTruthy(); + }); it("does not render without data props", () => { // Have to ts-ignore to test null data conditions