Compare commits
No commits in common. "817da07a2d7f9c7dde82d70e84e0735745a84cfc" and "937b12bb6722898a18d1b954aa366ed76edf4fdc" have entirely different histories.
817da07a2d
...
937b12bb67
@ -12,7 +12,6 @@ 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,10 +28,12 @@ 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";
|
||||||
@ -59,23 +61,31 @@ const App = () => (
|
|||||||
exact
|
exact
|
||||||
component={TorrentSearch}
|
component={TorrentSearch}
|
||||||
/>
|
/>
|
||||||
<Route path="/movies/polochon" exact component={MovieList} />
|
<MoviesRoute path="/movies/polochon" exact component={MovieList} />
|
||||||
<Route path="/movies/wishlist" exact component={MovieList} />
|
<MoviesRoute path="/movies/wishlist" exact component={MovieList} />
|
||||||
<Route path="/movies/search/:search" exact component={MovieList} />
|
<MoviesRoute
|
||||||
<Route
|
path="/movies/search/:search"
|
||||||
|
exact
|
||||||
|
component={MovieList}
|
||||||
|
/>
|
||||||
|
<MoviesRoute
|
||||||
path="/movies/explore/:source/:category"
|
path="/movies/explore/:source/:category"
|
||||||
exact
|
exact
|
||||||
component={MovieList}
|
component={MovieList}
|
||||||
/>
|
/>
|
||||||
<Route path="/shows/polochon" exact component={ShowList} />
|
<ShowsRoute path="/shows/polochon" exact component={ShowList} />
|
||||||
<Route path="/shows/wishlist" exact component={ShowList} />
|
<ShowsRoute path="/shows/wishlist" exact component={ShowList} />
|
||||||
<Route path="/shows/search/:search" exact component={ShowList} />
|
<ShowsRoute path="/shows/search/:search" exact component={ShowList} />
|
||||||
<Route
|
<ShowsRoute
|
||||||
path="/shows/explore/:source/:category"
|
path="/shows/explore/:source/:category"
|
||||||
exact
|
exact
|
||||||
component={ShowList}
|
component={ShowList}
|
||||||
/>
|
/>
|
||||||
<Route path="/shows/details/:imdbId" exact component={ShowDetails} />
|
<ShowsRoute
|
||||||
|
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,19 +1,17 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { connect } 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";
|
||||||
|
|
||||||
export const ProtectedRoute = ({ component: Component, ...otherProps }) => {
|
const protectedRoute = ({
|
||||||
const dispatch = useDispatch();
|
component: Component,
|
||||||
|
isLogged,
|
||||||
const isLogged = useSelector((state) => state.userStore.get("isLogged"));
|
isActivated,
|
||||||
const isActivated = useSelector((state) =>
|
isTokenSet,
|
||||||
state.userStore.get("isActivated")
|
setUserToken,
|
||||||
);
|
...otherProps
|
||||||
const isTokenSet = useSelector((state) => state.userStore.get("isTokenSet"));
|
}) => {
|
||||||
|
|
||||||
const isAuthenticated = () => {
|
const isAuthenticated = () => {
|
||||||
if (isTokenSet) {
|
if (isTokenSet) {
|
||||||
return true;
|
return true;
|
||||||
@ -22,7 +20,7 @@ export const ProtectedRoute = ({ component: Component, ...otherProps }) => {
|
|||||||
const token = localStorage.getItem("token");
|
const token = localStorage.getItem("token");
|
||||||
if (isLogged || (token && token !== "")) {
|
if (isLogged || (token && token !== "")) {
|
||||||
if (!isTokenSet) {
|
if (!isTokenSet) {
|
||||||
dispatch(setUserToken(token));
|
setUserToken(token);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -47,12 +45,24 @@ export const ProtectedRoute = ({ component: Component, ...otherProps }) => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
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);
|
||||||
|
|
||||||
export const AdminRoute = ({ component: Component, ...otherProps }) => {
|
const adminRoute = ({ component: Component, isAdmin, ...otherProps }) => {
|
||||||
const isAdmin = useSelector((state) => state.userStore.get("isAdmin"));
|
|
||||||
return (
|
return (
|
||||||
<Route
|
<Route
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
@ -66,6 +76,10 @@ export const AdminRoute = ({ component: Component, ...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,20 +1,28 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import PropTypes from "prop-types";
|
||||||
|
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";
|
||||||
|
|
||||||
export const AdminModules = () => {
|
const AdminModulesConnected = ({ modules, loading, getAdminModules }) => {
|
||||||
const dispatch = useDispatch();
|
|
||||||
|
|
||||||
const loading = useSelector((state) =>
|
|
||||||
state.adminStore.get("fetchingModules")
|
|
||||||
);
|
|
||||||
const modules = useSelector((state) => state.adminStore.get("modules"));
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(getAdminModules());
|
getAdminModules();
|
||||||
}, [dispatch]);
|
}, [getAdminModules]);
|
||||||
|
|
||||||
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,17 +1,15 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import PropTypes from "prop-types";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import { Stat } from "./stat";
|
import { Stat } from "./stat";
|
||||||
|
|
||||||
import { getStats } from "../../actions/admins";
|
import { getStats } from "../../actions/admins";
|
||||||
|
|
||||||
export const Stats = () => {
|
const StatsConnected = ({ stats, getStats }) => {
|
||||||
const dispatch = useDispatch();
|
|
||||||
const stats = useSelector((state) => state.adminStore.get("stats"));
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(getStats());
|
getStats();
|
||||||
}, [dispatch]);
|
}, [getStats]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row d-flex flex-wrap">
|
<div className="row d-flex flex-wrap">
|
||||||
@ -36,3 +34,13 @@ export const Stats = () => {
|
|||||||
</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,6 +1,7 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { useSelector, useDispatch } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
import { List } from "immutable";
|
||||||
|
|
||||||
import { updateUser, deleteUser } from "../../actions/admins";
|
import { updateUser, deleteUser } from "../../actions/admins";
|
||||||
|
|
||||||
@ -10,7 +11,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";
|
||||||
|
|
||||||
export const UserEdit = ({
|
const UserEditConnect = ({
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
admin: initAdmin,
|
admin: initAdmin,
|
||||||
@ -18,10 +19,10 @@ export const UserEdit = ({
|
|||||||
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);
|
||||||
@ -37,7 +38,6 @@ export const UserEdit = ({
|
|||||||
if (e) {
|
if (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
dispatch(
|
|
||||||
updateUser({
|
updateUser({
|
||||||
userId: id,
|
userId: id,
|
||||||
polochonToken: token,
|
polochonToken: token,
|
||||||
@ -46,8 +46,7 @@ export const UserEdit = ({
|
|||||||
polochonId,
|
polochonId,
|
||||||
polochonActivated,
|
polochonActivated,
|
||||||
password,
|
password,
|
||||||
})
|
});
|
||||||
);
|
|
||||||
setModal(false);
|
setModal(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -56,7 +55,7 @@ export const UserEdit = ({
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
if (confirmDelete) {
|
if (confirmDelete) {
|
||||||
dispatch(deleteUser(name));
|
deleteUser(name);
|
||||||
setModal(false);
|
setModal(false);
|
||||||
} else {
|
} else {
|
||||||
setConfirmDelete(true);
|
setConfirmDelete(true);
|
||||||
@ -138,12 +137,23 @@ export const UserEdit = ({
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
UserEdit.propTypes = {
|
UserEditConnect.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,19 +1,23 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import PropTypes from "prop-types";
|
||||||
|
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";
|
||||||
|
|
||||||
export const UserList = () => {
|
const mapStateToProps = (state) => ({
|
||||||
const dispatch = useDispatch();
|
users: state.adminStore.get("users"),
|
||||||
const users = useSelector((state) => state.adminStore.get("users"));
|
});
|
||||||
|
const mapDispatchToProps = { getUsers, getPolochons };
|
||||||
|
|
||||||
|
const UserListConnect = ({ users, getUsers, getPolochons }) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(getUsers());
|
getUsers();
|
||||||
dispatch(getPolochons());
|
getPolochons();
|
||||||
}, [dispatch]);
|
}, [getUsers, getPolochons]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="table-responsive my-2">
|
<div className="table-responsive my-2">
|
||||||
@ -50,3 +54,13 @@ export const UserList = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
UserListConnect.propTypes = {
|
||||||
|
getUsers: PropTypes.func,
|
||||||
|
getPolochons: PropTypes.func,
|
||||||
|
users: PropTypes.PropTypes.instanceOf(List),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const UserList = connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(UserListConnect);
|
||||||
|
@ -1,27 +1,35 @@
|
|||||||
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 { useSelector, useDispatch } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import { dismissAlert } from "../../actions/alerts";
|
import { dismissAlert } from "../../actions/alerts";
|
||||||
|
|
||||||
const Alert = () => {
|
const mapStateToProps = (state) => ({
|
||||||
const dispatch = useDispatch();
|
show: state.alerts.get("show"),
|
||||||
|
title: state.alerts.get("message"),
|
||||||
|
type: state.alerts.get("type"),
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = { dismissAlert };
|
||||||
|
|
||||||
const show = useSelector((state) => state.alerts.get("show"));
|
const Alert = (props) => {
|
||||||
const title = useSelector((state) => state.alerts.get("message"));
|
if (!props.show) {
|
||||||
const type = useSelector((state) => state.alerts.get("type"));
|
|
||||||
|
|
||||||
if (!show) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SweetAlert
|
<SweetAlert
|
||||||
type={type}
|
type={props.type}
|
||||||
title={title}
|
title={props.title}
|
||||||
onConfirm={() => dispatch(dismissAlert())}
|
onConfirm={props.dismissAlert}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Alert.propTypes = {
|
||||||
|
show: PropTypes.bool.isRequired,
|
||||||
|
title: PropTypes.string.isRequired,
|
||||||
|
dismissAlert: PropTypes.func.isRequired,
|
||||||
|
type: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
export default Alert;
|
export default connect(mapStateToProps, mapDispatchToProps)(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 { useDispatch } from "react-redux";
|
import { connect } 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TorrentsButton = ({ torrents, search, searching, url }) => {
|
const torrentsButton = ({ torrents, search, searching, addTorrent, url }) => {
|
||||||
const dispatch = useDispatch();
|
/* eslint-disable */
|
||||||
|
|
||||||
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,10 +97,7 @@ export const TorrentsButton = ({ torrents, search, searching, url }) => {
|
|||||||
return <Dropdown.Divider key={index} />;
|
return <Dropdown.Divider key={index} />;
|
||||||
case "entry":
|
case "entry":
|
||||||
return (
|
return (
|
||||||
<Dropdown.Item
|
<Dropdown.Item key={index} onClick={() => addTorrent(e.url)}>
|
||||||
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>
|
||||||
@ -114,12 +111,15 @@ export const TorrentsButton = ({ torrents, search, searching, 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,20 +1,10 @@
|
|||||||
import React, { useEffect } from "react";
|
import React 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 = ({
|
const ExplorerOptions = ({ display, params, options, type, history }) => {
|
||||||
display,
|
// Should this componennt be displayed
|
||||||
params,
|
|
||||||
options,
|
|
||||||
type,
|
|
||||||
history,
|
|
||||||
fetch,
|
|
||||||
}) => {
|
|
||||||
useEffect(() => {
|
|
||||||
fetch();
|
|
||||||
}, [fetch]);
|
|
||||||
|
|
||||||
if (!display) {
|
if (!display) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -113,7 +103,6 @@ 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,7 +55,6 @@ 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
|
||||||
@ -82,7 +81,6 @@ 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,14 +1,11 @@
|
|||||||
import React, { useEffect, useCallback } from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { useSelector, useDispatch } from "react-redux";
|
import { OrderedMap, Map } from "immutable";
|
||||||
import { Map } from "immutable";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
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";
|
||||||
@ -21,87 +18,55 @@ import { ShowMore } from "../buttons/showMore";
|
|||||||
import { MovieSubtitlesButton } from "./subtitlesButton";
|
import { MovieSubtitlesButton } from "./subtitlesButton";
|
||||||
import { MovieTorrentsButton } from "./torrentsButton";
|
import { MovieTorrentsButton } from "./torrentsButton";
|
||||||
|
|
||||||
const fetchUrl = (match) => {
|
function mapStateToProps(state) {
|
||||||
switch (match.path) {
|
return {
|
||||||
case "/movies/polochon":
|
loading: state.movieStore.get("loading"),
|
||||||
return "/movies/polochon";
|
movies: state.movieStore.get("movies"),
|
||||||
case "/movies/wishlist":
|
filter: state.movieStore.get("filter"),
|
||||||
return "/wishlist/movies";
|
selectedImdbId: state.movieStore.get("selectedImdbId"),
|
||||||
case "/movies/search/:search":
|
exploreOptions: state.movieStore.get("exploreOptions"),
|
||||||
return "/movies/search/" + match.params.search;
|
};
|
||||||
case "/movies/explore/:source/:category":
|
}
|
||||||
return (
|
const mapDispatchToProps = {
|
||||||
"/movies/explore?source=" +
|
selectMovie,
|
||||||
encodeURI(match.params.source) +
|
updateFilter,
|
||||||
"&category=" +
|
movieWishlistToggle,
|
||||||
encodeURI(match.params.category)
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const MovieList = ({ match }) => {
|
const MovieList = (props) => {
|
||||||
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 (movies !== undefined && movies.has(selectedImdbId)) {
|
if (props.movies !== undefined && props.movies.has(props.selectedImdbId)) {
|
||||||
selectedMovie = movies.get(selectedImdbId);
|
selectedMovie = props.movies.get(props.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={movies}
|
data={props.movies}
|
||||||
type="movies"
|
type="movies"
|
||||||
placeHolder="Filter movies..."
|
placeHolder="Filter movies..."
|
||||||
exploreFetchOptions={exploreFetchOptions}
|
exploreOptions={props.exploreOptions}
|
||||||
exploreOptions={exploreOptions}
|
selectedImdbId={props.selectedImdbId}
|
||||||
selectedImdbId={selectedImdbId}
|
updateFilter={props.updateFilter}
|
||||||
updateFilter={filterFunc}
|
filter={props.filter}
|
||||||
filter={filter}
|
onClick={props.selectMovie}
|
||||||
onClick={selectFunc}
|
onDoubleClick={function () {
|
||||||
onDoubleClick={() => {}}
|
return;
|
||||||
onKeyEnter={() => {}}
|
}}
|
||||||
params={match.params}
|
onKeyEnter={function () {
|
||||||
loading={loading}
|
return;
|
||||||
|
}}
|
||||||
|
params={props.match.params}
|
||||||
|
loading={props.loading}
|
||||||
/>
|
/>
|
||||||
<ListDetails
|
<ListDetails
|
||||||
data={selectedMovie}
|
data={selectedMovie}
|
||||||
loading={loading}
|
loading={props.loading}
|
||||||
wishlist={() =>
|
wishlist={() =>
|
||||||
dispatch(
|
props.movieWishlistToggle(
|
||||||
movieWishlistToggle(
|
|
||||||
selectedMovie.get("imdb_id"),
|
selectedMovie.get("imdb_id"),
|
||||||
isWishlisted(selectedMovie)
|
isWishlisted(selectedMovie)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ShowMore
|
<ShowMore
|
||||||
@ -126,12 +91,15 @@ const MovieList = ({ match }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
MovieList.propTypes = {
|
MovieList.propTypes = {
|
||||||
fetchMovies: PropTypes.func,
|
movies: PropTypes.instanceOf(OrderedMap),
|
||||||
getMovieExploreOptions: PropTypes.func,
|
exploreOptions: PropTypes.instanceOf(Map),
|
||||||
|
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 MovieList;
|
export default connect(mapStateToProps, mapDispatchToProps)(MovieList);
|
||||||
|
65
frontend/js/components/movies/route.js
Normal file
65
frontend/js/components/movies/route.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
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,32 +1,35 @@
|
|||||||
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 { useDispatch } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import { searchMovieSubtitles } from "../../actions/subtitles";
|
import { searchMovieSubtitles } from "../../actions/subtitles";
|
||||||
|
|
||||||
import { SubtitlesButton } from "../buttons/subtitles";
|
import { SubtitlesButton } from "../buttons/subtitles";
|
||||||
|
|
||||||
export const MovieSubtitlesButton = ({
|
const movieSubtitlesButton = ({
|
||||||
inLibrary,
|
inLibrary,
|
||||||
imdbId,
|
imdbId,
|
||||||
searching,
|
searching,
|
||||||
|
searchMovieSubtitles,
|
||||||
subtitles,
|
subtitles,
|
||||||
}) => {
|
}) => (
|
||||||
const dispatch = useDispatch();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SubtitlesButton
|
<SubtitlesButton
|
||||||
inLibrary={inLibrary}
|
inLibrary={inLibrary}
|
||||||
searching={searching}
|
searching={searching}
|
||||||
subtitles={subtitles}
|
subtitles={subtitles}
|
||||||
search={() => dispatch(searchMovieSubtitles(imdbId))}
|
search={() => searchMovieSubtitles(imdbId)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
|
||||||
MovieSubtitlesButton.propTypes = {
|
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,26 +1,33 @@
|
|||||||
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 { useDispatch } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import { getMovieDetails } from "../../actions/movies";
|
import { getMovieDetails } from "../../actions/movies";
|
||||||
import { TorrentsButton } from "../buttons/torrents";
|
import { TorrentsButton } from "../buttons/torrents";
|
||||||
|
|
||||||
export const MovieTorrentsButton = ({ torrents, imdbId, title, searching }) => {
|
const movieTorrentsButton = ({
|
||||||
const dispatch = useDispatch();
|
torrents,
|
||||||
return (
|
imdbId,
|
||||||
|
title,
|
||||||
|
searching,
|
||||||
|
getMovieDetails,
|
||||||
|
}) => (
|
||||||
<TorrentsButton
|
<TorrentsButton
|
||||||
torrents={torrents}
|
torrents={torrents}
|
||||||
searching={searching}
|
searching={searching}
|
||||||
search={() => dispatch(getMovieDetails(imdbId))}
|
search={() => getMovieDetails(imdbId)}
|
||||||
url={`#/torrents/search/movies/${encodeURI(title)}`}
|
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 { useSelector } from "react-redux";
|
import { connect } 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,14 +8,23 @@ 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 AppNavBar = () => {
|
const mapStateToProps = (state) => {
|
||||||
const [expanded, setExpanded] = useState(false);
|
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 username = useSelector((state) => state.userStore.get("username"));
|
const AppNavBar = (props) => {
|
||||||
const isAdmin = useSelector((state) => state.userStore.get("isAdmin"));
|
const [expanded, setExpanded] = useState(false);
|
||||||
const torrentCount = useSelector(
|
|
||||||
(state) => state.torrentStore.get("torrents").size
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Navbar
|
<Navbar
|
||||||
@ -36,7 +45,7 @@ const AppNavBar = () => {
|
|||||||
<MoviesDropdown />
|
<MoviesDropdown />
|
||||||
<ShowsDropdown />
|
<ShowsDropdown />
|
||||||
<WishlistDropdown />
|
<WishlistDropdown />
|
||||||
<TorrentsDropdown torrentsCount={torrentCount} />
|
<TorrentsDropdown torrentsCount={props.torrentCount} />
|
||||||
</Nav>
|
</Nav>
|
||||||
<Nav>
|
<Nav>
|
||||||
<Route
|
<Route
|
||||||
@ -61,16 +70,20 @@ const AppNavBar = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<UserDropdown username={username} isAdmin={isAdmin} />
|
<UserDropdown username={props.username} isAdmin={props.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 { useDispatch } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import { Toast } from "react-bootstrap";
|
import { Toast } from "react-bootstrap";
|
||||||
|
|
||||||
import { removeNotification } from "../../actions/notifications";
|
import { removeNotification } from "../../actions/notifications";
|
||||||
|
|
||||||
export const Notification = ({
|
const NotificationConnected = ({
|
||||||
id,
|
id,
|
||||||
icon,
|
icon,
|
||||||
title,
|
title,
|
||||||
@ -14,13 +14,13 @@ export const Notification = ({
|
|||||||
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(() => dispatch(removeNotification(id)), 200);
|
setTimeout(() => removeNotification(id), 200);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -38,7 +38,7 @@ export const Notification = ({
|
|||||||
</Toast>
|
</Toast>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
Notification.propTypes = {
|
NotificationConnected.propTypes = {
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
icon: PropTypes.string,
|
icon: PropTypes.string,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
@ -46,9 +46,10 @@ Notification.propTypes = {
|
|||||||
imageUrl: PropTypes.string,
|
imageUrl: PropTypes.string,
|
||||||
autohide: PropTypes.bool,
|
autohide: PropTypes.bool,
|
||||||
delay: PropTypes.number,
|
delay: PropTypes.number,
|
||||||
|
removeNotification: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
Notification.defaultProps = {
|
NotificationConnected.defaultProps = {
|
||||||
autohide: false,
|
autohide: false,
|
||||||
delay: 5000,
|
delay: 5000,
|
||||||
icon: "",
|
icon: "",
|
||||||
@ -56,3 +57,7 @@ Notification.defaultProps = {
|
|||||||
title: "Info",
|
title: "Info",
|
||||||
message: "",
|
message: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const Notification = connect(null, { removeNotification })(
|
||||||
|
NotificationConnected
|
||||||
|
);
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
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 { useSelector } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import { Notification } from "./notification";
|
import { Notification } from "./notification";
|
||||||
|
|
||||||
export const Notifications = () => {
|
const NotificationsConnected = ({ notifications }) => {
|
||||||
const notifications = useSelector((state) => state.notifications);
|
|
||||||
return (
|
return (
|
||||||
<div className="notifications">
|
<div className="notifications">
|
||||||
{notifications.map((el) => (
|
{notifications.map((el) => (
|
||||||
@ -24,6 +23,12 @@ export const Notifications = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
Notifications.propTypes = {
|
NotificationsConnected.propTypes = {
|
||||||
notifications: PropTypes.instanceOf(List),
|
notifications: PropTypes.instanceOf(List),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => ({
|
||||||
|
notifications: state.notifications,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Notifications = connect(mapStateToProps)(NotificationsConnected);
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { useDispatch } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import { addPolochon } from "../../actions/polochon";
|
import { addPolochon } from "../../actions/polochon";
|
||||||
|
|
||||||
import { PolochonEdit } from "./edit";
|
import { PolochonEdit } from "./edit";
|
||||||
|
|
||||||
export const PolochonAdd = () => {
|
export const PolochonAddConnected = ({ addPolochon }) => {
|
||||||
const dispatch = useDispatch();
|
|
||||||
const [modal, setModal] = useState(false);
|
const [modal, setModal] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -22,11 +21,13 @@ export const PolochonAdd = () => {
|
|||||||
icon="plus"
|
icon="plus"
|
||||||
show={modal}
|
show={modal}
|
||||||
setShow={setModal}
|
setShow={setModal}
|
||||||
update={(params) => dispatch(addPolochon(params))}
|
update={addPolochon}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
PolochonAdd.propTypes = {
|
PolochonAddConnected.propTypes = {
|
||||||
addPolochon: PropTypes.func,
|
addPolochon: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const PolochonAdd = connect(null, { addPolochon })(PolochonAddConnected);
|
||||||
|
@ -1,18 +1,25 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { useSelector, useDispatch } from "react-redux";
|
import PropTypes from "prop-types";
|
||||||
|
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";
|
||||||
|
|
||||||
export const PolochonList = () => {
|
const mapStateToProps = (state) => ({
|
||||||
const list = useSelector((state) => state.polochon.get("managed"));
|
managedList: state.polochon.get("managed"),
|
||||||
const dispatch = useDispatch();
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = {
|
||||||
|
getManagedPolochons,
|
||||||
|
};
|
||||||
|
|
||||||
|
const PolochonListConnected = ({ getManagedPolochons, managedList }) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(getManagedPolochons());
|
getManagedPolochons();
|
||||||
}, [dispatch]);
|
}, [getManagedPolochons]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row mb-3">
|
<div className="row mb-3">
|
||||||
@ -20,7 +27,7 @@ export const PolochonList = () => {
|
|||||||
<h2>My polochons</h2>
|
<h2>My polochons</h2>
|
||||||
<hr />
|
<hr />
|
||||||
<span>
|
<span>
|
||||||
{list.map((el, index) => (
|
{managedList.map((el, index) => (
|
||||||
<Polochon
|
<Polochon
|
||||||
key={index}
|
key={index}
|
||||||
id={el.get("id")}
|
id={el.get("id")}
|
||||||
@ -37,3 +44,12 @@ export const PolochonList = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
PolochonListConnected.propTypes = {
|
||||||
|
getManagedPolochons: PropTypes.func,
|
||||||
|
managedList: PropTypes.instanceOf(List),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PolochonList = connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(PolochonListConnected);
|
||||||
|
@ -1,18 +1,25 @@
|
|||||||
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 { useDispatch } from "react-redux";
|
import { connect } 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 Polochon = ({ id, name, token, url, authToken, users }) => {
|
export const PolochonConnected = ({
|
||||||
|
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">
|
||||||
@ -26,7 +33,7 @@ export const Polochon = ({ id, name, token, url, authToken, users }) => {
|
|||||||
/>
|
/>
|
||||||
<i
|
<i
|
||||||
className="fa fa-trash clickable"
|
className="fa fa-trash clickable"
|
||||||
onClick={() => dispatch(deletePolochon(id))}
|
onClick={() => deletePolochon(id)}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -42,7 +49,7 @@ export const Polochon = ({ id, name, token, url, authToken, users }) => {
|
|||||||
title="Polochon config"
|
title="Polochon config"
|
||||||
show={edit}
|
show={edit}
|
||||||
setShow={setEdit}
|
setShow={setEdit}
|
||||||
update={(params) => dispatch(updatePolochon(params))}
|
update={updatePolochon}
|
||||||
id={id}
|
id={id}
|
||||||
initialName={name}
|
initialName={name}
|
||||||
initialUrl={url}
|
initialUrl={url}
|
||||||
@ -51,11 +58,17 @@ export const Polochon = ({ id, name, token, url, authToken, users }) => {
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
Polochon.propTypes = {
|
PolochonConnected.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 { useDispatch } from "react-redux";
|
import { connect } 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 PolochonUser = ({
|
export const PolochonUserConnected = ({
|
||||||
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,14 +27,12 @@ export const PolochonUser = ({
|
|||||||
}, [initialActivated, initialToken]);
|
}, [initialActivated, initialToken]);
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
dispatch(
|
|
||||||
editPolochonUser({
|
editPolochonUser({
|
||||||
polochonId,
|
polochonId,
|
||||||
id,
|
id,
|
||||||
token,
|
token,
|
||||||
activated,
|
activated,
|
||||||
})
|
});
|
||||||
);
|
|
||||||
setEdit(false);
|
setEdit(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -69,7 +67,7 @@ export const PolochonUser = ({
|
|||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
PolochonUser.propTypes = {
|
PolochonUserConnected.propTypes = {
|
||||||
polochonId: PropTypes.string,
|
polochonId: PropTypes.string,
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
@ -77,3 +75,7 @@ PolochonUser.propTypes = {
|
|||||||
initialActivated: PropTypes.bool,
|
initialActivated: PropTypes.bool,
|
||||||
editPolochonUser: PropTypes.func,
|
editPolochonUser: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const PolochonUser = connect(null, { editPolochonUser })(
|
||||||
|
PolochonUserConnected
|
||||||
|
);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React, { useEffect } from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { useSelector, useDispatch } from "react-redux";
|
import { Map } from "immutable";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import Loader from "../loader/loader";
|
import Loader from "../loader/loader";
|
||||||
|
|
||||||
@ -8,17 +9,12 @@ 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";
|
||||||
|
|
||||||
import { fetchShowDetails } from "../../actions/shows";
|
const mapStateToProps = (state) => ({
|
||||||
|
loading: state.showStore.get("loading"),
|
||||||
export const ShowDetails = ({ match }) => {
|
show: state.showStore.get("show"),
|
||||||
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 />;
|
||||||
}
|
}
|
||||||
@ -33,6 +29,8 @@ export const ShowDetails = ({ match }) => {
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
ShowDetails.propTypes = {
|
showDetails.propTypes = {
|
||||||
match: PropTypes.object.isRequired,
|
loading: PropTypes.bool,
|
||||||
|
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 { useDispatch, useSelector } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import { showWishlistToggle } from "../../../actions/shows";
|
import { showWishlistToggle } from "../../../actions/shows";
|
||||||
|
|
||||||
@ -24,17 +24,12 @@ import { EpisodeSubtitlesButton } from "./subtitlesButton";
|
|||||||
import { EpisodeThumb } from "./episodeThumb";
|
import { EpisodeThumb } from "./episodeThumb";
|
||||||
import { EpisodeTorrentsButton } from "./torrentsButton";
|
import { EpisodeTorrentsButton } from "./torrentsButton";
|
||||||
|
|
||||||
export const Episode = (props) => {
|
const mapStateToProps = (state) => ({
|
||||||
const dispatch = useDispatch();
|
trackedSeason: state.showStore.getIn(["show", "tracked_season"], null),
|
||||||
|
trackedEpisode: state.showStore.getIn(["show", "tracked_episode"], null),
|
||||||
|
});
|
||||||
|
|
||||||
const trackedSeason = useSelector((state) =>
|
const episode = (props) => (
|
||||||
state.showStore.getIn(["show", "tracked_season"], null)
|
|
||||||
);
|
|
||||||
const trackedEpisode = useSelector((state) =>
|
|
||||||
state.showStore.getIn(["show", "tracked_episode"], null)
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="d-flex flex-column flex-lg-row mb-3 pb-3 border-bottom border-light">
|
<div className="d-flex flex-column flex-lg-row mb-3 pb-3 border-bottom border-light">
|
||||||
<EpisodeThumb url={props.data.get("thumb")} />
|
<EpisodeThumb url={props.data.get("thumb")} />
|
||||||
<div className="d-flex flex-column">
|
<div className="d-flex flex-column">
|
||||||
@ -42,18 +37,16 @@ export const Episode = (props) => {
|
|||||||
title={`${props.data.get("episode")}. ${props.data.get("title")}`}
|
title={`${props.data.get("episode")}. ${props.data.get("title")}`}
|
||||||
wishlisted={isEpisodeWishlisted(
|
wishlisted={isEpisodeWishlisted(
|
||||||
props.data,
|
props.data,
|
||||||
trackedSeason,
|
props.trackedSeason,
|
||||||
trackedEpisode
|
props.trackedEpisode
|
||||||
)}
|
)}
|
||||||
wishlist={() =>
|
wishlist={() =>
|
||||||
dispatch(
|
props.showWishlistToggle(
|
||||||
showWishlistToggle(
|
|
||||||
isEpisodeWishlisted(props.data),
|
isEpisodeWishlisted(props.data),
|
||||||
props.data.get("show_imdb_id"),
|
props.data.get("show_imdb_id"),
|
||||||
props.data.get("season"),
|
props.data.get("season"),
|
||||||
props.data.get("episode")
|
props.data.get("episode")
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ReleaseDate date={props.data.get("aired")} />
|
<ReleaseDate date={props.data.get("aired")} />
|
||||||
@ -103,9 +96,15 @@ export const Episode = (props) => {
|
|||||||
</ShowMore>
|
</ShowMore>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
episode.propTypes = {
|
||||||
Episode.propTypes = {
|
|
||||||
data: PropTypes.instanceOf(Map).isRequired,
|
data: PropTypes.instanceOf(Map).isRequired,
|
||||||
|
trackedSeason: PropTypes.number,
|
||||||
|
trackedEpisode: PropTypes.number,
|
||||||
showName: PropTypes.string.isRequired,
|
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 { useDispatch } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import { isWishlisted } from "../../../utils";
|
import { isWishlisted } from "../../../utils";
|
||||||
|
|
||||||
@ -15,9 +15,7 @@ import { TrackingLabel } from "../../details/tracking";
|
|||||||
|
|
||||||
import { ImdbBadge } from "../../buttons/imdb";
|
import { ImdbBadge } from "../../buttons/imdb";
|
||||||
|
|
||||||
export const Header = (props) => {
|
export const header = (props) => (
|
||||||
const dispatch = useDispatch();
|
|
||||||
return (
|
|
||||||
<div className="card col-12 col-md-10 offset-md-1 mt-n3 mb-3">
|
<div className="card col-12 col-md-10 offset-md-1 mt-n3 mb-3">
|
||||||
<div className="d-flex flex-column flex-md-row">
|
<div className="d-flex flex-column flex-md-row">
|
||||||
<div className="d-flex justify-content-center">
|
<div className="d-flex justify-content-center">
|
||||||
@ -33,12 +31,10 @@ export const Header = (props) => {
|
|||||||
title={props.data.get("title")}
|
title={props.data.get("title")}
|
||||||
wishlisted={isWishlisted(props.data)}
|
wishlisted={isWishlisted(props.data)}
|
||||||
wishlist={() =>
|
wishlist={() =>
|
||||||
dispatch(
|
props.showWishlistToggle(
|
||||||
showWishlistToggle(
|
|
||||||
isWishlisted(props.data),
|
isWishlisted(props.data),
|
||||||
props.data.get("imdb_id")
|
props.data.get("imdb_id")
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
@ -65,8 +61,10 @@ export const Header = (props) => {
|
|||||||
</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,37 +1,39 @@
|
|||||||
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 { useDispatch } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import { searchEpisodeSubtitles } from "../../../actions/subtitles";
|
import { searchEpisodeSubtitles } from "../../../actions/subtitles";
|
||||||
|
|
||||||
import { SubtitlesButton } from "../../buttons/subtitles";
|
import { SubtitlesButton } from "../../buttons/subtitles";
|
||||||
|
|
||||||
export const EpisodeSubtitlesButton = ({
|
const episodeSubtitlesButton = ({
|
||||||
inLibrary,
|
inLibrary,
|
||||||
imdbId,
|
imdbId,
|
||||||
season,
|
season,
|
||||||
episode,
|
episode,
|
||||||
searching,
|
searching,
|
||||||
|
searchEpisodeSubtitles,
|
||||||
subtitles,
|
subtitles,
|
||||||
}) => {
|
}) => (
|
||||||
const dispatch = useDispatch();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SubtitlesButton
|
<SubtitlesButton
|
||||||
subtitles={subtitles}
|
subtitles={subtitles}
|
||||||
inLibrary={inLibrary}
|
inLibrary={inLibrary}
|
||||||
searching={searching}
|
searching={searching}
|
||||||
search={() => dispatch(searchEpisodeSubtitles(imdbId, season, episode))}
|
search={() => searchEpisodeSubtitles(imdbId, season, episode)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
EpisodeSubtitlesButton.propTypes = {
|
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,39 +1,40 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { useDispatch } from "react-redux";
|
import { connect } 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";
|
||||||
|
|
||||||
export const EpisodeTorrentsButton = ({
|
const episodeTorrentsButton = ({
|
||||||
torrents,
|
torrents,
|
||||||
imdbId,
|
imdbId,
|
||||||
season,
|
season,
|
||||||
episode,
|
episode,
|
||||||
showName,
|
showName,
|
||||||
searching,
|
searching,
|
||||||
}) => {
|
getEpisodeDetails,
|
||||||
const dispatch = useDispatch();
|
}) => (
|
||||||
|
|
||||||
return (
|
|
||||||
<TorrentsButton
|
<TorrentsButton
|
||||||
torrents={torrents}
|
torrents={torrents}
|
||||||
searching={searching}
|
searching={searching}
|
||||||
search={() => dispatch(getEpisodeDetails(imdbId, season, episode))}
|
search={() => getEpisodeDetails(imdbId, season, episode)}
|
||||||
url={`#/torrents/search/shows/${encodeURI(
|
url={`#/torrents/search/shows/${encodeURI(
|
||||||
prettyEpisodeName(showName, season, episode)
|
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,14 +1,12 @@
|
|||||||
import React, { useEffect, useCallback } 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 { useSelector, useDispatch } from "react-redux";
|
import { connect } 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";
|
||||||
@ -16,91 +14,56 @@ import { isWishlisted } from "../../utils";
|
|||||||
import ListDetails from "../list/details";
|
import ListDetails from "../list/details";
|
||||||
import ListPosters from "../list/posters";
|
import ListPosters from "../list/posters";
|
||||||
|
|
||||||
const fetchUrl = (match) => {
|
function mapStateToProps(state) {
|
||||||
switch (match.path) {
|
return {
|
||||||
case "/shows/polochon":
|
loading: state.showsStore.get("loading"),
|
||||||
return "/shows/polochon";
|
shows: state.showsStore.get("shows"),
|
||||||
case "/shows/wishlist":
|
filter: state.showsStore.get("filter"),
|
||||||
return "/wishlist/shows";
|
selectedImdbId: state.showsStore.get("selectedImdbId"),
|
||||||
case "/shows/search/:search":
|
exploreOptions: state.showsStore.get("exploreOptions"),
|
||||||
return "/shows/search/" + match.params.search;
|
};
|
||||||
case "/shows/explore/:source/:category":
|
}
|
||||||
return (
|
const mapDispatchToProps = {
|
||||||
"/shows/explore?source=" +
|
selectShow,
|
||||||
encodeURI(match.params.source) +
|
showWishlistToggle,
|
||||||
"&category=" +
|
getShowDetails,
|
||||||
encodeURI(match.params.category)
|
updateFilter,
|
||||||
);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ShowList = ({ match, history }) => {
|
const ShowList = (props) => {
|
||||||
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) => {
|
||||||
history.push("/shows/details/" + imdbId);
|
props.history.push("/shows/details/" + imdbId);
|
||||||
};
|
};
|
||||||
|
|
||||||
let selectedShow = Map();
|
let selectedShow = Map();
|
||||||
if (selectedImdbId !== "") {
|
if (props.selectedImdbId !== "") {
|
||||||
selectedShow = shows.get(selectedImdbId);
|
selectedShow = props.shows.get(props.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={shows}
|
data={props.shows}
|
||||||
type="shows"
|
type="shows"
|
||||||
placeHolder="Filter shows..."
|
placeHolder="Filter shows..."
|
||||||
exploreOptions={exploreOptions}
|
exploreOptions={props.exploreOptions}
|
||||||
exploreFetchOptions={exploreFetchOptions}
|
updateFilter={props.updateFilter}
|
||||||
updateFilter={filterFunc}
|
selectedImdbId={props.selectedImdbId}
|
||||||
selectedImdbId={selectedImdbId}
|
filter={props.filter}
|
||||||
filter={filter}
|
onClick={props.selectShow}
|
||||||
onClick={selectFunc}
|
|
||||||
onDoubleClick={showDetails}
|
onDoubleClick={showDetails}
|
||||||
onKeyEnter={showDetails}
|
onKeyEnter={showDetails}
|
||||||
params={match.params}
|
params={props.match.params}
|
||||||
loading={loading}
|
loading={props.loading}
|
||||||
/>
|
/>
|
||||||
<ListDetails
|
<ListDetails
|
||||||
data={selectedShow}
|
data={selectedShow}
|
||||||
loading={loading}
|
loading={props.loading}
|
||||||
wishlist={() =>
|
wishlist={() =>
|
||||||
dispatch(
|
props.showWishlistToggle(
|
||||||
showWishlistToggle(
|
|
||||||
isWishlisted(selectedShow),
|
isWishlisted(selectedShow),
|
||||||
selectedShow.get("imdb_id")
|
selectedShow.get("imdb_id")
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
@ -119,5 +82,14 @@ const ShowList = ({ match, history }) => {
|
|||||||
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 ShowList;
|
export default connect(mapStateToProps, mapDispatchToProps)(ShowList);
|
||||||
|
76
frontend/js/components/shows/route.js
Normal file
76
frontend/js/components/shows/route.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
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,28 +1,39 @@
|
|||||||
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 { useDispatch, useSelector } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import { prettySize } from "../../utils";
|
import { prettySize } from "../../utils";
|
||||||
import { addTorrent, removeTorrent } from "../../actions/torrents";
|
import {
|
||||||
|
fetchTorrents,
|
||||||
|
addTorrent,
|
||||||
|
removeTorrent,
|
||||||
|
} from "../../actions/torrents";
|
||||||
|
|
||||||
const TorrentList = () => {
|
const mapStateToProps = (state) => ({
|
||||||
const torrents = useSelector((state) => state.torrentStore.get("torrents"));
|
torrents: state.torrentStore.get("torrents"),
|
||||||
const dispatch = useDispatch();
|
});
|
||||||
|
const mapDispatchToProps = {
|
||||||
|
fetchTorrents,
|
||||||
|
addTorrent,
|
||||||
|
removeTorrent,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
const TorrentList = (props) => (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<AddTorrent addTorrent={(url) => dispatch(addTorrent(url))} />
|
<AddTorrent addTorrent={props.addTorrent} />
|
||||||
<Torrents
|
<Torrents torrents={props.torrents} removeTorrent={props.removeTorrent} />
|
||||||
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 TorrentList;
|
export default connect(mapStateToProps, mapDispatchToProps)(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 { useDispatch, useSelector } from "react-redux";
|
import { connect } 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,38 +9,40 @@ import { OverlayTrigger, Tooltip } from "react-bootstrap";
|
|||||||
|
|
||||||
import { prettySize } from "../../utils";
|
import { prettySize } from "../../utils";
|
||||||
|
|
||||||
const TorrentSearch = ({ history, match }) => {
|
const mapStateToProps = (state) => ({
|
||||||
const dispatch = useDispatch();
|
searching: state.torrentStore.get("searching"),
|
||||||
|
results: state.torrentStore.get("searchResults"),
|
||||||
const searching = useSelector((state) => state.torrentStore.get("searching"));
|
});
|
||||||
const results = useSelector((state) =>
|
const mapDispatchToProps = { addTorrent, searchTorrents };
|
||||||
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 url = useCallback(() => {
|
const getUrl = useCallback(() => {
|
||||||
if (search === "" || type === "") {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return `/torrents/search/${type}/${encodeURI(search)}`;
|
return `/torrents/search/${type}/${encodeURI(search)}`;
|
||||||
}, [type, search]);
|
}, [type, search]);
|
||||||
|
|
||||||
const searchFunc = useCallback(() => {
|
useEffect(() => {
|
||||||
const searchURL = url();
|
if (search === "") {
|
||||||
if (searchURL === "") {
|
return;
|
||||||
|
}
|
||||||
|
if (type === "") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(searchTorrents(searchURL));
|
const url = getUrl();
|
||||||
history.push(searchURL);
|
searchTorrents(url);
|
||||||
}, [dispatch, history, url]);
|
history.push(url);
|
||||||
|
}, [url, getUrl, searchTorrents, history, search, type]);
|
||||||
useEffect(() => {
|
|
||||||
searchFunc();
|
|
||||||
}, [searchFunc]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
@ -59,7 +61,7 @@ const TorrentSearch = ({ history, match }) => {
|
|||||||
typeFromURL={type}
|
typeFromURL={type}
|
||||||
handleClick={() => {
|
handleClick={() => {
|
||||||
setType("movies");
|
setType("movies");
|
||||||
searchFunc();
|
setUrl(getUrl());
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<SearchButton
|
<SearchButton
|
||||||
@ -68,7 +70,7 @@ const TorrentSearch = ({ history, match }) => {
|
|||||||
typeFromURL={type}
|
typeFromURL={type}
|
||||||
handleClick={() => {
|
handleClick={() => {
|
||||||
setType("shows");
|
setType("shows");
|
||||||
searchFunc();
|
setUrl(getUrl());
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -77,7 +79,7 @@ const TorrentSearch = ({ history, match }) => {
|
|||||||
<TorrentList
|
<TorrentList
|
||||||
searching={searching}
|
searching={searching}
|
||||||
results={results}
|
results={results}
|
||||||
addTorrent={(url) => dispatch(addTorrent(url))}
|
addTorrent={addTorrent}
|
||||||
searchFromURL={search}
|
searchFromURL={search}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -85,20 +87,24 @@ const TorrentSearch = ({ history, match }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
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 = ({ type, typeFromURL, text, handleClick }) => {
|
const SearchButton = (props) => {
|
||||||
const variant = type === typeFromURL ? "primary" : "secondary";
|
const variant = props.type === props.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={handleClick}
|
onClick={props.handleClick}
|
||||||
>
|
>
|
||||||
<i className="fa fa-search" aria-hidden="true"></i> {text}
|
<i className="fa fa-search" aria-hidden="true"></i> {props.text}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -227,4 +233,4 @@ TorrentHealth.propTypes = {
|
|||||||
leechers: PropTypes.number,
|
leechers: PropTypes.number,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TorrentSearch;
|
export default connect(mapStateToProps, mapDispatchToProps)(TorrentSearch);
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { useSelector } from "react-redux";
|
import PropTypes from "prop-types";
|
||||||
|
import { connect } from "react-redux";
|
||||||
import { Redirect, Link } from "react-router-dom";
|
import { Redirect, Link } from "react-router-dom";
|
||||||
|
|
||||||
const UserActivation = () => {
|
const mapStateToProps = (state) => ({
|
||||||
const isLogged = useSelector((state) => state.userStore.get("isLogged"));
|
isActivated: state.userStore.get("isActivated"),
|
||||||
const isActivated = useSelector((state) =>
|
isLogged: state.userStore.get("isLogged"),
|
||||||
state.userStore.get("isActivated")
|
});
|
||||||
);
|
|
||||||
|
|
||||||
if (!isLogged) {
|
const UserActivation = (props) => {
|
||||||
|
if (!props.isLogged) {
|
||||||
return <Redirect to="/users/login" />;
|
return <Redirect to="/users/login" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isActivated) {
|
if (props.isActivated) {
|
||||||
return <Redirect to="/" />;
|
return <Redirect to="/" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,4 +31,9 @@ const UserActivation = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default UserActivation;
|
UserActivation.propTypes = {
|
||||||
|
isActivated: PropTypes.bool.isRequired,
|
||||||
|
isLogged: PropTypes.bool.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(UserActivation);
|
||||||
|
@ -1,30 +1,44 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import PropTypes from "prop-types";
|
||||||
|
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";
|
||||||
|
|
||||||
export const UserEdit = () => {
|
const mapStateToProps = (state) => ({
|
||||||
const dispatch = useDispatch();
|
loading: state.userStore.get("loading"),
|
||||||
|
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(() => {
|
||||||
dispatch(getPolochons());
|
getPolochons();
|
||||||
dispatch(getUserInfos());
|
getUserInfos();
|
||||||
}, [dispatch]);
|
}, [getPolochons, getUserInfos]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setId(polochonId);
|
setId(polochonId);
|
||||||
@ -32,13 +46,11 @@ export const UserEdit = () => {
|
|||||||
|
|
||||||
const handleSubmit = (ev) => {
|
const handleSubmit = (ev) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
dispatch(
|
|
||||||
updateUser({
|
updateUser({
|
||||||
password: password,
|
password: password,
|
||||||
password_confirm: passwordConfirm, // eslint-disable-line camelcase
|
password_confirm: passwordConfirm, // eslint-disable-line camelcase
|
||||||
polochon_id: id, // eslint-disable-line camelcase
|
polochon_id: id, // eslint-disable-line camelcase
|
||||||
})
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@ -103,3 +115,17 @@ export const UserEdit = () => {
|
|||||||
</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,28 +1,29 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { connect } 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 UserLoginForm = () => {
|
const mapStateToProps = (state) => ({
|
||||||
const dispatch = useDispatch();
|
isLogged: state.userStore.get("isLogged"),
|
||||||
|
isLoading: state.userStore.get("loading"),
|
||||||
const isLogged = useSelector((state) => state.userStore.get("isLogged"));
|
error: state.userStore.get("error"),
|
||||||
const isLoading = useSelector((state) => state.userStore.get("loading"));
|
});
|
||||||
const error = useSelector((state) => state.userStore.get("error"));
|
const mapDispatchToProps = { loginUser };
|
||||||
|
|
||||||
|
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 (!isLoading) {
|
if (!props.isLoading) {
|
||||||
dispatch(loginUser(username, password));
|
props.loginUser(username, password);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isLogged) {
|
if (props.isLogged) {
|
||||||
return <Redirect to="/" />;
|
return <Redirect to="/" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,8 +32,8 @@ const UserLoginForm = () => {
|
|||||||
<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 />
|
||||||
{error && error !== "" && (
|
{props.error && props.error !== "" && (
|
||||||
<div className="alert alert-danger">{error}</div>
|
<div className="alert alert-danger">{props.error}</div>
|
||||||
)}
|
)}
|
||||||
<form className="form-horizontal" onSubmit={(e) => handleSubmit(e)}>
|
<form className="form-horizontal" onSubmit={(e) => handleSubmit(e)}>
|
||||||
<div>
|
<div>
|
||||||
@ -65,12 +66,12 @@ const UserLoginForm = () => {
|
|||||||
No account yet ? <Link to="/users/signup">Create one</Link>
|
No account yet ? <Link to="/users/signup">Create one</Link>
|
||||||
</small>
|
</small>
|
||||||
</span>
|
</span>
|
||||||
{isLoading && (
|
{props.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>
|
||||||
)}
|
)}
|
||||||
{isLoading || (
|
{props.isLoading || (
|
||||||
<span className="spaced-icons">
|
<span className="spaced-icons">
|
||||||
<input
|
<input
|
||||||
className="btn btn-primary pull-right"
|
className="btn btn-primary pull-right"
|
||||||
@ -86,5 +87,11 @@ const UserLoginForm = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
UserLoginForm.propTypes = {
|
||||||
|
loginUser: PropTypes.func.isRequired,
|
||||||
|
isLoading: PropTypes.bool.isRequired,
|
||||||
|
isLogged: PropTypes.bool.isRequired,
|
||||||
|
error: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
export default UserLoginForm;
|
export default connect(mapStateToProps, mapDispatchToProps)(UserLoginForm);
|
||||||
|
@ -1,18 +1,26 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import PropTypes from "prop-types";
|
||||||
|
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 UserLogout = () => {
|
const mapStateToProps = (state) => ({
|
||||||
const dispatch = useDispatch();
|
isLogged: state.userStore.get("isLogged"),
|
||||||
const isLogged = useSelector((state) => state.userStore.get("isLogged"));
|
});
|
||||||
|
const mapDispatchToProps = { userLogout };
|
||||||
|
|
||||||
if (isLogged) {
|
const UserLogout = (props) => {
|
||||||
dispatch(userLogout());
|
if (props.isLogged) {
|
||||||
|
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 UserLogout;
|
export default connect(mapStateToProps, mapDispatchToProps)(UserLogout);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import PropTypes from "prop-types";
|
||||||
|
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";
|
||||||
@ -7,16 +9,17 @@ 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 UserProfile = () => {
|
const mapStateToProps = (state) => ({
|
||||||
const dispatch = useDispatch();
|
modules: state.userStore.get("modules"),
|
||||||
const modules = useSelector((state) => state.userStore.get("modules"));
|
modulesLoading: state.userStore.get("modulesLoading"),
|
||||||
const modulesLoading = useSelector((state) =>
|
});
|
||||||
state.userStore.get("modulesLoading")
|
|
||||||
);
|
|
||||||
|
|
||||||
|
const mapDispatchToProps = { getUserModules };
|
||||||
|
|
||||||
|
const UserProfile = ({ modules, modulesLoading, getUserModules }) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(getUserModules());
|
getUserModules();
|
||||||
}, [dispatch]);
|
}, [getUserModules]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -26,5 +29,10 @@ const UserProfile = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
UserProfile.propTypes = {
|
||||||
|
getUserModules: PropTypes.func.isRequired,
|
||||||
|
modules: PropTypes.instanceOf(Map),
|
||||||
|
modulesLoading: PropTypes.bool.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
export default UserProfile;
|
export default connect(mapStateToProps, mapDispatchToProps)(UserProfile);
|
||||||
|
@ -1,33 +1,33 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import PropTypes from "prop-types";
|
||||||
|
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 UserSignUp = () => {
|
const mapStateToProps = (state) => ({
|
||||||
const dispatch = useDispatch();
|
isLogged: state.userStore.get("isLogged"),
|
||||||
|
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("");
|
||||||
|
|
||||||
const isLogged = useSelector((state) => state.userStore.get("isLogged"));
|
if (props.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();
|
||||||
dispatch(
|
props.userSignUp({
|
||||||
userSignUp({
|
|
||||||
username: username,
|
username: username,
|
||||||
password: password,
|
password: password,
|
||||||
password_confirm: passwordConfirm, // eslint-disable-line camelcase
|
password_confirm: passwordConfirm, // eslint-disable-line camelcase
|
||||||
})
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -35,8 +35,8 @@ const UserSignUp = () => {
|
|||||||
<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 />
|
||||||
{error && error !== "" && (
|
{props.error && props.error !== "" && (
|
||||||
<div className="alert alert-danger">{error}</div>
|
<div className="alert alert-danger">{props.error}</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<form className="form-horizontal" onSubmit={(e) => handleSubmit(e)}>
|
<form className="form-horizontal" onSubmit={(e) => handleSubmit(e)}>
|
||||||
@ -70,12 +70,12 @@ const UserSignUp = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{isLoading && (
|
{props.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>
|
||||||
)}
|
)}
|
||||||
{isLoading || (
|
{props.isLoading || (
|
||||||
<span>
|
<span>
|
||||||
<input
|
<input
|
||||||
className="btn btn-primary pull-right"
|
className="btn btn-primary pull-right"
|
||||||
@ -90,5 +90,11 @@ const UserSignUp = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
UserSignUp.propTypes = {
|
||||||
|
isLogged: PropTypes.bool.isRequired,
|
||||||
|
isLoading: PropTypes.bool.isRequired,
|
||||||
|
userSignUp: PropTypes.func.isRequired,
|
||||||
|
error: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
export default UserSignUp;
|
export default connect(mapStateToProps, mapDispatchToProps)(UserSignUp);
|
||||||
|
@ -1,35 +1,40 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useState } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { connect } 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 } from "immutable";
|
import { Map, List } from "immutable";
|
||||||
|
|
||||||
import { getUserTokens, deleteUserToken } from "../../actions/users";
|
import { getUserTokens, deleteUserToken } from "../../actions/users";
|
||||||
|
|
||||||
const UserTokens = () => {
|
const mapStateToProps = (state) => ({
|
||||||
const dispatch = useDispatch();
|
tokens: state.userStore.get("tokens"),
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = { getUserTokens, deleteUserToken };
|
||||||
|
|
||||||
const tokens = useSelector((state) => state.userStore.get("tokens"));
|
const UserTokens = (props) => {
|
||||||
|
const [fetched, setIsFetched] = useState(false);
|
||||||
useEffect(() => {
|
if (!fetched) {
|
||||||
dispatch(getUserTokens());
|
props.getUserTokens();
|
||||||
}, [dispatch]);
|
setIsFetched(true);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
{tokens.map((el, index) => (
|
{props.tokens.map((el, index) => (
|
||||||
<Token
|
<Token key={index} data={el} deleteToken={props.deleteUserToken} />
|
||||||
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"));
|
||||||
@ -166,4 +171,4 @@ Browser.propTypes = {
|
|||||||
version: PropTypes.string,
|
version: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UserTokens;
|
export default connect(mapStateToProps, mapDispatchToProps)(UserTokens);
|
||||||
|
@ -1,14 +1,25 @@
|
|||||||
import { useEffect, useState, useCallback } from "react";
|
import { useEffect, useState, useCallback } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import PropTypes from "prop-types";
|
||||||
|
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 WsHandler = () => {
|
const mapStateToProps = (state) => ({
|
||||||
const dispatch = useDispatch();
|
isLogged: state.userStore.get("isLogged"),
|
||||||
|
});
|
||||||
const isLogged = useSelector((state) => state.userStore.get("isLogged"));
|
const mapDispatchToProps = {
|
||||||
|
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(() => {
|
||||||
@ -62,13 +73,13 @@ const WsHandler = () => {
|
|||||||
|
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case "torrents":
|
case "torrents":
|
||||||
dispatch(setFetchedTorrents(data.message));
|
setFetchedTorrents(data.message);
|
||||||
break;
|
break;
|
||||||
case "newVideo":
|
case "newVideo":
|
||||||
if (data.message.type === "movie") {
|
if (data.message.type === "movie") {
|
||||||
dispatch(newMovieEvent(data.message.data));
|
newMovieEvent(data.message.data);
|
||||||
} else if (data.message.type === "episode") {
|
} else if (data.message.type === "episode") {
|
||||||
dispatch(newEpisodeEvent(data.message.data));
|
newEpisodeEvent(data.message.data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -79,7 +90,7 @@ const WsHandler = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
setWs(socket);
|
setWs(socket);
|
||||||
}, [ws, isLogged, dispatch, stop]);
|
}, [ws, isLogged, newMovieEvent, setFetchedTorrents, newEpisodeEvent, stop]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const intervalID = setInterval(() => {
|
const intervalID = setInterval(() => {
|
||||||
@ -107,5 +118,11 @@ const WsHandler = () => {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
WsHandler.propTypes = {
|
||||||
|
isLogged: PropTypes.bool.isRequired,
|
||||||
|
setFetchedTorrents: PropTypes.func,
|
||||||
|
newMovieEvent: PropTypes.func,
|
||||||
|
newEpisodeEvent: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
export default WsHandler;
|
export default connect(mapStateToProps, mapDispatchToProps)(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 js"
|
"lint": "./node_modules/eslint/bin/eslint.js ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bootstrap": "^4.4.1",
|
"bootstrap": "^4.4.1",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user