From c144ef960dd34db3fe3f03e2e07f5b7bc6b05d25 Mon Sep 17 00:00:00 2001 From: Daniel Shleifman Date: Wed, 9 Jun 2021 12:48:43 +0300 Subject: [PATCH] refactor --- web/src/components/Add/AddDialog.jsx | 281 ++---------------- web/src/components/Add/helpers.js | 23 ++ web/src/components/Add/style.js | 236 +++++++++++++++ .../DetailedView/index.jsx | 6 +- .../DialogTorrentDetailsContent/index.jsx | 5 +- .../DialogTorrentDetailsContent/widgets.jsx | 27 +- 6 files changed, 306 insertions(+), 272 deletions(-) create mode 100644 web/src/components/Add/helpers.js create mode 100644 web/src/components/Add/style.js diff --git a/web/src/components/Add/AddDialog.jsx b/web/src/components/Add/AddDialog.jsx index 7766ed5..a4c1aa1 100644 --- a/web/src/components/Add/AddDialog.jsx +++ b/web/src/components/Add/AddDialog.jsx @@ -5,7 +5,6 @@ import Dialog from '@material-ui/core/Dialog' import { torrentsHost, torrentUploadHost } from 'utils/Hosts' import axios from 'axios' import { useTranslation } from 'react-i18next' -import styled, { css } from 'styled-components' import { NoImageIcon, AddItemIcon, TorrentIcon } from 'icons' import debounce from 'lodash/debounce' import { v4 as uuidv4 } from 'uuid' @@ -14,260 +13,25 @@ import { Cancel as CancelIcon } from '@material-ui/icons' import { useDropzone } from 'react-dropzone' import { useMediaQuery } from '@material-ui/core' -const Header = styled.div` - background: #00a572; - color: rgba(0, 0, 0, 0.87); - font-size: 20px; - color: #fff; - font-weight: 500; - box-shadow: 0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%); - padding: 15px 24px; - position: relative; -` - -const Content = styled.div` - background: linear-gradient(145deg, #e4f6ed, #b5dec9); - flex: 1; - display: grid; - grid-template-columns: repeat(2, 1fr); - border-bottom: 1px solid rgba(0, 0, 0, 0.12); - overflow: auto; - - @media (max-width: 930px) { - grid-template-columns: 1fr; - } -` - -const LeftSide = styled.div` - padding: 0 20px 20px 20px; - border-right: 1px solid rgba(0, 0, 0, 0.12); -` -const RightSide = styled.div` - display: flex; - flex-direction: column; -` - -const RightSideBottomSectionBasicStyles = css` - transition: transform 0.3s; - padding: 20px; - height: 100%; - display: grid; -` - -const RightSideBottomSectionNoFile = styled.div` - ${RightSideBottomSectionBasicStyles} - border: 4px dashed transparent; - - ${({ isDragActive }) => isDragActive && `border: 4px dashed green`}; - - justify-items: center; - grid-template-rows: 100px 1fr; - cursor: pointer; - - :hover { - background-color: rgba(0, 0, 0, 0.04); - svg { - transform: translateY(-4%); - } - } - - @media (max-width: 930px) { - height: 400px; - place-items: center; - grid-template-rows: 40% 1fr; - } -` - -const RightSideBottomSectionFileSelected = styled.div` - ${RightSideBottomSectionBasicStyles} - place-items: center; - - @media (max-width: 930px) { - height: 400px; - } -` - -const TorrentIconWrapper = styled.div` - position: relative; -` - -const CancelIconWrapper = styled.div` - position: absolute; - top: -9px; - left: 10px; - cursor: pointer; - - > svg { - transition: all 0.3s; - fill: rgba(0, 0, 0, 0.7); - - :hover { - fill: rgba(0, 0, 0, 0.6); - } - } -` - -const IconWrapper = styled.div` - display: grid; - justify-items: center; - align-content: start; - gap: 10px; - align-self: start; - - svg { - transition: all 0.3s; - } -` - -const RightSideTopSection = styled.div` - background: #e3f2eb; - padding: 0 20px 20px 20px; - transition: all 0.3s; - - ${({ active }) => active && 'box-shadow: 0 8px 10px -9px rgba(0, 0, 0, 0.5)'}; -` - -const PosterWrapper = styled.div` - margin-top: 20px; - display: grid; - grid-template-columns: max-content 1fr; - grid-template-rows: 300px max-content; - column-gap: 5px; - position: relative; - margin-bottom: 20px; - - grid-template-areas: - 'poster suggestions' - 'clear empty'; - - @media (max-width: 540px) { - grid-template-columns: 1fr; - gap: 5px 0; - justify-items: center; - grid-template-areas: - 'poster' - 'clear' - 'suggestions'; - } -` -const PosterSuggestions = styled.div` - display: grid; - grid-area: suggestions; - grid-template-columns: repeat(3, max-content); - grid-template-rows: repeat(4, max-content); - gap: 5px; - - @media (max-width: 540px) { - grid-template-columns: repeat(5, max-content); - } - @media (max-width: 375px) { - grid-template-columns: repeat(4, max-content); - } -` -const PosterSuggestionsItem = styled.div` - cursor: pointer; - width: 71px; - height: 71px; - - @media (max-width: 430px) { - width: 60px; - height: 60px; - } - - @media (max-width: 375px) { - width: 71px; - height: 71px; - } - - @media (max-width: 355px) { - width: 60px; - height: 60px; - } - - img { - transition: all 0.3s; - border-radius: 5px; - width: 100%; - height: 100%; - object-fit: cover; - - :hover { - filter: brightness(130%); - } - } -` - -export const Poster = styled.div` - ${({ poster }) => css` - border-radius: 5px; - overflow: hidden; - width: 200px; - grid-area: poster; - - ${poster - ? css` - img { - width: 200px; - object-fit: cover; - border-radius: 5px; - height: 100%; - } - ` - : css` - display: grid; - place-items: center; - background: #74c39c; - - svg { - transform: scale(1.5) translateY(-3px); - } - `} - `} -` - -const ClearPosterButton = styled(Button)` - grid-area: clear; - justify-self: center; - transform: translateY(-50%); - position: absolute; - ${({ showbutton }) => !showbutton && 'display: none'}; - - @media (max-width: 540px) { - transform: translateY(-140%); - } -` - -const ButtonWrapper = styled.div` - padding: 20px; - display: flex; - justify-content: flex-end; - - > :not(:last-child) { - margin-right: 10px; - } -` - -const getMoviePosters = (movieName, language = 'en') => { - const request = `${`http://api.themoviedb.org/3/search/multi?api_key=${process.env.REACT_APP_TMDB_API_KEY}`}&language=${language}&include_image_language=${language},null&query=${movieName}` - - return axios - .get(request) - .then(({ data: { results } }) => - results.filter(el => el.poster_path).map(el => `https://image.tmdb.org/t/p/w300${el.poster_path}`), - ) - .catch(() => null) -} - -const checkImageURL = async url => { - if (!url || !url.match(/.(jpg|jpeg|png|gif)$/i)) return false - - try { - await fetch(url) - return true - } catch (e) { - return false - } -} +import { + ButtonWrapper, + CancelIconWrapper, + ClearPosterButton, + Content, + Header, + IconWrapper, + LeftSide, + Poster, + PosterSuggestions, + PosterSuggestionsItem, + PosterWrapper, + RightSide, + RightSideBottomSectionFileSelected, + RightSideBottomSectionNoFile, + RightSideTopSection, + TorrentIconWrapper, +} from './style' +import { checkImageURL, getMoviePosters } from './helpers' export default function AddDialog({ handleClose }) { const { t } = useTranslation() @@ -338,16 +102,18 @@ export default function AddDialog({ handleClose }) { const handleSave = () => { if (selectedFile) { + // file save const data = new FormData() data.append('save', 'true') data.append('file', selectedFile) title && data.append('title', title) posterUrl && data.append('poster', posterUrl) - axios.post(torrentUploadHost(), data).finally(() => handleClose()) + axios.post(torrentUploadHost(), data).finally(handleClose) } else { + // link save axios .post(torrentsHost(), { action: 'add', link: torrentSource, title, poster: posterUrl, save_to_db: true }) - .finally(() => handleClose()) + .finally(handleClose) } } @@ -396,6 +162,7 @@ export default function AddDialog({ handleClose }) { {isPosterUrlCorrect ? poster : } + {posterList ?.filter(url => url !== posterUrl) diff --git a/web/src/components/Add/helpers.js b/web/src/components/Add/helpers.js new file mode 100644 index 0000000..215d2f8 --- /dev/null +++ b/web/src/components/Add/helpers.js @@ -0,0 +1,23 @@ +import axios from 'axios' + +export const getMoviePosters = (movieName, language = 'en') => { + const request = `${`http://api.themoviedb.org/3/search/multi?api_key=${process.env.REACT_APP_TMDB_API_KEY}`}&language=${language}&include_image_language=${language},null&query=${movieName}` + + return axios + .get(request) + .then(({ data: { results } }) => + results.filter(el => el.poster_path).map(el => `https://image.tmdb.org/t/p/w300${el.poster_path}`), + ) + .catch(() => null) +} + +export const checkImageURL = async url => { + if (!url || !url.match(/.(jpg|jpeg|png|gif)$/i)) return false + + try { + await fetch(url) + return true + } catch (e) { + return false + } +} diff --git a/web/src/components/Add/style.js b/web/src/components/Add/style.js new file mode 100644 index 0000000..bb475f4 --- /dev/null +++ b/web/src/components/Add/style.js @@ -0,0 +1,236 @@ +import { Button } from '@material-ui/core' +import styled, { css } from 'styled-components' + +export const Header = styled.div` + background: #00a572; + color: rgba(0, 0, 0, 0.87); + font-size: 20px; + color: #fff; + font-weight: 500; + box-shadow: 0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%); + padding: 15px 24px; + position: relative; +` + +export const Content = styled.div` + background: linear-gradient(145deg, #e4f6ed, #b5dec9); + flex: 1; + display: grid; + grid-template-columns: repeat(2, 1fr); + border-bottom: 1px solid rgba(0, 0, 0, 0.12); + overflow: auto; + + @media (max-width: 930px) { + grid-template-columns: 1fr; + } +` + +export const LeftSide = styled.div` + padding: 0 20px 20px 20px; + border-right: 1px solid rgba(0, 0, 0, 0.12); +` +export const RightSide = styled.div` + display: flex; + flex-direction: column; +` + +export const RightSideBottomSectionBasicStyles = css` + transition: transform 0.3s; + padding: 20px; + height: 100%; + display: grid; +` + +export const RightSideBottomSectionNoFile = styled.div` + ${RightSideBottomSectionBasicStyles} + border: 4px dashed transparent; + text-align: center; + + ${({ isDragActive }) => isDragActive && `border: 4px dashed green`}; + + justify-items: center; + grid-template-rows: 100px 1fr; + cursor: pointer; + + :hover { + background-color: rgba(0, 0, 0, 0.04); + svg { + transform: translateY(-4%); + } + } + + @media (max-width: 930px) { + height: 400px; + place-items: center; + grid-template-rows: 40% 1fr; + } +` + +export const RightSideBottomSectionFileSelected = styled.div` + ${RightSideBottomSectionBasicStyles} + place-items: center; + + @media (max-width: 930px) { + height: 400px; + } +` + +export const TorrentIconWrapper = styled.div` + position: relative; +` + +export const CancelIconWrapper = styled.div` + position: absolute; + top: -9px; + left: 10px; + cursor: pointer; + + > svg { + transition: all 0.3s; + fill: rgba(0, 0, 0, 0.7); + + :hover { + fill: rgba(0, 0, 0, 0.6); + } + } +` + +export const IconWrapper = styled.div` + display: grid; + justify-items: center; + align-content: start; + gap: 10px; + align-self: start; + + svg { + transition: all 0.3s; + } +` + +export const RightSideTopSection = styled.div` + background: #e3f2eb; + padding: 0 20px 20px 20px; + transition: all 0.3s; + + ${({ active }) => active && 'box-shadow: 0 8px 10px -9px rgba(0, 0, 0, 0.5)'}; +` + +export const PosterWrapper = styled.div` + margin-top: 20px; + display: grid; + grid-template-columns: max-content 1fr; + grid-template-rows: 300px max-content; + column-gap: 5px; + position: relative; + margin-bottom: 20px; + + grid-template-areas: + 'poster suggestions' + 'clear empty'; + + @media (max-width: 540px) { + grid-template-columns: 1fr; + gap: 5px 0; + justify-items: center; + grid-template-areas: + 'poster' + 'clear' + 'suggestions'; + } +` +export const PosterSuggestions = styled.div` + display: grid; + grid-area: suggestions; + grid-template-columns: repeat(3, max-content); + grid-template-rows: repeat(4, max-content); + gap: 5px; + + @media (max-width: 540px) { + grid-template-columns: repeat(5, max-content); + } + @media (max-width: 375px) { + grid-template-columns: repeat(4, max-content); + } +` +export const PosterSuggestionsItem = styled.div` + cursor: pointer; + width: 71px; + height: 71px; + + @media (max-width: 430px) { + width: 60px; + height: 60px; + } + + @media (max-width: 375px) { + width: 71px; + height: 71px; + } + + @media (max-width: 355px) { + width: 60px; + height: 60px; + } + + img { + transition: all 0.3s; + border-radius: 5px; + width: 100%; + height: 100%; + object-fit: cover; + + :hover { + filter: brightness(130%); + } + } +` + +export const Poster = styled.div` + ${({ poster }) => css` + border-radius: 5px; + overflow: hidden; + width: 200px; + grid-area: poster; + + ${poster + ? css` + img { + width: 200px; + object-fit: cover; + border-radius: 5px; + height: 100%; + } + ` + : css` + display: grid; + place-items: center; + background: #74c39c; + + svg { + transform: scale(1.5) translateY(-3px); + } + `} + `} +` + +export const ClearPosterButton = styled(Button)` + grid-area: clear; + justify-self: center; + transform: translateY(-50%); + position: absolute; + ${({ showbutton }) => !showbutton && 'display: none'}; + + @media (max-width: 540px) { + transform: translateY(-140%); + } +` + +export const ButtonWrapper = styled.div` + padding: 20px; + display: flex; + justify-content: flex-end; + + > :not(:last-child) { + margin-right: 10px; + } +` diff --git a/web/src/components/DialogTorrentDetailsContent/DetailedView/index.jsx b/web/src/components/DialogTorrentDetailsContent/DetailedView/index.jsx index a65a7e5..aa037ed 100644 --- a/web/src/components/DialogTorrentDetailsContent/DetailedView/index.jsx +++ b/web/src/components/DialogTorrentDetailsContent/DetailedView/index.jsx @@ -11,14 +11,14 @@ import { DownlodSpeedWidget, } from '../widgets' -export default function Test({ +export default function DetailedView({ downloadSpeed, uploadSpeed, torrent, torrentSize, PiecesCount, PiecesLength, - statString, + stat, cache, }) { return ( @@ -32,7 +32,7 @@ export default function Test({ - + diff --git a/web/src/components/DialogTorrentDetailsContent/index.jsx b/web/src/components/DialogTorrentDetailsContent/index.jsx index e1cdd42..f4ee8b7 100644 --- a/web/src/components/DialogTorrentDetailsContent/index.jsx +++ b/web/src/components/DialogTorrentDetailsContent/index.jsx @@ -54,7 +54,6 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) { stat, download_speed: downloadSpeed, upload_speed: uploadSpeed, - stat_string: statString, torrent_size: torrentSize, file_stats: torrentFileList, } = torrent @@ -133,7 +132,7 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) { torrentSize={torrentSize} PiecesCount={PiecesCount} PiecesLength={PiecesLength} - statString={statString} + stat={stat} cache={cache} /> ) : ( @@ -156,7 +155,7 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) { - + diff --git a/web/src/components/DialogTorrentDetailsContent/widgets.jsx b/web/src/components/DialogTorrentDetailsContent/widgets.jsx index a8d5f69..a4a1437 100644 --- a/web/src/components/DialogTorrentDetailsContent/widgets.jsx +++ b/web/src/components/DialogTorrentDetailsContent/widgets.jsx @@ -9,6 +9,7 @@ import { } from '@material-ui/icons' import { getPeerString, humanizeSize } from 'utils/Utils' import { useTranslation } from 'react-i18next' +import { GETTING_INFO, IN_DB, CLOSED, PRELOAD, WORKING } from 'torrentStates' import StatisticsField from './StatisticsField' @@ -69,17 +70,25 @@ export const PiecesLengthWidget = ({ data }) => { ) } -export const StatusWidget = ({ data }) => { +export const StatusWidget = ({ stat }) => { const { t } = useTranslation() - let i18nd = data - if (data.toLowerCase() === 'torrent added') i18nd = t('TorrentAdded') - else if (data.toLowerCase() === 'torrent getting info') i18nd = t('TorrentGettingInfo') - else if (data.toLowerCase() === 'torrent preload') i18nd = t('TorrentPreload') - else if (data.toLowerCase() === 'torrent working') i18nd = t('TorrentWorking') - else if (data.toLowerCase() === 'torrent closed') i18nd = t('TorrentClosed') - else if (data.toLowerCase() === 'torrent in db') i18nd = t('TorrentInDb') + + const values = { + [GETTING_INFO]: t('TorrentGettingInfo'), + [PRELOAD]: t('TorrentPreload'), + [WORKING]: t('TorrentWorking'), + [CLOSED]: t('TorrentClosed'), + [IN_DB]: t('TorrentInDb'), + } + return ( - + ) }