Compare commits
16 Commits
937b12bb67
...
817da07a2d
Author | SHA1 | Date | |
---|---|---|---|
817da07a2d | |||
af2641c317 | |||
d9fae3e23a | |||
e7f96a1bd7 | |||
2e83c3169f | |||
6ac382b659 | |||
81f497170f | |||
6cfee5ea74 | |||
ea62b1c6ec | |||
d998d2838d | |||
27f5c5d558 | |||
27f0b742a4 | |||
ac0d746cc9 | |||
c5336c477a | |||
834ee8bcfc | |||
5f7d402614 |
@ -12,6 +12,7 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- cd frontend
|
- cd frontend
|
||||||
- npm install
|
- npm install
|
||||||
|
- npm run-script lint
|
||||||
- npm run-script build
|
- npm run-script build
|
||||||
|
|
||||||
- name: backend
|
- name: backend
|
||||||
|
@ -28,12 +28,10 @@ import { AdminPanel } from "./components/admins/panel";
|
|||||||
import { Notifications } from "./components/notifications/notifications";
|
import { Notifications } from "./components/notifications/notifications";
|
||||||
import Alert from "./components/alerts/alert";
|
import Alert from "./components/alerts/alert";
|
||||||
import MovieList from "./components/movies/list";
|
import MovieList from "./components/movies/list";
|
||||||
import MoviesRoute from "./components/movies/route";
|
|
||||||
import NavBar from "./components/navbar";
|
import NavBar from "./components/navbar";
|
||||||
import WsHandler from "./components/websocket";
|
import WsHandler from "./components/websocket";
|
||||||
import { ShowDetails } from "./components/shows/details";
|
import { ShowDetails } from "./components/shows/details";
|
||||||
import ShowList from "./components/shows/list";
|
import ShowList from "./components/shows/list";
|
||||||
import ShowsRoute from "./components/shows/route";
|
|
||||||
import TorrentList from "./components/torrents/list";
|
import TorrentList from "./components/torrents/list";
|
||||||
import TorrentSearch from "./components/torrents/search";
|
import TorrentSearch from "./components/torrents/search";
|
||||||
import UserActivation from "./components/users/activation";
|
import UserActivation from "./components/users/activation";
|
||||||
@ -61,31 +59,23 @@ const App = () => (
|
|||||||
exact
|
exact
|
||||||
component={TorrentSearch}
|
component={TorrentSearch}
|
||||||
/>
|
/>
|
||||||
<MoviesRoute path="/movies/polochon" exact component={MovieList} />
|
<Route path="/movies/polochon" exact component={MovieList} />
|
||||||
<MoviesRoute path="/movies/wishlist" exact component={MovieList} />
|
<Route path="/movies/wishlist" exact component={MovieList} />
|
||||||
<MoviesRoute
|
<Route path="/movies/search/:search" exact component={MovieList} />
|
||||||
path="/movies/search/:search"
|
<Route
|
||||||
exact
|
|
||||||
component={MovieList}
|
|
||||||
/>
|
|
||||||
<MoviesRoute
|
|
||||||
path="/movies/explore/:source/:category"
|
path="/movies/explore/:source/:category"
|
||||||
exact
|
exact
|
||||||
component={MovieList}
|
component={MovieList}
|
||||||
/>
|
/>
|
||||||
<ShowsRoute path="/shows/polochon" exact component={ShowList} />
|
<Route path="/shows/polochon" exact component={ShowList} />
|
||||||
<ShowsRoute path="/shows/wishlist" exact component={ShowList} />
|
<Route path="/shows/wishlist" exact component={ShowList} />
|
||||||
<ShowsRoute path="/shows/search/:search" exact component={ShowList} />
|
<Route path="/shows/search/:search" exact component={ShowList} />
|
||||||
<ShowsRoute
|
<Route
|
||||||
path="/shows/explore/:source/:category"
|
path="/shows/explore/:source/:category"
|
||||||
exact
|
exact
|
||||||
component={ShowList}
|
component={ShowList}
|
||||||
/>
|
/>
|
||||||
<ShowsRoute
|
<Route path="/shows/details/:imdbId" exact component={ShowDetails} />
|
||||||
path="/shows/details/:imdbId"
|
|
||||||
exact
|
|
||||||
component={ShowDetails}
|
|
||||||
/>
|
|
||||||
<Route render={() => <Redirect to="/movies/explore/yts/seeds" />} />
|
<Route render={() => <Redirect to="/movies/explore/yts/seeds" />} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</Container>
|
</Container>
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { Route, Redirect } from "react-router-dom";
|
import { Route, Redirect } from "react-router-dom";
|
||||||
|
|
||||||
import { setUserToken } from "./actions/users";
|
import { setUserToken } from "./actions/users";
|
||||||
|
|
||||||
const protectedRoute = ({
|
export const ProtectedRoute = ({ component: Component, ...otherProps }) => {
|
||||||
component: Component,
|
const dispatch = useDispatch();
|
||||||
isLogged,
|
|
||||||
isActivated,
|
const isLogged = useSelector((state) => state.userStore.get("isLogged"));
|
||||||
isTokenSet,
|
const isActivated = useSelector((state) =>
|
||||||
setUserToken,
|
state.userStore.get("isActivated")
|
||||||
...otherProps
|
);
|
||||||
}) => {
|
const isTokenSet = useSelector((state) => state.userStore.get("isTokenSet"));
|
||||||
|
|
||||||
const isAuthenticated = () => {
|
const isAuthenticated = () => {
|
||||||
if (isTokenSet) {
|
if (isTokenSet) {
|
||||||
return true;
|
return true;
|
||||||
@ -20,7 +22,7 @@ const protectedRoute = ({
|
|||||||
const token = localStorage.getItem("token");
|
const token = localStorage.getItem("token");
|
||||||
if (isLogged || (token && token !== "")) {
|
if (isLogged || (token && token !== "")) {
|
||||||
if (!isTokenSet) {
|
if (!isTokenSet) {
|
||||||
setUserToken(token);
|
dispatch(setUserToken(token));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -45,24 +47,12 @@ const protectedRoute = ({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
protectedRoute.propTypes = {
|
ProtectedRoute.propTypes = {
|
||||||
component: PropTypes.func,
|
component: PropTypes.func,
|
||||||
isLogged: PropTypes.bool.isRequired,
|
|
||||||
isActivated: PropTypes.bool.isRequired,
|
|
||||||
isTokenSet: PropTypes.bool.isRequired,
|
|
||||||
setUserToken: PropTypes.func.isRequired,
|
|
||||||
};
|
};
|
||||||
export const ProtectedRoute = connect(
|
|
||||||
(state) => ({
|
|
||||||
isLogged: state.userStore.get("isLogged"),
|
|
||||||
isAdmin: state.userStore.get("isLogged"),
|
|
||||||
isActivated: state.userStore.get("isActivated"),
|
|
||||||
isTokenSet: state.userStore.get("isTokenSet"),
|
|
||||||
}),
|
|
||||||
{ setUserToken }
|
|
||||||
)(protectedRoute);
|
|
||||||
|
|
||||||
const adminRoute = ({ component: Component, isAdmin, ...otherProps }) => {
|
export const AdminRoute = ({ component: Component, ...otherProps }) => {
|
||||||
|
const isAdmin = useSelector((state) => state.userStore.get("isAdmin"));
|
||||||
return (
|
return (
|
||||||
<Route
|
<Route
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
@ -76,10 +66,6 @@ const adminRoute = ({ component: Component, isAdmin, ...otherProps }) => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
adminRoute.propTypes = {
|
AdminRoute.propTypes = {
|
||||||
component: PropTypes.func,
|
component: PropTypes.func,
|
||||||
isAdmin: PropTypes.bool.isRequired,
|
|
||||||
};
|
};
|
||||||
export const AdminRoute = connect((state) => ({
|
|
||||||
isAdmin: state.userStore.get("isLogged"),
|
|
||||||
}))(adminRoute);
|
|
||||||
|
@ -1,28 +1,20 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import PropTypes from "prop-types";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { getAdminModules } from "../../actions/admins";
|
import { getAdminModules } from "../../actions/admins";
|
||||||
|
|
||||||
import Modules from "../modules/modules";
|
import Modules from "../modules/modules";
|
||||||
|
|
||||||
const AdminModulesConnected = ({ modules, loading, getAdminModules }) => {
|
export const AdminModules = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const loading = useSelector((state) =>
|
||||||
|
state.adminStore.get("fetchingModules")
|
||||||
|
);
|
||||||
|
const modules = useSelector((state) => state.adminStore.get("modules"));
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getAdminModules();
|
dispatch(getAdminModules());
|
||||||
}, [getAdminModules]);
|
}, [dispatch]);
|
||||||
|
|
||||||
return <Modules modules={modules} isLoading={loading} />;
|
return <Modules modules={modules} isLoading={loading} />;
|
||||||
};
|
};
|
||||||
AdminModulesConnected.propTypes = {
|
|
||||||
modules: PropTypes.object,
|
|
||||||
loading: PropTypes.bool,
|
|
||||||
getAdminModules: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
|
||||||
loading: state.adminStore.get("fetchingModules"),
|
|
||||||
modules: state.adminStore.get("modules"),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const AdminModules = connect(mapStateToProps, { getAdminModules })(
|
|
||||||
AdminModulesConnected
|
|
||||||
);
|
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import PropTypes from "prop-types";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
|
||||||
|
|
||||||
import { Stat } from "./stat";
|
import { Stat } from "./stat";
|
||||||
|
|
||||||
import { getStats } from "../../actions/admins";
|
import { getStats } from "../../actions/admins";
|
||||||
|
|
||||||
const StatsConnected = ({ stats, getStats }) => {
|
export const Stats = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const stats = useSelector((state) => state.adminStore.get("stats"));
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getStats();
|
dispatch(getStats());
|
||||||
}, [getStats]);
|
}, [dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row d-flex flex-wrap">
|
<div className="row d-flex flex-wrap">
|
||||||
@ -34,13 +36,3 @@ const StatsConnected = ({ stats, getStats }) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
StatsConnected.propTypes = {
|
|
||||||
stats: PropTypes.object,
|
|
||||||
getStats: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
|
||||||
stats: state.adminStore.get("stats"),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Stats = connect(mapStateToProps, { getStats })(StatsConnected);
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { connect } from "react-redux";
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
import { List } from "immutable";
|
|
||||||
|
|
||||||
import { updateUser, deleteUser } from "../../actions/admins";
|
import { updateUser, deleteUser } from "../../actions/admins";
|
||||||
|
|
||||||
@ -11,7 +10,7 @@ import { PolochonSelect } from "../polochons/select";
|
|||||||
import { FormModal } from "../forms/modal";
|
import { FormModal } from "../forms/modal";
|
||||||
import { FormInput } from "../forms/input";
|
import { FormInput } from "../forms/input";
|
||||||
|
|
||||||
const UserEditConnect = ({
|
export const UserEdit = ({
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
admin: initAdmin,
|
admin: initAdmin,
|
||||||
@ -19,10 +18,10 @@ const UserEditConnect = ({
|
|||||||
polochonToken,
|
polochonToken,
|
||||||
polochonId: initPolochonId,
|
polochonId: initPolochonId,
|
||||||
polochonActivated: initPolochonActivated,
|
polochonActivated: initPolochonActivated,
|
||||||
updateUser,
|
|
||||||
deleteUser,
|
|
||||||
publicPolochons,
|
|
||||||
}) => {
|
}) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const publicPolochons = useSelector((state) => state.polochon.get("public"));
|
||||||
|
|
||||||
const [modal, setModal] = useState(false);
|
const [modal, setModal] = useState(false);
|
||||||
const [admin, setAdmin] = useState(initAdmin);
|
const [admin, setAdmin] = useState(initAdmin);
|
||||||
const [activated, setActivated] = useState(initActivated);
|
const [activated, setActivated] = useState(initActivated);
|
||||||
@ -38,15 +37,17 @@ const UserEditConnect = ({
|
|||||||
if (e) {
|
if (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
updateUser({
|
dispatch(
|
||||||
userId: id,
|
updateUser({
|
||||||
polochonToken: token,
|
userId: id,
|
||||||
admin,
|
polochonToken: token,
|
||||||
activated,
|
admin,
|
||||||
polochonId,
|
activated,
|
||||||
polochonActivated,
|
polochonId,
|
||||||
password,
|
polochonActivated,
|
||||||
});
|
password,
|
||||||
|
})
|
||||||
|
);
|
||||||
setModal(false);
|
setModal(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -55,7 +56,7 @@ const UserEditConnect = ({
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
if (confirmDelete) {
|
if (confirmDelete) {
|
||||||
deleteUser(name);
|
dispatch(deleteUser(name));
|
||||||
setModal(false);
|
setModal(false);
|
||||||
} else {
|
} else {
|
||||||
setConfirmDelete(true);
|
setConfirmDelete(true);
|
||||||
@ -137,23 +138,12 @@ const UserEditConnect = ({
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
UserEditConnect.propTypes = {
|
UserEdit.propTypes = {
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
activated: PropTypes.bool,
|
activated: PropTypes.bool,
|
||||||
admin: PropTypes.bool,
|
admin: PropTypes.bool,
|
||||||
updateUser: PropTypes.func,
|
|
||||||
deleteUser: PropTypes.func,
|
|
||||||
polochonToken: PropTypes.string,
|
polochonToken: PropTypes.string,
|
||||||
polochonId: PropTypes.string,
|
polochonId: PropTypes.string,
|
||||||
polochonActivated: PropTypes.bool,
|
polochonActivated: PropTypes.bool,
|
||||||
publicPolochons: PropTypes.instanceOf(List),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
|
||||||
publicPolochons: state.polochon.get("public"),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const UserEdit = connect(mapStateToProps, { updateUser, deleteUser })(
|
|
||||||
UserEditConnect
|
|
||||||
);
|
|
||||||
|
@ -1,23 +1,19 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import PropTypes from "prop-types";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { List } from "immutable";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
|
|
||||||
import { User } from "./user";
|
import { User } from "./user";
|
||||||
|
|
||||||
import { getUsers } from "../../actions/admins";
|
import { getUsers } from "../../actions/admins";
|
||||||
import { getPolochons } from "../../actions/polochon";
|
import { getPolochons } from "../../actions/polochon";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
export const UserList = () => {
|
||||||
users: state.adminStore.get("users"),
|
const dispatch = useDispatch();
|
||||||
});
|
const users = useSelector((state) => state.adminStore.get("users"));
|
||||||
const mapDispatchToProps = { getUsers, getPolochons };
|
|
||||||
|
|
||||||
const UserListConnect = ({ users, getUsers, getPolochons }) => {
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getUsers();
|
dispatch(getUsers());
|
||||||
getPolochons();
|
dispatch(getPolochons());
|
||||||
}, [getUsers, getPolochons]);
|
}, [dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="table-responsive my-2">
|
<div className="table-responsive my-2">
|
||||||
@ -54,13 +50,3 @@ const UserListConnect = ({ users, getUsers, getPolochons }) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
UserListConnect.propTypes = {
|
|
||||||
getUsers: PropTypes.func,
|
|
||||||
getPolochons: PropTypes.func,
|
|
||||||
users: PropTypes.PropTypes.instanceOf(List),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const UserList = connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(UserListConnect);
|
|
||||||
|
@ -1,35 +1,27 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
|
||||||
import SweetAlert from "react-bootstrap-sweetalert";
|
import SweetAlert from "react-bootstrap-sweetalert";
|
||||||
import { connect } from "react-redux";
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
|
|
||||||
import { dismissAlert } from "../../actions/alerts";
|
import { dismissAlert } from "../../actions/alerts";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const Alert = () => {
|
||||||
show: state.alerts.get("show"),
|
const dispatch = useDispatch();
|
||||||
title: state.alerts.get("message"),
|
|
||||||
type: state.alerts.get("type"),
|
|
||||||
});
|
|
||||||
const mapDispatchToProps = { dismissAlert };
|
|
||||||
|
|
||||||
const Alert = (props) => {
|
const show = useSelector((state) => state.alerts.get("show"));
|
||||||
if (!props.show) {
|
const title = useSelector((state) => state.alerts.get("message"));
|
||||||
|
const type = useSelector((state) => state.alerts.get("type"));
|
||||||
|
|
||||||
|
if (!show) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SweetAlert
|
<SweetAlert
|
||||||
type={props.type}
|
type={type}
|
||||||
title={props.title}
|
title={title}
|
||||||
onConfirm={props.dismissAlert}
|
onConfirm={() => dispatch(dismissAlert())}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
Alert.propTypes = {
|
|
||||||
show: PropTypes.bool.isRequired,
|
|
||||||
title: PropTypes.string.isRequired,
|
|
||||||
dismissAlert: PropTypes.func.isRequired,
|
|
||||||
type: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(Alert);
|
export default Alert;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { List } from "immutable";
|
import { List } from "immutable";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
import { prettySize } from "../../utils";
|
import { prettySize } from "../../utils";
|
||||||
import { addTorrent } from "../../actions/torrents";
|
import { addTorrent } from "../../actions/torrents";
|
||||||
@ -45,10 +45,10 @@ function buildMenuItems(torrents) {
|
|||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
const torrentsButton = ({ torrents, search, searching, addTorrent, url }) => {
|
export const TorrentsButton = ({ torrents, search, searching, url }) => {
|
||||||
/* eslint-disable */
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
/* eslint-enable */
|
|
||||||
const entries = buildMenuItems(torrents);
|
const entries = buildMenuItems(torrents);
|
||||||
const count = torrents && torrents.size !== 0 ? torrents.size : 0;
|
const count = torrents && torrents.size !== 0 ? torrents.size : 0;
|
||||||
|
|
||||||
@ -97,7 +97,10 @@ const torrentsButton = ({ torrents, search, searching, addTorrent, url }) => {
|
|||||||
return <Dropdown.Divider key={index} />;
|
return <Dropdown.Divider key={index} />;
|
||||||
case "entry":
|
case "entry":
|
||||||
return (
|
return (
|
||||||
<Dropdown.Item key={index} onClick={() => addTorrent(e.url)}>
|
<Dropdown.Item
|
||||||
|
key={index}
|
||||||
|
onClick={() => dispatch(addTorrent(e.url))}
|
||||||
|
>
|
||||||
{e.quality}
|
{e.quality}
|
||||||
{e.size !== 0 && (
|
{e.size !== 0 && (
|
||||||
<small className="ml-1">({prettySize(e.size)})</small>
|
<small className="ml-1">({prettySize(e.size)})</small>
|
||||||
@ -111,15 +114,12 @@ const torrentsButton = ({ torrents, search, searching, addTorrent, url }) => {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
torrentsButton.propTypes = {
|
TorrentsButton.propTypes = {
|
||||||
torrents: PropTypes.instanceOf(List),
|
torrents: PropTypes.instanceOf(List),
|
||||||
searching: PropTypes.bool,
|
searching: PropTypes.bool,
|
||||||
search: PropTypes.func.isRequired,
|
search: PropTypes.func.isRequired,
|
||||||
addTorrent: PropTypes.func.isRequired,
|
|
||||||
url: PropTypes.string,
|
url: PropTypes.string,
|
||||||
};
|
};
|
||||||
torrentsButton.defaultProps = {
|
TorrentsButton.defaultProps = {
|
||||||
torrents: List(),
|
torrents: List(),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TorrentsButton = connect(null, { addTorrent })(torrentsButton);
|
|
||||||
|
@ -1,10 +1,20 @@
|
|||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { withRouter } from "react-router-dom";
|
import { withRouter } from "react-router-dom";
|
||||||
import { Form, FormGroup, FormControl, FormLabel } from "react-bootstrap";
|
import { Form, FormGroup, FormControl, FormLabel } from "react-bootstrap";
|
||||||
|
|
||||||
const ExplorerOptions = ({ display, params, options, type, history }) => {
|
const ExplorerOptions = ({
|
||||||
// Should this componennt be displayed
|
display,
|
||||||
|
params,
|
||||||
|
options,
|
||||||
|
type,
|
||||||
|
history,
|
||||||
|
fetch,
|
||||||
|
}) => {
|
||||||
|
useEffect(() => {
|
||||||
|
fetch();
|
||||||
|
}, [fetch]);
|
||||||
|
|
||||||
if (!display) {
|
if (!display) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -103,6 +113,7 @@ ExplorerOptions.propTypes = {
|
|||||||
type: PropTypes.string,
|
type: PropTypes.string,
|
||||||
options: PropTypes.object,
|
options: PropTypes.object,
|
||||||
display: PropTypes.bool,
|
display: PropTypes.bool,
|
||||||
|
fetch: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withRouter(ExplorerOptions);
|
export default withRouter(ExplorerOptions);
|
||||||
|
@ -55,6 +55,7 @@ const ListPosters = (props) => {
|
|||||||
type={props.type}
|
type={props.type}
|
||||||
display={displayExplorerOptions}
|
display={displayExplorerOptions}
|
||||||
params={props.params}
|
params={props.params}
|
||||||
|
fetch={props.exploreFetchOptions}
|
||||||
options={props.exploreOptions}
|
options={props.exploreOptions}
|
||||||
/>
|
/>
|
||||||
<Posters
|
<Posters
|
||||||
@ -81,6 +82,7 @@ ListPosters.propTypes = {
|
|||||||
placeHolder: PropTypes.string.isRequired,
|
placeHolder: PropTypes.string.isRequired,
|
||||||
updateFilter: PropTypes.func.isRequired,
|
updateFilter: PropTypes.func.isRequired,
|
||||||
filter: PropTypes.string,
|
filter: PropTypes.string,
|
||||||
|
exploreFetchOptions: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ListPosters;
|
export default ListPosters;
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import React from "react";
|
import React, { useEffect, useCallback } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { OrderedMap, Map } from "immutable";
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
import { Map } from "immutable";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
selectMovie,
|
selectMovie,
|
||||||
updateFilter,
|
updateFilter,
|
||||||
movieWishlistToggle,
|
movieWishlistToggle,
|
||||||
|
fetchMovies,
|
||||||
|
getMovieExploreOptions,
|
||||||
} from "../../actions/movies";
|
} from "../../actions/movies";
|
||||||
|
|
||||||
import ListDetails from "../list/details";
|
import ListDetails from "../list/details";
|
||||||
@ -18,54 +21,86 @@ import { ShowMore } from "../buttons/showMore";
|
|||||||
import { MovieSubtitlesButton } from "./subtitlesButton";
|
import { MovieSubtitlesButton } from "./subtitlesButton";
|
||||||
import { MovieTorrentsButton } from "./torrentsButton";
|
import { MovieTorrentsButton } from "./torrentsButton";
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
const fetchUrl = (match) => {
|
||||||
return {
|
switch (match.path) {
|
||||||
loading: state.movieStore.get("loading"),
|
case "/movies/polochon":
|
||||||
movies: state.movieStore.get("movies"),
|
return "/movies/polochon";
|
||||||
filter: state.movieStore.get("filter"),
|
case "/movies/wishlist":
|
||||||
selectedImdbId: state.movieStore.get("selectedImdbId"),
|
return "/wishlist/movies";
|
||||||
exploreOptions: state.movieStore.get("exploreOptions"),
|
case "/movies/search/:search":
|
||||||
};
|
return "/movies/search/" + match.params.search;
|
||||||
}
|
case "/movies/explore/:source/:category":
|
||||||
const mapDispatchToProps = {
|
return (
|
||||||
selectMovie,
|
"/movies/explore?source=" +
|
||||||
updateFilter,
|
encodeURI(match.params.source) +
|
||||||
movieWishlistToggle,
|
"&category=" +
|
||||||
|
encodeURI(match.params.category)
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const MovieList = (props) => {
|
const MovieList = ({ match }) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const url = fetchUrl(match);
|
||||||
|
if (url !== null) {
|
||||||
|
dispatch(fetchMovies(url));
|
||||||
|
}
|
||||||
|
}, [dispatch, match]);
|
||||||
|
|
||||||
|
const loading = useSelector((state) => state.movieStore.get("loading"));
|
||||||
|
const movies = useSelector((state) => state.movieStore.get("movies"));
|
||||||
|
const filter = useSelector((state) => state.movieStore.get("filter"));
|
||||||
|
const selectedImdbId = useSelector((state) =>
|
||||||
|
state.movieStore.get("selectedImdbId")
|
||||||
|
);
|
||||||
|
const exploreOptions = useSelector((state) =>
|
||||||
|
state.movieStore.get("exploreOptions")
|
||||||
|
);
|
||||||
|
|
||||||
let selectedMovie = Map();
|
let selectedMovie = Map();
|
||||||
if (props.movies !== undefined && props.movies.has(props.selectedImdbId)) {
|
if (movies !== undefined && movies.has(selectedImdbId)) {
|
||||||
selectedMovie = props.movies.get(props.selectedImdbId);
|
selectedMovie = movies.get(selectedImdbId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selectFunc = useCallback((id) => dispatch(selectMovie(id)), [dispatch]);
|
||||||
|
const filterFunc = useCallback((filter) => dispatch(updateFilter(filter)), [
|
||||||
|
dispatch,
|
||||||
|
]);
|
||||||
|
const exploreFetchOptions = useCallback(
|
||||||
|
() => dispatch(getMovieExploreOptions()),
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<ListPosters
|
<ListPosters
|
||||||
data={props.movies}
|
data={movies}
|
||||||
type="movies"
|
type="movies"
|
||||||
placeHolder="Filter movies..."
|
placeHolder="Filter movies..."
|
||||||
exploreOptions={props.exploreOptions}
|
exploreFetchOptions={exploreFetchOptions}
|
||||||
selectedImdbId={props.selectedImdbId}
|
exploreOptions={exploreOptions}
|
||||||
updateFilter={props.updateFilter}
|
selectedImdbId={selectedImdbId}
|
||||||
filter={props.filter}
|
updateFilter={filterFunc}
|
||||||
onClick={props.selectMovie}
|
filter={filter}
|
||||||
onDoubleClick={function () {
|
onClick={selectFunc}
|
||||||
return;
|
onDoubleClick={() => {}}
|
||||||
}}
|
onKeyEnter={() => {}}
|
||||||
onKeyEnter={function () {
|
params={match.params}
|
||||||
return;
|
loading={loading}
|
||||||
}}
|
|
||||||
params={props.match.params}
|
|
||||||
loading={props.loading}
|
|
||||||
/>
|
/>
|
||||||
<ListDetails
|
<ListDetails
|
||||||
data={selectedMovie}
|
data={selectedMovie}
|
||||||
loading={props.loading}
|
loading={loading}
|
||||||
wishlist={() =>
|
wishlist={() =>
|
||||||
props.movieWishlistToggle(
|
dispatch(
|
||||||
selectedMovie.get("imdb_id"),
|
movieWishlistToggle(
|
||||||
isWishlisted(selectedMovie)
|
selectedMovie.get("imdb_id"),
|
||||||
|
isWishlisted(selectedMovie)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -91,15 +126,12 @@ const MovieList = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
MovieList.propTypes = {
|
MovieList.propTypes = {
|
||||||
movies: PropTypes.instanceOf(OrderedMap),
|
fetchMovies: PropTypes.func,
|
||||||
exploreOptions: PropTypes.instanceOf(Map),
|
getMovieExploreOptions: PropTypes.func,
|
||||||
selectedImdbId: PropTypes.string,
|
|
||||||
filter: PropTypes.string,
|
|
||||||
loading: PropTypes.bool,
|
|
||||||
updateFilter: PropTypes.func,
|
updateFilter: PropTypes.func,
|
||||||
movieWishlistToggle: PropTypes.func,
|
movieWishlistToggle: PropTypes.func,
|
||||||
selectMovie: PropTypes.func,
|
selectMovie: PropTypes.func,
|
||||||
match: PropTypes.object,
|
match: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(MovieList);
|
export default MovieList;
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import PropTypes from "prop-types";
|
|
||||||
import { Route } from "react-router-dom";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { fetchMovies, getMovieExploreOptions } from "../../actions/movies";
|
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
|
||||||
isExplorerFetched: state.movieStore.get("exploreOptions").size !== 0,
|
|
||||||
});
|
|
||||||
const mapDispatchToProps = { fetchMovies, getMovieExploreOptions };
|
|
||||||
|
|
||||||
const MoviesRoute = ({
|
|
||||||
component: Component,
|
|
||||||
isExplorerFetched,
|
|
||||||
fetchMovies,
|
|
||||||
getMovieExploreOptions,
|
|
||||||
...otherProps
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<Route
|
|
||||||
{...otherProps}
|
|
||||||
render={(props) => {
|
|
||||||
let fetchUrl = "";
|
|
||||||
switch (props.match.path) {
|
|
||||||
case "/movies/polochon":
|
|
||||||
fetchUrl = "/movies/polochon";
|
|
||||||
break;
|
|
||||||
case "/movies/wishlist":
|
|
||||||
fetchUrl = "/wishlist/movies";
|
|
||||||
break;
|
|
||||||
case "/movies/search/:search":
|
|
||||||
fetchUrl = "/movies/search/" + props.match.params.search;
|
|
||||||
break;
|
|
||||||
case "/movies/explore/:source/:category":
|
|
||||||
if (!isExplorerFetched) {
|
|
||||||
getMovieExploreOptions();
|
|
||||||
}
|
|
||||||
fetchUrl =
|
|
||||||
"/movies/explore?source=" +
|
|
||||||
encodeURI(props.match.params.source) +
|
|
||||||
"&category=" +
|
|
||||||
encodeURI(props.match.params.category);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fetchUrl != "") {
|
|
||||||
fetchMovies(fetchUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <Component {...props} />;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
MoviesRoute.propTypes = {
|
|
||||||
component: PropTypes.object,
|
|
||||||
match: PropTypes.object,
|
|
||||||
isExplorerFetched: PropTypes.bool.isRequired,
|
|
||||||
fetchMovies: PropTypes.func.isRequired,
|
|
||||||
getMovieExploreOptions: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(MoviesRoute);
|
|
@ -1,35 +1,32 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { List } from "immutable";
|
import { List } from "immutable";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
import { searchMovieSubtitles } from "../../actions/subtitles";
|
import { searchMovieSubtitles } from "../../actions/subtitles";
|
||||||
|
|
||||||
import { SubtitlesButton } from "../buttons/subtitles";
|
import { SubtitlesButton } from "../buttons/subtitles";
|
||||||
|
|
||||||
const movieSubtitlesButton = ({
|
export const MovieSubtitlesButton = ({
|
||||||
inLibrary,
|
inLibrary,
|
||||||
imdbId,
|
imdbId,
|
||||||
searching,
|
searching,
|
||||||
searchMovieSubtitles,
|
|
||||||
subtitles,
|
subtitles,
|
||||||
}) => (
|
}) => {
|
||||||
<SubtitlesButton
|
const dispatch = useDispatch();
|
||||||
inLibrary={inLibrary}
|
|
||||||
searching={searching}
|
|
||||||
subtitles={subtitles}
|
|
||||||
search={() => searchMovieSubtitles(imdbId)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
movieSubtitlesButton.propTypes = {
|
return (
|
||||||
|
<SubtitlesButton
|
||||||
|
inLibrary={inLibrary}
|
||||||
|
searching={searching}
|
||||||
|
subtitles={subtitles}
|
||||||
|
search={() => dispatch(searchMovieSubtitles(imdbId))}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
MovieSubtitlesButton.propTypes = {
|
||||||
searching: PropTypes.bool,
|
searching: PropTypes.bool,
|
||||||
inLibrary: PropTypes.bool,
|
inLibrary: PropTypes.bool,
|
||||||
imdbId: PropTypes.string,
|
imdbId: PropTypes.string,
|
||||||
searchMovieSubtitles: PropTypes.func,
|
|
||||||
subtitles: PropTypes.instanceOf(List),
|
subtitles: PropTypes.instanceOf(List),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MovieSubtitlesButton = connect(null, { searchMovieSubtitles })(
|
|
||||||
movieSubtitlesButton
|
|
||||||
);
|
|
||||||
|
@ -1,33 +1,26 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { List } from "immutable";
|
import { List } from "immutable";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
import { getMovieDetails } from "../../actions/movies";
|
import { getMovieDetails } from "../../actions/movies";
|
||||||
import { TorrentsButton } from "../buttons/torrents";
|
import { TorrentsButton } from "../buttons/torrents";
|
||||||
|
|
||||||
const movieTorrentsButton = ({
|
export const MovieTorrentsButton = ({ torrents, imdbId, title, searching }) => {
|
||||||
torrents,
|
const dispatch = useDispatch();
|
||||||
imdbId,
|
return (
|
||||||
title,
|
<TorrentsButton
|
||||||
searching,
|
torrents={torrents}
|
||||||
getMovieDetails,
|
searching={searching}
|
||||||
}) => (
|
search={() => dispatch(getMovieDetails(imdbId))}
|
||||||
<TorrentsButton
|
url={`#/torrents/search/movies/${encodeURI(title)}`}
|
||||||
torrents={torrents}
|
/>
|
||||||
searching={searching}
|
);
|
||||||
search={() => getMovieDetails(imdbId)}
|
};
|
||||||
url={`#/torrents/search/movies/${encodeURI(title)}`}
|
MovieTorrentsButton.propTypes = {
|
||||||
/>
|
|
||||||
);
|
|
||||||
movieTorrentsButton.propTypes = {
|
|
||||||
torrents: PropTypes.instanceOf(List),
|
torrents: PropTypes.instanceOf(List),
|
||||||
imdbId: PropTypes.string,
|
imdbId: PropTypes.string,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
searching: PropTypes.bool,
|
searching: PropTypes.bool,
|
||||||
getMovieDetails: PropTypes.func,
|
getMovieDetails: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MovieTorrentsButton = connect(null, { getMovieDetails })(
|
|
||||||
movieTorrentsButton
|
|
||||||
);
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Route } from "react-router-dom";
|
import { Route } from "react-router-dom";
|
||||||
import { connect } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { LinkContainer } from "react-router-bootstrap";
|
import { LinkContainer } from "react-router-bootstrap";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
@ -8,24 +8,15 @@ import Nav from "react-bootstrap/Nav";
|
|||||||
import Navbar from "react-bootstrap/Navbar";
|
import Navbar from "react-bootstrap/Navbar";
|
||||||
import NavDropdown from "react-bootstrap/NavDropdown";
|
import NavDropdown from "react-bootstrap/NavDropdown";
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
const AppNavBar = () => {
|
||||||
let torrentCount = 0;
|
|
||||||
if (
|
|
||||||
state.torrentStore.has("torrents") &&
|
|
||||||
state.torrentStore.get("torrents") !== undefined
|
|
||||||
) {
|
|
||||||
torrentCount = state.torrentStore.get("torrents").size;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
username: state.userStore.get("username"),
|
|
||||||
isAdmin: state.userStore.get("isAdmin"),
|
|
||||||
torrentCount: torrentCount,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const AppNavBar = (props) => {
|
|
||||||
const [expanded, setExpanded] = useState(false);
|
const [expanded, setExpanded] = useState(false);
|
||||||
|
|
||||||
|
const username = useSelector((state) => state.userStore.get("username"));
|
||||||
|
const isAdmin = useSelector((state) => state.userStore.get("isAdmin"));
|
||||||
|
const torrentCount = useSelector(
|
||||||
|
(state) => state.torrentStore.get("torrents").size
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Navbar
|
<Navbar
|
||||||
fixed="top"
|
fixed="top"
|
||||||
@ -45,7 +36,7 @@ const AppNavBar = (props) => {
|
|||||||
<MoviesDropdown />
|
<MoviesDropdown />
|
||||||
<ShowsDropdown />
|
<ShowsDropdown />
|
||||||
<WishlistDropdown />
|
<WishlistDropdown />
|
||||||
<TorrentsDropdown torrentsCount={props.torrentCount} />
|
<TorrentsDropdown torrentsCount={torrentCount} />
|
||||||
</Nav>
|
</Nav>
|
||||||
<Nav>
|
<Nav>
|
||||||
<Route
|
<Route
|
||||||
@ -70,20 +61,16 @@ const AppNavBar = (props) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<UserDropdown username={props.username} isAdmin={props.isAdmin} />
|
<UserDropdown username={username} isAdmin={isAdmin} />
|
||||||
</Nav>
|
</Nav>
|
||||||
</Navbar.Collapse>
|
</Navbar.Collapse>
|
||||||
</Navbar>
|
</Navbar>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
AppNavBar.propTypes = {
|
AppNavBar.propTypes = {
|
||||||
torrentCount: PropTypes.number.isRequired,
|
|
||||||
username: PropTypes.string.isRequired,
|
|
||||||
isAdmin: PropTypes.bool.isRequired,
|
|
||||||
history: PropTypes.object,
|
history: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
export default AppNavBar;
|
||||||
export default connect(mapStateToProps)(AppNavBar);
|
|
||||||
|
|
||||||
const Search = ({ path, placeholder, setExpanded, history }) => {
|
const Search = ({ path, placeholder, setExpanded, history }) => {
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
import { Toast } from "react-bootstrap";
|
import { Toast } from "react-bootstrap";
|
||||||
|
|
||||||
import { removeNotification } from "../../actions/notifications";
|
import { removeNotification } from "../../actions/notifications";
|
||||||
|
|
||||||
const NotificationConnected = ({
|
export const Notification = ({
|
||||||
id,
|
id,
|
||||||
icon,
|
icon,
|
||||||
title,
|
title,
|
||||||
@ -14,13 +14,13 @@ const NotificationConnected = ({
|
|||||||
imageUrl,
|
imageUrl,
|
||||||
autohide,
|
autohide,
|
||||||
delay,
|
delay,
|
||||||
removeNotification,
|
|
||||||
}) => {
|
}) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
const [show, setShow] = useState(true);
|
const [show, setShow] = useState(true);
|
||||||
|
|
||||||
const hide = () => {
|
const hide = () => {
|
||||||
setShow(false);
|
setShow(false);
|
||||||
setTimeout(() => removeNotification(id), 200);
|
setTimeout(() => dispatch(removeNotification(id)), 200);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -38,7 +38,7 @@ const NotificationConnected = ({
|
|||||||
</Toast>
|
</Toast>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
NotificationConnected.propTypes = {
|
Notification.propTypes = {
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
icon: PropTypes.string,
|
icon: PropTypes.string,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
@ -46,10 +46,9 @@ NotificationConnected.propTypes = {
|
|||||||
imageUrl: PropTypes.string,
|
imageUrl: PropTypes.string,
|
||||||
autohide: PropTypes.bool,
|
autohide: PropTypes.bool,
|
||||||
delay: PropTypes.number,
|
delay: PropTypes.number,
|
||||||
removeNotification: PropTypes.func,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
NotificationConnected.defaultProps = {
|
Notification.defaultProps = {
|
||||||
autohide: false,
|
autohide: false,
|
||||||
delay: 5000,
|
delay: 5000,
|
||||||
icon: "",
|
icon: "",
|
||||||
@ -57,7 +56,3 @@ NotificationConnected.defaultProps = {
|
|||||||
title: "Info",
|
title: "Info",
|
||||||
message: "",
|
message: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Notification = connect(null, { removeNotification })(
|
|
||||||
NotificationConnected
|
|
||||||
);
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { List } from "immutable";
|
import { List } from "immutable";
|
||||||
import { connect } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
import { Notification } from "./notification";
|
import { Notification } from "./notification";
|
||||||
|
|
||||||
const NotificationsConnected = ({ notifications }) => {
|
export const Notifications = () => {
|
||||||
|
const notifications = useSelector((state) => state.notifications);
|
||||||
return (
|
return (
|
||||||
<div className="notifications">
|
<div className="notifications">
|
||||||
{notifications.map((el) => (
|
{notifications.map((el) => (
|
||||||
@ -23,12 +24,6 @@ const NotificationsConnected = ({ notifications }) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
NotificationsConnected.propTypes = {
|
Notifications.propTypes = {
|
||||||
notifications: PropTypes.instanceOf(List),
|
notifications: PropTypes.instanceOf(List),
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
|
||||||
notifications: state.notifications,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Notifications = connect(mapStateToProps)(NotificationsConnected);
|
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
import { addPolochon } from "../../actions/polochon";
|
import { addPolochon } from "../../actions/polochon";
|
||||||
|
|
||||||
import { PolochonEdit } from "./edit";
|
import { PolochonEdit } from "./edit";
|
||||||
|
|
||||||
export const PolochonAddConnected = ({ addPolochon }) => {
|
export const PolochonAdd = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
const [modal, setModal] = useState(false);
|
const [modal, setModal] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -21,13 +22,11 @@ export const PolochonAddConnected = ({ addPolochon }) => {
|
|||||||
icon="plus"
|
icon="plus"
|
||||||
show={modal}
|
show={modal}
|
||||||
setShow={setModal}
|
setShow={setModal}
|
||||||
update={addPolochon}
|
update={(params) => dispatch(addPolochon(params))}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
PolochonAddConnected.propTypes = {
|
PolochonAdd.propTypes = {
|
||||||
addPolochon: PropTypes.func,
|
addPolochon: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PolochonAdd = connect(null, { addPolochon })(PolochonAddConnected);
|
|
||||||
|
@ -1,25 +1,18 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import PropTypes from "prop-types";
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { List } from "immutable";
|
|
||||||
|
|
||||||
import { getManagedPolochons } from "../../actions/polochon";
|
import { getManagedPolochons } from "../../actions/polochon";
|
||||||
|
|
||||||
import { Polochon } from "./polochon";
|
import { Polochon } from "./polochon";
|
||||||
import { PolochonAdd } from "./add";
|
import { PolochonAdd } from "./add";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
export const PolochonList = () => {
|
||||||
managedList: state.polochon.get("managed"),
|
const list = useSelector((state) => state.polochon.get("managed"));
|
||||||
});
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
|
||||||
getManagedPolochons,
|
|
||||||
};
|
|
||||||
|
|
||||||
const PolochonListConnected = ({ getManagedPolochons, managedList }) => {
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getManagedPolochons();
|
dispatch(getManagedPolochons());
|
||||||
}, [getManagedPolochons]);
|
}, [dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row mb-3">
|
<div className="row mb-3">
|
||||||
@ -27,7 +20,7 @@ const PolochonListConnected = ({ getManagedPolochons, managedList }) => {
|
|||||||
<h2>My polochons</h2>
|
<h2>My polochons</h2>
|
||||||
<hr />
|
<hr />
|
||||||
<span>
|
<span>
|
||||||
{managedList.map((el, index) => (
|
{list.map((el, index) => (
|
||||||
<Polochon
|
<Polochon
|
||||||
key={index}
|
key={index}
|
||||||
id={el.get("id")}
|
id={el.get("id")}
|
||||||
@ -44,12 +37,3 @@ const PolochonListConnected = ({ getManagedPolochons, managedList }) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
PolochonListConnected.propTypes = {
|
|
||||||
getManagedPolochons: PropTypes.func,
|
|
||||||
managedList: PropTypes.instanceOf(List),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const PolochonList = connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(PolochonListConnected);
|
|
||||||
|
@ -1,25 +1,18 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { List } from "immutable";
|
import { List } from "immutable";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
import { PolochonUsers } from "./users";
|
import { PolochonUsers } from "./users";
|
||||||
import { PolochonEdit } from "./edit";
|
import { PolochonEdit } from "./edit";
|
||||||
|
|
||||||
import { updatePolochon, deletePolochon } from "../../actions/polochon";
|
import { updatePolochon, deletePolochon } from "../../actions/polochon";
|
||||||
|
|
||||||
export const PolochonConnected = ({
|
export const Polochon = ({ id, name, token, url, authToken, users }) => {
|
||||||
id,
|
|
||||||
name,
|
|
||||||
token,
|
|
||||||
url,
|
|
||||||
authToken,
|
|
||||||
users,
|
|
||||||
updatePolochon,
|
|
||||||
deletePolochon,
|
|
||||||
}) => {
|
|
||||||
const [edit, setEdit] = useState(false);
|
const [edit, setEdit] = useState(false);
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className="card mb-2">
|
<div className="card mb-2">
|
||||||
@ -33,7 +26,7 @@ export const PolochonConnected = ({
|
|||||||
/>
|
/>
|
||||||
<i
|
<i
|
||||||
className="fa fa-trash clickable"
|
className="fa fa-trash clickable"
|
||||||
onClick={() => deletePolochon(id)}
|
onClick={() => dispatch(deletePolochon(id))}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -49,7 +42,7 @@ export const PolochonConnected = ({
|
|||||||
title="Polochon config"
|
title="Polochon config"
|
||||||
show={edit}
|
show={edit}
|
||||||
setShow={setEdit}
|
setShow={setEdit}
|
||||||
update={updatePolochon}
|
update={(params) => dispatch(updatePolochon(params))}
|
||||||
id={id}
|
id={id}
|
||||||
initialName={name}
|
initialName={name}
|
||||||
initialUrl={url}
|
initialUrl={url}
|
||||||
@ -58,17 +51,11 @@ export const PolochonConnected = ({
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
PolochonConnected.propTypes = {
|
Polochon.propTypes = {
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
token: PropTypes.string,
|
token: PropTypes.string,
|
||||||
url: PropTypes.string,
|
url: PropTypes.string,
|
||||||
authToken: PropTypes.string,
|
authToken: PropTypes.string,
|
||||||
users: PropTypes.instanceOf(List),
|
users: PropTypes.instanceOf(List),
|
||||||
updatePolochon: PropTypes.func,
|
|
||||||
deletePolochon: PropTypes.func,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Polochon = connect(null, { updatePolochon, deletePolochon })(
|
|
||||||
PolochonConnected
|
|
||||||
);
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
import { editPolochonUser } from "../../actions/polochon";
|
import { editPolochonUser } from "../../actions/polochon";
|
||||||
|
|
||||||
@ -9,14 +9,14 @@ import Toggle from "react-bootstrap-toggle";
|
|||||||
import { FormModal } from "../forms/modal";
|
import { FormModal } from "../forms/modal";
|
||||||
import { FormInput } from "../forms/input";
|
import { FormInput } from "../forms/input";
|
||||||
|
|
||||||
export const PolochonUserConnected = ({
|
export const PolochonUser = ({
|
||||||
polochonId,
|
polochonId,
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
initialToken,
|
initialToken,
|
||||||
initialActivated,
|
initialActivated,
|
||||||
editPolochonUser,
|
|
||||||
}) => {
|
}) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
const [edit, setEdit] = useState(false);
|
const [edit, setEdit] = useState(false);
|
||||||
const [token, setToken] = useState(initialToken);
|
const [token, setToken] = useState(initialToken);
|
||||||
const [activated, setActivated] = useState(initialActivated);
|
const [activated, setActivated] = useState(initialActivated);
|
||||||
@ -27,12 +27,14 @@ export const PolochonUserConnected = ({
|
|||||||
}, [initialActivated, initialToken]);
|
}, [initialActivated, initialToken]);
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
editPolochonUser({
|
dispatch(
|
||||||
polochonId,
|
editPolochonUser({
|
||||||
id,
|
polochonId,
|
||||||
token,
|
id,
|
||||||
activated,
|
token,
|
||||||
});
|
activated,
|
||||||
|
})
|
||||||
|
);
|
||||||
setEdit(false);
|
setEdit(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,7 +69,7 @@ export const PolochonUserConnected = ({
|
|||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
PolochonUserConnected.propTypes = {
|
PolochonUser.propTypes = {
|
||||||
polochonId: PropTypes.string,
|
polochonId: PropTypes.string,
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
@ -75,7 +77,3 @@ PolochonUserConnected.propTypes = {
|
|||||||
initialActivated: PropTypes.bool,
|
initialActivated: PropTypes.bool,
|
||||||
editPolochonUser: PropTypes.func,
|
editPolochonUser: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PolochonUser = connect(null, { editPolochonUser })(
|
|
||||||
PolochonUserConnected
|
|
||||||
);
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { Map } from "immutable";
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
|
||||||
|
|
||||||
import Loader from "../loader/loader";
|
import Loader from "../loader/loader";
|
||||||
|
|
||||||
@ -9,12 +8,17 @@ import { Fanart } from "./details/fanart";
|
|||||||
import { Header } from "./details/header";
|
import { Header } from "./details/header";
|
||||||
import { SeasonsList } from "./details/seasons";
|
import { SeasonsList } from "./details/seasons";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
import { fetchShowDetails } from "../../actions/shows";
|
||||||
loading: state.showStore.get("loading"),
|
|
||||||
show: state.showStore.get("show"),
|
export const ShowDetails = ({ match }) => {
|
||||||
});
|
const dispatch = useDispatch();
|
||||||
|
const loading = useSelector((state) => state.showStore.get("loading"));
|
||||||
|
const show = useSelector((state) => state.showStore.get("show"));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch(fetchShowDetails(match.params.imdbId));
|
||||||
|
}, [dispatch, match]);
|
||||||
|
|
||||||
const showDetails = ({ show, loading }) => {
|
|
||||||
if (loading === true) {
|
if (loading === true) {
|
||||||
return <Loader />;
|
return <Loader />;
|
||||||
}
|
}
|
||||||
@ -29,8 +33,6 @@ const showDetails = ({ show, loading }) => {
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
showDetails.propTypes = {
|
ShowDetails.propTypes = {
|
||||||
loading: PropTypes.bool,
|
match: PropTypes.object.isRequired,
|
||||||
show: PropTypes.instanceOf(Map),
|
|
||||||
};
|
};
|
||||||
export const ShowDetails = connect(mapStateToProps)(showDetails);
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { Map } from "immutable";
|
import { Map } from "immutable";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
|
||||||
import { showWishlistToggle } from "../../../actions/shows";
|
import { showWishlistToggle } from "../../../actions/shows";
|
||||||
|
|
||||||
@ -24,87 +24,88 @@ import { EpisodeSubtitlesButton } from "./subtitlesButton";
|
|||||||
import { EpisodeThumb } from "./episodeThumb";
|
import { EpisodeThumb } from "./episodeThumb";
|
||||||
import { EpisodeTorrentsButton } from "./torrentsButton";
|
import { EpisodeTorrentsButton } from "./torrentsButton";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
export const Episode = (props) => {
|
||||||
trackedSeason: state.showStore.getIn(["show", "tracked_season"], null),
|
const dispatch = useDispatch();
|
||||||
trackedEpisode: state.showStore.getIn(["show", "tracked_episode"], null),
|
|
||||||
});
|
|
||||||
|
|
||||||
const episode = (props) => (
|
const trackedSeason = useSelector((state) =>
|
||||||
<div className="d-flex flex-column flex-lg-row mb-3 pb-3 border-bottom border-light">
|
state.showStore.getIn(["show", "tracked_season"], null)
|
||||||
<EpisodeThumb url={props.data.get("thumb")} />
|
);
|
||||||
<div className="d-flex flex-column">
|
const trackedEpisode = useSelector((state) =>
|
||||||
<Title
|
state.showStore.getIn(["show", "tracked_episode"], null)
|
||||||
title={`${props.data.get("episode")}. ${props.data.get("title")}`}
|
);
|
||||||
wishlisted={isEpisodeWishlisted(
|
|
||||||
props.data,
|
return (
|
||||||
props.trackedSeason,
|
<div className="d-flex flex-column flex-lg-row mb-3 pb-3 border-bottom border-light">
|
||||||
props.trackedEpisode
|
<EpisodeThumb url={props.data.get("thumb")} />
|
||||||
)}
|
<div className="d-flex flex-column">
|
||||||
wishlist={() =>
|
<Title
|
||||||
props.showWishlistToggle(
|
title={`${props.data.get("episode")}. ${props.data.get("title")}`}
|
||||||
isEpisodeWishlisted(props.data),
|
wishlisted={isEpisodeWishlisted(
|
||||||
props.data.get("show_imdb_id"),
|
props.data,
|
||||||
|
trackedSeason,
|
||||||
|
trackedEpisode
|
||||||
|
)}
|
||||||
|
wishlist={() =>
|
||||||
|
dispatch(
|
||||||
|
showWishlistToggle(
|
||||||
|
isEpisodeWishlisted(props.data),
|
||||||
|
props.data.get("show_imdb_id"),
|
||||||
|
props.data.get("season"),
|
||||||
|
props.data.get("episode")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ReleaseDate date={props.data.get("aired")} />
|
||||||
|
<Runtime runtime={props.data.get("runtime")} />
|
||||||
|
<Plot plot={props.data.get("plot")} />
|
||||||
|
<DownloadAndStream
|
||||||
|
name={prettyEpisodeName(
|
||||||
|
props.showName,
|
||||||
props.data.get("season"),
|
props.data.get("season"),
|
||||||
props.data.get("episode")
|
props.data.get("episode")
|
||||||
)
|
)}
|
||||||
}
|
url={props.data.get("polochon_url")}
|
||||||
/>
|
|
||||||
<ReleaseDate date={props.data.get("aired")} />
|
|
||||||
<Runtime runtime={props.data.get("runtime")} />
|
|
||||||
<Plot plot={props.data.get("plot")} />
|
|
||||||
<DownloadAndStream
|
|
||||||
name={prettyEpisodeName(
|
|
||||||
props.showName,
|
|
||||||
props.data.get("season"),
|
|
||||||
props.data.get("episode")
|
|
||||||
)}
|
|
||||||
url={props.data.get("polochon_url")}
|
|
||||||
subtitles={props.data.get("subtitles")}
|
|
||||||
/>
|
|
||||||
<PolochonMetadata
|
|
||||||
quality={props.data.get("quality")}
|
|
||||||
releaseGroup={props.data.get("release_group")}
|
|
||||||
container={props.data.get("container")}
|
|
||||||
audioCodec={props.data.get("audio_codec")}
|
|
||||||
videoCodec={props.data.get("video_codec")}
|
|
||||||
light
|
|
||||||
/>
|
|
||||||
<ShowMore
|
|
||||||
id={prettyEpisodeName(
|
|
||||||
props.showName,
|
|
||||||
props.data.get("season"),
|
|
||||||
props.data.get("episode")
|
|
||||||
)}
|
|
||||||
inLibrary={inLibrary(props.data)}
|
|
||||||
>
|
|
||||||
<EpisodeTorrentsButton
|
|
||||||
torrents={props.data.get("torrents")}
|
|
||||||
showName={props.showName}
|
|
||||||
imdbId={props.data.get("show_imdb_id")}
|
|
||||||
season={props.data.get("season")}
|
|
||||||
episode={props.data.get("episode")}
|
|
||||||
searching={props.data.get("fetching")}
|
|
||||||
/>
|
|
||||||
<EpisodeSubtitlesButton
|
|
||||||
subtitles={props.data.get("subtitles")}
|
subtitles={props.data.get("subtitles")}
|
||||||
inLibrary={inLibrary(props.data)}
|
|
||||||
searching={props.data.get("fetchingSubtitles", false)}
|
|
||||||
imdbId={props.data.get("show_imdb_id")}
|
|
||||||
season={props.data.get("season")}
|
|
||||||
episode={props.data.get("episode")}
|
|
||||||
/>
|
/>
|
||||||
</ShowMore>
|
<PolochonMetadata
|
||||||
|
quality={props.data.get("quality")}
|
||||||
|
releaseGroup={props.data.get("release_group")}
|
||||||
|
container={props.data.get("container")}
|
||||||
|
audioCodec={props.data.get("audio_codec")}
|
||||||
|
videoCodec={props.data.get("video_codec")}
|
||||||
|
light
|
||||||
|
/>
|
||||||
|
<ShowMore
|
||||||
|
id={prettyEpisodeName(
|
||||||
|
props.showName,
|
||||||
|
props.data.get("season"),
|
||||||
|
props.data.get("episode")
|
||||||
|
)}
|
||||||
|
inLibrary={inLibrary(props.data)}
|
||||||
|
>
|
||||||
|
<EpisodeTorrentsButton
|
||||||
|
torrents={props.data.get("torrents")}
|
||||||
|
showName={props.showName}
|
||||||
|
imdbId={props.data.get("show_imdb_id")}
|
||||||
|
season={props.data.get("season")}
|
||||||
|
episode={props.data.get("episode")}
|
||||||
|
searching={props.data.get("fetching")}
|
||||||
|
/>
|
||||||
|
<EpisodeSubtitlesButton
|
||||||
|
subtitles={props.data.get("subtitles")}
|
||||||
|
inLibrary={inLibrary(props.data)}
|
||||||
|
searching={props.data.get("fetchingSubtitles", false)}
|
||||||
|
imdbId={props.data.get("show_imdb_id")}
|
||||||
|
season={props.data.get("season")}
|
||||||
|
episode={props.data.get("episode")}
|
||||||
|
/>
|
||||||
|
</ShowMore>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
};
|
||||||
episode.propTypes = {
|
Episode.propTypes = {
|
||||||
data: PropTypes.instanceOf(Map).isRequired,
|
data: PropTypes.instanceOf(Map).isRequired,
|
||||||
trackedSeason: PropTypes.number,
|
showName: PropTypes.string.isRequired,
|
||||||
trackedEpisode: PropTypes.number,
|
|
||||||
showName: PropTypes.string.isRequired,
|
|
||||||
showWishlistToggle: PropTypes.func,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Episode = connect(mapStateToProps, { showWishlistToggle })(
|
|
||||||
episode
|
|
||||||
);
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { Map } from "immutable";
|
import { Map } from "immutable";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
import { isWishlisted } from "../../../utils";
|
import { isWishlisted } from "../../../utils";
|
||||||
|
|
||||||
@ -15,56 +15,58 @@ import { TrackingLabel } from "../../details/tracking";
|
|||||||
|
|
||||||
import { ImdbBadge } from "../../buttons/imdb";
|
import { ImdbBadge } from "../../buttons/imdb";
|
||||||
|
|
||||||
export const header = (props) => (
|
export const Header = (props) => {
|
||||||
<div className="card col-12 col-md-10 offset-md-1 mt-n3 mb-3">
|
const dispatch = useDispatch();
|
||||||
<div className="d-flex flex-column flex-md-row">
|
return (
|
||||||
<div className="d-flex justify-content-center">
|
<div className="card col-12 col-md-10 offset-md-1 mt-n3 mb-3">
|
||||||
<img
|
<div className="d-flex flex-column flex-md-row">
|
||||||
className="overflow-hidden object-fit-cover"
|
<div className="d-flex justify-content-center">
|
||||||
src={props.data.get("poster_url")}
|
<img
|
||||||
/>
|
className="overflow-hidden object-fit-cover"
|
||||||
</div>
|
src={props.data.get("poster_url")}
|
||||||
<div>
|
/>
|
||||||
<div className="card-body">
|
</div>
|
||||||
<p className="card-title">
|
<div>
|
||||||
<Title
|
<div className="card-body">
|
||||||
title={props.data.get("title")}
|
<p className="card-title">
|
||||||
wishlisted={isWishlisted(props.data)}
|
<Title
|
||||||
wishlist={() =>
|
title={props.data.get("title")}
|
||||||
props.showWishlistToggle(
|
wishlisted={isWishlisted(props.data)}
|
||||||
isWishlisted(props.data),
|
wishlist={() =>
|
||||||
props.data.get("imdb_id")
|
dispatch(
|
||||||
)
|
showWishlistToggle(
|
||||||
}
|
isWishlisted(props.data),
|
||||||
/>
|
props.data.get("imdb_id")
|
||||||
</p>
|
)
|
||||||
<p className="card-text">
|
)
|
||||||
<ReleaseDate date={props.data.get("year")} />
|
}
|
||||||
</p>
|
/>
|
||||||
<p className="card-text">
|
</p>
|
||||||
<Rating rating={props.data.get("rating")} />
|
<p className="card-text">
|
||||||
</p>
|
<ReleaseDate date={props.data.get("year")} />
|
||||||
<p className="card-text">
|
</p>
|
||||||
<ImdbBadge imdbId={props.data.get("imdb_id")} />
|
<p className="card-text">
|
||||||
</p>
|
<Rating rating={props.data.get("rating")} />
|
||||||
<p className="card-text">
|
</p>
|
||||||
<TrackingLabel
|
<p className="card-text">
|
||||||
inLibrary={false}
|
<ImdbBadge imdbId={props.data.get("imdb_id")} />
|
||||||
trackedSeason={props.data.get("tracked_season")}
|
</p>
|
||||||
trackedEpisode={props.data.get("tracked_episode")}
|
<p className="card-text">
|
||||||
/>
|
<TrackingLabel
|
||||||
</p>
|
inLibrary={false}
|
||||||
<p className="card-text">
|
trackedSeason={props.data.get("tracked_season")}
|
||||||
<Plot plot={props.data.get("plot")} />
|
trackedEpisode={props.data.get("tracked_episode")}
|
||||||
</p>
|
/>
|
||||||
|
</p>
|
||||||
|
<p className="card-text">
|
||||||
|
<Plot plot={props.data.get("plot")} />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
};
|
||||||
header.propTypes = {
|
Header.propTypes = {
|
||||||
data: PropTypes.instanceOf(Map),
|
data: PropTypes.instanceOf(Map),
|
||||||
showWishlistToggle: PropTypes.func,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Header = connect(null, { showWishlistToggle })(header);
|
|
||||||
|
@ -1,39 +1,37 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { List } from "immutable";
|
import { List } from "immutable";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
import { searchEpisodeSubtitles } from "../../../actions/subtitles";
|
import { searchEpisodeSubtitles } from "../../../actions/subtitles";
|
||||||
|
|
||||||
import { SubtitlesButton } from "../../buttons/subtitles";
|
import { SubtitlesButton } from "../../buttons/subtitles";
|
||||||
|
|
||||||
const episodeSubtitlesButton = ({
|
export const EpisodeSubtitlesButton = ({
|
||||||
inLibrary,
|
inLibrary,
|
||||||
imdbId,
|
imdbId,
|
||||||
season,
|
season,
|
||||||
episode,
|
episode,
|
||||||
searching,
|
searching,
|
||||||
searchEpisodeSubtitles,
|
|
||||||
subtitles,
|
subtitles,
|
||||||
}) => (
|
}) => {
|
||||||
<SubtitlesButton
|
const dispatch = useDispatch();
|
||||||
subtitles={subtitles}
|
|
||||||
inLibrary={inLibrary}
|
|
||||||
searching={searching}
|
|
||||||
search={() => searchEpisodeSubtitles(imdbId, season, episode)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
episodeSubtitlesButton.propTypes = {
|
return (
|
||||||
|
<SubtitlesButton
|
||||||
|
subtitles={subtitles}
|
||||||
|
inLibrary={inLibrary}
|
||||||
|
searching={searching}
|
||||||
|
search={() => dispatch(searchEpisodeSubtitles(imdbId, season, episode))}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
EpisodeSubtitlesButton.propTypes = {
|
||||||
inLibrary: PropTypes.bool,
|
inLibrary: PropTypes.bool,
|
||||||
searching: PropTypes.bool,
|
searching: PropTypes.bool,
|
||||||
imdbId: PropTypes.string,
|
imdbId: PropTypes.string,
|
||||||
season: PropTypes.number,
|
season: PropTypes.number,
|
||||||
episode: PropTypes.number,
|
episode: PropTypes.number,
|
||||||
searchEpisodeSubtitles: PropTypes.func,
|
|
||||||
subtitles: PropTypes.instanceOf(List),
|
subtitles: PropTypes.instanceOf(List),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const EpisodeSubtitlesButton = connect(null, { searchEpisodeSubtitles })(
|
|
||||||
episodeSubtitlesButton
|
|
||||||
);
|
|
||||||
|
@ -1,40 +1,39 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { List } from "immutable";
|
import { List } from "immutable";
|
||||||
|
|
||||||
import { getEpisodeDetails } from "../../../actions/shows";
|
import { getEpisodeDetails } from "../../../actions/shows";
|
||||||
|
|
||||||
import { TorrentsButton } from "../../buttons/torrents";
|
import { TorrentsButton } from "../../buttons/torrents";
|
||||||
import { prettyEpisodeName } from "../../../utils";
|
import { prettyEpisodeName } from "../../../utils";
|
||||||
|
|
||||||
const episodeTorrentsButton = ({
|
export const EpisodeTorrentsButton = ({
|
||||||
torrents,
|
torrents,
|
||||||
imdbId,
|
imdbId,
|
||||||
season,
|
season,
|
||||||
episode,
|
episode,
|
||||||
showName,
|
showName,
|
||||||
searching,
|
searching,
|
||||||
getEpisodeDetails,
|
}) => {
|
||||||
}) => (
|
const dispatch = useDispatch();
|
||||||
<TorrentsButton
|
|
||||||
torrents={torrents}
|
return (
|
||||||
searching={searching}
|
<TorrentsButton
|
||||||
search={() => getEpisodeDetails(imdbId, season, episode)}
|
torrents={torrents}
|
||||||
url={`#/torrents/search/shows/${encodeURI(
|
searching={searching}
|
||||||
prettyEpisodeName(showName, season, episode)
|
search={() => dispatch(getEpisodeDetails(imdbId, season, episode))}
|
||||||
)}`}
|
url={`#/torrents/search/shows/${encodeURI(
|
||||||
/>
|
prettyEpisodeName(showName, season, episode)
|
||||||
);
|
)}`}
|
||||||
episodeTorrentsButton.propTypes = {
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
EpisodeTorrentsButton.propTypes = {
|
||||||
torrents: PropTypes.instanceOf(List),
|
torrents: PropTypes.instanceOf(List),
|
||||||
showName: PropTypes.string.isRequired,
|
showName: PropTypes.string.isRequired,
|
||||||
imdbId: PropTypes.string.isRequired,
|
imdbId: PropTypes.string.isRequired,
|
||||||
episode: PropTypes.number.isRequired,
|
episode: PropTypes.number.isRequired,
|
||||||
season: PropTypes.number.isRequired,
|
season: PropTypes.number.isRequired,
|
||||||
searching: PropTypes.bool.isRequired,
|
searching: PropTypes.bool.isRequired,
|
||||||
getEpisodeDetails: PropTypes.func.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const EpisodeTorrentsButton = connect(null, { getEpisodeDetails })(
|
|
||||||
episodeTorrentsButton
|
|
||||||
);
|
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
import React from "react";
|
import React, { useEffect, useCallback } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { Map } from "immutable";
|
import { Map } from "immutable";
|
||||||
import { connect } from "react-redux";
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
fetchShows,
|
||||||
selectShow,
|
selectShow,
|
||||||
showWishlistToggle,
|
showWishlistToggle,
|
||||||
getShowDetails,
|
|
||||||
updateFilter,
|
updateFilter,
|
||||||
|
getShowExploreOptions,
|
||||||
} from "../../actions/shows";
|
} from "../../actions/shows";
|
||||||
|
|
||||||
import { isWishlisted } from "../../utils";
|
import { isWishlisted } from "../../utils";
|
||||||
@ -14,55 +16,90 @@ import { isWishlisted } from "../../utils";
|
|||||||
import ListDetails from "../list/details";
|
import ListDetails from "../list/details";
|
||||||
import ListPosters from "../list/posters";
|
import ListPosters from "../list/posters";
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
const fetchUrl = (match) => {
|
||||||
return {
|
switch (match.path) {
|
||||||
loading: state.showsStore.get("loading"),
|
case "/shows/polochon":
|
||||||
shows: state.showsStore.get("shows"),
|
return "/shows/polochon";
|
||||||
filter: state.showsStore.get("filter"),
|
case "/shows/wishlist":
|
||||||
selectedImdbId: state.showsStore.get("selectedImdbId"),
|
return "/wishlist/shows";
|
||||||
exploreOptions: state.showsStore.get("exploreOptions"),
|
case "/shows/search/:search":
|
||||||
};
|
return "/shows/search/" + match.params.search;
|
||||||
}
|
case "/shows/explore/:source/:category":
|
||||||
const mapDispatchToProps = {
|
return (
|
||||||
selectShow,
|
"/shows/explore?source=" +
|
||||||
showWishlistToggle,
|
encodeURI(match.params.source) +
|
||||||
getShowDetails,
|
"&category=" +
|
||||||
updateFilter,
|
encodeURI(match.params.category)
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const ShowList = (props) => {
|
const ShowList = ({ match, history }) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const url = fetchUrl(match);
|
||||||
|
if (url !== null) {
|
||||||
|
dispatch(fetchShows(url));
|
||||||
|
}
|
||||||
|
}, [dispatch, match]);
|
||||||
|
|
||||||
|
const loading = useSelector((state) => state.showsStore.get("loading"));
|
||||||
|
const shows = useSelector((state) => state.showsStore.get("shows"));
|
||||||
|
const filter = useSelector((state) => state.showsStore.get("filter"));
|
||||||
|
const selectedImdbId = useSelector((state) =>
|
||||||
|
state.showsStore.get("selectedImdbId")
|
||||||
|
);
|
||||||
|
const exploreOptions = useSelector((state) =>
|
||||||
|
state.showsStore.get("exploreOptions")
|
||||||
|
);
|
||||||
|
|
||||||
const showDetails = (imdbId) => {
|
const showDetails = (imdbId) => {
|
||||||
props.history.push("/shows/details/" + imdbId);
|
history.push("/shows/details/" + imdbId);
|
||||||
};
|
};
|
||||||
|
|
||||||
let selectedShow = Map();
|
let selectedShow = Map();
|
||||||
if (props.selectedImdbId !== "") {
|
if (selectedImdbId !== "") {
|
||||||
selectedShow = props.shows.get(props.selectedImdbId);
|
selectedShow = shows.get(selectedImdbId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selectFunc = useCallback((id) => dispatch(selectShow(id)), [dispatch]);
|
||||||
|
const filterFunc = useCallback((filter) => dispatch(updateFilter(filter)), [
|
||||||
|
dispatch,
|
||||||
|
]);
|
||||||
|
const exploreFetchOptions = useCallback(
|
||||||
|
() => dispatch(getShowExploreOptions()),
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row" id="container">
|
<div className="row" id="container">
|
||||||
<ListPosters
|
<ListPosters
|
||||||
data={props.shows}
|
data={shows}
|
||||||
type="shows"
|
type="shows"
|
||||||
placeHolder="Filter shows..."
|
placeHolder="Filter shows..."
|
||||||
exploreOptions={props.exploreOptions}
|
exploreOptions={exploreOptions}
|
||||||
updateFilter={props.updateFilter}
|
exploreFetchOptions={exploreFetchOptions}
|
||||||
selectedImdbId={props.selectedImdbId}
|
updateFilter={filterFunc}
|
||||||
filter={props.filter}
|
selectedImdbId={selectedImdbId}
|
||||||
onClick={props.selectShow}
|
filter={filter}
|
||||||
|
onClick={selectFunc}
|
||||||
onDoubleClick={showDetails}
|
onDoubleClick={showDetails}
|
||||||
onKeyEnter={showDetails}
|
onKeyEnter={showDetails}
|
||||||
params={props.match.params}
|
params={match.params}
|
||||||
loading={props.loading}
|
loading={loading}
|
||||||
/>
|
/>
|
||||||
<ListDetails
|
<ListDetails
|
||||||
data={selectedShow}
|
data={selectedShow}
|
||||||
loading={props.loading}
|
loading={loading}
|
||||||
wishlist={() =>
|
wishlist={() =>
|
||||||
props.showWishlistToggle(
|
dispatch(
|
||||||
isWishlisted(selectedShow),
|
showWishlistToggle(
|
||||||
selectedShow.get("imdb_id")
|
isWishlisted(selectedShow),
|
||||||
|
selectedShow.get("imdb_id")
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -82,14 +119,5 @@ const ShowList = (props) => {
|
|||||||
ShowList.propTypes = {
|
ShowList.propTypes = {
|
||||||
match: PropTypes.object,
|
match: PropTypes.object,
|
||||||
history: PropTypes.object,
|
history: PropTypes.object,
|
||||||
shows: PropTypes.instanceOf(Map),
|
|
||||||
exploreOptions: PropTypes.instanceOf(Map),
|
|
||||||
selectedImdbId: PropTypes.string,
|
|
||||||
filter: PropTypes.string,
|
|
||||||
loading: PropTypes.bool,
|
|
||||||
showWishlistToggle: PropTypes.func,
|
|
||||||
selectShow: PropTypes.func,
|
|
||||||
getShowDetails: PropTypes.func,
|
|
||||||
updateFilter: PropTypes.func,
|
|
||||||
};
|
};
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(ShowList);
|
export default ShowList;
|
||||||
|
@ -1,76 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import PropTypes from "prop-types";
|
|
||||||
import { Route } from "react-router-dom";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import {
|
|
||||||
fetchShows,
|
|
||||||
fetchShowDetails,
|
|
||||||
getShowExploreOptions,
|
|
||||||
} from "../../actions/shows";
|
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
|
||||||
isExplorerFetched: state.showsStore.get("exploreOptions").size !== 0,
|
|
||||||
});
|
|
||||||
const mapDispatchToProps = {
|
|
||||||
fetchShows,
|
|
||||||
fetchShowDetails,
|
|
||||||
getShowExploreOptions,
|
|
||||||
};
|
|
||||||
|
|
||||||
const ShowsRoute = ({
|
|
||||||
component: Component,
|
|
||||||
isExplorerFetched,
|
|
||||||
fetchShows,
|
|
||||||
fetchShowDetails,
|
|
||||||
getShowExploreOptions,
|
|
||||||
...otherProps
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<Route
|
|
||||||
{...otherProps}
|
|
||||||
render={(props) => {
|
|
||||||
let fetchUrl = "";
|
|
||||||
switch (props.match.path) {
|
|
||||||
case "/shows/polochon":
|
|
||||||
fetchUrl = "/shows/polochon";
|
|
||||||
break;
|
|
||||||
case "/shows/wishlist":
|
|
||||||
fetchUrl = "/wishlist/shows";
|
|
||||||
break;
|
|
||||||
case "/shows/search/:search":
|
|
||||||
fetchUrl = "/shows/search/" + props.match.params.search;
|
|
||||||
break;
|
|
||||||
case "/shows/explore/:source/:category":
|
|
||||||
if (!isExplorerFetched) {
|
|
||||||
getShowExploreOptions();
|
|
||||||
}
|
|
||||||
fetchUrl =
|
|
||||||
"/shows/explore?source=" +
|
|
||||||
encodeURI(props.match.params.source) +
|
|
||||||
"&category=" +
|
|
||||||
encodeURI(props.match.params.category);
|
|
||||||
break;
|
|
||||||
case "/shows/details/:imdbId":
|
|
||||||
fetchShowDetails(props.match.params.imdbId);
|
|
||||||
fetchUrl = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fetchUrl != "") {
|
|
||||||
fetchShows(fetchUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <Component {...props} />;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
ShowsRoute.propTypes = {
|
|
||||||
component: PropTypes.object,
|
|
||||||
match: PropTypes.object,
|
|
||||||
isExplorerFetched: PropTypes.bool.isRequired,
|
|
||||||
fetchShows: PropTypes.func.isRequired,
|
|
||||||
fetchShowDetails: PropTypes.func.isRequired,
|
|
||||||
getShowExploreOptions: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(ShowsRoute);
|
|
@ -1,39 +1,28 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { Map, List } from "immutable";
|
import { Map, List } from "immutable";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
|
||||||
import { prettySize } from "../../utils";
|
import { prettySize } from "../../utils";
|
||||||
import {
|
import { addTorrent, removeTorrent } from "../../actions/torrents";
|
||||||
fetchTorrents,
|
|
||||||
addTorrent,
|
|
||||||
removeTorrent,
|
|
||||||
} from "../../actions/torrents";
|
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const TorrentList = () => {
|
||||||
torrents: state.torrentStore.get("torrents"),
|
const torrents = useSelector((state) => state.torrentStore.get("torrents"));
|
||||||
});
|
const dispatch = useDispatch();
|
||||||
const mapDispatchToProps = {
|
|
||||||
fetchTorrents,
|
|
||||||
addTorrent,
|
|
||||||
removeTorrent,
|
|
||||||
};
|
|
||||||
|
|
||||||
const TorrentList = (props) => (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<AddTorrent addTorrent={props.addTorrent} />
|
<AddTorrent addTorrent={(url) => dispatch(addTorrent(url))} />
|
||||||
<Torrents torrents={props.torrents} removeTorrent={props.removeTorrent} />
|
<Torrents
|
||||||
|
torrents={torrents}
|
||||||
|
removeTorrent={(id) => dispatch(removeTorrent(id))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</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);
|
export default TorrentList;
|
||||||
|
|
||||||
const AddTorrent = (props) => {
|
const AddTorrent = (props) => {
|
||||||
const [url, setUrl] = useState("");
|
const [url, setUrl] = useState("");
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect, useCallback } from "react";
|
import React, { useState, useEffect, useCallback } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { addTorrent, searchTorrents } from "../../actions/torrents";
|
import { addTorrent, searchTorrents } from "../../actions/torrents";
|
||||||
import { Map, List } from "immutable";
|
import { Map, List } from "immutable";
|
||||||
import Loader from "../loader/loader";
|
import Loader from "../loader/loader";
|
||||||
@ -9,40 +9,38 @@ import { OverlayTrigger, Tooltip } from "react-bootstrap";
|
|||||||
|
|
||||||
import { prettySize } from "../../utils";
|
import { prettySize } from "../../utils";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const TorrentSearch = ({ history, match }) => {
|
||||||
searching: state.torrentStore.get("searching"),
|
const dispatch = useDispatch();
|
||||||
results: state.torrentStore.get("searchResults"),
|
|
||||||
});
|
const searching = useSelector((state) => state.torrentStore.get("searching"));
|
||||||
const mapDispatchToProps = { addTorrent, searchTorrents };
|
const results = useSelector((state) =>
|
||||||
|
state.torrentStore.get("searchResults")
|
||||||
|
);
|
||||||
|
|
||||||
const TorrentSearch = ({
|
|
||||||
searching,
|
|
||||||
searchTorrents,
|
|
||||||
results,
|
|
||||||
addTorrent,
|
|
||||||
history,
|
|
||||||
match,
|
|
||||||
}) => {
|
|
||||||
const [search, setSearch] = useState(match.params.search || "");
|
const [search, setSearch] = useState(match.params.search || "");
|
||||||
const [type, setType] = useState(match.params.type || "");
|
const [type, setType] = useState(match.params.type || "");
|
||||||
const [url, setUrl] = useState("");
|
|
||||||
|
|
||||||
const getUrl = useCallback(() => {
|
const url = useCallback(() => {
|
||||||
|
if (search === "" || type === "") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
return `/torrents/search/${type}/${encodeURI(search)}`;
|
return `/torrents/search/${type}/${encodeURI(search)}`;
|
||||||
}, [type, search]);
|
}, [type, search]);
|
||||||
|
|
||||||
useEffect(() => {
|
const searchFunc = useCallback(() => {
|
||||||
if (search === "") {
|
const searchURL = url();
|
||||||
return;
|
if (searchURL === "") {
|
||||||
}
|
|
||||||
if (type === "") {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = getUrl();
|
dispatch(searchTorrents(searchURL));
|
||||||
searchTorrents(url);
|
history.push(searchURL);
|
||||||
history.push(url);
|
}, [dispatch, history, url]);
|
||||||
}, [url, getUrl, searchTorrents, history, search, type]);
|
|
||||||
|
useEffect(() => {
|
||||||
|
searchFunc();
|
||||||
|
}, [searchFunc]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
@ -61,7 +59,7 @@ const TorrentSearch = ({
|
|||||||
typeFromURL={type}
|
typeFromURL={type}
|
||||||
handleClick={() => {
|
handleClick={() => {
|
||||||
setType("movies");
|
setType("movies");
|
||||||
setUrl(getUrl());
|
searchFunc();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<SearchButton
|
<SearchButton
|
||||||
@ -70,7 +68,7 @@ const TorrentSearch = ({
|
|||||||
typeFromURL={type}
|
typeFromURL={type}
|
||||||
handleClick={() => {
|
handleClick={() => {
|
||||||
setType("shows");
|
setType("shows");
|
||||||
setUrl(getUrl());
|
searchFunc();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -79,7 +77,7 @@ const TorrentSearch = ({
|
|||||||
<TorrentList
|
<TorrentList
|
||||||
searching={searching}
|
searching={searching}
|
||||||
results={results}
|
results={results}
|
||||||
addTorrent={addTorrent}
|
addTorrent={(url) => dispatch(addTorrent(url))}
|
||||||
searchFromURL={search}
|
searchFromURL={search}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -87,24 +85,20 @@ const TorrentSearch = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
TorrentSearch.propTypes = {
|
TorrentSearch.propTypes = {
|
||||||
searching: PropTypes.bool.isRequired,
|
|
||||||
results: PropTypes.instanceOf(List),
|
|
||||||
searchFromURL: PropTypes.string,
|
searchFromURL: PropTypes.string,
|
||||||
match: PropTypes.object,
|
match: PropTypes.object,
|
||||||
history: PropTypes.object,
|
history: PropTypes.object,
|
||||||
addTorrent: PropTypes.func.isRequired,
|
|
||||||
searchTorrents: PropTypes.func.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const SearchButton = (props) => {
|
const SearchButton = ({ type, typeFromURL, text, handleClick }) => {
|
||||||
const variant = props.type === props.typeFromURL ? "primary" : "secondary";
|
const variant = type === typeFromURL ? "primary" : "secondary";
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`w-50 btn m-1 btn-lg btn-${variant}`}
|
className={`w-50 btn m-1 btn-lg btn-${variant}`}
|
||||||
onClick={props.handleClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
<i className="fa fa-search" aria-hidden="true"></i> {props.text}
|
<i className="fa fa-search" aria-hidden="true"></i> {text}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -233,4 +227,4 @@ TorrentHealth.propTypes = {
|
|||||||
leechers: PropTypes.number,
|
leechers: PropTypes.number,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(TorrentSearch);
|
export default TorrentSearch;
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import { useSelector } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { Redirect, Link } from "react-router-dom";
|
import { Redirect, Link } from "react-router-dom";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const UserActivation = () => {
|
||||||
isActivated: state.userStore.get("isActivated"),
|
const isLogged = useSelector((state) => state.userStore.get("isLogged"));
|
||||||
isLogged: state.userStore.get("isLogged"),
|
const isActivated = useSelector((state) =>
|
||||||
});
|
state.userStore.get("isActivated")
|
||||||
|
);
|
||||||
|
|
||||||
const UserActivation = (props) => {
|
if (!isLogged) {
|
||||||
if (!props.isLogged) {
|
|
||||||
return <Redirect to="/users/login" />;
|
return <Redirect to="/users/login" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.isActivated) {
|
if (isActivated) {
|
||||||
return <Redirect to="/" />;
|
return <Redirect to="/" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,9 +30,4 @@ const UserActivation = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
UserActivation.propTypes = {
|
export default UserActivation;
|
||||||
isActivated: PropTypes.bool.isRequired,
|
|
||||||
isLogged: PropTypes.bool.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(UserActivation);
|
|
||||||
|
@ -1,44 +1,30 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import PropTypes from "prop-types";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import Loader from "../loader/loader";
|
import Loader from "../loader/loader";
|
||||||
import { List } from "immutable";
|
|
||||||
|
|
||||||
import { getUserInfos, updateUser } from "../../actions/users";
|
import { getUserInfos, updateUser } from "../../actions/users";
|
||||||
import { getPolochons } from "../../actions/polochon";
|
import { getPolochons } from "../../actions/polochon";
|
||||||
|
|
||||||
import { PolochonSelect } from "../polochons/select";
|
import { PolochonSelect } from "../polochons/select";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
export const UserEdit = () => {
|
||||||
loading: state.userStore.get("loading"),
|
const dispatch = useDispatch();
|
||||||
publicPolochons: state.polochon.get("public"),
|
|
||||||
polochonId: state.userStore.get("polochonId"),
|
|
||||||
polochonActivated: state.userStore.get("polochonActivated"),
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
|
||||||
updateUser,
|
|
||||||
getPolochons,
|
|
||||||
getUserInfos,
|
|
||||||
};
|
|
||||||
|
|
||||||
const UserEditConnect = ({
|
|
||||||
loading,
|
|
||||||
polochonId,
|
|
||||||
polochonActivated,
|
|
||||||
updateUser,
|
|
||||||
getPolochons,
|
|
||||||
getUserInfos,
|
|
||||||
publicPolochons,
|
|
||||||
}) => {
|
|
||||||
const [id, setId] = useState(polochonId);
|
const [id, setId] = useState(polochonId);
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [passwordConfirm, setPasswordConfirm] = useState("");
|
const [passwordConfirm, setPasswordConfirm] = useState("");
|
||||||
|
|
||||||
|
const loading = useSelector((state) => state.userStore.get("loading"));
|
||||||
|
const publicPolochons = useSelector((state) => state.polochon.get("public"));
|
||||||
|
const polochonId = useSelector((state) => state.userStore.get("polochonId"));
|
||||||
|
const polochonActivated = useSelector((state) =>
|
||||||
|
state.userStore.get("polochonActivated")
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getPolochons();
|
dispatch(getPolochons());
|
||||||
getUserInfos();
|
dispatch(getUserInfos());
|
||||||
}, [getPolochons, getUserInfos]);
|
}, [dispatch]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setId(polochonId);
|
setId(polochonId);
|
||||||
@ -46,11 +32,13 @@ const UserEditConnect = ({
|
|||||||
|
|
||||||
const handleSubmit = (ev) => {
|
const handleSubmit = (ev) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
updateUser({
|
dispatch(
|
||||||
password: password,
|
updateUser({
|
||||||
password_confirm: passwordConfirm, // eslint-disable-line camelcase
|
password: password,
|
||||||
polochon_id: id, // eslint-disable-line camelcase
|
password_confirm: passwordConfirm, // eslint-disable-line camelcase
|
||||||
});
|
polochon_id: id, // eslint-disable-line camelcase
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@ -115,17 +103,3 @@ const UserEditConnect = ({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
UserEditConnect.propTypes = {
|
|
||||||
loading: PropTypes.bool.isRequired,
|
|
||||||
polochonId: PropTypes.string,
|
|
||||||
polochonActivated: PropTypes.bool,
|
|
||||||
updateUser: PropTypes.func,
|
|
||||||
getPolochons: PropTypes.func,
|
|
||||||
getUserInfos: PropTypes.func,
|
|
||||||
publicPolochons: PropTypes.instanceOf(List),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const UserEdit = connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(UserEditConnect);
|
|
||||||
|
@ -1,29 +1,28 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { Redirect, Link } from "react-router-dom";
|
import { Redirect, Link } from "react-router-dom";
|
||||||
|
|
||||||
import { loginUser } from "../../actions/users";
|
import { loginUser } from "../../actions/users";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const UserLoginForm = () => {
|
||||||
isLogged: state.userStore.get("isLogged"),
|
const dispatch = useDispatch();
|
||||||
isLoading: state.userStore.get("loading"),
|
|
||||||
error: state.userStore.get("error"),
|
const isLogged = useSelector((state) => state.userStore.get("isLogged"));
|
||||||
});
|
const isLoading = useSelector((state) => state.userStore.get("loading"));
|
||||||
const mapDispatchToProps = { loginUser };
|
const error = useSelector((state) => state.userStore.get("error"));
|
||||||
|
|
||||||
const UserLoginForm = (props) => {
|
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
|
|
||||||
const handleSubmit = (e) => {
|
const handleSubmit = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!props.isLoading) {
|
if (!isLoading) {
|
||||||
props.loginUser(username, password);
|
dispatch(loginUser(username, password));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (props.isLogged) {
|
if (isLogged) {
|
||||||
return <Redirect to="/" />;
|
return <Redirect to="/" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,8 +31,8 @@ const UserLoginForm = (props) => {
|
|||||||
<div className="col-10 offset-1 col-md-6 offset-md-3">
|
<div className="col-10 offset-1 col-md-6 offset-md-3">
|
||||||
<h2>Log in</h2>
|
<h2>Log in</h2>
|
||||||
<hr />
|
<hr />
|
||||||
{props.error && props.error !== "" && (
|
{error && error !== "" && (
|
||||||
<div className="alert alert-danger">{props.error}</div>
|
<div className="alert alert-danger">{error}</div>
|
||||||
)}
|
)}
|
||||||
<form className="form-horizontal" onSubmit={(e) => handleSubmit(e)}>
|
<form className="form-horizontal" onSubmit={(e) => handleSubmit(e)}>
|
||||||
<div>
|
<div>
|
||||||
@ -66,12 +65,12 @@ const UserLoginForm = (props) => {
|
|||||||
No account yet ? <Link to="/users/signup">Create one</Link>
|
No account yet ? <Link to="/users/signup">Create one</Link>
|
||||||
</small>
|
</small>
|
||||||
</span>
|
</span>
|
||||||
{props.isLoading && (
|
{isLoading && (
|
||||||
<button className="btn btn-primary pull-right">
|
<button className="btn btn-primary pull-right">
|
||||||
<i className="fa fa-spinner fa-spin"></i>
|
<i className="fa fa-spinner fa-spin"></i>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{props.isLoading || (
|
{isLoading || (
|
||||||
<span className="spaced-icons">
|
<span className="spaced-icons">
|
||||||
<input
|
<input
|
||||||
className="btn btn-primary pull-right"
|
className="btn btn-primary pull-right"
|
||||||
@ -87,11 +86,5 @@ const UserLoginForm = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
UserLoginForm.propTypes = {
|
|
||||||
loginUser: PropTypes.func.isRequired,
|
|
||||||
isLoading: PropTypes.bool.isRequired,
|
|
||||||
isLogged: PropTypes.bool.isRequired,
|
|
||||||
error: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(UserLoginForm);
|
export default UserLoginForm;
|
||||||
|
@ -1,26 +1,18 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { Redirect } from "react-router-dom";
|
import { Redirect } from "react-router-dom";
|
||||||
|
|
||||||
import { userLogout } from "../../actions/users";
|
import { userLogout } from "../../actions/users";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const UserLogout = () => {
|
||||||
isLogged: state.userStore.get("isLogged"),
|
const dispatch = useDispatch();
|
||||||
});
|
const isLogged = useSelector((state) => state.userStore.get("isLogged"));
|
||||||
const mapDispatchToProps = { userLogout };
|
|
||||||
|
|
||||||
const UserLogout = (props) => {
|
if (isLogged) {
|
||||||
if (props.isLogged) {
|
dispatch(userLogout());
|
||||||
props.userLogout();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Redirect to="/users/login" />;
|
return <Redirect to="/users/login" />;
|
||||||
};
|
};
|
||||||
UserLogout.propTypes = {
|
|
||||||
isLogged: PropTypes.bool.isRequired,
|
|
||||||
userLogout: PropTypes.func.isRequired,
|
|
||||||
history: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(UserLogout);
|
export default UserLogout;
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import PropTypes from "prop-types";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { Map } from "immutable";
|
|
||||||
|
|
||||||
import { PolochonList } from "../polochons/list";
|
import { PolochonList } from "../polochons/list";
|
||||||
import { UserEdit } from "./edit";
|
import { UserEdit } from "./edit";
|
||||||
@ -9,17 +7,16 @@ import { UserEdit } from "./edit";
|
|||||||
import { getUserModules } from "../../actions/users";
|
import { getUserModules } from "../../actions/users";
|
||||||
import Modules from "../modules/modules";
|
import Modules from "../modules/modules";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const UserProfile = () => {
|
||||||
modules: state.userStore.get("modules"),
|
const dispatch = useDispatch();
|
||||||
modulesLoading: state.userStore.get("modulesLoading"),
|
const modules = useSelector((state) => state.userStore.get("modules"));
|
||||||
});
|
const modulesLoading = useSelector((state) =>
|
||||||
|
state.userStore.get("modulesLoading")
|
||||||
|
);
|
||||||
|
|
||||||
const mapDispatchToProps = { getUserModules };
|
|
||||||
|
|
||||||
const UserProfile = ({ modules, modulesLoading, getUserModules }) => {
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getUserModules();
|
dispatch(getUserModules());
|
||||||
}, [getUserModules]);
|
}, [dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -29,10 +26,5 @@ const UserProfile = ({ modules, modulesLoading, getUserModules }) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
UserProfile.propTypes = {
|
|
||||||
getUserModules: PropTypes.func.isRequired,
|
|
||||||
modules: PropTypes.instanceOf(Map),
|
|
||||||
modulesLoading: PropTypes.bool.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(UserProfile);
|
export default UserProfile;
|
||||||
|
@ -1,33 +1,33 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import PropTypes from "prop-types";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { Redirect } from "react-router-dom";
|
import { Redirect } from "react-router-dom";
|
||||||
|
|
||||||
import { userSignUp } from "../../actions/users";
|
import { userSignUp } from "../../actions/users";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const UserSignUp = () => {
|
||||||
isLogged: state.userStore.get("isLogged"),
|
const dispatch = useDispatch();
|
||||||
isLoading: state.userStore.get("loading"),
|
|
||||||
error: state.userStore.get("error"),
|
|
||||||
});
|
|
||||||
const mapDispatchToProps = { userSignUp };
|
|
||||||
|
|
||||||
const UserSignUp = (props) => {
|
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [passwordConfirm, setPasswordConfirm] = useState("");
|
const [passwordConfirm, setPasswordConfirm] = useState("");
|
||||||
|
|
||||||
if (props.isLogged) {
|
const isLogged = useSelector((state) => state.userStore.get("isLogged"));
|
||||||
|
const isLoading = useSelector((state) => state.userStore.get("loading"));
|
||||||
|
const error = useSelector((state) => state.userStore.get("error"));
|
||||||
|
|
||||||
|
if (isLogged) {
|
||||||
return <Redirect to="/" />;
|
return <Redirect to="/" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSubmit = (e) => {
|
const handleSubmit = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
props.userSignUp({
|
dispatch(
|
||||||
username: username,
|
userSignUp({
|
||||||
password: password,
|
username: username,
|
||||||
password_confirm: passwordConfirm, // eslint-disable-line camelcase
|
password: password,
|
||||||
});
|
password_confirm: passwordConfirm, // eslint-disable-line camelcase
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -35,8 +35,8 @@ const UserSignUp = (props) => {
|
|||||||
<div className="col-10 offset-1 col-md-6 offset-md-3">
|
<div className="col-10 offset-1 col-md-6 offset-md-3">
|
||||||
<h2>Sign up</h2>
|
<h2>Sign up</h2>
|
||||||
<hr />
|
<hr />
|
||||||
{props.error && props.error !== "" && (
|
{error && error !== "" && (
|
||||||
<div className="alert alert-danger">{props.error}</div>
|
<div className="alert alert-danger">{error}</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<form className="form-horizontal" onSubmit={(e) => handleSubmit(e)}>
|
<form className="form-horizontal" onSubmit={(e) => handleSubmit(e)}>
|
||||||
@ -70,12 +70,12 @@ const UserSignUp = (props) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{props.isLoading && (
|
{isLoading && (
|
||||||
<button className="btn btn-primary pull-right">
|
<button className="btn btn-primary pull-right">
|
||||||
<i className="fa fa-spinner fa-spin"></i>
|
<i className="fa fa-spinner fa-spin"></i>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{props.isLoading || (
|
{isLoading || (
|
||||||
<span>
|
<span>
|
||||||
<input
|
<input
|
||||||
className="btn btn-primary pull-right"
|
className="btn btn-primary pull-right"
|
||||||
@ -90,11 +90,5 @@ const UserSignUp = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
UserSignUp.propTypes = {
|
|
||||||
isLogged: PropTypes.bool.isRequired,
|
|
||||||
isLoading: PropTypes.bool.isRequired,
|
|
||||||
userSignUp: PropTypes.func.isRequired,
|
|
||||||
error: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(UserSignUp);
|
export default UserSignUp;
|
||||||
|
@ -1,40 +1,35 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useEffect } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { connect } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { UAParser } from "ua-parser-js";
|
import { UAParser } from "ua-parser-js";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { Map, List } from "immutable";
|
import { Map } from "immutable";
|
||||||
|
|
||||||
import { getUserTokens, deleteUserToken } from "../../actions/users";
|
import { getUserTokens, deleteUserToken } from "../../actions/users";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const UserTokens = () => {
|
||||||
tokens: state.userStore.get("tokens"),
|
const dispatch = useDispatch();
|
||||||
});
|
|
||||||
const mapDispatchToProps = { getUserTokens, deleteUserToken };
|
|
||||||
|
|
||||||
const UserTokens = (props) => {
|
const tokens = useSelector((state) => state.userStore.get("tokens"));
|
||||||
const [fetched, setIsFetched] = useState(false);
|
|
||||||
if (!fetched) {
|
useEffect(() => {
|
||||||
props.getUserTokens();
|
dispatch(getUserTokens());
|
||||||
setIsFetched(true);
|
}, [dispatch]);
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
{props.tokens.map((el, index) => (
|
{tokens.map((el, index) => (
|
||||||
<Token key={index} data={el} deleteToken={props.deleteUserToken} />
|
<Token
|
||||||
|
key={index}
|
||||||
|
data={el}
|
||||||
|
deleteToken={(token) => dispatch(deleteUserToken(token))}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
UserTokens.propTypes = {
|
|
||||||
tokens: PropTypes.instanceOf(List),
|
|
||||||
isLoading: PropTypes.bool,
|
|
||||||
getUserTokens: PropTypes.func.isRequired,
|
|
||||||
deleteUserToken: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
const Token = (props) => {
|
const Token = (props) => {
|
||||||
const ua = UAParser(props.data.get("user_agent"));
|
const ua = UAParser(props.data.get("user_agent"));
|
||||||
@ -171,4 +166,4 @@ Browser.propTypes = {
|
|||||||
version: PropTypes.string,
|
version: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(UserTokens);
|
export default UserTokens;
|
||||||
|
@ -1,25 +1,14 @@
|
|||||||
import { useEffect, useState, useCallback } from "react";
|
import { useEffect, useState, useCallback } from "react";
|
||||||
import PropTypes from "prop-types";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { setFetchedTorrents } from "../actions/torrents";
|
import { setFetchedTorrents } from "../actions/torrents";
|
||||||
import { newMovieEvent } from "../actions/movies";
|
import { newMovieEvent } from "../actions/movies";
|
||||||
import { newEpisodeEvent } from "../actions/shows";
|
import { newEpisodeEvent } from "../actions/shows";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const WsHandler = () => {
|
||||||
isLogged: state.userStore.get("isLogged"),
|
const dispatch = useDispatch();
|
||||||
});
|
|
||||||
const mapDispatchToProps = {
|
const isLogged = useSelector((state) => state.userStore.get("isLogged"));
|
||||||
setFetchedTorrents,
|
|
||||||
newMovieEvent,
|
|
||||||
newEpisodeEvent,
|
|
||||||
};
|
|
||||||
|
|
||||||
const WsHandler = ({
|
|
||||||
isLogged,
|
|
||||||
setFetchedTorrents,
|
|
||||||
newMovieEvent,
|
|
||||||
newEpisodeEvent,
|
|
||||||
}) => {
|
|
||||||
const [ws, setWs] = useState(null);
|
const [ws, setWs] = useState(null);
|
||||||
|
|
||||||
const stop = useCallback(() => {
|
const stop = useCallback(() => {
|
||||||
@ -73,13 +62,13 @@ const WsHandler = ({
|
|||||||
|
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case "torrents":
|
case "torrents":
|
||||||
setFetchedTorrents(data.message);
|
dispatch(setFetchedTorrents(data.message));
|
||||||
break;
|
break;
|
||||||
case "newVideo":
|
case "newVideo":
|
||||||
if (data.message.type === "movie") {
|
if (data.message.type === "movie") {
|
||||||
newMovieEvent(data.message.data);
|
dispatch(newMovieEvent(data.message.data));
|
||||||
} else if (data.message.type === "episode") {
|
} else if (data.message.type === "episode") {
|
||||||
newEpisodeEvent(data.message.data);
|
dispatch(newEpisodeEvent(data.message.data));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -90,7 +79,7 @@ const WsHandler = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
setWs(socket);
|
setWs(socket);
|
||||||
}, [ws, isLogged, newMovieEvent, setFetchedTorrents, newEpisodeEvent, stop]);
|
}, [ws, isLogged, dispatch, stop]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const intervalID = setInterval(() => {
|
const intervalID = setInterval(() => {
|
||||||
@ -118,11 +107,5 @@ const WsHandler = ({
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
WsHandler.propTypes = {
|
|
||||||
isLogged: PropTypes.bool.isRequired,
|
|
||||||
setFetchedTorrents: PropTypes.func,
|
|
||||||
newMovieEvent: PropTypes.func,
|
|
||||||
newEpisodeEvent: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(WsHandler);
|
export default WsHandler;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "NODE_ENV=development ./node_modules/webpack/bin/webpack.js -d --progress --colors --watch",
|
"start": "NODE_ENV=development ./node_modules/webpack/bin/webpack.js -d --progress --colors --watch",
|
||||||
"build": "NODE_ENV=production ./node_modules/webpack/bin/webpack.js -p --progress --colors",
|
"build": "NODE_ENV=production ./node_modules/webpack/bin/webpack.js -p --progress --colors",
|
||||||
"lint": "./node_modules/eslint/bin/eslint.js ."
|
"lint": "./node_modules/eslint/bin/eslint.js js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bootstrap": "^4.4.1",
|
"bootstrap": "^4.4.1",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user