Files
nostrudel/src/components/relay-url-input.tsx
2023-08-03 22:01:20 -05:00

105 lines
3.1 KiB
TypeScript

import { forwardRef, useState } from "react";
import {
Button,
Flex,
IconButton,
Input,
InputGroup,
InputLeftElement,
InputProps,
InputRightElement,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalHeader,
ModalOverlay,
ModalProps,
useDisclosure,
} from "@chakra-ui/react";
import { useAsync } from "react-use";
import { unique } from "../helpers/array";
import { RelayIcon, SearchIcon } from "./icons";
function RelayPickerModal({
onSelect,
onClose,
...props
}: { onSelect: (relay: string) => void } & Omit<ModalProps, "children">) {
const [search, setSearch] = useState("");
const { value: onlineRelays } = useAsync(async () =>
fetch("https://api.nostr.watch/v1/online").then((res) => res.json() as Promise<string[]>)
);
const relayList = unique(onlineRelays ?? []);
const filteredRelays = search ? relayList.filter((url) => url.includes(search)) : relayList;
return (
<Modal onClose={onClose} {...props}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Pick Relay</ModalHeader>
<ModalCloseButton />
<ModalBody pt="0" px="4" pb="4">
<InputGroup mb="2">
<InputLeftElement pointerEvents="none" children={<SearchIcon />} />
<Input
type="search"
placeholder="Search"
name="relay-search"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
</InputGroup>
<Flex gap="2" direction="column">
{filteredRelays.map((url) => (
<Button
value={url}
onClick={() => {
onSelect(url);
onClose();
}}
variant="outline"
size="sm"
>
{url}
</Button>
))}
</Flex>
</ModalBody>
</ModalContent>
</Modal>
);
}
export type RelayUrlInputProps = Omit<InputProps, "type">;
export const RelayUrlInput = forwardRef(
({ onChange, ...props }: Omit<RelayUrlInputProps, "onChange"> & { onChange: (url: string) => void }, ref) => {
const { isOpen, onClose, onOpen } = useDisclosure();
const { value: relaysJson } = useAsync(async () =>
fetch("https://api.nostr.watch/v1/online").then((res) => res.json() as Promise<string[]>)
);
const relaySuggestions = unique(relaysJson ?? []);
return (
<>
<InputGroup>
<Input ref={ref} list="relay-suggestions" type="url" onChange={(e) => onChange(e.target.value)} {...props} />
<datalist id="relay-suggestions">
{relaySuggestions.map((url) => (
<option key={url} value={url}>
{url}
</option>
))}
</datalist>
<InputRightElement>
<IconButton icon={<RelayIcon />} aria-label="Pick from list" size="sm" onClick={onOpen} />
</InputRightElement>
</InputGroup>
<RelayPickerModal onClose={onClose} isOpen={isOpen} onSelect={(url) => onChange(url)} size="2xl" />
</>
);
}
);