fix the rest of warnings
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Martti Malmi 2024-01-10 20:16:30 +02:00
parent e6a42db658
commit 5baffd00b9
37 changed files with 415 additions and 390 deletions

View File

@ -2,5 +2,5 @@ import {ParsedFragment} from "@snort/system";
import { LRUCache } from "typescript-lru-cache"; import { LRUCache } from "typescript-lru-cache";
export const TextCache = new LRUCache<string, Array<ParsedFragment>>({ export const TextCache = new LRUCache<string, Array<ParsedFragment>>({
maxSize: 1000 maxSize: 1000,
}); });

View File

@ -8,7 +8,7 @@ import IconButton from "@/Components/Button/IconButton";
import Icon from "@/Components/Icons/Icon"; import Icon from "@/Components/Icons/Icon";
import useEventPublisher from "@/Hooks/useEventPublisher"; import useEventPublisher from "@/Hooks/useEventPublisher";
import useLogin from "@/Hooks/useLogin"; import useLogin from "@/Hooks/useLogin";
import { saveRelays } from "@/Pages/settings/Relays"; import { saveRelays } from "@/Pages/settings/saveRelays";
import { getRelayName } from "@/Utils"; import { getRelayName } from "@/Utils";
import { removeRelay } from "@/Utils/Login"; import { removeRelay } from "@/Utils/Login";

View File

@ -9,8 +9,8 @@ import NoteHeader from "@/Components/Event/Note/NoteHeader";
import { NoteText } from "@/Components/Event/Note/NoteText"; import { NoteText } from "@/Components/Event/Note/NoteText";
import { TranslationInfo } from "@/Components/Event/Note/TranslationInfo"; import { TranslationInfo } from "@/Components/Event/Note/TranslationInfo";
import useModeration from "@/Hooks/useModeration"; import useModeration from "@/Hooks/useModeration";
import { chainKey } from "@/Hooks/useThreadContext";
import { findTag } from "@/Utils"; import { findTag } from "@/Utils";
import { chainKey } from "@/Utils/Thread/ChainKey";
import messages from "../../messages"; import messages from "../../messages";
import Text from "../../Text/Text"; import Text from "../../Text/Text";

View File

@ -10,7 +10,9 @@ import BackButton from "@/Components/Button/BackButton";
import Collapsed from "@/Components/Collapsed"; import Collapsed from "@/Components/Collapsed";
import Note from "@/Components/Event/EventComponent"; import Note from "@/Components/Event/EventComponent";
import NoteGhost from "@/Components/Event/Note/NoteGhost"; import NoteGhost from "@/Components/Event/Note/NoteGhost";
import { chainKey, ThreadContext, ThreadContextWrapper } from "@/Hooks/useThreadContext"; import { chainKey } from "@/Utils/Thread/ChainKey";
import { ThreadContext } from "@/Utils/Thread/ThreadContext";
import { ThreadContextWrapper } from "@/Utils/Thread/ThreadContextWrapper";
import messages from "../messages"; import messages from "../messages";

View File

@ -3,8 +3,8 @@ import { NostrLink, TaggedNostrEvent } from "@snort/system";
import { Thread } from "@/Components/Event/Thread"; import { Thread } from "@/Components/Event/Thread";
import Modal from "@/Components/Modal/Modal"; import Modal from "@/Components/Modal/Modal";
import { SpotlightMedia } from "@/Components/Spotlight/SpotlightMedia"; import { SpotlightMedia } from "@/Components/Spotlight/SpotlightMedia";
import { ThreadContextWrapper } from "@/Hooks/useThreadContext";
import getEventMedia from "@/Utils/getEventMedia"; import getEventMedia from "@/Utils/getEventMedia";
import { ThreadContextWrapper } from "@/Utils/Thread/ThreadContextWrapper";
interface SpotlightThreadModalProps { interface SpotlightThreadModalProps {
thread?: NostrLink; thread?: NostrLink;

View File

@ -1,273 +0,0 @@
import { unixNow } from "@snort/shared";
import { NostrLink } from "@snort/system";
import { SnortContext } from "@snort/system-react";
import { lazy, useContext, useEffect, useMemo, useState } from "react";
import { FormattedMessage } from "react-intl";
import { Link, Outlet, RouteObject, useParams } from "react-router-dom";
import Timeline from "@/Components/Feed/Timeline";
import TimelineFollows from "@/Components/Feed/TimelineFollows";
import SuggestedProfiles from "@/Components/SuggestedProfiles";
import { TaskList } from "@/Components/Tasks/TaskList";
import TrendingHashtags from "@/Components/Trending/TrendingHashtags";
import TrendingNotes from "@/Components/Trending/TrendingPosts";
import { TimelineSubject } from "@/Feed/TimelineFeed";
import useLogin from "@/Hooks/useLogin";
import { DeckContext } from "@/Pages/DeckLayout";
import Discover from "@/Pages/Discover";
import HashTagsPage from "@/Pages/HashTagsPage";
import { debounce, getCurrentRefCode, getRelayName, sha256 } from "@/Utils";
import { TopicsPage } from "./TopicsPage";
const InviteModal = lazy(() => import("@/Components/Invite"));
import useHistoryState from "@/Hooks/useHistoryState";
import messages from "./messages";
interface RelayOption {
url: string;
paid: boolean;
}
export default function RootPage() {
const code = getCurrentRefCode();
return (
<>
<div className="main-content">
<Outlet />
</div>
{code && <InviteModal />}
</>
);
}
const FollowsHint = () => {
const { publicKey: pubKey, follows } = useLogin();
if (follows.item?.length === 0 && pubKey) {
return (
<FormattedMessage
{...messages.NoFollows}
values={{
newUsersPage: (
<Link to={"/discover"}>
<FormattedMessage {...messages.NewUsers} />
</Link>
),
}}
/>
);
}
return null;
};
export const GlobalTab = () => {
const { relays } = useLogin();
const [relay, setRelay] = useHistoryState<RelayOption>(undefined, "global-relay");
const [allRelays, setAllRelays] = useHistoryState<RelayOption[]>(undefined, "global-relay-options");
const [now] = useState(unixNow());
const system = useContext(SnortContext);
function globalRelaySelector() {
if (!allRelays || allRelays.length === 0) return null;
const paidRelays = allRelays.filter(a => a.paid);
const publicRelays = allRelays.filter(a => !a.paid);
return (
<div className="flex items-center g8 justify-end nowrap">
<h3>
<FormattedMessage
defaultMessage="Relay"
id="KHK8B9"
description="Label for reading global feed from specific relays"
/>
</h3>
<select
className="f-ellipsis"
onChange={e => setRelay(allRelays.find(a => a.url === e.target.value))}
value={relay?.url}>
{paidRelays.length > 0 && (
<optgroup label="Paid Relays">
{paidRelays.map(a => (
<option key={a.url} value={a.url}>
{getRelayName(a.url)}
</option>
))}
</optgroup>
)}
<optgroup label="Public Relays">
{publicRelays.map(a => (
<option key={a.url} value={a.url}>
{getRelayName(a.url)}
</option>
))}
</optgroup>
</select>
</div>
);
}
useEffect(() => {
return debounce(500, () => {
const ret: RelayOption[] = [];
system.Sockets.forEach(v => {
if (v.connected) {
ret.push({
url: v.address,
paid: v.info?.limitation?.payment_required ?? false,
});
}
});
ret.sort(a => (a.paid ? -1 : 1));
if (ret.length > 0 && !relay) {
setRelay(ret[0]);
}
setAllRelays(ret);
});
}, [relays, relay]);
return (
<>
{globalRelaySelector()}
{relay && (
<Timeline
subject={{
type: "global",
items: [],
relay: [relay.url],
discriminator: `all-${sha256(relay.url)}`,
}}
postsOnly={false}
method={"TIME_RANGE"}
window={600}
now={now}
/>
)}
</>
);
};
export const FollowedByFriendsTab = () => {
const { publicKey } = useLogin();
const subject: TimelineSubject = {
type: "global",
items: [],
discriminator: `followed-by-friends-${publicKey}`,
streams: true,
};
return <Timeline followDistance={2} subject={subject} postsOnly={true} method={"TIME_RANGE"} />;
};
export const NotesTab = () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const deckContext = useContext(DeckContext);
const noteOnClick = useMemo(() => {
if (deckContext) {
return ev => {
deckContext.setThread(NostrLink.fromEvent(ev));
};
}
return undefined;
}, [deckContext]);
return (
<>
<FollowsHint />
<TaskList />
<TimelineFollows postsOnly={true} noteOnClick={noteOnClick} />
</>
);
};
export const ConversationsTab = () => {
return <TimelineFollows postsOnly={false} />;
};
export const TagsTab = (params: { tag?: string }) => {
const { tag } = useParams();
const t = params.tag ?? tag ?? "";
const subject: TimelineSubject = {
type: "hashtag",
items: [t],
discriminator: `tags-${t}`,
streams: true,
};
return <Timeline subject={subject} postsOnly={false} method={"TIME_RANGE"} />;
};
const DefaultTab = () => {
const { preferences, publicKey } = useLogin(s => ({
preferences: s.appData.item.preferences,
publicKey: s.publicKey,
}));
const tab = publicKey ? preferences.defaultRootTab ?? `notes` : `trending/notes`;
const elm = RootTabRoutes.find(a => a.path === tab)?.element;
return elm;
};
export const RootTabRoutes = [
{
path: "",
element: <DefaultTab />,
},
{
path: "global",
element: <GlobalTab />,
},
{
path: "notes",
element: <NotesTab />,
},
{
path: "followed-by-friends",
element: <FollowedByFriendsTab />,
},
{
path: "conversations",
element: <ConversationsTab />,
},
{
path: "discover",
element: <Discover />,
},
{
path: "tag/:tag",
element: <TagsTab />,
},
{
path: "trending/notes",
element: <TrendingNotes />,
},
{
path: "trending/hashtags",
element: <TrendingHashtags />,
},
{
path: "suggested",
element: (
<div className="p">
<SuggestedProfiles />
</div>
),
},
{
path: "t/:tag",
element: <HashTagsPage />,
},
{
path: "topics",
element: <TopicsPage />,
},
];
export const RootRoutes = [
{
path: "/",
element: <RootPage />,
children: RootTabRoutes,
},
] as RouteObject[];

View File

@ -0,0 +1,5 @@
import TimelineFollows from "@/Components/Feed/TimelineFollows";
export const ConversationsTab = () => {
return <TimelineFollows postsOnly={false} />;
};

View File

@ -0,0 +1,12 @@
import useLogin from "@/Hooks/useLogin";
import { RootTabRoutes } from "@/Pages/Root/RootTabRoutes";
export const DefaultTab = () => {
const { preferences, publicKey } = useLogin(s => ({
preferences: s.appData.item.preferences,
publicKey: s.publicKey,
}));
const tab = publicKey ? preferences.defaultRootTab ?? `notes` : `trending/notes`;
const elm = RootTabRoutes.find(a => a.path === tab)?.element;
return elm;
};

View File

@ -0,0 +1,15 @@
import Timeline from "@/Components/Feed/Timeline";
import { TimelineSubject } from "@/Feed/TimelineFeed";
import useLogin from "@/Hooks/useLogin";
export const FollowedByFriendsTab = () => {
const { publicKey } = useLogin();
const subject: TimelineSubject = {
type: "global",
items: [],
discriminator: `followed-by-friends-${publicKey}`,
streams: true,
};
return <Timeline followDistance={2} subject={subject} postsOnly={true} method={"TIME_RANGE"} />;
};

View File

@ -0,0 +1,101 @@
import { unixNow } from "@snort/shared";
import { SnortContext } from "@snort/system-react";
import { useContext, useEffect, useState } from "react";
import { FormattedMessage } from "react-intl";
import Timeline from "@/Components/Feed/Timeline";
import useHistoryState from "@/Hooks/useHistoryState";
import useLogin from "@/Hooks/useLogin";
import { debounce, getRelayName, sha256 } from "@/Utils";
interface RelayOption {
url: string;
paid: boolean;
}
export const GlobalTab = () => {
const { relays } = useLogin();
const [relay, setRelay] = useHistoryState<RelayOption>(undefined, "global-relay");
const [allRelays, setAllRelays] = useHistoryState<RelayOption[]>(undefined, "global-relay-options");
const [now] = useState(unixNow());
const system = useContext(SnortContext);
function globalRelaySelector() {
if (!allRelays || allRelays.length === 0) return null;
const paidRelays = allRelays.filter(a => a.paid);
const publicRelays = allRelays.filter(a => !a.paid);
return (
<div className="flex items-center g8 justify-end nowrap">
<h3>
<FormattedMessage
defaultMessage="Relay"
id="KHK8B9"
description="Label for reading global feed from specific relays"
/>
</h3>
<select
className="f-ellipsis"
onChange={e => setRelay(allRelays.find(a => a.url === e.target.value))}
value={relay?.url}>
{paidRelays.length > 0 && (
<optgroup label="Paid Relays">
{paidRelays.map(a => (
<option key={a.url} value={a.url}>
{getRelayName(a.url)}
</option>
))}
</optgroup>
)}
<optgroup label="Public Relays">
{publicRelays.map(a => (
<option key={a.url} value={a.url}>
{getRelayName(a.url)}
</option>
))}
</optgroup>
</select>
</div>
);
}
useEffect(() => {
return debounce(500, () => {
const ret: RelayOption[] = [];
system.Sockets.forEach(v => {
if (v.connected) {
ret.push({
url: v.address,
paid: v.info?.limitation?.payment_required ?? false,
});
}
});
ret.sort(a => (a.paid ? -1 : 1));
if (ret.length > 0 && !relay) {
setRelay(ret[0]);
}
setAllRelays(ret);
});
}, [relays, relay]);
return (
<>
{globalRelaySelector()}
{relay && (
<Timeline
subject={{
type: "global",
items: [],
relay: [relay.url],
discriminator: `all-${sha256(relay.url)}`,
}}
postsOnly={false}
method={"TIME_RANGE"}
window={600}
now={now}
/>
)}
</>
);
};

View File

@ -0,0 +1,50 @@
import { NostrLink } from "@snort/system";
import { useContext, useMemo } from "react";
import { FormattedMessage } from "react-intl";
import { Link } from "react-router-dom";
import TimelineFollows from "@/Components/Feed/TimelineFollows";
import { TaskList } from "@/Components/Tasks/TaskList";
import useLogin from "@/Hooks/useLogin";
import { DeckContext } from "@/Pages/DeckLayout";
import messages from "@/Pages/messages";
const FollowsHint = () => {
const { publicKey: pubKey, follows } = useLogin();
if (follows.item?.length === 0 && pubKey) {
return (
<FormattedMessage
{...messages.NoFollows}
values={{
newUsersPage: (
<Link to={"/discover"}>
<FormattedMessage {...messages.NewUsers} />
</Link>
),
}}
/>
);
}
return null;
};
export const NotesTab = () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const deckContext = useContext(DeckContext);
const noteOnClick = useMemo(() => {
if (deckContext) {
return ev => {
deckContext.setThread(NostrLink.fromEvent(ev));
};
}
return undefined;
}, [deckContext]);
return (
<>
<FollowsHint />
<TaskList />
<TimelineFollows postsOnly={true} noteOnClick={noteOnClick} />
</>
);
};

View File

@ -0,0 +1,25 @@
import { lazy } from "react";
import { Outlet, RouteObject } from "react-router-dom";
import { RootTabRoutes } from "@/Pages/Root/RootTabRoutes";
import { getCurrentRefCode } from "@/Utils";
const InviteModal = lazy(() => import("@/Components/Invite"));
export default function RootPage() {
const code = getCurrentRefCode();
return (
<>
<div className="main-content">
<Outlet />
</div>
{code && <InviteModal />}
</>
);
}
export const RootRoutes = [
{
path: "/",
element: <RootPage />,
children: RootTabRoutes,
},
] as RouteObject[];

View File

@ -0,0 +1,67 @@
import SuggestedProfiles from "@/Components/SuggestedProfiles";
import TrendingHashtags from "@/Components/Trending/TrendingHashtags";
import TrendingNotes from "@/Components/Trending/TrendingPosts";
import Discover from "@/Pages/Discover";
import HashTagsPage from "@/Pages/HashTagsPage";
import { ConversationsTab } from "@/Pages/Root/ConversationsTab";
import { DefaultTab } from "@/Pages/Root/DefaultTab";
import { FollowedByFriendsTab } from "@/Pages/Root/FollowedByFriendsTab";
import { GlobalTab } from "@/Pages/Root/GlobalTab";
import { NotesTab } from "@/Pages/Root/NotesTab";
import { TagsTab } from "@/Pages/Root/TagsTab";
import { TopicsPage } from "@/Pages/TopicsPage";
export const RootTabRoutes = [
{
path: "",
element: <DefaultTab />,
},
{
path: "global",
element: <GlobalTab />,
},
{
path: "notes",
element: <NotesTab />,
},
{
path: "followed-by-friends",
element: <FollowedByFriendsTab />,
},
{
path: "conversations",
element: <ConversationsTab />,
},
{
path: "discover",
element: <Discover />,
},
{
path: "tag/:tag",
element: <TagsTab />,
},
{
path: "trending/notes",
element: <TrendingNotes />,
},
{
path: "trending/hashtags",
element: <TrendingHashtags />,
},
{
path: "suggested",
element: (
<div className="p">
<SuggestedProfiles />
</div>
),
},
{
path: "t/:tag",
element: <HashTagsPage />,
},
{
path: "topics",
element: <TopicsPage />,
},
];

View File

@ -0,0 +1,17 @@
import { useParams } from "react-router-dom";
import Timeline from "@/Components/Feed/Timeline";
import { TimelineSubject } from "@/Feed/TimelineFeed";
export const TagsTab = (params: { tag?: string }) => {
const { tag } = useParams();
const t = params.tag ?? tag ?? "";
const subject: TimelineSubject = {
type: "hashtag",
items: [t],
discriminator: `tags-${t}`,
streams: true,
};
return <Timeline subject={subject} postsOnly={false} method={"TIME_RANGE"} />;
};

View File

@ -1,5 +1,4 @@
import { unixNowMs, unwrap } from "@snort/shared"; import { unixNowMs, unwrap } from "@snort/shared";
import { EventPublisher, FullRelaySettings, RelaySettings, SystemInterface } from "@snort/system";
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
@ -8,25 +7,13 @@ import Relay from "@/Components/Relay/Relay";
import SnortApi, { RelayDistance } from "@/External/SnortApi"; import SnortApi, { RelayDistance } from "@/External/SnortApi";
import useEventPublisher from "@/Hooks/useEventPublisher"; import useEventPublisher from "@/Hooks/useEventPublisher";
import useLogin from "@/Hooks/useLogin"; import useLogin from "@/Hooks/useLogin";
import { saveRelays } from "@/Pages/settings/saveRelays";
import { getCountry, getRelayName, sanitizeRelayUrl } from "@/Utils"; import { getCountry, getRelayName, sanitizeRelayUrl } from "@/Utils";
import { Blasters } from "@/Utils/Const";
import { setRelays } from "@/Utils/Login"; import { setRelays } from "@/Utils/Login";
import { formatShort } from "@/Utils/Number"; import { formatShort } from "@/Utils/Number";
import messages from "./messages"; import messages from "./messages";
export async function saveRelays(
system: SystemInterface,
publisher: EventPublisher | undefined,
relays: Array<FullRelaySettings> | Record<string, RelaySettings>,
) {
if (publisher) {
const ev = await publisher.relayList(relays);
await system.BroadcastEvent(ev);
await Promise.all(Blasters.map(a => system.WriteOnceToRelay(a, ev)));
}
}
const RelaySettingsPage = () => { const RelaySettingsPage = () => {
const { publisher, system } = useEventPublisher(); const { publisher, system } = useEventPublisher();
const login = useLogin(); const login = useLogin();

View File

@ -16,18 +16,14 @@ import Relay from "@/Pages/settings/Relays";
import { ToolsPage, ToolsPages } from "./tools"; import { ToolsPage, ToolsPages } from "./tools";
import { WalletSettingsRoutes } from "./wallet"; import { WalletSettingsRoutes } from "./wallet";
const SettingsPage = () => {
return (
<div className="px-3">
<Outlet />
</div>
);
};
export default [ export default [
{ {
path: "/settings", path: "/settings",
element: <SettingsPage />, element: (
<div className="px-3">
<Outlet />
</div>
),
children: [ children: [
{ {
path: "", path: "",

View File

@ -0,0 +1,15 @@
import { EventPublisher, FullRelaySettings, RelaySettings, SystemInterface } from "@snort/system";
import { Blasters } from "@/Utils/Const";
export async function saveRelays(
system: SystemInterface,
publisher: EventPublisher | undefined,
relays: Array<FullRelaySettings> | Record<string, RelaySettings>,
) {
if (publisher) {
const ev = await publisher.relayList(relays);
await system.BroadcastEvent(ev);
await Promise.all(Blasters.map(a => system.WriteOnceToRelay(a, ev)));
}
}

View File

@ -0,0 +1,18 @@
import { unwrap } from "@snort/shared";
import { EventExt, NostrLink, TaggedNostrEvent } from "@snort/system";
/**
* Get the chain key as a reply event
*/
export function replyChainKey(ev: TaggedNostrEvent) {
const t = EventExt.extractThread(ev);
return t?.replyTo?.value ?? t?.root?.value;
}
/**
* Get the chain key of this event
*/
export function chainKey(ev: TaggedNostrEvent) {
const link = NostrLink.fromEvent(ev);
return unwrap(link.toEventTag())[1];
}

View File

@ -0,0 +1,14 @@
/* eslint-disable no-debugger */
import { TaggedNostrEvent } from "@snort/system";
import { createContext } from "react";
interface ThreadContext {
current: string;
root?: TaggedNostrEvent;
chains: Map<string, Array<TaggedNostrEvent>>;
data: Array<TaggedNostrEvent>;
reactions: Array<TaggedNostrEvent>;
setCurrent: (i: string) => void;
}
export const ThreadContext = createContext({} as ThreadContext);

View File

@ -1,39 +1,12 @@
/* eslint-disable no-debugger */
import { unwrap } from "@snort/shared"; import { unwrap } from "@snort/shared";
import { EventExt, NostrLink, TaggedNostrEvent, u256 } from "@snort/system"; import { NostrLink, TaggedNostrEvent, u256 } from "@snort/system";
import { createContext, ReactNode, useMemo, useState } from "react"; import { ReactNode, useMemo, useState } from "react";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import useThreadFeed from "@/Feed/ThreadFeed"; import useThreadFeed from "@/Feed/ThreadFeed";
import useModeration from "@/Hooks/useModeration";
import useModeration from "./useModeration"; import { chainKey, replyChainKey } from "@/Utils/Thread/ChainKey";
import { ThreadContext } from "@/Utils/Thread/ThreadContext";
export interface ThreadContext {
current: string;
root?: TaggedNostrEvent;
chains: Map<string, Array<TaggedNostrEvent>>;
data: Array<TaggedNostrEvent>;
reactions: Array<TaggedNostrEvent>;
setCurrent: (i: string) => void;
}
export const ThreadContext = createContext({} as ThreadContext);
/**
* Get the chain key as a reply event
*/
export function replyChainKey(ev: TaggedNostrEvent) {
const t = EventExt.extractThread(ev);
return t?.replyTo?.value ?? t?.root?.value;
}
/**
* Get the chain key of this event
*/
export function chainKey(ev: TaggedNostrEvent) {
const link = NostrLink.fromEvent(ev);
return unwrap(link.toEventTag())[1];
}
export function ThreadContextWrapper({ link, children }: { link: NostrLink; children?: ReactNode }) { export function ThreadContextWrapper({ link, children }: { link: NostrLink; children?: ReactNode }) {
const location = useLocation(); const location = useLocation();

View File

@ -29,7 +29,8 @@ import NostrLinkHandler from "@/Pages/NostrLinkHandler";
import NotificationsPage from "@/Pages/Notifications/Notifications"; import NotificationsPage from "@/Pages/Notifications/Notifications";
import { OnboardingRoutes } from "@/Pages/onboarding"; import { OnboardingRoutes } from "@/Pages/onboarding";
import ProfilePage from "@/Pages/Profile/ProfilePage"; import ProfilePage from "@/Pages/Profile/ProfilePage";
import { RootRoutes, RootTabRoutes } from "@/Pages/Root"; import { RootRoutes } from "@/Pages/Root/RootRoutes";
import { RootTabRoutes } from "@/Pages/Root/RootTabRoutes";
import SearchPage from "@/Pages/SearchPage"; import SearchPage from "@/Pages/SearchPage";
import SettingsRoutes from "@/Pages/settings/Routes"; import SettingsRoutes from "@/Pages/settings/Routes";
import { SubscribeRoutes } from "@/Pages/subscribe"; import { SubscribeRoutes } from "@/Pages/subscribe";