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
eqeqeq: ["error", "always"], // Enforce '===' instead of '=='
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/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 { showAlert } from "../../lib/alert-messages";
interface VideoFlowInputParams {
sessionName?: string;
gameType: string;
tableSize: string;
// TODO: #122 should decide on what values/labels go here.
enum GameType {
FreePlay = "freePlay",
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;
}
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();
// Initial state setup
const initialState = mode === "save-video" && params ? params : {};
// Session name input
// Should session name be required?
const [sessionName, setSessionName] = useState<string>(
initialState.sessionName || "",
);
// Game type dropdown
const [gameTypeOpen, setGameTypeOpen] = useState<boolean>(false);
const [gameType, setGameType] = useState<string | null>(
initialState.gameType || null,
const closeAllDropdowns = useCallback(() => {
gameType.setIsOpen(false);
tableSize.setIsOpen(false);
// 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 [tableSizeOpen, setTableSizeOpen] = useState<boolean>(false);
const [tableSize, setTableSize] = useState<string>(
initialState.tableSize || "",
const tableSize = useDropdown<TableSize | null>(
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 }] =
gql.useTerminateUploadStreamMutation();
@ -60,12 +111,21 @@ export const useVideoDetails = ({ mode, videoId, params, navigation }) => {
}
if (mode === "start-video") {
const params: VideoFlowInputParams = { sessionName, gameType, tableSize };
const params: VideoFlowInputParams = {
sessionName,
gameType: gameType.value,
tableSize: tableSize.value,
};
navigation.push("Camera", params);
} else {
try {
await TerminateUploadStream({
variables: { videoId, videoName: sessionName, tableSize, gameType },
variables: {
videoId,
videoName: sessionName,
tableSize: tableSize.value,
gameType: gameType.value,
},
});
navigation.push("Tabs");
} catch (err) {
@ -78,19 +138,7 @@ export const useVideoDetails = ({ mode, videoId, params, navigation }) => {
sessionName,
setSessionName,
gameType,
setGameType,
gameTypeOpen,
setGameTypeOpen,
gameTypes,
setGameTypes,
onGameTypeOpen,
tableSize,
setTableSize,
setTableSizes,
tableSizeOpen,
setTableSizeOpen,
tableSizes,
onTableSizeOpen,
handleSubmit,
loading,
error,

View File

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