diff --git a/web/.eslintrc b/web/.eslintrc index 929c132..02f9504 100644 --- a/web/.eslintrc +++ b/web/.eslintrc @@ -36,6 +36,7 @@ "react/prop-types": 0, "react/react-in-jsx-scope": 0, "react/jsx-uses-react": 0, - "import/no-unresolved": 0 // used to allow relative paths from "src" folder + "import/no-unresolved": 0, // used to allow relative paths from "src" folder + "react/jsx-props-no-spreading": 0 } } \ No newline at end of file diff --git a/web/src/components/Add/AddDialog.jsx b/web/src/components/Add/AddDialog.jsx index dbbbe72..4c7225f 100644 --- a/web/src/components/Add/AddDialog.jsx +++ b/web/src/components/Add/AddDialog.jsx @@ -63,7 +63,7 @@ export default function AddDialog({ handleClose }) { Cancel - diff --git a/web/src/components/DialogCacheInfo/SingleBlock.jsx b/web/src/components/DialogCacheInfo/SingleBlock.jsx index 07c75b4..96268f6 100644 --- a/web/src/components/DialogCacheInfo/SingleBlock.jsx +++ b/web/src/components/DialogCacheInfo/SingleBlock.jsx @@ -34,7 +34,6 @@ export default function SingleBlock({ width={boxHeight} fillAfterStrokeEnabled preventDefault={false} - // eslint-disable-next-line react/jsx-props-no-spreading {...(isComplete ? { fill: processCompletedColor } : inProgress && { diff --git a/web/src/components/DialogTorrentDetailsContent/SingleBlock.jsx b/web/src/components/DialogTorrentDetailsContent/SingleBlock.jsx index 07c75b4..96268f6 100644 --- a/web/src/components/DialogTorrentDetailsContent/SingleBlock.jsx +++ b/web/src/components/DialogTorrentDetailsContent/SingleBlock.jsx @@ -34,7 +34,6 @@ export default function SingleBlock({ width={boxHeight} fillAfterStrokeEnabled preventDefault={false} - // eslint-disable-next-line react/jsx-props-no-spreading {...(isComplete ? { fill: processCompletedColor } : inProgress && { diff --git a/web/src/components/DialogTorrentDetailsContent/customHooks.jsx b/web/src/components/DialogTorrentDetailsContent/customHooks.jsx index 41c0008..5eeed67 100644 --- a/web/src/components/DialogTorrentDetailsContent/customHooks.jsx +++ b/web/src/components/DialogTorrentDetailsContent/customHooks.jsx @@ -28,9 +28,7 @@ export const useUpdateCache = hash => { }, 100) } else clearInterval(timerID.current) - return () => { - clearInterval(timerID.current) - } + return () => clearInterval(timerID.current) }, [hash]) return cache diff --git a/web/src/components/DialogTorrentDetailsContent/index.jsx b/web/src/components/DialogTorrentDetailsContent/index.jsx index dea5b57..b9c0852 100644 --- a/web/src/components/DialogTorrentDetailsContent/index.jsx +++ b/web/src/components/DialogTorrentDetailsContent/index.jsx @@ -2,14 +2,13 @@ import { NoImageIcon } from 'icons' import { getPeerString, humanizeSize } from 'utils/Utils' import { CopyToClipboard } from 'react-copy-to-clipboard' import { useEffect, useState } from 'react' -import { Button, ButtonGroup, Typography } from '@material-ui/core' +import { Button } from '@material-ui/core' import ptt from 'parse-torrent-title' import { ArrowDownward as ArrowDownwardIcon, ArrowUpward as ArrowUpwardIcon, SwapVerticalCircle as SwapVerticalCircleIcon, ViewAgenda as ViewAgendaIcon, - Cached as CachedIcon, } from '@material-ui/icons' import axios from 'axios' import { streamHost, torrentsHost, viewedHost } from 'utils/Hosts' @@ -109,7 +108,6 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) { setIsDetailedCacheView(false) })} /> diff --git a/web/src/components/DialogTorrentDetailsContent/style.js b/web/src/components/DialogTorrentDetailsContent/style.js index 60af08e..7fc3be8 100644 --- a/web/src/components/DialogTorrentDetailsContent/style.js +++ b/web/src/components/DialogTorrentDetailsContent/style.js @@ -204,10 +204,6 @@ export const Table = styled.table` tbody tr { border-bottom: 1px solid #ddd; - /* :nth-of-type(even) { - background: #f3f3f3; - } */ - :last-of-type { border-bottom: 2px solid #009879; } diff --git a/web/src/components/DialogTorrentInfo.jsx b/web/src/components/DialogTorrentInfo.jsx index 5352519..a70ca79 100644 --- a/web/src/components/DialogTorrentInfo.jsx +++ b/web/src/components/DialogTorrentInfo.jsx @@ -126,7 +126,7 @@ export default function DialogTorrentInfo({ torrent, open }) { fetch(`${streamHost()}?link=${torrentLocalComponentValue.hash}&index=${file.id}&preload`) } > - + {/* */} Preload diff --git a/web/src/components/RemoveAll.jsx b/web/src/components/RemoveAll.jsx index fd81770..aac5c0f 100644 --- a/web/src/components/RemoveAll.jsx +++ b/web/src/components/RemoveAll.jsx @@ -1,7 +1,9 @@ +import { Button, Dialog, DialogActions, DialogTitle } from '@material-ui/core' import ListItem from '@material-ui/core/ListItem' import ListItemIcon from '@material-ui/core/ListItemIcon' import ListItemText from '@material-ui/core/ListItemText' import DeleteIcon from '@material-ui/icons/Delete' +import { useState } from 'react' import { torrentsHost } from 'utils/Hosts' const fnRemoveAll = () => { @@ -29,13 +31,40 @@ const fnRemoveAll = () => { } export default function RemoveAll() { - return ( - - - - + const [open, setOpen] = useState(false) + const closeDialog = () => setOpen(false) + const openDialog = () => setOpen(true) - - + return ( + <> + + + + + + + + + + Delete Torrent? + + + + + + + ) } diff --git a/web/src/components/Torrent/index.jsx b/web/src/components/Torrent/index.jsx deleted file mode 100644 index bf19069..0000000 --- a/web/src/components/Torrent/index.jsx +++ /dev/null @@ -1,208 +0,0 @@ -/* eslint-disable camelcase */ -import 'fontsource-roboto' -import { forwardRef, useEffect, useRef, useState } from 'react' -import DialogActions from '@material-ui/core/DialogActions' -import DialogTorrentInfo from 'components/DialogTorrentInfo' -import DialogCacheInfo from 'components/DialogCacheInfo' -import HeightIcon from '@material-ui/icons/Height' -import CloseIcon from '@material-ui/icons/Close' -import DeleteIcon from '@material-ui/icons/Delete' -import DataUsageIcon from '@material-ui/icons/DataUsage' -import { getPeerString, humanizeSize } from 'utils/Utils' -import { torrentsHost } from 'utils/Hosts' -import { NoImageIcon } from 'icons' -import DialogTorrentDetailsContent from 'components/DialogTorrentDetailsContent' -import Dialog from '@material-ui/core/Dialog' -import Slide from '@material-ui/core/Slide' -import { Button } from '@material-ui/core' - -import { - StyledButton, - TorrentCard, - TorrentCardButtons, - TorrentCardDescription, - TorrentCardDescriptionContent, - TorrentCardDescriptionLabel, - TorrentCardPoster, - TorrentCardDetails, -} from './style' - -// eslint-disable-next-line react/jsx-props-no-spreading -const Transition = forwardRef((props, ref) => ) - -export default function Torrent({ torrent }) { - const [open, setOpen] = useState(false) - const [showCache, setShowCache] = useState(false) - const [torrentLocalComponentValue, setTorrentLocalComponentValue] = useState(torrent) - const timerID = useRef(-1) - - useEffect(() => { - setTorrentLocalComponentValue(torrent) - }, [torrent]) - - useEffect(() => { - if (open) - timerID.current = setInterval(() => { - getTorrent(torrentLocalComponentValue.hash, (torr, error) => { - if (error) console.error(error) - else if (torr) setTorrentLocalComponentValue(torr) - }) - }, 1000) - else clearInterval(timerID.current) - - return () => { - clearInterval(timerID.current) - } - }, [torrentLocalComponentValue.hash, open]) - - const { title, name, poster, torrent_size, download_speed } = torrentLocalComponentValue - - return ( - <> - - - {poster ? poster : } - - - - { - setShowCache(true) - setOpen(true) - }} - > - - Cache - - - dropTorrent(torrentLocalComponentValue)}> - - Drop - - - { - setShowCache(false) - setOpen(true) - }} - > - - Details - - - deleteTorrent(torrentLocalComponentValue)}> - - Delete - - - - - - Name - {title || name} - - - - - Size - - {torrent_size > 0 && humanizeSize(torrent_size)} - - - - - Speed - - {download_speed > 0 ? humanizeSize(download_speed) : '---'} - - - - - Peers - - {getPeerString(torrentLocalComponentValue) || '---'} - - - - - - - - setOpen(false)} torrent={torrentLocalComponentValue} /> - - - {/* - {showCache ? ( - - ) : ( - - )} - - - - */} - - ) -} - -function getTorrent(hash, callback) { - try { - fetch(torrentsHost(), { - method: 'post', - body: JSON.stringify({ action: 'get', hash }), - headers: { - Accept: 'application/json, text/plain, */*', - 'Content-Type': 'application/json', - }, - }) - .then(res => res.json()) - .then( - json => { - callback(json, null) - }, - error => { - callback(null, error) - }, - ) - } catch (e) { - console.error(e) - } -} - -function deleteTorrent(torrent) { - try { - fetch(torrentsHost(), { - method: 'post', - body: JSON.stringify({ - action: 'rem', - hash: torrent.hash, - }), - headers: { - Accept: 'application/json, text/plain, */*', - 'Content-Type': 'application/json', - }, - }) - } catch (e) { - console.error(e) - } -} - -function dropTorrent(torrent) { - try { - fetch(torrentsHost(), { - method: 'post', - body: JSON.stringify({ - action: 'drop', - hash: torrent.hash, - }), - headers: { - Accept: 'application/json, text/plain, */*', - 'Content-Type': 'application/json', - }, - }) - } catch (e) { - console.error(e) - } -} diff --git a/web/src/components/TorrentCard/index.jsx b/web/src/components/TorrentCard/index.jsx new file mode 100644 index 0000000..30f7947 --- /dev/null +++ b/web/src/components/TorrentCard/index.jsx @@ -0,0 +1,132 @@ +/* eslint-disable camelcase */ +import 'fontsource-roboto' +import { forwardRef, useState } from 'react' +import HeightIcon from '@material-ui/icons/Height' +import CloseIcon from '@material-ui/icons/Close' +import DeleteIcon from '@material-ui/icons/Delete' +import { getPeerString, humanizeSize } from 'utils/Utils' +import { torrentsHost } from 'utils/Hosts' +import { NoImageIcon } from 'icons' +import DialogTorrentDetailsContent from 'components/DialogTorrentDetailsContent' +import Dialog from '@material-ui/core/Dialog' +import Slide from '@material-ui/core/Slide' +import { Button, DialogActions, DialogTitle, useMediaQuery, useTheme } from '@material-ui/core' +import axios from 'axios' + +import { + StyledButton, + TorrentCard, + TorrentCardButtons, + TorrentCardDescription, + TorrentCardDescriptionContent, + TorrentCardDescriptionLabel, + TorrentCardPoster, + TorrentCardDetails, +} from './style' + +const Transition = forwardRef((props, ref) => ) + +export default function Torrent({ torrent }) { + const [isDetailedInfoOpened, setIsDetailedInfoOpened] = useState(false) + const [isDeleteTorrentOpened, setIsDeleteTorrentOpened] = useState(false) + + const theme = useTheme() + const fullScreen = useMediaQuery(theme.breakpoints.down('md')) + + const openDetailedInfo = () => setIsDetailedInfoOpened(true) + const closeDetailedInfo = () => setIsDetailedInfoOpened(false) + const openDeleteTorrentAlert = () => setIsDeleteTorrentOpened(true) + const closeDeleteTorrentAlert = () => setIsDeleteTorrentOpened(false) + + const { title, name, poster, torrent_size, download_speed, hash } = torrent + + const dropTorrent = () => axios.post(torrentsHost(), { action: 'drop', hash }) + const deleteTorrent = () => axios.post(torrentsHost(), { action: 'rem', hash }) + + return ( + <> + + + {poster ? poster : } + + + + + + Details + + + dropTorrent(torrent)}> + + Drop + + + + + Delete + + + + + + Name + {title || name} + + + + + Size + + {torrent_size > 0 && humanizeSize(torrent_size)} + + + + + Speed + + {download_speed > 0 ? humanizeSize(download_speed) : '---'} + + + + + Peers + {getPeerString(torrent) || '---'} + + + + + + + + + + + Delete Torrent? + + + + + + + + ) +} diff --git a/web/src/components/Torrent/style.js b/web/src/components/TorrentCard/style.js similarity index 100% rename from web/src/components/Torrent/style.js rename to web/src/components/TorrentCard/style.js diff --git a/web/src/components/TorrentList.jsx b/web/src/components/TorrentList.jsx index 4fbaaa7..7b33671 100644 --- a/web/src/components/TorrentList.jsx +++ b/web/src/components/TorrentList.jsx @@ -2,7 +2,8 @@ import styled from 'styled-components' import { useEffect, useRef, useState } from 'react' import { Typography } from '@material-ui/core' import { torrentsHost } from 'utils/Hosts' -import Torrent from 'components/Torrent' +import TorrentCard from 'components/TorrentCard' +import axios from 'axios' const TorrentListWrapper = styled.div` display: grid; @@ -19,43 +20,29 @@ const TorrentListWrapper = styled.div` } ` -const getTorrentList = (callback, errorCallback) => { - fetch(torrentsHost(), { - method: 'post', - body: JSON.stringify({ action: 'list' }), - headers: { - Accept: 'application/json, text/plain, */*', - 'Content-Type': 'application/json', - }, - }) - .then(res => res.json()) - .then(callback) - .catch(() => errorCallback()) -} - export default function TorrentList() { const [torrents, setTorrents] = useState([]) const [offline, setOffline] = useState(true) const timerID = useRef(-1) - const updateTorrentList = torrs => { - setTorrents(torrs) - setOffline(false) - } - - const resetTorrentList = () => { - setTorrents([]) - setOffline(true) - } - useEffect(() => { timerID.current = setInterval(() => { - getTorrentList(updateTorrentList, resetTorrentList) + // getting torrent list + axios + .post(torrentsHost(), { action: 'list' }) + .then(({ data }) => { + // updating torrent list + setTorrents(data) + setOffline(false) + }) + .catch(() => { + // resetting torrent list + setTorrents([]) + setOffline(true) + }) }, 1000) - return () => { - clearInterval(timerID.current) - } + return () => clearInterval(timerID.current) }, []) return ( @@ -65,7 +52,7 @@ export default function TorrentList() { ) : !torrents.length ? ( No torrents added ) : ( - torrents && torrents.map(torrent => ) + torrents.map(torrent => ) )} )