mirror of
https://github.com/uqbar-dao/nectar.git
synced 2024-11-26 11:53:31 +03:00
fixes to name entry, error handling, visuals
This commit is contained in:
parent
3ba1a2e53d
commit
c9f0566955
@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import isValidDomain from "is-valid-domain";
|
||||
import { toAscii } from "idna-uts46-hx";
|
||||
import { usePublicClient } from 'wagmi'
|
||||
@ -14,33 +14,38 @@ export const NAME_NOT_OWNER = "Name already exists and does not belong to this w
|
||||
export const NAME_NOT_REGISTERED = "Name is not registered";
|
||||
|
||||
type ClaimOsNameProps = {
|
||||
address?: `0x${string}`;
|
||||
name: string;
|
||||
setName: React.Dispatch<React.SetStateAction<string>>;
|
||||
nameValidities: string[];
|
||||
setNameValidities: React.Dispatch<React.SetStateAction<string[]>>;
|
||||
triggerNameCheck: boolean;
|
||||
setTba?: React.Dispatch<React.SetStateAction<string>>;
|
||||
isReset?: boolean;
|
||||
};
|
||||
|
||||
function EnterKnsName({
|
||||
address,
|
||||
name,
|
||||
setName,
|
||||
nameValidities,
|
||||
setNameValidities,
|
||||
triggerNameCheck,
|
||||
setTba,
|
||||
isReset = false,
|
||||
}: ClaimOsNameProps) {
|
||||
const client = usePublicClient();
|
||||
const debouncer = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isReset) return;
|
||||
const [isPunyfied, setIsPunyfied] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (debouncer.current) clearTimeout(debouncer.current);
|
||||
|
||||
debouncer.current = setTimeout(async () => {
|
||||
let index: number;
|
||||
let validities = [...nameValidities];
|
||||
let validities: string[] = [];
|
||||
setIsPunyfied('');
|
||||
|
||||
const len = [...name].length;
|
||||
index = validities.indexOf(NAME_LENGTH);
|
||||
@ -57,6 +62,8 @@ function EnterKnsName({
|
||||
if (index === -1) validities.push(NAME_INVALID_PUNY);
|
||||
}
|
||||
|
||||
if (normalized !== (name + ".os")) setIsPunyfied(normalized);
|
||||
|
||||
// only check if name is valid punycode
|
||||
if (normalized && normalized !== '.os') {
|
||||
index = validities.indexOf(NAME_URL);
|
||||
@ -66,6 +73,7 @@ function EnterKnsName({
|
||||
|
||||
index = validities.indexOf(NAME_CLAIMED);
|
||||
|
||||
// only check if name is valid and long enough
|
||||
if (validities.length === 0 || index !== -1 && normalized.length > 2) {
|
||||
try {
|
||||
const namehash = kinohash(normalized)
|
||||
@ -78,34 +86,44 @@ function EnterKnsName({
|
||||
args: [namehash]
|
||||
})
|
||||
|
||||
const tba = data?.[0];
|
||||
if (tba !== undefined) {
|
||||
setTba ? (setTba(tba)) : null;
|
||||
} else {
|
||||
validities.push(NAME_NOT_REGISTERED);
|
||||
}
|
||||
|
||||
const owner = data?.[1];
|
||||
const owner_is_zero = owner === "0x0000000000000000000000000000000000000000";
|
||||
|
||||
if (!owner_is_zero && index === -1) validities.push(NAME_CLAIMED);
|
||||
if (!owner_is_zero && !isReset) validities.push(NAME_CLAIMED);
|
||||
|
||||
if (!owner_is_zero && isReset && address && owner !== address) validities.push(NAME_NOT_OWNER);
|
||||
|
||||
if (isReset && owner_is_zero) validities.push(NAME_NOT_REGISTERED);
|
||||
} catch (e) {
|
||||
console.error({ e })
|
||||
if (index !== -1) validities.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setNameValidities(validities);
|
||||
}, 100);
|
||||
}, 500);
|
||||
}, [name, triggerNameCheck, isReset]);
|
||||
|
||||
const noDots = (e: any) =>
|
||||
e.target.value.indexOf(".") === -1 && setName(e.target.value);
|
||||
const noDotsOrSpaces = (e: any) =>
|
||||
e.target.value.indexOf(".") === -1 && e.target.value.indexOf(" ") === -1 && setName(e.target.value);
|
||||
|
||||
return (
|
||||
<div className="enter-kns-name">
|
||||
<div className="input-wrapper">
|
||||
<input
|
||||
value={name}
|
||||
onChange={noDots}
|
||||
onChange={noDotsOrSpaces}
|
||||
type="text"
|
||||
required
|
||||
name="dot-os-name"
|
||||
placeholder="e.g. myname"
|
||||
placeholder="mynode123"
|
||||
className="kns-input"
|
||||
/>
|
||||
<span className="kns-suffix">.os</span>
|
||||
@ -113,6 +131,7 @@ function EnterKnsName({
|
||||
{nameValidities.map((x, i) => (
|
||||
<p key={i} className="error-message">{x}</p>
|
||||
))}
|
||||
{isPunyfied !== '' && <p className="puny-warning">special characters will be converted to punycode: {isPunyfied}</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -135,7 +135,7 @@
|
||||
|
||||
.kns-suffix {
|
||||
padding: 0.5rem;
|
||||
background-color: var(--gray);
|
||||
background-color: var(--blue);
|
||||
border: 1px solid var(--tasteful-dark);
|
||||
border-left: none;
|
||||
border-radius: 0 4px 4px 0;
|
||||
@ -240,7 +240,6 @@
|
||||
color: var(--off-white);
|
||||
}
|
||||
|
||||
button.clear {
|
||||
button.secondary {
|
||||
width: 100%;
|
||||
background-color: var(--ansi-red);
|
||||
}
|
@ -51,7 +51,7 @@ function CommitDotOsName({
|
||||
|
||||
useEffect(() => setTriggerNameCheck(!triggerNameCheck), [address])
|
||||
|
||||
const enterOsNameProps = { name, setName, nameValidities, setNameValidities, triggerNameCheck }
|
||||
const enterOsNameProps = { address, name, setName, nameValidities, setNameValidities, triggerNameCheck }
|
||||
|
||||
useEffect(() => {
|
||||
if (!address) {
|
||||
@ -102,7 +102,7 @@ function CommitDotOsName({
|
||||
<>
|
||||
<h3 className="form-label">
|
||||
<Tooltip text="Kinodes need an onchain node identity in order to communicate with other nodes in the network.">
|
||||
Choose a name for your Kinode
|
||||
Choose a name for your computer
|
||||
</Tooltip>
|
||||
</h3>
|
||||
<EnterKnsName {...enterOsNameProps} />
|
||||
|
@ -119,7 +119,7 @@ function Login({
|
||||
|
||||
<div className="additional-options">
|
||||
<button
|
||||
className="clear"
|
||||
className="secondary"
|
||||
onClick={() => navigate('/reset')}
|
||||
>
|
||||
Reset Node & Networking Info
|
||||
|
@ -2,24 +2,18 @@ import {
|
||||
FormEvent,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { toAscii } from "idna-uts46-hx";
|
||||
import isValidDomain from "is-valid-domain";
|
||||
import Loader from "../components/Loader";
|
||||
import { PageProps } from "../lib/types";
|
||||
import { KINOMAP, MULTICALL, generateNetworkingKeys, kinomapAbi, mechAbi } from "../abis";
|
||||
import { MULTICALL, generateNetworkingKeys, mechAbi } from "../abis";
|
||||
import { Tooltip } from "../components/Tooltip";
|
||||
import DirectCheckbox from "../components/DirectCheckbox";
|
||||
import EnterKnsName from "../components/EnterKnsName";
|
||||
|
||||
import { useAccount, usePublicClient, useWaitForTransactionReceipt, useWriteContract } from "wagmi";
|
||||
import { useAccount, useWaitForTransactionReceipt, useWriteContract } from "wagmi";
|
||||
import { useConnectModal, useAddRecentTransaction } from "@rainbow-me/rainbowkit";
|
||||
import { kinohash } from "../utils/kinohash";
|
||||
|
||||
import { NAME_URL, NAME_INVALID_PUNY, NAME_NOT_OWNER, NAME_NOT_REGISTERED } from "../components/EnterKnsName";
|
||||
|
||||
interface ResetProps extends PageProps { }
|
||||
|
||||
@ -28,7 +22,6 @@ function ResetKnsName({
|
||||
setDirect,
|
||||
setReset,
|
||||
knsName,
|
||||
setKnsName,
|
||||
setNetworkingKey,
|
||||
setIpAddress,
|
||||
setWsPort,
|
||||
@ -37,7 +30,6 @@ function ResetKnsName({
|
||||
}: ResetProps) {
|
||||
const { address } = useAccount();
|
||||
const navigate = useNavigate();
|
||||
const client = usePublicClient();
|
||||
const { openConnectModal } = useConnectModal();
|
||||
|
||||
const { data: hash, writeContract, isPending, isError, error } = useWriteContract({
|
||||
@ -54,7 +46,6 @@ function ResetKnsName({
|
||||
const addRecentTransaction = useAddRecentTransaction();
|
||||
|
||||
const [name, setName] = useState<string>(knsName.slice(0, -3));
|
||||
const [nameVets, setNameVets] = useState<string[]>([]);
|
||||
const [nameValidities, setNameValidities] = useState<string[]>([])
|
||||
const [tba, setTba] = useState<string>("");
|
||||
const [triggerNameCheck, setTriggerNameCheck] = useState<boolean>(false);
|
||||
@ -73,77 +64,6 @@ function ResetKnsName({
|
||||
}
|
||||
}, [address, openConnectModal]);
|
||||
|
||||
const nameDebouncer = useRef<NodeJS.Timeout | null>(null);
|
||||
useEffect(() => {
|
||||
if (nameDebouncer.current) clearTimeout(nameDebouncer.current);
|
||||
|
||||
nameDebouncer.current = setTimeout(async () => {
|
||||
setNameVets([]);
|
||||
|
||||
|
||||
if (name === "") return;
|
||||
|
||||
let index: number;
|
||||
let vets = [...nameVets];
|
||||
|
||||
let normalized: string;
|
||||
index = vets.indexOf(NAME_INVALID_PUNY);
|
||||
try {
|
||||
normalized = toAscii(name + ".os");
|
||||
if (index !== -1) vets.splice(index, 1);
|
||||
} catch (e) {
|
||||
if (index === -1) vets.push(NAME_INVALID_PUNY);
|
||||
}
|
||||
|
||||
// only check if name is valid punycode
|
||||
if (normalized! !== undefined) {
|
||||
index = vets.indexOf(NAME_URL);
|
||||
if (name !== "" && !isValidDomain(normalized)) {
|
||||
if (index === -1) vets.push(NAME_URL);
|
||||
} else if (index !== -1) vets.splice(index, 1);
|
||||
|
||||
try {
|
||||
const namehash = kinohash(normalized)
|
||||
console.log('normalized', normalized)
|
||||
console.log('namehash', namehash)
|
||||
// maybe separate into helper function for readability?
|
||||
// also note picking the right chain ID & address!
|
||||
const data = await client?.readContract({
|
||||
address: KINOMAP,
|
||||
abi: kinomapAbi,
|
||||
functionName: "get",
|
||||
args: [namehash]
|
||||
})
|
||||
const tba = data?.[0];
|
||||
const owner = data?.[1];
|
||||
|
||||
|
||||
console.log('GOT data', data)
|
||||
console.log('GOT tba', tba)
|
||||
|
||||
index = vets.indexOf(NAME_NOT_OWNER);
|
||||
if (owner === address && index !== -1) vets.splice(index, 1);
|
||||
else if (index === -1 && owner !== address)
|
||||
vets.push(NAME_NOT_OWNER);
|
||||
|
||||
index = vets.indexOf(NAME_NOT_REGISTERED);
|
||||
if (index !== -1) vets.splice(index, 1);
|
||||
|
||||
if (tba !== undefined) {
|
||||
setTba(tba);
|
||||
}
|
||||
} catch (e) {
|
||||
index = vets.indexOf(NAME_NOT_REGISTERED);
|
||||
if (index === -1) vets.push(NAME_NOT_REGISTERED);
|
||||
}
|
||||
|
||||
if (nameVets.length === 0) setKnsName(normalized);
|
||||
}
|
||||
|
||||
setNameVets(vets);
|
||||
}, 500);
|
||||
}, [name, triggerNameCheck]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const handleResetRecords = useCallback(
|
||||
async (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
@ -167,10 +87,6 @@ function ResetKnsName({
|
||||
reset: true,
|
||||
});
|
||||
|
||||
console.log('data', data)
|
||||
|
||||
console.log('tba', tba)
|
||||
|
||||
writeContract({
|
||||
address: tba as `0x${string}`,
|
||||
abi: mechAbi,
|
||||
@ -213,7 +129,7 @@ function ResetKnsName({
|
||||
Node ID to reset:
|
||||
</Tooltip>
|
||||
</h3>
|
||||
<EnterKnsName {...{ name, setName, nameVets, triggerNameCheck, nameValidities, setNameValidities, isReset: true }} />
|
||||
<EnterKnsName {...{ address, name, setName, triggerNameCheck, nameValidities, setNameValidities, setTba, isReset: true }} />
|
||||
<DirectCheckbox {...{ direct, setDirect }} />
|
||||
<p>
|
||||
A reset will not delete any data. It only updates the networking information that your node publishes onchain.
|
||||
|
Loading…
Reference in New Issue
Block a user