useDropdown hook, review requests

This commit is contained in:
Loewy 2024-02-19 13:19:21 -08:00
parent bcef200765
commit ffe95a12f2
3 changed files with 111 additions and 79 deletions

View File

@ -31,7 +31,7 @@ module.exports = {
// Best Practices // Best Practices
eqeqeq: ["error", "always"], // Enforce '===' instead of '==' eqeqeq: ["error", "always"], // Enforce '===' instead of '=='
curly: ["error", "multi-line", "consistent"], // Require curly braces for all control statements curly: ["error", "multi-line", "consistent"], // Require curly braces for all control statements
"no-unused-vars": "warn", // Warn about variables that are declared but not used "no-unused-vars": "off", // Not needed with TypeScript
// React Specific // React Specific
"react/jsx-filename-extension": [1, { extensions: [".tsx"] }], // Allow jsx syntax in .tsx files "react/jsx-filename-extension": [1, { extensions: [".tsx"] }], // Allow jsx syntax in .tsx files

View File

@ -4,52 +4,103 @@ import { useCallback, useState } from "react";
import { useCameraPermission } from "react-native-vision-camera"; import { useCameraPermission } from "react-native-vision-camera";
import { showAlert } from "../../lib/alert-messages"; import { showAlert } from "../../lib/alert-messages";
interface VideoFlowInputParams { // TODO: #122 should decide on what values/labels go here.
sessionName?: string; enum GameType {
gameType: string; FreePlay = "freePlay",
tableSize: string; StraightPool = "straightPool",
NineBall = "nineBall",
}
// TODO: #122 should be int -- inch value of table size.
enum TableSize {
NineFoot = "nineFoot",
EightFoot = "eightFoot",
SevenFoot = "sevenFoot",
}
interface VideoUserInputMeta {
sessionName: string;
gameType: GameType | null;
tableSize: TableSize | null;
}
interface VideoFlowInputParams extends VideoUserInputMeta {
videoId?: number; videoId?: number;
} }
export const useVideoDetails = ({ mode, videoId, params, navigation }) => { function useDropdown<T>(
initialValue: T | null,
options: Array<{ label: string; value: T }>,
closeOthers: () => void,
) {
const [isOpen, setIsOpen] = useState(false);
const [value, setValue] = useState<T | null>(initialValue);
const [optionsList, setOptionsList] = useState(options);
const toggleOpen = useCallback(() => {
if (!isOpen) {
closeOthers();
}
setIsOpen(!isOpen);
}, [isOpen, closeOthers]);
return {
isOpen,
toggleOpen,
value,
setValue,
optionsList,
setOptionsList,
setIsOpen,
};
}
export const useVideoDetails = ({
params: {
mode,
videoId,
sessionName: initialSessionName,
gameType: initialGameType,
tableSize: initialTableSize,
},
navigation,
}) => {
const initialState = {
sessionName: initialSessionName || "",
gameType: initialGameType || null,
tableSize: initialTableSize || null,
};
const { hasPermission, requestPermission } = useCameraPermission(); const { hasPermission, requestPermission } = useCameraPermission();
// Initial state setup
const initialState = mode === "save-video" && params ? params : {};
// Session name input
// Should session name be required?
const [sessionName, setSessionName] = useState<string>( const [sessionName, setSessionName] = useState<string>(
initialState.sessionName || "", initialState.sessionName || "",
); );
// Game type dropdown const closeAllDropdowns = useCallback(() => {
const [gameTypeOpen, setGameTypeOpen] = useState<boolean>(false); gameType.setIsOpen(false);
const [gameType, setGameType] = useState<string | null>( tableSize.setIsOpen(false);
initialState.gameType || null, // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const gameType = useDropdown<GameType | null>(
initialState.gameType,
[
{ label: "Free Play", value: GameType.FreePlay },
{ label: "Straight Pool", value: GameType.StraightPool },
{ label: "Nine Ball", value: GameType.NineBall },
],
closeAllDropdowns,
); );
const [gameTypes, setGameTypes] = useState([
{ label: "Free Play", value: "freePlay" },
{ label: "Straight Pool", value: "straightPool" },
{ label: "Nine Ball", value: "nineBall" },
]);
// Table size dropdown const tableSize = useDropdown<TableSize | null>(
const [tableSizeOpen, setTableSizeOpen] = useState<boolean>(false); initialState.tableSize,
const [tableSize, setTableSize] = useState<string>( [
initialState.tableSize || "", { label: `9'`, value: TableSize.NineFoot },
{ label: `8'`, value: TableSize.EightFoot },
{ label: `7'`, value: TableSize.SevenFoot },
],
closeAllDropdowns,
); );
const [tableSizes, setTableSizes] = useState([
{ label: `9'`, value: "nineFoot" },
{ label: `8'`, value: "eightFoot" },
{ label: `7'`, value: "sevenFoot" },
]);
// Toggle dropdowns mutually exclusive
const onGameTypeOpen = useCallback(() => setTableSizeOpen(false), []);
const onTableSizeOpen = useCallback(() => setGameTypeOpen(false), []);
// GraphQL Mutation
const [TerminateUploadStream, { loading, error }] = const [TerminateUploadStream, { loading, error }] =
gql.useTerminateUploadStreamMutation(); gql.useTerminateUploadStreamMutation();
@ -60,12 +111,21 @@ export const useVideoDetails = ({ mode, videoId, params, navigation }) => {
} }
if (mode === "start-video") { if (mode === "start-video") {
const params: VideoFlowInputParams = { sessionName, gameType, tableSize }; const params: VideoFlowInputParams = {
sessionName,
gameType: gameType.value,
tableSize: tableSize.value,
};
navigation.push("Camera", params); navigation.push("Camera", params);
} else { } else {
try { try {
await TerminateUploadStream({ await TerminateUploadStream({
variables: { videoId, videoName: sessionName, tableSize, gameType }, variables: {
videoId,
videoName: sessionName,
tableSize: tableSize.value,
gameType: gameType.value,
},
}); });
navigation.push("Tabs"); navigation.push("Tabs");
} catch (err) { } catch (err) {
@ -78,19 +138,7 @@ export const useVideoDetails = ({ mode, videoId, params, navigation }) => {
sessionName, sessionName,
setSessionName, setSessionName,
gameType, gameType,
setGameType,
gameTypeOpen,
setGameTypeOpen,
gameTypes,
setGameTypes,
onGameTypeOpen,
tableSize, tableSize,
setTableSize,
setTableSizes,
tableSizeOpen,
setTableSizeOpen,
tableSizes,
onTableSizeOpen,
handleSubmit, handleSubmit,
loading, loading,
error, error,

View File

@ -9,34 +9,20 @@ import {
View, View,
} from "react-native"; } from "react-native";
import DropDownPicker from "react-native-dropdown-picker"; import DropDownPicker from "react-native-dropdown-picker";
// @ts-ignore
import { useVideoDetails } from "../../component/video/use-video-details"; import { useVideoDetails } from "../../component/video/use-video-details";
import { globalInputStyles } from "../../styles"; import { globalInputStyles } from "../../styles";
import { recordStyles as styles } from "./styles"; import { recordStyles as styles } from "./styles";
export default function VideoDetails({ navigation, route }): React.JSX.Element { export default function VideoDetails({ navigation, route }): React.JSX.Element {
const { mode, videoId } = route.params; const { mode } = route.params;
const { const {
sessionName, sessionName,
setSessionName, setSessionName,
gameType, gameType,
setGameType,
tableSize, tableSize,
setTableSize,
gameTypeOpen,
setGameTypeOpen,
tableSizeOpen,
setTableSizeOpen,
onGameTypeOpen,
onTableSizeOpen,
handleSubmit, handleSubmit,
loading, loading,
tableSizes, } = useVideoDetails({ params: route.params, navigation });
gameTypes,
setGameTypes,
setTableSizes,
} = useVideoDetails({ mode, videoId, params: route.params, navigation });
const dropDownStyles = { const dropDownStyles = {
style: globalInputStyles.dropdownStyle, style: globalInputStyles.dropdownStyle,
@ -61,26 +47,24 @@ export default function VideoDetails({ navigation, route }): React.JSX.Element {
<DropDownPicker <DropDownPicker
zIndex={3000} zIndex={3000}
zIndexInverse={1000} zIndexInverse={1000}
open={gameTypeOpen} open={gameType.isOpen}
value={gameType} value={gameType.value}
items={gameTypes} items={gameType.optionsList}
setOpen={setGameTypeOpen} setOpen={gameType.toggleOpen}
setValue={setGameType} setValue={gameType.setValue}
setItems={setGameTypes} setItems={gameType.setOptionsList}
onOpen={onGameTypeOpen}
{...dropDownStyles} {...dropDownStyles}
/> />
<Text style={globalInputStyles.dropdownTitle}>Table size</Text> <Text style={globalInputStyles.dropdownTitle}>Table Size</Text>
<DropDownPicker <DropDownPicker
zIndex={2000} zIndex={2000}
zIndexInverse={2000} zIndexInverse={2000}
open={tableSizeOpen} open={tableSize.isOpen}
value={tableSize} value={tableSize.value}
items={tableSizes} items={tableSize.optionsList}
setOpen={setTableSizeOpen} setOpen={tableSize.toggleOpen}
setValue={setTableSize} setValue={tableSize.setValue}
setItems={setTableSizes} setItems={tableSize.setOptionsList}
onOpen={onTableSizeOpen}
{...dropDownStyles} {...dropDownStyles}
/> />
</View> </View>