Jelajahi Sumber

form generation in good shape.

Tomi Cvetic 5 tahun lalu
induk
melakukan
7e9cb0747f

+ 5 - 6
frontend/pages/admin/training/[id].tsx

@@ -5,15 +5,14 @@ import { useTrainingQuery } from '../../../src/gql'
 const EditTrainingPage = () => {
 const EditTrainingPage = () => {
   const router = useRouter()
   const router = useRouter()
   const { id } = router.query
   const { id } = router.query
-  const training = useTrainingQuery({
+  const { data, error, loading } = useTrainingQuery({
     variables: { id: typeof id === 'string' ? id : id[0] }
     variables: { id: typeof id === 'string' ? id : id[0] }
   })
   })
 
 
-  if (training.loading) return <p>Loading data...</p>
-  if (training.error) return <p>Error loading data.</p>
-  console.log(training.data?.training)
-  if (training.data?.training)
-    return <EditTraining training={training.data.training} />
+  if (loading) return <p>Loading data...</p>
+  if (error) return <p>Error loading data.</p>
+  console.log(data?.training)
+  if (data?.training) return <EditTraining training={data.training} />
   else return <p>Training {id} not found.</p>
   else return <p>Training {id} not found.</p>
 }
 }
 
 

+ 9 - 0
frontend/pages/admin/training/create.tsx

@@ -0,0 +1,9 @@
+import EditTraining from '../../../src/training/components/EditTraining'
+import { emptyTraining } from '../../../src/training/utils'
+
+const CreateTrainingPage = () => {
+  const newTraining = emptyTraining()
+  return <EditTraining training={newTraining} />
+}
+
+export default CreateTrainingPage

+ 0 - 7
frontend/pages/admin/training/new.tsx

@@ -1,7 +0,0 @@
-import EditTraining from '../../../src/training/components/EditTraining'
-
-const TrainingPage = () => {
-  return <EditTraining />
-}
-
-export default TrainingPage

+ 60 - 0
frontend/src/training/components/AddFormat.tsx

@@ -0,0 +1,60 @@
+import { TextInput, useForm } from '../../form'
+import {
+  useCreateFormatMutation,
+  FormatsDocument,
+  CreateFormatMutation
+} from '../../gql'
+import { FetchResult } from '@apollo/client'
+
+const AddFormat = ({
+  onSuccess
+}: {
+  onSuccess: (
+    result: FetchResult<
+      CreateFormatMutation,
+      Record<string, any>,
+      Record<string, any>
+    >
+  ) => void
+}) => {
+  const [createFormat, { data, error, loading }] = useCreateFormatMutation()
+  const { values, touched, ...props } = useForm({
+    name: '',
+    description: ''
+  })
+
+  return (
+    <form
+      onSubmit={async event => {
+        event.preventDefault()
+        event.stopPropagation()
+        const result = await createFormat({
+          variables: values,
+          refetchQueries: [{ query: FormatsDocument }]
+        })
+        if (result.data) onSuccess(result)
+      }}
+    >
+      <h1>Add Format</h1>
+      <TextInput name='name' label='Name' value={values.name} {...props} />
+      <TextInput
+        name='description'
+        label='Description'
+        value={values.description}
+        {...props}
+      />
+      <button type='submit'>Save</button>
+      {error && <span className='error'>{error.message}</span>}
+
+      <style jsx>
+        {`
+          form {
+            max-width: 700px;
+          }
+        `}
+      </style>
+    </form>
+  )
+}
+
+export default AddFormat

+ 8 - 6
frontend/src/training/components/BlockInputs.tsx

@@ -27,25 +27,25 @@ const BlockInputs = ({ onChange, value, name }: IBlockInputs) => {
       <TextInput
       <TextInput
         name={`${name}.description`}
         name={`${name}.description`}
         label='Description'
         label='Description'
-        value={value.description || ''}
+        value={value.description ?? ''}
         onChange={onChange}
         onChange={onChange}
       />
       />
       <TextInput
       <TextInput
         name={`${name}.duration`}
         name={`${name}.duration`}
         label='Duration'
         label='Duration'
-        value={value.duration || ''}
+        value={value.duration ?? ''}
         type='number'
         type='number'
         onChange={onChange}
         onChange={onChange}
       />
       />
       <TextInput
       <TextInput
         name={`${name}.rest`}
         name={`${name}.rest`}
         label='Rest'
         label='Rest'
-        value={value.rest || ''}
+        value={value.rest ?? ''}
         type='number'
         type='number'
         onChange={onChange}
         onChange={onChange}
       />
       />
       <label>Blocks</label>
       <label>Blocks</label>
-      {value.blocks && (
+      {value.blocks && value.blocks.length > 0 && (
         <BlockInstanceInputs
         <BlockInstanceInputs
           name={`${name}.blocks`}
           name={`${name}.blocks`}
           value={value.blocks}
           value={value.blocks}
@@ -55,11 +55,13 @@ const BlockInputs = ({ onChange, value, name }: IBlockInputs) => {
       <button
       <button
         onClick={event => {
         onClick={event => {
           event.preventDefault()
           event.preventDefault()
-          const newBlock = emptyBlockInstance()
+          const newBlock = emptyBlockInstance({
+            order: value.blocks ? value.blocks.length : 0
+          })
           onChange({
           onChange({
             target: {
             target: {
               type: 'custom',
               type: 'custom',
-              name: 'blocks',
+              name: `${name}.blocks`,
               value: value.blocks ? [...value.blocks, newBlock] : [newBlock]
               value: value.blocks ? [...value.blocks, newBlock] : [newBlock]
             }
             }
           })
           })

+ 0 - 1
frontend/src/training/components/BlockInstanceInputs.tsx

@@ -83,7 +83,6 @@ const BlockInstanceInputs = ({
             onChange={onChange}
             onChange={onChange}
           />
           />
         )}
         )}
-        <button type='button'>Add block</button>
       </div>
       </div>
     )
     )
   })
   })

+ 72 - 74
frontend/src/training/components/EditTraining.tsx

@@ -11,82 +11,80 @@ const EditTraining = ({ training }: { training?: Partial<Training> }) => {
   const [createTraining, createData] = useCreateTrainingMutation()
   const [createTraining, createData] = useCreateTrainingMutation()
 
 
   return (
   return (
-    <>
-      <form
-        onSubmit={ev => {
-          ev.preventDefault()
-          //createTraining({ variables: values })
-        }}
-      >
-        <TextInput
-          name='title'
-          label='Title'
-          value={values.title}
-          onChange={onChange}
-        />
-        <TrainingTypeSelector
-          name='type'
-          value={values.type}
-          onChange={onChange}
-        />
-        <DateTimeInput
-          name='trainingDate'
-          label='Training date'
-          value={values.trainingDate}
-          onChange={onChange}
-        />
-        <TextInput
-          name='location'
-          label='Location'
-          value={values.location}
-          onChange={onChange}
-        />
-        <TextInput
-          name='attendance'
-          label='Attendance'
-          type='number'
-          value={values.attendance}
+    <form
+      onSubmit={ev => {
+        ev.preventDefault()
+        //createTraining({ variables: values })
+      }}
+    >
+      <TextInput
+        name='title'
+        label='Title'
+        value={values.title}
+        onChange={onChange}
+      />
+      <TrainingTypeSelector
+        name='type'
+        value={values.type}
+        onChange={onChange}
+      />
+      <DateTimeInput
+        name='trainingDate'
+        label='Training date'
+        value={values.trainingDate}
+        onChange={onChange}
+      />
+      <TextInput
+        name='location'
+        label='Location'
+        value={values.location}
+        onChange={onChange}
+      />
+      <TextInput
+        name='attendance'
+        label='Attendance'
+        type='number'
+        value={values.attendance}
+        onChange={onChange}
+      />
+      <Checkbox
+        name='published'
+        label='Published'
+        value={values.published}
+        onChange={onChange}
+      />
+      <label>Blocks</label>
+      {values.blocks && (
+        <BlockInstanceInputs
+          name='blocks'
+          value={values.blocks}
           onChange={onChange}
           onChange={onChange}
         />
         />
-        <Checkbox
-          name='published'
-          label='Published'
-          value={values.published}
-          onChange={onChange}
-        />
-        <label>Blocks</label>
-        {values.blocks && (
-          <BlockInstanceInputs
-            name='blocks'
-            value={values.blocks}
-            onChange={onChange}
-          />
-        )}
-        <button
-          onClick={event => {
-            event.preventDefault()
-            const newBlock = emptyBlockInstance()
-            onChange({
-              target: {
-                type: 'custom',
-                name: 'blocks',
-                value: values.blocks ? [...values.blocks, newBlock] : [newBlock]
-              }
-            })
-          }}
-          type='button'
-        >
-          Add block
-        </button>
-        <button type='submit' disabled={createData.loading}>
-          Save
-        </button>
-        {createData.data && <span color='green'>Saved.</span>}
-        {createData.error && (
-          <span color='red'>Error saving: {createData.error.message}</span>
-        )}
-      </form>
-    </>
+      )}
+      <button
+        onClick={event => {
+          event.preventDefault()
+          const newBlock = emptyBlockInstance()
+          onChange({
+            target: {
+              type: 'custom',
+              name: 'blocks',
+              value: values.blocks ? [...values.blocks, newBlock] : [newBlock]
+            }
+          })
+        }}
+        type='button'
+      >
+        Add block
+      </button>
+      <button type='submit' disabled={createData.loading}>
+        Save
+      </button>
+      {createData.data && <span color='green'>Saved.</span>}
+      {createData.error && (
+        <span color='red'>Error saving: {createData.error.message}</span>
+      )}
+    </form>
   )
   )
 }
 }
 
 

+ 21 - 2
frontend/src/training/components/FormatSelector.tsx

@@ -1,5 +1,7 @@
 import { useFormatsQuery, FormatCreateOneInput, Format } from '../../gql'
 import { useFormatsQuery, FormatCreateOneInput, Format } from '../../gql'
-import { useEffect } from 'react'
+import { useEffect, useState } from 'react'
+import AddFormat from './AddFormat'
+import { Modal } from '../../modal'
 
 
 interface IFormatSelector {
 interface IFormatSelector {
   value?: Format
   value?: Format
@@ -14,6 +16,7 @@ const FormatSelector = ({
   name = 'format',
   name = 'format',
   label = 'Format'
   label = 'Format'
 }: IFormatSelector) => {
 }: IFormatSelector) => {
+  const [modalState, setModalState] = useState(false)
   const formats = useFormatsQuery()
   const formats = useFormatsQuery()
   const id = value?.id
   const id = value?.id
 
 
@@ -59,11 +62,27 @@ const FormatSelector = ({
       <button
       <button
         type='button'
         type='button'
         onClick={event => {
         onClick={event => {
-          event.preventDefault()
+          setModalState(true)
         }}
         }}
       >
       >
         Add format
         Add format
       </button>
       </button>
+      <Modal state={[modalState, setModalState]}>
+        <AddFormat
+          onSuccess={result => {
+            setModalState(false)
+            if (result.data) {
+              onChange({
+                target: {
+                  type: 'custom',
+                  value: { connect: { id: result.data.createFormat.id } },
+                  name
+                }
+              })
+            }
+          }}
+        />
+      </Modal>
     </>
     </>
   )
   )
 }
 }

+ 4 - 0
frontend/src/training/types.ts

@@ -1,3 +1,5 @@
+import { Training } from '../gql'
+
 export interface ITraining {
 export interface ITraining {
   id: string
   id: string
   title: string
   title: string
@@ -16,6 +18,8 @@ export interface ITraining {
   blocks: IBlock[]
   blocks: IBlock[]
 }
 }
 
 
+export type TTraining = Pick<Training, 'id'> & Partial<Omit<Training, 'id'>>
+
 export interface IBlock {
 export interface IBlock {
   id: string
   id: string
   sequence?: number
   sequence?: number