184 lines
4.7 KiB
JavaScript
184 lines
4.7 KiB
JavaScript
import React, { useState, useEffect } from "react"
|
|
import PropTypes from "prop-types"
|
|
import { Map, List } from "immutable"
|
|
import { connect } from "react-redux"
|
|
import { fetchTorrents, addTorrent, removeTorrent } from "../../actions/torrents"
|
|
|
|
const mapStateToProps = (state) => ({
|
|
torrents: state.torrentStore.get("torrents")
|
|
});
|
|
const mapDispatchToProps = {
|
|
fetchTorrents, addTorrent, removeTorrent,
|
|
};
|
|
|
|
const TorrentList = (props) => {
|
|
const [fetched, setIsFetched] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const intervalID = setInterval(() => {
|
|
props.fetchTorrents();
|
|
}, 10000);
|
|
|
|
return () => {
|
|
clearInterval(intervalID);
|
|
};
|
|
});
|
|
|
|
if (!fetched) {
|
|
props.fetchTorrents();
|
|
setIsFetched(true);
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<AddTorrent addTorrent={props.addTorrent} />
|
|
<Torrents
|
|
torrents={props.torrents}
|
|
removeTorrent={props.removeTorrent}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
TorrentList.propTypes = {
|
|
fetchTorrents: PropTypes.func.isRequired,
|
|
addTorrent: PropTypes.func.isRequired,
|
|
removeTorrent: PropTypes.func.isRequired,
|
|
torrents: PropTypes.instanceOf(List),
|
|
};
|
|
export default connect(mapStateToProps, mapDispatchToProps)(TorrentList);
|
|
|
|
const AddTorrent = (props) => {
|
|
const [url, setUrl] = useState("");
|
|
|
|
const handleSubmit = (ev) => {
|
|
if (ev) { ev.preventDefault(); }
|
|
if (url === "") { return; }
|
|
props.addTorrent(url);
|
|
setUrl("");
|
|
}
|
|
|
|
return (
|
|
<div className="row">
|
|
<div className="col-xs-12 col-md-12">
|
|
<form className="input-group" onSubmit={() => handleSubmit()}>
|
|
<input
|
|
className="form-control"
|
|
placeholder="Add torrent URL"
|
|
value={url}
|
|
onChange={(e) => setUrl(e.target.value)}
|
|
/>
|
|
<span className="input-group-btn">
|
|
<button
|
|
className="btn btn-primary"
|
|
type="button"
|
|
onClick={() => handleSubmit()}
|
|
>
|
|
Add
|
|
</button>
|
|
</span>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
AddTorrent.propTypes = {
|
|
addTorrent: PropTypes.func.isRequired,
|
|
};
|
|
|
|
const Torrents = (props) => {
|
|
if (props.torrents.size === 0) {
|
|
return (
|
|
<div className="row">
|
|
<div className="col-xs-12 col-md-12">
|
|
<h3>Torrents</h3>
|
|
<div className="panel panel-default">
|
|
<div className="panel-heading">No torrents</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="row">
|
|
<div className="col-xs-12 col-md-12">
|
|
<h3>Torrents</h3>
|
|
{props.torrents.map((el, index) => (
|
|
<Torrent
|
|
key={index}
|
|
data={el}
|
|
removeTorrent={props.removeTorrent}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
Torrents.propTypes = {
|
|
removeTorrent: PropTypes.func.isRequired,
|
|
torrents: PropTypes.instanceOf(List),
|
|
};
|
|
|
|
const Torrent = (props) => {
|
|
const handleClick = () => {
|
|
props.removeTorrent(props.data.get("id"));
|
|
}
|
|
|
|
const done = props.data.get("is_finished");
|
|
var progressStyle = "progress-bar progress-bar-info active";
|
|
if (done) {
|
|
progressStyle = "progress-bar progress-bar-success";
|
|
}
|
|
var percentDone = props.data.get("percent_done");
|
|
const started = (percentDone !== 0);
|
|
if (started) {
|
|
percentDone = Number(percentDone).toFixed(1) + "%";
|
|
}
|
|
|
|
// Pretty sizes
|
|
const downloadedSize = prettySize(props.data.get("downloaded_size"));
|
|
const totalSize = prettySize(props.data.get("total_size"));
|
|
const downloadRate = prettySize(props.data.get("download_rate")) + "/s";
|
|
return (
|
|
<div className="panel panel-default">
|
|
<div className="panel-heading">
|
|
{props.data.get("name")}
|
|
<span className="fa fa-trash clickable pull-right" onClick={() => handleClick()}></span>
|
|
</div>
|
|
<div className="panel-body">
|
|
{started &&
|
|
<div className="progress progress-striped">
|
|
<div
|
|
className={progressStyle}
|
|
style={{width: percentDone}}>
|
|
</div>
|
|
</div>
|
|
}
|
|
{!started &&
|
|
<p>Download not yet started</p>
|
|
}
|
|
{started &&
|
|
<div>
|
|
<p>{downloadedSize} / {totalSize} - {percentDone} - {downloadRate}</p>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
Torrent.propTypes = {
|
|
removeTorrent: PropTypes.func.isRequired,
|
|
data: PropTypes.instanceOf(Map),
|
|
};
|
|
|
|
const prettySize = (fileSizeInBytes) => {
|
|
var i = -1;
|
|
var byteUnits = [" kB", " MB", " GB", " TB", "PB", "EB", "ZB", "YB"];
|
|
do {
|
|
fileSizeInBytes = fileSizeInBytes / 1024;
|
|
i++;
|
|
} while (fileSizeInBytes > 1024);
|
|
|
|
return Math.max(fileSizeInBytes, 0.1).toFixed(1) + byteUnits[i];
|
|
};
|