瀏覽代碼

Add category range question per path

Tatiana Inama 6 年之前
父節點
當前提交
954ccf1847
共有 2 個文件被更改,包括 155 次插入10 次删除
  1. 43 0
      src/App.css
  2. 112 10
      src/DrawCanvas.tsx

+ 43 - 0
src/App.css

@@ -86,6 +86,49 @@ form button {
   line-height: 1rem;
 }
 
+.vom-rating {
+  display: grid;
+  grid-template-columns: 2fr repeat(5, 1fr);
+  grid-template-rows: repeat(5, 1fr);
+  justify-items: center;
+  align-items: center;
+}
+
+.vom-rating ~ .is-invalid {
+  display: block;
+}
+
+.vom-rating-label.is-invalid,
+.vom-rating-value label.is-invalid {
+  color: #dc3545;
+}
+.vom-rating-label.is-valid,
+.vom-rating-value label.is-valid {
+  color: #28a745
+}
+.vom-rating-value {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.vom-rating-value label {
+  margin: 0;
+}
+
+.vom-rating-arrow-container {
+  grid-column: 3 / span 3;
+  grid-row: 1;
+}
+
+.vom-rating-arrow {
+  width: 100%;
+  height: 0;
+  border-style: solid;
+  border-width: 0.5rem 10rem 0px 0;
+  border-color: transparent #6c757d transparent transparent;
+}
+
 #magic-canvas,
 #vom-admin-canvas {
   width: 100%;

+ 112 - 10
src/DrawCanvas.tsx

@@ -85,9 +85,15 @@ type CanvasProps = {
 };
 
 type FormData = {
-  name: string,
-  soundExample: string,
-  associations: string[],
+  [key: string]: any } &
+  {
+    name: string,
+    soundExample: string,
+    associations: string[],
+    correctness: number,
+    pleasantness: number,
+    trustworthiness: number,
+    friendliness: number
 };
 
 type PathQuestionFormState = {
@@ -156,27 +162,80 @@ const Associations: React.FunctionComponent<{
   )
 }
 
+const Slider: React.FunctionComponent<{
+  label: string,
+  onChange: (selection: number) => void,
+  initialValue: number,
+  valid?: boolean,
+  invalid?: boolean,
+}> = ({label, onChange, initialValue, valid, invalid}) => {
+  const values = [ 1, 2, 3, 4, 5];
+  const [ selection, setSelection ] = useState(initialValue);
+
+  useEffect(() => {
+    setSelection(initialValue)
+  }, [initialValue]);
+
+  const update = ({ target }: React.ChangeEvent<HTMLInputElement>) => {
+    const result = parseInt(target.value);
+    setSelection(result);
+    onChange(result)
+  }
+  
+  return (
+    <>
+      <label className={`vom-rating-label ${invalid ? 'is-invalid' : ''} ${valid ? 'is-valid' : ''}`}>{ label }</label>
+      {
+        values.map(value => (
+          <FormGroup key={value} className="vom-rating-value" check>
+            <Label for={`${label}-${value}`} check className={`${invalid ? 'is-invalid' : ''} ${valid ? 'is-valid' : ''}`} >
+              <Input
+                type="radio" 
+                name={`radio-${label}`} 
+                id={`${label}-${value}`} 
+                value={value} 
+                onChange={update} 
+                checked={value === selection}
+                valid={valid}
+                invalid={invalid}
+              />{' '}
+              {value}
+            </Label>
+            {/* <input type="radio" value={value} onChange={update} checked={value === selection} name={`radio-${label}`} id={`${label}-${value}`} /> */}
+          </FormGroup>
+        ))
+      }
+    </>
+  )
+}
+
 const PathQuestions: React.FunctionComponent<{
   saveData: (data: FormData, editing?: boolean) => void,
   cancel: () => void,
-  initialData?: {
-    name: string,
-    soundExample: string,
-    associations: string[],
-  }
+  initialData?: FormData
 }> = ({ saveData, cancel, initialData }) => {
   const [ data, setData ] = useState<FormData>({
     name: '',
     soundExample: '',
     associations: [],
+    correctness: 0,
+    friendliness: 0,
+    pleasantness: 0,
+    trustworthiness: 0
   });
 
+  const SLIDER = ['correctness', 'friendliness', 'pleasantness', 'trustworthiness'];
+
   const [ form, setFormState ] = useState<PathQuestionFormState>({
     submitted: false,
     validation: {
       name: false,
       soundExample: false,
       associations: false,
+      correctness: false,
+      friendliness: false,
+      pleasantness: false,
+      trustworthiness: false
     }
   });
 
@@ -200,6 +259,13 @@ const PathQuestions: React.FunctionComponent<{
     })
   }
 
+  const setScale = (scale: keyof FormData) => (value: number) => {
+    setData({
+      ...data,
+      [scale]: value
+    })
+  }
+
   const setInputValidation = (field: keyof FormData): undefined | { valid: true } | { invalid: true } => {
     if (!form.submitted) {
       return undefined;
@@ -217,7 +283,11 @@ const PathQuestions: React.FunctionComponent<{
       validation: {
         name: data.name !== '',
         soundExample: data.soundExample !== '',
-        associations: data.associations.length !== 0
+        associations: data.associations.length !== 0,
+        correctness: data.correctness !== 0,
+        friendliness: data.friendliness !== 0,
+        pleasantness: data.pleasantness !== 0,
+        trustworthiness: data.trustworthiness !== 0
       }
     }
     setFormState(_form);
@@ -245,6 +315,34 @@ const PathQuestions: React.FunctionComponent<{
             <Associations id="path-associations" initialValue={data.associations} saveAssociations={saveAssociations} {...setInputValidation('associations')}></Associations>
           </FormGroup>
 
+          <FormGroup>
+            <Label for="rate-area">How would you rate the speech of this area along the following scales?</Label>
+            <div className="vom-rating">
+              <div></div>
+              <div>least</div>
+              <div className="vom-rating-arrow-container">
+                <div className="vom-rating-arrow"></div>
+              </div>
+              <div>most</div>
+            {
+              SLIDER.map(scale => (
+                <Slider
+                  key={scale}
+                  initialValue={data[scale]}
+                  label={scale}
+                  onChange={setScale(scale)}
+                  {...setInputValidation(scale)}
+                />
+              ))
+            }
+            </div>
+            {
+              form.submitted && !(form.validation.correctness || form.validation.friendliness || form.validation.pleasantness || form.validation.trustworthiness) &&
+              (<div className="is-invalid invalid-feedback">
+                Please, select on option for each category
+              </div>)
+            }
+          </FormGroup>
         </Form> 
       </ModalBody>
       <ModalFooter>
@@ -288,8 +386,12 @@ class Canvas extends React.Component<CanvasProps, CanvasState> {
         _path: {
           form: {
             name: '',
-            associations: [],
+            associations: [''],
             soundExample: '',
+            correctness: 0,
+            friendliness: 0,
+            pleasantness: 0,
+            trustworthiness: 0
           },
           path: mkPath(color, event.point),
           text: mkText(color)