소스 검색

before try to create logic when song ended, start the next song

Alyona Brytvina 2 년 전
부모
커밋
7fc1eaec97

+ 18 - 0
src/assets/theme.js

@@ -0,0 +1,18 @@
+import { purple } from '@mui/material/colors';
+import { createTheme } from '@mui/material/styles';
+
+const primary = purple[500];
+
+const defaultTheme = {
+  palette: {
+    type: 'dark',
+    primary: {
+      main: primary,
+    },
+    secondary: {
+      main: '#fafafa',
+    },
+  },
+};
+
+export const theme = createTheme(defaultTheme);

+ 17 - 10
src/components/App/App.jsx

@@ -2,21 +2,28 @@ import React from 'react';
 import './App.scss';
 import { BrowserRouter, Route, Switch } from 'react-router-dom';
 import { Provider } from 'react-redux';
+import { ThemeProvider } from '@mui/material/styles';
 import { Header } from '../Header/Header';
+import { Player } from '../Player/Player';
 import { MainPage } from '../../pages/MainPage/MainPage';
 import { LoginPage } from '../../pages/LoginPage/LoginPage';
 import { PlaylistsPage } from '../../pages/PlaylistsPage/PlaylistsPage';
 import store from '../../store/store';
+import { theme } from '../../assets/theme';
+import { PaginationControlled } from '../PaginationControlled/PaginationControlled';
 
 export const App = () => (
-  <Provider store={store}>
-    <BrowserRouter>
-      <Header/>
-      <Switch>
-        <Route exact path="/" component={MainPage}/>
-        <Route exact path="/playlists" component={PlaylistsPage}/>
-        <Route exact path="/login" component={LoginPage}/>
-      </Switch>
-    </BrowserRouter>
-  </Provider>
+  <ThemeProvider theme={theme}>
+    <Provider store={store}>
+      <BrowserRouter>
+        <Header/>
+        <Switch>
+          <Route exact path="/" component={MainPage}/>
+          <Route exact path="/playlists" component={PlaylistsPage}/>
+          <Route exact path="/login" component={LoginPage}/>
+        </Switch>
+        <Player/>
+      </BrowserRouter>
+    </Provider>
+  </ThemeProvider>
 );

+ 24 - 0
src/components/Dropzone/Dropzone.jsx

@@ -0,0 +1,24 @@
+import React, { useCallback } from 'react';
+import { useDropzone } from 'react-dropzone';
+import { useDispatch } from 'react-redux';
+import { actionUploadFile } from '../../store/types/playerTypes';
+
+export const Dropzone = () => {
+  const dispatch = useDispatch();
+  const onDrop = useCallback(acceptedFiles => {
+    dispatch(actionUploadFile(acceptedFiles[0]));
+    console.log(acceptedFiles);
+  }, []);
+  const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop});
+
+  return (
+    <div {...getRootProps()}>
+      <input {...getInputProps()} />
+      {
+        isDragActive
+          ? <p>Drop the files here ...</p>
+          : <p>Drag drop some files here, or click to select files</p>
+      }
+    </div>
+  );
+};

+ 23 - 12
src/components/Header/Header.jsx

@@ -1,24 +1,35 @@
 import React from 'react';
 import './Header.scss';
+import { AccountCircle } from '@mui/icons-material';
 import {
-  AppBar, Toolbar, Box, Button,
+  AppBar, Toolbar, IconButton, Typography, Box, Button,
 } from '@mui/material';
 import { Link } from 'react-router-dom';
 import { ReactComponent as Vector } from '../../assets/svgs/Vector.svg';
 
 export const Header = () => (
-  <AppBar position="relative">
-    <Toolbar>
+  <AppBar position="static">
+    <Toolbar sx={{display: 'flex', justifyContent: 'space-between'}}>
       <Vector className="logo"/>
-      <Link to="/">
-        <Button variant="secondary">Main</Button>
-      </Link>
-      <Link to="/playlists">
-        <Button variant="secondary">Playlists</Button>
-      </Link>
-      <Link to="/login">
-        <Button variant="secondary">Login</Button>
-      </Link>
+      <Box sx={{
+        width: '50%', display: 'flex', justifyContent: 'space-between', alignItems: 'center',
+      }}
+      >
+        <Link to="/">
+          <Button variant="secondary">Main</Button>
+        </Link>
+        <Link to="/playlists">
+          <Button variant="secondary">Playlists</Button>
+        </Link>
+        <Link to="/login">
+          <IconButton
+            size="large"
+            color="inherit"
+          >
+            <AccountCircle/>
+          </IconButton>
+        </Link>
+      </Box>
     </Toolbar>
   </AppBar>
 );

+ 49 - 0
src/components/PaginationControlled/PaginationControlled.jsx

@@ -0,0 +1,49 @@
+import React, { useEffect, useState } from 'react';
+import {
+  Stack, Typography, Pagination, PaginationItem,
+} from '@mui/material';
+import { getGql } from '../../utils/getGql';
+import { BACKEND_URL } from '../../constants';
+
+export const PaginationControlled = (tracks) => {
+  const [page, setPage] = useState(1);
+  const [trackList, setTrackList] = useState(tracks);
+
+  useEffect(() => {
+    const gql = getGql(`${BACKEND_URL}/graphql`);
+    gql(`
+      query skipTracks($query: String) {
+        TrackFind(query: $query) {
+       _id url originalFileName
+        }
+      }
+  `, {query: JSON.stringify([{}, {skip: [100]}])})
+      .then(data => setTrackList(data.map(track => ({
+        ...track,
+        url: `${BACKEND_URL}/${track.url}`,
+      }))));
+  }, []);
+
+  const handleChange = (e) => {
+    console.log(page, e);
+    setPage(page + 1);
+  };
+
+  return (
+    <Stack
+      spacing={2}
+      position="static"
+      bottom="0"
+      sx={{
+        display: 'flex',
+        alignItems: 'center',
+      }}
+    >
+      <Pagination
+        page={page}
+        count={10}
+        onClick={handleChange}
+      />
+    </Stack>
+  );
+};

+ 172 - 0
src/components/Player/Player.jsx

@@ -0,0 +1,172 @@
+import React, { useEffect, useState } from 'react';
+import {
+  Box, IconButton, Slider, Stack,
+} from '@mui/material';
+import VolumeOffIcon from '@mui/icons-material/VolumeOff';
+import {
+  FastForwardRounded, FastRewindRounded, PauseRounded, PlayArrowRounded, VolumeDown, VolumeUp,
+} from '@mui/icons-material';
+import { useDispatch, useSelector } from 'react-redux';
+import { PlayerBar } from '../PlayerBar/PlayerBar';
+import {
+  actionPause, actionPlay, actionSetAudio, actionSetCurrentTrackId,
+} from '../../store/types/playerTypes';
+
+export const Player = () => {
+  const playerState = useSelector(state => state.player);
+  const dispatch = useDispatch();
+  const [volume, setVolume] = useState(1);
+  const [muted, setMuted] = useState(false);
+  console.log(playerState);
+
+  const onVolumeChange = (e) => {
+    const volume = e.target.value / 100;
+    setVolume(volume);
+    playerState.audio.volume = volume;
+  };
+
+  const onMuted = () => {
+    setMuted(!muted);
+    !muted ? playerState.audio.volume = 0 : playerState.audio.volume = volume;
+  };
+
+  const onBackward = () => {
+    const {trackList} = playerState;
+    const trackIndex = playerState.trackList.findIndex(track => track._id === playerState.currentPlayingTrackId);
+
+    if (trackIndex === 0) {
+      const findFirstTrack = playerState.trackList.find((track, index) => index === playerState.trackList.length - 1);
+      playerState.audio.pause();
+
+      const {url, _id} = findFirstTrack;
+      const audio = new Audio(url);
+      const id = _id;
+
+      dispatch(actionSetAudio(audio));
+      dispatch(actionPlay({trackList, id}));
+    } else {
+      const findPrevTrack = playerState.trackList.find((track, index) => index === trackIndex - 1);
+      playerState.audio.pause();
+
+      const {url, _id} = findPrevTrack;
+      const audio = new Audio(url);
+      const id = _id;
+
+      dispatch(actionSetAudio(audio));
+      dispatch(actionPlay({trackList, id}));
+    }
+  };
+
+  const onForward = () => {
+    const {trackList} = playerState;
+    console.log(trackList);
+    const trackIndex = trackList.findIndex(track => track._id === playerState.currentPlayingTrackId);
+
+    if (trackIndex === trackList.length - 1) {
+      const findFirstTrack = trackList.find((track, index) => index === 0);
+      playerState.audio.pause();
+
+      const {url, _id} = findFirstTrack;
+
+      const audio = new Audio(url);
+      const id = _id;
+
+      dispatch(actionSetAudio(audio));
+      dispatch(actionPlay({trackList, id}));
+    } else {
+      const findNextTrack = playerState.trackList.find((track, index) => index === trackIndex + 1);
+      playerState.audio.pause();
+
+      const {url, _id} = findNextTrack;
+
+      const audio = new Audio(url);
+      const id = _id;
+
+      dispatch(actionSetAudio(audio));
+      dispatch(actionPlay({trackList, id}));
+    }
+  };
+
+  const togglePlayPause = () => {
+    const {trackList, currentPlayingTrackId} = playerState;
+    const id = currentPlayingTrackId;
+    if (playerState.isPlaying) {
+      dispatch(actionPause());
+      playerState.audio.pause();
+    } else if (playerState.isPlaying === false) {
+      dispatch(actionPlay({trackList, id}));
+      playerState.audio.play();
+    }
+  };
+
+  return (
+    <Box sx={{
+      width: '100%',
+      height: '20%',
+      position: 'sticky',
+      bottom: '0',
+      backgroundColor: 'white',
+      display: playerState.audio === null ? 'none' : 'flex',
+      alignItems: 'center',
+      flexDirection: 'column',
+    }}
+    >
+      <PlayerBar/>
+      <Box
+        sx={{
+          display: 'flex',
+          alignItems: 'center',
+          flexDirection: 'row',
+        }}
+      >
+        <IconButton
+          color="primary"
+          onClick={onBackward}
+        >
+          <FastRewindRounded fontSize="large"/>
+        </IconButton>
+        <IconButton
+          onClick={togglePlayPause}
+          color="primary"
+        >
+          {!playerState.isPlaying
+            ? (<PlayArrowRounded fontSize="large"/>)
+            : (<PauseRounded fontSize="large"/>)}
+        </IconButton>
+        <IconButton
+          color="primary"
+          onClick={onForward}
+        >
+          <FastForwardRounded
+            fontSize="large"
+          />
+        </IconButton>
+      </Box>
+      <Stack
+        spacing={2}
+        direction="row"
+        alignItems="center"
+        minWidth="20%"
+        sx={
+          {ml: 2, width: 200}
+        }
+      >
+        <IconButton onClick={onMuted}>
+          {muted
+            ? (<VolumeOffIcon fontSize="large"/>)
+            : volume <= 0.5 && volume !== 0
+              ? (<VolumeDown fontSize="large"/>)
+              : volume <= 0
+                ? (<VolumeOffIcon fontSize="large"/>)
+                : (<VolumeUp fontSize="large"/>)}
+        </IconButton>
+        <Slider
+          arial-label="Volume"
+          max={100}
+          value={volume * 100}
+          onChange={onVolumeChange}
+        />
+      </Stack>
+    </Box>
+  );
+};

+ 82 - 0
src/components/PlayerBar/PlayerBar.jsx

@@ -0,0 +1,82 @@
+import React, { useEffect, useState } from 'react';
+import {
+  Box, Slider, styled, Typography,
+} from '@mui/material';
+import { useSelector } from 'react-redux';
+
+export const PlayerBar = () => {
+  const [position, setPosition] = useState(0);
+  const playerState = useSelector(state => state.player);
+  console.log('render');
+
+  const onChange = e => {
+    playerState.audio.currentTime = e.target.value;
+  };
+
+  const formatDuration = value => {
+    const min = Math.floor(value / 60);
+    const sec = Math.floor(value - min * 60);
+    const readableSec = sec > 9 ? sec : `0${sec}`;
+    return Number.isNaN(value) ? '0:00' : `${min}:${readableSec}`;
+  };
+
+  const onTimeUpdate = () => {
+    setPosition(Math.floor(playerState.audio.currentTime));
+  };
+
+  useEffect(() => {
+    playerState.audio?.addEventListener('timeupdate', onTimeUpdate);
+    return () => {
+      playerState.audio?.removeEventListener('timeupdate', onTimeUpdate);
+    };
+  }, [playerState.audio]);
+
+  const TinyText = styled(Typography)({
+    fontSize: '0.75rem',
+    opacity: 0.8,
+    fontWeight: 500,
+    letterSpacing: 0.2,
+    margin: '10px 0',
+  });
+  return (
+    <Box sx={{
+      width: '100%',
+      height: '20%',
+      bottom: '0',
+      backgroundColor: 'white',
+      display: playerState.audio === null ? 'none' : 'flex',
+      alignItems: 'center',
+      flexDirection: 'column',
+    }}
+    >
+      <Slider
+        aria-label="time-indicator"
+        size="small"
+        min={0}
+        step={1}
+        value={position}
+        onChange={onChange}
+        max={
+          playerState.audio?.duration === undefined ? 0
+            : Number.isNaN(playerState.audio?.duration)
+              ? 0
+              : Math.floor(playerState.audio?.duration)
+        }
+      />
+      <Box
+        sx={{
+          display: 'flex',
+          alignItems: 'center',
+          justifyContent: 'space-between',
+          mt: -2,
+        }}
+      >
+        <TinyText>{formatDuration(playerState.audio?.currentTime)}</TinyText>
+        <TinyText>
+          -
+          {formatDuration(playerState.audio?.duration)}
+        </TinyText>
+      </Box>
+    </Box>
+  );
+};

+ 87 - 38
src/components/TrackList/TrackList.jsx

@@ -1,33 +1,32 @@
 import React, { useEffect, useState } from 'react';
 import {
   IconButton, List, ListItem, Typography,
-  Slider, Stack,
+  Slider, Stack, Box, Pagination, PaginationItem,
 } from '@mui/material';
-import { PlayCircle, VolumeUp } from '@mui/icons-material';
+import {
+  PauseRounded, PlayArrowRounded, PlayCircle, VolumeDown, VolumeUp,
+} from '@mui/icons-material';
 import { useDispatch, useSelector } from 'react-redux';
 import {
   actionPause, actionPlay, actionSetAudio, actionSetCurrentTrackId,
 } from '../../store/types/playerTypes';
+import { getGql } from '../../utils/getGql';
+import { BACKEND_URL } from '../../constants';
 
-export const TrackList = ({trackList}) => {
+export const TrackList = ({tracks, trackCount}) => {
   const dispatch = useDispatch();
   const playerState = useSelector(state => state.player);
-  const [volume, setVolume] = useState(0);
-  console.log(playerState);
+  const [trackList, setTrackList] = useState(tracks);
+  const [page, setPage] = useState(1);
+  console.log(trackList, page);
 
-  const onVolumeChange = (id, value) => {
-    if (playerState.currentPlayingTrackId === id) {
-      setVolume(value / 100);
-      playerState.audio.volume = volume;
-    }
-  };
   useEffect(() => {
     if (playerState.trackList.length === 0) {
       return;
     }
     if (playerState.isPlaying) {
       if (playerState.audio === null) {
-        const {url} = playerState.trackList.find(track => track._id === playerState.currentPlayingTrackId);
+        const {url} = trackList.find(track => track._id === playerState.currentPlayingTrackId);
         const audio = new Audio(url);
         audio.play();
         dispatch(actionSetAudio(audio));
@@ -40,11 +39,33 @@ export const TrackList = ({trackList}) => {
   }, [playerState.isPlaying]);
 
   useEffect(() => {
+    console.log('here', 1);
     if (playerState.audio !== null) {
-      const {url} = playerState.trackList.find(track => track._id === playerState.currentPlayingTrackId);
+      console.log('here', 2);
+      if (playerState.audio.duration === playerState.audio.currentTime) {
+        console.log('here', 3);
+
+        playerState.audio.addEventListener('onended', togglePlayPause);
+
+        return () => {
+          playerState.audio.removeEventListener('onended', togglePlayPause);
+        };
+      }
+      ;
+    }
+  }, [playerState.audio?.currentTime]);
+
+  useEffect(() => {
+    if (playerState.audio !== null) {
+      console.log(trackList, playerState.currentPlayingTrackId);
+      const {url} = trackList.find(track => track._id === playerState.currentPlayingTrackId);
       const audio = new Audio(url);
       audio.play();
       dispatch(actionSetAudio(audio));
+      const id = playerState.currentPlayingTrackId;
+      dispatch(actionPlay({
+        trackList, id,
+      }));
     }
   }, [playerState.currentPlayingTrackId]);
 
@@ -60,32 +81,60 @@ export const TrackList = ({trackList}) => {
       dispatch(actionPause());
     }
   };
+  useEffect(() => {
+    const gql = getGql(`${BACKEND_URL}/graphql`);
+    gql(`
+      query skipTracks($query: String) {
+        TrackFind(query: $query) {
+       _id url originalFileName
+        }
+      }
+  `, {query: JSON.stringify([{}, {skip: [(page - 1) * 100]}])})
+      .then(data => setTrackList(data.map(track => ({
+        ...track,
+        url: `${BACKEND_URL}/${track.url}`,
+      }))));
+  }, [page]);
+
+  const handleChange = (e, value) => {
+    setPage(value);
+  };
 
   return (
-    <List>
-      {trackList.map(track => (
-        <ListItem key={track._id}>
-          <IconButton onClick={() => togglePlayPause(track._id)}>
-            <PlayCircle/>
-          </IconButton>
-          <Typography>{track.originalFileName}</Typography>
-          <Stack
-            spacing={2}
-            direction="row"
-            sx={
-              {ml: 2, width: 200}
-            }
-          >
-            <VolumeUp/>
-            <Slider
-              max={100}
-              arial-label="Volume"
-              onChange={(e) => onVolumeChange(track._id, e.target.value)}
-              value={volume * 100}
-            />
-          </Stack>
-        </ListItem>
-      ))}
-    </List>
+    <Box>
+      <List>
+        {trackList.map(track => (
+          <ListItem key={track._id}>
+            <IconButton
+              onClick={() => togglePlayPause(track._id)}
+            >
+              {
+                playerState.isPlaying && track._id === playerState.currentPlayingTrackId
+                  ? (<PauseRounded fontSize="large" color="primary"/>)
+                  : (<PlayArrowRounded fontSize="large" color="primary"/>)
+              }
+            </IconButton>
+            <Typography>{track.originalFileName}</Typography>
+          </ListItem>
+        ))}
+      </List>
+      <Stack
+        spacing={2}
+        position="static"
+        bottom="0"
+        sx={{
+          display: 'flex',
+          alignItems: 'center',
+          mb: '3%',
+        }}
+      >
+        <Pagination
+          page={page}
+          count={Math.ceil(trackCount / 100)}
+          onChange={handleChange}
+          color="primary"
+        />
+      </Stack>
+    </Box>
   );
 };

+ 61 - 3
src/pages/LoginPage/LoginPage.jsx

@@ -1,7 +1,65 @@
 import React from 'react';
+import {
+  Avatar, Button, Checkbox, FormControlLabel, Grid, Paper, TextField, Typography,
+} from '@mui/material';
+import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
+import './LoginPage.scss';
 
 export const LoginPage = () => (
-  <div>
-    LoginPage
-  </div>
+  <Paper elevation={10} className="paperStyle">
+    <Grid
+      alignItems="center"
+      justifyContent="center"
+      flexDirection="column"
+      container
+    >
+      <Grid item>
+        <Avatar>
+          <LockOutlinedIcon/>
+        </Avatar>
+      </Grid>
+      <Grid item>
+        <Typography variant="h4">
+          Sign in
+        </Typography>
+      </Grid>
+    </Grid>
+    <TextField
+      label="Username"
+      variant="standard"
+      placeholder="Enter username"
+      sx={{margin: '10px 0'}}
+      fullWidth
+      required
+    />
+    <TextField
+      label="Password"
+      variant="standard"
+      placeholder="Enter password"
+      fullWidth
+      required
+    />
+    <FormControlLabel
+      control={(
+        <Checkbox
+          color="primary"
+        />
+      )}
+      label="Remember me"
+    />
+    <Button
+      type="submit"
+      color="primary"
+      variant="contained"
+      sx={{
+        margin: '20px 0',
+      }}
+      fullWidth
+    >
+      Sign in
+    </Button>
+    <Typography>
+      Do you have an account?
+    </Typography>
+  </Paper>
 );

+ 6 - 0
src/pages/LoginPage/LoginPage.scss

@@ -0,0 +1,6 @@
+.paperStyle{
+  height: 70vh;
+  padding: 20px;
+  width: 280px;
+  margin: 20px auto;
+}

+ 10 - 24
src/pages/MainPage/MainPage.jsx

@@ -3,31 +3,9 @@ import { TrackList } from '../../components/TrackList/TrackList';
 import { BACKEND_URL } from '../../constants';
 import { getGql } from '../../utils/getGql';
 
-// const trackList = [
-//   {
-//     _id: 1,
-//     url: 'https://cdn.drivemusic.club/dl/online/92VXJSQQDxV6Y6mnyWyxLg/1640753197/download_music/novogodnie_pesni/abba-happy-new-year.mp3',
-//     originalFileName: 'ABBA - Happy New Year!',
-//   },
-//   {
-//     _id: 2,
-//     url: 'https://cdn.drivemusic.club/dl/online/oT6fMW-T0FqmX3gYYp9Ijg/1640753313/download_music/2021/12/oksana-kovalevskaja-happy-end.mp3',
-//     originalFileName: 'Оксана Ковалевская - Happy End',
-//   },
-//   {
-//     _id: 3,
-//     url: 'https://cdn.drivemusic.club/dl/online/fA4XCWzbjt9Rox1rfhELbA/1640753313/download_music/2021/12/khleb-novogodnjaja.mp3',
-//     originalFileName: 'Новогодняя - ХЛЕБ',
-//   },
-//   {
-//     _id: 4,
-//     url: 'https://cdn.drivemusic.club/dl/online/cUrD6jj6Npb7dUu8IR0MLA/1640835038/download_music/2014/05/nico-vinz-am-i-wrong.mp3',
-//     originalFileName: 'Am I Wrong - Nico & Vinz',
-//   },
-// ];
-
 export const MainPage = () => {
   const [tracks, setTracks] = useState([]);
+  const [trackCount, setTrackCount] = useState([]);
 
   useEffect(() => {
     const gql = getGql(`${BACKEND_URL}/graphql`);
@@ -40,9 +18,17 @@ export const MainPage = () => {
   `).then(data => setTracks(data.map(track => ({...track, url: `${BACKEND_URL}/${track.url}`}))));
   }, []);
 
+  useEffect(() => {
+    const gql = getGql(`${BACKEND_URL}/graphql`);
+    gql(`
+      query getCount{
+           TrackCount(query:"[{}]")
+             } `).then(response => setTrackCount(response));
+  }, []);
+
   return (
     <div>
-      <TrackList trackList={tracks}/>
+      <TrackList tracks={tracks} trackCount={trackCount}/>
     </div>
   );
 };

+ 2 - 0
src/pages/PlaylistsPage/PlaylistsPage.jsx

@@ -1,7 +1,9 @@
 import React from 'react';
+import { Dropzone } from '../../components/Dropzone/Dropzone';
 
 export const PlaylistsPage = () => (
   <div>
     PlaylistsPage
+    <Dropzone/>
   </div>
 );

+ 14 - 0
src/store/reducers/playerReducer.js

@@ -1,4 +1,5 @@
 import types from '../types/playerTypes';
+import { BACKEND_URL } from '../../constants';
 
 const initialState = {
   trackList: [],
@@ -13,6 +14,7 @@ export function playerReducer(state = initialState, action) {
   switch (action.type) {
     case types.PLAY:
       const trackPlay = action.payload.trackList.find(track => track._id === action.payload.id);
+      console.log(action.payload.trackList.find(track => track._id === action.payload.id), action.payload.id);
       return {
         ...state,
         isPlaying: true,
@@ -34,6 +36,18 @@ export function playerReducer(state = initialState, action) {
         ...state,
         currentPlayingTrackId: action.payload,
       };
+    case types.SET_UPLOAD_FILE:
+      const fd = new FormData();
+      fd.append('track', action.payload);
+      fetch(`${BACKEND_URL}/track`, {
+        method: 'POST',
+        headers: localStorage.authToken ? {Authorization: `Bearer ${localStorage.authToken}`} : {},
+        body: fd,
+      }).then(response => console.log(response));
+      return {
+        ...state,
+        currentPlayingTrackId: action.payload,
+      };
     default:
       return state;
   }

+ 2 - 0
src/store/types/playerTypes.js

@@ -3,11 +3,13 @@ const types = {
   PLAY: 'PLAY',
   SET_AUDIO: 'SET_AUDIO',
   SET_CURRENT_TRACK_ID: 'SET_CURRENT_TRACK_ID',
+  SET_UPLOAD_FILE: 'SET_UPLOAD_FILE',
 };
 
 export const actionPause = (payload) => ({type: types.PAUSE, payload});
 export const actionPlay = (payload) => ({type: types.PLAY, payload});
 export const actionSetAudio = (payload) => ({type: types.SET_AUDIO, payload});
 export const actionSetCurrentTrackId = (payload) => ({type: types.SET_CURRENT_TRACK_ID, payload});
+export const actionUploadFile = (payload) => ({type: types.SET_UPLOAD_FILE, payload});
 
 export default types;