Quellcode durchsuchen

dropzones added for playlists and profile page. Now tracks can be uploaded casualy and uploaded to playlists. Sidebar components moved to separate folder

miskson vor 2 Jahren
Ursprung
Commit
829efda0d9
4 geänderte Dateien mit 177 neuen und 82 gelöschten Zeilen
  1. 12 56
      src/App.js
  2. 46 5
      src/actions/index.js
  3. 47 18
      src/components/Page/index.js
  4. 72 3
      src/components/Sidebar/index.js

+ 12 - 56
src/App.js

@@ -6,9 +6,8 @@ import * as Sidebar from './components/Sidebar'
 import * as Page from './components/Page'
 
 import thunk from 'redux-thunk';
-import { useEffect, useState } from 'react';
 import { createStore, combineReducers, applyMiddleware } from 'redux';
-import { Provider, connect } from 'react-redux';
+import { Provider } from 'react-redux';
 import { Link, Route, Router, Switch } from 'react-router-dom';
 import createHistory from 'history/createBrowserHistory'
 
@@ -19,7 +18,7 @@ export function jwtDecode(token) {
     decoded = atob(decoded)
     decoded = JSON.parse(decoded)
     return decoded
-  } 
+  }
   catch (e) {
     return;
   }
@@ -56,7 +55,7 @@ const store = createStore(
 )
 store.subscribe(() => console.log(store.getState()))
 //works only once on start of page
-if(store.getState().auth?.token) {
+if (store.getState().auth?.token) {
   history.push('/player')
   store.dispatch(action.actionGetUserData())
   store.dispatch(action.actionGetUserPlaylists())
@@ -64,62 +63,24 @@ if(store.getState().auth?.token) {
   history.push('/login')
 }
 
-const ProfileWindow = ({user, onLogout}) => {
-  let [userInfo, setUserInfo] = useState(user.payload)
-
-  useEffect(()=> {
-    setUserInfo(user.payload)
-  },[user, userInfo])
-
-  return(
-    <section>
-      <div
-        style={{ border: '1px solid black', backgroundColor: 'red', color: 'white' }}
-        onClick={() => { onLogout(); history.push('/login') }}
-      >log-out[X]</div>
-      <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
-        to={`/player/tracks/:${userInfo?._id}`} 
-        style={{
-          display:'block', 
-          backgroundColor: 'purple', 
-          color: 'white', 
-          margin: '5px', 
-          padding:'5px'
-        }} 
-      >My tracks</Link>
-    </section>
-   )
-}
-const ProfileWindowConnect = connect(state => ({ user: state.promise.userData || {} }),{ onLogout: action.actionAuthLogout })(ProfileWindow)
-  
-
-const Player = () => 
+const Player = () =>
   <>
-    <header>Player</header>
+    <header><Link to="/player">Player</Link></header>
     <div style={{ display: 'flex' }}>
       <aside style={{ border: '1px solid black', width: '30%' }}>
-        <ProfileWindowConnect />
+        <Sidebar.LogoutBtnConnect />
+        <Sidebar.ProfileWindowDropzoneConnect />
+        <Sidebar.UserTracksBtnConnect />
         <Sidebar.PlaylistsConnect />
       </aside>
       <main style={{ border: '1px solid black', width: '80%' }}>
         <Switch>
-          <Route path="/player/playlist/:_id" component={Page.PlaylistPageConnect} exact/>
-          <Route path="/player/tracks/:_id" component={Page.UserTrackDropzoneConnect} exact/>
+          <Route path="/player/playlist/:_id" component={Page.PlaylistPageConnect} exact />
+          <Route path="/player/tracks/:_id" component={Page.UserTracksPageConnect} exact />
           <>
             <h2>Welcome to online Player!</h2>
-            <div style={{width:'50%',margin: '0 auto'}}>
-              <ul style={{textAlign:'start'}}>
+            <div style={{ width: '50%', margin: '0 auto' }}>
+              <ul style={{ textAlign: 'start' }}>
                 <li><strong>To create playlist: </strong>click "NEW PLAYLIST"</li>
                 <li><strong>To upload track: </strong>drag and drop it to playlist area</li>
                 <li><strong>To see list of all your tracks: </strong>click "My tracks"</li>
@@ -132,11 +93,6 @@ const Player = () =>
     <footer> back stop forw</footer>
   </>
 
-// const PlayerConnect = connect(
-//   state => ({ user: state.promise.userData || {} }),{ onLogout: action.actionAuthLogout}
-// )(Player)
-
-
 function App() {
   return (
     <Router history={history}>

+ 46 - 5
src/actions/index.js

@@ -77,14 +77,15 @@ export const actionGetUserPlaylists = () => {
     )
 }
 
-export const actionGetPlaylistById = (_id='5fe35e5ce926687ee86b0a4f') =>
+export const actionGetPlaylistById = (_id/*='5fe35e5ce926687ee86b0a4f'*/) =>
     actionPromise('playlistTracks', gql(`
         query playlistById($playlistId: String!) {
             PlaylistFind(query: $playlistId) {
                 _id, 
                 name,
                 tracks {
-                    url, originalFileName,
+
+                    _id, url, originalFileName,
                     id3{ title, artist, album },
                 }
             }
@@ -134,8 +135,48 @@ export const actionLoadFile = (file, type) => {
     )
 }
 
-export const actionUploadUserTrack = file =>
-    async dispatch => {
+export const actionUploadUserTrack = (file, playlistId) =>
+    async (dispatch, getState) => {
         await dispatch(actionLoadFile(file, 'track'))
-        dispatch(actionGetUserTracks())
+        if(!playlistId) {
+            dispatch(actionGetUserTracks())
+        } 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}))
+            }
+            updPlaylist.push({_id: getState().promise.loadFile.payload?._id})
+            console.log('UPDATED PLST', updPlaylist)
+
+            await dispatch(actionPromise('trackToPlaylist', gql(`
+            mutation($playlistId: ID, $newTracks: [TrackInput]) {
+                PlaylistUpsert(playlist:{ _id: $playlistId, tracks: $newTracks}) {
+                _id, name, tracks { _id, originalFileName, }
+                }
+            }
+            `, { playlistId: playlistId ,  newTracks: updPlaylist.reverse() })))
+            dispatch(actionGetPlaylistById(playlistId))
+        }
+    }
+
+export const actionUploadAvatar = (file) =>
+    async (dispatch, getState) => {
+      await dispatch(actionLoadFile(file, 'upload'))
+      //let picId = getState().promise?.loadFile?.payload?._id
+      //let userId = jwtDecode(localStorage.authToken).sub.id
+  
+      await dispatch(actionPromise('setAvatar', gql(`
+        mutation {
+          UserUpsert(user:{_id: "${jwtDecode(localStorage.authToken).sub.id}", avatar: {_id: "${getState().promise?.loadFile?.payload?._id}"}}){
+            _id, login, avatar{
+                _id, url
+            }
+          }
+        }
+      `)))
+      dispatch(actionGetUserData())
     }

+ 47 - 18
src/components/Page/index.js

@@ -1,6 +1,6 @@
 import * as action from '../../actions'
 
-import { useEffect} from 'react';
+import { useEffect, useState} from 'react';
 import { connect } from 'react-redux';
 import { useDropzone } from 'react-dropzone'
 import React, {useCallback} from 'react'
@@ -20,28 +20,56 @@ const Track = ({track:{url, originalFileName, id3:{title, artist, album}}}) =>
         <p>{url}</p>
       </div>
     </li>
-
-const Playlist = ({playlist}) =>
+//----------------------------------------------------
+const Playlist = ({playlist}) => {
+  return(
     <>
       <h2>{playlist[0]?.name || 'Playlist'}</h2>
       <ul>
         {(playlist[0]?.tracks || []).map(track => <Track track={track}/>)}
       </ul>
     </>
-
+  )
+}
 export const PlaylistConnect = connect(state => ({playlist: state.promise.playlistTracks?.payload || []}))(Playlist)
 
+const PlaylistTrackDropzone = ({playlist, uploadTrack}) => {
+  let [playlistId, setPlaylistId] = useState()
+
+  useEffect(()=> {
+    setPlaylistId(playlist[0]?._id)
+  }, [playlist])
+
+  const onDrop = useCallback(acceptedFiles => {
+    uploadTrack(acceptedFiles[0], playlistId)
+  }, [uploadTrack, playlistId])
+  const {getRootProps, getInputProps, 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>}
+        <PlaylistConnect />
+      </div>
+  )
+}
+const PlaylistTrackDropzoneConnect = connect(
+    state => ({playlist: state.promise.playlistTracks?.payload || []}),
+    {uploadTrack: action.actionUploadUserTrack}
+  )(PlaylistTrackDropzone)
+
 const PlaylistPage = ({match: {params: {_id}}, getTracks}) => {
   useEffect(() => { getTracks(_id.substring(1)) }, [_id, getTracks])
-  return(<PlaylistConnect />)
+  //return(<PlaylistConnect />)
+  return(<PlaylistTrackDropzoneConnect />)
 }
 export 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}/>)}
+      {(tracks || []).map(track => <Track track={track}/>).reverse()}
     </ul>
   </>
 
@@ -51,23 +79,24 @@ const UserTracksConnect = connect(state => ({
   })
 )(UserTracks)
 
-const UserTracksPage = ({match: {params: {_id}}, getUserTracks}) => {
-  useEffect(() => { getUserTracks() },[_id, getUserTracks])
-  return(<UserTracksConnect/>)
-}
-export const UserTracksPageConnect = connect(null, {getUserTracks: action.actionGetUserTracks})(UserTracksPage)
-
 const UserTracksDropzone = ({onLoad}) => {
   const onDrop = useCallback(acceptedFiles => {
     onLoad(acceptedFiles[0])
-  }, [])
+  }, [onLoad])
   const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop})
 
   return (
-    <div {...getRootProps()}>
-      <input {...getInputProps()} />
-      { isDragActive ? <p>Drop the files here ...</p> : <UserTracksPageConnect /> }
-    </div>
+      <div {...getRootProps()} style={isDragActive? {border:'1px solid mediumseagreen'} : {border:'1px solid black'}}>
+        {isDragActive? <small>drag here...</small> : <small>to upload drag track here</small>}
+        <UserTracksConnect />
+      </div>
   )
 }
-export const UserTrackDropzoneConnect = connect(null, {onLoad: action.actionLoadFile})(UserTracksDropzone)
+export const UserTrackDropzoneConnect = connect(null, {onLoad: action.actionUploadUserTrack})(UserTracksDropzone)
+
+const UserTracksPage = ({match: {params: {_id}}, getUserTracks}) => {
+  useEffect(() => { getUserTracks() },[_id, getUserTracks])
+  //return(<UserTracksConnect/>)
+  return(<UserTrackDropzoneConnect/>)
+}
+export const UserTracksPageConnect = connect(null, {getUserTracks: action.actionGetUserTracks})(UserTracksPage)

+ 72 - 3
src/components/Sidebar/index.js

@@ -1,9 +1,78 @@
 import * as action from '../../actions'
 
-import { useState } from 'react';
+import { useState, useEffect, useCallback } from 'react';
 import { connect } from 'react-redux';
 import { Link } from 'react-router-dom';
-import { history } from '../../App';
+import { history, backendURL } from '../../App';
+import { useDropzone } from 'react-dropzone'
+
+const LogoutBtn = ({onLogout}) =>
+  <div
+  style={{ border: '1px solid black', backgroundColor: 'red', color: 'white' }}
+  onClick={() => { onLogout(); history.push('/login') }}
+  >log-out[X]</div>
+
+export const LogoutBtnConnect = connect(null, {onLogout: action.actionAuthLogout })(LogoutBtn)
+
+const ProfileWindow = ({user}) => {
+  let [userInfo, setUserInfo] = useState(user.payload)
+
+  useEffect(()=> {
+    setUserInfo(user.payload)
+  },[user, userInfo])
+
+  return(
+    <section>
+      <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' 
+      />
+    </section>
+   )
+}
+export const ProfileWindowConnect = connect(state => ({ user: state.promise.userData || {} }))(ProfileWindow)
+
+const ProfileWindowDropzone = ({onLoad}) => {
+  const onDrop = useCallback(acceptedFiles => {
+    onLoad(acceptedFiles[0])
+  }, [onLoad])
+  const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop})
+
+  return (
+      <div {...getRootProps()} style={isDragActive? {border:'1px solid mediumseagreen'} : {border:'1px solid black'}}>
+        <input {...getInputProps()} />
+        <ProfileWindowConnect />
+        {isDragActive? <small>drag here...</small> : <small>change avatar</small>}
+      </div>
+  )
+}
+export const ProfileWindowDropzoneConnect = connect(null, {onLoad: action.actionUploadAvatar})(ProfileWindowDropzone)
+
+const UserTracksBtn = ({userId}) => {
+  let [_id, setId] = useState()
+  useEffect(() => {
+    console.log('CHENG', userId)
+    setId(userId)
+  }, [userId])
+
+  return (
+    <Link
+    to={`/player/tracks/:${_id}`} 
+    style={{
+      display:'block', 
+      backgroundColor: 'purple', 
+      color: 'white', 
+      margin: '5px', 
+      padding:'5px'
+    }} 
+    >My tracks</Link>
+  )
+}
+export const UserTracksBtnConnect = connect(state => ({userId: state.promise.userData?.payload?._id || ''}))(UserTracksBtn)
 
 const PlaylistAdd = ({addPlaylist}) => {
   let [clicked, setClicked] = useState(false)
@@ -54,7 +123,7 @@ const Playlists = ({playlists}) => {
               to={`${history.location.pathname}/playlist/:${item._id}`}
             >{item.name}</Link>
           )
-        }) : '' 
+        }) : ''
       }
     </div>
   )