new features context to render features correctly on change
This commit is contained in:
		
							
								
								
									
										46
									
								
								src/App.tsx
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								src/App.tsx
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | |||||||
| import React from 'react'; | import React, {useContext} from 'react'; | ||||||
| import HomePage from './pages/HomePage/HomePage'; | import HomePage from './pages/HomePage/HomePage'; | ||||||
| import RandomPage from './pages/RandomPage/RandomPage'; | import RandomPage from './pages/RandomPage/RandomPage'; | ||||||
| import GlobalInfos from './utils/GlobalInfos'; | import GlobalInfos from './utils/GlobalInfos'; | ||||||
| @@ -18,6 +18,7 @@ import AuthenticationPage from './pages/AuthenticationPage/AuthenticationPage'; | |||||||
| import TVShowPage from './pages/TVShowPage/TVShowPage'; | import TVShowPage from './pages/TVShowPage/TVShowPage'; | ||||||
| import TVPlayer from './pages/TVShowPage/TVPlayer'; | import TVPlayer from './pages/TVShowPage/TVPlayer'; | ||||||
| import {LoginContextProvider} from './utils/context/LoginContextProvider'; | import {LoginContextProvider} from './utils/context/LoginContextProvider'; | ||||||
|  | import {FeatureContext} from './utils/context/FeatureContext'; | ||||||
|  |  | ||||||
| interface state { | interface state { | ||||||
|     mediacentername: string; |     mediacentername: string; | ||||||
| @@ -48,13 +49,7 @@ class App extends React.Component<{}, state> { | |||||||
|             <LoginContextProvider> |             <LoginContextProvider> | ||||||
|                 <Switch> |                 <Switch> | ||||||
|                     <Route path='/login'> |                     <Route path='/login'> | ||||||
|                         <AuthenticationPage |                         <AuthenticationPage /> | ||||||
|                             onSuccessLogin={(): void => { |  | ||||||
|                                 // this.setState({password: false}); |  | ||||||
|                                 // reinit general infos |  | ||||||
|                                 // this.initialAPICall(); |  | ||||||
|                             }} |  | ||||||
|                         /> |  | ||||||
|                     </Route> |                     </Route> | ||||||
|                     <Route path='/media'> |                     <Route path='/media'> | ||||||
|                         {this.navBar()} |                         {this.navBar()} | ||||||
| @@ -63,32 +58,10 @@ class App extends React.Component<{}, state> { | |||||||
|                 </Switch> |                 </Switch> | ||||||
|             </LoginContextProvider> |             </LoginContextProvider> | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         // if (this.state.password === true) { |  | ||||||
|         //     // render authentication page if auth is neccessary |  | ||||||
|         //     return ( |  | ||||||
|         //         <AuthenticationPage |  | ||||||
|         //             onSuccessLogin={(): void => { |  | ||||||
|         //                 this.setState({password: false}); |  | ||||||
|         //                 // reinit general infos |  | ||||||
|         //                 this.initialAPICall(); |  | ||||||
|         //             }} |  | ||||||
|         //         /> |  | ||||||
|         //     ); |  | ||||||
|         // } else if (this.state.password === false) { |  | ||||||
|         //     return ( |  | ||||||
|         //         <Router> |  | ||||||
|         //             <div className={style.app}> |  | ||||||
|         //                 {this.navBar()} |  | ||||||
|         //                 {this.routing()} |  | ||||||
|         //             </div> |  | ||||||
|         //         </Router> |  | ||||||
|         //     ); |  | ||||||
|         // } else { |  | ||||||
|         //     return <>still loading...</>; |  | ||||||
|         // } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     static contextType = FeatureContext; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * render the top navigation bar |      * render the top navigation bar | ||||||
|      */ |      */ | ||||||
| @@ -115,7 +88,7 @@ class App extends React.Component<{}, state> { | |||||||
|                     Categories |                     Categories | ||||||
|                 </NavLink> |                 </NavLink> | ||||||
|  |  | ||||||
|                 {GlobalInfos.isTVShowEnabled() ? ( |                 {this.context.TVShowEnabled ? ( | ||||||
|                     <NavLink |                     <NavLink | ||||||
|                         className={[style.navitem, themeStyle.navitem].join(' ')} |                         className={[style.navitem, themeStyle.navitem].join(' ')} | ||||||
|                         to={'/media/tvshows'} |                         to={'/media/tvshows'} | ||||||
| @@ -137,6 +110,7 @@ class App extends React.Component<{}, state> { | |||||||
|  |  | ||||||
| const MyRouter = (): JSX.Element => { | const MyRouter = (): JSX.Element => { | ||||||
|     const match = useRouteMatch(); |     const match = useRouteMatch(); | ||||||
|  |     const features = useContext(FeatureContext); | ||||||
|  |  | ||||||
|     return ( |     return ( | ||||||
|         <Switch> |         <Switch> | ||||||
| @@ -159,13 +133,13 @@ const MyRouter = (): JSX.Element => { | |||||||
|                 <ActorPage /> |                 <ActorPage /> | ||||||
|             </Route> |             </Route> | ||||||
|  |  | ||||||
|             {GlobalInfos.isTVShowEnabled() ? ( |             {features.TVShowEnabled ? ( | ||||||
|                 <Route exact path={`${match.url}/tvshows`}> |                 <Route path={`${match.url}/tvshows`}> | ||||||
|                     <TVShowPage /> |                     <TVShowPage /> | ||||||
|                 </Route> |                 </Route> | ||||||
|             ) : null} |             ) : null} | ||||||
|  |  | ||||||
|             {GlobalInfos.isTVShowEnabled() ? ( |             {features.TVShowEnabled ? ( | ||||||
|                 <Route exact path={`${match.url}/tvplayer/:id`}> |                 <Route exact path={`${match.url}/tvplayer/:id`}> | ||||||
|                     <TVPlayer /> |                     <TVPlayer /> | ||||||
|                 </Route> |                 </Route> | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ import React from 'react'; | |||||||
| import ReactDOM from 'react-dom'; | import ReactDOM from 'react-dom'; | ||||||
| import App from './App'; | import App from './App'; | ||||||
| import {BrowserRouter} from 'react-router-dom'; | import {BrowserRouter} from 'react-router-dom'; | ||||||
|  | import {FeatureContextProvider} from './utils/context/FeatureContext'; | ||||||
|  |  | ||||||
| // don't allow console logs within production env | // don't allow console logs within production env | ||||||
| global.console.log = process.env.NODE_ENV !== 'development' ? (_: string | number | boolean): void => {} : global.console.log; | global.console.log = process.env.NODE_ENV !== 'development' ? (_: string | number | boolean): void => {} : global.console.log; | ||||||
| @@ -9,7 +10,9 @@ global.console.log = process.env.NODE_ENV !== 'development' ? (_: string | numbe | |||||||
| ReactDOM.render( | ReactDOM.render( | ||||||
|     <React.StrictMode> |     <React.StrictMode> | ||||||
|         <BrowserRouter> |         <BrowserRouter> | ||||||
|             <App /> |             <FeatureContextProvider> | ||||||
|  |                 <App /> | ||||||
|  |             </FeatureContextProvider> | ||||||
|         </BrowserRouter> |         </BrowserRouter> | ||||||
|     </React.StrictMode>, |     </React.StrictMode>, | ||||||
|     document.getElementById('root') |     document.getElementById('root') | ||||||
|   | |||||||
| @@ -13,9 +13,7 @@ interface state { | |||||||
|     wrongPWDInfo: boolean; |     wrongPWDInfo: boolean; | ||||||
| } | } | ||||||
|  |  | ||||||
| interface Props { | interface Props {} | ||||||
|     onSuccessLogin: () => void; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| class AuthenticationPage extends React.Component<Props, state> { | class AuthenticationPage extends React.Component<Props, state> { | ||||||
|     constructor(props: Props) { |     constructor(props: Props) { | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ import {Button} from '../../elements/GPElements/Button'; | |||||||
| import {VideoTypes} from '../../types/ApiTypes'; | import {VideoTypes} from '../../types/ApiTypes'; | ||||||
| import GlobalInfos from '../../utils/GlobalInfos'; | import GlobalInfos from '../../utils/GlobalInfos'; | ||||||
| import {ButtonPopup} from '../../elements/Popups/ButtonPopup/ButtonPopup'; | import {ButtonPopup} from '../../elements/Popups/ButtonPopup/ButtonPopup'; | ||||||
|  | import {FeatureContext} from '../../utils/context/FeatureContext'; | ||||||
|  |  | ||||||
| interface Props extends RouteComponentProps<{id: string}> {} | interface Props extends RouteComponentProps<{id: string}> {} | ||||||
|  |  | ||||||
| @@ -65,6 +66,8 @@ export class Player extends React.Component<Props, mystate> { | |||||||
|         this.quickAddTag = this.quickAddTag.bind(this); |         this.quickAddTag = this.quickAddTag.bind(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     static contextType = FeatureContext; | ||||||
|  |  | ||||||
|     componentDidMount(): void { |     componentDidMount(): void { | ||||||
|         // initial fetch of current movie data |         // initial fetch of current movie data | ||||||
|         this.fetchMovieData(); |         this.fetchMovieData(); | ||||||
| @@ -205,7 +208,7 @@ export class Player extends React.Component<Props, mystate> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     renderDeletePopup(): JSX.Element { |     renderDeletePopup(): JSX.Element { | ||||||
|         if (GlobalInfos.isVideoFulldeleteable()) { |         if (this.context.VideosFullyDeleteable) { | ||||||
|             return ( |             return ( | ||||||
|                 <ButtonPopup |                 <ButtonPopup | ||||||
|                     onDeny={(): void => this.setState({deletepopupvisible: false})} |                     onDeny={(): void => this.setState({deletepopupvisible: false})} | ||||||
|   | |||||||
| @@ -1,9 +1,10 @@ | |||||||
| import React from 'react'; | import React, {useContext} from 'react'; | ||||||
| import MovieSettings from './MovieSettings'; | import MovieSettings from './MovieSettings'; | ||||||
| import GeneralSettings from './GeneralSettings'; | import GeneralSettings from './GeneralSettings'; | ||||||
| import style from './SettingsPage.module.css'; | import style from './SettingsPage.module.css'; | ||||||
| import GlobalInfos from '../../utils/GlobalInfos'; | import GlobalInfos from '../../utils/GlobalInfos'; | ||||||
| import {NavLink, Redirect, Route, Switch, useRouteMatch} from 'react-router-dom'; | import {NavLink, Redirect, Route, Switch, useRouteMatch} from 'react-router-dom'; | ||||||
|  | import {FeatureContext} from '../../utils/context/FeatureContext'; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * The Settingspage handles all kinds of settings for the mediacenter |  * The Settingspage handles all kinds of settings for the mediacenter | ||||||
| @@ -12,6 +13,7 @@ import {NavLink, Redirect, Route, Switch, useRouteMatch} from 'react-router-dom' | |||||||
| const SettingsPage = (): JSX.Element => { | const SettingsPage = (): JSX.Element => { | ||||||
|     const themestyle = GlobalInfos.getThemeStyle(); |     const themestyle = GlobalInfos.getThemeStyle(); | ||||||
|     const match = useRouteMatch(); |     const match = useRouteMatch(); | ||||||
|  |     const features = useContext(FeatureContext); | ||||||
|  |  | ||||||
|     return ( |     return ( | ||||||
|         <div> |         <div> | ||||||
| @@ -23,7 +25,7 @@ const SettingsPage = (): JSX.Element => { | |||||||
|                 <NavLink to='/media/settings/movies'> |                 <NavLink to='/media/settings/movies'> | ||||||
|                     <div className={style.SettingSidebarElement}>Movies</div> |                     <div className={style.SettingSidebarElement}>Movies</div> | ||||||
|                 </NavLink> |                 </NavLink> | ||||||
|                 {GlobalInfos.isTVShowEnabled() ? ( |                 {features.TVShowEnabled ? ( | ||||||
|                     <NavLink to='/media/settings/tv'> |                     <NavLink to='/media/settings/tv'> | ||||||
|                         <div className={style.SettingSidebarElement}>TV Shows</div> |                         <div className={style.SettingSidebarElement}>TV Shows</div> | ||||||
|                     </NavLink> |                     </NavLink> | ||||||
| @@ -37,7 +39,7 @@ const SettingsPage = (): JSX.Element => { | |||||||
|                     <Route path={`${match.url}/movies`}> |                     <Route path={`${match.url}/movies`}> | ||||||
|                         <MovieSettings /> |                         <MovieSettings /> | ||||||
|                     </Route> |                     </Route> | ||||||
|                     {GlobalInfos.isTVShowEnabled() ? ( |                     {features.TVShowEnabled ? ( | ||||||
|                         <Route path={`${match.url}/tv`}> |                         <Route path={`${match.url}/tv`}> | ||||||
|                             <span /> |                             <span /> | ||||||
|                         </Route> |                         </Route> | ||||||
|   | |||||||
| @@ -72,7 +72,7 @@ export default function (): JSX.Element { | |||||||
|  |  | ||||||
|     return ( |     return ( | ||||||
|         <Switch> |         <Switch> | ||||||
|             <Route path={`${match.path}/:id`}> |             <Route exact path={`${match.path}/:id`}> | ||||||
|                 <EpisodePage /> |                 <EpisodePage /> | ||||||
|             </Route> |             </Route> | ||||||
|             <Route path={match.path}> |             <Route path={match.path}> | ||||||
|   | |||||||
| @@ -1,4 +1,3 @@ | |||||||
| import GlobalInfos from './GlobalInfos'; |  | ||||||
| import {cookie} from './context/Cookie'; | import {cookie} from './context/Cookie'; | ||||||
|  |  | ||||||
| const APIPREFIX: string = '/api/'; | const APIPREFIX: string = '/api/'; | ||||||
| @@ -84,13 +83,7 @@ function generalAPICall<T>( | |||||||
|             } |             } | ||||||
|         } else if (response.status === 400) { |         } else if (response.status === 400) { | ||||||
|             // Bad Request --> invalid token |             // Bad Request --> invalid token | ||||||
|             console.log('loading Password page.'); |             console.log('bad request todo sth here'); | ||||||
|             // load password page |  | ||||||
|             if (GlobalInfos.loadPasswordPage) { |  | ||||||
|                 GlobalInfos.loadPasswordPage(() => { |  | ||||||
|                     callAPI(apinode, fd, callback, errorcallback); |  | ||||||
|                 }); |  | ||||||
|             } |  | ||||||
|         } else { |         } else { | ||||||
|             console.log('Error: ' + response.statusText); |             console.log('Error: ' + response.statusText); | ||||||
|             if (errorcallback) { |             if (errorcallback) { | ||||||
|   | |||||||
| @@ -49,6 +49,7 @@ class StaticInfos { | |||||||
|     /** |     /** | ||||||
|      * set the current videopath |      * set the current videopath | ||||||
|      * @param vidpath videopath with beginning and ending slash |      * @param vidpath videopath with beginning and ending slash | ||||||
|  |      * @param tvshowpath | ||||||
|      */ |      */ | ||||||
|     setVideoPaths(vidpath: string, tvshowpath: string): void { |     setVideoPaths(vidpath: string, tvshowpath: string): void { | ||||||
|         this.videopath = vidpath; |         this.videopath = vidpath; | ||||||
| @@ -68,27 +69,6 @@ class StaticInfos { | |||||||
|     getTVShowPath(): string { |     getTVShowPath(): string { | ||||||
|         return this.tvshowpath; |         return this.tvshowpath; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * load the Password page manually |  | ||||||
|      */ |  | ||||||
|     loadPasswordPage: ((callback?: () => void) => void) | undefined = undefined; |  | ||||||
|  |  | ||||||
|     setTVShowsEnabled(TVShowEnabled: boolean): void { |  | ||||||
|         this.TVShowsEnabled = TVShowEnabled; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     isTVShowEnabled(): boolean { |  | ||||||
|         return this.TVShowsEnabled; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     setFullDeleteEnabled(FullDeleteEnabled: boolean): void { |  | ||||||
|         this.fullDeleteable = FullDeleteEnabled; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     isVideoFulldeleteable(): boolean { |  | ||||||
|         return this.fullDeleteable; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| export default new StaticInfos(); | export default new StaticInfos(); | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								src/utils/context/FeatureContext.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/utils/context/FeatureContext.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | import React, {FunctionComponent, useState} from 'react'; | ||||||
|  |  | ||||||
|  | export interface FeatureContextType { | ||||||
|  |     setTVShowEnabled: (enabled: boolean) => void; | ||||||
|  |     TVShowEnabled: boolean; | ||||||
|  |     setVideosFullyDeleteable: (fullyDeletable: boolean) => void; | ||||||
|  |     VideosFullyDeleteable: boolean; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A global context providing a way to interact with user login states | ||||||
|  |  */ | ||||||
|  | export const FeatureContext = React.createContext<FeatureContextType>({ | ||||||
|  |     setTVShowEnabled: (_) => {}, | ||||||
|  |     TVShowEnabled: false, | ||||||
|  |     setVideosFullyDeleteable: (_) => {}, | ||||||
|  |     VideosFullyDeleteable: false | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | export const FeatureContextProvider: FunctionComponent = (props): JSX.Element => { | ||||||
|  |     const [tvshowenabled, settvshowenabled] = useState(false); | ||||||
|  |     const [fullydeletablevids, setfullydeleteable] = useState(false); | ||||||
|  |  | ||||||
|  |     const value: FeatureContextType = { | ||||||
|  |         VideosFullyDeleteable: fullydeletablevids, | ||||||
|  |         TVShowEnabled: tvshowenabled, | ||||||
|  |         setTVShowEnabled: (e) => settvshowenabled(e), | ||||||
|  |         setVideosFullyDeleteable: (e) => setfullydeleteable(e) | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     return <FeatureContext.Provider value={value}>{props.children}</FeatureContext.Provider>; | ||||||
|  | }; | ||||||
| @@ -5,18 +5,21 @@ import {cookie} from './Cookie'; | |||||||
| import {APINode, callAPI} from '../Api'; | import {APINode, callAPI} from '../Api'; | ||||||
| import {SettingsTypes} from '../../types/ApiTypes'; | import {SettingsTypes} from '../../types/ApiTypes'; | ||||||
| import GlobalInfos from '../GlobalInfos'; | import GlobalInfos from '../GlobalInfos'; | ||||||
|  | import {FeatureContext} from './FeatureContext'; | ||||||
|  |  | ||||||
| export const LoginContextProvider: FunctionComponent = (props): JSX.Element => { | export const LoginContextProvider: FunctionComponent = (props): JSX.Element => { | ||||||
|     let initialLoginState = LoginState.LoggedIn; |     let initialLoginState = LoginState.LoggedIn; | ||||||
|     let initialUserPerm = LoginPerm.User; |     let initialUserPerm = LoginPerm.User; | ||||||
|  |  | ||||||
|  |     const features = useContext(FeatureContext); | ||||||
|  |  | ||||||
|     const t = cookie.Load(); |     const t = cookie.Load(); | ||||||
|     // we are already logged in so we can set the token and redirect to dashboard |     // we are already logged in so we can set the token and redirect to dashboard | ||||||
|     if (t !== null) { |     if (t !== null) { | ||||||
|         initialLoginState = LoginState.LoggedIn; |         initialLoginState = LoginState.LoggedIn; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const initialAPICall = (): void => { |     useEffect(() => { | ||||||
|         // this is the first api call so if it fails we know there is no connection to backend |         // this is the first api call so if it fails we know there is no connection to backend | ||||||
|         callAPI( |         callAPI( | ||||||
|             APINode.Settings, |             APINode.Settings, | ||||||
| @@ -27,9 +30,9 @@ export const LoginContextProvider: FunctionComponent = (props): JSX.Element => { | |||||||
|  |  | ||||||
|                 GlobalInfos.setVideoPaths(result.VideoPath, result.TVShowPath); |                 GlobalInfos.setVideoPaths(result.VideoPath, result.TVShowPath); | ||||||
|  |  | ||||||
|                 GlobalInfos.setTVShowsEnabled(result.TVShowEnabled); |                 features.setTVShowEnabled(result.TVShowEnabled); | ||||||
|                 GlobalInfos.setFullDeleteEnabled(result.FullDeleteEnabled); |                 features.setVideosFullyDeleteable(result.FullDeleteEnabled); | ||||||
|                 // |  | ||||||
|                 // this.setState({ |                 // this.setState({ | ||||||
|                 //     mediacentername: result.MediacenterName |                 //     mediacentername: result.MediacenterName | ||||||
|                 // }); |                 // }); | ||||||
| @@ -42,11 +45,7 @@ export const LoginContextProvider: FunctionComponent = (props): JSX.Element => { | |||||||
|                 setLoginState(LoginState.LoggedOut); |                 setLoginState(LoginState.LoggedOut); | ||||||
|             } |             } | ||||||
|         ); |         ); | ||||||
|     }; |     }, [features]); | ||||||
|  |  | ||||||
|     useEffect(() => { |  | ||||||
|         initialAPICall(); |  | ||||||
|     }, []); |  | ||||||
|  |  | ||||||
|     const [loginState, setLoginState] = useState<LoginState>(initialLoginState); |     const [loginState, setLoginState] = useState<LoginState>(initialLoginState); | ||||||
|     const [permission, setPermission] = useState<LoginPerm>(initialUserPerm); |     const [permission, setPermission] = useState<LoginPerm>(initialUserPerm); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user