🏗 Wiring up Settings form

This commit is contained in:
2021-11-15 21:27:04 -08:00
parent 305c172be7
commit b34c985ff4
6 changed files with 201 additions and 76 deletions

View File

@@ -1,13 +1,31 @@
import axios from "axios"; import axios from "axios";
import { IExtractionOptions } from "threetwo-ui-typings"; import { IExtractionOptions } from "threetwo-ui-typings";
import {} from "../constants/action-types"; import { SETTINGS_OBJECT_FETCHED } from "../constants/action-types";
import { SETTINGS_SERVICE_BASE_URI } from "../constants/endpoints"; import { SETTINGS_SERVICE_BASE_URI } from "../constants/endpoints";
export const saveSettings = (settingsObject) => async (dispatch) => { export const saveSettings =
(settingsObject, airdcppUserSettings) => async (dispatch) => {
const result = await axios({
url: `${SETTINGS_SERVICE_BASE_URI}/saveSettings`,
method: "POST",
data: { settingsObject, airdcppUserSettings },
});
dispatch({
type: SETTINGS_OBJECT_FETCHED,
data: result.data,
});
};
export const getSettings = (settingsKey?) => async (dispatch) => {
const result = await axios({ const result = await axios({
url: `${SETTINGS_SERVICE_BASE_URI}/saveSettings`, url: `${SETTINGS_SERVICE_BASE_URI}/getSettings`,
method: "POST", method: "POST",
data: settingsObject, data: settingsKey,
}); });
console.log(result); {
dispatch({
type: SETTINGS_OBJECT_FETCHED,
data: result.data,
});
}
}; };

View File

@@ -1,91 +1,180 @@
import React, { ReactElement } from "react"; import React, { ReactElement, useEffect } from "react";
import { Form, Field } from "react-final-form"; import { Form, Field } from "react-final-form";
import { useDispatch } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { saveSettings } from "../actions/settings.actions"; import { saveSettings, getSettings } from "../actions/settings.actions";
import axios from "axios"; import axios from "axios";
import { isUndefined, isEmpty } from "lodash";
export const AirDCPPSettingsForm = (): ReactElement => { export const AirDCPPSettingsForm = (): ReactElement => {
const airdcppClientSettings = useSelector(
(state: RootState) => state.settings.data[0],
);
const dispatch = useDispatch(); const dispatch = useDispatch();
useEffect(() => {
dispatch(getSettings());
}, [dispatch]);
const onSubmit = async (values) => { const onSubmit = async (values) => {
try { try {
const fqdn = values.protocol + values.hostname;
const airdcppResponse = await axios({ const airdcppResponse = await axios({
url: `https://${values.airdcpp_hostname}/api/v1/sessions/authorize`, url: `${fqdn}/api/v1/sessions/authorize`,
method: "POST", method: "POST",
data: { data: {
username: values.airdcpp_username, username: values.username,
password: values.airdcpp_password, password: values.password,
}, },
}); });
if (airdcppResponse.status === 200) { if (airdcppResponse.status === 200) {
dispatch(saveSettings(values)); dispatch(saveSettings(values, airdcppResponse.data));
} }
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
}; };
const validate = async () => {}; const validate = async () => {};
const initFormData = !isUndefined(airdcppClientSettings)
? airdcppClientSettings.directConnect.client
: null;
return ( return (
<Form <>
onSubmit={onSubmit} <Form
validate={validate} onSubmit={onSubmit}
render={({ handleSubmit }) => ( validate={validate}
<form onSubmit={handleSubmit}> initialValues={initFormData}
<h2>AirDC++ Connection Information</h2> render={({ handleSubmit }) => (
<div className="field"> <form onSubmit={handleSubmit}>
<h2>AirDC++ Connection Information</h2>
<label className="label">AirDC++ Hostname</label> <label className="label">AirDC++ Hostname</label>
<div className="control"> <div className="field has-addons">
<Field <p className="control">
name="airdcpp_hostname" <span className="select">
component="input" <Field name="protocol" component="select">
className="input" <option value="http://">http://</option>
placeholder="111.222.333.4 / one.airdcpp.com" <option value="https://">https://</option>
/> </Field>
</span>
</p>
<p className="control is-expanded">
<Field
name="hostname"
component="input"
className="input"
placeholder="AirDC++ host IP / hostname"
/>
</p>
</div> </div>
</div> <div className="field">
<div className="field"> <div className="is-clearfix">
<div className="is-clearfix"> <label className="label">Credentials</label>
<label className="label">Credentials</label>
</div>
<div className="field-body">
<div className="field">
<p className="control is-expanded has-icons-left">
<Field
name="airdcpp_username"
component="input"
className="input"
placeholder="Username"
/>
<span className="icon is-small is-left">
<i className="fa-solid fa-user-ninja"></i>
</span>
</p>
</div> </div>
<div className="field"> <div className="field-body">
<p className="control is-expanded has-icons-left has-icons-right"> <div className="field">
<Field <p className="control is-expanded has-icons-left">
name="airdcpp_password" <Field
component="input" name="username"
type="password" component="input"
className="input" className="input"
placeholder="Password" placeholder="Username"
/> />
<span className="icon is-small is-left"> <span className="icon is-small is-left">
<i className="fa-solid fa-lock"></i> <i className="fa-solid fa-user-ninja"></i>
</span> </span>
<span className="icon is-small is-right"> </p>
<i className="fas fa-check"></i> </div>
</span> <div className="field">
</p> <p className="control is-expanded has-icons-left has-icons-right">
<Field
name="password"
component="input"
type="password"
className="input"
placeholder="Password"
/>
<span className="icon is-small is-left">
<i className="fa-solid fa-lock"></i>
</span>
<span className="icon is-small is-right">
<i className="fas fa-check"></i>
</span>
</p>
</div>
</div> </div>
</div> </div>
</div>
<button type="submit" className="button is-primary"> <button type="submit" className="button is-primary">
Submit {!isEmpty(initFormData) ? "Update" : "Save"}
</button> </button>
</form> </form>
)} )}
/> />
{!isUndefined(airdcppClientSettings) &&
!isEmpty(airdcppClientSettings) ? (
<div className="mt-4 is-clearfix">
<div className="card">
<div className="card-content">
<span className="icon is-medium is-pulled-right">
<i className="fa-solid fa-circle has-text-success"></i>
</span>
<div className="content is-size-7">
<dl>
<dt>{airdcppClientSettings._id}</dt>
<dt>
Client version:{" "}
{
airdcppClientSettings.directConnect.client
.airdcppUserSettings.system_info.client_version
}
</dt>
<dt>
Hostname:{" "}
{
airdcppClientSettings.directConnect.client
.airdcppUserSettings.system_info.hostname
}
</dt>
<dt>
Platform:{" "}
{
airdcppClientSettings.directConnect.client
.airdcppUserSettings.system_info.platform
}
</dt>
<dt>
Username:{" "}
{
airdcppClientSettings.directConnect.client
.airdcppUserSettings.user.username
}
</dt>
<dt>
Active Sessions:{" "}
{
airdcppClientSettings.directConnect.client
.airdcppUserSettings.user.active_sessions
}
</dt>
<dt>
Permissions:{" "}
<pre>
{JSON.stringify(
airdcppClientSettings.directConnect.client
.airdcppUserSettings.user.permissions,
undefined,
2,
)}
</pre>
</dt>
</dl>
</div>
</div>
</div>
</div>
) : null}
</>
); );
}; };

View File

@@ -14,6 +14,7 @@ import { Form, Field } from "react-final-form";
import { getComicBooks } from "../actions/fileops.actions"; import { getComicBooks } from "../actions/fileops.actions";
import { isNil } from "lodash"; import { isNil } from "lodash";
import { IMPORT_SERVICE_HOST } from "../constants/endpoints"; import { IMPORT_SERVICE_HOST } from "../constants/endpoints";
import { Link } from "react-router-dom";
interface IComicBookLibraryProps { interface IComicBookLibraryProps {
matches?: unknown; matches?: unknown;
@@ -142,6 +143,26 @@ export const Library = ({}: IComicBookLibraryProps): ReactElement => {
</div> </div>
)} )}
/> />
<div className="column one-fifth">
<div className="field has-addons">
<p className="control">
<button className="button">
<span className="icon is-small">
<i className="fa-solid fa-list"></i>
</span>
</button>
</p>
<p className="control">
<button className="button">
<Link to="/library-grid">
<span className="icon is-small">
<i className="fa-solid fa-image"></i>
</span>
</Link>
</button>
</p>
</div>
</div>
</div> </div>
); );
}; };
@@ -292,6 +313,7 @@ export const Library = ({}: IComicBookLibraryProps): ReactElement => {
<section className="container"> <section className="container">
<div className="section"> <div className="section">
<h1 className="title">Library</h1> <h1 className="title">Library</h1>
<SearchBar /> <SearchBar />
<div> <div>
<div className="library"> <div className="library">

View File

@@ -46,9 +46,7 @@ const Navbar: React.FunctionComponent = (props) => {
<Link to="/library" className="navbar-item"> <Link to="/library" className="navbar-item">
Library Library
</Link> </Link>
<Link to="/library-grid" className="navbar-item">
Library Grid
</Link>
<Link to="/search" className="navbar-item"> <Link to="/search" className="navbar-item">
Search Search
</Link> </Link>

View File

@@ -34,10 +34,8 @@ export const Settings = (props: ISettingsProps): ReactElement => {
<aside className="menu"> <aside className="menu">
{map(settingsObject, (settingObject, idx) => { {map(settingsObject, (settingObject, idx) => {
return ( return (
<> <div key={idx}>
<p className="menu-label" key={idx}> <p className="menu-label">{settingObject.category}</p>
{settingObject.category}
</p>
{/* First level children */} {/* First level children */}
{!isUndefined(settingObject.children) ? ( {!isUndefined(settingObject.children) ? (
<ul className="menu-list" key={settingObject.id}> <ul className="menu-list" key={settingObject.id}>
@@ -78,7 +76,7 @@ export const Settings = (props: ISettingsProps): ReactElement => {
})} })}
</ul> </ul>
) : null} ) : null}
</> </div>
); );
})} })}
</aside> </aside>

View File

@@ -4,7 +4,7 @@ import {
SETTINGS_CALL_IN_PROGRESS, SETTINGS_CALL_IN_PROGRESS,
} from "../constants/action-types"; } from "../constants/action-types";
const initialState = { const initialState = {
settings: {}, data: {},
inProgress: false, inProgress: false,
}; };