mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-04-12 05:39:18 +02:00
Add debug modal for community posts
This commit is contained in:
parent
8871aedae5
commit
7e92713182
46
src/components/debug-modals/community-post-debug-modal.tsx
Normal file
46
src/components/debug-modals/community-post-debug-modal.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import { Modal, ModalOverlay, ModalContent, ModalBody, ModalCloseButton, Flex } from "@chakra-ui/react";
|
||||
import { ModalProps } from "@chakra-ui/react";
|
||||
import { nip19 } from "nostr-tools";
|
||||
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
import RawJson from "./raw-json";
|
||||
import RawValue from "./raw-value";
|
||||
import RawPre from "./raw-pre";
|
||||
import userMetadataService from "../../services/user-metadata";
|
||||
import { getUserDisplayName } from "../../helpers/user-metadata";
|
||||
import { getEventCoordinate } from "../../helpers/nostr/events";
|
||||
|
||||
export default function CommunityPostDebugModal({
|
||||
event,
|
||||
community,
|
||||
approvals,
|
||||
...props
|
||||
}: { event: NostrEvent; community: NostrEvent; approvals: NostrEvent[] } & Omit<ModalProps, "children">) {
|
||||
return (
|
||||
<Modal {...props}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalCloseButton />
|
||||
<ModalBody p="4">
|
||||
<Flex gap="2" direction="column">
|
||||
<RawValue heading="Event Id" value={event.id} />
|
||||
<RawValue heading="Encoded id (NIP-19)" value={nip19.noteEncode(event.id)} />
|
||||
<RawValue heading="Community Coordinate" value={getEventCoordinate(community)} />
|
||||
<RawPre heading="Content" value={event.content} />
|
||||
<RawJson heading="JSON" json={event} />
|
||||
{approvals.map((approval) => (
|
||||
<RawJson
|
||||
key={approval.id}
|
||||
heading={`Approval by ${getUserDisplayName(
|
||||
userMetadataService.getSubject(approval.pubkey).value,
|
||||
approval.pubkey,
|
||||
)}`}
|
||||
json={approval}
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
87
src/views/community/components/community-post-menu.tsx
Normal file
87
src/views/community/components/community-post-menu.tsx
Normal file
@ -0,0 +1,87 @@
|
||||
import { MenuItem, useDisclosure } from "@chakra-ui/react";
|
||||
import { nip19 } from "nostr-tools";
|
||||
|
||||
import { CustomMenuIconButton, MenuIconButtonProps } from "../../../components/menu-icon-button";
|
||||
import { useCurrentAccount } from "../../../hooks/use-current-account";
|
||||
import { NostrEvent } from "../../../types/nostr-event";
|
||||
import { useMuteModalContext } from "../../../providers/mute-modal-provider";
|
||||
import useUserMuteFunctions from "../../../hooks/use-user-mute-functions";
|
||||
import { useDeleteEventContext } from "../../../providers/delete-event-provider";
|
||||
import { getSharableEventAddress } from "../../../helpers/nip19";
|
||||
import {
|
||||
CodeIcon,
|
||||
CopyToClipboardIcon,
|
||||
ExternalLinkIcon,
|
||||
MuteIcon,
|
||||
RepostIcon,
|
||||
TrashIcon,
|
||||
UnmuteIcon,
|
||||
} from "../../../components/icons";
|
||||
import { buildAppSelectUrl } from "../../../helpers/nostr/apps";
|
||||
import CommunityPostDebugModal from "../../../components/debug-modals/community-post-debug-modal";
|
||||
|
||||
export default function CommunityPostMenu({
|
||||
event,
|
||||
community,
|
||||
approvals,
|
||||
...props
|
||||
}: Omit<MenuIconButtonProps, "children"> & { event: NostrEvent; community: NostrEvent; approvals: NostrEvent[] }) {
|
||||
const account = useCurrentAccount();
|
||||
const debugModal = useDisclosure();
|
||||
|
||||
// const { isMuted, unmute } = useUserMuteFunctions(event.pubkey);
|
||||
// const { openModal } = useMuteModalContext();
|
||||
|
||||
const { deleteEvent } = useDeleteEventContext();
|
||||
|
||||
const noteId = nip19.noteEncode(event.id);
|
||||
const address = getSharableEventAddress(event);
|
||||
|
||||
return (
|
||||
<>
|
||||
<CustomMenuIconButton {...props}>
|
||||
{address && (
|
||||
<MenuItem onClick={() => window.open(buildAppSelectUrl(address), "_blank")} icon={<ExternalLinkIcon />}>
|
||||
View in app...
|
||||
</MenuItem>
|
||||
)}
|
||||
{/* {account?.pubkey !== event.pubkey && (
|
||||
<MenuItem
|
||||
onClick={isMuted ? unmute : () => openModal(event.pubkey)}
|
||||
icon={isMuted ? <UnmuteIcon /> : <MuteIcon />}
|
||||
color="red.500"
|
||||
>
|
||||
{isMuted ? "Unmute User" : "Mute User"}
|
||||
</MenuItem>
|
||||
)} */}
|
||||
<MenuItem onClick={() => window.navigator.clipboard.writeText("nostr:" + address)} icon={<RepostIcon />}>
|
||||
Copy Share Link
|
||||
</MenuItem>
|
||||
{noteId && (
|
||||
<MenuItem onClick={() => window.navigator.clipboard.writeText(noteId)} icon={<CopyToClipboardIcon />}>
|
||||
Copy Note ID
|
||||
</MenuItem>
|
||||
)}
|
||||
{account?.pubkey === event.pubkey && (
|
||||
<MenuItem icon={<TrashIcon />} color="red.500" onClick={() => deleteEvent(event)}>
|
||||
Delete Note
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem onClick={debugModal.onOpen} icon={<CodeIcon />}>
|
||||
View Raw
|
||||
</MenuItem>
|
||||
</CustomMenuIconButton>
|
||||
|
||||
{debugModal.isOpen && (
|
||||
<CommunityPostDebugModal
|
||||
event={event}
|
||||
isOpen={debugModal.isOpen}
|
||||
onClose={debugModal.onClose}
|
||||
size="6xl"
|
||||
approvals={approvals}
|
||||
community={community}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,5 +1,15 @@
|
||||
import { MouseEventHandler, useCallback, useRef } from "react";
|
||||
import { AvatarGroup, Card, CardBody, CardFooter, CardHeader, Heading, LinkBox, Text } from "@chakra-ui/react";
|
||||
import {
|
||||
AvatarGroup,
|
||||
Card,
|
||||
CardBody,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardProps,
|
||||
Heading,
|
||||
LinkBox,
|
||||
Text,
|
||||
} from "@chakra-ui/react";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import dayjs from "dayjs";
|
||||
import { Kind } from "nostr-tools";
|
||||
@ -17,6 +27,7 @@ import UserAvatarLink from "../../../components/user-avatar-link";
|
||||
import useUserMuteFilter from "../../../hooks/use-user-mute-filter";
|
||||
import { useReadRelayUrls } from "../../../hooks/use-client-relays";
|
||||
import useSingleEvent from "../../../hooks/use-single-event";
|
||||
import CommunityPostMenu from "./community-post-menu";
|
||||
|
||||
export function ApprovalIcon({ approval }: { approval: NostrEvent }) {
|
||||
const ref = useRef<HTMLAnchorElement | null>(null);
|
||||
@ -71,12 +82,17 @@ function Approvals({ approvals }: { approvals: NostrEvent[] }) {
|
||||
);
|
||||
}
|
||||
|
||||
export function CommunityTextPost({ event, approvals, community }: CommunityPostPropTypes) {
|
||||
export function CommunityTextPost({
|
||||
event,
|
||||
approvals,
|
||||
community,
|
||||
...props
|
||||
}: Omit<CardProps, "children"> & CommunityPostPropTypes) {
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
useRegisterIntersectionEntity(ref, getEventUID(event));
|
||||
|
||||
return (
|
||||
<Card as={LinkBox} overflow="hidden" ref={ref}>
|
||||
<Card as={LinkBox} ref={ref} {...props}>
|
||||
<PostSubject event={event} />
|
||||
<CardBody p="2">
|
||||
<InlineNoteContent event={event} maxLength={96} />
|
||||
@ -86,12 +102,25 @@ export function CommunityTextPost({ event, approvals, community }: CommunityPost
|
||||
Posted {dayjs.unix(event.created_at).fromNow()} by <UserLink pubkey={event.pubkey} fontWeight="bold" />
|
||||
</Text>
|
||||
{approvals.length > 0 && <Approvals approvals={approvals} />}
|
||||
<CommunityPostMenu
|
||||
event={event}
|
||||
community={community}
|
||||
approvals={approvals}
|
||||
aria-label="More Options"
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
/>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export function CommunityRepostPost({ event, approvals, community }: CommunityPostPropTypes) {
|
||||
export function CommunityRepostPost({
|
||||
event,
|
||||
approvals,
|
||||
community,
|
||||
...props
|
||||
}: Omit<CardProps, "children"> & CommunityPostPropTypes) {
|
||||
const encodedRepost = parseHardcodedNoteContent(event);
|
||||
|
||||
const [_, eventId, relay] = event.tags.find(isETag) ?? [];
|
||||
@ -107,7 +136,7 @@ export function CommunityRepostPost({ event, approvals, community }: CommunityPo
|
||||
if (repost && muteFilter(repost)) return;
|
||||
|
||||
return (
|
||||
<Card as={LinkBox} overflow="hidden" ref={ref}>
|
||||
<Card as={LinkBox} ref={ref} {...props}>
|
||||
{repost && (
|
||||
<>
|
||||
<PostSubject event={repost} />
|
||||
@ -121,17 +150,30 @@ export function CommunityRepostPost({ event, approvals, community }: CommunityPo
|
||||
Shared {dayjs.unix(event.created_at).fromNow()} by <UserLink pubkey={event.pubkey} fontWeight="bold" />
|
||||
</Text>
|
||||
{approvals.length > 0 && <Approvals approvals={approvals} />}
|
||||
<CommunityPostMenu
|
||||
event={event}
|
||||
community={community}
|
||||
approvals={approvals}
|
||||
aria-label="More Options"
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
/>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default function CommunityPost({ event, approvals, community }: CommunityPostPropTypes) {
|
||||
export default function CommunityPost({
|
||||
event,
|
||||
approvals,
|
||||
community,
|
||||
...props
|
||||
}: Omit<CardProps, "children"> & CommunityPostPropTypes) {
|
||||
switch (event.kind) {
|
||||
case Kind.Text:
|
||||
return <CommunityTextPost event={event} approvals={approvals} community={community} />;
|
||||
return <CommunityTextPost event={event} approvals={approvals} community={community} {...props} />;
|
||||
case Kind.Repost:
|
||||
return <CommunityRepostPost event={event} approvals={approvals} community={community} />;
|
||||
return <CommunityRepostPost event={event} approvals={approvals} community={community} {...props} />;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { Card, IconButton, Text, useToast } from "@chakra-ui/react";
|
||||
import { Card, CardProps, IconButton, Text, useToast } from "@chakra-ui/react";
|
||||
|
||||
import { useCurrentAccount } from "../../../hooks/use-current-account";
|
||||
import useEventReactions from "../../../hooks/use-event-reactions";
|
||||
@ -13,7 +13,11 @@ import NostrPublishAction from "../../../classes/nostr-publish-action";
|
||||
import { ChevronDownIcon, ChevronUpIcon } from "../../../components/icons";
|
||||
import { NostrEvent } from "../../../types/nostr-event";
|
||||
|
||||
export default function PostVoteButtons({ event, community }: { event: NostrEvent; community: NostrEvent }) {
|
||||
export default function PostVoteButtons({
|
||||
event,
|
||||
community,
|
||||
...props
|
||||
}: Omit<CardProps, "children"> & { event: NostrEvent; community: NostrEvent }) {
|
||||
const account = useCurrentAccount();
|
||||
const reactions = useEventReactions(event.id);
|
||||
const toast = useToast();
|
||||
@ -50,7 +54,7 @@ export default function PostVoteButtons({ event, community }: { event: NostrEven
|
||||
);
|
||||
|
||||
return (
|
||||
<Card direction="column" alignItems="center" borderRadius="lg">
|
||||
<Card direction="column" alignItems="center" borderRadius="lg" {...props}>
|
||||
<IconButton
|
||||
aria-label="up vote"
|
||||
title="up vote"
|
||||
|
@ -11,15 +11,14 @@ import TimelineActionAndStatus from "../../../components/timeline-page/timeline-
|
||||
import PostVoteButtons from "../components/post-vote-buttions";
|
||||
import TimelineLoader from "../../../classes/timeline-loader";
|
||||
import CommunityPost from "../components/community-post";
|
||||
import useUserMuteFilter from "../../../hooks/use-user-mute-filter";
|
||||
|
||||
const ApprovedEvent = memo(
|
||||
({ event, approvals, community }: { event: NostrEvent; approvals: NostrEvent[]; community: NostrEvent }) => {
|
||||
return (
|
||||
<Flex gap="2" alignItems="flex-start" overflow="hidden">
|
||||
<PostVoteButtons event={event} community={community} />
|
||||
<Flex gap="2" direction="column" flex={1} overflow="hidden">
|
||||
<CommunityPost event={event} community={community} approvals={approvals} />
|
||||
</Flex>
|
||||
<Flex gap="2" alignItems="flex-start">
|
||||
<PostVoteButtons event={event} community={community} flexShrink={0} />
|
||||
<CommunityPost event={event} community={community} approvals={approvals} flex={1} />
|
||||
</Flex>
|
||||
);
|
||||
},
|
||||
@ -27,6 +26,7 @@ const ApprovedEvent = memo(
|
||||
|
||||
export default function CommunityNewestView() {
|
||||
const { community, timeline } = useOutletContext() as { community: NostrEvent; timeline: TimelineLoader };
|
||||
const muteFilter = useUserMuteFilter();
|
||||
const mods = getCommunityMods(community);
|
||||
|
||||
const events = useSubject(timeline.timeline);
|
||||
@ -34,7 +34,8 @@ export default function CommunityNewestView() {
|
||||
|
||||
const approved = events
|
||||
.filter((e) => approvalMap.has(e.id))
|
||||
.map((event) => ({ event, approvals: approvalMap.get(event.id) }));
|
||||
.map((event) => ({ event, approvals: approvalMap.get(event.id) }))
|
||||
.filter((e) => !muteFilter(e.event));
|
||||
|
||||
const callback = useTimelineCurserIntersectionCallback(timeline);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user