mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-04-09 20:29:17 +02:00
Add approval button for pending community posts
This commit is contained in:
parent
62a729a805
commit
5f9c96e744
5
.changeset/large-wolves-perform.md
Normal file
5
.changeset/large-wolves-perform.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"nostrudel": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add approval button for pending community posts
|
@ -20,7 +20,7 @@ export function QuoteRepostButton({
|
|||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
const nevent = getSharableEventAddress(event);
|
const nevent = getSharableEventAddress(event);
|
||||||
openModal("\nnostr:" + nevent);
|
openModal({ initContent: "\nnostr:" + nevent });
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -55,11 +55,19 @@ type FormValues = {
|
|||||||
split: EventSplit;
|
split: EventSplit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type PostModalProps = {
|
||||||
|
cacheFormKey?: string;
|
||||||
|
initContent?: string;
|
||||||
|
initCommunity?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export default function PostModal({
|
export default function PostModal({
|
||||||
isOpen,
|
isOpen,
|
||||||
onClose,
|
onClose,
|
||||||
|
cacheFormKey = "new-note",
|
||||||
initContent = "",
|
initContent = "",
|
||||||
}: Omit<ModalProps, "children"> & { initContent?: string }) {
|
initCommunity = "",
|
||||||
|
}: Omit<ModalProps, "children"> & PostModalProps) {
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const account = useCurrentAccount()!;
|
const account = useCurrentAccount()!;
|
||||||
const { requestSignature } = useSigningContext();
|
const { requestSignature } = useSigningContext();
|
||||||
@ -73,7 +81,7 @@ export default function PostModal({
|
|||||||
content: initContent,
|
content: initContent,
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
nsfwReason: "",
|
nsfwReason: "",
|
||||||
community: "",
|
community: initCommunity,
|
||||||
split: [] as EventSplit,
|
split: [] as EventSplit,
|
||||||
},
|
},
|
||||||
mode: "all",
|
mode: "all",
|
||||||
@ -84,7 +92,7 @@ export default function PostModal({
|
|||||||
watch("split");
|
watch("split");
|
||||||
|
|
||||||
// cache form to localStorage
|
// cache form to localStorage
|
||||||
useCacheForm<FormValues>("new-note", getValues, setValue, formState);
|
useCacheForm<FormValues>(cacheFormKey, getValues, setValue, formState);
|
||||||
|
|
||||||
const textAreaRef = useRef<RefType | null>(null);
|
const textAreaRef = useRef<RefType | null>(null);
|
||||||
const imageUploadRef = useRef<HTMLInputElement | null>(null);
|
const imageUploadRef = useRef<HTMLInputElement | null>(null);
|
||||||
|
@ -29,6 +29,10 @@ export function getCommunityRules(community: NostrEvent) {
|
|||||||
return community.tags.find((t) => t[0] === "rules")?.[1];
|
return community.tags.find((t) => t[0] === "rules")?.[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getPostSubject(event: NostrEvent) {
|
||||||
|
return event.tags.find((t) => t[0] === "subject")?.[1] || event.content.match(/^[^\n\t]+/);
|
||||||
|
}
|
||||||
|
|
||||||
export function getApprovedEmbeddedNote(approval: NostrEvent) {
|
export function getApprovedEmbeddedNote(approval: NostrEvent) {
|
||||||
if (!approval.content) return null;
|
if (!approval.content) return null;
|
||||||
try {
|
try {
|
||||||
@ -48,10 +52,10 @@ export function validateCommunity(community: NostrEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildApprovalMap(events: Iterable<NostrEvent>) {
|
export function buildApprovalMap(events: Iterable<NostrEvent>, mods: string[]) {
|
||||||
const approvals = new Map<string, NostrEvent[]>();
|
const approvals = new Map<string, NostrEvent[]>();
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
if (event.kind === COMMUNITY_APPROVAL_KIND) {
|
if (event.kind === COMMUNITY_APPROVAL_KIND && mods.includes(event.pubkey)) {
|
||||||
for (const tag of event.tags) {
|
for (const tag of event.tags) {
|
||||||
if (isETag(tag)) {
|
if (isETag(tag)) {
|
||||||
const arr = approvals.get(tag[1]);
|
const arr = approvals.get(tag[1]);
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { COMMUNITY_DEFINITION_KIND, SUBSCRIBED_COMMUNITIES_LIST_IDENTIFIER } from "../helpers/nostr/communities";
|
import { COMMUNITY_DEFINITION_KIND, SUBSCRIBED_COMMUNITIES_LIST_IDENTIFIER } from "../helpers/nostr/communities";
|
||||||
import { NOTE_LIST_KIND, getParsedCordsFromList } from "../helpers/nostr/lists";
|
import { NOTE_LIST_KIND, getParsedCordsFromList } from "../helpers/nostr/lists";
|
||||||
|
import { RequestOptions } from "../services/replaceable-event-requester";
|
||||||
import { useCurrentAccount } from "./use-current-account";
|
import { useCurrentAccount } from "./use-current-account";
|
||||||
import useReplaceableEvent from "./use-replaceable-event";
|
import useReplaceableEvent from "./use-replaceable-event";
|
||||||
|
|
||||||
export default function useSubscribedCommunitiesList(pubkey?: string) {
|
export default function useSubscribedCommunitiesList(pubkey?: string, opts?: RequestOptions) {
|
||||||
const account = useCurrentAccount();
|
const account = useCurrentAccount();
|
||||||
const key = pubkey ?? account?.pubkey;
|
const key = pubkey ?? account?.pubkey;
|
||||||
|
|
||||||
@ -15,6 +16,8 @@ export default function useSubscribedCommunitiesList(pubkey?: string) {
|
|||||||
pubkey: key,
|
pubkey: key,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
|
[],
|
||||||
|
opts,
|
||||||
);
|
);
|
||||||
|
|
||||||
const pointers = list ? getParsedCordsFromList(list).filter((cord) => cord.kind === COMMUNITY_DEFINITION_KIND) : [];
|
const pointers = list ? getParsedCordsFromList(list).filter((cord) => cord.kind === COMMUNITY_DEFINITION_KIND) : [];
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import React, { PropsWithChildren, useCallback, useMemo, useState } from "react";
|
import React, { PropsWithChildren, useCallback, useMemo, useState } from "react";
|
||||||
import { useDisclosure } from "@chakra-ui/react";
|
import { useDisclosure } from "@chakra-ui/react";
|
||||||
import { ErrorBoundary } from "../components/error-boundary";
|
import { ErrorBoundary } from "../components/error-boundary";
|
||||||
import PostModal from "../components/post-modal";
|
import PostModal, { PostModalProps } from "../components/post-modal";
|
||||||
|
|
||||||
export type PostModalContextType = {
|
export type PostModalContextType = {
|
||||||
openModal: (content?: string) => void;
|
openModal: (props?: PostModalProps) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PostModalContext = React.createContext<PostModalContextType>({
|
export const PostModalContext = React.createContext<PostModalContextType>({
|
||||||
@ -13,20 +13,26 @@ export const PostModalContext = React.createContext<PostModalContextType>({
|
|||||||
|
|
||||||
export default function PostModalProvider({ children }: PropsWithChildren) {
|
export default function PostModalProvider({ children }: PropsWithChildren) {
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
const [initContent, setInitContent] = useState("");
|
const [initProps, setInitProps] = useState<PostModalProps>({});
|
||||||
|
|
||||||
const openModal = useCallback(
|
const openModal = useCallback(
|
||||||
(content?: string) => {
|
(props?: PostModalProps) => {
|
||||||
if (content) setInitContent(content);
|
setInitProps(props ?? {});
|
||||||
onOpen();
|
onOpen();
|
||||||
},
|
},
|
||||||
[onOpen, setInitContent],
|
[onOpen, setInitProps],
|
||||||
);
|
);
|
||||||
|
const closeModal = useCallback(() => {
|
||||||
|
setInitProps({});
|
||||||
|
onClose();
|
||||||
|
}, [onOpen, setInitProps]);
|
||||||
|
|
||||||
const context = useMemo(() => ({ openModal }), [openModal]);
|
const context = useMemo(() => ({ openModal }), [openModal]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PostModalContext.Provider value={context}>
|
<PostModalContext.Provider value={context}>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
{isOpen && <PostModal isOpen={isOpen} onClose={onClose} initContent={initContent} />}
|
{isOpen && <PostModal {...initProps} isOpen={isOpen} onClose={closeModal} />}
|
||||||
{children}
|
{children}
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</PostModalContext.Provider>
|
</PostModalContext.Provider>
|
||||||
|
@ -20,7 +20,7 @@ function LoadCommunityCard({ pointer }: { pointer: AddressPointer }) {
|
|||||||
|
|
||||||
function CommunitiesHomePage() {
|
function CommunitiesHomePage() {
|
||||||
const account = useCurrentAccount()!;
|
const account = useCurrentAccount()!;
|
||||||
const { pointers: communities } = useSubscribedCommunitiesList(account.pubkey);
|
const { pointers: communities } = useSubscribedCommunitiesList(account.pubkey, { alwaysRequest: true });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VerticalPageLayout>
|
<VerticalPageLayout>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Button, ButtonGroup, Flex, Heading, Text } from "@chakra-ui/react";
|
import { Button, ButtonGroup, Divider, Flex, Heading, Text } from "@chakra-ui/react";
|
||||||
import { Outlet, Link as RouterLink, useLocation } from "react-router-dom";
|
import { Outlet, Link as RouterLink, useLocation } from "react-router-dom";
|
||||||
import { Kind, nip19 } from "nostr-tools";
|
import { Kind, nip19 } from "nostr-tools";
|
||||||
|
|
||||||
@ -23,6 +23,9 @@ import HorizontalCommunityDetails from "./components/horizonal-community-details
|
|||||||
import { useReadRelayUrls } from "../../hooks/use-client-relays";
|
import { useReadRelayUrls } from "../../hooks/use-client-relays";
|
||||||
import useTimelineLoader from "../../hooks/use-timeline-loader";
|
import useTimelineLoader from "../../hooks/use-timeline-loader";
|
||||||
import { getEventCoordinate, getEventUID } from "../../helpers/nostr/events";
|
import { getEventCoordinate, getEventUID } from "../../helpers/nostr/events";
|
||||||
|
import { WritingIcon } from "../../components/icons";
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { PostModalContext } from "../../providers/post-modal-provider";
|
||||||
|
|
||||||
function getCommunityPath(community: NostrEvent) {
|
function getCommunityPath(community: NostrEvent) {
|
||||||
return `/c/${encodeURIComponent(getCommunityName(community))}/${nip19.npubEncode(community.pubkey)}`;
|
return `/c/${encodeURIComponent(getCommunityName(community))}/${nip19.npubEncode(community.pubkey)}`;
|
||||||
@ -31,6 +34,8 @@ function getCommunityPath(community: NostrEvent) {
|
|||||||
export default function CommunityHomePage({ community }: { community: NostrEvent }) {
|
export default function CommunityHomePage({ community }: { community: NostrEvent }) {
|
||||||
const image = getCommunityImage(community);
|
const image = getCommunityImage(community);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const { openModal } = useContext(PostModalContext);
|
||||||
|
const communityCoordinate = getEventCoordinate(community);
|
||||||
|
|
||||||
const verticalLayout = useBreakpointValue({ base: true, xl: false });
|
const verticalLayout = useBreakpointValue({ base: true, xl: false });
|
||||||
|
|
||||||
@ -38,7 +43,7 @@ export default function CommunityHomePage({ community }: { community: NostrEvent
|
|||||||
const readRelays = useReadRelayUrls(communityRelays);
|
const readRelays = useReadRelayUrls(communityRelays);
|
||||||
const timeline = useTimelineLoader(`${getEventUID(community)}-timeline`, readRelays, {
|
const timeline = useTimelineLoader(`${getEventUID(community)}-timeline`, readRelays, {
|
||||||
kinds: [Kind.Text, COMMUNITY_APPROVAL_KIND],
|
kinds: [Kind.Text, COMMUNITY_APPROVAL_KIND],
|
||||||
"#a": [getEventCoordinate(community)],
|
"#a": [communityCoordinate],
|
||||||
});
|
});
|
||||||
|
|
||||||
let active = "new";
|
let active = "new";
|
||||||
@ -73,6 +78,16 @@ export default function CommunityHomePage({ community }: { community: NostrEvent
|
|||||||
<Flex gap="4" alignItems="flex-start" overflow="hidden">
|
<Flex gap="4" alignItems="flex-start" overflow="hidden">
|
||||||
<Flex direction="column" gap="4" flex={1} overflow="hidden">
|
<Flex direction="column" gap="4" flex={1} overflow="hidden">
|
||||||
<ButtonGroup size="sm">
|
<ButtonGroup size="sm">
|
||||||
|
<Button
|
||||||
|
colorScheme="primary"
|
||||||
|
leftIcon={<WritingIcon />}
|
||||||
|
onClick={() =>
|
||||||
|
openModal({ cacheFormKey: communityCoordinate + "-new-post", initCommunity: communityCoordinate })
|
||||||
|
}
|
||||||
|
>
|
||||||
|
New Post
|
||||||
|
</Button>
|
||||||
|
<Divider orientation="vertical" h="2rem" />
|
||||||
<Button leftIcon={<TrendUp01 />} isDisabled>
|
<Button leftIcon={<TrendUp01 />} isDisabled>
|
||||||
Trending
|
Trending
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -3,7 +3,7 @@ import { AvatarGroup, Card, CardBody, CardFooter, CardHeader, Flex, Heading, Lin
|
|||||||
import { useOutletContext, Link as RouterLink } from "react-router-dom";
|
import { useOutletContext, Link as RouterLink } from "react-router-dom";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
import { COMMUNITY_APPROVAL_KIND, buildApprovalMap, getCommunityMods } from "../../../helpers/nostr/communities";
|
import { buildApprovalMap, getCommunityMods, getPostSubject } from "../../../helpers/nostr/communities";
|
||||||
import { getEventUID } from "../../../helpers/nostr/events";
|
import { getEventUID } from "../../../helpers/nostr/events";
|
||||||
import useSubject from "../../../hooks/use-subject";
|
import useSubject from "../../../hooks/use-subject";
|
||||||
import { useTimelineCurserIntersectionCallback } from "../../../hooks/use-timeline-cursor-intersection-callback";
|
import { useTimelineCurserIntersectionCallback } from "../../../hooks/use-timeline-cursor-intersection-callback";
|
||||||
@ -60,7 +60,7 @@ const ApprovedEvent = memo(
|
|||||||
<CardHeader px="2" pt="4" pb="0">
|
<CardHeader px="2" pt="4" pb="0">
|
||||||
<Heading size="md">
|
<Heading size="md">
|
||||||
<HoverLinkOverlay as={RouterLink} to={to} onClick={handleClick}>
|
<HoverLinkOverlay as={RouterLink} to={to} onClick={handleClick}>
|
||||||
{event.content.match(/^[^\n\t]+/)}
|
{getPostSubject(event)}
|
||||||
</HoverLinkOverlay>
|
</HoverLinkOverlay>
|
||||||
</Heading>
|
</Heading>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
@ -92,13 +92,12 @@ export default function CommunityNewestView() {
|
|||||||
const mods = getCommunityMods(community);
|
const mods = getCommunityMods(community);
|
||||||
|
|
||||||
const events = useSubject(timeline.timeline);
|
const events = useSubject(timeline.timeline);
|
||||||
const approvalMap = buildApprovalMap(events);
|
const approvalMap = buildApprovalMap(events, mods);
|
||||||
|
|
||||||
const approved = events
|
const approved = events
|
||||||
.filter((e) => approvalMap.has(e.id))
|
.filter((e) => approvalMap.has(e.id))
|
||||||
.map((event) => ({ event, approvals: approvalMap.get(event.id) }));
|
.map((event) => ({ event, approvals: approvalMap.get(event.id) }));
|
||||||
|
|
||||||
const approvals = events.filter((e) => e.kind === COMMUNITY_APPROVAL_KIND && mods.includes(e.pubkey));
|
|
||||||
const callback = useTimelineCurserIntersectionCallback(timeline);
|
const callback = useTimelineCurserIntersectionCallback(timeline);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,18 +1,87 @@
|
|||||||
import { useRef } from "react";
|
import { useCallback, useRef, useState } from "react";
|
||||||
import { Box } from "@chakra-ui/react";
|
import { Box, Button, Flex, useToast } from "@chakra-ui/react";
|
||||||
import { useOutletContext } from "react-router-dom";
|
import { useOutletContext } from "react-router-dom";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
import { NostrEvent } from "../../../types/nostr-event";
|
import { DraftNostrEvent, NostrEvent } from "../../../types/nostr-event";
|
||||||
import { getEventUID } from "../../../helpers/nostr/events";
|
import { getEventCoordinate, getEventUID } from "../../../helpers/nostr/events";
|
||||||
import { COMMUNITY_APPROVAL_KIND, buildApprovalMap } from "../../../helpers/nostr/communities";
|
import {
|
||||||
|
COMMUNITY_APPROVAL_KIND,
|
||||||
|
buildApprovalMap,
|
||||||
|
getCommunityMods,
|
||||||
|
getCommunityRelays,
|
||||||
|
} from "../../../helpers/nostr/communities";
|
||||||
import useSubject from "../../../hooks/use-subject";
|
import useSubject from "../../../hooks/use-subject";
|
||||||
import IntersectionObserverProvider, { useRegisterIntersectionEntity } from "../../../providers/intersection-observer";
|
import IntersectionObserverProvider, { useRegisterIntersectionEntity } from "../../../providers/intersection-observer";
|
||||||
import { EmbedEvent } from "../../../components/embed-event";
|
import { EmbedEvent } from "../../../components/embed-event";
|
||||||
import { useTimelineCurserIntersectionCallback } from "../../../hooks/use-timeline-cursor-intersection-callback";
|
import { useTimelineCurserIntersectionCallback } from "../../../hooks/use-timeline-cursor-intersection-callback";
|
||||||
import TimelineActionAndStatus from "../../../components/timeline-page/timeline-action-and-status";
|
import TimelineActionAndStatus from "../../../components/timeline-page/timeline-action-and-status";
|
||||||
import TimelineLoader from "../../../classes/timeline-loader";
|
import TimelineLoader from "../../../classes/timeline-loader";
|
||||||
|
import { CheckIcon } from "../../../components/icons";
|
||||||
|
import { useSigningContext } from "../../../providers/signing-provider";
|
||||||
|
import { useCurrentAccount } from "../../../hooks/use-current-account";
|
||||||
|
import NostrPublishAction from "../../../classes/nostr-publish-action";
|
||||||
|
import { useWriteRelayUrls } from "../../../hooks/use-client-relays";
|
||||||
|
|
||||||
function PendingPost({ event }: { event: NostrEvent }) {
|
type PendingProps = {
|
||||||
|
event: NostrEvent;
|
||||||
|
community: NostrEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
function ModPendingPost({ event, community }: PendingProps) {
|
||||||
|
const toast = useToast();
|
||||||
|
const { requestSignature } = useSigningContext();
|
||||||
|
|
||||||
|
const ref = useRef<HTMLDivElement | null>(null);
|
||||||
|
useRegisterIntersectionEntity(ref, getEventUID(event));
|
||||||
|
|
||||||
|
const communityRelays = getCommunityRelays(community);
|
||||||
|
const writeRelays = useWriteRelayUrls(communityRelays);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const approve = useCallback(async () => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const relay = communityRelays[0];
|
||||||
|
const draft: DraftNostrEvent = {
|
||||||
|
kind: COMMUNITY_APPROVAL_KIND,
|
||||||
|
content: JSON.stringify(event),
|
||||||
|
created_at: dayjs().unix(),
|
||||||
|
tags: [
|
||||||
|
relay ? ["a", getEventCoordinate(community), relay] : ["a", getEventCoordinate(community)],
|
||||||
|
["e", event.id],
|
||||||
|
["p", event.pubkey],
|
||||||
|
["k", String(event.kind)],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const signed = await requestSignature(draft);
|
||||||
|
new NostrPublishAction("Approve", writeRelays, signed);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof Error) toast({ description: e.message, status: "error" });
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
}, [event, requestSignature, writeRelays, setLoading, community]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex direction="column" gap="2" ref={ref}>
|
||||||
|
<EmbedEvent event={event} />
|
||||||
|
<Flex gap="2">
|
||||||
|
<Button
|
||||||
|
colorScheme="primary"
|
||||||
|
leftIcon={<CheckIcon />}
|
||||||
|
size="sm"
|
||||||
|
ml="auto"
|
||||||
|
onClick={approve}
|
||||||
|
isLoading={loading}
|
||||||
|
>
|
||||||
|
Approve
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function PendingPost({ event }: PendingProps) {
|
||||||
const ref = useRef<HTMLDivElement | null>(null);
|
const ref = useRef<HTMLDivElement | null>(null);
|
||||||
useRegisterIntersectionEntity(ref, getEventUID(event));
|
useRegisterIntersectionEntity(ref, getEventUID(event));
|
||||||
|
|
||||||
@ -24,20 +93,25 @@ function PendingPost({ event }: { event: NostrEvent }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function CommunityPendingView() {
|
export default function CommunityPendingView() {
|
||||||
|
const account = useCurrentAccount();
|
||||||
const { community, timeline } = useOutletContext() as { community: NostrEvent; timeline: TimelineLoader };
|
const { community, timeline } = useOutletContext() as { community: NostrEvent; timeline: TimelineLoader };
|
||||||
|
|
||||||
const events = useSubject(timeline.timeline);
|
const events = useSubject(timeline.timeline);
|
||||||
|
|
||||||
const approvals = buildApprovalMap(events);
|
const mods = getCommunityMods(community);
|
||||||
|
const approvals = buildApprovalMap(events, mods);
|
||||||
const pending = events.filter((e) => e.kind !== COMMUNITY_APPROVAL_KIND && !approvals.has(e.id));
|
const pending = events.filter((e) => e.kind !== COMMUNITY_APPROVAL_KIND && !approvals.has(e.id));
|
||||||
|
|
||||||
const callback = useTimelineCurserIntersectionCallback(timeline);
|
const callback = useTimelineCurserIntersectionCallback(timeline);
|
||||||
|
|
||||||
|
const isMod = !!account && mods.includes(account?.pubkey);
|
||||||
|
const PostComponent = isMod ? ModPendingPost : PendingPost;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<IntersectionObserverProvider callback={callback}>
|
<IntersectionObserverProvider callback={callback}>
|
||||||
{pending.map((event) => (
|
{pending.map((event) => (
|
||||||
<PendingPost key={getEventUID(event)} event={event} />
|
<PostComponent key={getEventUID(event)} event={event} community={community} />
|
||||||
))}
|
))}
|
||||||
</IntersectionObserverProvider>
|
</IntersectionObserverProvider>
|
||||||
<TimelineActionAndStatus timeline={timeline} />
|
<TimelineActionAndStatus timeline={timeline} />
|
||||||
|
@ -23,7 +23,7 @@ export default function StreamShareButton({
|
|||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
const nevent = getSharableEventAddress(stream.event);
|
const nevent = getSharableEventAddress(stream.event);
|
||||||
openModal("\nnostr:" + nevent);
|
openModal({ initContent: "\nnostr:" + nevent });
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user