Grégoire Delattre 83d1894a25 Fix torrent search on every keystroke
Cleanup the search results when leaving the page.
2020-04-10 17:09:43 +02:00

208 lines
5.1 KiB
JavaScript

import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import { useDispatch, useSelector } from "react-redux";
import Loader from "../loader/loader";
import { OverlayTrigger, Tooltip } from "react-bootstrap";
import { prettySize } from "../../utils";
import {
addTorrent,
searchTorrents,
clearTorrentSearch,
} from "../../actions/torrents";
export const TorrentSearch = ({ history, match }) => {
const dispatch = useDispatch();
const [search, setSearch] = useState(match.params.search || "");
const [type, setType] = useState(match.params.type || "");
const searchFunc = (type = "") => {
if (search === "" || type === "") {
return;
}
const url = `/torrents/search/${type}/${encodeURI(search)}`;
setType(type);
dispatch(searchTorrents(url));
history.push(url);
};
useEffect(() => {
searchFunc(type);
return () => dispatch(clearTorrentSearch());
}, []); // eslint-disable-line react-hooks/exhaustive-deps
return (
<div className="row">
<div className="col-12 d-flex flex-row flex-wrap">
<input
type="text"
className="form-control mb-1 w-100 form-control-lg"
placeholder="Search torrents"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<div className="mb-3 w-100 d-flex">
<SearchButton
text="Search movies"
type="movies"
typeFromURL={type}
handleClick={() => {
searchFunc("movies");
}}
/>
<SearchButton
text="Search shows"
type="shows"
typeFromURL={type}
handleClick={() => {
searchFunc("shows");
}}
/>
</div>
</div>
<div className="col-12">
<TorrentList />
</div>
</div>
);
};
TorrentSearch.propTypes = {
search: PropTypes.string,
match: PropTypes.object,
history: PropTypes.object,
};
const SearchButton = ({ type, typeFromURL, text, handleClick }) => {
const variant = type === typeFromURL ? "primary" : "secondary";
return (
<button
type="button"
className={`w-50 btn m-1 btn-lg btn-${variant}`}
onClick={handleClick}
>
<i className="fa fa-search" aria-hidden="true"></i> {text}
</button>
);
};
SearchButton.propTypes = {
type: PropTypes.string,
typeFromURL: PropTypes.string,
text: PropTypes.string,
handleClick: PropTypes.func.isRequired,
};
const TorrentList = () => {
const searching = useSelector((state) => state.torrents.searching);
const results = useSelector((state) => state.torrents.searchResults);
if (searching) {
return <Loader />;
}
if (results.size === 0) {
return (
<div className="jumbotron">
<h2>No results</h2>
</div>
);
}
return (
<React.Fragment>
{results.map(function (el, index) {
return <Torrent key={index} torrent={el} />;
})}
</React.Fragment>
);
};
const Torrent = ({ torrent }) => {
const dispatch = useDispatch();
return (
<div className="alert d-flex border-bottom border-secondary align-items-center">
<TorrentHealth
url={torrent.result.url}
seeders={torrent.result.seeders}
leechers={torrent.result.leechers}
/>
<span className="mx-3 text text-start text-break flex-fill">
{torrent.result.name}
</span>
<div>
{torrent.result.size !== 0 && (
<span className="mx-1 badge badge-pill badge-warning">
{prettySize(torrent.result.size)}
</span>
)}
<span className="mx-1 badge badge-pill badge-warning">
{torrent.quality}
</span>
<span className="mx-1 badge badge-pill badge-success">
{torrent.result.source}
</span>
<span className="mx-1 badge badge-pill badge-info">
{torrent.result.upload_user}
</span>
</div>
<div className="align-self-end ml-3">
<i
className="fa fa-cloud-download clickable"
onClick={() => dispatch(addTorrent(torrent))}
></i>
</div>
</div>
);
};
Torrent.propTypes = {
torrent: PropTypes.object.isRequired,
};
const TorrentHealth = ({ url, seeders = 0, leechers = 1 }) => {
let color;
let health;
let ratio = seeders / leechers;
if (seeders > 20) {
health = "good";
color = "success";
} else {
if (ratio > 1) {
health = "medium";
color = "warning";
} else {
health = "bad";
color = "danger";
}
}
const className = `align-self-start text text-center text-${color}`;
const tooltip = (
<Tooltip id={`tooltip-health-${url}`}>
<p>
<span className={className}>Health: {health}</span>
</p>
<p>Seeders: {seeders}</p>
<p>Leechers: {leechers}</p>
</Tooltip>
);
return (
<OverlayTrigger placement="right" overlay={tooltip}>
<span className={className}>
<i className="fa fa-circle" aria-hidden="true"></i>
</span>
</OverlayTrigger>
);
};
TorrentHealth.propTypes = {
url: PropTypes.string,
seeders: PropTypes.number,
leechers: PropTypes.number,
};