mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-04-24 03:47:53 +00:00
register name dialog redesigned
This commit is contained in:
parent
c772e8cebe
commit
e02ac2d869
161
src/App.tsx
161
src/App.tsx
@ -149,6 +149,8 @@ import { useBlockedAddresses } from "./components/Group/useBlockUsers";
|
||||
import { WalletIcon } from "./assets/Icons/WalletIcon";
|
||||
import { DrawerUserLookup } from "./components/Drawer/DrawerUserLookup";
|
||||
import { UserLookup } from "./components/UserLookup.tsx/UserLookup";
|
||||
import { RegisterName } from "./components/RegisterName";
|
||||
import { BuyQortInformation } from "./components/BuyQortInformation";
|
||||
|
||||
type extStates =
|
||||
| "not-authenticated"
|
||||
@ -361,6 +363,7 @@ function App() {
|
||||
const [hasSettingsChanged, setHasSettingsChanged] = useRecoilState(
|
||||
hasSettingsChangedAtom
|
||||
);
|
||||
const balanceSetIntervalRef = useRef(null)
|
||||
const {downloadResource} = useFetchResources()
|
||||
const holdRefExtState = useRef<extStates>("not-authenticated");
|
||||
const isFocusedRef = useRef<boolean>(true);
|
||||
@ -396,10 +399,7 @@ function App() {
|
||||
message: messageQortalRequestExtension,
|
||||
} = useModal();
|
||||
|
||||
const [openRegisterName, setOpenRegisterName] = useState(false);
|
||||
const registerNamePopoverRef = useRef(null);
|
||||
const [isLoadingRegisterName, setIsLoadingRegisterName] = useState(false);
|
||||
const [registerNameValue, setRegisterNameValue] = useState("");
|
||||
|
||||
const [infoSnack, setInfoSnack] = useState(null);
|
||||
const [openSnack, setOpenSnack] = useState(false);
|
||||
const [hasLocalNode, setHasLocalNode] = useState(false);
|
||||
@ -702,6 +702,35 @@ function App() {
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
const balanceSetInterval = ()=> {
|
||||
try {
|
||||
if(balanceSetIntervalRef?.current){
|
||||
clearInterval(balanceSetIntervalRef?.current);
|
||||
}
|
||||
|
||||
let isCalling = false;
|
||||
balanceSetIntervalRef.current = setInterval(async () => {
|
||||
if (isCalling) return;
|
||||
isCalling = true;
|
||||
window
|
||||
.sendMessage("balance")
|
||||
.then((response) => {
|
||||
if (!response?.error && !isNaN(+response)) {
|
||||
setBalance(response);
|
||||
}
|
||||
isCalling = false;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Failed to get balance:", error);
|
||||
isCalling = false;
|
||||
});
|
||||
}, 40000);
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
const getBalanceFunc = () => {
|
||||
setQortBalanceLoading(true);
|
||||
window
|
||||
@ -710,11 +739,14 @@ function App() {
|
||||
if (!response?.error && !isNaN(+response)) {
|
||||
setBalance(response);
|
||||
}
|
||||
|
||||
setQortBalanceLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Failed to get balance:", error);
|
||||
setQortBalanceLoading(false);
|
||||
}).finally(()=> {
|
||||
balanceSetInterval()
|
||||
});
|
||||
};
|
||||
const getLtcBalanceFunc = () => {
|
||||
@ -1121,6 +1153,9 @@ function App() {
|
||||
setTxList([]);
|
||||
setMemberGroups([]);
|
||||
resetAllRecoil();
|
||||
if(balanceSetIntervalRef?.current){
|
||||
clearInterval(balanceSetIntervalRef?.current);
|
||||
}
|
||||
};
|
||||
|
||||
function roundUpToDecimals(number, decimals = 8) {
|
||||
@ -1275,72 +1310,7 @@ function App() {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const registerName = async () => {
|
||||
try {
|
||||
if (!userInfo?.address) throw new Error("Your address was not found");
|
||||
if(!registerNameValue) throw new Error('Enter a name')
|
||||
const fee = await getFee("REGISTER_NAME");
|
||||
await show({
|
||||
message: "Would you like to register this name?",
|
||||
publishFee: fee.fee + " QORT",
|
||||
});
|
||||
setIsLoadingRegisterName(true);
|
||||
new Promise((res, rej) => {
|
||||
window
|
||||
.sendMessage("registerName", {
|
||||
name: registerNameValue,
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response?.error) {
|
||||
res(response);
|
||||
setIsLoadingRegisterName(false);
|
||||
setInfoSnack({
|
||||
type: "success",
|
||||
message:
|
||||
"Successfully registered. It may take a couple of minutes for the changes to propagate",
|
||||
});
|
||||
setOpenRegisterName(false);
|
||||
setRegisterNameValue("");
|
||||
setOpenSnack(true);
|
||||
setTxList((prev) => [
|
||||
{
|
||||
...response,
|
||||
type: "register-name",
|
||||
label: `Registered name: awaiting confirmation. This may take a couple minutes.`,
|
||||
labelDone: `Registered name: success!`,
|
||||
done: false,
|
||||
},
|
||||
...prev.filter((item) => !item.done),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
setInfoSnack({
|
||||
type: "error",
|
||||
message: response?.error,
|
||||
});
|
||||
setOpenSnack(true);
|
||||
rej(response.error);
|
||||
})
|
||||
.catch((error) => {
|
||||
setInfoSnack({
|
||||
type: "error",
|
||||
message: error.message || "An error occurred",
|
||||
});
|
||||
setOpenSnack(true);
|
||||
rej(error);
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
if (error?.message) {
|
||||
setInfoSnack({
|
||||
type: "error",
|
||||
message: error?.message,
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
setIsLoadingRegisterName(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const renderProfileLeft = ()=> {
|
||||
|
||||
@ -1527,7 +1497,6 @@ function App() {
|
||||
<Spacer height="35px" />
|
||||
{userInfo && !userInfo?.name && (
|
||||
<TextP
|
||||
ref={registerNamePopoverRef}
|
||||
sx={{
|
||||
textAlign: "center",
|
||||
lineHeight: 1.2,
|
||||
@ -1539,7 +1508,7 @@ function App() {
|
||||
textDecoration: "underline",
|
||||
}}
|
||||
onClick={() => {
|
||||
setOpenRegisterName(true);
|
||||
executeEvent('openRegisterName', {})
|
||||
}}
|
||||
>
|
||||
REGISTER NAME
|
||||
@ -3616,52 +3585,6 @@ function App() {
|
||||
</Box>
|
||||
</Dialog>
|
||||
)}
|
||||
<Popover
|
||||
open={openRegisterName}
|
||||
anchorEl={registerNamePopoverRef.current}
|
||||
onClose={() => {
|
||||
setOpenRegisterName(false);
|
||||
setRegisterNameValue("");
|
||||
}}
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "center",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
}}
|
||||
style={{ marginTop: "8px" }}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "325px",
|
||||
height: "250px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
gap: "10px",
|
||||
padding: "10px",
|
||||
}}
|
||||
>
|
||||
<Label>Choose a name</Label>
|
||||
<Input
|
||||
onChange={(e) => setRegisterNameValue(e.target.value)}
|
||||
value={registerNameValue}
|
||||
placeholder="Choose a name"
|
||||
/>
|
||||
<Spacer height="25px" />
|
||||
<LoadingButton
|
||||
loading={isLoadingRegisterName}
|
||||
loadingPosition="start"
|
||||
variant="contained"
|
||||
disabled={!registerNameValue}
|
||||
onClick={registerName}
|
||||
>
|
||||
Register Name
|
||||
</LoadingButton>
|
||||
</Box>
|
||||
</Popover>
|
||||
{isSettingsOpen && (
|
||||
<Settings open={isSettingsOpen} setOpen={setIsSettingsOpen} />
|
||||
)}
|
||||
@ -3678,6 +3601,8 @@ function App() {
|
||||
{renderProfileLeft()}
|
||||
</DrawerComponent>
|
||||
<UserLookup isOpenDrawerLookup={isOpenDrawerLookup} setIsOpenDrawerLookup={setIsOpenDrawerLookup} />
|
||||
<RegisterName balance={balance} show={show} setTxList={setTxList} userInfo={userInfo} setOpenSnack={setOpenSnack} setInfoSnack={setInfoSnack}/>
|
||||
<BuyQortInformation balance={balance} />
|
||||
</GlobalContext.Provider>
|
||||
{extState === "create-wallet" && walletToBeDownloaded && (
|
||||
<ButtonBase onClick={()=> {
|
||||
|
154
src/components/BuyQortInformation.tsx
Normal file
154
src/components/BuyQortInformation.tsx
Normal file
@ -0,0 +1,154 @@
|
||||
import React, { useCallback, useContext, useEffect, useState } from 'react'
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
ButtonBase,
|
||||
Collapse,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
Input,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
List,
|
||||
MenuItem,
|
||||
Popover,
|
||||
Select,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { Label } from './Group/AddGroup';
|
||||
import { Spacer } from '../common/Spacer';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { getBaseApiReact, MyContext } from '../App';
|
||||
import { getFee } from '../background';
|
||||
import qTradeLogo from "../assets/Icons/q-trade-logo.webp";
|
||||
|
||||
import RadioButtonCheckedIcon from '@mui/icons-material/RadioButtonChecked';
|
||||
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from '../utils/events';
|
||||
import { BarSpinner } from '../common/Spinners/BarSpinner/BarSpinner';
|
||||
|
||||
|
||||
|
||||
export const BuyQortInformation = ({balance}) => {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
|
||||
const openBuyQortInfoFunc = useCallback((e) => {
|
||||
setIsOpen(true)
|
||||
|
||||
}, [ setIsOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
subscribeToEvent("openBuyQortInfo", openBuyQortInfoFunc);
|
||||
|
||||
return () => {
|
||||
unsubscribeFromEvent("openBuyQortInfo", openBuyQortInfoFunc);
|
||||
};
|
||||
}, [openBuyQortInfoFunc]);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isOpen}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
{"Get QORT"}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Box
|
||||
sx={{
|
||||
width: "400px",
|
||||
maxWidth: '90vw',
|
||||
height: "400px",
|
||||
maxHeight: '90vh',
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
gap: "10px",
|
||||
padding: "10px",
|
||||
}}
|
||||
>
|
||||
<Typography>Get QORT using Qortal's crosschain trade portal</Typography>
|
||||
<ButtonBase
|
||||
sx={{
|
||||
"&:hover": { backgroundColor: "secondary.main" },
|
||||
transition: "all 0.1s ease-in-out",
|
||||
padding: "5px",
|
||||
borderRadius: "5px",
|
||||
gap: "5px",
|
||||
}}
|
||||
onClick={async () => {
|
||||
executeEvent("addTab", {
|
||||
data: { service: "APP", name: "q-trade" },
|
||||
});
|
||||
executeEvent("open-apps-mode", {});
|
||||
setIsOpen(false)
|
||||
}}
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
borderRadius: "50%",
|
||||
height: '30px'
|
||||
}}
|
||||
src={qTradeLogo}
|
||||
/>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "1rem",
|
||||
}}
|
||||
>
|
||||
Trade QORT
|
||||
</Typography>
|
||||
</ButtonBase>
|
||||
<Spacer height='40px' />
|
||||
<Typography sx={{
|
||||
textDecoration: 'underline'
|
||||
}}>Benefits of having QORT</Typography>
|
||||
<List
|
||||
sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}
|
||||
aria-label="contacts"
|
||||
>
|
||||
<ListItem disablePadding>
|
||||
|
||||
<ListItemIcon>
|
||||
<RadioButtonCheckedIcon sx={{
|
||||
color: 'white'
|
||||
}} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Create transactions on the Qortal Blockchain" />
|
||||
|
||||
</ListItem>
|
||||
<ListItem disablePadding>
|
||||
|
||||
<ListItemIcon>
|
||||
<RadioButtonCheckedIcon sx={{
|
||||
color: 'white'
|
||||
}} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Having at least 4 QORT in your balance allows you to send chat messages at near instant speed." />
|
||||
|
||||
</ListItem>
|
||||
</List>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
setIsOpen(false)
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
@ -2528,6 +2528,7 @@ export const Group = ({
|
||||
|
||||
|
||||
<HomeDesktop
|
||||
name={userInfo?.name}
|
||||
refreshHomeDataFunc={refreshHomeDataFunc}
|
||||
myAddress={myAddress}
|
||||
isLoadingGroups={isLoadingGroups}
|
||||
|
@ -14,6 +14,7 @@ import { NewUsersCTA } from "../Home/NewUsersCTA";
|
||||
export const HomeDesktop = ({
|
||||
refreshHomeDataFunc,
|
||||
myAddress,
|
||||
name,
|
||||
isLoadingGroups,
|
||||
balance,
|
||||
userInfo,
|
||||
@ -27,6 +28,31 @@ export const HomeDesktop = ({
|
||||
setDesktopViewMode,
|
||||
desktopViewMode,
|
||||
}) => {
|
||||
const [checked1, setChecked1] = React.useState(false);
|
||||
const [checked2, setChecked2] = React.useState(false);
|
||||
React.useEffect(() => {
|
||||
if (balance && +balance >= 6) {
|
||||
setChecked1(true);
|
||||
}
|
||||
}, [balance]);
|
||||
|
||||
|
||||
React.useEffect(() => {
|
||||
if (name) setChecked2(true);
|
||||
}, [name]);
|
||||
|
||||
|
||||
const isLoaded = React.useMemo(()=> {
|
||||
if(userInfo !== null) return true
|
||||
return false
|
||||
}, [ userInfo])
|
||||
|
||||
const hasDoneNameAndBalanceAndIsLoaded = React.useMemo(()=> {
|
||||
if(isLoaded && checked1 && checked2) return true
|
||||
return false
|
||||
}, [checked1, isLoaded, checked2])
|
||||
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
@ -114,7 +140,9 @@ export const HomeDesktop = ({
|
||||
}}>
|
||||
<ListOfThreadPostsWatched />
|
||||
</Box> */}
|
||||
<Box
|
||||
{hasDoneNameAndBalanceAndIsLoaded && (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
width: "330px",
|
||||
display: "flex",
|
||||
@ -150,6 +178,9 @@ export const HomeDesktop = ({
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
<QortPrice />
|
||||
</Box>
|
||||
@ -185,6 +216,9 @@ export const HomeDesktop = ({
|
||||
</Typography>{" "}
|
||||
</Box>
|
||||
</Divider>
|
||||
{!hasDoneNameAndBalanceAndIsLoaded && (
|
||||
<Spacer height="40px" />
|
||||
)}
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
@ -194,9 +228,14 @@ export const HomeDesktop = ({
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<ListOfGroupPromotions />
|
||||
{hasDoneNameAndBalanceAndIsLoaded && (
|
||||
<ListOfGroupPromotions />
|
||||
|
||||
)}
|
||||
|
||||
<Explore setDesktopViewMode={setDesktopViewMode} />
|
||||
</Box>
|
||||
|
||||
<NewUsersCTA balance={balance} />
|
||||
</>
|
||||
|
||||
|
@ -12,27 +12,17 @@ import { Box, Typography } from "@mui/material";
|
||||
import { Spacer } from "../../common/Spacer";
|
||||
import { isMobile } from "../../App";
|
||||
import { QMailMessages } from "./QMailMessages";
|
||||
import { executeEvent } from "../../utils/events";
|
||||
|
||||
export const ThingsToDoInitial = ({ myAddress, name, hasGroups, balance, userInfo }) => {
|
||||
const [checked1, setChecked1] = React.useState(false);
|
||||
const [checked2, setChecked2] = React.useState(false);
|
||||
const [checked3, setChecked3] = React.useState(false);
|
||||
// const [checked3, setChecked3] = React.useState(false);
|
||||
|
||||
// const getAddressInfo = async (address) => {
|
||||
// const response = await fetch(getBaseApiReact() + "/addresses/" + address);
|
||||
// const data = await response.json();
|
||||
// if (data.error && data.error === 124) {
|
||||
// setChecked1(false);
|
||||
// } else if (data.address) {
|
||||
// setChecked1(true);
|
||||
// }
|
||||
// };
|
||||
// React.useEffect(() => {
|
||||
// if (hasGroups) setChecked3(true);
|
||||
// }, [hasGroups]);
|
||||
|
||||
// const checkInfo = async () => {
|
||||
// try {
|
||||
// getAddressInfo(myAddress);
|
||||
// } catch (error) {}
|
||||
// };
|
||||
|
||||
React.useEffect(() => {
|
||||
if (balance && +balance >= 6) {
|
||||
@ -40,9 +30,6 @@ export const ThingsToDoInitial = ({ myAddress, name, hasGroups, balance, userInf
|
||||
}
|
||||
}, [balance]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (hasGroups) setChecked3(true);
|
||||
}, [hasGroups]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (name) setChecked2(true);
|
||||
@ -120,11 +107,14 @@ if(!isLoaded) return null
|
||||
disableRipple
|
||||
role={undefined}
|
||||
dense
|
||||
onClick={()=> {
|
||||
executeEvent("openBuyQortInfo", {})
|
||||
}}
|
||||
>
|
||||
<ListItemText
|
||||
sx={{
|
||||
"& .MuiTypography-root": {
|
||||
fontSize: "13px",
|
||||
fontSize: "1rem",
|
||||
fontWeight: 400,
|
||||
},
|
||||
}}
|
||||
@ -181,9 +171,11 @@ if(!isLoaded) return null
|
||||
padding: "0px",
|
||||
}} disableRipple role={undefined} dense>
|
||||
|
||||
<ListItemText sx={{
|
||||
<ListItemText onClick={() => {
|
||||
executeEvent('openRegisterName', {})
|
||||
}} sx={{
|
||||
"& .MuiTypography-root": {
|
||||
fontSize: "13px",
|
||||
fontSize: "1rem",
|
||||
fontWeight: 400,
|
||||
},
|
||||
}} primary={`Register a name`} />
|
||||
@ -202,16 +194,7 @@ if(!isLoaded) return null
|
||||
</ListItemIcon>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<ListItem
|
||||
// secondaryAction={
|
||||
// <IconButton edge="end" aria-label="comments">
|
||||
// <InfoIcon
|
||||
// sx={{
|
||||
// color: "white",
|
||||
// }}
|
||||
// />
|
||||
// </IconButton>
|
||||
// }
|
||||
{/* <ListItem
|
||||
disablePadding
|
||||
>
|
||||
<ListItemButton sx={{
|
||||
@ -238,7 +221,7 @@ if(!isLoaded) return null
|
||||
/>
|
||||
</ListItemIcon>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</ListItem> */}
|
||||
</List>
|
||||
)}
|
||||
|
||||
|
312
src/components/RegisterName.tsx
Normal file
312
src/components/RegisterName.tsx
Normal file
@ -0,0 +1,312 @@
|
||||
import React, { useCallback, useContext, useEffect, useState } from 'react'
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
ButtonBase,
|
||||
Collapse,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
Input,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
List,
|
||||
MenuItem,
|
||||
Popover,
|
||||
Select,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { Label } from './Group/AddGroup';
|
||||
import { Spacer } from '../common/Spacer';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { getBaseApiReact, MyContext } from '../App';
|
||||
import { getFee } from '../background';
|
||||
import RadioButtonCheckedIcon from '@mui/icons-material/RadioButtonChecked';
|
||||
import { subscribeToEvent, unsubscribeFromEvent } from '../utils/events';
|
||||
import { BarSpinner } from '../common/Spinners/BarSpinner/BarSpinner';
|
||||
import CheckIcon from '@mui/icons-material/Check';
|
||||
import ErrorIcon from '@mui/icons-material/Error';
|
||||
|
||||
enum Availability {
|
||||
NULL = 'null',
|
||||
LOADING = 'loading',
|
||||
AVAILABLE = 'available',
|
||||
NOT_AVAILABLE = 'not-available'
|
||||
}
|
||||
export const RegisterName = ({setOpenSnack, setInfoSnack, userInfo, show, setTxList, balance}) => {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [registerNameValue, setRegisterNameValue] = useState('')
|
||||
const [isLoadingRegisterName, setIsLoadingRegisterName] = useState(false)
|
||||
const [isNameAvailable, setIsNameAvailable] = useState<Availability>(Availability.NULL)
|
||||
const [nameFee, setNameFee] = useState(null)
|
||||
|
||||
const checkIfNameExisits = async (name)=> {
|
||||
if(!name?.trim()){
|
||||
setIsNameAvailable(Availability.NULL)
|
||||
|
||||
return
|
||||
}
|
||||
setIsNameAvailable(Availability.LOADING)
|
||||
try {
|
||||
const res = await fetch(`${getBaseApiReact()}/names/` + name);
|
||||
const data = await res.json()
|
||||
if(data?.message === 'name unknown'){
|
||||
setIsNameAvailable(Availability.AVAILABLE)
|
||||
} else {
|
||||
setIsNameAvailable(Availability.NOT_AVAILABLE)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
// Debounce logic
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => {
|
||||
checkIfNameExisits(registerNameValue);
|
||||
}, 500);
|
||||
|
||||
// Cleanup timeout if searchValue changes before the timeout completes
|
||||
return () => {
|
||||
clearTimeout(handler);
|
||||
};
|
||||
}, [registerNameValue]);
|
||||
|
||||
const openRegisterNameFunc = useCallback((e) => {
|
||||
setIsOpen(true)
|
||||
|
||||
}, [ setIsOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
subscribeToEvent("openRegisterName", openRegisterNameFunc);
|
||||
|
||||
return () => {
|
||||
unsubscribeFromEvent("openRegisterName", openRegisterNameFunc);
|
||||
};
|
||||
}, [openRegisterNameFunc]);
|
||||
|
||||
useEffect(()=> {
|
||||
const nameRegistrationFee = async ()=> {
|
||||
try {
|
||||
const fee = await getFee("REGISTER_NAME");
|
||||
setNameFee(fee?.fee)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
nameRegistrationFee()
|
||||
}, [])
|
||||
|
||||
const registerName = async () => {
|
||||
try {
|
||||
if (!userInfo?.address) throw new Error("Your address was not found");
|
||||
if(!registerNameValue) throw new Error('Enter a name')
|
||||
|
||||
const fee = await getFee("REGISTER_NAME");
|
||||
await show({
|
||||
message: "Would you like to register this name?",
|
||||
publishFee: fee.fee + " QORT",
|
||||
});
|
||||
setIsLoadingRegisterName(true);
|
||||
new Promise((res, rej) => {
|
||||
window
|
||||
.sendMessage("registerName", {
|
||||
name: registerNameValue,
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response?.error) {
|
||||
res(response);
|
||||
setIsLoadingRegisterName(false);
|
||||
setInfoSnack({
|
||||
type: "success",
|
||||
message:
|
||||
"Successfully registered. It may take a couple of minutes for the changes to propagate",
|
||||
});
|
||||
setIsOpen(false);
|
||||
setRegisterNameValue("");
|
||||
setOpenSnack(true);
|
||||
setTxList((prev) => [
|
||||
{
|
||||
...response,
|
||||
type: "register-name",
|
||||
label: `Registered name: awaiting confirmation. This may take a couple minutes.`,
|
||||
labelDone: `Registered name: success!`,
|
||||
done: false,
|
||||
},
|
||||
...prev.filter((item) => !item.done),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
setInfoSnack({
|
||||
type: "error",
|
||||
message: response?.error,
|
||||
});
|
||||
setOpenSnack(true);
|
||||
rej(response.error);
|
||||
})
|
||||
.catch((error) => {
|
||||
setInfoSnack({
|
||||
type: "error",
|
||||
message: error.message || "An error occurred",
|
||||
});
|
||||
setOpenSnack(true);
|
||||
rej(error);
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
if (error?.message) {
|
||||
setOpenSnack(true)
|
||||
setInfoSnack({
|
||||
type: "error",
|
||||
message: error?.message,
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
setIsLoadingRegisterName(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isOpen}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
{"Register name"}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Box
|
||||
sx={{
|
||||
width: "400px",
|
||||
maxWidth: '90vw',
|
||||
height: "500px",
|
||||
maxHeight: '90vh',
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
gap: "10px",
|
||||
padding: "10px",
|
||||
}}
|
||||
>
|
||||
<Label>Choose a name</Label>
|
||||
<TextField
|
||||
autoComplete='off'
|
||||
autoFocus
|
||||
onChange={(e) => setRegisterNameValue(e.target.value)}
|
||||
value={registerNameValue}
|
||||
placeholder="Choose a name"
|
||||
/>
|
||||
{(!balance || (nameFee && balance && balance < nameFee))&& (
|
||||
<>
|
||||
<Spacer height="10px" />
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
gap: '5px',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
<ErrorIcon sx={{
|
||||
color: 'white'
|
||||
}} />
|
||||
<Typography>Your balance is {balance ?? 0} QORT. A name registration requires a {nameFee} QORT fee</Typography>
|
||||
</Box>
|
||||
<Spacer height="10px" />
|
||||
|
||||
</>
|
||||
)}
|
||||
<Spacer height="5px" />
|
||||
{isNameAvailable === Availability.AVAILABLE && (
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
gap: '5px',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
<CheckIcon sx={{
|
||||
color: 'white'
|
||||
}} />
|
||||
<Typography>{registerNameValue} is available</Typography>
|
||||
</Box>
|
||||
)}
|
||||
{isNameAvailable === Availability.NOT_AVAILABLE && (
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
gap: '5px',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
<ErrorIcon sx={{
|
||||
color: 'white'
|
||||
}} />
|
||||
<Typography>{registerNameValue} is unavailable</Typography>
|
||||
</Box>
|
||||
)}
|
||||
{isNameAvailable === Availability.LOADING && (
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
gap: '5px',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
<BarSpinner width="16px" color="white" />
|
||||
<Typography>Checking if name already existis</Typography>
|
||||
</Box>
|
||||
)}
|
||||
<Spacer height="25px" />
|
||||
<Typography sx={{
|
||||
textDecoration: 'underline'
|
||||
}}>Benefits of a name</Typography>
|
||||
<List
|
||||
sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}
|
||||
aria-label="contacts"
|
||||
>
|
||||
<ListItem disablePadding>
|
||||
|
||||
<ListItemIcon>
|
||||
<RadioButtonCheckedIcon sx={{
|
||||
color: 'white'
|
||||
}} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Publish data to Qortal: anything from apps to videos. Fully decentralized!" />
|
||||
|
||||
</ListItem>
|
||||
<ListItem disablePadding>
|
||||
|
||||
<ListItemIcon>
|
||||
<RadioButtonCheckedIcon sx={{
|
||||
color: 'white'
|
||||
}} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Secure ownership of data published by your name. You can even sell your name, along with your data to a third party." />
|
||||
|
||||
</ListItem>
|
||||
</List>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
disabled={isLoadingRegisterName}
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
setIsOpen(false)
|
||||
setRegisterNameValue('')
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
<Button
|
||||
disabled={!registerNameValue.trim() ||isLoadingRegisterName || isNameAvailable !== Availability.AVAILABLE || !balance || ((balance && nameFee) && +balance < +nameFee)}
|
||||
variant="contained"
|
||||
onClick={registerName}
|
||||
autoFocus
|
||||
>
|
||||
Register Name
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
@ -24,6 +24,10 @@ const theme = createTheme({
|
||||
secondary: '#b0b0b0', // Light gray for secondary text
|
||||
disabled: '#808080', // Gray for disabled text
|
||||
},
|
||||
action: {
|
||||
// disabledBackground: 'set color of background here',
|
||||
disabled: 'rgb(255 255 255 / 70%)'
|
||||
}
|
||||
},
|
||||
typography: {
|
||||
fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif', // Font family
|
||||
|
Loading…
x
Reference in New Issue
Block a user