Add multiple polochon handling in the frontend

This commit is contained in:
Grégoire Delattre 2019-07-09 22:06:34 +02:00
parent d9d71c8ebd
commit 615a0b6d7c
12 changed files with 386 additions and 0 deletions

View File

@ -0,0 +1,35 @@
import { configureAxios, request } from "../requests"
export const getPolochons = () => request(
"PUBLIC_POLOCHON_LIST_FETCH",
configureAxios().get("/polochons"),
)
export const getManagedPolochons = () => request(
"MANAGED_POLOCHON_LIST_FETCH",
configureAxios().get("/users/polochons"),
)
export const addPolochon = (params) => request(
"ADD_POLOCHON",
configureAxios().post("/polochons", params),
[
() => getManagedPolochons(),
],
)
export const updatePolochon = ({ id, ...params }) => request(
"UPDATE_POLOCHON",
configureAxios().post(`/polochons/${id}`, params),
[
() => getManagedPolochons(),
],
)
export const deletePolochon = (id) => request(
"UPDATE_POLOCHON",
configureAxios().delete(`/polochons/${id}`),
[
() => getManagedPolochons(),
],
)

View File

@ -0,0 +1,22 @@
import React from "react"
import PropTypes from "prop-types"
export const FormInput = ({ label, value, updateValue }) => {
return (
<div className="form-group">
<label className="control-label">
{label}
</label>
<input
className="form-control"
value={value}
onChange={(e) => updateValue(e.target.value)}
/>
</div>
)
}
FormInput.propTypes = {
label: PropTypes.string,
value: PropTypes.string,
updateValue: PropTypes.func,
};

View File

@ -0,0 +1,49 @@
import React from "react"
import PropTypes from "prop-types"
import { Modal } from "react-bootstrap"
export const FormModal = ({
show,
setShow,
title,
icon,
handleSubmit,
children,
}) => {
const submit = function(e) {
if (e) { e.preventDefault(); }
handleSubmit();
};
return (
<Modal show={show} onHide={() => setShow(false)}>
<Modal.Header closeButton>
<Modal.Title>
<i className={`fa fa-${icon} mr-1`} />
{title}
</Modal.Title>
</Modal.Header>
<Modal.Body bsPrefix="modal-body">
<form className="form-horizontal" onSubmit={(ev) => submit(ev)}>
{children}
</form>
</Modal.Body>
<Modal.Footer>
<div className="btn btn-success" onClick={submit}>Apply</div>
<div className="btn btn-error" onClick={() => setShow(false)}>Close</div>
</Modal.Footer>
</Modal>
)
}
FormModal.propTypes = {
show: PropTypes.bool,
setShow: PropTypes.func,
icon: PropTypes.string,
title: PropTypes.string,
handleSubmit: PropTypes.func,
children: PropTypes.oneOf(
PropTypes.object,
PropTypes.array,
),
};

View File

@ -0,0 +1,31 @@
import React, { useState } from "react"
import PropTypes from "prop-types"
import { connect } from "react-redux"
import { addPolochon } from "../../actions/polochon"
import { PolochonEdit } from "./edit"
export const PolochonAddConnected = ({ addPolochon }) => {
const [modal, setModal] = useState(false);
return (
<React.Fragment>
<div className="btn btn-primary btn-lg" onClick={() => setModal(true)}>
<i className="fa fa-plus mr-2" />
Add new polochon
</div>
<PolochonEdit
show={modal}
setShow={setModal}
update={addPolochon}
/>
</React.Fragment>
)
}
PolochonAddConnected.propTypes = {
addPolochon: PropTypes.func,
};
export const PolochonAdd = connect(null, {addPolochon})(PolochonAddConnected);

View File

@ -0,0 +1,59 @@
import React, { useState, useEffect } from "react"
import PropTypes from "prop-types"
import { FormModal } from "../forms/modal"
import { FormInput } from "../forms/input"
export const PolochonEdit = ({
show,
setShow,
id,
initialName,
initialUrl,
initialToken,
update,
}) => {
const [name, setName] = useState(initialName);
const [url, setUrl] = useState(initialUrl);
const [token, setToken] = useState(initialToken);
useEffect(() => {
setName(initialName);
setUrl(initialUrl);
setToken(initialToken);
}, [id, initialName, initialUrl, initialToken])
const handleSubmit = () => {
update({ id, name, url, token });
setShow(false);
};
return (
<FormModal
show={show}
setShow={setShow}
title="Add a new polochon"
icon="plus"
handleSubmit={handleSubmit}
>
<FormInput label="Name" value={name} updateValue={setName} />
<FormInput label="URL" value={url} updateValue={setUrl} />
<FormInput label="Token" value={token} updateValue={setToken} />
</FormModal>
)
}
PolochonEdit.propTypes = {
show: PropTypes.bool,
setShow: PropTypes.func,
update: PropTypes.func,
id: PropTypes.string,
initialName: PropTypes.string,
initialUrl: PropTypes.string,
initialToken: PropTypes.string,
};
PolochonEdit.defaultProps = {
id: "",
initialName: "",
initialUrl: "",
initialToken: "",
};

View File

@ -0,0 +1,56 @@
import React, { useEffect } from "react"
import PropTypes from "prop-types"
import { connect } from "react-redux"
import { List } from "immutable"
import { getManagedPolochons } from "../../actions/polochon"
import { Polochon } from "./polochon"
import { PolochonAdd } from "./add"
const mapStateToProps = (state) => ({
managedList: state.polochon.get("managed"),
});
const mapDispatchToProps = {
getManagedPolochons,
}
const PolochonListConnected = ({
getManagedPolochons,
managedList,
}) => {
useEffect(() => {
getManagedPolochons();
}, [getManagedPolochons])
return (
<div className="row mb-3">
<div className="col-12 col-md-6 offset-md-3">
<h2>My polochons</h2>
<hr />
<span>
{managedList.map((el, index) => (
<Polochon
key={index}
id={el.get("id")}
name={el.get("name")}
token={el.get("token")}
url={el.get("url")}
authToken={el.get("auth_token")}
users={el.get("users")}
/>
))}
</span>
<PolochonAdd />
</div>
</div>
)
}
PolochonListConnected.propTypes = {
getManagedPolochons: PropTypes.func,
managedList: PropTypes.instanceOf(List),
};
export const PolochonList = connect(mapStateToProps, mapDispatchToProps)(PolochonListConnected);

View File

@ -0,0 +1,83 @@
import React, { useState } from "react"
import PropTypes from "prop-types"
import { List } from "immutable"
import { connect } from "react-redux"
import { PolochonUser } from "./user"
import { PolochonEdit } from "./edit"
import { updatePolochon, deletePolochon } from "../../actions/polochon"
export const PolochonConnected = ({
id,
name,
token,
url,
authToken,
users,
updatePolochon,
deletePolochon,
}) => {
const [edit, setEdit] = useState(false);
return (
<React.Fragment>
<div className="card mb-2">
<div className="card-header">
{name !== "" ? name : "-"}
<small className="ml-1">
({url !== "" ? url : "-"})
</small>
<span className="pull-right">
<i
className="fa fa-edit mr-3 clickable"
onClick={() => setEdit(true)}
/>
<i
className="fa fa-trash clickable"
onClick={() => deletePolochon(id)}
/>
</span>
</div>
<div className="card-body">
<p className="card-text">ID: {id}</p>
<p className="card-text">Egress token: {token}</p>
<p className="card-text">Ingress token: {authToken}</p>
<p className="card-text">
Users:
{users.map((user, index) => (
<PolochonUser
key={index}
id={user.get("id")}
name={user.get("name")}
/>
))}
</p>
</div>
</div>
<PolochonEdit
show={edit}
setShow={setEdit}
update={updatePolochon}
id={id}
initialName={name}
initialUrl={url}
initialToken={token}
initialAuthToken={authToken}
/>
</React.Fragment>
)
}
PolochonConnected.propTypes = {
id: PropTypes.string,
name: PropTypes.string,
token: PropTypes.string,
url: PropTypes.string,
authToken: PropTypes.string,
users: PropTypes.instanceOf(List),
updatePolochon: PropTypes.func,
deletePolochon: PropTypes.func,
};
export const Polochon = connect(null, { updatePolochon, deletePolochon })(PolochonConnected);

View File

@ -0,0 +1,14 @@
import React from "react"
import PropTypes from "prop-types"
export const PolochonUser = ({ id, name }) => {
return (
<span>
{name} ({id})
</span>
)
}
PolochonUser.propTypes = {
id: PropTypes.string,
name: PropTypes.string,
};

View File

@ -4,6 +4,8 @@ import { connect } from "react-redux"
import Loader from "../loader/loader" import Loader from "../loader/loader"
import { Map } from "immutable" import { Map } from "immutable"
import { PolochonList } from "../polochons/list"
import { import {
updateUser, getUserInfos, updateUser, getUserInfos,
getUserTokens, getUserModules getUserTokens, getUserModules
@ -37,6 +39,7 @@ const UserProfile = (props) => {
url={props.url} url={props.url}
updateUser={props.updateUser} updateUser={props.updateUser}
/> />
<PolochonList />
<Modules <Modules
modules={props.modules} modules={props.modules}
isLoading={props.modulesLoading} isLoading={props.modulesLoading}

View File

@ -7,6 +7,7 @@ import userStore from "./users"
import alerts from "./alerts" import alerts from "./alerts"
import torrentStore from "./torrents" import torrentStore from "./torrents"
import adminStore from "./admins" import adminStore from "./admins"
import polochon from "./polochon"
export default combineReducers({ export default combineReducers({
movieStore, movieStore,
@ -16,4 +17,5 @@ export default combineReducers({
alerts, alerts,
torrentStore, torrentStore,
adminStore, adminStore,
polochon,
}); });

View File

@ -0,0 +1,28 @@
import { List, Map, fromJS } from "immutable"
const defaultState = Map({
loadingPublic: false,
loadingManaged: false,
public: List(),
managed: List(),
});
const handlers = {
"PUBLIC_POLOCHON_LIST_FETCH_PENDING": state => state.set("loadingPublic", true),
"PUBLIC_POLOCHON_LIST_FETCH_FULFILLED": (state, action) => {
return state.merge({
loadingPublic: false,
public: List(fromJS(action.payload.response.data)),
});
},
"MANAGED_POLOCHON_LIST_FETCH_PENDING": state => state.set("loadingManaged", true),
"MANAGED_POLOCHON_LIST_FETCH_FULFILLED": (state, action) => {
return state.merge({
loadingManaged: false,
managed: List(fromJS(action.payload.response.data)),
});
},
}
export default (state = defaultState, action) =>
handlers[action.type] ? handlers[action.type](state, action) : state;

View File

@ -13,6 +13,8 @@ const defaultState = Map({
isLogged: false, isLogged: false,
polochonToken: "", polochonToken: "",
polochonUrl: "", polochonUrl: "",
polochonName: "",
polochonActivated: false,
tokens: List(), tokens: List(),
modules: Map(), modules: Map(),
modulesLoading: false, modulesLoading: false,
@ -45,6 +47,8 @@ const handlers = {
"GET_USER_FULFILLED": (state, action) => state.merge(Map({ "GET_USER_FULFILLED": (state, action) => state.merge(Map({
polochonToken: action.payload.response.data.token, polochonToken: action.payload.response.data.token,
polochonUrl: action.payload.response.data.url, polochonUrl: action.payload.response.data.url,
polochonName: action.payload.response.data.name,
polochonActivated: action.payload.response.data.activated,
loading: false, loading: false,
})), })),
"GET_USER_TOKENS_PENDING": state => state.set("loading", true), "GET_USER_TOKENS_PENDING": state => state.set("loading", true),