2023-12-26 18:15:26 +00:00
|
|
|
import { useState } from "react";
|
2024-01-04 10:43:45 +00:00
|
|
|
import { EventExt, NostrEvent, NostrLink, TaggedNostrEvent } from "@snort/system";
|
2023-11-09 12:20:53 +00:00
|
|
|
import { useReactions } from "@snort/system-react";
|
2023-05-10 11:32:09 +00:00
|
|
|
|
2023-11-17 11:52:10 +00:00
|
|
|
import PageSpinner from "@/Element/PageSpinner";
|
|
|
|
import Note from "@/Element/Event/Note";
|
|
|
|
import NostrBandApi from "@/External/NostrBand";
|
|
|
|
import { ErrorOrOffline } from "@/Element/ErrorOrOffline";
|
|
|
|
import { useLocale } from "@/IntlProvider";
|
|
|
|
import useModeration from "@/Hooks/useModeration";
|
2023-11-30 10:52:13 +00:00
|
|
|
import ShortNote from "@/Element/Trending/ShortNote";
|
|
|
|
import classNames from "classnames";
|
2023-12-07 11:33:36 +00:00
|
|
|
import { DisplayAs, DisplayAsSelector } from "@/Element/Feed/DisplayAsSelector";
|
|
|
|
import ImageGridItem from "@/Element/Feed/ImageGridItem";
|
2023-12-07 11:56:03 +00:00
|
|
|
import { SpotlightThreadModal } from "@/Element/Spotlight/SpotlightThreadModal";
|
|
|
|
import useLogin from "@/Hooks/useLogin";
|
2023-12-26 18:15:26 +00:00
|
|
|
import useCachedFetch from "@/Hooks/useCachedFetch";
|
2024-01-03 18:21:35 +00:00
|
|
|
import { System } from "@/index";
|
2023-05-10 11:32:09 +00:00
|
|
|
|
2024-01-04 10:43:45 +00:00
|
|
|
export default function TrendingNotes({ count = Infinity, small = false }: { count: number, small: boolean }) {
|
2023-12-26 18:15:26 +00:00
|
|
|
const api = new NostrBandApi();
|
|
|
|
const { lang } = useLocale();
|
2023-12-27 20:31:57 +00:00
|
|
|
const trendingNotesUrl = api.trendingNotesUrl(lang);
|
2023-12-26 18:15:26 +00:00
|
|
|
const storageKey = `nostr-band-${trendingNotesUrl}`;
|
|
|
|
|
|
|
|
const {
|
|
|
|
data: trendingNotesData,
|
|
|
|
isLoading,
|
|
|
|
error,
|
2024-01-04 10:43:45 +00:00
|
|
|
} = useCachedFetch<{ notes: Array<{ event: NostrEvent }> }, Array<NostrEvent>>(trendingNotesUrl, storageKey, data => {
|
2024-01-03 18:21:35 +00:00
|
|
|
return data.notes.map(a => {
|
|
|
|
const ev = a.event;
|
2024-01-04 10:43:45 +00:00
|
|
|
if (!System.Optimizer.schnorrVerify(ev)) {
|
2024-01-03 18:21:35 +00:00
|
|
|
console.error(`Event with invalid sig\n\n${ev}\n\nfrom ${trendingNotesUrl}`);
|
|
|
|
return;
|
|
|
|
}
|
2024-01-04 10:43:45 +00:00
|
|
|
System.HandleEvent(ev as TaggedNostrEvent);
|
2024-01-03 18:21:35 +00:00
|
|
|
return ev;
|
|
|
|
});
|
|
|
|
});
|
2023-12-26 18:15:26 +00:00
|
|
|
|
2023-12-07 11:56:03 +00:00
|
|
|
const login = useLogin();
|
|
|
|
const displayAsInitial = small ? "list" : login.feedDisplayAs ?? "list";
|
|
|
|
const [displayAs, setDisplayAs] = useState<DisplayAs>(displayAsInitial);
|
2023-12-26 18:15:26 +00:00
|
|
|
const { isEventMuted } = useModeration();
|
|
|
|
const related = useReactions("trending", trendingNotesData?.map(a => NostrLink.fromEvent(a)) ?? [], undefined, true);
|
2023-12-07 11:56:03 +00:00
|
|
|
const [modalThread, setModalThread] = useState<NostrLink | undefined>(undefined);
|
2023-05-10 11:32:09 +00:00
|
|
|
|
2023-12-27 20:31:57 +00:00
|
|
|
if (error && !trendingNotesData) return <ErrorOrOffline error={error} className="p" />;
|
2023-12-26 18:15:26 +00:00
|
|
|
if (isLoading) return <PageSpinner />;
|
2023-05-10 11:32:09 +00:00
|
|
|
|
2023-12-26 18:15:26 +00:00
|
|
|
const filteredAndLimitedPosts = trendingNotesData
|
|
|
|
? trendingNotesData.filter(a => !isEventMuted(a)).slice(0, count)
|
|
|
|
: [];
|
2023-12-07 11:33:36 +00:00
|
|
|
|
|
|
|
const renderGrid = () => {
|
|
|
|
return (
|
|
|
|
<div className="grid grid-cols-3 gap-px md:gap-1">
|
2023-12-26 18:15:26 +00:00
|
|
|
{filteredAndLimitedPosts.map(e => (
|
2023-12-21 20:43:11 +00:00
|
|
|
<ImageGridItem
|
|
|
|
key={e.id}
|
|
|
|
event={e as TaggedNostrEvent}
|
|
|
|
onClick={() => setModalThread(NostrLink.fromEvent(e))}
|
|
|
|
/>
|
2023-12-07 11:33:36 +00:00
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const renderList = () => {
|
2023-12-26 18:15:26 +00:00
|
|
|
return filteredAndLimitedPosts.map(e =>
|
2023-12-07 11:33:36 +00:00
|
|
|
small ? (
|
2023-12-21 20:05:00 +00:00
|
|
|
<ShortNote key={e.id} event={e as TaggedNostrEvent} />
|
2023-12-07 11:33:36 +00:00
|
|
|
) : (
|
2023-12-26 18:15:26 +00:00
|
|
|
<Note
|
|
|
|
key={e.id}
|
|
|
|
data={e as TaggedNostrEvent}
|
|
|
|
related={related?.data ?? []}
|
|
|
|
depth={0}
|
|
|
|
options={{
|
|
|
|
showFooter: !small,
|
|
|
|
showReactionsLink: !small,
|
|
|
|
showMedia: !small,
|
|
|
|
longFormPreview: !small,
|
|
|
|
truncate: small,
|
|
|
|
showContextMenu: !small,
|
|
|
|
}}
|
|
|
|
/>
|
2023-12-07 11:33:36 +00:00
|
|
|
),
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2023-05-10 11:32:09 +00:00
|
|
|
return (
|
2023-11-30 11:14:29 +00:00
|
|
|
<div className={classNames("flex flex-col", { "gap-6": small, "py-4": small })}>
|
2023-12-07 11:33:36 +00:00
|
|
|
{!small && <DisplayAsSelector activeSelection={displayAs} onSelect={a => setDisplayAs(a)} />}
|
|
|
|
{displayAs === "grid" ? renderGrid() : renderList()}
|
2023-12-07 11:56:03 +00:00
|
|
|
{modalThread && (
|
|
|
|
<SpotlightThreadModal
|
|
|
|
thread={modalThread}
|
|
|
|
onClose={() => setModalThread(undefined)}
|
|
|
|
onBack={() => setModalThread(undefined)}
|
|
|
|
/>
|
|
|
|
)}
|
2023-11-25 19:19:22 +00:00
|
|
|
</div>
|
2023-05-10 11:32:09 +00:00
|
|
|
);
|
|
|
|
}
|