Standardize button with VoidButton

This commit is contained in:
Kieran 2022-03-14 22:57:05 +00:00
parent 3d8dba9eae
commit 20d32ad6d3
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
8 changed files with 39 additions and 50 deletions

View File

@ -4,6 +4,7 @@ import {PaywallServices} from "./Const";
import {useState} from "react"; import {useState} from "react";
import {LightningPaywall} from "./LightningPaywall"; import {LightningPaywall} from "./LightningPaywall";
import {useApi} from "./Api"; import {useApi} from "./Api";
import {VoidButton} from "./VoidButton";
export function FilePaywall(props) { export function FilePaywall(props) {
const {Api} = useApi(); const {Api} = useApi();
@ -14,15 +15,11 @@ export function FilePaywall(props) {
const [order, setOrder] = useState(); const [order, setOrder] = useState();
async function fetchOrder(e) { async function fetchOrder() {
if(e.target.classList.contains("disabled")) return;
e.target.classList.add("disabled");
let req = await Api.createOrder(file.id); let req = await Api.createOrder(file.id);
if (req.ok && req.status === 200) { if (req.ok && req.status === 200) {
setOrder(await req.json()); setOrder(await req.json());
} }
e.target.classList.remove("disabled");
} }
function reset() { function reset() {
@ -42,7 +39,7 @@ export function FilePaywall(props) {
<h3> <h3>
You must pay {FormatCurrency(pw.cost.amount, pw.cost.currency)} to view this file. You must pay {FormatCurrency(pw.cost.amount, pw.cost.currency)} to view this file.
</h3> </h3>
<div className="btn" onClick={fetchOrder}>Pay</div> <VoidButton onClick={fetchOrder}>Pay</VoidButton>
</div> </div>
); );
} else { } else {

View File

@ -1,14 +1,12 @@
import {Fragment, useEffect, useState} from "react"; import {Fragment} from "react";
import FeatherIcon from "feather-icons-react"; import FeatherIcon from "feather-icons-react";
import {FormatBytes} from "./Util"; import {FormatBytes} from "./Util";
import "./GlobalStats.css"; import "./GlobalStats.css";
import {useApi} from "./Api";
import moment from "moment"; import moment from "moment";
import {useSelector} from "react-redux"; import {useSelector} from "react-redux";
export function GlobalStats(props) { export function GlobalStats() {
const {Api} = useApi();
let stats = useSelector(state => state.info.stats); let stats = useSelector(state => state.info.stats);
return ( return (

View File

@ -3,8 +3,8 @@ import {useDispatch, useSelector} from "react-redux";
import {setAuth} from "./LoginState"; import {setAuth} from "./LoginState";
import {useApi} from "./Api"; import {useApi} from "./Api";
import "./Login.css"; import "./Login.css";
import {btnDisable, btnEnable} from "./Util";
import HCaptcha from "@hcaptcha/react-hcaptcha"; import HCaptcha from "@hcaptcha/react-hcaptcha";
import {VoidButton} from "./VoidButton";
export function Login() { export function Login() {
const {Api} = useApi(); const {Api} = useApi();
@ -15,8 +15,7 @@ export function Login() {
const captchaKey = useSelector(state => state.info.stats.captchaSiteKey); const captchaKey = useSelector(state => state.info.stats.captchaSiteKey);
const dispatch = useDispatch(); const dispatch = useDispatch();
async function login(e, fnLogin) { async function login(fnLogin) {
if(!btnDisable(e.target)) return;
setError(null); setError(null);
let req = await fnLogin(username, password, captchaResponse); let req = await fnLogin(username, password, captchaResponse);
@ -28,8 +27,6 @@ export function Login() {
setError(rsp.error); setError(rsp.error);
} }
} }
btnEnable(e.target);
} }
return ( return (
@ -42,8 +39,8 @@ export function Login() {
<dd><input type="password" onChange={(e) => setPassword(e.target.value)}/></dd> <dd><input type="password" onChange={(e) => setPassword(e.target.value)}/></dd>
</dl> </dl>
{captchaKey ? <HCaptcha sitekey={captchaKey} onVerify={setCaptchaResponse}/> : null} {captchaKey ? <HCaptcha sitekey={captchaKey} onVerify={setCaptchaResponse}/> : null}
<div className="btn" onClick={(e) => login(e, Api.login)}>Login</div> <VoidButton onClick={() => login(Api.login)}>Login</VoidButton>
<div className="btn" onClick={(e) => login(e, Api.register)}>Register</div> <VoidButton onClick={() => login(Api.register)}>Register</VoidButton>
{error ? <div className="error-msg">{error}</div> : null} {error ? <div className="error-msg">{error}</div> : null}
</div> </div>
); );

View File

@ -1,15 +1,13 @@
import FeatherIcon from "feather-icons-react"; import FeatherIcon from "feather-icons-react";
import {useState} from "react"; import {useState} from "react";
import {btnDisable, btnEnable} from "./Util"; import {VoidButton} from "./VoidButton";
export function NoPaywallConfig(props) { export function NoPaywallConfig(props) {
const [saveStatus, setSaveStatus] = useState(); const [saveStatus, setSaveStatus] = useState();
const privateFile = props.privateFile; const privateFile = props.privateFile;
const onSaveConfig = props.onSaveConfig; const onSaveConfig = props.onSaveConfig;
async function saveConfig(e) { async function saveConfig() {
if(!btnDisable(e.target)) return;
let cfg = { let cfg = {
editSecret: privateFile.metadata.editSecret editSecret: privateFile.metadata.editSecret
}; };
@ -17,12 +15,11 @@ export function NoPaywallConfig(props) {
if (typeof onSaveConfig === "function") { if (typeof onSaveConfig === "function") {
setSaveStatus(await onSaveConfig(cfg)); setSaveStatus(await onSaveConfig(cfg));
} }
btnEnable(e.target);
} }
return ( return (
<div> <div>
<div className="btn" onClick={saveConfig}>Save</div> <VoidButton onClick={saveConfig}>Save</VoidButton>
{saveStatus ? <FeatherIcon icon={saveStatus === true ? "check-circle" : "alert-circle"}/> : null} {saveStatus ? <FeatherIcon icon={saveStatus === true ? "check-circle" : "alert-circle"}/> : null}
</div> </div>
) )

View File

@ -6,10 +6,11 @@ import "./Profile.css";
import {useDispatch, useSelector} from "react-redux"; import {useDispatch, useSelector} from "react-redux";
import {logout, setProfile as setGlobalProfile} from "./LoginState"; import {logout, setProfile as setGlobalProfile} from "./LoginState";
import {DigestAlgo} from "./FileUpload"; import {DigestAlgo} from "./FileUpload";
import {btnDisable, btnEnable, buf2hex, hasFlag} from "./Util"; import {buf2hex, hasFlag} from "./Util";
import moment from "moment"; import moment from "moment";
import FeatherIcon from "feather-icons-react"; import FeatherIcon from "feather-icons-react";
import {FileList} from "./FileList"; import {FileList} from "./FileList";
import {VoidButton} from "./VoidButton";
export function Profile() { export function Profile() {
const [profile, setProfile] = useState(); const [profile, setProfile] = useState();
@ -93,8 +94,6 @@ export function Profile() {
} }
async function saveUser(e) { async function saveUser(e) {
if (!btnDisable(e.target)) return;
let r = await Api.updateUser({ let r = await Api.updateUser({
id: profile.id, id: profile.id,
avatar: profile.avatar, avatar: profile.avatar,
@ -106,19 +105,15 @@ export function Profile() {
dispatch(setGlobalProfile(profile)); dispatch(setGlobalProfile(profile));
setSaved(true); setSaved(true);
} }
btnEnable(e.target);
} }
async function submitCode(e) { async function submitCode(e) {
if (!btnDisable(e.target)) return;
let r = await Api.submitVerifyCode(profile.id, emailCode); let r = await Api.submitVerifyCode(profile.id, emailCode);
if (r.ok) { if (r.ok) {
await loadProfile(); await loadProfile();
} else { } else {
setEmailCodeError("Invalid or expired code."); setEmailCodeError("Invalid or expired code.");
} }
btnEnable(e.target);
} }
async function sendNewCode() { async function sendNewCode() {
@ -138,8 +133,8 @@ export function Profile() {
<br/> <br/>
<input type="text" placeholder="Verification code" value={emailCode} <input type="text" placeholder="Verification code" value={emailCode}
onChange={(e) => setEmailCode(e.target.value)}/> onChange={(e) => setEmailCode(e.target.value)}/>
<div className="btn" onClick={submitCode}>Submit</div> <VoidButton onClick={submitCode}>Submit</VoidButton>
<div className="btn" onClick={() => dispatch(logout())}>Logout</div> <VoidButton onClick={() => dispatch(logout())}>Logout</VoidButton>
<br/> <br/>
{emailCodeError ? <b>{emailCodeError}</b> : null} {emailCodeError ? <b>{emailCodeError}</b> : null}
{emailCodeError && !newCodeSent ? <a onClick={sendNewCode}>Send verfication email</a> : null} {emailCodeError && !newCodeSent ? <a onClick={sendNewCode}>Send verfication email</a> : null}
@ -165,13 +160,13 @@ export function Profile() {
</dl> </dl>
<div className="flex flex-center"> <div className="flex flex-center">
<div> <div>
<div className="btn" onClick={saveUser}>Save</div> <VoidButton onClick={saveUser}>Save</VoidButton>
</div> </div>
<div> <div>
{saved ? <FeatherIcon icon="check-circle"/> : null} {saved ? <FeatherIcon icon="check-circle"/> : null}
</div> </div>
<div> <div>
<div className="btn" onClick={() => dispatch(logout())}>Logout</div> <VoidButton onClick={() => dispatch(logout())}>Logout</VoidButton>
</div> </div>
</div> </div>
</Fragment> </Fragment>

View File

@ -1,7 +1,7 @@
import {useState} from "react"; import {useState} from "react";
import FeatherIcon from "feather-icons-react"; import FeatherIcon from "feather-icons-react";
import {PaywallCurrencies} from "./Const"; import {PaywallCurrencies} from "./Const";
import {btnDisable, btnEnable} from "./Util"; import {VoidButton} from "./VoidButton";
export function StrikePaywallConfig(props) { export function StrikePaywallConfig(props) {
const file = props.file; const file = props.file;
@ -16,8 +16,6 @@ export function StrikePaywallConfig(props) {
const [saveStatus, setSaveStatus] = useState(); const [saveStatus, setSaveStatus] = useState();
async function saveStrikeConfig(e) { async function saveStrikeConfig(e) {
if(!btnDisable(e.target)) return;
let cfg = { let cfg = {
editSecret, editSecret,
strike: { strike: {
@ -37,7 +35,6 @@ export function StrikePaywallConfig(props) {
setSaveStatus(false); setSaveStatus(false);
} }
} }
btnEnable(e.target);
} }
return ( return (
@ -57,7 +54,7 @@ export function StrikePaywallConfig(props) {
<dt>Price:</dt> <dt>Price:</dt>
<dd><input type="number" value={price} onChange={(e) => setPrice(parseFloat(e.target.value))}/></dd> <dd><input type="number" value={price} onChange={(e) => setPrice(parseFloat(e.target.value))}/></dd>
</dl> </dl>
<div className="btn" onClick={saveStrikeConfig}>Save</div> <VoidButton onClick={saveStrikeConfig}>Save</VoidButton>
{saveStatus ? <FeatherIcon icon="check-circle"/> : null} {saveStatus ? <FeatherIcon icon="check-circle"/> : null}
</div> </div>
); );

View File

@ -80,13 +80,3 @@ export function FormatCurrency(value, currency) {
export function hasFlag(value, flag) { export function hasFlag(value, flag) {
return (value & flag) === flag; return (value & flag) === flag;
} }
export function btnDisable(btn){
if(btn.classList.contains("disabled")) return false;
btn.classList.add("disabled");
return true;
}
export function btnEnable(btn){
btn.classList.remove("disabled");
}

View File

@ -0,0 +1,18 @@
export function VoidButton(props) {
async function handleClick(e) {
if (e.target.classList.contains("disabled")) return;
e.target.classList.add("disabled");
let fn = props.onClick;
if (typeof fn === "function") {
let ret = fn(e);
if (typeof ret === "object" && typeof ret.then === "function") {
await ret;
}
}
e.target.classList.remove("disabled");
}
return <div className="btn" onClick={handleClick}>{props.children}</div>;
}