From 2276605e6df8e00db4a6a8e87661bd0b13b2988c Mon Sep 17 00:00:00 2001 From: Ivan Malison Date: Sat, 3 Feb 2024 20:23:31 -0700 Subject: [PATCH] Actually respect prettier configuration --- .gitea/workflows/tests.yaml | 2 + .prettierignore | 4 + app.json | 84 +++--- component/charts/bar-graph/bar-graph.tsx | 225 +++++++------- component/charts/bar.tsx | 78 ++--- component/charts/chart-label/chart-label.tsx | 60 ++-- component/charts/chart-styles.ts | 78 ++--- component/charts/chart-view.tsx | 20 +- component/charts/custom-bar-utils.ts | 92 +++--- component/charts/custom-bars.tsx | 85 +++--- component/charts/custom-grid.tsx | 135 +++++---- component/charts/graph-config.ts | 20 +- component/charts/graph-types.ts | 94 +++--- component/charts/graph-utils.tsx | 73 +++-- component/charts/line-graph/line-graph.tsx | 177 ++++++----- component/charts/use-graph-data.ts | 105 ++++--- component/video/camera.tsx | 300 ++++++++++--------- component/video/constants.ts | 37 +-- component/video/is-foreground.tsx | 24 +- google-services.json | 92 +++--- index.js | 4 +- mock/charts/mock-data.ts | 108 +++---- navigation/app-navigator.tsx | 63 ++-- navigation/tab-navigator.tsx | 78 ++--- screens/login.tsx | 204 ++++++------- screens/session.tsx | 19 +- screens/video-stack/record.tsx | 263 ++++++++-------- screens/video-stack/styles.ts | 110 +++---- styles.ts | 36 +-- test/component/bar-graph.test.tsx | 34 +-- test/component/chart-label.test.tsx | 62 ++-- test/component/chart-view.test.tsx | 52 ++-- test/component/custom-bars.test.tsx | 148 ++++----- test/component/line-graph.test.tsx | 35 ++- test/component/use-graph-data.test.tsx | 114 +++---- tsconfig.json | 6 +- yarn.lock | 5 + 37 files changed, 1629 insertions(+), 1497 deletions(-) create mode 100644 .prettierignore diff --git a/.gitea/workflows/tests.yaml b/.gitea/workflows/tests.yaml index 4461b52..4682b3e 100644 --- a/.gitea/workflows/tests.yaml +++ b/.gitea/workflows/tests.yaml @@ -21,5 +21,7 @@ jobs: run: nix develop --impure --command bash -c 'export HOME=$PWD; yarn run lint' - name: typecheck run: nix develop --impure --command bash -c 'export HOME=$PWD; yarn tsc --noEmit' + - name: prettier + run: nix develop --impure --command bash -c 'export HOME=$PWD; prettier . --check' - name: test run: nix develop --impure --command bash -c 'export HOME=$PWD; yarn run test --no-watchman' diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..18b5678 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +/android +/ios +/react-native-vision-camera +flake.lock diff --git a/app.json b/app.json index 7766581..8029e3a 100644 --- a/app.json +++ b/app.json @@ -1,44 +1,44 @@ { - "expo": { - "name": "Railbird", - "slug": "railbird-rn", - "version": "1.0.0", - "orientation": "portrait", - "icon": "./assets/icon.png", - "userInterfaceStyle": "light", - "splash": { - "image": "./assets/splash.png", - "resizeMode": "contain", - "backgroundColor": "#ffffff" - }, - "assetBundlePatterns": ["**/*"], - "plugins": [ - "@react-native-firebase/app", - "@react-native-firebase/auth", - [ - "expo-build-properties", - { - "ios": { - "useFrameworks": "static" - } - } - ] - ], - "ios": { - "supportsTablet": true, - "bundleIdentifier": "ai.railbird.railbird", - "googleServicesFile": "./GoogleService-Info.plist" - }, - "android": { - "adaptiveIcon": { - "foregroundImage": "./assets/adaptive-icon.png", - "backgroundColor": "#ffffff" - }, - "package": "android.railbird.app", - "googleServicesFile": "./google-services.json" - }, - "web": { - "favicon": "./assets/favicon.png" - } - } + "expo": { + "name": "Railbird", + "slug": "railbird-rn", + "version": "1.0.0", + "orientation": "portrait", + "icon": "./assets/icon.png", + "userInterfaceStyle": "light", + "splash": { + "image": "./assets/splash.png", + "resizeMode": "contain", + "backgroundColor": "#ffffff" + }, + "assetBundlePatterns": ["**/*"], + "plugins": [ + "@react-native-firebase/app", + "@react-native-firebase/auth", + [ + "expo-build-properties", + { + "ios": { + "useFrameworks": "static" + } + } + ] + ], + "ios": { + "supportsTablet": true, + "bundleIdentifier": "ai.railbird.railbird", + "googleServicesFile": "./GoogleService-Info.plist" + }, + "android": { + "adaptiveIcon": { + "foregroundImage": "./assets/adaptive-icon.png", + "backgroundColor": "#ffffff" + }, + "package": "android.railbird.app", + "googleServicesFile": "./google-services.json" + }, + "web": { + "favicon": "./assets/favicon.png" + } + } } diff --git a/component/charts/bar-graph/bar-graph.tsx b/component/charts/bar-graph/bar-graph.tsx index ff3bb51..2220273 100644 --- a/component/charts/bar-graph/bar-graph.tsx +++ b/component/charts/bar-graph/bar-graph.tsx @@ -1,116 +1,137 @@ -import React from 'react'; -import * as scale from 'd3-scale'; -import { View } from 'react-native'; -import { BarChart, XAxis, YAxis } from 'react-native-svg-charts'; +import React from "react"; +import * as scale from "d3-scale"; +import { View } from "react-native"; +import { BarChart, XAxis, YAxis } from "react-native-svg-charts"; -import { useGraphData } from '../use-graph-data'; -import { GraphData, YAxisProps } from '../graph-types'; +import { useGraphData } from "../use-graph-data"; +import { GraphData, YAxisProps } from "../graph-types"; -import { CustomBars } from '../custom-bars'; -import { CustomGrid } from '../custom-grid'; -import { graphStyles } from '../chart-styles'; -import ChartView from '../chart-view'; -import ChartLabel from '../chart-label/chart-label'; +import { CustomBars } from "../custom-bars"; +import { CustomGrid } from "../custom-grid"; +import { graphStyles } from "../chart-styles"; +import ChartView from "../chart-view"; +import ChartLabel from "../chart-label/chart-label"; 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; + 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: 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 { - 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}); +export const BarGraph: React.FC = ({ + data, + useCommonScale = false, + testID, + ...props +}) => { + if (!data) { + return null; + } // TODO:#38 + 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' + // 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"; - return ( - - - - + return ( + + + + - - (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} - /> - + + + (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} + /> + - - - - ); + + + + ); }; -export default BarGraph; \ No newline at end of file +export default BarGraph; diff --git a/component/charts/bar.tsx b/component/charts/bar.tsx index d2694bb..0bf286a 100644 --- a/component/charts/bar.tsx +++ b/component/charts/bar.tsx @@ -1,48 +1,48 @@ -import React from 'react'; -import { Path } from 'react-native-svg'; +import React from "react"; +import { Path } from "react-native-svg"; -import { calculateBarOrigin, drawBarPath } from './custom-bar-utils'; -import { ScaleBandType, ScaleLinearType, } from './graph-types'; +import { calculateBarOrigin, drawBarPath } from "./custom-bar-utils"; +import { ScaleBandType, ScaleLinearType } from "./graph-types"; interface BarProps { - scaleX: ScaleBandType; - scaleY: ScaleLinearType; - data: { value: number }; - barNumber: number; - index: number; - fill: string; - barWidth: number; - gap: number; - roundedRadius: number; + scaleX: ScaleBandType; + scaleY: ScaleLinearType; + data: { value: number }; + barNumber: number; + index: number; + fill: string; + barWidth: number; + gap: number; + roundedRadius: number; } export const Bar: React.FC = ({ - scaleX, - scaleY, - data, - barNumber, - index, - fill, - barWidth, - gap, - roundedRadius + scaleX, + scaleY, + data, + barNumber, + index, + fill, + barWidth, + gap, + roundedRadius, }) => { - const { xOrigin, yOrigin, height } = calculateBarOrigin({ - scaleX, - scaleY, - index, - data, - barNumber, - barWidth, - gap - }); + const { xOrigin, yOrigin, height } = calculateBarOrigin({ + scaleX, + scaleY, + index, + data, + barNumber, + barWidth, + gap, + }); - return ( - - ); + return ( + + ); }; diff --git a/component/charts/chart-label/chart-label.tsx b/component/charts/chart-label/chart-label.tsx index 6f787f7..f2518cf 100644 --- a/component/charts/chart-label/chart-label.tsx +++ b/component/charts/chart-label/chart-label.tsx @@ -1,42 +1,44 @@ -import React from 'react'; -import { Text, View } from 'react-native'; +import React from "react"; +import { Text, View } from "react-native"; -import { chartLabel } from '../chart-styles'; +import { chartLabel } from "../chart-styles"; -type Axis = 'RIGHT' | 'LEFT' +type Axis = "RIGHT" | "LEFT"; interface YLabel { - axis: Axis; - displayName: string; - color: string; + axis: Axis; + displayName: string; + color: string; } type ChartLabelProps = { - title: string; - yLabels: Array; + title: string; + yLabels: Array; }; const renderLabels = (yLabels: Array) => { - return yLabels.map((label) => ( - - - - {label.displayName} - - - )); + return yLabels.map((label) => ( + + + + {label.displayName} + + + )); }; export default function ChartLabel({ title, yLabels }: ChartLabelProps) { - - return ( - - - {title} - - {renderLabels(yLabels)} - - ); -} \ No newline at end of file + return ( + + + {title} + + {renderLabels(yLabels)} + + ); +} diff --git a/component/charts/chart-styles.ts b/component/charts/chart-styles.ts index a924840..f26a9ac 100644 --- a/component/charts/chart-styles.ts +++ b/component/charts/chart-styles.ts @@ -1,46 +1,46 @@ -import { StyleSheet } from 'react-native'; +import { StyleSheet } from "react-native"; -import { colors, shadows } from '../../styles'; +import { colors, shadows } from "../../styles"; export const graphStyles = StyleSheet.create({ - container: { - backgroundColor: colors.panelWhite, - borderColor: 'black', - borderRadius: 5, - marginVertical: 10, - marginHorizontal: 15, - paddingTop: 15, - paddingHorizontal: 15, - ...shadows.standard - }, - rowContainer: { flexDirection: 'row', padding: 10 }, - flex: { flex: 1 }, - yAxisLeftPadding: { paddingRight: 3 }, - yAxisRightPadding: { paddingLeft: 3 }, - yAxisFontStyle: { fontSize: 10, fill: 'grey' }, - xAxisFontStyle: { fontSize: 12, fill: 'black' }, - xAxisMarginTop: { marginTop: -15 }, - horizontalInset: { right: 10, left: 10 }, + container: { + backgroundColor: colors.panelWhite, + borderColor: "black", + borderRadius: 5, + marginVertical: 10, + marginHorizontal: 15, + paddingTop: 15, + paddingHorizontal: 15, + ...shadows.standard, + }, + rowContainer: { flexDirection: "row", padding: 10 }, + flex: { flex: 1 }, + yAxisLeftPadding: { paddingRight: 3 }, + yAxisRightPadding: { paddingLeft: 3 }, + yAxisFontStyle: { fontSize: 10, fill: "grey" }, + xAxisFontStyle: { fontSize: 12, fill: "black" }, + xAxisMarginTop: { marginTop: -15 }, + horizontalInset: { right: 10, left: 10 }, }); export const chartLabel = StyleSheet.create({ - titleRow: { - flexDirection: 'row', - marginHorizontal: 10 - }, - titleText: { fontWeight: '500' }, - labelOuterRow: { - flexDirection: 'row', - flexWrap: 'wrap', - marginHorizontal: 10 - }, - labelInnerRow: { flexDirection: 'row', alignItems: 'center', marginTop: 5 }, - labelColorBox: { - height: 15, - width: 15, - borderRadius: 4, - marginRight: 2 - }, - labelTextMargin: { marginRight: 15 }, - labelText: { fontSize: 12 } + titleRow: { + flexDirection: "row", + marginHorizontal: 10, + }, + titleText: { fontWeight: "500" }, + labelOuterRow: { + flexDirection: "row", + flexWrap: "wrap", + marginHorizontal: 10, + }, + labelInnerRow: { flexDirection: "row", alignItems: "center", marginTop: 5 }, + labelColorBox: { + height: 15, + width: 15, + borderRadius: 4, + marginRight: 2, + }, + labelTextMargin: { marginRight: 15 }, + labelText: { fontSize: 12 }, }); diff --git a/component/charts/chart-view.tsx b/component/charts/chart-view.tsx index b0df597..6fd53da 100644 --- a/component/charts/chart-view.tsx +++ b/component/charts/chart-view.tsx @@ -1,16 +1,20 @@ -import React from 'react'; -import { StyleProp, View, ViewStyle } from 'react-native'; +import React from "react"; +import { StyleProp, View, ViewStyle } from "react-native"; -import { graphStyles } from './chart-styles'; +import { graphStyles } from "./chart-styles"; interface ChartViewProps { - style?: StyleProp; - children: React.ReactNode; - testID?: string; + style?: StyleProp; + children: React.ReactNode; + testID?: string; } const ChartView: React.FC = ({ children, style, testID }) => { - return {children}; + return ( + + {children} + + ); }; -export default ChartView; \ No newline at end of file +export default ChartView; diff --git a/component/charts/custom-bar-utils.ts b/component/charts/custom-bar-utils.ts index c5a22b9..58d6723 100644 --- a/component/charts/custom-bar-utils.ts +++ b/component/charts/custom-bar-utils.ts @@ -1,59 +1,63 @@ -import { path as d3 } from 'd3-path'; +import { path as d3 } from "d3-path"; -import { ScaleLinearType, ScaleBandType } from './graph-types'; +import { ScaleLinearType, ScaleBandType } from "./graph-types"; type BarCalculationProps = { - scaleX: ScaleBandType; - scaleY: ScaleLinearType; - data: { value: number }; - barNumber: number; - index: number; - barWidth: number; - gap: number; + scaleX: ScaleBandType; + scaleY: ScaleLinearType; + data: { value: number }; + barNumber: number; + index: number; + barWidth: number; + gap: number; }; export function calculateBarOrigin({ - scaleX, - scaleY, - barWidth, - data, - index, - barNumber, - gap + scaleX, + scaleY, + barWidth, + data, + index, + barNumber, + gap, }: BarCalculationProps): { xOrigin: number; yOrigin: number; height: number } { - const firstBar = barNumber === 0; - const xOrigin = scaleX(index) + (firstBar ? 0 : barWidth * barNumber + gap * barNumber); - const yOrigin = scaleY(data.value); - const height = scaleY(0) - yOrigin; + const firstBar = barNumber === 0; + const xOrigin = + scaleX(index) + (firstBar ? 0 : barWidth * barNumber + gap * barNumber); + const yOrigin = scaleY(data.value); + const height = scaleY(0) - yOrigin; - return { xOrigin, yOrigin, height }; + return { xOrigin, yOrigin, height }; } export function drawBarPath( - xOrigin: number, - yOrigin: number, - barWidth: number, - height: number, - roundedRadius: number + xOrigin: number, + yOrigin: number, + barWidth: number, + height: number, + roundedRadius: number, ): string { - const path = d3(); - path.moveTo(xOrigin, yOrigin + height); - path.lineTo(xOrigin, yOrigin + roundedRadius); - path.arcTo(xOrigin, yOrigin, xOrigin + roundedRadius, yOrigin, roundedRadius); - path.lineTo(xOrigin + barWidth - roundedRadius, yOrigin); - path.arcTo( - xOrigin + barWidth, - yOrigin, - xOrigin + barWidth, - yOrigin + roundedRadius, - roundedRadius - ); - path.lineTo(xOrigin + barWidth, yOrigin + height); - path.lineTo(xOrigin, yOrigin + height); - path.closePath(); + const path = d3(); + path.moveTo(xOrigin, yOrigin + height); + path.lineTo(xOrigin, yOrigin + roundedRadius); + path.arcTo(xOrigin, yOrigin, xOrigin + roundedRadius, yOrigin, roundedRadius); + path.lineTo(xOrigin + barWidth - roundedRadius, yOrigin); + path.arcTo( + xOrigin + barWidth, + yOrigin, + xOrigin + barWidth, + yOrigin + roundedRadius, + roundedRadius, + ); + path.lineTo(xOrigin + barWidth, yOrigin + height); + path.lineTo(xOrigin, yOrigin + height); + path.closePath(); - return path.toString(); + return path.toString(); } -export const calculateBarWidth = (bandwidth: number, combinedDataLength: number, gap: number) => - (bandwidth - gap * (combinedDataLength - 1)) / combinedDataLength; \ No newline at end of file +export const calculateBarWidth = ( + bandwidth: number, + combinedDataLength: number, + gap: number, +) => (bandwidth - gap * (combinedDataLength - 1)) / combinedDataLength; diff --git a/component/charts/custom-bars.tsx b/component/charts/custom-bars.tsx index 2ac7522..f0d597c 100644 --- a/component/charts/custom-bars.tsx +++ b/component/charts/custom-bars.tsx @@ -1,54 +1,53 @@ +import { Svg } from "react-native-svg"; -import { Svg } from 'react-native-svg'; - -import { Bar } from './bar'; -import { ScaleBandType, ScaleLinearType } from './graph-types'; -import { calculateBarWidth } from './custom-bar-utils'; +import { Bar } from "./bar"; +import { ScaleBandType, ScaleLinearType } from "./graph-types"; +import { calculateBarWidth } from "./custom-bar-utils"; export interface CombinedData { - data: { value: number }[]; - svg: { fill: string }; + data: { value: number }[]; + svg: { fill: string }; } interface CustomBarsProps { - x: ScaleBandType; - y: ScaleLinearType; - bandwidth: number; - barColors: string[]; - xValues: unknown[]; // TODO: update this value when this data type is defined - barData: CombinedData[]; - gap: number; - roundedRadius: number; + x: ScaleBandType; + y: ScaleLinearType; + bandwidth: number; + barColors: string[]; + xValues: unknown[]; // TODO: update this value when this data type is defined + barData: CombinedData[]; + gap: number; + roundedRadius: number; } export const CustomBars: React.FC> = ({ - x: scaleX, - y: scaleY, - bandwidth, - barData, - xValues, - barColors, - gap = 2, - roundedRadius = 4 + x: scaleX, + y: scaleY, + bandwidth, + barData, + xValues, + barColors, + gap = 2, + roundedRadius = 4, }) => { - const barWidth = calculateBarWidth(bandwidth, barData.length, gap); + const barWidth = calculateBarWidth(bandwidth, barData.length, gap); - return xValues.map((_, index) => ( - - {barData.map((item, i) => ( - - ))} - - )); -}; \ No newline at end of file + return xValues.map((_, index) => ( + + {barData.map((item, i) => ( + + ))} + + )); +}; diff --git a/component/charts/custom-grid.tsx b/component/charts/custom-grid.tsx index 13760e7..e513dc3 100644 --- a/component/charts/custom-grid.tsx +++ b/component/charts/custom-grid.tsx @@ -1,20 +1,20 @@ -import React from 'react'; -import { G, Line } from 'react-native-svg'; -import { colors } from '../../styles'; -import { ScaleBandType, ScaleLinearType } from './graph-types'; +import React from "react"; +import { G, Line } from "react-native-svg"; +import { colors } from "../../styles"; +import { ScaleBandType, ScaleLinearType } from "./graph-types"; interface CustomGridProps { - x: ScaleBandType; - y: ScaleLinearType; - ticks: Array; - includeVertical?: boolean; - xTicks?: Array; + x: ScaleBandType; + y: ScaleLinearType; + ticks: Array; + includeVertical?: boolean; + xTicks?: Array; } /** * CustomGrid Component - * + * * This component is used within a react-native-svg-chart component to render grid lines. - * + * * @param {ScaleBandType} x - X-axis scale function, received from the parent chart component. * @param {ScaleLinearType} y - Y-axis scale function, received from the parent chart component. * @param {Array} ticks - Y-axis tick values for horizontal lines, received from the parent. @@ -34,55 +34,74 @@ interface CustomGridProps { * Note: Use `includeVertical` cautiously; vertical lines are not fully developed. */ export const CustomGrid: React.FC> = ({ - x, - y, - ticks, - xTicks, - includeVertical = false + x, + y, + ticks, + xTicks, + includeVertical = false, }) => { - const [firstTick, ...remainingTicks] = ticks; - const dashArray = [1, 3]; - const strokeSolidWidth = 0.2; - const strokeSolidColor = colors.bgBlack; - const strokeDashWidth = 1; - const strokeDashColor = colors.lightGrey; + const [firstTick, ...remainingTicks] = ticks; + const dashArray = [1, 3]; + const strokeSolidWidth = 0.2; + const strokeSolidColor = colors.bgBlack; + const strokeDashWidth = 1; + const strokeDashColor = colors.lightGrey; - const renderHorizontalLine = (tick: number, stroke: string, strokeWidth: number, dashArray?: number[]) => ( - - ); + const renderHorizontalLine = ( + tick: number, + stroke: string, + strokeWidth: number, + dashArray?: number[], + ) => ( + + ); - const topY = y(Math.max(...ticks)); - const bottomY = y(Math.min(...ticks)); - const renderVerticalLine = (tick: number, stroke: string, strokeWidth: number, dashArray?: number[]) => { - return ( - - ); - }; + const topY = y(Math.max(...ticks)); + const bottomY = y(Math.min(...ticks)); + const renderVerticalLine = ( + tick: number, + stroke: string, + strokeWidth: number, + dashArray?: number[], + ) => { + return ( + + ); + }; - - return ( - - {renderHorizontalLine(firstTick, strokeSolidColor, strokeSolidWidth)} - {remainingTicks.map((tick) => renderHorizontalLine(tick, strokeDashColor, strokeDashWidth, dashArray))} - {includeVertical && xTicks.map((_, index) => renderVerticalLine(index, strokeDashColor, strokeDashWidth, dashArray))} - - ); + return ( + + {renderHorizontalLine(firstTick, strokeSolidColor, strokeSolidWidth)} + {remainingTicks.map((tick) => + renderHorizontalLine(tick, strokeDashColor, strokeDashWidth, dashArray), + )} + {includeVertical && + xTicks.map((_, index) => + renderVerticalLine( + index, + strokeDashColor, + strokeDashWidth, + dashArray, + ), + )} + + ); }; diff --git a/component/charts/graph-config.ts b/component/charts/graph-config.ts index d906f2f..7d3643f 100644 --- a/component/charts/graph-config.ts +++ b/component/charts/graph-config.ts @@ -1,13 +1,13 @@ // TODO: Style values should be moved to styles // non-style config can live here as chartDefaults export const chartDefaults = { - height: 300, - spacingInner: 0.3, - spacingOuter: 0.2, - contentInset: { top: 30, bottom: 30 }, - numberOfTicks: 6, - min: 0, - barColors: ['#598EBB', '#F2D4BC', '#DB7878'], - includeColors: true, - lineStrokeWidth: 2 -}; \ No newline at end of file + height: 300, + spacingInner: 0.3, + spacingOuter: 0.2, + contentInset: { top: 30, bottom: 30 }, + numberOfTicks: 6, + min: 0, + barColors: ["#598EBB", "#F2D4BC", "#DB7878"], + includeColors: true, + lineStrokeWidth: 2, +}; diff --git a/component/charts/graph-types.ts b/component/charts/graph-types.ts index b7b7a5c..e498466 100644 --- a/component/charts/graph-types.ts +++ b/component/charts/graph-types.ts @@ -1,54 +1,54 @@ -import { ScaleBand, ScaleLinear } from 'd3-scale' +import { ScaleBand, ScaleLinear } from "d3-scale"; export type ScaleLinearType = ScaleLinear; export type ScaleBandType = ScaleBand; export interface YAxisData { - key: string; // string value for ChartLabel and useGraphData - values: Array; - // including this code only for review -- - // do we prefer the idea of passing label formatting from the data or in the component? - // generic function type, specific usage of value varies - // eslint-disable-next-line no-unused-vars - formatLabel?: (value: number) => string; + key: string; // string value for ChartLabel and useGraphData + values: Array; + // including this code only for review -- + // do we prefer the idea of passing label formatting from the data or in the component? + // generic function type, specific usage of value varies + // eslint-disable-next-line no-unused-vars + formatLabel?: (value: number) => string; } -export type XValue = string | number +export type XValue = string | number; export interface GraphData { - xValues: Array; - yValues: Array; + xValues: Array; + yValues: Array; } export interface YAxisProps { - maxLeftYAxisValue?: number; - maxRightYAxisValue?: number; - selectedLeftYAxisLabel?: string; - selectedRightYAxisLabel?: string; - // generic function type, specific usage of value varies - // eslint-disable-next-line no-unused-vars - formatRightYAxisLabel?: (value: string) => string; - // generic function type, specific usage of value varies - // eslint-disable-next-line no-unused-vars - formatLeftYAxisLabel?: (value: string) => string; + maxLeftYAxisValue?: number; + maxRightYAxisValue?: number; + selectedLeftYAxisLabel?: string; + selectedRightYAxisLabel?: string; + // generic function type, specific usage of value varies + // eslint-disable-next-line no-unused-vars + formatRightYAxisLabel?: (value: string) => string; + // generic function type, specific usage of value varies + // eslint-disable-next-line no-unused-vars + formatLeftYAxisLabel?: (value: string) => string; } export interface GraphProps { - data: GraphData; - includeColors?: boolean; - height?: number; - spacingInner?: number; - spacingOuter?: number; - contentInset?: { top: number; bottom: number }; - min?: number; - numberOfTicks?: number; - barColors?: Array; - lineStrokeWidth?: number; - useCommonScale?: boolean; - yAxisProps?: YAxisProps; + data: GraphData; + includeColors?: boolean; + height?: number; + spacingInner?: number; + spacingOuter?: number; + contentInset?: { top: number; bottom: number }; + min?: number; + numberOfTicks?: number; + barColors?: Array; + lineStrokeWidth?: number; + useCommonScale?: boolean; + yAxisProps?: YAxisProps; } /** * Common properties for graph render components. - * + * * @interface CommonProps * @property {GraphData} data - The primary data source for the graph. * @property {number} [height] - Optional. The height of the graph. @@ -63,16 +63,16 @@ export interface GraphProps { * @property {string} [testID] - Optional. Identifier for testing purposes. */ export interface CommonProps { - data: GraphData; - height?: number; - spacingInner?: number; - spacingOuter?: number; - contentInset?: { top: number; bottom: number }; - min?: number; - numberOfTicks?: number; - barColors?: Array; - lineStrokeWidth?: number; - useCommonScale?: boolean; - yAxisProps?: YAxisProps; - testID?: string; -} \ No newline at end of file + data: GraphData; + height?: number; + spacingInner?: number; + spacingOuter?: number; + contentInset?: { top: number; bottom: number }; + min?: number; + numberOfTicks?: number; + barColors?: Array; + lineStrokeWidth?: number; + useCommonScale?: boolean; + yAxisProps?: YAxisProps; + testID?: string; +} diff --git a/component/charts/graph-utils.tsx b/component/charts/graph-utils.tsx index 631e614..9a84d57 100644 --- a/component/charts/graph-utils.tsx +++ b/component/charts/graph-utils.tsx @@ -1,43 +1,52 @@ import { GraphData } from "./graph-types"; - export const convertToGraphData = ( - graphData: GraphData, - options: { - selectedLeftYAxisLabel?: string; - selectedRightYAxisLabel?: string; - maxRightYAxisValue: number; - maxLeftYAxisValue: number; - includeColors: boolean; - barColors: Array - } + graphData: GraphData, + options: { + selectedLeftYAxisLabel?: string; + selectedRightYAxisLabel?: string; + maxRightYAxisValue: number; + maxLeftYAxisValue: number; + includeColors: boolean; + barColors: Array; + }, ) => { - const xValues = graphData.xValues; - const leftAxisIndex = graphData.yValues.findIndex( - (y) => y.key === options.selectedLeftYAxisLabel - ); - const rightAxisIndex = graphData.yValues.findIndex( - (y) => y.key === options.selectedRightYAxisLabel - ); + const xValues = graphData.xValues; + const leftAxisIndex = graphData.yValues.findIndex( + (y) => y.key === options.selectedLeftYAxisLabel, + ); + const rightAxisIndex = graphData.yValues.findIndex( + (y) => y.key === options.selectedRightYAxisLabel, + ); - // scale data points according to max value - const yData = graphData.yValues.map((yAxis, index) => { - const maxValue = index === rightAxisIndex ? options.maxRightYAxisValue : options.maxLeftYAxisValue; + // scale data points according to max value + const yData = graphData.yValues.map((yAxis, index) => { + const maxValue = + index === rightAxisIndex + ? options.maxRightYAxisValue + : options.maxLeftYAxisValue; - // scale values as a percentage of the max value - const scaledValues = yAxis.values.map((value) => (value / maxValue) * 100); + // scale values as a percentage of the max value + const scaledValues = yAxis.values.map((value) => (value / maxValue) * 100); - const strokeColor = options.includeColors && options.barColors ? options.barColors[index % options.barColors.length] : 'transparent'; + const strokeColor = + options.includeColors && options.barColors + ? options.barColors[index % options.barColors.length] + : "transparent"; - const mappedData = scaledValues.map((scaledValue) => ({ value: scaledValue })); + const mappedData = scaledValues.map((scaledValue) => ({ + value: scaledValue, + })); - return { - data: mappedData, - svg: { fill: 'transparent', stroke: strokeColor } // Apply the stroke color here - }; - }); - const yAxisLeftLabels = leftAxisIndex !== -1 ? graphData.yValues[leftAxisIndex] : null; - const yAxisRightLabels = rightAxisIndex !== -1 ? graphData.yValues[rightAxisIndex] : undefined; + return { + data: mappedData, + svg: { fill: "transparent", stroke: strokeColor }, // Apply the stroke color here + }; + }); + const yAxisLeftLabels = + leftAxisIndex !== -1 ? graphData.yValues[leftAxisIndex] : null; + const yAxisRightLabels = + rightAxisIndex !== -1 ? graphData.yValues[rightAxisIndex] : undefined; - return { yData, yAxisLeftLabels, yAxisRightLabels, xValues }; + return { yData, yAxisLeftLabels, yAxisRightLabels, xValues }; }; diff --git a/component/charts/line-graph/line-graph.tsx b/component/charts/line-graph/line-graph.tsx index 43bacd6..3f3001f 100644 --- a/component/charts/line-graph/line-graph.tsx +++ b/component/charts/line-graph/line-graph.tsx @@ -1,90 +1,103 @@ -import React from 'react'; -import * as shape from 'd3-shape'; -import { View } from 'react-native'; -import { LineChart, XAxis, YAxis } from 'react-native-svg-charts'; +import React from "react"; +import * as shape from "d3-shape"; +import { View } from "react-native"; +import { LineChart, XAxis, YAxis } from "react-native-svg-charts"; -import { useGraphData } from '../use-graph-data'; -import { CustomGrid } from '../custom-grid'; -import { graphStyles } from '../chart-styles'; -import ChartView from '../chart-view'; -import { CommonProps } from '../graph-types'; +import { useGraphData } from "../use-graph-data"; +import { CustomGrid } from "../custom-grid"; +import { graphStyles } from "../chart-styles"; +import ChartView from "../chart-view"; +import { CommonProps } from "../graph-types"; // TODO: 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 = ({ data, useCommonScale = false, testID, ...props }) => { - if (!data || typeof data !== 'object') { - return null - }; // TODO:#38 - const { - xValues, - yData, - yAxisLeftLabels, - yAxisRightLabels, - defaultProps: { - height, - contentInset, - min, - numberOfTicks, - lineStrokeWidth, - yAxisProps: { - maxLeftYAxisValue, - maxRightYAxisValue, - formatLeftYAxisLabel, - formatRightYAxisLabel - } - } - // Proper error/loading handling from useQueryHandler can work with this rule #38 - // eslint-disable-next-line react-hooks/rules-of-hooks - } = useGraphData(data, props); +const LineGraph: React.FC = ({ + data, + useCommonScale = false, + testID, + ...props +}) => { + if (!data || typeof data !== "object") { + return null; + } // TODO:#38 + const { + xValues, + yData, + yAxisLeftLabels, + yAxisRightLabels, + defaultProps: { + height, + contentInset, + min, + numberOfTicks, + lineStrokeWidth, + yAxisProps: { + maxLeftYAxisValue, + maxRightYAxisValue, + formatLeftYAxisLabel, + formatRightYAxisLabel, + }, + }, + // Proper error/loading handling from useQueryHandler can work with this rule #38 + // eslint-disable-next-line react-hooks/rules-of-hooks + } = useGraphData(data, props); - return ( - - - - - (item as unknown as { value: number }).value} - xAccessor={({ index }) => xValues[index] as number} - gridMin={min} - contentInset={contentInset} - numberOfTicks={numberOfTicks} - > - - - index)} // TODO: update when useGraphHook returns explicit display values - style={[graphStyles.xAxisMarginTop]} - svg={graphStyles.xAxisFontStyle} - numberOfTicks={numberOfTicks} - contentInset={graphStyles.horizontalInset} - /> - - - - - ); + return ( + + + + + + (item as unknown as { value: number }).value + } + xAccessor={({ index }) => xValues[index] as number} + gridMin={min} + contentInset={contentInset} + numberOfTicks={numberOfTicks} + > + + + index)} // TODO: update when useGraphHook returns explicit display values + style={[graphStyles.xAxisMarginTop]} + svg={graphStyles.xAxisFontStyle} + numberOfTicks={numberOfTicks} + contentInset={graphStyles.horizontalInset} + /> + + + + + ); }; export default LineGraph; diff --git a/component/charts/use-graph-data.ts b/component/charts/use-graph-data.ts index 30269b5..81e0912 100644 --- a/component/charts/use-graph-data.ts +++ b/component/charts/use-graph-data.ts @@ -1,57 +1,70 @@ -import { useMemo } from 'react'; - -import { convertToGraphData } from './graph-utils'; -import { chartDefaults } from './graph-config'; -import { GraphData, GraphProps, XValue, YAxisData } from './graph-types'; - +import { useMemo } from "react"; +import { convertToGraphData } from "./graph-utils"; +import { chartDefaults } from "./graph-config"; +import { GraphData, GraphProps, XValue, YAxisData } from "./graph-types"; interface useGraphDataInterface { - xValues: Array; - yData: { - data: { - value: number; - }[]; - svg: { - fill: string; - }; - }[]; - yAxisLeftLabels: YAxisData; - yAxisRightLabels: YAxisData; - defaultProps: Partial; + xValues: Array; + yData: { + data: { + value: number; + }[]; + svg: { + fill: string; + }; + }[]; + yAxisLeftLabels: YAxisData; + yAxisRightLabels: YAxisData; + defaultProps: Partial; } // this version assumes string values for X, this isn't necessarily the case // convertToGraphData is specifically tailored to bar/group bar graphs // ultimately this component could be used by any x & y axis graph types (line/bar/scatter) -export const useGraphData = (graphData: GraphData, props: Partial): useGraphDataInterface => { - const { yAxisProps = {}, ...otherProps } = props; - const defaultProps = { - ...chartDefaults, - ...otherProps, - // assign default values for yAxisProps + spread to override with values coming from props - yAxisProps: { - maxLeftYAxisValue: Math.max(...(graphData.yValues[0]?.values ?? [0])), - maxRightYAxisValue: - graphData.yValues.length > 1 ? Math.max(...graphData.yValues[1]?.values) : undefined, - formatRightYAxisLabel: yAxisProps.formatRightYAxisLabel, - formatLeftYAxisLabel: yAxisProps.formatLeftYAxisLabel, - selectedLeftYAxisLabel: graphData.yValues[0]?.key, - selectedRightYAxisLabel: graphData.yValues[1]?.key, - ...yAxisProps - } - }; +export const useGraphData = ( + graphData: GraphData, + props: Partial, +): useGraphDataInterface => { + const { yAxisProps = {}, ...otherProps } = props; + const defaultProps = { + ...chartDefaults, + ...otherProps, + // assign default values for yAxisProps + spread to override with values coming from props + yAxisProps: { + maxLeftYAxisValue: Math.max(...(graphData.yValues[0]?.values ?? [0])), + maxRightYAxisValue: + graphData.yValues.length > 1 + ? Math.max(...graphData.yValues[1]?.values) + : undefined, + formatRightYAxisLabel: yAxisProps.formatRightYAxisLabel, + formatLeftYAxisLabel: yAxisProps.formatLeftYAxisLabel, + selectedLeftYAxisLabel: graphData.yValues[0]?.key, + selectedRightYAxisLabel: graphData.yValues[1]?.key, + ...yAxisProps, + }, + }; - const { yData, yAxisLeftLabels, yAxisRightLabels, xValues } = useMemo( - () => convertToGraphData(graphData, { ...defaultProps.yAxisProps, includeColors: defaultProps.includeColors, barColors: defaultProps.barColors}), - [graphData, defaultProps.yAxisProps, defaultProps.includeColors, defaultProps.barColors] - ); + const { yData, yAxisLeftLabels, yAxisRightLabels, xValues } = useMemo( + () => + convertToGraphData(graphData, { + ...defaultProps.yAxisProps, + includeColors: defaultProps.includeColors, + barColors: defaultProps.barColors, + }), + [ + graphData, + defaultProps.yAxisProps, + defaultProps.includeColors, + defaultProps.barColors, + ], + ); - return { - xValues, - yData, - yAxisLeftLabels, - yAxisRightLabels, - defaultProps - }; + return { + xValues, + yData, + yAxisLeftLabels, + yAxisRightLabels, + defaultProps, + }; }; diff --git a/component/video/camera.tsx b/component/video/camera.tsx index 9c86995..c004fe4 100644 --- a/component/video/camera.tsx +++ b/component/video/camera.tsx @@ -1,169 +1,177 @@ import React, { useCallback, useRef, useState } from "react"; import { Button, StyleSheet, Text, View } from "react-native"; import { - Camera, - useCameraPermission, - useCameraDevice, - useCameraFormat, - PhotoFile, - VideoFile, - CameraRuntimeError, - Orientation, - // @ts-ignore + Camera, + useCameraPermission, + useCameraDevice, + useCameraFormat, + PhotoFile, + VideoFile, + CameraRuntimeError, + Orientation, + // @ts-ignore } from "react-native-vision-camera"; import { RecordingButton } from "./capture-button"; import { useIsForeground } from "./is-foreground"; import { useIsFocused } from "@react-navigation/native"; -export default function CameraScreen({ route, navigation }): React.ReactElement { - // TODO: #73 Does this need to be passed to Camera component? - // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars - const { gameType, tableSize, tags, location } = route.params - // LOG for params -- Remove when no longer needed - // Note: camelCased value being passed, change on record.tsx if you want a different value format - console.log(gameType, tableSize, tags, location) +export default function CameraScreen({ + route, + navigation, +}): React.ReactElement { + // TODO: #73 Does this need to be passed to Camera component? + // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars + const { gameType, tableSize, tags, location } = route.params; + // LOG for params -- Remove when no longer needed + // Note: camelCased value being passed, change on record.tsx if you want a different value format + console.log(gameType, tableSize, tags, location); + const camera = useRef(null); + const { hasPermission, requestPermission } = useCameraPermission(); + const [isCameraInitialized, setIsCameraInitialized] = + useState(false); - const camera = useRef(null); - const { hasPermission, requestPermission } = useCameraPermission(); - const [isCameraInitialized, setIsCameraInitialized] = - useState(false); + const isForeground = useIsForeground(); + const isFocused = useIsFocused(); + const isActive = isForeground && isFocused; - const isForeground = useIsForeground(); - const isFocused = useIsFocused(); - const isActive = isForeground && isFocused; + const onError = useCallback((error: CameraRuntimeError) => { + console.error(error); + }, []); - const onError = useCallback((error: CameraRuntimeError) => { - console.error(error); - }, []); + const onInitialized = useCallback(() => { + console.log("Camera initialized!"); + setIsCameraInitialized(true); + }, []); - const onInitialized = useCallback(() => { - console.log("Camera initialized!"); - setIsCameraInitialized(true); - }, []); + const onMediaCaptured = useCallback((media: PhotoFile | VideoFile) => { + console.log(`Media captured! ${JSON.stringify(media)}`); + }, []); - const onMediaCaptured = useCallback((media: PhotoFile | VideoFile) => { - console.log(`Media captured! ${JSON.stringify(media)}`); - }, []); + const onVideoChunkReady = useCallback((event) => { + console.log(`Chunk ready in react-native`, event.nativeEvent); + }, []); - const onVideoChunkReady = useCallback((event) => { - console.log(`Chunk ready in react-native`, event.nativeEvent); - }, []); + if (!hasPermission) { + requestPermission(); + // Error handling in case they refuse to give permission + } - if (!hasPermission) { - requestPermission(); - // Error handling in case they refuse to give permission - } + const device = useCameraDevice("back"); + const format = useCameraFormat(device, [ + { videoResolution: { width: 3048, height: 2160 } }, + { fps: 60 }, + ]); // this sets as a target - const device = useCameraDevice("back"); - const format = useCameraFormat(device, [ - { videoResolution: { width: 3048, height: 2160 } }, - { fps: 60 }, - ]); // this sets as a target + //Orientation detection + const [orientation, setOrientation] = useState("portrait"); - //Orientation detection - const [orientation, setOrientation] = useState("portrait"); + const toggleOrientation = () => { + setOrientation( + (currentOrientation) => + currentOrientation === "landscape-left" ? "portrait" : "landscape-left", // Can adjust this and the type to match what we want + ); + }; - const toggleOrientation = () => { - setOrientation( - (currentOrientation) => - currentOrientation === "landscape-left" ? "portrait" : "landscape-left", // Can adjust this and the type to match what we want - ); - }; - - // Replace with error handling - if (device === null) { - console.log(device); - return ( - - Camera not available. Does user have permissions: {hasPermission} - - ); - } - return ( - hasPermission && ( - - - -