Nip5 shop #50

Merged
v0l merged 9 commits from nip5-shop into main 2023-01-13 09:48:07 +00:00
13 changed files with 420 additions and 18 deletions

View File

@ -41,6 +41,7 @@ export const RecommendedFollows = [
"1577e4599dd10c863498fe3c20bd82aafaf829a595ce83c5cf8ac3463531b09b", // yegorpetrov "1577e4599dd10c863498fe3c20bd82aafaf829a595ce83c5cf8ac3463531b09b", // yegorpetrov
"04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9", // ODELL "04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9", // ODELL
"7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194", // verbiricha "7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194", // verbiricha
"52b4a076bcbbbdc3a1aefa3735816cf74993b1b8db202b01c883c58be7fad8bd", // semisol
]; ];
/** /**

View File

@ -0,0 +1,27 @@
import { useState } from "react"
export default function AsyncButton(props: any) {
const [loading, setLoading] = useState<boolean>(false);
async function handle(e : any) {
if(loading) return;
setLoading(true);
try {
if (typeof props.onClick === "function") {
let f = props.onClick(e);
if (f instanceof Promise) {
await f;
}
}
}
finally {
setLoading(false);
}
}
return (
<div {...props} className={`btn ${props.className}${loading ? "disabled" : ""}`} onClick={(e) => handle(e)}>
{props.children}
</div>
)
}

View File

@ -19,7 +19,7 @@ export default function LNURLTip(props) {
const [success, setSuccess] = useState(null); const [success, setSuccess] = useState(null);
useEffect(() => { useEffect(() => {
if (show && invoice === null) { if (show && !props.invoice) {
loadService() loadService()
.then(a => setPayService(a)) .then(a => setPayService(a))
.catch(() => setError("Failed to load LNURL service")); .catch(() => setError("Failed to load LNURL service"));
@ -204,7 +204,7 @@ export default function LNURLTip(props) {
return ( return (
<Modal onClose={() => onClose()}> <Modal onClose={() => onClose()}>
<div className="lnurl-tip" onClick={(e) => e.stopPropagation()}> <div className="lnurl-tip" onClick={(e) => e.stopPropagation()}>
<h2> Send sats</h2> <h2>{props.title || "⚡️ Send sats"}</h2>
{invoiceForm()} {invoiceForm()}
{error ? <p className="error">{error}</p> : null} {error ? <p className="error">{error}</p> : null}
{payInvoice()} {payInvoice()}

195
src/element/Nip5Service.tsx Normal file
View File

@ -0,0 +1,195 @@
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
import { useEffect, useMemo, useState } from "react";
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
import { useDispatch, useSelector } from "react-redux";
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
import { useNavigate } from "react-router-dom";
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
import {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
ServiceProvider,
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
ServiceConfig,
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
ServiceError,
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
HandleAvailability,
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
ServiceErrorCode,
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
HandleRegisterResponse,
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
CheckRegisterResponse
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
} from "../nip05/ServiceProvider";
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
import AsyncButton from "./AsyncButton";
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
// @ts-ignore
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
verbiricha commented 2023-01-13 07:56:30 +00:00 (Migrated from github.com)
Review

We can revisit this once our components are in TS.

We can revisit this once our components are in TS.
import LNURLTip from "./LNURLTip";
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
// @ts-ignore
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
import Copy from "./Copy";
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
// @ts-ignore
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
import useProfile from "../feed/ProfileFeed";
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
// @ts-ignore
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
import useEventPublisher from "../feed/EventPublisher";
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
// @ts-ignore
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
import { resetProfile } from "../state/Users";
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
// @ts-ignore
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
import { hexToBech32 } from "../Util";
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
type Nip05ServiceProps = {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
name: string,
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
service: URL | string,
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
about: JSX.Element,
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
link: string,
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
supportLink: string
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
};
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
type ReduxStore = any;
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
export default function Nip5Service(props: Nip05ServiceProps) {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const dispatch = useDispatch();
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const navigate = useNavigate();
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const pubkey = useSelector<ReduxStore, string>(s => s.login.publicKey);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const user: any = useProfile(pubkey);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const publisher = useEventPublisher();
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const svc = new ServiceProvider(props.service);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const [serviceConfig, setServiceConfig] = useState<ServiceConfig>();
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const [error, setError] = useState<ServiceError>();
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const [handle, setHandle] = useState<string>("");
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const [domain, setDomain] = useState<string>("");
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const [availabilityResponse, setAvailabilityResponse] = useState<HandleAvailability>();
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const [registerResponse, setRegisterResponse] = useState<HandleRegisterResponse>();
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const [showInvoice, setShowInvoice] = useState<boolean>(false);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const [registerStatus, setRegisterStatus] = useState<CheckRegisterResponse>();
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
const domainConfig = useMemo(() => serviceConfig?.domains.find(a => a.name === domain), [domain]);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
useEffect(() => {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
svc.GetConfig()
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
.then(a => {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
if ('error' in a) {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setError(a as ServiceError)
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
} else {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
let svc = a as ServiceConfig;
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setServiceConfig(svc);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
let defaultDomain = svc.domains.find(a => a.default)?.name || svc.domains[0].name;
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setDomain(defaultDomain);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
})
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
.catch(console.error)
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}, [props]);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
useEffect(() => {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
if (handle.length === 0) {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setAvailabilityResponse(undefined);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
if (handle && domain) {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
let rx = new RegExp(domainConfig?.regex[0] ?? "", domainConfig?.regex[1] ?? "");
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
if (!rx.test(handle)) {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setAvailabilityResponse({ available: false, why: "REGEX" });
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
return;
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
let t = setTimeout(() => {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
svc.CheckAvailable(handle, domain)
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
.then(a => {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
if ('error' in a) {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setError(a as ServiceError);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
} else {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setAvailabilityResponse(a as HandleAvailability);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
})
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
.catch(console.error);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}, 500);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
return () => clearTimeout(t);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}, [handle, domain]);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
useEffect(() => {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
if (registerResponse && showInvoice) {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
let t = setInterval(async () => {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
let status = await svc.CheckRegistration(registerResponse.token);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
if ('error' in status) {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setError(status);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setRegisterResponse(undefined);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setShowInvoice(false);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
} else {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
let result: CheckRegisterResponse = status;
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
if (result.available && result.paid) {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setShowInvoice(false);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setRegisterStatus(status);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setRegisterResponse(undefined);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setError(undefined);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}, 2_000);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
return () => clearInterval(t);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}, [registerResponse, showInvoice])
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
function mapError(e: ServiceErrorCode, t: string | null): string | undefined {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
let whyMap = new Map([
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
["TOO_SHORT", "name too short"],
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
["TOO_LONG", "name too long"],
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
["REGEX", "name has disallowed characters"],
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
["REGISTERED", "name is registered"],
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
["DISALLOWED_null", "name is blocked"],
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
["DISALLOWED_later", "name will be available later"],
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
]);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
return whyMap.get(e === "DISALLOWED" ? `${e}_${t}` : e);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
async function startBuy(handle: string, domain: string) {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
if (registerResponse) {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setShowInvoice(true);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
return;
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
let rsp = await svc.RegisterHandle(handle, domain, pubkey);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
if ('error' in rsp) {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setError(rsp);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
} else {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setRegisterResponse(rsp);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
setShowInvoice(true);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
async function updateProfile(handle: string, domain: string) {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
let newProfile = {
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
...user,
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
nip05: `${handle}@${domain}`
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
};
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
delete newProfile["loaded"];
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
delete newProfile["fromEvent"];
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
delete newProfile["pubkey"];
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
let ev = await publisher.metadata(newProfile);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
dispatch(resetProfile(pubkey));
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
publisher.broadcast(ev);
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
navigate("/settings");
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
return (
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<h3>{props.name}</h3>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
{props.about}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<p>Find out more info about {props.name} at <a href={props.link} target="_blank" rel="noreferrer">{props.link}</a></p>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
{error && <b className="error">{error.error}</b>}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
{!registerStatus && <div className="flex mb10">
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<input type="text" placeholder="Handle" value={handle} onChange={(e) => setHandle(e.target.value)} />
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
&nbsp;@&nbsp;
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<select value={domain} onChange={(e) => setDomain(e.target.value)}>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
{serviceConfig?.domains.map(a => <option key={a.name}>{a.name}</option>)}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
</select>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
</div>}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
{availabilityResponse?.available && !registerStatus && <div className="flex">
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<div className="mr10">
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
{availabilityResponse.quote?.price.toLocaleString()} sats<br />
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<small>{availabilityResponse.quote?.data.type}</small>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
</div>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<input type="text" className="f-grow mr10" placeholder="pubkey" value={hexToBech32("npub", pubkey)} disabled />
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<AsyncButton onClick={() => startBuy(handle, domain)}>Buy Now</AsyncButton>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
</div>}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
{availabilityResponse?.available === false && !registerStatus && <div className="flex">
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<b className="error">Not available: {mapError(availabilityResponse.why!, availabilityResponse.reasonTag || null)}</b>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
</div>}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<LNURLTip invoice={registerResponse?.invoice} show={showInvoice} onClose={() => setShowInvoice(false)} title={`Buying ${handle}@${domain}`} />
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
{registerStatus?.paid && <div className="flex f-col">
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<h4>Order Paid!</h4>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<p>Your new NIP-05 handle is: <code>{handle}@{domain}</code></p>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<h3>Account Support</h3>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<p>Please make sure to save the following password in order to manage your handle in the future</p>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<Copy text={registerStatus.password} />
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<p>Go to <a href={props.supportLink} target="_blank" rel="noreferrer">account page</a></p>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<h4>Activate Now</h4>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
<AsyncButton onClick={() => updateProfile(handle, domain)}>Add to Profile</AsyncButton>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
</div>}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
</>
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
)
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥
}
verbiricha commented 2023-01-13 07:52:28 +00:00 (Migrated from github.com)
Review

🔥

🔥

View File

@ -91,6 +91,10 @@ code {
font-weight: bold; font-weight: bold;
} }
.btn.disabled {
color: var(--gray-light);
}
.btn:hover { .btn:hover {
background-color: var(--gray); background-color: var(--gray);
} }
@ -107,7 +111,7 @@ textarea {
font: inherit; font: inherit;
} }
input[type="text"], input[type="password"], input[type="number"], textarea { input[type="text"], input[type="password"], input[type="number"], textarea, select {
padding: 10px; padding: 10px;
border-radius: 5px; border-radius: 5px;
border: 0; border: 0;
@ -115,6 +119,11 @@ input[type="text"], input[type="password"], input[type="number"], textarea {
color: var(--font-color); color: var(--font-color);
} }
input:disabled {
color: var(--gray-medium);
cursor:not-allowed;
}
textarea:placeholder { textarea:placeholder {
color: var(--gray-superlight); color: var(--gray-superlight);
} }

View File

@ -18,7 +18,8 @@ import Store from "./state/Store";
import NotificationsPage from './pages/Notifications'; import NotificationsPage from './pages/Notifications';
import NewUserPage from './pages/NewUserPage'; import NewUserPage from './pages/NewUserPage';
import SettingsPage from './pages/SettingsPage'; import SettingsPage from './pages/SettingsPage';
import ErrorPage from './pages/ErrorPage.tsx'; import ErrorPage from './pages/ErrorPage';
import VerificationPage from './pages/Verification';
/** /**
* Nostr websocket managment system * Nostr websocket managment system
@ -57,6 +58,10 @@ const router = createBrowserRouter([
{ {
path: "/settings", path: "/settings",
element: <SettingsPage /> element: <SettingsPage />
},
{
path: "/verification",
element: <VerificationPage />
} }
] ]
} }

View File

@ -0,0 +1,99 @@
export type ServiceErrorCode = "UNKNOWN_ERROR" | "INVALID_BODY" | "NO_SUCH_DOMAIN" | "TOO_SHORT" | "TOO_LONG" | "REGEX" | "DISALLOWED" | "REGISTERED" | "NOT_AVAILABLE" | "RATE_LIMITED" | "NO_TOKEN" | "INVALID_TOKEN" | "NO_SUCH_PAYMENT";
export interface ServiceError {
error: ServiceErrorCode
};
export interface ServiceConfig {
domains: DomainConfig[]
}
export type DomainConfig = {
name: string,
default: boolean,
length: [number, number],
regex: [string, string],
regexChars: [string, string]
}
export type HandleAvailability = {
available: boolean,
why?: ServiceErrorCode,
reasonTag?: string | null,
quote?: HandleQuote
}
export type HandleQuote = {
price: number,
data: HandleData
}
export type HandleData = {
type: string | "premium" | "short"
}
export type HandleRegisterResponse = {
quote: HandleQuote,
paymentHash: string,
invoice: string,
token: string
}
export type CheckRegisterResponse = {
available: boolean,
paid: boolean,
password: string
}
export class ServiceProvider {
readonly url: URL | string
constructor(url: URL | string) {
this.url = url;
}
async GetConfig(): Promise<ServiceConfig | ServiceError> {
return await this._GetJson("/config.json");
}
async CheckAvailable(handle: string, domain: string): Promise<HandleAvailability | ServiceError> {
return await this._GetJson("/registration/availability", "POST", { name: handle, domain });
}
async RegisterHandle(handle: string, domain: string, pubkey: string): Promise<HandleRegisterResponse | ServiceError> {
return await this._GetJson("/registration/register", "PUT", {
name: handle,
domain,
pk: pubkey,
ref: "snort"
});
}
async CheckRegistration(token: string): Promise<CheckRegisterResponse | ServiceError> {
return await this._GetJson("/registration/register/check", "POST", undefined, {
authorization: token
});
}
async _GetJson<T>(path: string, method?: "GET" | string, body?: any, headers?: any): Promise<T | ServiceError> {
try {
let rsp = await fetch(`${this.url}${path}`, {
method: method,
body: body ? JSON.stringify(body) : undefined,
headers: {
accept: "application/json",
...(body ? { "content-type": "application/json" } : {}),
...headers
}
});
let obj = await rsp.json();
if ('error' in obj) {
return <ServiceError>obj;
}
return obj;
} catch (e) {
console.warn(e);
}
return { error: "UNKNOWN_ERROR" };
}
}

View File

@ -70,7 +70,11 @@ export default class Connection {
for (let p of this.Pending) { for (let p of this.Pending) {
this._SendJson(p); this._SendJson(p);
} }
this.Pending = [];
for (let s of Object.values(this.Subscriptions)) {
this._SendSubscription(s, s.ToObject());
}
this._UpdateState(); this._UpdateState();
} }
@ -159,15 +163,7 @@ export default class Connection {
return; return;
} }
let req = ["REQ", sub.Id, subObj]; this._SendSubscription(sub, subObj);
if (sub.OrSubs.length > 0) {
req = [
...req,
...sub.OrSubs.map(o => o.ToObject())
];
}
sub.Started[this.Address] = new Date().getTime();
this._SendJson(req);
this.Subscriptions[sub.Id] = sub; this.Subscriptions[sub.Id] = sub;
} }
@ -227,6 +223,18 @@ export default class Connection {
} }
} }
_SendSubscription(sub, subObj) {
let req = ["REQ", sub.Id, subObj];
if (sub.OrSubs.length > 0) {
req = [
...req,
...sub.OrSubs.map(o => o.ToObject())
];
}
sub.Started[this.Address] = new Date().getTime();
this._SendJson(req);
}
_SendJson(obj) { _SendJson(obj) {
if (this.Socket?.readyState !== WebSocket.OPEN) { if (this.Socket?.readyState !== WebSocket.OPEN) {
this.Pending.push(obj); this.Pending.push(obj);

View File

@ -1,15 +1,14 @@
import React, { FC } from "react";
import { useRouteError } from "react-router-dom"; import { useRouteError } from "react-router-dom";
const ErrorPage: FC = () => { const ErrorPage = () => {
const error = useRouteError(); const error = useRouteError();
console.error(error); console.error(error);
return ( return (
<> <>
<h4>{error?.message ?? "Uknown error"}</h4> <h4>An error has occured!</h4>
<pre> <pre>
{JSON.stringify(error)} {JSON.stringify(error, undefined, ' ')}
</pre> </pre>
</> </>
); );

View File

@ -4,6 +4,8 @@ import Nostrich from "../nostrich.jpg";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faShop } from "@fortawesome/free-solid-svg-icons";
import useEventPublisher from "../feed/EventPublisher"; import useEventPublisher from "../feed/EventPublisher";
import useProfile from "../feed/ProfileFeed"; import useProfile from "../feed/ProfileFeed";
@ -128,7 +130,12 @@ export default function SettingsPage(props) {
<div className="form-group"> <div className="form-group">
<div>NIP-05:</div> <div>NIP-05:</div>
<div> <div>
<input type="text" value={nip05} onChange={(e) => setNip05(e.target.value)} /> <input type="text" className="mr10" value={nip05} onChange={(e) => setNip05(e.target.value)} />
<div className="btn" onClick={() => navigate("/verification")}>
<FontAwesomeIcon icon={faShop} />
&nbsp;
Buy
</div>
</div> </div>
</div> </div>
<div className="form-group"> <div className="form-group">

View File

@ -0,0 +1,3 @@
.verification a {
color: var(--highlight);
}

View File

@ -0,0 +1,40 @@
import Nip5Service from "../element/Nip5Service";
import './Verification.css'
export default function VerificationPage() {
const services = [
/*{
name: "Snort",
service: "https://api.snort.social/api/v1/n5sp",
link: "https://snort.social/",
about: <>Our very own NIP-05 verification service, help support the development of this site and get a shiny special badge on our site!</>
},*/
{
name: "Nostr Plebs",
service: "https://nostrplebs.com/api/v1",
link: "https://nostrplebs.com/",
supportLink: "https://nostrplebs.com/manage",
about: <>
<p>Nostr Plebs is one of the first NIP-05 providers in the space and offers a good collection of domains at reasonable prices</p>
</>
}
];
return (
<div className="verification">
<h2>Get Verified</h2>
<p>
NIP-05 is a DNS based verification spec which helps to validate you as a real user.
</p>
<p>Getting NIP-05 verified can help:</p>
<ul>
<li>Prevent fake accounts from immitating you</li>
<li>Make your profile easier to find and share</li>
<li>Fund developers and platforms providing NIP-05 verification services</li>
</ul>
{services.map(a => <Nip5Service key={a.name} {...a} />)}
</div>
)
}

9
tsconfig.json Normal file
View File

@ -0,0 +1,9 @@
{
"compilerOptions": {
"jsx": "react-jsx",
"moduleResolution": "node",
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}