mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-04-09 20:29:17 +02:00
Add community create and edit modals
This commit is contained in:
parent
6c276147aa
commit
28de4d4704
5
.changeset/soft-eagles-smash.md
Normal file
5
.changeset/soft-eagles-smash.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"nostrudel": minor
|
||||
---
|
||||
|
||||
Add community create and edit modals
|
@ -29,6 +29,9 @@ export function getCommunityDescription(community: NostrEvent) {
|
||||
export function getCommunityRules(community: NostrEvent) {
|
||||
return community.tags.find((t) => t[0] === "rules")?.[1];
|
||||
}
|
||||
export function getCommunityRanking(community: NostrEvent) {
|
||||
return community.tags.find((t) => t[0] === "rank_mode")?.[1];
|
||||
}
|
||||
|
||||
export function getPostSubject(event: NostrEvent) {
|
||||
const subject = event.tags.find((t) => t[0] === "subject")?.[1];
|
||||
|
150
src/views/communities/components/community-create-modal.tsx
Normal file
150
src/views/communities/components/community-create-modal.tsx
Normal file
@ -0,0 +1,150 @@
|
||||
import {
|
||||
Button,
|
||||
Flex,
|
||||
FormControl,
|
||||
FormErrorMessage,
|
||||
FormHelperText,
|
||||
FormLabel,
|
||||
Input,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
ModalProps,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Stack,
|
||||
Textarea,
|
||||
} 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";
|
||||
|
||||
export type FormValues = {
|
||||
name: string;
|
||||
banner: string;
|
||||
description: string;
|
||||
rules: string;
|
||||
mods: string[];
|
||||
relays: string[];
|
||||
ranking: string;
|
||||
};
|
||||
|
||||
export default function CommunityCreateModal({
|
||||
isOpen,
|
||||
onClose,
|
||||
onSubmit,
|
||||
defaultValues,
|
||||
isUpdate,
|
||||
...props
|
||||
}: Omit<ModalProps, "children"> & {
|
||||
onSubmit: SubmitHandler<FormValues>;
|
||||
defaultValues?: FormValues;
|
||||
isUpdate?: boolean;
|
||||
}) {
|
||||
const account = useCurrentAccount();
|
||||
|
||||
const {
|
||||
register,
|
||||
formState: { errors },
|
||||
handleSubmit,
|
||||
watch,
|
||||
getValues,
|
||||
setValue,
|
||||
} = useForm<FormValues>({
|
||||
mode: "all",
|
||||
defaultValues: defaultValues || {
|
||||
name: "",
|
||||
banner: "",
|
||||
description: "",
|
||||
rules: "",
|
||||
mods: account ? [account.pubkey] : [],
|
||||
relays: [],
|
||||
ranking: "votes",
|
||||
},
|
||||
});
|
||||
|
||||
watch("mods");
|
||||
watch("ranking");
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="2xl" {...props}>
|
||||
<ModalOverlay />
|
||||
<ModalContent as="form" onSubmit={handleSubmit(onSubmit)}>
|
||||
<ModalHeader p="4">{isUpdate ? "Update Community" : "Create Community"}</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody px="4" py="0" gap="4" display="flex" flexDirection="column">
|
||||
{!isUpdate && (
|
||||
<FormControl isInvalid={!!errors.name}>
|
||||
<FormLabel>Community Name</FormLabel>
|
||||
<Input
|
||||
type="text"
|
||||
{...register("name", {
|
||||
required: true,
|
||||
validate: (v) => {
|
||||
if (/\p{Z}/iu.test(v)) return "Must not have spaces";
|
||||
return true;
|
||||
},
|
||||
})}
|
||||
isReadOnly={isUpdate}
|
||||
autoComplete="off"
|
||||
/>
|
||||
<FormHelperText>The name of your community (no-spaces)</FormHelperText>
|
||||
{errors.name?.message && <FormErrorMessage>{errors.name?.message}</FormErrorMessage>}
|
||||
</FormControl>
|
||||
)}
|
||||
|
||||
<FormControl isInvalid={!!errors.description}>
|
||||
<FormLabel>Description</FormLabel>
|
||||
<Textarea {...register("description")} autoComplete="off" />
|
||||
<FormHelperText>short description about your community</FormHelperText>
|
||||
{errors.description?.message && <FormErrorMessage>{errors.description?.message}</FormErrorMessage>}
|
||||
</FormControl>
|
||||
|
||||
<FormControl isInvalid={!!errors.rules}>
|
||||
<FormLabel>Rules and Guidelines</FormLabel>
|
||||
<Textarea {...register("rules")} autoComplete="off" />
|
||||
<FormHelperText>Rules and posting guidelines</FormHelperText>
|
||||
{errors.rules?.message && <FormErrorMessage>{errors.rules?.message}</FormErrorMessage>}
|
||||
</FormControl>
|
||||
|
||||
<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>
|
||||
))}
|
||||
</FormControl>
|
||||
|
||||
<FormControl isInvalid={!!errors.mods}>
|
||||
<FormLabel>Default Raking</FormLabel>
|
||||
<RadioGroup
|
||||
value={getValues().ranking}
|
||||
onChange={(e) => setValue("ranking", e, { shouldDirty: true, shouldTouch: true })}
|
||||
>
|
||||
<Stack direction="row">
|
||||
<Radio value="votes">Votes</Radio>
|
||||
<Radio value="zaps">Zaps</Radio>
|
||||
</Stack>
|
||||
</RadioGroup>
|
||||
<FormHelperText>The default by posts are ranked when viewing the community</FormHelperText>
|
||||
{errors.rules?.message && <FormErrorMessage>{errors.rules?.message}</FormErrorMessage>}
|
||||
</FormControl>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter p="4" display="flex" gap="2">
|
||||
<Button onClick={onClose}>Cancel</Button>
|
||||
<Button colorScheme="primary" type="submit">
|
||||
{isUpdate ? "Update Community" : "Create Community"}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -1,44 +1,101 @@
|
||||
import { Button, Center, Flex, Heading, Link, SimpleGrid, Text } from "@chakra-ui/react";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import { Button, Center, Flex, Heading, Link, SimpleGrid, Text, useDisclosure, useToast } from "@chakra-ui/react";
|
||||
import { Link as RouterLink, useNavigate } from "react-router-dom";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import VerticalPageLayout from "../../components/vertical-page-layout";
|
||||
import { ErrorBoundary } from "../../components/error-boundary";
|
||||
import useSubscribedCommunitiesList from "../../hooks/use-subscribed-communities-list";
|
||||
import { useCurrentAccount } from "../../hooks/use-current-account";
|
||||
import { PointerCommunityCard } from "./components/community-card";
|
||||
import CommunityCreateModal, { FormValues } from "./components/community-create-modal";
|
||||
import { useSigningContext } from "../../providers/signing-provider";
|
||||
import { DraftNostrEvent } from "../../types/nostr-event";
|
||||
import { COMMUNITY_DEFINITION_KIND, getCommunityName } from "../../helpers/nostr/communities";
|
||||
import NostrPublishAction from "../../classes/nostr-publish-action";
|
||||
import { unique } from "../../helpers/array";
|
||||
import clientRelaysService from "../../services/client-relays";
|
||||
import replaceableEventLoaderService from "../../services/replaceable-event-requester";
|
||||
|
||||
function CommunitiesHomePage() {
|
||||
const toast = useToast();
|
||||
const { requestSignature } = useSigningContext();
|
||||
const navigate = useNavigate();
|
||||
const account = useCurrentAccount()!;
|
||||
const createModal = useDisclosure();
|
||||
const { pointers: communities } = useSubscribedCommunitiesList(account.pubkey, { alwaysRequest: true });
|
||||
|
||||
const createCommunity = async (values: FormValues) => {
|
||||
try {
|
||||
const draft: DraftNostrEvent = {
|
||||
kind: COMMUNITY_DEFINITION_KIND,
|
||||
created_at: dayjs().unix(),
|
||||
content: "",
|
||||
tags: [["d", values.name]],
|
||||
};
|
||||
|
||||
for (const pubkey of values.mods) {
|
||||
draft.tags.push(["p", pubkey, "moderator"]);
|
||||
}
|
||||
for (const url of values.relays) {
|
||||
draft.tags.push(["relay", url]);
|
||||
}
|
||||
|
||||
if (values.description) draft.tags.push(["description", values.description]);
|
||||
if (values.banner) draft.tags.push(["image", values.banner]);
|
||||
if (values.ranking) draft.tags.push(["rank_mode", values.ranking]);
|
||||
|
||||
const signed = await requestSignature(draft);
|
||||
new NostrPublishAction(
|
||||
"Create Community",
|
||||
unique([...clientRelaysService.getWriteUrls(), ...values.relays]),
|
||||
signed,
|
||||
);
|
||||
|
||||
replaceableEventLoaderService.handleEvent(signed);
|
||||
|
||||
navigate(`/c/${getCommunityName(signed)}/${signed.pubkey}`);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) toast({ description: e.message, status: "error" });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<VerticalPageLayout>
|
||||
<Flex gap="2" alignItems="center" wrap="wrap">
|
||||
<Button as={RouterLink} to="/communities/explore">
|
||||
Explore Communities
|
||||
</Button>
|
||||
</Flex>
|
||||
{communities.length > 0 ? (
|
||||
<SimpleGrid spacing="2" columns={{ base: 1, lg: 2 }}>
|
||||
{communities.map((pointer) => (
|
||||
<ErrorBoundary key={pointer.kind + pointer.pubkey + pointer.identifier}>
|
||||
<PointerCommunityCard pointer={pointer} />
|
||||
</ErrorBoundary>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
) : (
|
||||
<Center aspectRatio={3 / 4} flexDirection="column" gap="4">
|
||||
<Heading size="md">No communities :(</Heading>
|
||||
<Text>
|
||||
go find a cool one to join.{" "}
|
||||
<Link as={RouterLink} to="/communities/explore" color="blue.500">
|
||||
Explore
|
||||
</Link>
|
||||
</Text>
|
||||
</Center>
|
||||
<>
|
||||
<VerticalPageLayout>
|
||||
<Flex gap="2" alignItems="center" wrap="wrap">
|
||||
<Button as={RouterLink} to="/communities/explore">
|
||||
Explore Communities
|
||||
</Button>
|
||||
|
||||
<Button ml="auto" onClick={createModal.onOpen}>
|
||||
Create Community
|
||||
</Button>
|
||||
</Flex>
|
||||
{communities.length > 0 ? (
|
||||
<SimpleGrid spacing="2" columns={{ base: 1, lg: 2 }}>
|
||||
{communities.map((pointer) => (
|
||||
<ErrorBoundary key={pointer.kind + pointer.pubkey + pointer.identifier}>
|
||||
<PointerCommunityCard pointer={pointer} />
|
||||
</ErrorBoundary>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
) : (
|
||||
<Center aspectRatio={3 / 4} flexDirection="column" gap="4">
|
||||
<Heading size="md">No communities :(</Heading>
|
||||
<Text>
|
||||
go find a cool one to join.{" "}
|
||||
<Link as={RouterLink} to="/communities/explore" color="blue.500">
|
||||
Explore
|
||||
</Link>
|
||||
</Text>
|
||||
</Center>
|
||||
)}
|
||||
</VerticalPageLayout>
|
||||
{createModal.isOpen && (
|
||||
<CommunityCreateModal isOpen={createModal.isOpen} onClose={createModal.onClose} onSubmit={createCommunity} />
|
||||
)}
|
||||
</VerticalPageLayout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Button, ButtonGroup, Divider, Flex, Heading, Text } from "@chakra-ui/react";
|
||||
import { Button, ButtonGroup, Divider, Flex, Heading, Text, useDisclosure } from "@chakra-ui/react";
|
||||
import { Outlet, Link as RouterLink, useLocation } from "react-router-dom";
|
||||
import { Kind, nip19 } from "nostr-tools";
|
||||
|
||||
@ -26,6 +26,7 @@ import { getEventCoordinate, getEventUID } from "../../helpers/nostr/events";
|
||||
import { WritingIcon } from "../../components/icons";
|
||||
import { useContext } from "react";
|
||||
import { PostModalContext } from "../../providers/post-modal-provider";
|
||||
import CommunityEditModal from "./components/community-edit-modal";
|
||||
|
||||
function getCommunityPath(community: NostrEvent) {
|
||||
return `/c/${encodeURIComponent(getCommunityName(community))}/${nip19.npubEncode(community.pubkey)}`;
|
||||
@ -35,6 +36,7 @@ export default function CommunityHomePage({ community }: { community: NostrEvent
|
||||
const image = getCommunityImage(community);
|
||||
const location = useLocation();
|
||||
const { openModal } = useContext(PostModalContext);
|
||||
const editModal = useDisclosure();
|
||||
const communityCoordinate = getEventCoordinate(community);
|
||||
|
||||
const verticalLayout = useBreakpointValue({ base: true, xl: false });
|
||||
@ -50,77 +52,90 @@ export default function CommunityHomePage({ community }: { community: NostrEvent
|
||||
if (location.pathname.endsWith("/pending")) active = "pending";
|
||||
|
||||
return (
|
||||
<AdditionalRelayProvider relays={communityRelays}>
|
||||
<VerticalPageLayout pt={image && "0"}>
|
||||
<Flex
|
||||
backgroundImage={getCommunityImage(community)}
|
||||
backgroundRepeat="no-repeat"
|
||||
backgroundSize="cover"
|
||||
backgroundPosition="center"
|
||||
aspectRatio={3 / 1}
|
||||
backgroundColor="rgba(0,0,0,0.2)"
|
||||
p="4"
|
||||
gap="4"
|
||||
direction="column"
|
||||
justifyContent="flex-end"
|
||||
textShadow="2px 2px var(--chakra-blur-sm) var(--chakra-colors-blackAlpha-800)"
|
||||
>
|
||||
<Heading>{getCommunityName(community)}</Heading>
|
||||
<Flex gap="2" alignItems="center">
|
||||
<UserAvatarLink pubkey={community.pubkey} size="sm" />
|
||||
<Text>by</Text>
|
||||
<UserLink pubkey={community.pubkey} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
{verticalLayout && <HorizontalCommunityDetails community={community} w="full" flexShrink={0} />}
|
||||
|
||||
<Flex gap="4" alignItems="flex-start" overflow="hidden">
|
||||
<Flex direction="column" gap="4" flex={1} overflow="hidden">
|
||||
<ButtonGroup size="sm">
|
||||
<Button
|
||||
colorScheme="primary"
|
||||
leftIcon={<WritingIcon />}
|
||||
onClick={() =>
|
||||
openModal({
|
||||
cacheFormKey: communityCoordinate + "-new-post",
|
||||
initCommunity: communityCoordinate,
|
||||
requireSubject: true,
|
||||
})
|
||||
}
|
||||
>
|
||||
New Post
|
||||
</Button>
|
||||
<Divider orientation="vertical" h="2rem" />
|
||||
<Button leftIcon={<TrendUp01 />} isDisabled>
|
||||
Trending
|
||||
</Button>
|
||||
<Button
|
||||
leftIcon={<Clock />}
|
||||
as={RouterLink}
|
||||
to={getCommunityPath(community)}
|
||||
replace
|
||||
colorScheme={active === "new" ? "primary" : "gray"}
|
||||
>
|
||||
New
|
||||
</Button>
|
||||
<Button
|
||||
leftIcon={<Hourglass03 />}
|
||||
as={RouterLink}
|
||||
to={getCommunityPath(community) + "/pending"}
|
||||
replace
|
||||
colorScheme={active == "pending" ? "primary" : "gray"}
|
||||
>
|
||||
Pending
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<Outlet context={{ community, timeline }} />
|
||||
<>
|
||||
<AdditionalRelayProvider relays={communityRelays}>
|
||||
<VerticalPageLayout pt={image && "0"}>
|
||||
<Flex
|
||||
backgroundImage={getCommunityImage(community)}
|
||||
backgroundRepeat="no-repeat"
|
||||
backgroundSize="cover"
|
||||
backgroundPosition="center"
|
||||
aspectRatio={3 / 1}
|
||||
backgroundColor="rgba(0,0,0,0.2)"
|
||||
p="4"
|
||||
gap="4"
|
||||
direction="column"
|
||||
justifyContent="flex-end"
|
||||
textShadow="2px 2px var(--chakra-blur-sm) var(--chakra-colors-blackAlpha-800)"
|
||||
>
|
||||
<Heading>{getCommunityName(community)}</Heading>
|
||||
<Flex gap="2" alignItems="center">
|
||||
<UserAvatarLink pubkey={community.pubkey} size="sm" />
|
||||
<Text>by</Text>
|
||||
<UserLink pubkey={community.pubkey} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
{!verticalLayout && <VerticalCommunityDetails community={community} w="full" maxW="xs" flexShrink={0} />}
|
||||
</Flex>
|
||||
</VerticalPageLayout>
|
||||
</AdditionalRelayProvider>
|
||||
{verticalLayout && (
|
||||
<HorizontalCommunityDetails community={community} w="full" flexShrink={0} onEditClick={editModal.onOpen} />
|
||||
)}
|
||||
|
||||
<Flex gap="4" alignItems="flex-start" overflow="hidden">
|
||||
<Flex direction="column" gap="4" flex={1} overflow="hidden">
|
||||
<ButtonGroup size="sm">
|
||||
<Button
|
||||
colorScheme="primary"
|
||||
leftIcon={<WritingIcon />}
|
||||
onClick={() =>
|
||||
openModal({
|
||||
cacheFormKey: communityCoordinate + "-new-post",
|
||||
initCommunity: communityCoordinate,
|
||||
requireSubject: true,
|
||||
})
|
||||
}
|
||||
>
|
||||
New Post
|
||||
</Button>
|
||||
<Divider orientation="vertical" h="2rem" />
|
||||
<Button leftIcon={<TrendUp01 />} isDisabled>
|
||||
Trending
|
||||
</Button>
|
||||
<Button
|
||||
leftIcon={<Clock />}
|
||||
as={RouterLink}
|
||||
to={getCommunityPath(community)}
|
||||
replace
|
||||
colorScheme={active === "new" ? "primary" : "gray"}
|
||||
>
|
||||
New
|
||||
</Button>
|
||||
<Button
|
||||
leftIcon={<Hourglass03 />}
|
||||
as={RouterLink}
|
||||
to={getCommunityPath(community) + "/pending"}
|
||||
replace
|
||||
colorScheme={active == "pending" ? "primary" : "gray"}
|
||||
>
|
||||
Pending
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<Outlet context={{ community, timeline }} />
|
||||
</Flex>
|
||||
|
||||
{!verticalLayout && (
|
||||
<VerticalCommunityDetails
|
||||
community={community}
|
||||
w="full"
|
||||
maxW="xs"
|
||||
flexShrink={0}
|
||||
onEditClick={editModal.onOpen}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
</VerticalPageLayout>
|
||||
</AdditionalRelayProvider>
|
||||
{editModal && <CommunityEditModal isOpen={editModal.isOpen} onClose={editModal.onClose} community={community} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
88
src/views/community/components/community-edit-modal.tsx
Normal file
88
src/views/community/components/community-edit-modal.tsx
Normal file
@ -0,0 +1,88 @@
|
||||
import { useMemo } from "react";
|
||||
import { ModalProps, useDisclosure, useToast } from "@chakra-ui/react";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import { DraftNostrEvent, NostrEvent } from "../../../types/nostr-event";
|
||||
import { useSigningContext } from "../../../providers/signing-provider";
|
||||
import {
|
||||
COMMUNITY_DEFINITION_KIND,
|
||||
getCommunityDescription,
|
||||
getCommunityImage,
|
||||
getCommunityMods,
|
||||
getCommunityName,
|
||||
getCommunityRanking,
|
||||
getCommunityRelays,
|
||||
getCommunityRules,
|
||||
} from "../../../helpers/nostr/communities";
|
||||
import CommunityCreateModal, { FormValues } from "../../communities/components/community-create-modal";
|
||||
import NostrPublishAction from "../../../classes/nostr-publish-action";
|
||||
import clientRelaysService from "../../../services/client-relays";
|
||||
import { unique } from "../../../helpers/array";
|
||||
import replaceableEventLoaderService from "../../../services/replaceable-event-requester";
|
||||
|
||||
export default function CommunityEditModal({
|
||||
isOpen,
|
||||
onClose,
|
||||
community,
|
||||
...props
|
||||
}: Omit<ModalProps, "children"> & { community: NostrEvent }) {
|
||||
const toast = useToast();
|
||||
const { requestSignature } = useSigningContext();
|
||||
|
||||
const defaultValues = useMemo<FormValues>(
|
||||
() => ({
|
||||
name: getCommunityName(community),
|
||||
description: getCommunityDescription(community) || "",
|
||||
banner: getCommunityImage(community) || "",
|
||||
rules: getCommunityRules(community) || "",
|
||||
mods: getCommunityMods(community) || [],
|
||||
relays: getCommunityRelays(community) || [],
|
||||
ranking: getCommunityRanking(community) || "votes",
|
||||
}),
|
||||
[community],
|
||||
);
|
||||
|
||||
const updateCommunity = async (values: FormValues) => {
|
||||
try {
|
||||
const draft: DraftNostrEvent = {
|
||||
kind: COMMUNITY_DEFINITION_KIND,
|
||||
created_at: dayjs().unix(),
|
||||
content: "",
|
||||
tags: [["d", getCommunityName(community)]],
|
||||
};
|
||||
|
||||
for (const pubkey of values.mods) {
|
||||
draft.tags.push(["p", pubkey, "moderator"]);
|
||||
}
|
||||
for (const url of values.relays) {
|
||||
draft.tags.push(["relay", url]);
|
||||
}
|
||||
|
||||
if (values.description) draft.tags.push(["description", values.description]);
|
||||
if (values.banner) draft.tags.push(["image", values.banner]);
|
||||
if (values.ranking) draft.tags.push(["rank_mode", values.ranking]);
|
||||
|
||||
const signed = await requestSignature(draft);
|
||||
new NostrPublishAction(
|
||||
"Update Community",
|
||||
unique([...clientRelaysService.getWriteUrls(), ...values.relays]),
|
||||
signed,
|
||||
);
|
||||
|
||||
replaceableEventLoaderService.handleEvent(signed);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) toast({ description: e.message, status: "error" });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<CommunityCreateModal
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
onSubmit={updateCommunity}
|
||||
defaultValues={defaultValues}
|
||||
isUpdate
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
@ -7,11 +7,15 @@ import { CodeIcon, ExternalLinkIcon, RepostIcon } from "../../../components/icon
|
||||
import NoteDebugModal from "../../../components/debug-modals/note-debug-modal";
|
||||
import { buildAppSelectUrl } from "../../../helpers/nostr/apps";
|
||||
import { getSharableEventAddress } from "../../../helpers/nip19";
|
||||
import { useCurrentAccount } from "../../../hooks/use-current-account";
|
||||
import PencilLine from "../../../components/icons/pencil-line";
|
||||
|
||||
export default function CommunityMenu({
|
||||
community,
|
||||
onEditClick,
|
||||
...props
|
||||
}: Omit<MenuIconButtonProps, "children"> & { community: NostrEvent }) {
|
||||
}: Omit<MenuIconButtonProps, "children"> & { community: NostrEvent; onEditClick?: () => void }) {
|
||||
const account = useCurrentAccount();
|
||||
const debugModal = useDisclosure();
|
||||
const [_clipboardState, copyToClipboard] = useCopyToClipboard();
|
||||
|
||||
@ -25,6 +29,11 @@ export default function CommunityMenu({
|
||||
View in app...
|
||||
</MenuItem>
|
||||
)}
|
||||
{account?.pubkey === community.pubkey && onEditClick && (
|
||||
<MenuItem onClick={onEditClick} icon={<PencilLine />}>
|
||||
Edit Community
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem onClick={() => copyToClipboard("nostr:" + address)} icon={<RepostIcon />}>
|
||||
Copy Share Link
|
||||
</MenuItem>
|
||||
|
@ -30,8 +30,9 @@ import CommunityMembersModal from "./community-members-modal";
|
||||
|
||||
export default function HorizontalCommunityDetails({
|
||||
community,
|
||||
onEditClick,
|
||||
...props
|
||||
}: Omit<CardProps, "children"> & { community: NostrEvent }) {
|
||||
}: Omit<CardProps, "children"> & { community: NostrEvent; onEditClick?: () => void }) {
|
||||
const membersModal = useDisclosure();
|
||||
const communityRelays = getCommunityRelays(community);
|
||||
const mods = getCommunityMods(community);
|
||||
@ -47,7 +48,7 @@ export default function HorizontalCommunityDetails({
|
||||
<CardBody>
|
||||
<ButtonGroup float="right">
|
||||
<CommunityJoinButton community={community} />
|
||||
<CommunityMenu community={community} aria-label="More" />
|
||||
<CommunityMenu community={community} aria-label="More" onEditClick={onEditClick} />
|
||||
</ButtonGroup>
|
||||
{description && (
|
||||
<>
|
||||
|
@ -18,8 +18,9 @@ import { readablizeSats } from "../../../helpers/bolt11";
|
||||
|
||||
export default function VerticalCommunityDetails({
|
||||
community,
|
||||
onEditClick,
|
||||
...props
|
||||
}: Omit<CardProps, "children"> & { community: NostrEvent }) {
|
||||
}: Omit<CardProps, "children"> & { community: NostrEvent; onEditClick?: () => void }) {
|
||||
const membersModal = useDisclosure();
|
||||
const communityRelays = getCommunityRelays(community);
|
||||
const mods = getCommunityMods(community);
|
||||
@ -41,7 +42,7 @@ export default function VerticalCommunityDetails({
|
||||
)}
|
||||
<ButtonGroup w="full">
|
||||
<CommunityJoinButton community={community} flex={1} />
|
||||
<CommunityMenu community={community} aria-label="More" />
|
||||
<CommunityMenu community={community} aria-label="More" onEditClick={onEditClick} />
|
||||
</ButtonGroup>
|
||||
<Box>
|
||||
<Heading size="sm" mb="1">
|
||||
|
Loading…
x
Reference in New Issue
Block a user