瀏覽代碼

still not running.

Tomi Cvetic 5 年之前
父節點
當前提交
34f4c012f0

+ 1 - 1
backend/datamodel.prisma

@@ -22,7 +22,7 @@ type Training {
     title: String!
     type: TrainingType!
     createdAt: DateTime! @createdAt
-    trainingDate: DateTime
+    trainingDate: DateTime!
     location: String
     registrations: [User!]!
     attendance: Int

+ 20 - 0
frontend/pages/admin/training/[id].tsx

@@ -0,0 +1,20 @@
+import { useRouter } from 'next/router'
+import EditTraining from '../../../src/training/components/EditTraining'
+import { useTrainingQuery } from '../../../src/gql'
+
+const EditTrainingPage = () => {
+  const router = useRouter()
+  const { id } = router.query
+  const training = useTrainingQuery({
+    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} />
+  else return <p>Training {id} not found.</p>
+}
+
+export default EditTrainingPage

+ 22 - 0
frontend/pages/admin/training/index.tsx

@@ -0,0 +1,22 @@
+import Link from 'next/link'
+import { useTrainingsQuery } from '../../../src/gql'
+
+const TrainingsList = () => {
+  const { data, error, loading } = useTrainingsQuery()
+
+  if (error) return <p>Error loading trainings...</p>
+  if (loading) return <p>Loading data...</p>
+  return (
+    <ul>
+      {data?.trainings.map(training => (
+        <li key={training.id}>
+          <Link href='training/[id]' as={`training/${training.id}`}>
+            <a>{training.title}</a>
+          </Link>
+        </li>
+      ))}
+    </ul>
+  )
+}
+
+export default TrainingsList

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

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

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

@@ -4,11 +4,7 @@ import { useRouter } from 'next/router'
 const TrainingPage = () => {
   const router = useRouter()
 
-  return (
-    <EditTraining
-      id={typeof router.query.id === 'string' ? router.query.id : undefined}
-    />
-  )
+  return <p>Nothing here yet...</p>
 }
 
 export default TrainingPage

+ 9 - 2
frontend/src/form/components/Checkbox.tsx

@@ -1,14 +1,21 @@
 import { DetailedHTMLProps, InputHTMLAttributes } from 'react'
 
 type ICheckbox = {
-  value: boolean
+  value?: boolean
   label?: string
 } & Omit<
   DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>,
   'value'
 >
 
-const Checkbox = ({ name, label, id, value, type, ...props }: ICheckbox) => {
+const Checkbox = ({
+  name,
+  label,
+  id,
+  value = false,
+  type,
+  ...props
+}: ICheckbox) => {
   return (
     <>
       {label && <label htmlFor={id || name}>{label}</label>}

+ 0 - 1
frontend/src/timer/components/Timer.tsx

@@ -1,5 +1,4 @@
 import { useState, useEffect, useRef } from 'react'
-import { VideoJsPlayer } from 'video.js'
 
 import { ITraining } from '../../training/types'
 import { getExerciseList, getTrainingTime, getPosition } from '../utils'

+ 2 - 2
frontend/src/timer/components/VideoPlayer.tsx

@@ -7,7 +7,7 @@ interface IVideoPlayer {
 }
 
 const VideoPlayer = ({ getVideoHandle, src }: IVideoPlayer) => {
-  const videoPlayerRef = useRef()
+  const videoPlayerRef: any = useRef()
   const video: { current: VideoJsPlayer | undefined } = useRef()
 
   /**
@@ -38,7 +38,7 @@ const VideoPlayer = ({ getVideoHandle, src }: IVideoPlayer) => {
 
   return (
     <div data-vjs-player>
-      <video ref={videoPlayerRef as any} className='video-js vjs-16-9' />
+      <video ref={videoPlayerRef} className='video-js vjs-16-9' />
     </div>
   )
 }

+ 3 - 3
frontend/src/training/components/BlockInputs.tsx

@@ -6,13 +6,13 @@ import { emptyBlockInstance } from '../utils'
 
 interface IBlockInputs {
   onChange: GenericEventHandler
-  value?: Partial<BlockContentFragment>
+  value: Partial<BlockContentFragment>
   name: string
 }
 
 const BlockInputs = ({ onChange, value, name }: IBlockInputs) => {
   return (
-    <fieldset>
+    <>
       <TextInput
         name={`${name}.title`}
         label='Title'
@@ -68,7 +68,7 @@ const BlockInputs = ({ onChange, value, name }: IBlockInputs) => {
       >
         Add block
       </button>
-    </fieldset>
+    </>
   )
 }
 

+ 59 - 16
frontend/src/training/components/BlockInstanceInputs.tsx

@@ -3,17 +3,18 @@ import arrayMove from 'array-move'
 import BlockInputs from './BlockInputs'
 import { SortableList } from '../../sortable'
 import { SubBlockFragment } from '../../gql'
+import { TextInput } from '../../form'
 
 const BlockInstanceInputs = ({
+  value = [],
   name,
-  value,
   onChange
 }: {
-  name: string
   value?: Partial<SubBlockFragment>[]
+  name: string
   onChange: GenericEventHandler
 }) => {
-  const [state, setState] = useState(value.map((item, index) => index))
+  const [state, setState] = useState(value.map(item => item.id))
 
   function onSortEnd({
     oldIndex,
@@ -24,28 +25,70 @@ const BlockInstanceInputs = ({
   }) {
     const newOrder = arrayMove(state, oldIndex, newIndex)
     setState(newOrder)
+    const updatedValues = value.map(item => {
+      const order = newOrder.findIndex(orderedId => orderedId === item.id)
+      return { ...item, order }
+    })
+    onChange({
+      target: {
+        type: 'custom',
+        name,
+        value: updatedValues
+      }
+    })
   }
 
   useEffect(() => {
-    const missingIndices = []
-    for (let idx = 0; idx < value.length - 0; idx++) {
-      if (!state.includes(idx)) missingIndices.push(idx)
-    }
-    setState([...state, ...missingIndices])
+    const missingIds = value
+      .filter(item => !state.includes(item.id))
+      .map(item => item.id)
+    const stateWithoutRemovedItems = state.filter(stateId =>
+      value.find(item => stateId === item.id)
+    )
+    console.log('filtered!', {
+      value,
+      state,
+      missingIds,
+      stateWithoutRemovedItems
+    })
+    setState([...stateWithoutRemovedItems, ...missingIds])
   }, [value])
 
-  const items = state.map((order, index) => {
-    const item = value[order]
+  const items = state.map(stateId => {
+    const itemIndex = value.findIndex(item => item.id === stateId)
+    if (itemIndex < 0) return null
+    const item = value[itemIndex]
     return (
-      <BlockInputs
-        key={item.id}
-        name={`${name}.${order}.block`}
-        value={item.block}
-        onChange={onChange}
-      />
+      <div key={item.id}>
+        <p>
+          {item.order} {item.id}
+        </p>
+        <TextInput
+          name='rounds'
+          label='Rounds'
+          value={item.rounds}
+          type='number'
+          onChange={onChange}
+        />
+        <TextInput
+          name='variation'
+          label='Variation'
+          value={item.variation}
+          onChange={onChange}
+        />
+        {item.block && (
+          <BlockInputs
+            name={`${name}.${itemIndex}.block`}
+            value={item.block}
+            onChange={onChange}
+          />
+        )}
+        <button type='button'>Add block</button>
+      </div>
     )
   })
 
+  console.log({ name, items, value, state })
   return (
     <SortableList
       items={items}

+ 5 - 10
frontend/src/training/components/EditTraining.tsx

@@ -1,20 +1,15 @@
-import { useEffect } from 'react'
-import { useTrainingQuery, useCreateTrainingMutation } from '../../gql'
+import { useCreateTrainingMutation, Training } from '../../gql'
 import { useForm, TextInput, DateTimeInput, Checkbox } from '../../form'
 import { emptyTraining, emptyBlockInstance } from '../utils'
 import TrainingTypeSelector from './TrainingTypeSelector'
 import BlockInstanceInputs from './BlockInstanceInputs'
 
-const EditTraining = ({ id = '' }: { id?: string }) => {
-  const trainingData = useTrainingQuery({ variables: { id } })
-
-  const { values, touched, onChange, loadData } = useForm(emptyTraining())
+const EditTraining = ({ training }: { training?: Partial<Training> }) => {
+  const { values, touched, onChange, loadData } = useForm(
+    training || emptyTraining()
+  )
   const [createTraining, createData] = useCreateTrainingMutation()
 
-  useEffect(() => {
-    if (trainingData.data?.training) loadData(trainingData.data.training)
-  }, [trainingData.data])
-
   return (
     <>
       <form

+ 4 - 4
frontend/src/training/components/FormatSelector.tsx

@@ -2,7 +2,7 @@ import { useFormatsQuery, FormatCreateOneInput, Format } from '../../gql'
 import { useEffect } from 'react'
 
 interface IFormatSelector {
-  value: Format
+  value?: Format
   onChange: GenericEventHandler
   name?: string
   label?: string
@@ -15,7 +15,7 @@ const FormatSelector = ({
   label = 'Format'
 }: IFormatSelector) => {
   const formats = useFormatsQuery()
-  const { id } = value
+  const id = value?.id
 
   useEffect(() => {
     if (formats.data && formats.data.formats.length > 0 && !id) {
@@ -27,7 +27,7 @@ const FormatSelector = ({
         }
       })
     }
-  }, [formats])
+  }, [formats.data])
 
   return (
     <>
@@ -35,7 +35,7 @@ const FormatSelector = ({
       <select
         id={name}
         name={name}
-        value={id || undefined}
+        value={id}
         onChange={event => {
           const copy: CustomChangeEvent = {
             target: {

+ 2 - 0
frontend/src/training/components/Training.tsx

@@ -4,6 +4,8 @@ import TrainingBlock from './TrainingBlock'
 import Link from 'next/link'
 import { ITraining } from '../types'
 import TrainingMeta from './TrainingMeta'
+import { useRouter } from 'next/router'
+import { useTrainingLazyQuery } from '../../gql'
 
 const Training = ({ training }: { training: ITraining }) => {
   return (

+ 7 - 3
frontend/src/training/components/TrainingTypeSelector.tsx

@@ -4,7 +4,7 @@ import AddTrainingType from './AddTrainingType'
 import { useState, useEffect } from 'react'
 
 interface ITrainingTypeSelector {
-  value: TrainingType
+  value?: TrainingType
   onChange: GenericEventHandler
   name?: string
   label?: string
@@ -21,7 +21,11 @@ const TrainingTypeSelector = ({
   const id = value?.id
 
   useEffect(() => {
-    if (trainingTypes.data && trainingTypes.data.trainingTypes.length > 0) {
+    if (
+      trainingTypes.data &&
+      trainingTypes.data.trainingTypes.length > 0 &&
+      !id
+    ) {
       onChange({
         target: {
           type: 'custom',
@@ -30,7 +34,7 @@ const TrainingTypeSelector = ({
         }
       })
     }
-  }, [trainingTypes])
+  }, [trainingTypes.data])
 
   return (
     <>

+ 15 - 14
frontend/src/training/utils.ts

@@ -1,6 +1,11 @@
 import { parse } from 'date-fns'
 import { IBlock, IExercise, IRating } from './types'
-import { TrainingQuery, SubBlockFragment, BlockContentFragment } from '../gql'
+import {
+  TrainingQuery,
+  SubBlockFragment,
+  BlockContentFragment,
+  Training
+} from '../gql'
 
 /**
  * Takes a block of exercises and calculates the duration in seconds.
@@ -104,7 +109,7 @@ function randomID() {
   return `__${Math.random()
     .toString(36)
     .replace(/[^a-zA-Z0-9]+/g, '')
-    .substr(0, 11)}`
+    .substr(0, 10)}`
 }
 
 export function emptyBlock(input?: Partial<BlockContentFragment>) {
@@ -123,25 +128,21 @@ export function emptyBlock(input?: Partial<BlockContentFragment>) {
 export function emptyBlockInstance(input?: Partial<SubBlockFragment>) {
   const emptyBlockInstance: SubBlockFragment = {
     id: randomID(),
-    order: 0,
-    block: emptyBlock()
+    block: emptyBlock(),
+    order: 0
   }
   return { ...emptyBlockInstance, ...input }
 }
 
-export function emptyTraining(
-  input?: Partial<NonNullable<TrainingQuery['training']>>
-) {
-  const emptyTraining: NonNullable<TrainingQuery['training']> = {
+export function emptyTraining(input?: Partial<Training>) {
+  const emptyTraining: Partial<Training> = {
     id: randomID(),
-    createdAt: '',
     title: '',
-    location: '',
-    attendance: 0,
-    trainingDate: nextTime('Tuesday', '11:45'),
     type: { id: '', name: '', description: '' },
-    blocks: [] as SubBlockFragment[],
-    published: false
+    createdAt: '',
+    trainingDate: nextTime('Tuesday', '11:45'),
+    published: false,
+    blocks: []
   }
   return { ...emptyTraining, ...input }
 }