allow user to edit community moderators

This commit is contained in:
hzrd149
2023-10-24 12:12:50 -05:00
parent 331bb445e5
commit 55271c3436
3 changed files with 85 additions and 46 deletions

View File

@@ -0,0 +1,36 @@
import { Input, InputProps } from "@chakra-ui/react";
import { forwardRef } from "react";
import { useAsync } from "react-use";
import { nip19 } from "nostr-tools";
import { useUserSearchDirectoryContext } from "../providers/user-directory-provider";
import userMetadataService from "../services/user-metadata";
import { getUserDisplayName } from "../helpers/user-metadata";
const NpubAutocomplete = forwardRef<HTMLInputElement, InputProps>(({ value, ...props }, ref) => {
const getDirectory = useUserSearchDirectoryContext();
const { value: users } = useAsync(async () => {
const dir = await getDirectory();
return dir.map(({ pubkey }) => ({ pubkey, metadata: userMetadataService.getSubject(pubkey).value }));
}, [getDirectory]);
return (
<>
<Input placeholder="npub..." list="users" value={value} {...props} ref={ref} />
{users && (
<datalist id="users">
{users
.filter((p) => !!p.metadata)
.map(({ metadata, pubkey }) => (
<option key={pubkey} value={nip19.npubEncode(pubkey)}>
{getUserDisplayName(metadata, pubkey)}
</option>
))}
</datalist>
)}
</>
);
});
export default NpubAutocomplete;

View File

@@ -2,7 +2,6 @@ import {
Flex,
Heading,
IconButton,
Input,
NumberDecrementStepper,
NumberIncrementStepper,
NumberInput,
@@ -12,18 +11,14 @@ import {
useToast,
} from "@chakra-ui/react";
import { CloseIcon } from "@chakra-ui/icons";
import { nip19 } from "nostr-tools";
import { useForm } from "react-hook-form";
import { EventSplit } from "../../helpers/nostr/zaps";
import { AddIcon } from "../icons";
import { useUserSearchDirectoryContext } from "../../providers/user-directory-provider";
import { useAsync } from "react-use";
import { getUserDisplayName } from "../../helpers/user-metadata";
import userMetadataService from "../../services/user-metadata";
import { normalizeToHex } from "../../helpers/nip19";
import UserAvatar from "../user-avatar";
import { UserLink } from "../user-link";
import NpubAutocomplete from "../npub-autocomplete";
function getRemainingPercent(split: EventSplit) {
return Math.round((1 - split.reduce((v, p) => v + p.percent, 0)) * 100) / 100;
@@ -58,12 +53,6 @@ function AddUserForm({
});
watch("percent");
const getDirectory = useUserSearchDirectoryContext();
const { value: users } = useAsync(async () => {
const dir = await getDirectory();
return dir.map(({ pubkey }) => ({ pubkey, metadata: userMetadataService.getSubject(pubkey).value }));
}, [getDirectory]);
const submit = handleSubmit((values) => {
try {
const pubkey = normalizeToHex(values.pubkey);
@@ -78,18 +67,7 @@ function AddUserForm({
return (
<Flex as="form" gap="2" onSubmit={submit}>
<Input placeholder="npub..." list="users" {...register("pubkey", { required: true, validate: validateNpub })} />
{users && (
<datalist id="users">
{users
.filter((p) => !!p.metadata)
.map(({ metadata, pubkey }) => (
<option key={pubkey} value={nip19.npubEncode(pubkey)}>
{getUserDisplayName(metadata, pubkey)}
</option>
))}
</datalist>
)}
<NpubAutocomplete {...register("pubkey", { required: true, validate: validateNpub })} />
<NumberInput
step={1}
min={1}

View File

@@ -1,3 +1,4 @@
import { useCallback, useState } from "react";
import {
Box,
Button,
@@ -7,9 +8,8 @@ import {
FormHelperText,
FormLabel,
IconButton,
Image,
IconButtonProps,
Input,
Link,
Modal,
ModalBody,
ModalCloseButton,
@@ -26,18 +26,23 @@ import {
useToast,
} from "@chakra-ui/react";
import { SubmitHandler, useForm } from "react-hook-form";
import { useCurrentAccount } from "../../../hooks/use-current-account";
import UserAvatar from "../../../components/user-avatar";
import { UserLink } from "../../../components/user-link";
import { TrashIcon, UploadImageIcon } from "../../../components/icons";
import { TrashIcon } from "../../../components/icons";
import Upload01 from "../../../components/icons/upload-01";
import Upload02 from "../../../components/icons/upload-02";
import { useCallback, useState } from "react";
import { nostrBuildUploadImage } from "../../../helpers/nostr-build";
import { useSigningContext } from "../../../providers/signing-provider";
import { RelayUrlInput } from "../../../components/relay-url-input";
import { normalizeRelayUrl, safeRelayUrl } from "../../../helpers/url";
import { safeRelayUrl } from "../../../helpers/url";
import { RelayFavicon } from "../../../components/relay-favicon";
import NpubAutocomplete from "../../../components/npub-autocomplete";
import { normalizeToHex } from "../../../helpers/nip19";
function RemoveButton({ ...props }: IconButtonProps) {
return <IconButton icon={<TrashIcon />} size="sm" colorScheme="red" variant="ghost" ml="auto" {...props} />;
}
export type FormValues = {
name: string;
@@ -113,6 +118,22 @@ export default function CommunityCreateModal({
[setValue, getValues, requestSignature, toast],
);
const [modInput, setModInput] = useState("");
const addMod = () => {
if (!modInput) return;
const pubkey = normalizeToHex(modInput);
if (pubkey) {
setValue("mods", getValues("mods").concat(pubkey));
}
setModInput("");
};
const removeMod = (pubkey: string) => {
setValue(
"mods",
getValues("mods").filter((p) => p !== pubkey),
);
};
const [relayInput, setRelayInput] = useState("");
const addRelay = () => {
if (!relayInput) return;
@@ -216,12 +237,25 @@ export default function CommunityCreateModal({
<FormControl isInvalid={!!errors.mods}>
<FormLabel>Moderators</FormLabel>
{getValues().mods.map((pubkey) => (
<Flex gap="2" alignItems="center" key={pubkey}>
<UserAvatar pubkey={pubkey} size="sm" />
<UserLink pubkey={pubkey} fontWeight="bold" />
</Flex>
))}
<Flex direction="column" gap="2" pb="2">
{getValues().mods.map((pubkey) => (
<Flex gap="2" alignItems="center" key={pubkey}>
<UserAvatar pubkey={pubkey} size="sm" />
<UserLink pubkey={pubkey} fontWeight="bold" />
<RemoveButton
aria-label={`Remove moderator`}
title={`Remove moderator`}
onClick={() => removeMod(pubkey)}
/>
</Flex>
))}
</Flex>
<Flex gap="2">
<NpubAutocomplete value={modInput} onChange={(e) => setModInput(e.target.value)} />
<Button isDisabled={!modInput} onClick={addMod}>
Add
</Button>
</Flex>
</FormControl>
<FormControl isInvalid={!!errors.mods}>
@@ -249,16 +283,7 @@ export default function CommunityCreateModal({
<Text fontWeight="bold" isTruncated>
{url}
</Text>
<IconButton
icon={<TrashIcon />}
aria-label={`Remove ${url}`}
title={`Remove ${url}`}
onClick={() => removeRelay(url)}
size="sm"
colorScheme="red"
variant="ghost"
ml="auto"
/>
<RemoveButton aria-label={`Remove ${url}`} title={`Remove ${url}`} onClick={() => removeRelay(url)} />
</Flex>
))}
</Flex>