ソースを参照

Modify dropdown to be a controlled component, and add presets to GameCreationForm

Kirk Trombley 4 年 前
コミット
57a86bfc94

+ 11 - 5
client/src/components/util/GameCreationForm/Dropdown.jsx

@@ -8,29 +8,35 @@ export const Item = ({ value, display, onSelect, children }) => (
   </div>
 );
 
-export const Dropdown = ({ open, onSelect, onClick, children }) => {
+export const Dropdown = ({ selected, open, onSelect, onClick, forceDisplay, children }) => {
   const transitionRef = useRef(null);
   const [ displayed, setDisplayed ] = useState(null);
   const onSelectCallback = useCallback((value, display) => { 
     setDisplayed(display); 
     onSelect(value); 
   }, [onSelect]);
+
   useEffect(() => {
-    if (displayed) {
+    if (forceDisplay) {
       return;
     }
+
+    if (selected === undefined) {
+      return;
+    }
+
     let found = null;
     children.forEach(element => {
-      if (React.isValidElement(element) && !found && element.props['default']) {
+      if (React.isValidElement(element) && (found === null) && element.props.value === selected) {
         const { value, display } = element.props;
         found = display ?? value;
       }
     });
     setDisplayed(found);
-  }, [children, displayed]);
+  }, [children, selected, forceDisplay]);
   return (
     <div className={styles.container}>
-      <div className={styles.button} onClick={onClick}>{displayed}</div>
+      <div className={styles.button} onClick={onClick}>{forceDisplay ?? displayed}</div>
       <CSSTransition nodeRef={transitionRef} in={open} timeout={200} mountOnEnter unmountOnExit classNames={{
         enter: styles['list-enter'],
         enterActive: styles['list-enter-active'],

+ 58 - 16
client/src/components/util/GameCreationForm/GameCreationForm.jsx

@@ -1,5 +1,5 @@
 import ms from 'pretty-ms';
-import { useState } from 'react';
+import { useCallback, useState } from 'react';
 import { createGame } from '../../../domain/apiMethods';
 import { MAP_CRUNCH, RANDOM_STREET_VIEW, URBAN } from '../../../domain/genMethods';
 import { FROZEN, NORMAL, TIME_BANK, RACE } from '../../../domain/ruleSets';
@@ -7,13 +7,50 @@ import Loading from '../Loading';
 import { Dropdown, DropdownGroup, Item } from './Dropdown';
 import styles from './GameCreationForm.module.css';
 
+const DEFAULTS = {
+  timer: 300,
+  rounds: 5,
+  onlyAmerica: false,
+  genMethod: RANDOM_STREET_VIEW,
+  ruleSet: NORMAL,
+}
+
+const PRESETS = {
+  URBAN_AMERICA: {
+    ...DEFAULTS,
+    genMethod: URBAN,
+    onlyAmerica: true,
+  },
+  URBAN_GLOBAL: {
+    ...DEFAULTS,
+    genMethod: URBAN,
+  },
+  FAST_FROZEN: {
+    ...DEFAULTS,
+    timer: 30,
+    rounds: 3,
+    genMethod: RANDOM_STREET_VIEW,
+    ruleSet: FROZEN,
+  },
+}
+
 const GameCreationForm = ({ afterCreate }) => {
   const [ loading, setLoading ] = useState(false);
-  const [ timer, setTimer ] = useState(300);
-  const [ rounds, setRounds ] = useState(5);
-  const [ onlyAmerica, setOnlyAmerica ] = useState(false);
-  const [ genMethod, setGenMethod ] = useState(MAP_CRUNCH);
-  const [ ruleSet, setRuleSet ] = useState(NORMAL);
+  const [ timer, setTimer ] = useState(DEFAULTS.timer);
+  const [ rounds, setRounds ] = useState(DEFAULTS.rounds);
+  const [ onlyAmerica, setOnlyAmerica ] = useState(DEFAULTS.onlyAmerica);
+  const [ genMethod, setGenMethod ] = useState(DEFAULTS.genMethod);
+  const [ ruleSet, setRuleSet ] = useState(DEFAULTS.ruleSet);
+
+  const setPreset = useCallback(({
+    timer, rounds, onlyAmerica, genMethod, ruleSet,
+  }) => {
+    setTimer(timer);
+    setRounds(rounds);
+    setOnlyAmerica(onlyAmerica);
+    setGenMethod(genMethod);
+    setRuleSet(ruleSet);
+  }, []);
 
   if (loading) {
     return <Loading />;
@@ -31,33 +68,38 @@ const GameCreationForm = ({ afterCreate }) => {
     <div className={styles.form}>
       <div className={styles.dropdowns}>
         <DropdownGroup>
-          <Dropdown onSelect={setTimer} open='timer'>
+          <Dropdown selected={timer} onSelect={setTimer} open='timer'>
             <Item value={30} display={ms(30 * 1000)}>30 Seconds</Item>
             <Item value={120} display={ms(2 * 60 * 1000)}>2 Minutes</Item>
-            <Item value={300} display={ms(5 * 60 * 1000)} default>5 Minutes</Item>
+            <Item value={300} display={ms(5 * 60 * 1000)}>5 Minutes</Item>
             <Item value={3600} display={ms(60 * 60 * 1000)}>1 Hour</Item>
           </Dropdown>
-          <Dropdown onSelect={setRounds} open='rounds'>
+          <Dropdown selected={rounds} onSelect={setRounds} open='rounds'>
             <Item value={1}>1 Round</Item>
             <Item value={3}>3 Rounds</Item>
-            <Item value={5} default>5 Rounds</Item>
+            <Item value={5}>5 Rounds</Item>
             <Item value={10}>10 Rounds</Item>
           </Dropdown>
-          <Dropdown onSelect={setOnlyAmerica} open='america'>
-            <Item value={false} display='🌎' default>All Countries</Item>
+          <Dropdown selected={onlyAmerica} onSelect={setOnlyAmerica} open='america'>
+            <Item value={false} display='🌎'>All Countries</Item>
             <Item value={true} display='🇺🇸'>Just America</Item>
           </Dropdown>
-          <Dropdown onSelect={setGenMethod} open='gen'>
-            <Item value={MAP_CRUNCH} display='MC' default>Map Crunch</Item>
+          <Dropdown selected={genMethod} onSelect={setGenMethod} open='gen'>
             <Item value={RANDOM_STREET_VIEW} display='RSV'>Random Street View</Item>
             <Item value={URBAN} display='🏙️'>Urban Centers</Item>
+            <Item value={MAP_CRUNCH} display='MC' default>Map Crunch</Item>
           </Dropdown>
-          <Dropdown onSelect={setRuleSet} open='rule'>
-            <Item value={NORMAL} display='⏰' default>Normal</Item>
+          <Dropdown selected={ruleSet} onSelect={setRuleSet} open='rule'>
+            <Item value={NORMAL} display='⏰'>Normal</Item>
             <Item value={TIME_BANK} display='🏦'>Time Bank</Item>
             <Item value={FROZEN} display='❄️'>Frozen</Item>
             <Item value={RACE} display='🏃'>Race</Item>
           </Dropdown>
+          <Dropdown onSelect={setPreset} open='presets' forceDisplay='...'>
+            <Item value={PRESETS.URBAN_AMERICA} display=''>Urban America</Item>
+            <Item value={PRESETS.URBAN_GLOBAL} display=''>Urban Global</Item>
+            <Item value={PRESETS.FAST_FROZEN} display=''>Fast Frozen</Item>
+          </Dropdown>
         </DropdownGroup>
       </div>
       <button className={styles.start} onClick={onCreateGame}>