Tomi Cvetic пре 4 година
родитељ
комит
9f917b20cd

+ 0 - 5
frontend/pages/index.tsx

@@ -34,9 +34,6 @@ const Home = () => {
 
         <style jsx>
           {`
-            .next-training {
-              padding: 1em 0.3em;
-            }
             .training-title {
               grid-area: title;
               margin: 0.3em 0;
@@ -79,7 +76,6 @@ const Home = () => {
                   'program  program'
                   'archive  archive';
                 column-gap: 1em;
-                padding: 2em 3em;
               }
             }
             @media (min-width: 1024px) {
@@ -92,7 +88,6 @@ const Home = () => {
                   'info     program'
                   'archive  program';
                 column-gap: 2em;
-                padding: 2em 3em;
               }
               .training-title {
                 font-size: 8rem;

+ 1 - 1
frontend/pages/timer/[id].tsx

@@ -9,7 +9,7 @@ const TimerPage = () => {
   const { id } = router.query
 
   const { data, error, loading } = useTrainingQuery({
-    variables: { id: typeof id === 'string' ? id : id[0] },
+    variables: { id: typeof id === 'string' ? id : id && id[0] },
   })
 
   return (

+ 7 - 2
frontend/src/app/components/Page.tsx

@@ -7,13 +7,18 @@ import { UserContext } from '../../user/hooks'
 import { LoginPage } from '../../user'
 
 const Page: FunctionComponent = ({ children }) => {
-  const user = useContext(UserContext)
+  const { user } = useContext(UserContext)
   return (
     <>
       <Meta />
 
       <Header />
-      <main>{user.user?.data?.currentUser ? children : <LoginPage />}</main>
+      <main>
+        {(!user || user.loading) && <p>Please wait...</p>}
+        {user?.error && <p>Error logging in.</p>}
+        {!user?.data && <LoginPage />}
+        {children}
+      </main>
       <Footer />
 
       <style jsx global>

+ 9 - 12
frontend/src/styles/global.ts

@@ -29,7 +29,7 @@ const GlobalStyle = css.global`
       'header'
       'main'
       'footer';
-    grid-template-rows: auto 1fr minmax(140px, auto);
+    grid-template-rows: auto 1fr minmax(75px, auto);
 
     min-height: 100vh;
 
@@ -38,23 +38,14 @@ const GlobalStyle = css.global`
     box-shadow: ${theme.bs};
   }
 
-  @media (min-width: 500px) {
-    body #__next {
-      grid-template-areas:
-        'header header'
-        'main main'
-        'footer footer';
-      grid-template-columns: auto 1fr;
-      grid-template-rows: auto 1fr minmax(75px, auto);
-    }
-  }
-
   header {
     grid-area: header;
   }
   main {
     grid-area: main;
+    padding: 1em 0.3em;
   }
+
   footer {
     grid-area: footer;
   }
@@ -75,6 +66,12 @@ const GlobalStyle = css.global`
     font-family: 'Roboto Mono', monospace;
   }
 
+  @media (min-width: 480px) {
+    main {
+      padding: 2em 3em;
+    }
+  }
+
   form * {
     font-size: 120%;
     padding: 0.3em 0.8em;

+ 9 - 42
frontend/src/timer/components/Countdown.tsx

@@ -10,18 +10,9 @@ interface ICountdown {
   onClick: () => void
 }
 
-const Countdown = ({
-  seconds,
-  totalPercent,
-  exercisePercent,
-  onClick
-}: ICountdown) => {
+const Countdown = ({ seconds, totalPercent, exercisePercent, onClick }: ICountdown) => {
   const [color, setColor] = useState('rgba(55,55,55,1)')
-  const [intSeconds, setIntSeconds] = useState(0)
-
-  useEffect(() => {
-    setIntSeconds(Math.ceil(seconds))
-  }, [seconds])
+  const intSeconds = Math.ceil(seconds)
 
   useEffect(() => {
     if (intSeconds <= 5) {
@@ -38,50 +29,26 @@ const Countdown = ({
   }
 
   return (
-    <div id='timer' style={{ color }} onClick={onClick}>
+    <div id='timer' onClick={onClick}>
       <svg>
-        <text
-          textAnchor='middle'
-          alignmentBaseline='central'
-          y='185'
-          x='150'
-          fill={color}
-        >
+        <text textAnchor='middle' alignmentBaseline='central' y='185' x='150' fill={color}>
           {formatTime(intSeconds)}
         </text>
-        <circle
-          cx='150'
-          cy='150'
-          r='140'
-          fill='none'
-          stroke='#aa333344'
-          strokeWidth='5'
-        />
-        <circle
-          cx='150'
-          cy='150'
-          r='130'
-          fill='none'
-          stroke='#3333aa44'
-          strokeWidth='5'
-        />
+        <circle cx='150' cy='150' r='140' fill='none' stroke='#aa333344' strokeWidth='5' />
+        <circle cx='150' cy='150' r='130' fill='none' stroke='#3333aa44' strokeWidth='5' />
         <path
           d={describeArc(150, 150, 140, 0, limit(totalPercent * 360, 0, 359))}
           fill='none'
           stroke='#aa3333ff'
           strokeWidth='8'
+          className='redPath'
         />
         <path
-          d={describeArc(
-            150,
-            150,
-            130,
-            0,
-            limit(exercisePercent * 360, 0, 359)
-          )}
+          d={describeArc(150, 150, 130, 0, limit(exercisePercent * 360, 0, 359))}
           fill='none'
           stroke='#3333aaff'
           strokeWidth='8'
+          className='bluePath'
         />
       </svg>
 

+ 21 - 31
frontend/src/timer/components/Timer.tsx

@@ -12,12 +12,12 @@ import { useVideo } from '../hooks/useVideo'
 import theme from '../../styles/theme'
 
 const Timer = ({ training }: { training: TTraining }) => {
-  const [time, timer] = useTimer({ tickPeriod: 100 })
+  const [time, timer] = useTimer()
   const voice = useVoice('rosie')
 
   const [state, setState] = useState({
     exerciseList: [] as IExerciseItem[],
-    totalTime: 0
+    totalTime: 0,
   })
 
   useEffect(() => {
@@ -25,32 +25,32 @@ const Timer = ({ training }: { training: TTraining }) => {
     const exerciseList = getExerciseList(training.blocks)
     const totalTime = getTrainingTime(exerciseList)
     setState({ ...state, exerciseList, totalTime })
-    console.log(training, exerciseList, totalTime)
   }, [training])
 
-  const {
-    currentExercise,
-    previousExercise,
-    nextExercise,
-    exerciseTime
-  } = getPosition(state.exerciseList, timer.time)
+  const { currentExercise, previousExercise, nextExercise, exerciseTime } = getPosition(
+    state.exerciseList,
+    time
+  )
 
   const videoSrc =
-    (currentExercise?.videos &&
-      currentExercise.videos.length > 0 &&
-      currentExercise.videos[0]) ||
+    (currentExercise?.videos && currentExercise.videos.length > 0 && currentExercise.videos[0]) ||
     '/media/block0.mp4'
   const [videoRef, videoPlayer] = useVideo(videoSrc)
+  if (videoPlayer) {
+    videoPlayer.on('seeked', (args) => console.log('seeked!', videoPlayer.currentTime()))
+    videoPlayer.on('pause', () => console.log('paused'))
+    videoPlayer.on('play', () => console.log('play'))
+    videoPlayer.on('loaded', () => console.log('duration', videoPlayer.duration()))
+  }
 
   useEffect(() => {
     if (time > state.totalTime) stopTimer()
     const countdown = currentExercise
-      ? currentExercise.duration + currentExercise.offset - timer.intTime + 1
+      ? currentExercise.duration + currentExercise.offset - time + 1
       : 0
     if (timer.running && voice && !voice.playing()) {
       if (exerciseTime < 1) {
-        if (currentExercise && currentExercise.exercise !== 'Rest')
-          voice.play('go')
+        if (currentExercise && currentExercise.exercise !== 'Rest') voice.play('go')
         else voice.play('rest')
       } else if (countdown === 90) voice.play('ninety')
       else if (countdown === 60) voice.play('sixty')
@@ -93,13 +93,9 @@ const Timer = ({ training }: { training: TTraining }) => {
       <h1>{(currentExercise && currentExercise.toplevelBlock) || 'Torture'}</h1>
       <div id='flow'>
         <Countdown
-          seconds={
-            currentExercise ? currentExercise.duration - exerciseTime : 0
-          }
-          totalPercent={timer.time / state.totalTime}
-          exercisePercent={
-            exerciseTime / (currentExercise ? currentExercise.duration : 1)
-          }
+          seconds={currentExercise ? currentExercise.duration - exerciseTime : 0}
+          totalPercent={time / state.totalTime}
+          exercisePercent={exerciseTime / (currentExercise ? currentExercise.duration : 1)}
           onClick={timer.running ? stopTimer : startTimer}
         />
         <div id='controls'>
@@ -116,21 +112,15 @@ const Timer = ({ training }: { training: TTraining }) => {
           </button>
         </div>
         <h2>current exercise</h2>
-        <p className='exercise'>
-          {currentExercise ? currentExercise.exercise : '😎'}
-        </p>
+        <p className='exercise'>{currentExercise ? currentExercise.exercise : '😎'}</p>
         <h2>next up</h2>
-        <p className='exercise'>
-          {nextExercise ? nextExercise.exercise : '😎'}
-        </p>
+        <p className='exercise'>{nextExercise ? nextExercise.exercise : '😎'}</p>
       </div>
       <div id='description'>
         <div data-vjs-player>
           <video ref={videoRef} className='video-js vjs-16-9' />
         </div>
-        <p className='description'>
-          {currentExercise && currentExercise.description}
-        </p>
+        <p className='description'>{currentExercise && currentExercise.description}</p>
       </div>
 
       <style jsx>{`

+ 10 - 18
frontend/src/timer/hooks/useTimer.tsx

@@ -1,13 +1,8 @@
 import { useState, useEffect, useRef } from 'react'
 
-interface ITimer {
-  tickPeriod?: number
-}
-
 interface ITimerHandler {
   running: boolean
   time: number
-  intTime: number
   start: () => void
   stop: () => void
   reset: () => void
@@ -18,12 +13,9 @@ interface ITimeoutRef {
   current: ReturnType<typeof setTimeout> | undefined
 }
 
-export const useTimer = (args?: ITimer): [number, ITimerHandler] => {
-  const { tickPeriod } = { tickPeriod: 100, ...args }
-
+export const useTimer = (tickPeriod = 1000): [number, ITimerHandler] => {
   const [running, setRunning] = useState(false)
   const [time, setTime] = useState(0)
-  const [intTime, setIntTime] = useState(0)
 
   const timeout: ITimeoutRef = useRef()
   const lastTick = useRef(Date.now())
@@ -31,28 +23,29 @@ export const useTimer = (args?: ITimer): [number, ITimerHandler] => {
 
   useEffect(() => {
     if (!running) return
-    timeout.current = setTimeout(tick, tickPeriod - timeBuffer.current)
+    const delta = time - Math.round(time)
+    console.log('new timeout', tickPeriod - timeBuffer.current - delta * 1000)
+    timeout.current = setTimeout(tick, tickPeriod - timeBuffer.current - delta * 1000)
     timeBuffer.current = 0
   }, [time, running])
 
   function tick() {
-    const elapsedTime = Date.now() - lastTick.current
-    lastTick.current = Date.now()
+    const now = Date.now()
+    const elapsedTime = now - lastTick.current
+    lastTick.current = now
     const newTime = (time * 1000 + elapsedTime) / 1000
     setTime(newTime)
-    setIntTime(Math.ceil(newTime))
   }
 
   function start() {
-    console.log('start')
     lastTick.current = Date.now()
     setRunning(true)
   }
 
   function stop() {
-    console.log('stop')
     if (timeout.current) clearTimeout(timeout.current)
     timeBuffer.current = Date.now() - lastTick.current
+    console.log('stopped', time)
     setRunning(false)
   }
 
@@ -63,12 +56,11 @@ export const useTimer = (args?: ITimer): [number, ITimerHandler] => {
   const handler = {
     running,
     time,
-    intTime,
     start,
     stop,
     reset,
-    setTime
+    setTime,
   }
 
-  return [intTime, handler]
+  return [time, handler]
 }

+ 0 - 2
frontend/src/timer/utils.ts

@@ -67,7 +67,6 @@ export function getExerciseList(
         }
         return blockArray.flat()
       } else if (block.exercises) {
-        console.log('found exercises', block.exercises)
         const blockArray: IExerciseItem[] = []
         const newItem = {
           exercise: block.exercises
@@ -89,7 +88,6 @@ export function getExerciseList(
           blockArray.push({ ...newItem, offset })
           offset += newItem.duration
         }
-        console.log(newItem, blockArray)
         return blockArray.flat()
       }
     })

+ 3 - 4
frontend/src/user/components/UserNav.tsx

@@ -14,7 +14,7 @@ const UserNav = () => {
     <li>
       <a
         href=''
-        onClick={ev => {
+        onClick={(ev) => {
           ev.preventDefault()
           setMenu(!menu)
         }}
@@ -25,7 +25,7 @@ const UserNav = () => {
 
       {menu ? (
         <section className='usermenu'>
-          {user?.data ? (
+          {user?.data && (
             <>
               <h2>Welcome, {user.data.currentUser.name}</h2>
               <Link href={{ pathname: 'user' }}>
@@ -33,9 +33,8 @@ const UserNav = () => {
               </Link>
               <LogoutButton />
             </>
-          ) : (
-            <LoginForm />
           )}
+          {user?.error && <LoginForm />}
         </section>
       ) : null}
     </li>