feat: add discover newsfeeds and interests
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 984 B |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 276 KiB |
|
Before Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB |
@@ -5,7 +5,7 @@ use specta::Type;
|
|||||||
use std::{str::FromStr, time::Duration};
|
use std::{str::FromStr, time::Duration};
|
||||||
use tauri::{Emitter, Manager, State};
|
use tauri::{Emitter, Manager, State};
|
||||||
|
|
||||||
use crate::{common::process_event, Nostr, RichEvent};
|
use crate::{common::process_event, Nostr, RichEvent, FETCH_LIMIT};
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Type)]
|
#[derive(Clone, Serialize, Deserialize, Type)]
|
||||||
pub struct Mention {
|
pub struct Mention {
|
||||||
@@ -259,6 +259,35 @@ pub async fn get_all_newsfeeds(
|
|||||||
Ok(alt_events)
|
Ok(alt_events)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
|
pub async fn get_all_local_newsfeeds(
|
||||||
|
until: Option<String>,
|
||||||
|
state: State<'_, Nostr>,
|
||||||
|
) -> Result<Vec<RichEvent>, String> {
|
||||||
|
let client = &state.client;
|
||||||
|
|
||||||
|
let as_of = match until {
|
||||||
|
Some(until) => Timestamp::from_str(&until).unwrap_or(Timestamp::now()),
|
||||||
|
None => Timestamp::now(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let filter = Filter::new()
|
||||||
|
.kind(Kind::FollowSet)
|
||||||
|
.limit(FETCH_LIMIT)
|
||||||
|
.until(as_of);
|
||||||
|
|
||||||
|
let events = client
|
||||||
|
.database()
|
||||||
|
.query(vec![filter])
|
||||||
|
.await
|
||||||
|
.map_err(|err| err.to_string())?;
|
||||||
|
|
||||||
|
let alt_events = process_event(client, events, false).await;
|
||||||
|
|
||||||
|
Ok(alt_events)
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
#[specta::specta]
|
#[specta::specta]
|
||||||
pub async fn set_interest(
|
pub async fn set_interest(
|
||||||
@@ -361,6 +390,35 @@ pub async fn get_all_interests(
|
|||||||
Ok(alt_events)
|
Ok(alt_events)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
|
pub async fn get_all_local_interests(
|
||||||
|
until: Option<String>,
|
||||||
|
state: State<'_, Nostr>,
|
||||||
|
) -> Result<Vec<RichEvent>, String> {
|
||||||
|
let client = &state.client;
|
||||||
|
|
||||||
|
let as_of = match until {
|
||||||
|
Some(until) => Timestamp::from_str(&until).unwrap_or(Timestamp::now()),
|
||||||
|
None => Timestamp::now(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let filter = Filter::new()
|
||||||
|
.kinds(vec![Kind::Interests, Kind::InterestSet])
|
||||||
|
.limit(FETCH_LIMIT)
|
||||||
|
.until(as_of);
|
||||||
|
|
||||||
|
let events = client
|
||||||
|
.database()
|
||||||
|
.query(vec![filter])
|
||||||
|
.await
|
||||||
|
.map_err(|err| err.to_string())?;
|
||||||
|
|
||||||
|
let alt_events = process_event(client, events, false).await;
|
||||||
|
|
||||||
|
Ok(alt_events)
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
#[specta::specta]
|
#[specta::specta]
|
||||||
pub async fn get_all_profiles(state: State<'_, Nostr>) -> Result<Vec<Mention>, String> {
|
pub async fn get_all_profiles(state: State<'_, Nostr>) -> Result<Vec<Mention>, String> {
|
||||||
|
|||||||
@@ -97,9 +97,11 @@ fn main() {
|
|||||||
set_group,
|
set_group,
|
||||||
get_group,
|
get_group,
|
||||||
get_all_newsfeeds,
|
get_all_newsfeeds,
|
||||||
|
get_all_local_newsfeeds,
|
||||||
set_interest,
|
set_interest,
|
||||||
get_interest,
|
get_interest,
|
||||||
get_all_interests,
|
get_all_interests,
|
||||||
|
get_all_local_interests,
|
||||||
set_wallet,
|
set_wallet,
|
||||||
load_wallet,
|
load_wallet,
|
||||||
remove_wallet,
|
remove_wallet,
|
||||||
|
|||||||
@@ -208,6 +208,14 @@ async getAllNewsfeeds(id: string) : Promise<Result<RichEvent[], string>> {
|
|||||||
else return { status: "error", error: e as any };
|
else return { status: "error", error: e as any };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async getAllLocalNewsfeeds(until: string | null) : Promise<Result<RichEvent[], string>> {
|
||||||
|
try {
|
||||||
|
return { status: "ok", data: await TAURI_INVOKE("get_all_local_newsfeeds", { until }) };
|
||||||
|
} catch (e) {
|
||||||
|
if(e instanceof Error) throw e;
|
||||||
|
else return { status: "error", error: e as any };
|
||||||
|
}
|
||||||
|
},
|
||||||
async setInterest(title: string, description: string | null, image: string | null, hashtags: string[]) : Promise<Result<string, string>> {
|
async setInterest(title: string, description: string | null, image: string | null, hashtags: string[]) : Promise<Result<string, string>> {
|
||||||
try {
|
try {
|
||||||
return { status: "ok", data: await TAURI_INVOKE("set_interest", { title, description, image, hashtags }) };
|
return { status: "ok", data: await TAURI_INVOKE("set_interest", { title, description, image, hashtags }) };
|
||||||
@@ -232,6 +240,14 @@ async getAllInterests(id: string) : Promise<Result<RichEvent[], string>> {
|
|||||||
else return { status: "error", error: e as any };
|
else return { status: "error", error: e as any };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async getAllLocalInterests(until: string | null) : Promise<Result<RichEvent[], string>> {
|
||||||
|
try {
|
||||||
|
return { status: "ok", data: await TAURI_INVOKE("get_all_local_interests", { until }) };
|
||||||
|
} catch (e) {
|
||||||
|
if(e instanceof Error) throw e;
|
||||||
|
else return { status: "error", error: e as any };
|
||||||
|
}
|
||||||
|
},
|
||||||
async setWallet(uri: string) : Promise<Result<boolean, string>> {
|
async setWallet(uri: string) : Promise<Result<boolean, string>> {
|
||||||
try {
|
try {
|
||||||
return { status: "ok", data: await TAURI_INVOKE("set_wallet", { uri }) };
|
return { status: "ok", data: await TAURI_INVOKE("set_wallet", { uri }) };
|
||||||
|
|||||||
@@ -51,6 +51,12 @@ const ColumnsLayoutSearchLazyImport = createFileRoute(
|
|||||||
const ColumnsLayoutOnboardingLazyImport = createFileRoute(
|
const ColumnsLayoutOnboardingLazyImport = createFileRoute(
|
||||||
'/columns/_layout/onboarding',
|
'/columns/_layout/onboarding',
|
||||||
)()
|
)()
|
||||||
|
const ColumnsLayoutDiscoverNewsfeedsLazyImport = createFileRoute(
|
||||||
|
'/columns/_layout/discover-newsfeeds',
|
||||||
|
)()
|
||||||
|
const ColumnsLayoutDiscoverInterestsLazyImport = createFileRoute(
|
||||||
|
'/columns/_layout/discover-interests',
|
||||||
|
)()
|
||||||
const ColumnsLayoutUsersIdLazyImport = createFileRoute(
|
const ColumnsLayoutUsersIdLazyImport = createFileRoute(
|
||||||
'/columns/_layout/users/$id',
|
'/columns/_layout/users/$id',
|
||||||
)()
|
)()
|
||||||
@@ -196,6 +202,28 @@ const ColumnsLayoutOnboardingLazyRoute =
|
|||||||
import('./routes/columns/_layout/onboarding.lazy').then((d) => d.Route),
|
import('./routes/columns/_layout/onboarding.lazy').then((d) => d.Route),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const ColumnsLayoutDiscoverNewsfeedsLazyRoute =
|
||||||
|
ColumnsLayoutDiscoverNewsfeedsLazyImport.update({
|
||||||
|
id: '/discover-newsfeeds',
|
||||||
|
path: '/discover-newsfeeds',
|
||||||
|
getParentRoute: () => ColumnsLayoutRoute,
|
||||||
|
} as any).lazy(() =>
|
||||||
|
import('./routes/columns/_layout/discover-newsfeeds.lazy').then(
|
||||||
|
(d) => d.Route,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
const ColumnsLayoutDiscoverInterestsLazyRoute =
|
||||||
|
ColumnsLayoutDiscoverInterestsLazyImport.update({
|
||||||
|
id: '/discover-interests',
|
||||||
|
path: '/discover-interests',
|
||||||
|
getParentRoute: () => ColumnsLayoutRoute,
|
||||||
|
} as any).lazy(() =>
|
||||||
|
import('./routes/columns/_layout/discover-interests.lazy').then(
|
||||||
|
(d) => d.Route,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
const SettingsIdWalletRoute = SettingsIdWalletImport.update({
|
const SettingsIdWalletRoute = SettingsIdWalletImport.update({
|
||||||
id: '/wallet',
|
id: '/wallet',
|
||||||
path: '/wallet',
|
path: '/wallet',
|
||||||
@@ -469,6 +497,20 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof SettingsIdWalletImport
|
preLoaderRoute: typeof SettingsIdWalletImport
|
||||||
parentRoute: typeof SettingsIdLazyImport
|
parentRoute: typeof SettingsIdLazyImport
|
||||||
}
|
}
|
||||||
|
'/columns/_layout/discover-interests': {
|
||||||
|
id: '/columns/_layout/discover-interests'
|
||||||
|
path: '/discover-interests'
|
||||||
|
fullPath: '/columns/discover-interests'
|
||||||
|
preLoaderRoute: typeof ColumnsLayoutDiscoverInterestsLazyImport
|
||||||
|
parentRoute: typeof ColumnsLayoutImport
|
||||||
|
}
|
||||||
|
'/columns/_layout/discover-newsfeeds': {
|
||||||
|
id: '/columns/_layout/discover-newsfeeds'
|
||||||
|
path: '/discover-newsfeeds'
|
||||||
|
fullPath: '/columns/discover-newsfeeds'
|
||||||
|
preLoaderRoute: typeof ColumnsLayoutDiscoverNewsfeedsLazyImport
|
||||||
|
parentRoute: typeof ColumnsLayoutImport
|
||||||
|
}
|
||||||
'/columns/_layout/onboarding': {
|
'/columns/_layout/onboarding': {
|
||||||
id: '/columns/_layout/onboarding'
|
id: '/columns/_layout/onboarding'
|
||||||
path: '/onboarding'
|
path: '/onboarding'
|
||||||
@@ -602,6 +644,8 @@ const ColumnsLayoutCreateNewsfeedRouteWithChildren =
|
|||||||
interface ColumnsLayoutRouteChildren {
|
interface ColumnsLayoutRouteChildren {
|
||||||
ColumnsLayoutCreateNewsfeedRoute: typeof ColumnsLayoutCreateNewsfeedRouteWithChildren
|
ColumnsLayoutCreateNewsfeedRoute: typeof ColumnsLayoutCreateNewsfeedRouteWithChildren
|
||||||
ColumnsLayoutGlobalRoute: typeof ColumnsLayoutGlobalRoute
|
ColumnsLayoutGlobalRoute: typeof ColumnsLayoutGlobalRoute
|
||||||
|
ColumnsLayoutDiscoverInterestsLazyRoute: typeof ColumnsLayoutDiscoverInterestsLazyRoute
|
||||||
|
ColumnsLayoutDiscoverNewsfeedsLazyRoute: typeof ColumnsLayoutDiscoverNewsfeedsLazyRoute
|
||||||
ColumnsLayoutOnboardingLazyRoute: typeof ColumnsLayoutOnboardingLazyRoute
|
ColumnsLayoutOnboardingLazyRoute: typeof ColumnsLayoutOnboardingLazyRoute
|
||||||
ColumnsLayoutSearchLazyRoute: typeof ColumnsLayoutSearchLazyRoute
|
ColumnsLayoutSearchLazyRoute: typeof ColumnsLayoutSearchLazyRoute
|
||||||
ColumnsLayoutTrendingLazyRoute: typeof ColumnsLayoutTrendingLazyRoute
|
ColumnsLayoutTrendingLazyRoute: typeof ColumnsLayoutTrendingLazyRoute
|
||||||
@@ -620,6 +664,10 @@ const ColumnsLayoutRouteChildren: ColumnsLayoutRouteChildren = {
|
|||||||
ColumnsLayoutCreateNewsfeedRoute:
|
ColumnsLayoutCreateNewsfeedRoute:
|
||||||
ColumnsLayoutCreateNewsfeedRouteWithChildren,
|
ColumnsLayoutCreateNewsfeedRouteWithChildren,
|
||||||
ColumnsLayoutGlobalRoute: ColumnsLayoutGlobalRoute,
|
ColumnsLayoutGlobalRoute: ColumnsLayoutGlobalRoute,
|
||||||
|
ColumnsLayoutDiscoverInterestsLazyRoute:
|
||||||
|
ColumnsLayoutDiscoverInterestsLazyRoute,
|
||||||
|
ColumnsLayoutDiscoverNewsfeedsLazyRoute:
|
||||||
|
ColumnsLayoutDiscoverNewsfeedsLazyRoute,
|
||||||
ColumnsLayoutOnboardingLazyRoute: ColumnsLayoutOnboardingLazyRoute,
|
ColumnsLayoutOnboardingLazyRoute: ColumnsLayoutOnboardingLazyRoute,
|
||||||
ColumnsLayoutSearchLazyRoute: ColumnsLayoutSearchLazyRoute,
|
ColumnsLayoutSearchLazyRoute: ColumnsLayoutSearchLazyRoute,
|
||||||
ColumnsLayoutTrendingLazyRoute: ColumnsLayoutTrendingLazyRoute,
|
ColumnsLayoutTrendingLazyRoute: ColumnsLayoutTrendingLazyRoute,
|
||||||
@@ -685,6 +733,8 @@ export interface FileRoutesByFullPath {
|
|||||||
'/settings/$id/general': typeof SettingsIdGeneralRoute
|
'/settings/$id/general': typeof SettingsIdGeneralRoute
|
||||||
'/settings/$id/relay': typeof SettingsIdRelayRoute
|
'/settings/$id/relay': typeof SettingsIdRelayRoute
|
||||||
'/settings/$id/wallet': typeof SettingsIdWalletRoute
|
'/settings/$id/wallet': typeof SettingsIdWalletRoute
|
||||||
|
'/columns/discover-interests': typeof ColumnsLayoutDiscoverInterestsLazyRoute
|
||||||
|
'/columns/discover-newsfeeds': typeof ColumnsLayoutDiscoverNewsfeedsLazyRoute
|
||||||
'/columns/onboarding': typeof ColumnsLayoutOnboardingLazyRoute
|
'/columns/onboarding': typeof ColumnsLayoutOnboardingLazyRoute
|
||||||
'/columns/search': typeof ColumnsLayoutSearchLazyRoute
|
'/columns/search': typeof ColumnsLayoutSearchLazyRoute
|
||||||
'/columns/trending': typeof ColumnsLayoutTrendingLazyRoute
|
'/columns/trending': typeof ColumnsLayoutTrendingLazyRoute
|
||||||
@@ -720,6 +770,8 @@ export interface FileRoutesByTo {
|
|||||||
'/settings/$id/general': typeof SettingsIdGeneralRoute
|
'/settings/$id/general': typeof SettingsIdGeneralRoute
|
||||||
'/settings/$id/relay': typeof SettingsIdRelayRoute
|
'/settings/$id/relay': typeof SettingsIdRelayRoute
|
||||||
'/settings/$id/wallet': typeof SettingsIdWalletRoute
|
'/settings/$id/wallet': typeof SettingsIdWalletRoute
|
||||||
|
'/columns/discover-interests': typeof ColumnsLayoutDiscoverInterestsLazyRoute
|
||||||
|
'/columns/discover-newsfeeds': typeof ColumnsLayoutDiscoverNewsfeedsLazyRoute
|
||||||
'/columns/onboarding': typeof ColumnsLayoutOnboardingLazyRoute
|
'/columns/onboarding': typeof ColumnsLayoutOnboardingLazyRoute
|
||||||
'/columns/search': typeof ColumnsLayoutSearchLazyRoute
|
'/columns/search': typeof ColumnsLayoutSearchLazyRoute
|
||||||
'/columns/trending': typeof ColumnsLayoutTrendingLazyRoute
|
'/columns/trending': typeof ColumnsLayoutTrendingLazyRoute
|
||||||
@@ -758,6 +810,8 @@ export interface FileRoutesById {
|
|||||||
'/settings/$id/general': typeof SettingsIdGeneralRoute
|
'/settings/$id/general': typeof SettingsIdGeneralRoute
|
||||||
'/settings/$id/relay': typeof SettingsIdRelayRoute
|
'/settings/$id/relay': typeof SettingsIdRelayRoute
|
||||||
'/settings/$id/wallet': typeof SettingsIdWalletRoute
|
'/settings/$id/wallet': typeof SettingsIdWalletRoute
|
||||||
|
'/columns/_layout/discover-interests': typeof ColumnsLayoutDiscoverInterestsLazyRoute
|
||||||
|
'/columns/_layout/discover-newsfeeds': typeof ColumnsLayoutDiscoverNewsfeedsLazyRoute
|
||||||
'/columns/_layout/onboarding': typeof ColumnsLayoutOnboardingLazyRoute
|
'/columns/_layout/onboarding': typeof ColumnsLayoutOnboardingLazyRoute
|
||||||
'/columns/_layout/search': typeof ColumnsLayoutSearchLazyRoute
|
'/columns/_layout/search': typeof ColumnsLayoutSearchLazyRoute
|
||||||
'/columns/_layout/trending': typeof ColumnsLayoutTrendingLazyRoute
|
'/columns/_layout/trending': typeof ColumnsLayoutTrendingLazyRoute
|
||||||
@@ -796,6 +850,8 @@ export interface FileRouteTypes {
|
|||||||
| '/settings/$id/general'
|
| '/settings/$id/general'
|
||||||
| '/settings/$id/relay'
|
| '/settings/$id/relay'
|
||||||
| '/settings/$id/wallet'
|
| '/settings/$id/wallet'
|
||||||
|
| '/columns/discover-interests'
|
||||||
|
| '/columns/discover-newsfeeds'
|
||||||
| '/columns/onboarding'
|
| '/columns/onboarding'
|
||||||
| '/columns/search'
|
| '/columns/search'
|
||||||
| '/columns/trending'
|
| '/columns/trending'
|
||||||
@@ -830,6 +886,8 @@ export interface FileRouteTypes {
|
|||||||
| '/settings/$id/general'
|
| '/settings/$id/general'
|
||||||
| '/settings/$id/relay'
|
| '/settings/$id/relay'
|
||||||
| '/settings/$id/wallet'
|
| '/settings/$id/wallet'
|
||||||
|
| '/columns/discover-interests'
|
||||||
|
| '/columns/discover-newsfeeds'
|
||||||
| '/columns/onboarding'
|
| '/columns/onboarding'
|
||||||
| '/columns/search'
|
| '/columns/search'
|
||||||
| '/columns/trending'
|
| '/columns/trending'
|
||||||
@@ -866,6 +924,8 @@ export interface FileRouteTypes {
|
|||||||
| '/settings/$id/general'
|
| '/settings/$id/general'
|
||||||
| '/settings/$id/relay'
|
| '/settings/$id/relay'
|
||||||
| '/settings/$id/wallet'
|
| '/settings/$id/wallet'
|
||||||
|
| '/columns/_layout/discover-interests'
|
||||||
|
| '/columns/_layout/discover-newsfeeds'
|
||||||
| '/columns/_layout/onboarding'
|
| '/columns/_layout/onboarding'
|
||||||
| '/columns/_layout/search'
|
| '/columns/_layout/search'
|
||||||
| '/columns/_layout/trending'
|
| '/columns/_layout/trending'
|
||||||
@@ -975,6 +1035,8 @@ export const routeTree = rootRoute
|
|||||||
"children": [
|
"children": [
|
||||||
"/columns/_layout/create-newsfeed",
|
"/columns/_layout/create-newsfeed",
|
||||||
"/columns/_layout/global",
|
"/columns/_layout/global",
|
||||||
|
"/columns/_layout/discover-interests",
|
||||||
|
"/columns/_layout/discover-newsfeeds",
|
||||||
"/columns/_layout/onboarding",
|
"/columns/_layout/onboarding",
|
||||||
"/columns/_layout/search",
|
"/columns/_layout/search",
|
||||||
"/columns/_layout/trending",
|
"/columns/_layout/trending",
|
||||||
@@ -1040,6 +1102,14 @@ export const routeTree = rootRoute
|
|||||||
"filePath": "settings.$id/wallet.tsx",
|
"filePath": "settings.$id/wallet.tsx",
|
||||||
"parent": "/settings/$id"
|
"parent": "/settings/$id"
|
||||||
},
|
},
|
||||||
|
"/columns/_layout/discover-interests": {
|
||||||
|
"filePath": "columns/_layout/discover-interests.lazy.tsx",
|
||||||
|
"parent": "/columns/_layout"
|
||||||
|
},
|
||||||
|
"/columns/_layout/discover-newsfeeds": {
|
||||||
|
"filePath": "columns/_layout/discover-newsfeeds.lazy.tsx",
|
||||||
|
"parent": "/columns/_layout"
|
||||||
|
},
|
||||||
"/columns/_layout/onboarding": {
|
"/columns/_layout/onboarding": {
|
||||||
"filePath": "columns/_layout/onboarding.lazy.tsx",
|
"filePath": "columns/_layout/onboarding.lazy.tsx",
|
||||||
"parent": "/columns/_layout"
|
"parent": "/columns/_layout"
|
||||||
|
|||||||
182
src/routes/columns/_layout/discover-interests.lazy.tsx
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
import { commands } from "@/commands.gen";
|
||||||
|
import { toLumeEvents } from "@/commons";
|
||||||
|
import { Spinner, User } from "@/components";
|
||||||
|
import { LumeWindow } from "@/system";
|
||||||
|
import { ArrowDown } from "@phosphor-icons/react";
|
||||||
|
import * as ScrollArea from "@radix-ui/react-scroll-area";
|
||||||
|
import { useInfiniteQuery } from "@tanstack/react-query";
|
||||||
|
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||||
|
import { nanoid } from "nanoid";
|
||||||
|
import type { NostrEvent } from "nostr-tools";
|
||||||
|
import { type RefObject, useCallback, useRef } from "react";
|
||||||
|
import { Virtualizer } from "virtua";
|
||||||
|
|
||||||
|
export const Route = createLazyFileRoute("/columns/_layout/discover-interests")(
|
||||||
|
{
|
||||||
|
component: Screen,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
function Screen() {
|
||||||
|
const {
|
||||||
|
isLoading,
|
||||||
|
isError,
|
||||||
|
error,
|
||||||
|
isFetchingNextPage,
|
||||||
|
hasNextPage,
|
||||||
|
fetchNextPage,
|
||||||
|
data,
|
||||||
|
} = useInfiniteQuery({
|
||||||
|
queryKey: ["local-interests"],
|
||||||
|
initialPageParam: 0,
|
||||||
|
queryFn: async ({ pageParam }: { pageParam: number }) => {
|
||||||
|
const until = pageParam > 0 ? pageParam.toString() : null;
|
||||||
|
const res = await commands.getAllLocalInterests(until);
|
||||||
|
|
||||||
|
if (res.status === "ok") {
|
||||||
|
const data = toLumeEvents(res.data);
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
throw new Error(res.error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getNextPageParam: (lastPage) => {
|
||||||
|
const lastEvent = lastPage.at(-1);
|
||||||
|
|
||||||
|
if (lastEvent) {
|
||||||
|
return lastEvent.created_at - 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
select: (data) =>
|
||||||
|
data?.pages
|
||||||
|
.flat()
|
||||||
|
.filter(
|
||||||
|
(item) => item.tags.filter((tag) => tag[0] === "p")?.length > 0,
|
||||||
|
),
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const renderItem = useCallback(
|
||||||
|
(item: NostrEvent) => {
|
||||||
|
const name =
|
||||||
|
item.tags.find((tag) => tag[0] === "title")?.[1] || "Unnamed";
|
||||||
|
const label =
|
||||||
|
item.tags.find((tag) => tag[0] === "label")?.[1] || nanoid();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={item.id}
|
||||||
|
className="group flex flex-col rounded-xl overflow-hidden bg-white dark:bg-neutral-800/50 shadow-lg shadow-primary dark:ring-1 dark:ring-neutral-800"
|
||||||
|
>
|
||||||
|
<div className="px-2 pt-2">
|
||||||
|
<ScrollArea.Root
|
||||||
|
type={"scroll"}
|
||||||
|
scrollHideDelay={300}
|
||||||
|
className="overflow-hidden size-full"
|
||||||
|
>
|
||||||
|
<ScrollArea.Viewport className="p-3 h-16 bg-neutral-100 dark:bg-neutral-800 rounded-lg">
|
||||||
|
<div className="flex flex-wrap items-center justify-center gap-2">
|
||||||
|
{item.tags
|
||||||
|
.filter((tag) => tag[0] === "t")
|
||||||
|
.map((tag) => (
|
||||||
|
<div key={tag[1]} className="text-sm font-medium">
|
||||||
|
{tag[1].includes("#") ? tag[1] : `#${tag[1]}`}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</ScrollArea.Viewport>
|
||||||
|
<ScrollArea.Scrollbar
|
||||||
|
className="flex select-none touch-none p-0.5 duration-[160ms] ease-out data-[orientation=vertical]:w-2"
|
||||||
|
orientation="vertical"
|
||||||
|
>
|
||||||
|
<ScrollArea.Thumb className="flex-1 bg-black/10 dark:bg-white/10 rounded-full relative before:content-[''] before:absolute before:top-1/2 before:left-1/2 before:-translate-x-1/2 before:-translate-y-1/2 before:w-full before:h-full before:min-w-[44px] before:min-h-[44px]" />
|
||||||
|
</ScrollArea.Scrollbar>
|
||||||
|
<ScrollArea.Corner className="bg-transparent" />
|
||||||
|
</ScrollArea.Root>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 flex items-center justify-between">
|
||||||
|
<div className="inline-flex items-center gap-2">
|
||||||
|
<User.Provider pubkey={item.pubkey}>
|
||||||
|
<User.Root>
|
||||||
|
<User.Avatar className="size-7 rounded-full" />
|
||||||
|
</User.Root>
|
||||||
|
</User.Provider>
|
||||||
|
<h5 className="text-xs font-medium">{name}</h5>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() =>
|
||||||
|
LumeWindow.openColumn({
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
url: `/columns/interests/${item.id}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
className="h-6 w-16 inline-flex items-center justify-center gap-1 text-xs font-semibold rounded-full bg-neutral-100 group-hover:bg-blue-600 dark:group-hover:bg-blue-400 group-hover:text-white"
|
||||||
|
>
|
||||||
|
Add
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[data],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollArea.Root
|
||||||
|
type={"scroll"}
|
||||||
|
scrollHideDelay={300}
|
||||||
|
className="overflow-hidden size-full"
|
||||||
|
>
|
||||||
|
<ScrollArea.Viewport ref={ref} className="relative h-full px-3 pb-3">
|
||||||
|
<Virtualizer scrollRef={ref as unknown as RefObject<HTMLElement>}>
|
||||||
|
{isLoading ? (
|
||||||
|
<div className="inline-flex items-center gap-1.5">
|
||||||
|
<Spinner className="size-4" />
|
||||||
|
Loading...
|
||||||
|
</div>
|
||||||
|
) : isError ? (
|
||||||
|
<div className="mb-3 flex flex-col items-center justify-center h-16 w-full rounded-xl overflow-hidden bg-neutral-200/50 dark:bg-neutral-800/50">
|
||||||
|
<p className="text-center">{error?.message ?? "Error"}</p>
|
||||||
|
</div>
|
||||||
|
) : !data?.length ? (
|
||||||
|
<div className="mb-3 flex flex-col items-center justify-center h-16 w-full rounded-xl overflow-hidden bg-neutral-200/50 dark:bg-neutral-800/50">
|
||||||
|
<p className="text-center">Empty.</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
data?.map((item) => renderItem(item))
|
||||||
|
)}
|
||||||
|
{hasNextPage ? (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => fetchNextPage()}
|
||||||
|
disabled={isFetchingNextPage || isLoading}
|
||||||
|
className="h-11 w-full px-3 flex items-center justify-center gap-1.5 bg-neutral-200/50 hover:bg-neutral-200 rounded-full text-sm font-medium text-blue-600 dark:hover:bg-neutral-800 dark:bg-neutral-800/50 dark:text-blue-400"
|
||||||
|
>
|
||||||
|
{isFetchingNextPage ? (
|
||||||
|
<Spinner className="size-4" />
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<ArrowDown className="size-4" />
|
||||||
|
Load more
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
</Virtualizer>
|
||||||
|
</ScrollArea.Viewport>
|
||||||
|
<ScrollArea.Scrollbar
|
||||||
|
className="flex select-none touch-none p-0.5 duration-[160ms] ease-out data-[orientation=vertical]:w-2"
|
||||||
|
orientation="vertical"
|
||||||
|
>
|
||||||
|
<ScrollArea.Thumb className="flex-1 bg-black/10 dark:bg-white/10 rounded-full relative before:content-[''] before:absolute before:top-1/2 before:left-1/2 before:-translate-x-1/2 before:-translate-y-1/2 before:w-full before:h-full before:min-w-[44px] before:min-h-[44px]" />
|
||||||
|
</ScrollArea.Scrollbar>
|
||||||
|
<ScrollArea.Corner className="bg-transparent" />
|
||||||
|
</ScrollArea.Root>
|
||||||
|
);
|
||||||
|
}
|
||||||
184
src/routes/columns/_layout/discover-newsfeeds.lazy.tsx
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
import { commands } from "@/commands.gen";
|
||||||
|
import { toLumeEvents } from "@/commons";
|
||||||
|
import { Spinner, User } from "@/components";
|
||||||
|
import { LumeWindow } from "@/system";
|
||||||
|
import { ArrowDown } from "@phosphor-icons/react";
|
||||||
|
import * as ScrollArea from "@radix-ui/react-scroll-area";
|
||||||
|
import { useInfiniteQuery } from "@tanstack/react-query";
|
||||||
|
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||||
|
import { nanoid } from "nanoid";
|
||||||
|
import type { NostrEvent } from "nostr-tools";
|
||||||
|
import { type RefObject, useCallback, useRef } from "react";
|
||||||
|
import { Virtualizer } from "virtua";
|
||||||
|
|
||||||
|
export const Route = createLazyFileRoute("/columns/_layout/discover-newsfeeds")(
|
||||||
|
{
|
||||||
|
component: Screen,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
function Screen() {
|
||||||
|
const {
|
||||||
|
isLoading,
|
||||||
|
isError,
|
||||||
|
error,
|
||||||
|
isFetchingNextPage,
|
||||||
|
hasNextPage,
|
||||||
|
fetchNextPage,
|
||||||
|
data,
|
||||||
|
} = useInfiniteQuery({
|
||||||
|
queryKey: ["local-newsfeeds"],
|
||||||
|
initialPageParam: 0,
|
||||||
|
queryFn: async ({ pageParam }: { pageParam: number }) => {
|
||||||
|
const until = pageParam > 0 ? pageParam.toString() : null;
|
||||||
|
const res = await commands.getAllLocalNewsfeeds(until);
|
||||||
|
|
||||||
|
if (res.status === "ok") {
|
||||||
|
const data = toLumeEvents(res.data);
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
throw new Error(res.error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getNextPageParam: (lastPage) => {
|
||||||
|
const lastEvent = lastPage.at(-1);
|
||||||
|
|
||||||
|
if (lastEvent) {
|
||||||
|
return lastEvent.created_at - 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
select: (data) =>
|
||||||
|
data?.pages
|
||||||
|
.flat()
|
||||||
|
.filter(
|
||||||
|
(item) => item.tags.filter((tag) => tag[0] === "p")?.length > 0,
|
||||||
|
),
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const renderItem = useCallback(
|
||||||
|
(item: NostrEvent) => {
|
||||||
|
const name =
|
||||||
|
item.tags.find((tag) => tag[0] === "title")?.[1] || "Unnamed";
|
||||||
|
|
||||||
|
const label = item.tags.find((tag) => tag[0] === "d")?.[1] || nanoid();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={item.id}
|
||||||
|
className="mb-3 group flex flex-col rounded-xl overflow-hidden bg-white dark:bg-neutral-800/50 shadow-lg shadow-primary dark:ring-1 dark:ring-neutral-800"
|
||||||
|
>
|
||||||
|
<div className="px-2 pt-2">
|
||||||
|
<ScrollArea.Root
|
||||||
|
type={"scroll"}
|
||||||
|
scrollHideDelay={300}
|
||||||
|
className="overflow-hidden size-full"
|
||||||
|
>
|
||||||
|
<ScrollArea.Viewport className="p-3 h-16 bg-neutral-100 dark:bg-neutral-800 rounded-lg">
|
||||||
|
<div className="flex flex-wrap items-center justify-center gap-2">
|
||||||
|
{item.tags
|
||||||
|
.filter((tag) => tag[0] === "p")
|
||||||
|
.map((tag) => (
|
||||||
|
<User.Provider key={tag[1]} pubkey={tag[1]}>
|
||||||
|
<User.Root>
|
||||||
|
<User.Avatar className="size-8 rounded-full" />
|
||||||
|
</User.Root>
|
||||||
|
</User.Provider>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</ScrollArea.Viewport>
|
||||||
|
<ScrollArea.Scrollbar
|
||||||
|
className="flex select-none touch-none p-0.5 duration-[160ms] ease-out data-[orientation=vertical]:w-2"
|
||||||
|
orientation="vertical"
|
||||||
|
>
|
||||||
|
<ScrollArea.Thumb className="flex-1 bg-black/10 dark:bg-white/10 rounded-full relative before:content-[''] before:absolute before:top-1/2 before:left-1/2 before:-translate-x-1/2 before:-translate-y-1/2 before:w-full before:h-full before:min-w-[44px] before:min-h-[44px]" />
|
||||||
|
</ScrollArea.Scrollbar>
|
||||||
|
<ScrollArea.Corner className="bg-transparent" />
|
||||||
|
</ScrollArea.Root>
|
||||||
|
</div>
|
||||||
|
<div className="p-2 flex items-center justify-between">
|
||||||
|
<div className="inline-flex items-center gap-2">
|
||||||
|
<User.Provider pubkey={item.pubkey}>
|
||||||
|
<User.Root>
|
||||||
|
<User.Avatar className="size-7 rounded-full" />
|
||||||
|
</User.Root>
|
||||||
|
</User.Provider>
|
||||||
|
<h5 className="text-xs font-medium">{name}</h5>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() =>
|
||||||
|
LumeWindow.openColumn({
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
url: `/columns/groups/${item.id}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
className="h-6 w-16 inline-flex items-center justify-center gap-1 text-xs font-semibold rounded-full bg-neutral-100 group-hover:bg-blue-600 dark:group-hover:bg-blue-400 group-hover:text-white"
|
||||||
|
>
|
||||||
|
Add
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[data],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollArea.Root
|
||||||
|
type={"scroll"}
|
||||||
|
scrollHideDelay={300}
|
||||||
|
className="overflow-hidden size-full"
|
||||||
|
>
|
||||||
|
<ScrollArea.Viewport ref={ref} className="relative h-full px-3 pb-3">
|
||||||
|
<Virtualizer scrollRef={ref as unknown as RefObject<HTMLElement>}>
|
||||||
|
{isLoading ? (
|
||||||
|
<div className="inline-flex items-center gap-1.5">
|
||||||
|
<Spinner className="size-4" />
|
||||||
|
Loading...
|
||||||
|
</div>
|
||||||
|
) : isError ? (
|
||||||
|
<div className="mb-3 flex flex-col items-center justify-center h-16 w-full rounded-xl overflow-hidden bg-neutral-200/50 dark:bg-neutral-800/50">
|
||||||
|
<p className="text-center">{error?.message ?? "Error"}</p>
|
||||||
|
</div>
|
||||||
|
) : !data?.length ? (
|
||||||
|
<div className="mb-3 flex flex-col items-center justify-center h-16 w-full rounded-xl overflow-hidden bg-neutral-200/50 dark:bg-neutral-800/50">
|
||||||
|
<p className="text-center">Empty.</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
data?.map((item) => renderItem(item))
|
||||||
|
)}
|
||||||
|
{hasNextPage ? (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => fetchNextPage()}
|
||||||
|
disabled={isFetchingNextPage || isLoading}
|
||||||
|
className="h-11 w-full px-3 flex items-center justify-center gap-1.5 bg-neutral-200/50 hover:bg-neutral-200 rounded-full text-sm font-medium text-blue-600 dark:hover:bg-neutral-800 dark:bg-neutral-800/50 dark:text-blue-400"
|
||||||
|
>
|
||||||
|
{isFetchingNextPage ? (
|
||||||
|
<Spinner className="size-4" />
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<ArrowDown className="size-4" />
|
||||||
|
Load more
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
</Virtualizer>
|
||||||
|
</ScrollArea.Viewport>
|
||||||
|
<ScrollArea.Scrollbar
|
||||||
|
className="flex select-none touch-none p-0.5 duration-[160ms] ease-out data-[orientation=vertical]:w-2"
|
||||||
|
orientation="vertical"
|
||||||
|
>
|
||||||
|
<ScrollArea.Thumb className="flex-1 bg-black/10 dark:bg-white/10 rounded-full relative before:content-[''] before:absolute before:top-1/2 before:left-1/2 before:-translate-x-1/2 before:-translate-y-1/2 before:w-full before:h-full before:min-w-[44px] before:min-h-[44px]" />
|
||||||
|
</ScrollArea.Scrollbar>
|
||||||
|
<ScrollArea.Corner className="bg-transparent" />
|
||||||
|
</ScrollArea.Root>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -182,10 +182,20 @@ function Newsfeeds() {
|
|||||||
) : (
|
) : (
|
||||||
data?.map((item) => renderItem(item))
|
data?.map((item) => renderItem(item))
|
||||||
)}
|
)}
|
||||||
<div className="h-12 px-3 flex items-center justify-between items-betwe bg-neutral-200/50 rounded-xl text-blue-600 dark:text-blue-400">
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() =>
|
||||||
|
LumeWindow.openColumn({
|
||||||
|
name: "Newsfeeds",
|
||||||
|
url: "/columns/discover-newsfeeds",
|
||||||
|
label: "discover_newsfeeds",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
className="h-12 px-3 flex items-center justify-between bg-neutral-200/50 rounded-xl text-blue-600 dark:text-blue-400"
|
||||||
|
>
|
||||||
<span className="text-sm font-medium">Discover newsfeeds</span>
|
<span className="text-sm font-medium">Discover newsfeeds</span>
|
||||||
<ArrowRight className="size-4" weight="bold" />
|
<ArrowRight className="size-4" weight="bold" />
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -326,10 +336,20 @@ function Interests() {
|
|||||||
) : (
|
) : (
|
||||||
data?.map((item) => renderItem(item))
|
data?.map((item) => renderItem(item))
|
||||||
)}
|
)}
|
||||||
<div className="h-12 px-3 flex items-center justify-between items-betwe bg-neutral-200/50 rounded-xl text-blue-600 dark:text-blue-400">
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() =>
|
||||||
|
LumeWindow.openColumn({
|
||||||
|
name: "Interests",
|
||||||
|
url: "/columns/discover-interests",
|
||||||
|
label: "discover_interests",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
className="h-12 px-3 flex items-center justify-between bg-neutral-200/50 rounded-xl text-blue-600 dark:text-blue-400"
|
||||||
|
>
|
||||||
<span className="text-sm font-medium">Discover interests</span>
|
<span className="text-sm font-medium">Discover interests</span>
|
||||||
<ArrowRight className="size-4" weight="bold" />
|
<ArrowRight className="size-4" weight="bold" />
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,13 +2,31 @@ import { commands } from "@/commands.gen";
|
|||||||
import type { NostrEvent } from "@/types";
|
import type { NostrEvent } from "@/types";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { nip19 } from "nostr-tools";
|
import { nip19 } from "nostr-tools";
|
||||||
|
import { useMemo } from "react";
|
||||||
import { LumeEvent } from "./event";
|
import { LumeEvent } from "./event";
|
||||||
|
|
||||||
export function useEvent(id: string, repost?: string) {
|
export function useEvent(id: string, repost?: string) {
|
||||||
|
const hex = useMemo(() => {
|
||||||
|
try {
|
||||||
|
const normalized = id.replace("nostr:", "").replace(/[^\w\s]/gi, "");
|
||||||
|
const decoded = nip19.decode(normalized);
|
||||||
|
|
||||||
|
switch (decoded.type) {
|
||||||
|
case "note":
|
||||||
|
return decoded.data;
|
||||||
|
case "nevent":
|
||||||
|
return decoded.data.id;
|
||||||
|
default:
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
const { isLoading, isError, error, data } = useQuery({
|
const { isLoading, isError, error, data } = useQuery({
|
||||||
queryKey: ["ids", "event", id],
|
queryKey: ["ids", "event", id],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
try {
|
|
||||||
if (repost?.length) {
|
if (repost?.length) {
|
||||||
const nostrEvent: NostrEvent = JSON.parse(repost);
|
const nostrEvent: NostrEvent = JSON.parse(repost);
|
||||||
const res = await commands.getMetaFromEvent(nostrEvent.content);
|
const res = await commands.getMetaFromEvent(nostrEvent.content);
|
||||||
@@ -20,17 +38,7 @@ export function useEvent(id: string, repost?: string) {
|
|||||||
return new LumeEvent(nostrEvent);
|
return new LumeEvent(nostrEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
let normalizedId = id.replace("nostr:", "").replace(/[^\w\s]/gi, "");
|
const res = await commands.getEvent(hex);
|
||||||
|
|
||||||
if (normalizedId.startsWith("nevent")) {
|
|
||||||
const decoded = nip19.decode(normalizedId);
|
|
||||||
|
|
||||||
if (decoded.type === "nevent") {
|
|
||||||
normalizedId = decoded.data.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await commands.getEvent(normalizedId);
|
|
||||||
|
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
const data = res.data;
|
const data = res.data;
|
||||||
@@ -44,13 +52,11 @@ export function useEvent(id: string, repost?: string) {
|
|||||||
} else {
|
} else {
|
||||||
throw new Error(res.error);
|
throw new Error(res.error);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
throw new Error(String(e));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
refetchOnMount: false,
|
refetchOnMount: false,
|
||||||
refetchOnReconnect: false,
|
refetchOnReconnect: false,
|
||||||
|
enabled: !!hex,
|
||||||
});
|
});
|
||||||
|
|
||||||
return { isLoading, isError, error, data };
|
return { isLoading, isError, error, data };
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export function useProfile(pubkey: string, data?: string) {
|
|||||||
case "naddr":
|
case "naddr":
|
||||||
return decoded.data.pubkey;
|
return decoded.data.pubkey;
|
||||||
default:
|
default:
|
||||||
return pubkey;
|
return normalized;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
return pubkey;
|
return pubkey;
|
||||||
|
|||||||