mirror of
https://git.v0l.io/Kieran/void.cat.git
synced 2025-03-29 16:01:43 +01:00
Standardize button with VoidButton
This commit is contained in:
parent
3d8dba9eae
commit
20d32ad6d3
@ -4,6 +4,7 @@ import {PaywallServices} from "./Const";
|
||||
import {useState} from "react";
|
||||
import {LightningPaywall} from "./LightningPaywall";
|
||||
import {useApi} from "./Api";
|
||||
import {VoidButton} from "./VoidButton";
|
||||
|
||||
export function FilePaywall(props) {
|
||||
const {Api} = useApi();
|
||||
@ -14,15 +15,11 @@ export function FilePaywall(props) {
|
||||
|
||||
const [order, setOrder] = useState();
|
||||
|
||||
async function fetchOrder(e) {
|
||||
if(e.target.classList.contains("disabled")) return;
|
||||
e.target.classList.add("disabled");
|
||||
|
||||
async function fetchOrder() {
|
||||
let req = await Api.createOrder(file.id);
|
||||
if (req.ok && req.status === 200) {
|
||||
setOrder(await req.json());
|
||||
}
|
||||
e.target.classList.remove("disabled");
|
||||
}
|
||||
|
||||
function reset() {
|
||||
@ -42,7 +39,7 @@ export function FilePaywall(props) {
|
||||
<h3>
|
||||
You must pay {FormatCurrency(pw.cost.amount, pw.cost.currency)} to view this file.
|
||||
</h3>
|
||||
<div className="btn" onClick={fetchOrder}>Pay</div>
|
||||
<VoidButton onClick={fetchOrder}>Pay</VoidButton>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
|
@ -1,16 +1,14 @@
|
||||
import {Fragment, useEffect, useState} from "react";
|
||||
import {Fragment} from "react";
|
||||
import FeatherIcon from "feather-icons-react";
|
||||
import {FormatBytes} from "./Util";
|
||||
|
||||
import "./GlobalStats.css";
|
||||
import {useApi} from "./Api";
|
||||
import moment from "moment";
|
||||
import {useSelector} from "react-redux";
|
||||
|
||||
export function GlobalStats(props) {
|
||||
const {Api} = useApi();
|
||||
export function GlobalStats() {
|
||||
let stats = useSelector(state => state.info.stats);
|
||||
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<dl className="stats">
|
||||
|
@ -3,8 +3,8 @@ import {useDispatch, useSelector} from "react-redux";
|
||||
import {setAuth} from "./LoginState";
|
||||
import {useApi} from "./Api";
|
||||
import "./Login.css";
|
||||
import {btnDisable, btnEnable} from "./Util";
|
||||
import HCaptcha from "@hcaptcha/react-hcaptcha";
|
||||
import {VoidButton} from "./VoidButton";
|
||||
|
||||
export function Login() {
|
||||
const {Api} = useApi();
|
||||
@ -15,8 +15,7 @@ export function Login() {
|
||||
const captchaKey = useSelector(state => state.info.stats.captchaSiteKey);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
async function login(e, fnLogin) {
|
||||
if(!btnDisable(e.target)) return;
|
||||
async function login(fnLogin) {
|
||||
setError(null);
|
||||
|
||||
let req = await fnLogin(username, password, captchaResponse);
|
||||
@ -28,8 +27,6 @@ export function Login() {
|
||||
setError(rsp.error);
|
||||
}
|
||||
}
|
||||
|
||||
btnEnable(e.target);
|
||||
}
|
||||
|
||||
return (
|
||||
@ -42,8 +39,8 @@ export function Login() {
|
||||
<dd><input type="password" onChange={(e) => setPassword(e.target.value)}/></dd>
|
||||
</dl>
|
||||
{captchaKey ? <HCaptcha sitekey={captchaKey} onVerify={setCaptchaResponse}/> : null}
|
||||
<div className="btn" onClick={(e) => login(e, Api.login)}>Login</div>
|
||||
<div className="btn" onClick={(e) => login(e, Api.register)}>Register</div>
|
||||
<VoidButton onClick={() => login(Api.login)}>Login</VoidButton>
|
||||
<VoidButton onClick={() => login(Api.register)}>Register</VoidButton>
|
||||
{error ? <div className="error-msg">{error}</div> : null}
|
||||
</div>
|
||||
);
|
||||
|
@ -1,15 +1,13 @@
|
||||
import FeatherIcon from "feather-icons-react";
|
||||
import {useState} from "react";
|
||||
import {btnDisable, btnEnable} from "./Util";
|
||||
import {VoidButton} from "./VoidButton";
|
||||
|
||||
export function NoPaywallConfig(props) {
|
||||
const [saveStatus, setSaveStatus] = useState();
|
||||
const privateFile = props.privateFile;
|
||||
const onSaveConfig = props.onSaveConfig;
|
||||
|
||||
async function saveConfig(e) {
|
||||
if(!btnDisable(e.target)) return;
|
||||
|
||||
async function saveConfig() {
|
||||
let cfg = {
|
||||
editSecret: privateFile.metadata.editSecret
|
||||
};
|
||||
@ -17,12 +15,11 @@ export function NoPaywallConfig(props) {
|
||||
if (typeof onSaveConfig === "function") {
|
||||
setSaveStatus(await onSaveConfig(cfg));
|
||||
}
|
||||
btnEnable(e.target);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="btn" onClick={saveConfig}>Save</div>
|
||||
<VoidButton onClick={saveConfig}>Save</VoidButton>
|
||||
{saveStatus ? <FeatherIcon icon={saveStatus === true ? "check-circle" : "alert-circle"}/> : null}
|
||||
</div>
|
||||
)
|
||||
|
@ -6,10 +6,11 @@ import "./Profile.css";
|
||||
import {useDispatch, useSelector} from "react-redux";
|
||||
import {logout, setProfile as setGlobalProfile} from "./LoginState";
|
||||
import {DigestAlgo} from "./FileUpload";
|
||||
import {btnDisable, btnEnable, buf2hex, hasFlag} from "./Util";
|
||||
import {buf2hex, hasFlag} from "./Util";
|
||||
import moment from "moment";
|
||||
import FeatherIcon from "feather-icons-react";
|
||||
import {FileList} from "./FileList";
|
||||
import {VoidButton} from "./VoidButton";
|
||||
|
||||
export function Profile() {
|
||||
const [profile, setProfile] = useState();
|
||||
@ -93,8 +94,6 @@ export function Profile() {
|
||||
}
|
||||
|
||||
async function saveUser(e) {
|
||||
if (!btnDisable(e.target)) return;
|
||||
|
||||
let r = await Api.updateUser({
|
||||
id: profile.id,
|
||||
avatar: profile.avatar,
|
||||
@ -106,19 +105,15 @@ export function Profile() {
|
||||
dispatch(setGlobalProfile(profile));
|
||||
setSaved(true);
|
||||
}
|
||||
btnEnable(e.target);
|
||||
}
|
||||
|
||||
async function submitCode(e) {
|
||||
if (!btnDisable(e.target)) return;
|
||||
|
||||
let r = await Api.submitVerifyCode(profile.id, emailCode);
|
||||
if (r.ok) {
|
||||
await loadProfile();
|
||||
} else {
|
||||
setEmailCodeError("Invalid or expired code.");
|
||||
}
|
||||
btnEnable(e.target);
|
||||
}
|
||||
|
||||
async function sendNewCode() {
|
||||
@ -138,8 +133,8 @@ export function Profile() {
|
||||
<br/>
|
||||
<input type="text" placeholder="Verification code" value={emailCode}
|
||||
onChange={(e) => setEmailCode(e.target.value)}/>
|
||||
<div className="btn" onClick={submitCode}>Submit</div>
|
||||
<div className="btn" onClick={() => dispatch(logout())}>Logout</div>
|
||||
<VoidButton onClick={submitCode}>Submit</VoidButton>
|
||||
<VoidButton onClick={() => dispatch(logout())}>Logout</VoidButton>
|
||||
<br/>
|
||||
{emailCodeError ? <b>{emailCodeError}</b> : null}
|
||||
{emailCodeError && !newCodeSent ? <a onClick={sendNewCode}>Send verfication email</a> : null}
|
||||
@ -165,13 +160,13 @@ export function Profile() {
|
||||
</dl>
|
||||
<div className="flex flex-center">
|
||||
<div>
|
||||
<div className="btn" onClick={saveUser}>Save</div>
|
||||
<VoidButton onClick={saveUser}>Save</VoidButton>
|
||||
</div>
|
||||
<div>
|
||||
{saved ? <FeatherIcon icon="check-circle"/> : null}
|
||||
</div>
|
||||
<div>
|
||||
<div className="btn" onClick={() => dispatch(logout())}>Logout</div>
|
||||
<VoidButton onClick={() => dispatch(logout())}>Logout</VoidButton>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {useState} from "react";
|
||||
import FeatherIcon from "feather-icons-react";
|
||||
import {PaywallCurrencies} from "./Const";
|
||||
import {btnDisable, btnEnable} from "./Util";
|
||||
import {VoidButton} from "./VoidButton";
|
||||
|
||||
export function StrikePaywallConfig(props) {
|
||||
const file = props.file;
|
||||
@ -16,8 +16,6 @@ export function StrikePaywallConfig(props) {
|
||||
const [saveStatus, setSaveStatus] = useState();
|
||||
|
||||
async function saveStrikeConfig(e) {
|
||||
if(!btnDisable(e.target)) return;
|
||||
|
||||
let cfg = {
|
||||
editSecret,
|
||||
strike: {
|
||||
@ -37,7 +35,6 @@ export function StrikePaywallConfig(props) {
|
||||
setSaveStatus(false);
|
||||
}
|
||||
}
|
||||
btnEnable(e.target);
|
||||
}
|
||||
|
||||
return (
|
||||
@ -57,7 +54,7 @@ export function StrikePaywallConfig(props) {
|
||||
<dt>Price:</dt>
|
||||
<dd><input type="number" value={price} onChange={(e) => setPrice(parseFloat(e.target.value))}/></dd>
|
||||
</dl>
|
||||
<div className="btn" onClick={saveStrikeConfig}>Save</div>
|
||||
<VoidButton onClick={saveStrikeConfig}>Save</VoidButton>
|
||||
{saveStatus ? <FeatherIcon icon="check-circle"/> : null}
|
||||
</div>
|
||||
);
|
||||
|
@ -79,14 +79,4 @@ export function FormatCurrency(value, currency) {
|
||||
|
||||
export function hasFlag(value, 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");
|
||||
}
|
18
VoidCat/spa/src/VoidButton.js
Normal file
18
VoidCat/spa/src/VoidButton.js
Normal 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>;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user