snort/packages/app/src/Components/Trending/TrendingPosts.tsx

107 lines
3.6 KiB
TypeScript
Raw Normal View History

2024-01-04 17:01:18 +00:00
import { removeUndefined } from "@snort/shared";
2024-01-04 11:04:52 +00:00
import { NostrEvent, NostrLink, TaggedNostrEvent } from "@snort/system";
2024-01-04 17:01:18 +00:00
import classNames from "classnames";
2024-01-08 13:42:25 +00:00
import { useMemo, useState } from "react";
2023-05-10 11:32:09 +00:00
import { ErrorOrOffline } from "@/Components/ErrorOrOffline";
import Note from "@/Components/Event/EventComponent";
import { DisplayAs, DisplayAsSelector } from "@/Components/Feed/DisplayAsSelector";
import ImageGridItem from "@/Components/Feed/ImageGridItem";
2024-01-10 18:16:30 +00:00
import { useLocale } from "@/Components/IntlProvider/useLocale";
2024-01-04 17:01:18 +00:00
import PageSpinner from "@/Components/PageSpinner";
import { SpotlightThreadModal } from "@/Components/Spotlight/SpotlightThreadModal";
2024-01-04 17:01:18 +00:00
import ShortNote from "@/Components/Trending/ShortNote";
import NostrBandApi from "@/External/NostrBand";
import useCachedFetch from "@/Hooks/useCachedFetch";
2024-01-04 17:01:18 +00:00
import useLogin from "@/Hooks/useLogin";
import useModeration from "@/Hooks/useModeration";
2024-01-04 13:15:46 +00:00
import { System } from "@/system";
2023-05-10 11:32:09 +00:00
2024-01-11 08:39:03 +00:00
export default function TrendingNotes({ count = Infinity, small = false }: { count?: number; small?: boolean }) {
const api = new NostrBandApi();
const { lang } = useLocale();
const trendingNotesUrl = api.trendingNotesUrl(lang);
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-04 12:05:13 +00:00
return removeUndefined(
data.notes.map(a => {
const ev = a.event;
if (!System.optimizer.schnorrVerify(ev)) {
2024-01-04 12:05:13 +00:00
console.error(`Event with invalid sig\n\n${ev}\n\nfrom ${trendingNotesUrl}`);
return;
}
System.HandleEvent(ev as TaggedNostrEvent);
return ev;
}),
);
2024-01-03 18:21:35 +00:00
});
2024-01-08 13:42:25 +00:00
const options = useMemo(
() => ({
showFooter: !small,
showReactionsLink: !small,
showMedia: !small,
longFormPreview: !small,
truncate: small,
showContextMenu: !small,
}),
[small],
);
2023-12-07 11:56:03 +00:00
const login = useLogin();
const displayAsInitial = small ? "list" : login.feedDisplayAs ?? "list";
const [displayAs, setDisplayAs] = useState<DisplayAs>(displayAsInitial);
const { isEventMuted } = useModeration();
2023-12-07 11:56:03 +00:00
const [modalThread, setModalThread] = useState<NostrLink | undefined>(undefined);
2023-05-10 11:32:09 +00:00
if (error && !trendingNotesData) return <ErrorOrOffline error={error} className="p" />;
if (isLoading) return <PageSpinner />;
2023-05-10 11:32:09 +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">
{filteredAndLimitedPosts.map(e => (
<ImageGridItem
key={e.id}
event={e as TaggedNostrEvent}
onClick={() => setModalThread(NostrLink.fromEvent(e))}
/>
2023-12-07 11:33:36 +00:00
))}
</div>
);
};
const renderList = () => {
2024-01-08 13:42:25 +00:00
return filteredAndLimitedPosts.map((e, index) =>
2023-12-07 11:33:36 +00:00
small ? (
<ShortNote key={e.id} event={e as TaggedNostrEvent} />
2023-12-07 11:33:36 +00:00
) : (
2024-01-08 13:42:25 +00:00
<Note key={e.id} data={e as TaggedNostrEvent} depth={0} options={options} waitUntilInView={index > 5} />
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
);
}