From 8e662c8594cb1e85591dfd1cc144c7b4cd2f4db1 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Fri, 27 Nov 2020 11:58:43 +0100
Subject: [PATCH] Update JSX and fix bugs

---
 src/App.test.tsx                             |  1 -
 src/App.tsx                                  |  1 -
 src/index.tsx                                |  6 +--
 src/routes/ContentRoute.tsx                  |  2 +-
 src/routes/main/MainPage.tsx                 |  2 +-
 src/routes/player/Player.tsx                 | 53 ++++++++++----------
 src/routes/player/PlayerError.tsx            |  2 -
 src/routes/player/PlayerLoading.tsx          |  2 -
 src/routes/player/PlayerPage.tsx             |  1 -
 src/routes/player/PreviewBar.tsx             |  2 +-
 src/routes/player/PreviewViewer.tsx          |  6 +--
 src/routes/player/SeekBar.tsx                |  8 +--
 src/routes/player/subtitles/TtmlRenderer.tsx |  2 +-
 src/routes/player/video/DashVideoElement.tsx | 47 ++++++++++++++---
 src/routes/player/video/RawVideoElement.tsx  |  4 +-
 src/routes/player/video/VideoElement.tsx     |  4 +-
 src/util/head/HeadPortal.tsx                 |  2 +-
 src/util/media/useTextTrackCues.ts           |  6 +--
 tsconfig.json                                |  3 +-
 19 files changed, 91 insertions(+), 63 deletions(-)

diff --git a/src/App.test.tsx b/src/App.test.tsx
index 4db7ebc..9a9be2e 100644
--- a/src/App.test.tsx
+++ b/src/App.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
 import { render } from '@testing-library/react';
 import App from './App';
 
diff --git a/src/App.tsx b/src/App.tsx
index 46aa883..be09b03 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
 import {BrowserRouter, Route} from 'react-router-dom';
 import {MainPage} from "./routes/main/MainPage";
 import {PlayerPage} from "./routes/player/PlayerPage";
diff --git a/src/index.tsx b/src/index.tsx
index e245541..33c5e0b 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,5 +1,5 @@
 import {produce} from 'immer'
-import React from 'react';
+import { StrictMode } from 'react';
 import ReactDOM from 'react-dom';
 
 import {defaults} from 'react-sweet-state';
@@ -15,9 +15,9 @@ defaults.devtools = process.env.NODE_ENV !== "production";
 defaults.mutator = (currentState, producer) => produce(currentState, producer)
 
 ReactDOM.render(
-    <React.StrictMode>
+    <StrictMode>
         <App/>
-    </React.StrictMode>,
+    </StrictMode>,
     document.getElementById('root')
 );
 
diff --git a/src/routes/ContentRoute.tsx b/src/routes/ContentRoute.tsx
index be5f46f..5d5b36a 100644
--- a/src/routes/ContentRoute.tsx
+++ b/src/routes/ContentRoute.tsx
@@ -1,4 +1,4 @@
-import React, {PropsWithChildren, useEffect, useState} from "react";
+import { PropsWithChildren, useEffect, useState } from "react";
 import {useParams} from "react-router";
 import {useApiClient} from "../api/ApiClientContext";
 import {ContentMeta} from "../api/models/dto/ContentMeta";
diff --git a/src/routes/main/MainPage.tsx b/src/routes/main/MainPage.tsx
index 3501ace..03d69bc 100644
--- a/src/routes/main/MainPage.tsx
+++ b/src/routes/main/MainPage.tsx
@@ -1,4 +1,4 @@
-import React, {useEffect, useState} from "react";
+import { useEffect, useState } from "react";
 import {createUseStyles} from "react-jss";
 import {Link} from "react-router-dom";
 import {useApiClient} from "../../api/ApiClientContext";
diff --git a/src/routes/player/Player.tsx b/src/routes/player/Player.tsx
index 25d15d1..c812b3e 100644
--- a/src/routes/player/Player.tsx
+++ b/src/routes/player/Player.tsx
@@ -1,4 +1,4 @@
-import React, {useState} from "react";
+import {useState} from "react";
 import {createUseStyles} from "react-jss";
 import {Link} from "react-router-dom";
 import {ContentMeta} from "../../api/models/dto/ContentMeta";
@@ -54,7 +54,10 @@ export function Player(
     return (
         <div>
             <Link to="/">Back</Link>
-            <p>{name?.name}</p>
+            <h2>{name?.name}</h2>
+            <p>{rating?.certification}</p>
+            <strong>{description?.tagline}</strong>
+            <p>{description?.overview}</p>
             <p>{instalment?.content && getLocalizedName(instalment?.content, locale)?.name}</p>
             <div className={classes.player}>
                 <div className={classes.playerCanvas}>
@@ -91,30 +94,28 @@ export function Player(
             <p style={{fontVariant: "tabular-nums"}}>{formatDuration(position)} / {formatDuration(duration)}</p>
             <button onClick={videoElement?.play}>Play</button>
             <button onClick={videoElement?.pause}>Pause</button>
-            <p>
-                Audio
-                <ul>
-                    {audioTracks.map(track => (
-                        <li key={track.index}>
-                            <strong>{track.lang}</strong>
-                            &nbsp;{track.labels}
-                            &nbsp;<button onClick={() => videoElement?.setAudioTrack(track)}>Choose</button>
-                        </li>
-                    ))}
-                </ul>
-            </p>
-            <p>
-                Subtitles
-                <ul>
-                    {content.subtitles.map(track => (
-                        <li key={track.src}>
-                            <strong>{track.language}</strong>
-                            &nbsp;{track.specifier}
-                            &nbsp;<button onClick={() => setSubtitle(track)}>Choose</button>
-                        </li>
-                    ))}
-                </ul>
-            </p>
+            <h3>Audio</h3>
+            <ul>
+                {audioTracks.map(track => (
+                    <li key={track.index}>
+                        <strong>{track.lang}</strong>
+                        &nbsp;{track.labels}
+                        &nbsp;
+                        <button onClick={() => videoElement?.setAudioTrack(track)}>Choose</button>
+                    </li>
+                ))}
+            </ul>
+            <h3>Subtitles</h3>
+            <ul>
+                {content.subtitles.map(track => (
+                    <li key={track.src}>
+                        <strong>{track.language}</strong>
+                        &nbsp;{track.specifier}
+                        &nbsp;
+                        <button onClick={() => setSubtitle(track)}>Choose</button>
+                    </li>
+                ))}
+            </ul>
             <SeekBar
                 video={videoElement}
                 previewTrack={previewTrack}
diff --git a/src/routes/player/PlayerError.tsx b/src/routes/player/PlayerError.tsx
index 6cec388..d6669c2 100644
--- a/src/routes/player/PlayerError.tsx
+++ b/src/routes/player/PlayerError.tsx
@@ -1,5 +1,3 @@
-import React from "react";
-
 export function PlayerError() {
     return (
         <div>Error</div>
diff --git a/src/routes/player/PlayerLoading.tsx b/src/routes/player/PlayerLoading.tsx
index ae71f1f..b11833e 100644
--- a/src/routes/player/PlayerLoading.tsx
+++ b/src/routes/player/PlayerLoading.tsx
@@ -1,5 +1,3 @@
-import React from "react";
-
 export function PlayerLoading() {
     return (
         <div>Loading</div>
diff --git a/src/routes/player/PlayerPage.tsx b/src/routes/player/PlayerPage.tsx
index eb96af0..d65c9eb 100644
--- a/src/routes/player/PlayerPage.tsx
+++ b/src/routes/player/PlayerPage.tsx
@@ -1,4 +1,3 @@
-import React from "react";
 import {getPlayableMedia} from "../../api/models/Content";
 import {usePlayabilityRating} from "../../util/mime/usePlayabilityRating";
 import {useCurrentContent} from "../../util/CurrentContentContext";
diff --git a/src/routes/player/PreviewBar.tsx b/src/routes/player/PreviewBar.tsx
index 27a6b62..9c5a7fe 100644
--- a/src/routes/player/PreviewBar.tsx
+++ b/src/routes/player/PreviewBar.tsx
@@ -1,4 +1,4 @@
-import React, {useMemo} from "react";
+import { useMemo } from "react";
 import {createUseStyles} from "react-jss";
 import {MousePosition} from "../../util/mouse/MousePosition";
 import {useOffsetAbsoluteRef} from "../../util/offset/useOffsetAbsoluteRef";
diff --git a/src/routes/player/PreviewViewer.tsx b/src/routes/player/PreviewViewer.tsx
index 9928f52..4649bb4 100644
--- a/src/routes/player/PreviewViewer.tsx
+++ b/src/routes/player/PreviewViewer.tsx
@@ -1,4 +1,4 @@
-import React, {useMemo} from "react";
+import { Fragment, useMemo } from "react";
 import {createUseStyles} from "react-jss";
 import {HeadPortal} from "../../util/head/HeadPortal";
 import {useImage} from "../../util/media/useImage";
@@ -26,14 +26,14 @@ export function PreviewViewer({previewTrack, position}: Props) {
         return url.toString();
     }))), [cues, previewTrack]);
     return useMemo(() => (
-        <React.Fragment>
+        <Fragment>
             <HeadPortal>
                 {sources?.map(it => (
                     <link key={it} rel="preload" href={it} as="image" crossOrigin="anonymous"/>
                 ))}
             </HeadPortal>
             <img alt="" className={classes.preview} src={sprite || undefined}/>
-        </React.Fragment>
+        </Fragment>
     ), [classes.preview, sources, sprite]);
 }
 
diff --git a/src/routes/player/SeekBar.tsx b/src/routes/player/SeekBar.tsx
index 90bcbda..b77d4de 100644
--- a/src/routes/player/SeekBar.tsx
+++ b/src/routes/player/SeekBar.tsx
@@ -1,4 +1,4 @@
-import React, {MouseEvent, useCallback, useMemo, useState} from "react";
+import { Fragment, MouseEvent, useCallback, useMemo, useState } from "react";
 import {createUseStyles} from "react-jss";
 import {getMousePosition} from "../../util/mouse/getMousePosition";
 import {MousePosition} from "../../util/mouse/MousePosition";
@@ -79,7 +79,7 @@ export function SeekBar({video, previewTrack, duration, position}: Props) {
     ), [classes.seekBar, onClick, onMouseLeave, onMouseMove, playHead, seekHead]);
 
     return (
-        <React.Fragment>
+        <Fragment>
             <PreviewBar
                 previewTrack={previewTrack}
                 duration={duration}
@@ -87,8 +87,8 @@ export function SeekBar({video, previewTrack, duration, position}: Props) {
                 hidden={mousePosition === null}
             />
             {seekBar}
-        </React.Fragment>
-    )
+        </Fragment>
+    );
 }
 
 const useStyles = createUseStyles({
diff --git a/src/routes/player/subtitles/TtmlRenderer.tsx b/src/routes/player/subtitles/TtmlRenderer.tsx
index 5f5b151..bd599e6 100644
--- a/src/routes/player/subtitles/TtmlRenderer.tsx
+++ b/src/routes/player/subtitles/TtmlRenderer.tsx
@@ -1,4 +1,4 @@
-import React, {useEffect, useState} from "react";
+import { useEffect, useState } from "react";
 import TtmlHelper from "./TtmlHelper";
 
 interface Props {
diff --git a/src/routes/player/video/DashVideoElement.tsx b/src/routes/player/video/DashVideoElement.tsx
index 84a0b3b..c6698ea 100644
--- a/src/routes/player/video/DashVideoElement.tsx
+++ b/src/routes/player/video/DashVideoElement.tsx
@@ -1,4 +1,4 @@
-import React, {PropsWithChildren, useEffect, useImperativeHandle, useMemo, useState} from "react";
+import {forwardRef, PropsWithChildren, useEffect, useImperativeHandle, useMemo, useState,} from "react";
 import {Media} from "../../../api/models/Media";
 import dashjs, {MediaInfo} from "dashjs";
 import {VideoApi} from "./VideoApi";
@@ -9,7 +9,7 @@ interface Props {
     className?: string,
 }
 
-export const DashVideoElement = React.forwardRef<VideoApi, PropsWithChildren<Props>>(function (
+export const DashVideoElement = forwardRef<VideoApi, PropsWithChildren<Props>>(function (
     {media, autoPlay, className, children},
     ref
 ) {
@@ -19,34 +19,64 @@ export const DashVideoElement = React.forwardRef<VideoApi, PropsWithChildren<Pro
     useImperativeHandle(ref, () => ({
         METADATA_EVENT: dashjs.MediaPlayer.events.PLAYBACK_METADATA_LOADED,
         TIMECHANGE_EVENT: dashjs.MediaPlayer.events.PLAYBACK_TIME_UPDATED,
-        play: () => {
+        play() {
+            if (!player.isReady()) {
+                return;
+            }
             player.play();
         },
-        pause: () => {
+        pause() {
+            if (!player.isReady()) {
+                return;
+            }
             player.pause();
         },
-        isPaused: () => {
+        isPaused() {
+            if (!player.isReady()) {
+                return true;
+            }
             return player.isPaused();
         },
-        setPlaybackRate: (value: number) => {
+        setPlaybackRate(value: number) {
+            if (!player.isReady()) {
+                return;
+            }
             player.setPlaybackRate(value);
         },
-        getPlaybackRate: () => {
+        getPlaybackRate(): number {
+            if (!player.isReady()) {
+                return 1;
+            }
             return player.getPlaybackRate();
         },
         setCurrentTime(value: number) {
+            if (!player.isReady()) {
+                return;
+            }
             player.seek(value);
         },
         getCurrentTime(): number {
+            if (!player.isReady()) {
+                return 0;
+            }
             return player.time();
         },
         getDuration(): number {
+            if (!player.isReady()) {
+                return 0;
+            }
             return player.duration();
         },
         canPlay(): boolean {
+            if (!player.isReady()) {
+                return false;
+            }
             return !Number.isNaN(player.duration());
         },
         setAudioTrack(track: MediaInfo) {
+            if (!player.isReady()) {
+                return;
+            }
             player.setQualityFor("audio", 0);
             player.setCurrentTrack(track);
         },
@@ -57,6 +87,9 @@ export const DashVideoElement = React.forwardRef<VideoApi, PropsWithChildren<Pro
             player.off(event, listener);
         },
         getAudioTracks(): MediaInfo[] {
+            if (!player.isReady()) {
+                return [];
+            }
             return player.getTracksFor("audio").map((info: MediaInfo) => {
                 return info;
             })
diff --git a/src/routes/player/video/RawVideoElement.tsx b/src/routes/player/video/RawVideoElement.tsx
index 4dba70e..b957682 100644
--- a/src/routes/player/video/RawVideoElement.tsx
+++ b/src/routes/player/video/RawVideoElement.tsx
@@ -1,4 +1,4 @@
-import React, {PropsWithChildren, useImperativeHandle, useState} from "react";
+import { forwardRef, PropsWithChildren, useImperativeHandle, useState } from "react";
 import {Media} from "../../../api/models/Media";
 import {VideoApi} from "./VideoApi";
 import {MediaInfo} from "dashjs";
@@ -9,7 +9,7 @@ interface Props {
     className?: string,
 }
 
-export const RawVideoElement = React.forwardRef<VideoApi, PropsWithChildren<Props>>(function (
+export const RawVideoElement = forwardRef<VideoApi, PropsWithChildren<Props>>(function (
     {media, autoPlay, className, children},
     ref
 ) {
diff --git a/src/routes/player/video/VideoElement.tsx b/src/routes/player/video/VideoElement.tsx
index 99c9c48..526b40a 100644
--- a/src/routes/player/video/VideoElement.tsx
+++ b/src/routes/player/video/VideoElement.tsx
@@ -1,4 +1,4 @@
-import React, {PropsWithChildren} from "react";
+import { forwardRef, PropsWithChildren } from "react";
 import {Media} from "../../../api/models/Media";
 import {DashVideoElement} from "./DashVideoElement";
 import {RawVideoElement} from "./RawVideoElement";
@@ -10,7 +10,7 @@ interface Props {
     className?: string,
 }
 
-export const VideoElement = React.forwardRef<VideoApi, PropsWithChildren<Props>>(function (
+export const VideoElement = forwardRef<VideoApi, PropsWithChildren<Props>>(function (
     props: Props, ref
 ) {
     switch (props.media.mime) {
diff --git a/src/util/head/HeadPortal.tsx b/src/util/head/HeadPortal.tsx
index 8b70c22..f35b2ef 100644
--- a/src/util/head/HeadPortal.tsx
+++ b/src/util/head/HeadPortal.tsx
@@ -1,4 +1,4 @@
-import React from "react";
+import * as React from "react";
 import ReactDOM from "react-dom";
 
 export function HeadPortal({children}: React.PropsWithChildren<{}>) {
diff --git a/src/util/media/useTextTrackCues.ts b/src/util/media/useTextTrackCues.ts
index 557a774..b4e1d6d 100644
--- a/src/util/media/useTextTrackCues.ts
+++ b/src/util/media/useTextTrackCues.ts
@@ -1,17 +1,17 @@
 import {useEffect, useState} from "react";
 
 export const useTextTrackCues = (track: HTMLTrackElement | null) => {
-    const [cues, setCues] = useState<TextTrackCue[]>([]);
+    const [cues, setCues] = useState<VTTCue[]>([]);
     useEffect(() => {
         if (track !== null) {
             track.track.mode = "hidden";
             if (track.readyState >= 1) {
-                setCues(Array.from(track.track.cues || []))
+                setCues(Array.from(track.track.cues || []) as VTTCue[])
             } else {
                 let animationFrame: number | null = null;
                 const listener = () => {
                     animationFrame = window.requestAnimationFrame(() => {
-                        setCues(Array.from(track.track.cues || []))
+                        setCues(Array.from(track.track.cues || []) as VTTCue[])
                     })
                 };
                 track.addEventListener("load", listener)
diff --git a/tsconfig.json b/tsconfig.json
index f2850b7..e18c413 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -17,7 +17,8 @@
     "resolveJsonModule": true,
     "isolatedModules": true,
     "noEmit": true,
-    "jsx": "react"
+    "jsx": "react-jsx",
+    "noFallthroughCasesInSwitch": true
   },
   "include": [
     "src"
-- 
GitLab