diff --git a/web/src/components/layout/ListSkeleton.tsx b/web/src/components/layout/ListSkeleton.tsx new file mode 100644 index 0000000..39e7055 --- /dev/null +++ b/web/src/components/layout/ListSkeleton.tsx @@ -0,0 +1,9 @@ +export default function ListSkeleton() { + return ( +
+
+
+
+
+ ); +} diff --git a/web/src/pages/BBS.tsx b/web/src/pages/BBS.tsx index c806b11..876b8cb 100644 --- a/web/src/pages/BBS.tsx +++ b/web/src/pages/BBS.tsx @@ -29,6 +29,7 @@ import ListLink from "../components/nav/ListLink"; import ActionBar from "../components/nav/ActionBar"; import { ActionLink } from "../components/nav/ActionButton"; import PinButton from "../components/PinButton"; +import ListSkeleton from "../components/layout/ListSkeleton"; const INITIAL_NEWS_COUNT = 3; @@ -41,7 +42,7 @@ export default function BBSPage() { const [showAllNews, setShowAllNews] = useState(false); const { data: bbs } = useSuspenseQuery(bbsQuery(handle!)); - const { data: news } = useSuspenseQuery(newsQuery(bbs.identity.did)); + const { data: news } = useQuery(newsQuery(bbs.identity.did)); const { data: pins } = useQuery({ ...pinsQuery(user?.pdsUrl ?? "", user?.did ?? ""), enabled: !!user, @@ -104,7 +105,11 @@ export default function BBSPage() { }); } - const visibleNews = showAllNews ? news : news.slice(0, INITIAL_NEWS_COUNT); + const visibleNews = news + ? showAllNews + ? news + : news.slice(0, INITIAL_NEWS_COUNT) + : []; return ( <> @@ -185,7 +190,9 @@ export default function BBSPage() { )} - {news.length ? ( + {!news ? ( + + ) : news.length ? ( <> {visibleNews.map((item, i) => ( page.threads); - const threads = isSysop - ? allThreads - : allThreads.filter( - (t) => - !moderation.banRkeys[t.did] && - !moderation.hideRkeys[t.uri], - ); + const ready = !!threadPages && !!moderation; + const allThreads = threadPages?.pages.flatMap((page) => page.threads) ?? []; + const threads = + isSysop || !moderation + ? allThreads + : allThreads.filter( + (t) => + !moderation.banRkeys[t.did] && !moderation.hideRkeys[t.uri], + ); const [title, setTitle] = useState(""); const [body, setBody] = useState(""); @@ -195,7 +196,9 @@ export default function BoardPage() { )}
- {threads.length ? ( + {!ready ? ( + + ) : threads.length ? ( <> {threads.map((t) => ( diff --git a/web/src/pages/Dashboard.tsx b/web/src/pages/Dashboard.tsx index 1db0c6f..9fa2e58 100644 --- a/web/src/pages/Dashboard.tsx +++ b/web/src/pages/Dashboard.tsx @@ -1,5 +1,5 @@ import { useMemo, useState } from "react"; -import { useSuspenseQuery, useMutation } from "@tanstack/react-query"; +import { useQuery, useMutation } from "@tanstack/react-query"; import { useAuth, type AuthUser } from "../lib/auth"; import { deleteBBS } from "../lib/deletebbs"; import { usePageTitle } from "../hooks/usePageTitle"; @@ -20,6 +20,7 @@ import PinnedList from "../components/dashboard/PinnedList"; import MyThreadList from "../components/dashboard/MyThreadList"; import ActivityList from "../components/dashboard/ActivityList"; import BBSPanel from "../components/dashboard/BBSPanel"; +import ListSkeleton from "../components/layout/ListSkeleton"; type Tab = "inbox" | "threads" | "pinned" | "bbs"; @@ -37,17 +38,14 @@ export default function Dashboard({ user }: DashboardProps) { const [tab, setTab] = useState("inbox"); usePageTitle("atbbs"); - const { data: sysopInfo } = useSuspenseQuery(homeSysopQuery(user.did)); - const { data: pins } = useSuspenseQuery(pinsQuery(user.pdsUrl, user.did)); - const { data: threads } = useSuspenseQuery( - myThreadsQuery(user.pdsUrl, user.did), - ); - const { data: activity } = useSuspenseQuery( - activityQuery(user.pdsUrl, user.did), - ); - const { data: discovered } = useSuspenseQuery(discoveryQuery()); + const { data: sysopInfo } = useQuery(homeSysopQuery(user.did)); + const { data: pins } = useQuery(pinsQuery(user.pdsUrl, user.did)); + const { data: threads } = useQuery(myThreadsQuery(user.pdsUrl, user.did)); + const { data: activity } = useQuery(activityQuery(user.pdsUrl, user.did)); + const { data: discovered } = useQuery(discoveryQuery()); - const suggestions = useMemo(() => { + const suggestions = useMemo(() => { + if (!pins || !discovered) return undefined; const pinnedDids = new Set(pins.map((pin) => pin.did)); const fromPins = pins.map(bbsToSuggestion); const fromDiscovery = discovered @@ -120,7 +118,7 @@ export default function Dashboard({ user }: DashboardProps) {

Recent replies from other users.

- + {activity ? : } )} @@ -129,7 +127,7 @@ export default function Dashboard({ user }: DashboardProps) {

Threads you've posted across all communities.

- + {threads ? : } )} @@ -138,7 +136,7 @@ export default function Dashboard({ user }: DashboardProps) {

Communities you've pinned for quick access.

- + {pins ? : } )} @@ -147,15 +145,20 @@ export default function Dashboard({ user }: DashboardProps) {

Manage your community.

- + {sysopInfo ? ( + + ) : ( + + )} )} ); } + diff --git a/web/src/pages/LoggedOutHome.tsx b/web/src/pages/LoggedOutHome.tsx index 0a2b9f4..35c8ee1 100644 --- a/web/src/pages/LoggedOutHome.tsx +++ b/web/src/pages/LoggedOutHome.tsx @@ -1,6 +1,6 @@ import { useMemo, useState } from "react"; import { Phone, Copy, Check } from "lucide-react"; -import { useSuspenseQuery } from "@tanstack/react-query"; +import { useQuery } from "@tanstack/react-query"; import { usePageTitle } from "../hooks/usePageTitle"; import { discoveryQuery } from "../lib/queries"; import DialBBS, { @@ -10,9 +10,9 @@ import DialBBS, { import DiscoveryList from "../components/dashboard/DiscoveryList"; export default function LoggedOutHome() { - const { data: discovered } = useSuspenseQuery(discoveryQuery()); - const suggestions = useMemo( - () => discovered.map(bbsToSuggestion), + const { data: discovered } = useQuery(discoveryQuery()); + const suggestions = useMemo( + () => discovered?.map(bbsToSuggestion), [discovered], ); const [tab, setTab] = useState<"brew" | "uv" | "telnet">("brew"); @@ -73,7 +73,7 @@ export default function LoggedOutHome() {
- + {discovered && }
diff --git a/web/src/pages/Profile.tsx b/web/src/pages/Profile.tsx index d338404..3080134 100644 --- a/web/src/pages/Profile.tsx +++ b/web/src/pages/Profile.tsx @@ -1,6 +1,6 @@ import { useState } from "react"; import { useParams } from "react-router-dom"; -import { useSuspenseQuery, useMutation } from "@tanstack/react-query"; +import { useQuery, useMutation } from "@tanstack/react-query"; import { MessageSquare } from "lucide-react"; import { useAuth } from "../lib/auth"; import { usePageTitle } from "../hooks/usePageTitle"; @@ -10,16 +10,18 @@ import { queryClient } from "../lib/queryClient"; import ViewProfile from "../components/profile/ViewProfile"; import EditProfile from "../components/profile/EditProfile"; import MyThreadList from "../components/dashboard/MyThreadList"; +import ListSkeleton from "../components/layout/ListSkeleton"; export default function Profile() { const { handle } = useParams(); const { user, agent } = useAuth(); const [editing, setEditing] = useState(false); - const { data: profile } = useSuspenseQuery(profileQuery(handle!)); - const { data: threads } = useSuspenseQuery( - myThreadsQuery(profile?.pdsUrl ?? "", profile?.did ?? ""), - ); + const { data: profile } = useQuery(profileQuery(handle!)); + const { data: threads } = useQuery({ + ...myThreadsQuery(profile?.pdsUrl ?? "", profile?.did ?? ""), + enabled: !!profile, + }); usePageTitle(`${profile?.name ?? handle} — atbbs`); @@ -58,7 +60,7 @@ export default function Profile() { <> setEditing(true)} /> @@ -66,7 +68,11 @@ export default function Profile() {

Recent Threads

- + {threads ? ( + + ) : ( + + )}
);