123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- import './App.css';
- import * as action from './actions'
- import * as reducer from './reducers'
- import thunk from 'redux-thunk';
- import { useEffect, useState } from 'react';
- import { createStore, combineReducers, applyMiddleware } from 'redux';
- import { Provider, connect } from 'react-redux';
- import { Link, Route, Router, Switch, Redirect } from 'react-router-dom';
- import createHistory from 'history/createBrowserHistory'
- export const getGQL = url =>
- (query, variables = {}) =>
- fetch(url, {
- method: 'POST',
- headers: {
- "Content-Type": "application/json",
- ...(localStorage.authToken ? { "Authorization": "Bearer " + localStorage.authToken } : {})
- },
- body: JSON.stringify({ query, variables })
- })
- .then(res => res.json())
- .then(data => {
- if (data.errors && !data.data) throw new Error(JSON.stringify(data.errors))
- return data.data[Object.keys(data.data)[0]]
- })
- const history = createHistory()
- const backendURL = "http://player.asmer.fs.a-level.com.ua"
- export const gql = getGQL(backendURL + '/graphql')
- const store = createStore(
- combineReducers(
- {
- promise: reducer.promiseReducer,
- auth: reducer.authReducer,
- //local: localStoreReducer(promiseReducer, 'locale')
- }
- ), applyMiddleware(thunk)
- )
- store.subscribe(() => console.log(store.getState()))
- //works only once on start of page
- if(store.getState().auth?.token) {
- history.push('/player')
- store.dispatch(action.actionGetUserData())
- store.dispatch(action.actionGetUserPlaylists())
- } else {
- history.push('/login')
- }
- export function jwtDecode(token) {
- try {
- let decoded = token.split('.')
- decoded = decoded[1]
- decoded = atob(decoded)
- decoded = JSON.parse(decoded)
- return decoded
- } catch (e) {
- return;
- }
- }
- const LoginForm = ({ loged, onLogin }) => {
- let [login, setLogin] = useState()
- let [password, setPassword] = useState()
- let [log, setLog] = useState()
- useEffect(() => {
- setLog(loged)
- if (log?.payload && localStorage.authToken) history.push('/player')
- }, [loged, log])
- return (
- <>
- <h1>Web-player</h1>
- <div>
- <h2>Log-in</h2>
- <input type="text" placeholder='Login' onChange={(e) => setLogin(e.target.value)} />
- <br />
- <input type="password" placeholder='Password' onChange={(e) => setPassword(e.target.value)} />
- <br />
- <small style={{ color: 'red' }}>{loged.status === 'REJECTED' || (loged.status === 'RESOLVED' && !loged.payload) ? 'invalid login or password' : ''}</small>
- <br />
- <button
- disabled={!password || !login}
- onClick={() => { onLogin(login, password) }}
- >Login</button>
- <p>- OR -</p>
- <Link to="/registration">Register new user</Link>
- </div>
- </>
- )
- }
- const LoginFormConnect = connect(state => ({ loged: state.promise.login || {} }), { onLogin: action.actionFullLogin })(LoginForm)
- const RegisterForm = ({ onRegister }) => {
- let [login, setLogin] = useState()
- let [password, setPassword] = useState()
- let [password2, setPassword2] = useState()
- return (
- <>
- <h1>Web-player</h1>
- <div>
- <h2>Registration</h2>
- <input type="text" placeholder='Login' onChange={(e) => setLogin(e.target.value)} />
- <br />
- <input type="password" placeholder='Password' onChange={(e) => setPassword(e.target.value)} />
- <br />
- <input disabled={!password} type="password" placeholder='Repeat Password' onChange={(e) => setPassword2(e.target.value)} />
- <br />
- <small style={{ color: 'red' }}>{password2 && password2 !== password ? 'Passwords do not match' : ''}</small>
- <br />
- <button disabled={!password || !login || password2 !== password} onClick={() => onRegister(login, password)}>Register</button>
- <br />
- <Link to="/login">Back to log-in page</Link>
- </div>
- </>
- )
- }
- const RegisterFormConnect = connect(null, { onRegister: action.actionRegister })(RegisterForm)
- const PlaylistAdd = ({addPlaylist}) => {
- let [clicked, setClicked] = useState(false)
- let [name, setName] = useState()
- return (
- <div>
- {
- !clicked?
- <button
- style={{ border: '1px solid black', backgroundColor: 'mediumseagreen',width : '95%',padding: '5px', margin: '5px' }}
- onClick={() => setClicked(true)}
- >NEW PLAYLIST</button>
- :
- <div style={{width : '95%', margin:'0 auto'}}>
- <input
- style={{width:'72%', padding:'5px'}}
- placeholder='Playlist name'
- value={name}
- onChange={(e) => setName(e.target.value)}
- />
- <button
- disabled={!name}
- style={{padding:'5px', backgroundColor:'mediumseagreen'}}
- onClick={() => {addPlaylist(name); setClicked(false); setName('');}}
- >+</button>
- <button
- style={{padding:'5px', backgroundColor:'red'}}
- onClick={() => {setClicked(false); setName('')}}
- >X</button>
- </div>
- }
- </div>
- )
- }
- const PlaylistAddConnect = connect(null, {addPlaylist: action.actionAddPlaylist})(PlaylistAdd)
- const Playlists = ({playlists}) => {
- return (
- <div style={{backgroundColor: 'lightcyan'}}>
- <PlaylistAddConnect />
- {
- playlists?.payload? playlists.payload.map(item => {
- return (
- <Link
- style={{display:'block', backgroundColor: 'darkcyan', color: 'cyan', margin: '5px', padding:'5px'}}
- to={`${history.location.pathname}/playlist/:${item._id}`}
- >{item.name}</Link>
- )
- }) : ''
- }
- </div>
- )
- }
- const PlaylistsConnect = connect(state => ({playlists: state.promise.userPlaylists || {}}))(Playlists)
- const Track = ({track:{url, originalFileName, id3:{title, artist, album}}}) =>
- <li style={{border: '1px solid black', display:'flex', alignItems:'center'}}>
- <div style={{marginRight:'2%'}}>
- <button style={{padding: '10px', margin:'2px'}}> {`>`} </button>
- <button style={{padding: '10px', margin:'2px'}}>| |</button>
- <br/>
- <button style={{padding: '10px', margin:'2px'}}>Add to...</button>
- </div>
- <div style={{textAlign: 'left'}}>
- <h5>{artist || 'Artist: unknown'}</h5>
- <h6>{album || 'Album: unknown'}</h6>
- <h5>{title || originalFileName}</h5>
- <p>{url}</p>
- </div>
- </li>
- const Playlist = ({playlist}) =>
- <>
- <h2>{playlist[0]?.name || 'Playlist'}</h2>
- <ul>
- {(playlist[0]?.tracks || []).map(track => <Track track={track}/>)}
- </ul>
- </>
- const PlaylistConnect = connect(state => ({playlist: state.promise.playlistTracks?.payload || []}))(Playlist)
- const PlaylistPage = ({match: {params: {_id}}, getTracks}) => {
- useEffect(() => {
- console.log('BANG', _id)
- getTracks(_id.substring(1))
- //getTracks()
- }, [_id])
- return(<PlaylistConnect />)
- }
- const PlaylistPageConnect = connect(null, {getTracks: action.actionGetPlaylistById})(PlaylistPage)
- const UserTracks = ({user, tracks}) =>
- <>
- <h2>{ user.login || 'My' } tracks:</h2>
- <ul>
- {(tracks || []).map(track => <Track track={track}/>)}
- </ul>
- </>
- const UserTracksConnect = connect(state => ({
- tracks: state.promise.userTracks?.payload || [],
- user: state.promise.userData?.payload || {}
- })
- )(UserTracks)
- const UserTracksPage = ({match: {params: {_id}}, getUserTracks}) => {
- useEffect(() => {
- getUserTracks()
- },[_id])
- return(<UserTracksConnect/>)
- }
- const UserTracksPageConnect = connect(null, {getUserTracks: action.actionGetUserTracks})(UserTracksPage)
- const Player = ({ user, playlists, onLogout }) => {
- let [userInfo, setUserInfo] = useState(user.payload)
- let [userPlaylists, setPlaylists] = useState(user.payload)
- useEffect(()=> {
- setUserInfo(user.payload)
- setPlaylists(playlists.payload)
- console.log(userPlaylists)
- },[user, playlists, userInfo, userPlaylists])
-
- return (
- <>
- <header>Player</header>
- <div style={{ display: 'flex' }}>
- <aside style={{ border: '1px solid black', width: '30%' }}>
- <div
- style={{ border: '1px solid black', backgroundColor: 'red', color: 'white' }}
- onClick={() => { onLogout(); history.push('/login') }}
- >log-out[X]</div>
- {/* profile window */}
- <div style={{border:'1px solid chartreuse'}}>
- <h3>{userInfo?.login || 'user'}</h3>
- <img
- width={100}
- height={100}
- style={{ border: '1px solid black', display:'block', margin:'5% auto', marginBottom:'2px'}}
- src={ userInfo?.avatar?.url ? backendURL + '/' + userInfo?.avatar?.url : ''}
- alt='avatar'
- />
- <small>change avavtar</small>
- </div>
- <Link
- style={{display:'block', backgroundColor: 'purple', color: 'white', margin: '5px', padding:'5px'}}
- to={`/player/tracks/:${userInfo?._id}`}
- >My tracks</Link>
- <PlaylistsConnect />
- </aside>
- <main style={{ border: '1px solid black', width: '80%' }}>
- <Switch>
- <Route path="/player/playlist/:_id" component={PlaylistPageConnect} exact/>
- <Route path="/player/tracks/:_id" component={UserTracksPageConnect} exact/>
- </Switch>
- </main>
- </div>
- <footer> back stop forw</footer>
- </>
- )
- }
- const PlayerConnect = connect(
- state => ({
- user: state.promise.userData || {},
- playlists: state.promise.userPlaylists || {}
- }),
- {
- onLogout: action.actionAuthLogout,
- }
- )(Player)
- function App() {
- return (
- <Router history={history}>
- <Provider store={store}>
- <div className="App">
- <Switch>
- <Route path="/login" component={LoginFormConnect} exact />
- <Route path="/registration" component={RegisterFormConnect} exact />
- <Route path='/player' component={PlayerConnect} />
- </Switch>
- </div>
- </Provider>
- </Router>
- );
- }
- export default App;
|