From 6c7cc110388b51641b59d40a4153b13ea3b9fb72 Mon Sep 17 00:00:00 2001 From: Lukas Heiligenbrunner Date: Fri, 22 Jan 2021 21:05:21 +0000 Subject: [PATCH] typescriptify Popupbase focus textfield on filterclick --- api/src/handlers/Settings.php | 8 +-- src/App.tsx | 10 +-- src/api/VideoTypes.ts | 31 -------- src/elements/ActorTile/ActorTile.tsx | 2 +- .../{InfoHeaderItem.js => InfoHeaderItem.tsx} | 15 +++- .../Popups/AddActorPopup/AddActorPopup.tsx | 15 ++-- .../{AddTagPopup.js => AddTagPopup.tsx} | 30 +++++--- .../Popups/NewActorPopup/NewActorPopup.tsx | 2 +- .../{NewTagPopup.js => NewTagPopup.tsx} | 23 +++--- .../Popups/{PopupBase.js => PopupBase.tsx} | 41 +++++++---- .../Preview/{Preview.js => Preview.tsx} | 31 ++++---- src/elements/Tag/Tag.tsx | 2 +- .../VideoContainer/VideoContainer.tsx | 6 +- src/{index.js => index.tsx} | 2 +- .../ActorOverviewPage/ActorOverviewPage.tsx | 2 +- src/pages/ActorPage/ActorPage.tsx | 14 ++-- src/pages/CategoryPage/CategoryPage.tsx | 11 ++- src/pages/CategoryPage/CategoryView.tsx | 6 +- src/pages/CategoryPage/TagView.tsx | 5 +- src/pages/HomePage/HomePage.tsx | 16 ++--- src/pages/HomePage/SearchHandling.tsx | 6 +- src/pages/Player/Player.tsx | 7 +- src/pages/RandomPage/RandomPage.tsx | 7 +- ...GeneralSettings.js => GeneralSettings.tsx} | 72 ++++++++++++------- .../{MovieSettings.js => MovieSettings.tsx} | 46 +++++++----- src/types/ApiTypes.ts | 66 +++++++++++++++++ src/{api => types}/GeneralTypes.ts | 0 src/types/VideoTypes.ts | 15 ++++ src/utils/Api.ts | 2 +- 29 files changed, 303 insertions(+), 190 deletions(-) delete mode 100644 src/api/VideoTypes.ts rename src/elements/InfoHeaderItem/{InfoHeaderItem.js => InfoHeaderItem.tsx} (78%) rename src/elements/Popups/AddTagPopup/{AddTagPopup.js => AddTagPopup.tsx} (65%) rename src/elements/Popups/NewTagPopup/{NewTagPopup.js => NewTagPopup.tsx} (68%) rename src/elements/Popups/{PopupBase.js => PopupBase.tsx} (74%) rename src/elements/Preview/{Preview.js => Preview.tsx} (78%) rename src/{index.js => index.tsx} (83%) rename src/pages/SettingsPage/{GeneralSettings.js => GeneralSettings.tsx} (82%) rename src/pages/SettingsPage/{MovieSettings.js => MovieSettings.tsx} (70%) create mode 100644 src/types/ApiTypes.ts rename src/{api => types}/GeneralTypes.ts (100%) create mode 100644 src/types/VideoTypes.ts diff --git a/api/src/handlers/Settings.php b/api/src/handlers/Settings.php index a0c9edc..cf78e8c 100644 --- a/api/src/handlers/Settings.php +++ b/api/src/handlers/Settings.php @@ -98,9 +98,9 @@ class Settings extends RequestBase { WHERE 1"; if ($this->conn->query($query) === true) { - $this->commitMessage('{"success": true}'); + $this->commitMessage('{"result": "success"}'); } else { - $this->commitMessage('{"success": true}'); + $this->commitMessage('{"result": "success"}'); } }); } @@ -127,9 +127,9 @@ class Settings extends RequestBase { $cmd = 'php extractvideopreviews.php'; exec(sprintf("%s > %s 2>&1 & echo $! >> %s", $cmd, '/dev/zero', '/tmp/openmediacenterpid')); - $this->commitMessage('{"success": true}'); + $this->commitMessage('{"result": "success"}'); } else { - $this->commitMessage('{"success": false}'); + $this->commitMessage('{"result": "success"}'); } }); diff --git a/src/App.tsx b/src/App.tsx index 524af94..5d48df6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -16,6 +16,7 @@ import {BrowserRouter as Router, NavLink, Route, Switch} from 'react-router-dom' import Player from './pages/Player/Player'; import ActorOverviewPage from './pages/ActorOverviewPage/ActorOverviewPage'; import ActorPage from './pages/ActorPage/ActorPage'; +import {SettingsTypes} from './types/ApiTypes'; interface state { generalSettingsLoaded: boolean; @@ -24,13 +25,6 @@ interface state { onapierror: boolean; } -interface initialApiCallData { - DarkMode: boolean; - passwordEnabled: boolean; - mediacenter_name: string; - -} - /** * The main App handles the main tabs and which content to show */ @@ -47,7 +41,7 @@ class App extends React.Component<{}, state> { initialAPICall(): void { // this is the first api call so if it fails we know there is no connection to backend - callAPI('settings.php', {action: 'loadInitialData'}, (result: initialApiCallData) => { + callAPI('settings.php', {action: 'loadInitialData'}, (result: SettingsTypes.initialApiCallData) => { // set theme GlobalInfos.enableDarkTheme(result.DarkMode); diff --git a/src/api/VideoTypes.ts b/src/api/VideoTypes.ts deleted file mode 100644 index 998ca5c..0000000 --- a/src/api/VideoTypes.ts +++ /dev/null @@ -1,31 +0,0 @@ -export interface loadVideoType { - movie_url: string - thumbnail: string - movie_id: number - movie_name: string - likes: number - quality: number - length: number - tags: TagType[] - suggesttag: TagType[] - actors: ActorType[] -} - -export interface VideoUnloadedType { - movie_id: number; - movie_name: string -} - -/** - * type accepted by Tag component - */ -export interface TagType { - tag_name: string - tag_id: number -} - -export interface ActorType { - thumbnail: string; - name: string; - actor_id: number; -} diff --git a/src/elements/ActorTile/ActorTile.tsx b/src/elements/ActorTile/ActorTile.tsx index 55b0229..a508a7b 100644 --- a/src/elements/ActorTile/ActorTile.tsx +++ b/src/elements/ActorTile/ActorTile.tsx @@ -3,7 +3,7 @@ import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faUser} from '@fortawesome/free-solid-svg-icons'; import React from 'react'; import {Link} from 'react-router-dom'; -import {ActorType} from '../../api/VideoTypes'; +import {ActorType} from '../../types/VideoTypes'; interface props { actor: ActorType; diff --git a/src/elements/InfoHeaderItem/InfoHeaderItem.js b/src/elements/InfoHeaderItem/InfoHeaderItem.tsx similarity index 78% rename from src/elements/InfoHeaderItem/InfoHeaderItem.js rename to src/elements/InfoHeaderItem/InfoHeaderItem.tsx index b8a65d3..ef773ab 100644 --- a/src/elements/InfoHeaderItem/InfoHeaderItem.js +++ b/src/elements/InfoHeaderItem/InfoHeaderItem.tsx @@ -2,14 +2,23 @@ import React from 'react'; import style from './InfoHeaderItem.module.css'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {Spinner} from 'react-bootstrap'; +import {IconDefinition} from '@fortawesome/fontawesome-common-types'; + +interface props { + onClick?: () => void + backColor: string + icon: IconDefinition + text: string | number + subtext: string | number +} /** * a component to display one of the short quickinfo tiles on dashboard */ -class InfoHeaderItem extends React.Component { - render() { +class InfoHeaderItem extends React.Component { + render(): JSX.Element { return ( -
{ +
{ // call clicklistener if defined if (this.props.onClick != null) this.props.onClick(); }} className={style.infoheaderitem} style={{backgroundColor: this.props.backColor}}> diff --git a/src/elements/Popups/AddActorPopup/AddActorPopup.tsx b/src/elements/Popups/AddActorPopup/AddActorPopup.tsx index 0893cb9..a5a860f 100644 --- a/src/elements/Popups/AddActorPopup/AddActorPopup.tsx +++ b/src/elements/Popups/AddActorPopup/AddActorPopup.tsx @@ -4,8 +4,8 @@ import ActorTile from '../../ActorTile/ActorTile'; import style from './AddActorPopup.module.css'; import {NewActorPopupContent} from '../NewActorPopup/NewActorPopup'; import {callAPI} from '../../../utils/Api'; -import {ActorType} from '../../../api/VideoTypes'; -import {GeneralSuccess} from '../../../api/GeneralTypes'; +import {ActorType} from '../../../types/VideoTypes'; +import {GeneralSuccess} from '../../../types/GeneralTypes'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faFilter, faTimes} from '@fortawesome/free-solid-svg-icons'; import {Button} from '../../GPElements/Button'; @@ -26,6 +26,9 @@ interface state { * Popup for Adding a new Actor to a Video */ class AddActorPopup extends React.Component { + // filterfield anchor, needed to focus after filter btn click + private filterfield: HTMLInputElement | null | undefined; + constructor(props: props) { super(props); @@ -89,7 +92,8 @@ class AddActorPopup extends React.Component { type='text' placeholder='Filter' value={this.state.filter} onChange={(e): void => { this.setState({filter: e.target.value}); - }}/> + }} + ref={(input): void => {this.filterfield = input;}}/>
diff --git a/src/elements/Popups/AddTagPopup/AddTagPopup.js b/src/elements/Popups/AddTagPopup/AddTagPopup.tsx similarity index 65% rename from src/elements/Popups/AddTagPopup/AddTagPopup.js rename to src/elements/Popups/AddTagPopup/AddTagPopup.tsx index 57d21fb..9803fa5 100644 --- a/src/elements/Popups/AddTagPopup/AddTagPopup.js +++ b/src/elements/Popups/AddTagPopup/AddTagPopup.tsx @@ -2,19 +2,31 @@ import React from 'react'; import Tag from '../../Tag/Tag'; import PopupBase from '../PopupBase'; import {callAPI} from '../../../utils/Api'; +import {TagType} from '../../../types/VideoTypes'; +import {GeneralSuccess} from '../../../types/GeneralTypes'; + +interface props { + onHide: () => void; + submit: (tagId: number, tagName: string) => void; + movie_id: number; +} + +interface state { + items: TagType[]; +} /** * component creates overlay to add a new tag to a video */ -class AddTagPopup extends React.Component { - constructor(props, context) { - super(props, context); +class AddTagPopup extends React.Component { + constructor(props: props) { + super(props); this.state = {items: []}; } - componentDidMount() { - callAPI('tags.php', {action: 'getAllTags'}, (result) => { + componentDidMount(): void { + callAPI('tags.php', {action: 'getAllTags'}, (result: TagType[]) => { console.log(result); this.setState({ items: result @@ -22,13 +34,13 @@ class AddTagPopup extends React.Component { }); } - render() { + render(): JSX.Element { return ( {this.state.items ? this.state.items.map((i) => ( { + onclick={(): void => { this.addTag(i.tag_id, i.tag_name); }}/> )) : null} @@ -41,8 +53,8 @@ class AddTagPopup extends React.Component { * @param tagid tag id to add * @param tagname tag name to add */ - addTag(tagid, tagname) { - callAPI('tags.php', {action: 'addTag', id: tagid, movieid: this.props.movie_id}, result => { + addTag(tagid: number, tagname: string): void { + callAPI('tags.php', {action: 'addTag', id: tagid, movieid: this.props.movie_id}, (result: GeneralSuccess) => { if (result.result !== 'success') { console.log('error occured while writing to db -- todo error handling'); console.log(result.result); diff --git a/src/elements/Popups/NewActorPopup/NewActorPopup.tsx b/src/elements/Popups/NewActorPopup/NewActorPopup.tsx index 2114bce..5aead10 100644 --- a/src/elements/Popups/NewActorPopup/NewActorPopup.tsx +++ b/src/elements/Popups/NewActorPopup/NewActorPopup.tsx @@ -2,7 +2,7 @@ import React from 'react'; import PopupBase from '../PopupBase'; import style from './NewActorPopup.module.css'; import {callAPI} from '../../../utils/Api'; -import {GeneralSuccess} from '../../../api/GeneralTypes'; +import {GeneralSuccess} from '../../../types/GeneralTypes'; interface NewActorPopupProps { onHide: () => void; diff --git a/src/elements/Popups/NewTagPopup/NewTagPopup.js b/src/elements/Popups/NewTagPopup/NewTagPopup.tsx similarity index 68% rename from src/elements/Popups/NewTagPopup/NewTagPopup.js rename to src/elements/Popups/NewTagPopup/NewTagPopup.tsx index dd5f548..eb06ffd 100644 --- a/src/elements/Popups/NewTagPopup/NewTagPopup.js +++ b/src/elements/Popups/NewTagPopup/NewTagPopup.tsx @@ -2,24 +2,25 @@ import React from 'react'; import PopupBase from '../PopupBase'; import style from './NewTagPopup.module.css'; import {callAPI} from '../../../utils/Api'; +import {GeneralSuccess} from '../../../types/GeneralTypes'; + +interface props { + onHide: () => void +} /** * creates modal overlay to define a new Tag */ -class NewTagPopup extends React.Component { - constructor(props, context) { - super(props, context); +class NewTagPopup extends React.Component { + private value: string = ''; - this.props = props; - } - - render() { + render(): JSX.Element { return ( -
{ +
{ this.value = v.target.value; }}/>
- + ); } @@ -27,8 +28,8 @@ class NewTagPopup extends React.Component { /** * store the filled in form to the backend */ - storeselection() { - callAPI('tags.php', {action: 'createTag', tagname: this.value}, result => { + storeselection(): void { + callAPI('tags.php', {action: 'createTag', tagname: this.value}, (result: GeneralSuccess) => { if (result.result !== 'success') { console.log('error occured while writing to db -- todo error handling'); console.log(result.result); diff --git a/src/elements/Popups/PopupBase.js b/src/elements/Popups/PopupBase.tsx similarity index 74% rename from src/elements/Popups/PopupBase.js rename to src/elements/Popups/PopupBase.tsx index 0ff6f2f..7216b8e 100644 --- a/src/elements/Popups/PopupBase.js +++ b/src/elements/Popups/PopupBase.tsx @@ -1,13 +1,24 @@ import GlobalInfos from '../../utils/GlobalInfos'; import style from './PopupBase.module.css'; import {Line} from '../PageTitle/PageTitle'; -import React from 'react'; +import React, {RefObject} from 'react'; + +interface props { + width?: string; + height?: string; + banner?: JSX.Element; + title: string; + onHide: () => void +} /** * wrapper class for generic types of popups */ -class PopupBase extends React.Component { - constructor(props) { +class PopupBase extends React.Component { + private wrapperRef: RefObject; + private framedimensions: { minHeight: string | undefined; width: string | undefined; height: string | undefined }; + + constructor(props: props) { super(props); this.state = {items: []}; @@ -25,7 +36,7 @@ class PopupBase extends React.Component { }; } - componentDidMount() { + componentDidMount(): void { document.addEventListener('mousedown', this.handleClickOutside); document.addEventListener('keyup', this.keypress); @@ -35,13 +46,13 @@ class PopupBase extends React.Component { } } - componentWillUnmount() { + componentWillUnmount(): void { // remove the appended listeners document.removeEventListener('mousedown', this.handleClickOutside); document.removeEventListener('keyup', this.keypress); } - render() { + render(): JSX.Element { const themeStyle = GlobalInfos.getThemeStyle(); return (
@@ -61,8 +72,8 @@ class PopupBase extends React.Component { /** * Alert if clicked on outside of element */ - handleClickOutside(event) { - if (this.wrapperRef && !this.wrapperRef.current.contains(event.target)) { + handleClickOutside(event: MouseEvent): void { + if (this.wrapperRef && this.wrapperRef.current && !this.wrapperRef.current.contains(event.target as Node)) { this.props.onHide(); } } @@ -71,7 +82,7 @@ class PopupBase extends React.Component { * key event handling * @param event keyevent */ - keypress(event) { + keypress(event: KeyboardEvent): void { // hide if escape is pressed if (event.key === 'Escape') { this.props.onHide(); @@ -81,16 +92,17 @@ class PopupBase extends React.Component { /** * make the element drag and droppable */ - dragElement() { + dragElement(): void { let xOld = 0, yOld = 0; const elmnt = this.wrapperRef.current; if (elmnt === null) return; + if (elmnt.firstChild === null) return; - elmnt.firstChild.onmousedown = dragMouseDown; + (elmnt.firstChild as HTMLDivElement).onmousedown = dragMouseDown; - function dragMouseDown(e) { + function dragMouseDown(e: MouseEvent): void { e.preventDefault(); // get the mouse cursor position at startup: xOld = e.clientX; @@ -100,7 +112,7 @@ class PopupBase extends React.Component { document.onmousemove = elementDrag; } - function elementDrag(e) { + function elementDrag(e: MouseEvent): void { e.preventDefault(); // calculate the new cursor position: const dx = xOld - e.clientX; @@ -108,11 +120,12 @@ class PopupBase extends React.Component { xOld = e.clientX; yOld = e.clientY; // set the element's new position: + if (elmnt === null) return; elmnt.style.top = (elmnt.offsetTop - dy) + 'px'; elmnt.style.left = (elmnt.offsetLeft - dx) + 'px'; } - function closeDragElement() { + function closeDragElement(): void { // stop moving when mouse button is released: document.onmouseup = null; document.onmousemove = null; diff --git a/src/elements/Preview/Preview.js b/src/elements/Preview/Preview.tsx similarity index 78% rename from src/elements/Preview/Preview.js rename to src/elements/Preview/Preview.tsx index 1355b86..d077bbf 100644 --- a/src/elements/Preview/Preview.js +++ b/src/elements/Preview/Preview.tsx @@ -5,35 +5,42 @@ import {Link} from 'react-router-dom'; import GlobalInfos from '../../utils/GlobalInfos'; import {callAPIPlain} from '../../utils/Api'; +interface PreviewProps{ + name: string; + movie_id: number; +} + +interface PreviewState { + previewpicture: string | null; +} + /** * Component for single preview tile * floating side by side */ -class Preview extends React.Component { - constructor(props, context) { - super(props, context); +class Preview extends React.Component { + constructor(props: PreviewProps) { + super(props); this.state = { - previewpicture: null, - name: null + previewpicture: null }; } - componentDidMount() { + componentDidMount(): void { callAPIPlain('video.php', {action: 'readThumbnail', movieid: this.props.movie_id}, (result) => { this.setState({ - previewpicture: result, - name: this.props.name + previewpicture: result }); }); } - render() { + render(): JSX.Element { const themeStyle = GlobalInfos.getThemeStyle(); return (
-
{this.state.name}
+
{this.props.name}
{this.state.previewpicture !== null ? { + render(): JSX.Element { const themeStyle = GlobalInfos.getThemeStyle(); return (
void diff --git a/src/elements/VideoContainer/VideoContainer.tsx b/src/elements/VideoContainer/VideoContainer.tsx index 1ec22d6..bcd0737 100644 --- a/src/elements/VideoContainer/VideoContainer.tsx +++ b/src/elements/VideoContainer/VideoContainer.tsx @@ -1,14 +1,14 @@ import React from 'react'; import Preview from '../Preview/Preview'; import style from './VideoContainer.module.css'; -import {VideoUnloadedType} from '../../api/VideoTypes'; +import {VideoTypes} from '../../types/ApiTypes'; interface props { - data: VideoUnloadedType[] + data: VideoTypes.VideoUnloadedType[] } interface state { - loadeditems: VideoUnloadedType[]; + loadeditems: VideoTypes.VideoUnloadedType[]; selectionnr: number; } diff --git a/src/index.js b/src/index.tsx similarity index 83% rename from src/index.js rename to src/index.tsx index 219b67b..2a553e3 100644 --- a/src/index.js +++ b/src/index.tsx @@ -3,7 +3,7 @@ import ReactDOM from 'react-dom'; import App from './App'; // don't allow console logs within production env -global.console.log = process.env.NODE_ENV !== 'development' ? (s) => {} : global.console.log; +global.console.log = process.env.NODE_ENV !== 'development' ? (s: string | number | boolean): void => {} : global.console.log; ReactDOM.render( diff --git a/src/pages/ActorOverviewPage/ActorOverviewPage.tsx b/src/pages/ActorOverviewPage/ActorOverviewPage.tsx index 6fd9be6..4f5cd53 100644 --- a/src/pages/ActorOverviewPage/ActorOverviewPage.tsx +++ b/src/pages/ActorOverviewPage/ActorOverviewPage.tsx @@ -1,6 +1,6 @@ import React from 'react'; import {callAPI} from '../../utils/Api'; -import {ActorType} from '../../api/VideoTypes'; +import {ActorType} from '../../types/VideoTypes'; import ActorTile from '../../elements/ActorTile/ActorTile'; import PageTitle from '../../elements/PageTitle/PageTitle'; import SideBar from '../../elements/SideBar/SideBar'; diff --git a/src/pages/ActorPage/ActorPage.tsx b/src/pages/ActorPage/ActorPage.tsx index 4a5ca31..0126e67 100644 --- a/src/pages/ActorPage/ActorPage.tsx +++ b/src/pages/ActorPage/ActorPage.tsx @@ -6,13 +6,14 @@ import {faUser} from '@fortawesome/free-solid-svg-icons'; import style from './ActorPage.module.css'; import VideoContainer from '../../elements/VideoContainer/VideoContainer'; import {callAPI} from '../../utils/Api'; -import {ActorType, VideoUnloadedType} from '../../api/VideoTypes'; +import {ActorType} from '../../types/VideoTypes'; import {Link, withRouter} from 'react-router-dom'; import {RouteComponentProps} from 'react-router'; import {Button} from '../../elements/GPElements/Button'; +import {ActorTypes, VideoTypes} from '../../types/ApiTypes'; interface state { - data: VideoUnloadedType[], + data: VideoTypes.VideoUnloadedType[], actor: ActorType } @@ -22,13 +23,6 @@ interface state { interface props extends RouteComponentProps<{ id: string }> { } -/** - * result of actor fetch - */ -interface videofetchresult { - videos: VideoUnloadedType[]; - info: ActorType; -} /** * info page about a specific actor and a list of all its videos @@ -75,7 +69,7 @@ export class ActorPage extends React.Component { callAPI('actor.php', { action: 'getActorInfo', actorid: this.props.match.params.id - }, (result: videofetchresult) => { + }, (result: ActorTypes.videofetchresult) => { this.setState({ data: result.videos ? result.videos : [], actor: result.info diff --git a/src/pages/CategoryPage/CategoryPage.tsx b/src/pages/CategoryPage/CategoryPage.tsx index 37b7a83..3de5cd8 100644 --- a/src/pages/CategoryPage/CategoryPage.tsx +++ b/src/pages/CategoryPage/CategoryPage.tsx @@ -4,7 +4,7 @@ import Tag from '../../elements/Tag/Tag'; import NewTagPopup from '../../elements/Popups/NewTagPopup/NewTagPopup'; import PageTitle, {Line} from '../../elements/PageTitle/PageTitle'; import {Route, Switch} from 'react-router-dom'; -import {DefaultTags} from '../../api/GeneralTypes'; +import {DefaultTags} from '../../types/GeneralTypes'; import {CategoryViewWR} from './CategoryView'; import TagView from './TagView'; @@ -60,11 +60,10 @@ class CategoryPage extends React.Component<{}, CategoryPageState> { {this.state.popupvisible ? - { - this.setState({popupvisible: false}); - // this.loadTags(); - }}/> : + { + this.setState({popupvisible: false}); + // this.loadTags(); + }}/> : null } diff --git a/src/pages/CategoryPage/CategoryView.tsx b/src/pages/CategoryPage/CategoryView.tsx index 0288730..6171429 100644 --- a/src/pages/CategoryPage/CategoryView.tsx +++ b/src/pages/CategoryPage/CategoryView.tsx @@ -1,9 +1,9 @@ import {RouteComponentProps} from 'react-router'; import React from 'react'; -import {VideoUnloadedType} from '../../api/VideoTypes'; import VideoContainer from '../../elements/VideoContainer/VideoContainer'; import {callAPI} from '../../utils/Api'; import {withRouter} from 'react-router-dom'; +import {VideoTypes} from '../../types/ApiTypes'; interface CategoryViewProps extends RouteComponentProps<{ id: string }> { setSubTitle: (title: string) => void @@ -17,7 +17,7 @@ interface CategoryViewState { * plain class (for unit testing only) */ export class CategoryView extends React.Component { - private videodata: VideoUnloadedType[] = []; + private videodata: VideoTypes.VideoUnloadedType[] = []; constructor(props: CategoryViewProps) { super(props); @@ -60,7 +60,7 @@ export class CategoryView extends React.Component('video.php', {action: 'getMovies', tag: id}, result => { + callAPI('video.php', {action: 'getMovies', tag: id}, result => { this.videodata = result; this.setState({loaded: true}); this.props.setSubTitle(this.videodata.length + ' Videos'); diff --git a/src/pages/CategoryPage/TagView.tsx b/src/pages/CategoryPage/TagView.tsx index 0031653..28d00d4 100644 --- a/src/pages/CategoryPage/TagView.tsx +++ b/src/pages/CategoryPage/TagView.tsx @@ -1,4 +1,4 @@ -import {TagType} from '../../api/VideoTypes'; +import {TagType} from '../../types/VideoTypes'; import React from 'react'; import videocontainerstyle from '../../elements/VideoContainer/VideoContainer.module.css'; import {Link} from 'react-router-dom'; @@ -32,8 +32,7 @@ class TagView extends React.Component { this.state.loadedtags.map((m) => ( + name={m.tag_name}/> )) : 'loading'}
diff --git a/src/pages/HomePage/HomePage.tsx b/src/pages/HomePage/HomePage.tsx index 575c01e..123b371 100644 --- a/src/pages/HomePage/HomePage.tsx +++ b/src/pages/HomePage/HomePage.tsx @@ -7,9 +7,9 @@ import style from './HomePage.module.css'; import PageTitle, {Line} from '../../elements/PageTitle/PageTitle'; import {callAPI} from '../../utils/Api'; import {Route, Switch, withRouter} from 'react-router-dom'; -import {VideoUnloadedType} from '../../api/VideoTypes'; import {RouteComponentProps} from 'react-router'; import SearchHandling from './SearchHandling'; +import {VideoTypes} from '../../types/ApiTypes'; interface props extends RouteComponentProps {} @@ -22,18 +22,10 @@ interface state { tagnr: number }, subtitle: string, - data: VideoUnloadedType[], + data: VideoTypes.VideoUnloadedType[], selectionnr: number } -interface startDataData { - total: number; - fullhd: number; - hd: number; - sd: number; - tags: number; -} - /** * The home page component showing on the initial pageload */ @@ -71,7 +63,7 @@ export class HomePage extends React.Component { * @param tag tag to fetch videos */ fetchVideoData(tag: string): void { - callAPI('video.php', {action: 'getMovies', tag: tag}, (result: VideoUnloadedType[]) => { + callAPI('video.php', {action: 'getMovies', tag: tag}, (result: VideoTypes.VideoUnloadedType[]) => { this.setState({ data: [] }); @@ -87,7 +79,7 @@ export class HomePage extends React.Component { * fetch the necessary data for left info box */ fetchStartData(): void { - callAPI('video.php', {action: 'getStartData'}, (result: startDataData) => { + callAPI('video.php', {action: 'getStartData'}, (result: VideoTypes.startDataType) => { this.setState({ sideinfo: { videonr: result['total'], diff --git a/src/pages/HomePage/SearchHandling.tsx b/src/pages/HomePage/SearchHandling.tsx index 788e69a..8efea87 100644 --- a/src/pages/HomePage/SearchHandling.tsx +++ b/src/pages/HomePage/SearchHandling.tsx @@ -2,10 +2,10 @@ import {RouteComponentProps} from 'react-router'; import React from 'react'; import {withRouter} from 'react-router-dom'; import {callAPI} from '../../utils/Api'; -import {VideoUnloadedType} from '../../api/VideoTypes'; import VideoContainer from '../../elements/VideoContainer/VideoContainer'; import PageTitle from '../../elements/PageTitle/PageTitle'; import SideBar from '../../elements/SideBar/SideBar'; +import {VideoTypes} from '../../types/ApiTypes'; interface params { name: string; @@ -14,7 +14,7 @@ interface params { interface props extends RouteComponentProps {} interface state { - data: VideoUnloadedType[]; + data: VideoTypes.VideoUnloadedType[]; } export class SearchHandling extends React.Component { @@ -59,7 +59,7 @@ export class SearchHandling extends React.Component { * @param keyword The keyword to search for */ searchVideos(keyword: string): void { - callAPI('video.php', {action: 'getSearchKeyWord', keyword: keyword}, (result: VideoUnloadedType[]) => { + callAPI('video.php', {action: 'getSearchKeyWord', keyword: keyword}, (result: VideoTypes.VideoUnloadedType[]) => { this.setState({ data: result }); diff --git a/src/pages/Player/Player.tsx b/src/pages/Player/Player.tsx index c0996a9..d238a0b 100644 --- a/src/pages/Player/Player.tsx +++ b/src/pages/Player/Player.tsx @@ -15,10 +15,11 @@ import ActorTile from '../../elements/ActorTile/ActorTile'; import {withRouter} from 'react-router-dom'; import {callAPI, getBackendDomain} from '../../utils/Api'; import {RouteComponentProps} from 'react-router'; -import {GeneralSuccess} from '../../api/GeneralTypes'; -import {ActorType, loadVideoType, TagType} from '../../api/VideoTypes'; +import {GeneralSuccess} from '../../types/GeneralTypes'; +import {ActorType, TagType} from '../../types/VideoTypes'; import PlyrJS from 'plyr'; import {Button} from '../../elements/GPElements/Button'; +import {VideoTypes} from '../../types/ApiTypes'; interface myprops extends RouteComponentProps<{ id: string }> {} @@ -239,7 +240,7 @@ export class Player extends React.Component { * fetch all the required infos of a video from backend */ fetchMovieData(): void { - callAPI('video.php', {action: 'loadVideo', movieid: this.props.match.params.id}, (result: loadVideoType) => { + callAPI('video.php', {action: 'loadVideo', movieid: this.props.match.params.id}, (result: VideoTypes.loadVideoType) => { this.setState({ sources: { type: 'video', diff --git a/src/pages/RandomPage/RandomPage.tsx b/src/pages/RandomPage/RandomPage.tsx index 3ca1e83..41c23a6 100644 --- a/src/pages/RandomPage/RandomPage.tsx +++ b/src/pages/RandomPage/RandomPage.tsx @@ -5,15 +5,16 @@ import Tag from '../../elements/Tag/Tag'; import PageTitle from '../../elements/PageTitle/PageTitle'; import VideoContainer from '../../elements/VideoContainer/VideoContainer'; import {callAPI} from '../../utils/Api'; -import {TagType, VideoUnloadedType} from '../../api/VideoTypes'; +import {TagType} from '../../types/VideoTypes'; +import {VideoTypes} from '../../types/ApiTypes'; interface state { - videos: VideoUnloadedType[]; + videos: VideoTypes.VideoUnloadedType[]; tags: TagType[]; } interface GetRandomMoviesType { - rows: VideoUnloadedType[]; + rows: VideoTypes.VideoUnloadedType[]; tags: TagType[]; } diff --git a/src/pages/SettingsPage/GeneralSettings.js b/src/pages/SettingsPage/GeneralSettings.tsx similarity index 82% rename from src/pages/SettingsPage/GeneralSettings.js rename to src/pages/SettingsPage/GeneralSettings.tsx index caa04ac..f5ca066 100644 --- a/src/pages/SettingsPage/GeneralSettings.js +++ b/src/pages/SettingsPage/GeneralSettings.tsx @@ -7,37 +7,59 @@ import {faArchive, faBalanceScaleLeft, faRulerVertical} from '@fortawesome/free- import {faAddressCard} from '@fortawesome/free-regular-svg-icons'; import {version} from '../../../package.json'; import {callAPI, setCustomBackendDomain} from '../../utils/Api'; +import {SettingsTypes} from '../../types/ApiTypes'; +import {GeneralSuccess} from '../../types/GeneralTypes'; + +interface state { + passwordsupport: boolean, + tmdbsupport: boolean, + customapi: boolean, + + videopath: string, + tvshowpath: string, + mediacentername: string, + password: string, + apipath: string, + + videonr: number, + dbsize: number, + difftagnr: number, + tagsadded: number +} + +interface props {} /** * Component for Generalsettings tag on Settingspage * handles general settings of mediacenter which concerns to all pages */ -class GeneralSettings extends React.Component { - constructor(props) { +class GeneralSettings extends React.Component { + constructor(props: props) { super(props); this.state = { passwordsupport: false, - tmdbsupport: null, + tmdbsupport: false, customapi: false, videopath: '', tvshowpath: '', mediacentername: '', password: '', + apipath: '', - videonr: null, - dbsize: null, - difftagnr: null, - tagsadded: null + videonr: 0, + dbsize: 0, + difftagnr: 0, + tagsadded: 0 }; } - componentDidMount() { + componentDidMount(): void { this.loadSettings(); } - render() { + render(): JSX.Element { const themeStyle = GlobalInfos.getThemeStyle(); return ( <> @@ -47,7 +69,7 @@ class GeneralSettings extends React.Component { subtext='Videos in Gravity' icon={faArchive}/>
-
{ + { e.preventDefault(); this.saveSettings(); }}> @@ -68,14 +90,14 @@ class GeneralSettings extends React.Component { Video Path this.setState({videopath: ee.target.value})}/> + onChange={(ee): void => this.setState({videopath: ee.target.value})}/> TV Show Path this.setState({tvshowpath: e.target.value})}/> + onChange={(e): void => this.setState({tvshowpath: e.target.value})}/> @@ -84,7 +106,7 @@ class GeneralSettings extends React.Component { id='custom-switch-api' label='Use custom API url' checked={this.state.customapi} - onChange={() => { + onChange={(): void => { if (this.state.customapi) { setCustomBackendDomain(''); } @@ -97,7 +119,7 @@ class GeneralSettings extends React.Component { API Backend url { + onChange={(e): void => { this.setState({apipath: e.target.value}); setCustomBackendDomain(e.target.value); }}/> @@ -110,7 +132,7 @@ class GeneralSettings extends React.Component { data-testid='passwordswitch' label='Enable Password support' checked={this.state.passwordsupport} - onChange={() => { + onChange={(): void => { this.setState({passwordsupport: !this.state.passwordsupport}); }} /> @@ -119,7 +141,7 @@ class GeneralSettings extends React.Component { Password this.setState({password: e.target.value})}/> + onChange={(e): void => this.setState({password: e.target.value})}/> : null } @@ -129,7 +151,7 @@ class GeneralSettings extends React.Component { data-testid='tmdb-switch' label='Enable TMDB video grabbing support' checked={this.state.tmdbsupport} - onChange={() => { + onChange={(): void => { this.setState({tmdbsupport: !this.state.tmdbsupport}); }} /> @@ -140,7 +162,7 @@ class GeneralSettings extends React.Component { data-testid='darktheme-switch' label='Enable Dark-Theme' checked={GlobalInfos.isDarkTheme()} - onChange={() => { + onChange={(): void => { GlobalInfos.enableDarkTheme(!GlobalInfos.isDarkTheme()); this.forceUpdate(); // todo initiate rerender @@ -150,7 +172,7 @@ class GeneralSettings extends React.Component { The name of the Mediacenter this.setState({mediacentername: e.target.value})}/> + onChange={(e): void => this.setState({mediacentername: e.target.value})}/>
{this.state.text.map(m => (
{m}
@@ -44,7 +56,7 @@ class MovieSettings extends React.Component { /** * starts the reindex process of the videos in the specified folder */ - startReindex() { + startReindex(): void { // clear output text before start this.setState({text: []}); @@ -52,9 +64,9 @@ class MovieSettings extends React.Component { console.log('starting'); - callAPI('settings.php', {action: 'startReindex'}, (result) => { + callAPI('settings.php', {action: 'startReindex'}, (result: GeneralSuccess): void => { console.log(result); - if (result.success) { + if (result.result === 'success') { console.log('started successfully'); } else { console.log('error, reindex already running'); @@ -62,17 +74,17 @@ class MovieSettings extends React.Component { } }); - if (this.myinterval) { + if (this.myinterval !== -1) { clearInterval(this.myinterval); } - this.myinterval = setInterval(this.updateStatus, 1000); + this.myinterval = window.setInterval(this.updateStatus, 1000); } /** * This interval function reloads the current status of reindexing from backend */ - updateStatus = () => { - callAPI('settings.php', {action: 'getStatusMessage'}, (result) => { + updateStatus = (): void => { + callAPI('settings.php', {action: 'getStatusMessage'}, (result: SettingsTypes.getStatusMessageType) => { if (result.contentAvailable === true) { console.log(result); // todo 2020-07-4: scroll to bottom of div here @@ -93,7 +105,7 @@ class MovieSettings extends React.Component { /** * send request to cleanup db gravity */ - cleanupGravity() { + cleanupGravity(): void { callAPI('settings.php', {action: 'cleanupGravity'}, (result) => { this.setState({ text: ['successfully cleaned up gravity!'] diff --git a/src/types/ApiTypes.ts b/src/types/ApiTypes.ts new file mode 100644 index 0000000..fbf76d3 --- /dev/null +++ b/src/types/ApiTypes.ts @@ -0,0 +1,66 @@ +import {ActorType, TagType} from './VideoTypes'; + +export namespace VideoTypes{ + export interface loadVideoType { + movie_url: string + thumbnail: string + movie_id: number + movie_name: string + likes: number + quality: number + length: number + tags: TagType[] + suggesttag: TagType[] + actors: ActorType[] + } + + export interface startDataType{ + total: number; + fullhd: number; + hd: number; + sd: number; + tags: number; + } + + export interface VideoUnloadedType { + movie_id: number; + movie_name: string + } +} + +export namespace SettingsTypes{ + export interface initialApiCallData { + DarkMode: boolean; + passwordEnabled: boolean; + mediacenter_name: string; + } + + export interface loadGeneralSettingsType{ + video_path: string, + episode_path: string, + mediacenter_name: string, + password: string, + passwordEnabled: boolean, + TMDB_grabbing: boolean, + + videonr: number, + dbsize: number, + difftagnr: number, + tagsadded: number + } + + export interface getStatusMessageType{ + contentAvailable: boolean; + message: string; + } +} + +export namespace ActorTypes{ + /** + * result of actor fetch + */ + export interface videofetchresult { + videos: VideoTypes.VideoUnloadedType[]; + info: ActorType; + } +} diff --git a/src/api/GeneralTypes.ts b/src/types/GeneralTypes.ts similarity index 100% rename from src/api/GeneralTypes.ts rename to src/types/GeneralTypes.ts diff --git a/src/types/VideoTypes.ts b/src/types/VideoTypes.ts new file mode 100644 index 0000000..15b3f79 --- /dev/null +++ b/src/types/VideoTypes.ts @@ -0,0 +1,15 @@ + + +/** + * type accepted by Tag component + */ +export interface TagType { + tag_name: string + tag_id: number +} + +export interface ActorType { + thumbnail: string; + name: string; + actor_id: number; +} diff --git a/src/utils/Api.ts b/src/utils/Api.ts index 787717e..deba0b5 100644 --- a/src/utils/Api.ts +++ b/src/utils/Api.ts @@ -40,7 +40,7 @@ function getAPIDomain(): string { interface ApiBaseRequest { action: string | number, - [_: string]: string | number + [_: string]: string | number | boolean } /**