refactoring (login): simplify code + lint

This commit is contained in:
Mickael Kerjean
2021-12-21 17:04:35 +11:00
parent 5156432b52
commit efe202bfd0
4 changed files with 155 additions and 325 deletions

View File

@ -1,111 +1,74 @@
import React from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
import React, { useState, useEffect } from "react";
import './connectpage.scss';
import { Session } from '../model/';
import { Container, NgIf, NgShow, Loader, Notification, ErrorPage } from '../components/';
import { ForkMe, PoweredByFilestash, Form } from './connectpage/';
import { cache, notify, urlParams } from '../helpers/';
import "./connectpage.scss";
import { Session } from "../model/";
import { Container, NgShow, Loader, ErrorPage } from "../components/";
import { ForkMe, PoweredByFilestash, Form } from "./connectpage/";
import { cache, notify, urlParams } from "../helpers/";
import { Alert } from '../components/';
function ConnectPageComponent({ error, history }) {
const [isLoading, setIsLoading] = useState(true);
const _GET = urlParams();
@ErrorPage
export class ConnectPage extends React.Component {
constructor(props){
super(props);
this.state = {
loading: true,
doing_a_third_party_login: false
};
}
componentDidMount(){
const urlData = urlParams();
const get_params = Object.keys(urlData);
if(get_params.length === 0){
return;
}else if(get_params.length === 1 && !!urlData["next"]){
return;
}
if(!urlData.type){
urlData.type = urlData.state;
}
this.setState({
doing_a_third_party_login: true,
loading: true
}, () => this.authenticate(urlData));
}
authenticate(params){
Session.authenticate(params)
const authenticate = (formData) => {
return Session.authenticate(formData)
.then(Session.currentUser)
.then((user) => {
if(location.search.indexOf("?next=") === 0){
location = urlParams()["next"];
if (formData["next"]) {
location = formData["next"];
return;
}
let url = "/files/";
let path = user.home;
if(path){
path = path.replace(/^\/?(.*?)\/?$/, "$1");
if(path !== ""){
url += path + "/";
}
if (user["home"]) {
user["home"] = user["home"].replace(/^\/?(.*?)\/?$/, "$1").trim();
if (user["home"] !== "") url = `${url}${user["home"]}/`;
}
cache.destroy();
this.props.history.push(url);
})
.catch((err) => {
this.setState({loading: false});
notify.send(err, "error");
history.push(url);
});
}
};
onFormSubmit(data){
if("oauth2" in data){
this.setState({loading: true});
Session.oauth2(data.oauth2).then((url) => {
const onFormSubmit = (formData) => {
if ("oauth2" in formData) {
setIsLoading(true);
Session.oauth2(formData["oauth2"]).then((url) => {
window.location.href = url;
});
return;
}
this.setState({
loading: true
}, () => this.authenticate(data));
}
setIsLoading(true);
authenticate({ ..._GET, ...formData }).catch((err) => {
setIsLoading(false);
notify.send(err, "error");
});
};
setLoading(value){
if(this.state.doing_a_third_party_login !== true){
this.setState({loading: value});
const onFormChangeLoadingState = (onOrOff) => {
if (_GET["state"]) return; // Don't do anything when using oauth2
setIsLoading(onOrOff);
};
useEffect(() => {
if (_GET["state"]) {
authenticate({ ..._GET, type: _GET["state"] })
.catch((err) => error(err));
}
}
}, []);
onError(err){
this.props.error(err);
}
render() {
return (
<div className="component_page_connect">
<NgIf cond={window.CONFIG["fork_button"]}>
<ForkMe repo="https://github.com/mickael-kerjean/filestash" />
</NgIf>
<Container maxWidth="565px">
<NgIf cond={this.state.loading === true}>
<Loader/>
</NgIf>
<NgShow cond={this.state.loading === false}>
<ReactCSSTransitionGroup transitionName="form" transitionLeave={false} transitionEnter={false} transitionAppear={true} transitionAppearTimeout={500}>
<Form onLoadingChange={this.setLoading.bind(this)}
onError={this.onError.bind(this)}
onSubmit={this.onFormSubmit.bind(this)} />
</ReactCSSTransitionGroup>
<ReactCSSTransitionGroup transitionName="remember" transitionLeave={false} transitionEnter={false} transitionAppear={true} transitionAppearTimeout={5000}>
<PoweredByFilestash />
</ReactCSSTransitionGroup>
return (
<div className="component_page_connect">
{ window.CONFIG["fork_button"] && <ForkMe /> }
<Container maxWidth="565px">
{ isLoading && <Loader /> }
<NgShow cond={!isLoading}>
<Form onLoadingChange={onFormChangeLoadingState}
onError={error}
onSubmit={onFormSubmit} />
{ window.CONFIG["fork_button"] && <PoweredByFilestash /> }
</NgShow>
</Container>
</div>
);
}
</Container>
</div>
);
}
export const ConnectPage = ErrorPage(ConnectPageComponent);

View File

@ -5,3 +5,19 @@
.dark-mode .component_page_connect{
background: var(--dark-mode-bg-color);
}
/* PAGE ANIMATION */
@keyframes PageConnectionPoweredBy {
from { transform: translateY(2px); opacity: 0;}
to {transform: translateY(0); opacity: 1; }
}
@keyframes PageConnectionForm {
from { transform: scale(0.99); }
to {transform: scale(1); }
}
.component_poweredbyfilestash, .component_page_connect .component_page_connection_form {
animation-duration: 0.3s;
animation-fill-mode: forwards;
}
.component_poweredbyfilestash { animation-name: PageConnectionPoweredBy; animation-delay: 0.2s; opacity: 0; }
.component_page_connect .component_page_connection_form { animation-name: PageConnectionForm; }

View File

@ -1,41 +1,33 @@
import React, { useState, useEffect } from "react";
import { Container, Card, NgIf, Input, Button, Textarea, FormBuilder } from "../../components/";
import { gid, settings_get, settings_put, createFormBackend, FormObjToJSON, nop } from "../../helpers/";
import { Session, Backend } from "../../model/";
import { Card, Button, FormBuilder } from "../../components/";
import {
settings_get, settings_put, createFormBackend, FormObjToJSON, nop,
} from "../../helpers/";
import { Backend } from "../../model/";
import { t } from "../../locales/";
import "./form.scss";
export function Form({
onLoadingChange = nop, onError = nop, onSubmit = nop
onLoadingChange = nop, onError = nop, onSubmit = nop,
}) {
const [selectedTab, setSelectedTab] = useState(function(){
const [enabledBackends, setEnabledBackends] = useState([]);
const [selectedTab, setSelectedTab] = useState(function() { // TODO: buggy
const connLength = window.CONFIG["connections"].length;
if(connLength < 4) return 0;
else if(connLength < 5) return 1;
if (connLength < 4) return 0;
else if (connLength < 5) return 1;
return 2;
}());
const [enabledBackends, setEnabledBackends] = useState([]);
const _marginTop = () => {
let size = 300;
const $screen = document.querySelector(".login-form");
if($screen) size = $screen.offsetHeight;
size = Math.round((document.body.offsetHeight - size) / 2);
if(size < 0) return 0;
if(size > 150) return 150;
return size;
};
useEffect(() => {
const select = settings_get("login_tab");
if(select !== null && select < window.CONFIG["connections"].length){
if (select !== null && select < window.CONFIG["connections"].length) {
setSelectedTab(select);
}
Backend.all().then((backend) => {
onLoadingChange(false)
onLoadingChange(false);
setEnabledBackends(window.CONFIG["connections"].reduce((acc, conn) => {
const f = createFormBackend(backend, conn);
if(Object.keys(f).length > 0){
if (Object.keys(f).length > 0) {
acc.push(f);
}
return acc;
@ -52,70 +44,82 @@ export function Form({
};
const onSubmitForm = (e) => {
e.preventDefault();
const data = () => {
const formData = FormObjToJSON((() => {
const tmp = enabledBackends[selectedTab];
return tmp[Object.keys(tmp)[0]];
};
const dataToBeSubmitted = JSON.parse(JSON.stringify(FormObjToJSON(data())));
delete dataToBeSubmitted.image;
delete dataToBeSubmitted.label;
delete dataToBeSubmitted.advanced;
onSubmit(dataToBeSubmitted);
})());
delete formData.image;
delete formData.label;
delete formData.advanced;
onSubmit(formData);
};
const onTypeChange = (tabn) => {
setSelectedTab(tabn);
};
return (
<Card style={{marginTop: _marginTop()+"px"}} className="no-select component_page_connection_form">
<NgIf cond={ window.CONFIG["connections"].length > 1 }>
<div role="navigation" className={"buttons "+((window.innerWidth < 600) ? "scroll-x" : "")}>
{
enabledBackends.map((backend, i) => {
const key = Object.keys(backend)[0];
if(!backend[key]) return null;
return (
<Button key={"menu-"+i} className={i === selectedTab ? "active primary" : ""} onClick={() => onTypeChange(i)}>
{ backend[key].label.value }
</Button>
);
})
}
const renderForm = ($input, props, struct, onChange) => {
if (struct.type === "image") {
return (
<div className="center">
{ $input }
</div>
</NgIf>
);
} else if (struct.enabled === true) {
return null;
} else if (struct.label === "advanced") {
return (
<label style={{ color: "rgba(0,0,0,0.4)" }}>
{ $input }
{ t("Advanced") }
</label>
);
}
return (
<label htmlFor={props.params["id"]}
className={"no-select input_type_" + props.params["type"]}>
<div>
{ $input }
</div>
</label>
);
};
return (
<Card style={{ marginTop: `${_centerThis()}px` }}
className="no-select component_page_connection_form">
{
enabledBackends.length > 1 && (
<div role="navigation"
className={`buttons ${((window.innerWidth < 600) ? "scroll-x" : "")}`}>
{
enabledBackends.map((backend, i) => {
const key = Object.keys(backend)[0];
if (!backend[key]) return null; // TODO: this shouldn't be needed
return (
<Button
key={`menu-${i}`}
className={i === selectedTab ? "active primary" : ""}
onClick={() => onTypeChange(i)}
>
{ backend[key].label.value }
</Button>
);
})
}
</div>
)
}
<div>
<form onSubmit={(e) => onSubmitForm(e)} autoComplete="off" autoCapitalize="off" spellCheck="false" autoCorrect="off">
<form onSubmit={(e) => onSubmitForm(e)} autoComplete="off" autoCapitalize="off"
spellCheck="false" autoCorrect="off">
{
enabledBackends.map((form, i) => {
const key = Object.keys(form)[0];
if(!form[key]) return null;
else if(selectedTab !== i) return null;
if (!form[key]) return null; // TODO: this shouldn't be needed
else if (selectedTab !== i) return null;
return (
<FormBuilder form={form[key]} onChange={onFormChange} key={"form"+i}
render={ ($input, props, struct, onChange) => {
if(struct.type === "image"){
return (
<div className="center">
{ $input }
</div>
);
} else if(struct.enabled === true){
return null;
} else if(struct.label === "advanced") return (
<label style={{color: "rgba(0,0,0,0.4)"}}>
{ $input }
{ t("Advanced") }
</label>
);
return (
<label htmlFor={props.params["id"]} className={"no-select input_type_" + props.params["type"]}>
<div>
{ $input }
</div>
</label>
);
}} />
render={renderForm} />
);
})
}
@ -123,159 +127,16 @@ export function Form({
</form>
</div>
</Card>
)
);
}
const _centerThis = () => {
let size = 300;
const $screen = document.querySelector(".login-form");
if ($screen) size = $screen.offsetHeight;
export class FormOld extends React.Component {
constructor(props){
super(props);
this.state = {
select: function(){
const connLength = window.CONFIG["connections"].length;
if(connLength < 4) return 0;
else if(connLength < 5) return 1;
return 2;
}(),
backends_enabled: []
};
const select = settings_get("login_tab");
if(select !== null && select < window.CONFIG["connections"].length){ this.state.select = select; }
this.rerender = () => this.setState({_refresh: !this.state._refresh});
}
componentDidMount(){
window.addEventListener("resize", this.rerender);
Backend.all().then((backend) => {
this.props.onLoadingChange(false);
this.setState({
backends_available: backend,
backends_enabled: window.CONFIG["connections"].reduce((acc, conn) => {
const f = createFormBackend(backend, conn);
if(Object.keys(f).length > 0){
acc.push(f);
}
return acc;
}, [])
}, () => this.publishState(this.props));
}).catch((err) => this.props.onError(err));
}
componentWillUnmount(){
settings_put("login_tab", this.state.select);
window.removeEventListener("resize", this.rerender);
}
componentWillReceiveProps(props){
if(JSON.stringify(props.credentials) !== JSON.stringify(this.props.credentials)){
this.publishState(props);
}
}
publishState(props){
for(let key in props.credentials){
this.state.backends_enabled = this.state.backends_enabled.map((backend) => {
const b = backend[Object.keys(backend)[0]];
if(b["type"].value + "_" + b["label"].value === key){
for(let k in b){
if(props.credentials[key][k]){
b[k].value = props.credentials[key][k];
}
}
}
return backend;
});
}
this.setState({backends_enabled: this.state.backends_enabled});
}
onSubmit(e){
e.preventDefault();
const data = () => {
const tmp = this.state.backends_enabled[this.state.select];
return tmp[Object.keys(tmp)[0]];
};
const dataToBeSubmitted = JSON.parse(JSON.stringify(FormObjToJSON(data())));
const key = dataToBeSubmitted["type"] + "_" + dataToBeSubmitted["label"];
delete dataToBeSubmitted.image;
delete dataToBeSubmitted.label;
delete dataToBeSubmitted.advanced;
this.props.credentials[key] = dataToBeSubmitted;
this.props.onSubmit(dataToBeSubmitted, this.props.credentials);
}
onTypeChange(n){
this.setState({select: n});
}
render() {
const _marginTop = () => {
let size = 300;
const $screen = document.querySelector(".login-form");
if($screen) size = $screen.offsetHeight;
size = Math.round((document.body.offsetHeight - size) / 2);
if(size < 0) return 0;
if(size > 150) return 150;
return size;
};
return (
<Card style={{marginTop: _marginTop()+"px"}} className="no-select component_page_connection_form">
<NgIf cond={ window.CONFIG["connections"].length > 1 }>
<div role="navigation" className={"buttons "+((window.innerWidth < 600) ? "scroll-x" : "")}>
{
this.state.backends_enabled.map((backend, i) => {
const key = Object.keys(backend)[0];
if(!backend[key]) return null;
return (
<Button key={"menu-"+i} className={i === this.state.select ? "active primary" : ""} onClick={this.onTypeChange.bind(this, i)}>
{ backend[key].label.value }
</Button>
);
})
}
</div>
</NgIf>
<div>
<form onSubmit={this.onSubmit.bind(this)} autoComplete="off" autoCapitalize="off" spellCheck="false" autoCorrect="off">
{
this.state.backends_enabled.map((form, i) => {
const key = Object.keys(form)[0];
if(!form[key]) return null;
else if(this.state.select !== i) return null;
return (
<FormBuilder form={form[key]} onChange={this.rerender.bind(this)} key={"form"+i}
render={ ($input, props, struct, onChange) => {
if(struct.type === "image"){
return (
<div className="center">
{ $input }
</div>
);
} else if(struct.enabled === true){
return null;
} else if(struct.label === "advanced") return (
<label style={{color: "rgba(0,0,0,0.4)"}}>
{ $input }
{ t("Advanced") }
</label>
);
return (
<label htmlFor={props.params["id"]} className={"no-select input_type_" + props.params["type"]}>
<div>
{ $input }
</div>
</label>
);
}} />
);
})
}
<Button theme="emphasis">{ t("CONNECT") }</Button>
</form>
</div>
</Card>
);
}
}
size = Math.round((document.body.offsetHeight - size) / 2);
if (size < 0) return 0;
if (size > 150) return 150;
return size;
};

View File

@ -67,16 +67,6 @@
}
.component_rememberme.remember-appear{
opacity: 0;
transform: translateX(40px);
}
.component_rememberme.remember-appear.remember-appear-active{
opacity: 1;
transform: translateX(0px);
transition: all 0.3s ease-out;
transition-delay: 0.5s;
}
.scroll-x{
overflow-x: auto!important;