#5 improved reducer + track navigation

Scalone
Sergei-Levshnia scala 13 commity/ów z Sergei-Levshnia/player-reducer-new-logig do Sergei-Levshnia/dev 2 lat temu

+ 8 - 19
src/App.js

@@ -4,6 +4,7 @@ import * as reducer from './reducers'
 import * as Logcomp from './components/Login'
 import * as Sidebar from './components/Sidebar'
 import * as Page from './components/Page'
+import  {PlayerbarConnect} from './components/Playerbar'
 
 import thunk from 'redux-thunk';
 import { createStore, combineReducers, applyMiddleware } from 'redux';
@@ -44,11 +45,12 @@ export const history = createHistory()
 export const backendURL = "http://player.asmer.fs.a-level.com.ua"
 export const gql = getGQL(backendURL + '/graphql')
 
-const store = createStore(
+export const store = createStore(
   combineReducers(
     {
       promise: reducer.promiseReducer,
       auth: reducer.authReducer,
+      player: reducer.playerReducer
       //local: localStoreReducer(promiseReducer, 'locale')
     }
   ), applyMiddleware(thunk)
@@ -63,24 +65,10 @@ if (store.getState().auth?.token) {
   history.push('/login')
 }
 
-const PlayerBar = () => {
-  return (
-    <footer>
-      <div>
-        <button>{`<<`}</button>
-        <button>{`> / ||`}</button>
-        <button>{`>>`}</button>
-        <input type="range" />
-      </div>
-      <small>ARTIST - TRACK NAME</small>
-    </footer>
-  )
-}
-
 const Player = () =>
   <div>
-    <header><Link to="/player">Player</Link></header>
-    <div style={{ border:'1px solid blue',display: 'flex', height: '89vh', minHeight: '60vh', overflow:'none'}}>
+    {/* <header><Link to="/player">Player</Link></header> */}
+    <div style={{ border:'1px solid blue', display: 'flex', maxHeight: '89vh', minHeight:'30vh', overflow:'none'}}>
       <aside style={{width: '30%', overflow:'auto'}}>
         <Sidebar.LogoutBtnConnect />
         <Sidebar.ProfileWindowDropzoneConnect />
@@ -88,7 +76,7 @@ const Player = () =>
         <Sidebar.PlaylistAddConnect />
         <Sidebar.PlaylistsConnect />
       </aside>
-      <main style={{ border: '1px solid red', width: '80%', height:'100%', overflow:'auto'}}>
+      <main style={{ border: '1px solid red', width: '80%', height:'inherit', overflow:'auto'}}>
         <Switch>
           <Route path="/player/playlist/:_id" component={Page.PlaylistPageConnect} exact />
           <Route path="/player/tracks/:_id" component={Page.UserTracksPageConnect} exact />
@@ -106,7 +94,8 @@ const Player = () =>
         </Switch>
       </main>
     </div>
-    <PlayerBar />
+    <PlayerbarConnect />
+    {/* <PlayerBar /> */}
   </div>
 
 function App() {

+ 126 - 38
src/actions/index.js

@@ -1,4 +1,89 @@
-import { jwtDecode, gql, backendURL } from '../App'
+import { jwtDecode, gql, backendURL, store } from '../App'
+
+const audio = new Audio()
+
+const actionTrackSet = (track, audio, playlist) =>
+({
+    type: 'SET_TRACK',
+    track: track,
+    playlist: playlist,
+    duration: audio.duration,
+    currentTime: audio.currentTime,
+    volume: audio.volume
+})
+
+const actionTrackSetDuration = (time) => ({ type: 'SET_DURATION', duration: time })
+
+const actionTrackSetCurrTime = (time) => ({ type: 'SET_CURRTIME', currentTime: time })
+
+const actionTrackSetVolume = (value) => ({ type: 'SET_VOLUME', volume: value })
+const actionTrackPlay = () => ({ type: 'PLAY_TRACK' })
+const actionTrackPause = (currentTime) => ({ type: 'PAUSE_TRACK', currentTime: currentTime })
+
+const actionPlaylistSet = (playlist) => ({type: 'SET_PLAYLIST', playlist: playlist})
+const actionSetPlaylistIndex = (index) => ({type: 'SET_INDEX', playlistIndex: index})
+
+export const setPlaylist = (playlist) => dispatch => dispatch(actionPlaylistSet(playlist))
+export const setIndex = (index) => dispatch => dispatch(actionSetPlaylistIndex(index))
+
+export const setTrack = (track, playlist) =>
+    dispatch => {
+        audio.src = backendURL + '/' + track.url
+        dispatch(actionTrackSet(track, audio, playlist))
+    }
+
+export const switchTrack = (isForward, currentTrackIndex, playlist) =>
+    dispatch => {
+        let playlistLength = playlist.constructor.name ==='Array'? playlist.length - 1 : playlist.tracks.length - 1
+        let tracks = playlist.constructor.name ==='Array'? playlist : playlist.tracks
+        console.log('stuff', tracks, playlistLength)
+
+        if (isForward ? currentTrackIndex < playlistLength : currentTrackIndex > 0) {
+            dispatch(setTrack(tracks[currentTrackIndex + (isForward ? 1 : -1)], playlist))
+        } else if (currentTrackIndex === (isForward ? playlistLength : 0)) {
+            dispatch(setTrack(tracks[isForward ? 0 : playlistLength], playlist))
+        }
+        dispatch(playTrack())
+    }
+
+export const playTrack = () =>
+    dispatch => {
+        dispatch(actionTrackPlay())
+        audio.play()
+    }
+
+export const pauseTrack = () =>
+    dispatch => {
+        dispatch(actionTrackPause(audio.currentTime))
+        audio.pause()
+    }
+
+export const setTrackVolume = (volume) =>
+    dispatch => {
+        audio.volume = volume
+        dispatch(actionTrackSetVolume(volume))
+    }
+
+export const setNewTrackCurrentTime = (time) =>
+    (dispatch, getState) => {
+        audio.pause()
+        audio.currentTime = time
+        getState().player.isPlaying? audio.play() : audio.pause()
+        dispatch(actionTrackSetCurrTime(time))
+    }
+
+audio.onended = () => store.dispatch(switchTrack(true, store.getState().player.playlistIndex, store.getState().player.playlist))
+audio.ondurationchange = (e) =>  store.dispatch(actionTrackSetDuration(e.target.duration))
+audio.ontimeupdate = (e) => store.dispatch(actionTrackSetCurrTime(e.target.currentTime))
+
+
+
+
+
+
+
+
+
 
 const actionPending = name => ({ type: 'PROMISE', status: 'PENDING', name })
 const actionResolved = (name, payload) => ({ type: 'PROMISE', status: 'RESOLVED', name, payload })
@@ -66,18 +151,18 @@ export const actionGetUserData = () => {
 
 export const actionGetUserPlaylists = () => {
     let _id = jwtDecode(localStorage.authToken).sub.id
-    return(
+    return (
         actionPromise('userPlaylists', gql(`
             query getPlaylistByOwnerId($ownerId:String!) {
                 PlaylistFind(query: $ownerId) {
                     _id, name
                 }
             }
-        `, { ownerId: JSON.stringify([{ ___owner: _id }]) } ))
+        `, { ownerId: JSON.stringify([{ ___owner: _id }]) }))
     )
 }
 
-export const actionGetPlaylistById = (_id/*='5fe35e5ce926687ee86b0a4f'*/) =>
+export const actionGetPlaylistById = (_id) =>
     actionPromise('playlistTracks', gql(`
         query playlistById($playlistId: String!) {
             PlaylistFind(query: $playlistId) {
@@ -94,8 +179,7 @@ export const actionGetPlaylistById = (_id/*='5fe35e5ce926687ee86b0a4f'*/) =>
 
 export const actionGetUserTracks = () => {
     let _id = jwtDecode(localStorage.authToken).sub.id
-    //let _id = '5fe35e1ce926687ee86b0a3f' //newUserId
-    return(
+    return (
         actionPromise('userTracks', gql(`
             query getUserTracks($ownerId: String!) {
                 TrackFind(query: $ownerId) {
@@ -103,11 +187,11 @@ export const actionGetUserTracks = () => {
                     id3 { title, artist, album }
                 }
             }
-        `, { ownerId: JSON.stringify([{ ___owner: _id }]) } ))
+        `, { ownerId: JSON.stringify([{ ___owner: _id }]) }))
     )
 }
 
-export const actionAddPlaylist = playlistName => 
+export const actionAddPlaylist = playlistName =>
     async dispatch => {
         await dispatch(actionPromise('addPlaylist', gql(`
             mutation addPlaylist ($playlistName: String!){
@@ -115,66 +199,70 @@ export const actionAddPlaylist = playlistName =>
                     _id, name
                 }
             }
-        `, {playlistName: playlistName})))
+        `, { playlistName: playlistName })))
         dispatch(actionGetUserPlaylists())
     }
 
 export const actionLoadFile = (file, type) => {
     let fd = new FormData()
     console.log('TYPE', type)
-    fd.append(type === 'upload'? 'photo' : type, file)
-    
+    fd.append(type === 'upload' ? 'photo' : type, file)
+
     return (
-        actionPromise('loadFile', fetch(backendURL + `/${type}`,{
-        method: "POST",
-        headers: localStorage.authToken ? {Authorization: 'Bearer ' + localStorage.authToken} : {},
-        body: fd
+        actionPromise('loadFile', fetch(backendURL + `/${type}`, {
+            method: "POST",
+            headers: localStorage.authToken ? { Authorization: 'Bearer ' + localStorage.authToken } : {},
+            body: fd
         })
-        .then(res => res.json())
+            .then(res => res.json())
         )
     )
 }
 
-export const actionUpdatePlaylist = (playlistId, updPlaylist) => {
-    console.log('UPDATING', playlistId, updPlaylist)
-    return (
-        actionPromise('trackToPlaylist', gql(`
+export const actionUpdatePlaylist = (playlistId, updPlaylist) =>
+    async dispatch => {
+        await dispatch(actionPromise('trackToPlaylist', gql(`
             mutation($playlistId: ID, $newTracks: [TrackInput]) {
                 PlaylistUpsert(playlist:{ _id: $playlistId, tracks: $newTracks}) {
-                _id, name, tracks { _id, originalFileName, }
+                _id, name, tracks { _id, url, originalFileName, id3{ title, artist, album } }
                 }
             }
-            `, { playlistId: playlistId ,  newTracks: updPlaylist }))
+            `, { playlistId: playlistId, newTracks: updPlaylist }))
+        )
+        await dispatch(actionGetPlaylistById(playlistId))
+    }
+
 
-    )
-}
 export const actionUploadUserTrack = (file, playlistId) =>
     async (dispatch, getState) => {
         await dispatch(actionLoadFile(file, 'track'))
 
-        if(!playlistId) {
-            dispatch(actionGetUserTracks())
+        if (!playlistId) {
+            await dispatch(actionGetUserTracks())
+            if(getState().player.track && getState().player.playlist.constructor.name === 'Array') {
+                console.log('HERE', getState().promise.userTracks.payload)
+                dispatch(setPlaylist(getState().promise.userTracks.payload.reverse()))
+                dispatch(setIndex(getState().player.playlist.map(item => item._id).indexOf(getState().player.track._id)))
+            }
         } else {
-            console.log('UPLOADING TO PLAYLIS')
             let updPlaylist = []
             let oldPlaylist = getState().promise.playlistTracks.payload[0].tracks
 
-            if(oldPlaylist) {
-                //console.log('id pashet', oldPlaylist)
-                oldPlaylist.forEach(track => updPlaylist.push({_id: track._id}))
+            if (oldPlaylist) oldPlaylist.forEach(track => updPlaylist.push({ _id: track._id }))
+            updPlaylist.unshift({ _id: getState().promise.loadFile.payload?._id })
+            await dispatch(actionUpdatePlaylist(playlistId, updPlaylist))
+            
+            if(getState().player.track && getState().player.playlist._id === playlistId) {
+                dispatch(setPlaylist(getState().promise.trackToPlaylist.payload))
+                dispatch(setIndex(updPlaylist.map(item => item._id).indexOf(getState().player.track._id)))
             }
-            updPlaylist.push({_id: getState().promise.loadFile.payload?._id})
-            console.log('UPDATED PLST', updPlaylist)
-
-            await dispatch(actionUpdatePlaylist(playlistId, updPlaylist.reverse()))
-            dispatch(actionGetPlaylistById(playlistId))
         }
     }
 
 export const actionUploadAvatar = (file) =>
     async (dispatch, getState) => {
-      await dispatch(actionLoadFile(file, 'upload'))
-      await dispatch(actionPromise('setAvatar', gql(`
+        await dispatch(actionLoadFile(file, 'upload'))
+        await dispatch(actionPromise('setAvatar', gql(`
         mutation {
           UserUpsert(user:{_id: "${jwtDecode(localStorage.authToken).sub.id}", avatar: {_id: "${getState().promise?.loadFile?.payload?._id}"}}){
             _id, login, avatar{
@@ -183,5 +271,5 @@ export const actionUploadAvatar = (file) =>
           }
         }
       `)))
-      dispatch(actionGetUserData())
+        dispatch(actionGetUserData())
     }

+ 79 - 39
src/components/Page/index.js

@@ -7,49 +7,86 @@ import { sortableContainer, sortableElement } from 'react-sortable-hoc';
 import { arrayMoveImmutable } from 'array-move';
 
 
-const Track = ({ track: { _id, 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>
-    </div>
-    <div style={{ textAlign: 'left' }}>
-      <h5>{artist || 'Artist: unknown'}</h5>
-      <h6>{album || 'Album: unknown'}</h6>
-      <h5>{title || originalFileName}</h5>
-      <p>{_id}</p>
-      <p>{url}</p>
-    </div>
-  </li>
-
-const SortableItem = sortableElement(Track);
-
-const SortableContainer = sortableContainer(({ children }) => {
-  return <ul>{children}</ul>;
-});
+const Track = ({ track, playlist, player, setTrack, playTrack, pauseTrack }) => {
+  let [_player, setPlayer] = useState()
+  let [isPlay, setPlay] = useState(true)
+  useEffect(() => setPlayer(player), [player])
 
-const Playlist = ({ playlist, updPlaylist }) => {
+  return (
+    <li style={{ border: '1px solid black', display: 'flex', alignItems: 'center' }}>
+      <div style={{ marginRight: '2%', padding: '2%' }}>
+
+        {isPlay && _player?.isPlaying && _player.track?._id === track._id ?
+          <button style={{ fontSize: '3vh' }} onClick={() => { pauseTrack(); setPlay(false) }}>{`\u23F8`}</button> :
+          <button
+            style={{ fontSize: '3vh' }}
+            onClick={() => {
+              if (track?._id !== _player?.track?._id) setTrack(track, playlist)
+              playTrack()
+              setPlay(true)
+            }}
+          >{`\u23F5`}</button>
+        }
+
+      </div>
+      <div style={{ textAlign: 'left' }}>
+        <h5>{track.id3.artist || 'Artist: unknown'}</h5>
+        <h6>{track.id3.album || 'Album: unknown'}</h6>
+        <h5>{track.id3.title || track.originalFileName}</h5>
+      </div>
+    </li>
+  )
+}
+const TrackConnect = connect(
+  state => ({
+    player: state.player || {},
+  }),
+  {
+    setTrack: action.setTrack,
+    pauseTrack: action.pauseTrack,
+    playTrack: action.playTrack
+  }
+)(Track)
+
+const SortableItem = sortableElement(TrackConnect);
+const SortableContainer = sortableContainer(({ children }) => { return <ul>{children}</ul> });
+
+const Playlist = ({ player, playlist, setPlaylist, updPlaylist, setIndex }) => {
   let [_tracks, setTracks] = useState()
-
+  let [_player, setPlayer] = useState()
+  useEffect(() => setPlayer(player), [player])
   useEffect(() => setTracks(playlist[0]?.tracks), [playlist])
 
   const onSortEnd = ({ oldIndex, newIndex }) => {
-    setTracks(arrayMoveImmutable(_tracks, oldIndex, newIndex))
-    updPlaylist(playlist[0]._id, arrayMoveImmutable(_tracks, oldIndex, newIndex).map(track => ({ _id: track._id })))
+    let newArr = arrayMoveImmutable(_tracks, oldIndex, newIndex)
+    setTracks(newArr)
+    updPlaylist(playlist[0]._id, newArr.map(track => ({ _id: track._id })))
+
+    if(_player?.playlist?._id === playlist[0]?._id) {
+      setPlaylist({..._player.playlist, 'tracks': newArr})
+      if (_player?.track) setIndex(newArr.map((item) => item._id).indexOf(_player?.track?._id))
+    }
   };
 
   return (
     <>
       <h2>{playlist[0]?.name || 'Playlist'}</h2>
       <SortableContainer onSortEnd={onSortEnd}>
-        {(_tracks || []).map((track, index) => <SortableItem index={index} track={track} />)}
+        {(_tracks || []).map((track, index) => <SortableItem index={index} track={track} playlist={playlist[0]} />)}
       </SortableContainer>
     </>
   )
 }
 export const PlaylistConnect = connect(
-  state => ({ playlist: state.promise.playlistTracks?.payload || [] }),
-  { updPlaylist: action.actionUpdatePlaylist }
+  state => ({
+    playlist: state.promise.playlistTracks?.payload || [],
+    player: state.player || {}
+  }),
+  {
+    updPlaylist: action.actionUpdatePlaylist,
+    setPlaylist: action.setPlaylist,
+    setIndex: action.setIndex
+  }
 )(Playlist)
 
 const PlaylistTrackDropzone = ({ playlist, uploadTrack }) => {
@@ -62,11 +99,13 @@ const PlaylistTrackDropzone = ({ playlist, uploadTrack }) => {
   const onDrop = useCallback(acceptedFiles => {
     uploadTrack(acceptedFiles[0], playlistId)
   }, [uploadTrack, playlistId])
-  const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop })
-
+  const { getRootProps, isDragActive } = useDropzone({ onDrop })
   return (
-    <div {...getRootProps()} style={isDragActive ? { border: '1px solid mediumseagreen' } : { border: '1px solid black' }}>
-      {isDragActive ? <small>drag here...</small> : <small>to upload drag track here</small>}
+    <div
+      {...getRootProps()}
+      style={{ height: 'fit-content', border: `${isDragActive ? '1px solid mediumseagreen' : '1px solid black'}` }}
+    >
+      {isDragActive ? <small>...drag here</small> : <small>to upload drag track here</small>}
       <PlaylistConnect />
     </div>
   )
@@ -82,16 +121,15 @@ const PlaylistPage = ({ match: { params: { _id } }, getTracks }) => {
 }
 export const PlaylistPageConnect = connect(null, { getTracks: action.actionGetPlaylistById })(PlaylistPage)
 
-
 const UserTracks = ({ user, tracks }) => {
+  let tracksRev = [...tracks].reverse()
   return (
     <>
-      <h2>{user.login || 'My'} tracks:</h2>
-      <ul>{(tracks || []).map(track => <Track track={track} />).reverse()}</ul>
+      <h2>{user.login || 'My'} uploaded tracks:</h2>
+      <ul>{(tracksRev || []).map(track => <TrackConnect track={track} playlist={tracksRev} />)}</ul>
     </>
   )
 }
-
 const UserTracksConnect = connect(state => ({
   tracks: state.promise.userTracks?.payload || [],
   user: state.promise.userData?.payload || {}
@@ -102,11 +140,13 @@ const UserTracksDropzone = ({ onLoad }) => {
   const onDrop = useCallback(acceptedFiles => {
     onLoad(acceptedFiles[0])
   }, [onLoad])
-  const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop })
-
+  const { getRootProps, isDragActive } = useDropzone({ onDrop })
   return (
-    <div {...getRootProps()} style={isDragActive ? { border: '1px solid mediumseagreen' } : { border: '1px solid black' }}>
-      {isDragActive ? <small>drag here...</small> : <small>to upload drag track here</small>}
+    <div
+      {...getRootProps()}
+      style={{ height: 'fit-content', border: `${isDragActive ? '1px solid mediumseagreen' : '1px solid black'}` }}
+    >
+      {isDragActive ? <small>...drag here</small> : <small>to upload drag track here</small>}
       <UserTracksConnect />
     </div>
   )

+ 85 - 0
src/components/Playerbar.js

@@ -0,0 +1,85 @@
+import { useEffect, useState } from "react"
+import { connect } from "react-redux"
+import * as action from "../actions"
+
+
+const Timestamp = ({time}) =>
+    <small style={{margin: '0 10px'}}>
+        {Math.floor((time / 60) % 60) < 10? `0` + Math.floor((time / 60) % 60) : Math.floor((time / 60) % 60)} : 
+        {Math.floor(time % 60) < 10?  `0`+ Math.floor(time % 60) : Math.floor(time % 60)}
+    </small>
+
+const Playerbar = ({ player, playTrack, pauseTrack, switchTrack, setTrackVolume, setCurrentTime }) => {
+    let [_player, setPlayer] = useState()
+
+    useEffect(() => {
+        setPlayer(player)
+    }, [player, _player])
+
+    return (
+        <>
+            {_player?.track ?  
+                <footer style={{display: `${_player?.track ? 'block' : 'none'}`, width: '95%', margin:'0 auto'}}>
+                    <input
+                        style={{width:'100%'}}
+                        type="range" min="0" max={_player?.duration} step="any"
+                        value={_player?.currentTime}
+                        onChange={(e) => setCurrentTime(e.target.value)}
+                    />
+                    <div style={{display:"flex", justifyContent:"space-between", width:'95%', margin:'0 auto'}}>
+                        {/* <small style={{margin: '0 10px'}}>
+                            {Math.floor((_player?.currentTime / 60) % 60) < 10? 
+                                `0` + Math.floor((_player?.currentTime / 60) % 60) : Math.floor((_player?.currentTime / 60) % 60)} : 
+                            {Math.floor(_player?.currentTime % 60) < 10? 
+                                `0`+ Math.floor(_player?.currentTime % 60) : Math.floor(_player?.currentTime % 60)}
+                        </small> */}
+                        <Timestamp time={_player?.currentTime} />
+                        {_player ? (_player.track?.id3?.artist && _player.track?.id3?.title ?
+                            <strong>{_player.track?.id3?.artist} - {_player.track?.id3?.title}</strong> :
+                            <strong>{_player.track?.originalFileName}</strong>) : ''}
+                        {/* <small style={{margin: '0 10px'}}>
+                            {Math.floor((_player?.duration / 60) % 60) < 10? 
+                                `0` + Math.floor((_player?.duration / 60) % 60) : Math.floor((_player?.duration / 60) % 60)} : 
+                            {Math.floor(_player?.duration % 60) < 10? 
+                                `0`+ Math.floor(_player?.duration % 60) : Math.floor(_player?.duration % 60)}
+                        </small> */}
+                        <Timestamp time={_player?.duration} />
+                    </div>
+                    <div style={{marginTop:'0.5%'}}>
+                        <button
+                            style={{ fontSize: '2vh' }}
+                            onClick={() => switchTrack(false, _player?.playlistIndex, _player?.playlist)}
+                        >
+                            {_player?.playlistIndex === 0 ? `\u23F4` : `\u23EE`}
+                        </button>
+
+                        {_player?.isPlaying ?
+                            <button style={{ fontSize: '2vh' }} onClick={() => pauseTrack()}>{`\u23F8`}</button> :
+                            <button style={{ fontSize: '2vh' }} onClick={() => playTrack()}>{`\u23F5`}</button>
+                        }
+
+                        <button
+                            style={{ fontSize: '2vh' }}
+                            onClick={() => switchTrack(true, _player?.playlistIndex, _player?.playlist)}
+                        >
+                            {_player?.playlistIndex === (_player?.playlist?.constructor.name === 'Array'? _player?.playlist?.length - 1 : _player?.playlist?.tracks.length - 1) ? 
+                                `\u23F5` : `\u23ED`}
+                        </button>
+                        <input style={{marginLeft: '1%'}} type="range" min="0" max="1" step="any" onChange={(e) => setTrackVolume(e.target.value)} />
+                    </div>
+                    <small>{_player?.playlistIndex}</small>
+                </footer> : <div style={{width:'inherit', height:'inherit', padding:'2em'}}>C'mon, Push the play button on some track :)</div>}
+        </>
+    )
+}
+
+export const PlayerbarConnect = connect(
+    state => ({ player: state.player || {} }),
+    {
+        playTrack: action.playTrack,
+        pauseTrack: action.pauseTrack,
+        switchTrack: action.switchTrack,
+        setTrackVolume: action.setTrackVolume,
+        setCurrentTime: action.setNewTrackCurrentTime
+    }
+)(Playerbar)

+ 2 - 2
src/components/Sidebar/index.js

@@ -69,7 +69,7 @@ const UserTracksBtn = ({ userId }) => {
         margin: '5px',
         padding: '5px'
       }}
-    >My tracks</Link>
+    >My uploads</Link>
   )
 }
 export const UserTracksBtnConnect = connect(state => ({ userId: state.promise.userData?.payload?._id || '' }))(UserTracksBtn)
@@ -119,7 +119,7 @@ const Playlists = ({ playlists }) => {
           return (
             <Link
               style={{ display: 'block', backgroundColor:'darkcyan', color: 'cyan', margin: '5px', padding: '5px' }}
-              to={`${history.location.pathname}/playlist/:${item._id}`}
+              to={`/player/playlist/:${item._id}`}
             >{item.name}</Link>
           )
         }).reverse() : ''

+ 28 - 0
src/reducers/index.js

@@ -33,6 +33,34 @@ export function promiseReducer(state = {}, { type, name, status, payload, error
     return state
 }
 
+export function playerReducer(state, { type, track, playlist, duration, currentTime, volume, playlistIndex }) {
+    if (!state || type === 'EJECT_TRACK') return {}
+    if (type === 'PLAY_TRACK') return { ...state, 'isPlaying': true }
+    if (type === 'PAUSE_TRACK') return { ...state, 'isPlaying': false }
+    if (type === 'SET_CURRTIME') return { ...state, 'currentTime': currentTime }
+    if (type === 'SET_DURATION') return { ...state, 'duration': duration }
+    if (type === 'SET_VOLUME') return { ...state, 'volume': volume }
+    if (type === 'SET_PLAYLIST')  return { ...state, 'playlist': playlist} 
+    if (type === 'SET_INDEX')  {
+        console.log('SEt_INDEX', playlistIndex)
+        return { ...state, 'playlistIndex': playlistIndex}
+    } 
+
+    if (type === 'SET_TRACK') {
+        return {
+            isPlaying: false,
+            track: track,
+            playlist: playlist,
+            duration: duration,
+            currentTime: currentTime,
+            volume: volume,
+            playlistIndex: 
+                playlist.constructor.name === 'Array'? playlist.indexOf(track) : playlist.tracks.indexOf(track)
+        }
+    }
+    return state
+}
+
 export const localStoreReducer = (reducer, localStorageName) => {
     return (
         (state, action) => {