feat: discover page

This commit is contained in:
Kieran 2023-05-15 09:51:17 +01:00
parent 6fa242c5f9
commit 3e5b7ec4a6
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
9 changed files with 108 additions and 5 deletions

View File

@ -1,7 +1,7 @@
.profile-preview {
display: flex;
align-items: center;
min-height: 40px;
min-height: 59px;
}
.profile-preview .pfp {

View File

@ -0,0 +1,36 @@
import { useEffect, useState } from "react";
import { HexKey, NostrPrefix } from "@snort/nostr";
import { FormattedMessage } from "react-intl";
import FollowListBase from "Element/FollowListBase";
import PageSpinner from "Element/PageSpinner";
import NostrBandApi from "External/NostrBand";
import useLogin from "Hooks/useLogin";
import { hexToBech32 } from "Util";
export default function SuggestedProfiles() {
const login = useLogin();
const [userList, setUserList] = useState<HexKey[]>();
async function loadSuggestedProfiles() {
const api = new NostrBandApi();
const users = await api.sugguestedFollows(hexToBech32(NostrPrefix.PublicKey, login.publicKey));
const keys = users.profiles.map(a => a.pubkey);
setUserList(keys);
}
useEffect(() => {
loadSuggestedProfiles().catch(console.error);
}, []);
if (!userList) return <PageSpinner />;
return (
<>
<h3>
<FormattedMessage defaultMessage="Suggested Follows" />
</h3>
<FollowListBase pubkeys={userList} showAbout={true} />
</>
);
}

View File

@ -4,7 +4,7 @@ import { FormattedMessage } from "react-intl";
import PageSpinner from "Element/PageSpinner";
import Note from "Element/Note";
import NostrBandApi from "NostrBand";
import NostrBandApi from "External/NostrBand";
export default function TrendingNotes() {
const [posts, setPosts] = useState<Array<RawEvent>>();

View File

@ -4,7 +4,7 @@ import { FormattedMessage } from "react-intl";
import FollowListBase from "Element/FollowListBase";
import PageSpinner from "Element/PageSpinner";
import NostrBandApi from "NostrBand";
import NostrBandApi from "External/NostrBand";
export default function TrendingUsers() {
const [userList, setUserList] = useState<HexKey[]>();

View File

@ -17,6 +17,14 @@ export interface TrendingNoteResponse {
notes: Array<TrendingNote>;
}
export interface SuggestedFollow {
pubkey: string;
}
export interface SuggestedFollowsResponse {
profiles: Array<SuggestedFollow>;
}
export class NostrBandError extends Error {
body: string;
statusCode: number;
@ -29,7 +37,7 @@ export class NostrBandError extends Error {
}
export default class NostrBandApi {
#url = "https://api.nostr.band";
readonly #url = "https://api.nostr.band";
async trendingProfiles() {
return await this.#json<TrendingUserResponse>("GET", "/v0/trending/profiles");
@ -39,6 +47,10 @@ export default class NostrBandApi {
return await this.#json<TrendingNoteResponse>("GET", "/v0/trending/notes");
}
async sugguestedFollows(pubkey: string) {
return await this.#json<SuggestedFollowsResponse>("GET", `/v0/suggested/profiles/${pubkey}`);
}
async #json<T>(method: string, path: string) {
const res = await fetch(`${this.#url}${path}`, {
method: method ?? "GET",

1
packages/app/src/External/index.ts vendored Normal file
View File

@ -0,0 +1 @@
export * from "./NostrBand";

View File

@ -0,0 +1,40 @@
import SuggestedProfiles from "Element/SuggestedProfiles";
import { Tab, TabElement } from "Element/Tabs";
import TrendingNotes from "Element/TrendingPosts";
import TrendingUsers from "Element/TrendingUsers";
import { useState } from "react";
import { useIntl } from "react-intl";
export default function Discover() {
const { formatMessage } = useIntl();
// tabs
const Tabs = {
Follows: { text: formatMessage({ defaultMessage: "Suggested Follows" }), value: 0 },
Posts: { text: formatMessage({ defaultMessage: "Trending Notes" }), value: 1 },
Profiles: { text: formatMessage({ defaultMessage: "Trending People" }), value: 2 },
};
const [tab, setTab] = useState<Tab>(Tabs.Follows);
function renderTab() {
switch (tab.value) {
case 0:
return <SuggestedProfiles />;
case 1:
return <TrendingNotes />;
case 2:
return <TrendingUsers />;
}
return null;
}
return (
<>
<div className="tabs">
{[Tabs.Follows, Tabs.Posts, Tabs.Profiles].map(a => (
<TabElement key={a.value} tab={tab} setTab={setTab} t={a} />
))}
</div>
{renderTab()}
</>
);
}

View File

@ -9,6 +9,7 @@ import { System } from "System";
import { TimelineSubject } from "Feed/TimelineFeed";
import { debounce, getRelayName, sha256, unixNow, unwrap } from "Util";
import useLogin from "Hooks/useLogin";
import Discover from "Pages/Discover";
import messages from "./messages";
@ -39,12 +40,17 @@ export default function RootPage() {
value: 2,
data: "/global",
},
Discover: {
text: formatMessage({ defaultMessage: "Discover" }),
value: 3,
data: "/discover",
},
};
const tagTabs = tags.item.map((t, idx) => {
return { text: `#${t}`, value: idx + 3, data: `/tag/${t}` };
});
const tabs = [RootTab.Posts, RootTab.PostsAndReplies, RootTab.Global, ...tagTabs];
const tabs = [RootTab.Posts, RootTab.PostsAndReplies, RootTab.Global, RootTab.Discover, ...tagTabs];
const tab = useMemo(() => {
const pTab = location.pathname.split("/").slice(-1)[0];
@ -63,6 +69,9 @@ export default function RootPage() {
case "global": {
return RootTab.Global;
}
case "discover": {
return RootTab.Discover;
}
default: {
return RootTab.Posts;
}
@ -237,6 +246,10 @@ export const RootRoutes = [
path: "conversations",
element: <ConversationsTab />,
},
{
path: "discover",
element: <Discover />,
},
{
path: "tag/:tag",
element: <TagsTab />,

View File

@ -30,6 +30,7 @@ import { WalletRoutes } from "Pages/WalletPage";
import NostrLinkHandler from "Pages/NostrLinkHandler";
import Thread from "Element/Thread";
import { SubscribeRoutes } from "Pages/subscribe";
import Discover from "Pages/Discover";
/**
* HTTP query provider