Skip to content

Commit b03a928

Browse files
committed
Merge branch 'preview'
2 parents e8eaac9 + 721eaad commit b03a928

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+165
-125
lines changed

src/app/dashboard/layout.tsx

+13-10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import TopBar from "@/components/navigational/topBar/TopBar";
66
import Composer from "@/components/actions/composer/Composer";
77
import { getProfile } from "@/lib/api/bsky/actor";
88
import { getSessionFromServer } from "@/lib/api/auth/session";
9+
import { AgentProvider } from "../providers/agent";
910

1011
export const metadata: Metadata = {
1112
title: { template: "%s — Ouranos", default: "Ouranos" },
@@ -21,15 +22,17 @@ export default async function DashboardLayout({
2122
const profile = await getProfile(session?.user.bskySession.handle);
2223

2324
return (
24-
<main className="bg-skin-base flex justify-center gap-6 pb-20 md:mt-6 lg:gap-16 animate-fade">
25-
{profile && <Composer author={profile} />}
26-
<SidePanel />
27-
<section className="w-full md:max-w-xl">
28-
{profile && <TopBar profile={profile} />}
29-
{children}
30-
</section>
31-
{profile && <Aside avatar={profile?.avatar} handle={profile?.handle} />}
32-
<AppBar />
33-
</main>
25+
<AgentProvider session={session}>
26+
<main className="bg-skin-base flex justify-center gap-6 pb-20 md:mt-6 lg:gap-16 animate-fade">
27+
{profile && <Composer author={profile} />}
28+
<SidePanel />
29+
<section className="w-full md:max-w-xl">
30+
{profile && <TopBar profile={profile} />}
31+
{children}
32+
</section>
33+
{profile && <Aside avatar={profile?.avatar} handle={profile?.handle} />}
34+
<AppBar />
35+
</main>
36+
</AgentProvider>
3437
);
3538
}

src/app/providers/agent.tsx

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"use client";
2+
3+
import { ReactNode, createContext, useContext, useEffect, useRef } from "react";
4+
import { createAgent } from "@/lib/api/bsky/agent";
5+
import AtpAgent from "@atproto/api";
6+
import type { Session } from "next-auth";
7+
import { isSessionExpired } from "@/lib/utils/session";
8+
import { useSession } from "next-auth/react";
9+
10+
const AgentContext = createContext<AtpAgent | null>(null);
11+
12+
interface AgentProviderProps {
13+
children: ReactNode;
14+
session: Session | null;
15+
}
16+
17+
export const AgentProvider = (props: AgentProviderProps) => {
18+
const { children, session } = props;
19+
20+
if (!session) return;
21+
const agent = createAgent(session.user.service);
22+
agent.sessionManager.session = session.user.bskySession;
23+
24+
return (
25+
<AgentContext.Provider value={agent}>{children}</AgentContext.Provider>
26+
);
27+
};
28+
29+
export const useAgent = () => {
30+
const { data: session, status } = useSession();
31+
const agent = useContext(AgentContext);
32+
33+
useEffect(() => {
34+
if (!session || !agent) return;
35+
36+
const getSession = async () => {
37+
if (isSessionExpired(session.user.bskySession)) {
38+
const result = await agent.resumeSession(session.user.bskySession);
39+
40+
if (!result.success) {
41+
throw new Error("Could not resume session");
42+
}
43+
}
44+
45+
agent.sessionManager.session = session.user.bskySession;
46+
};
47+
48+
getSession();
49+
}, [agent, session]);
50+
51+
if (status !== "authenticated" || !agent || !session?.user) {
52+
throw new Error("AgentProvider must be used inside SessionProvider");
53+
}
54+
55+
return agent;
56+
};

src/components/contentDisplay/feedHeader/FeedHeader.tsx

+2-4
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ import { BiSolidBookmarkAlt } from "react-icons/bi";
2020
import { BiPlus } from "react-icons/bi";
2121
import { BiSolidHeart } from "react-icons/bi";
2222
import Link from "next/link";
23-
import { getAgentFromClient } from "@/lib/api/bsky/agent";
23+
import { useAgent } from "@/app/providers/agent";
2424

2525
interface Props {
2626
feed: string;
2727
}
2828

2929
export default function FeedHeader(props: Props) {
3030
const { feed } = props;
31+
const agent = useAgent();
3132
const router = useRouter();
3233
const [isSaved, setIsSaved] = useState<boolean | null>(null);
3334
const [isPinned, setIsPinned] = useState<boolean | null>(null);
@@ -55,7 +56,6 @@ export default function FeedHeader(props: Props) {
5556
const toggleSave = async () => {
5657
setIsSaved((prev) => !prev);
5758
try {
58-
const agent = await getAgentFromClient();
5959
const response = await toggleSaveFeed(agent, feed);
6060
if (!response.success) {
6161
setIsSaved((prev) => !prev);
@@ -71,7 +71,6 @@ export default function FeedHeader(props: Props) {
7171
const togglePin = async () => {
7272
setIsPinned((prev) => !prev);
7373
try {
74-
const agent = await getAgentFromClient();
7574
const response = await togglePinFeed(agent, feed);
7675
if (!response.success) {
7776
setIsPinned((prev) => !prev);
@@ -85,7 +84,6 @@ export default function FeedHeader(props: Props) {
8584
};
8685

8786
const toggleLike = async () => {
88-
const agent = await getAgentFromClient();
8987
setIsLiked((prev) => !prev);
9088
if (!likeUri && feedInfo) {
9189
try {

src/components/contentDisplay/feedItem/FeedItem.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { toggleSaveFeed } from "@/lib/api/bsky/feed";
1111
import Link from "next/link";
1212
import { useQueryClient } from "@tanstack/react-query";
1313
import { savedFeedsQueryKey } from "@/containers/settings/myFeedsContainer/MyFeedsContainer";
14-
import { getAgentFromClient } from "@/lib/api/bsky/agent";
14+
import { useAgent } from "@/app/providers/agent";
1515

1616
interface Props {
1717
feedItem: GeneratorView;
@@ -21,6 +21,7 @@ interface Props {
2121

2222
export default function FeedItem(props: Props) {
2323
const { feedItem, saved, rounded = true } = props;
24+
const agent = useAgent();
2425
const { avatar, displayName, description, likeCount, creator } = feedItem;
2526
const [isSaved, setIsSaved] = useState(saved);
2627
const router = useRouter();
@@ -29,7 +30,6 @@ export default function FeedItem(props: Props) {
2930
const handleSave = async () => {
3031
setIsSaved((prev) => !prev);
3132
try {
32-
const agent = await getAgentFromClient();
3333
const response = await toggleSaveFeed(agent, feedItem.uri);
3434
if (!response.success) {
3535
setIsSaved((prev) => !prev);
@@ -46,7 +46,7 @@ export default function FeedItem(props: Props) {
4646
<Link
4747
href={{
4848
pathname: `/dashboard/feeds/${encodeURIComponent(
49-
feedItem.uri.split(":")[3].split("/")[0]
49+
feedItem.uri.split(":")[3].split("/")[0],
5050
)}`,
5151
query: { uri: feedItem.uri },
5252
}}

src/components/contentDisplay/lists/Lists.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ import FeedAlert from "@/components/feedback/feedAlert/FeedAlert";
99
import LoadingSpinner from "@/components/status/loadingSpinner/LoadingSpinner";
1010
import ListsSkeleton from "./ListsSkeleton";
1111
import InfiniteScroll from "react-infinite-scroll-component";
12-
import { getAgentFromClient } from "@/lib/api/bsky/agent";
12+
import { useAgent } from "@/app/providers/agent";
1313

1414
export default function Lists() {
1515
const { data: session } = useSession();
16+
const agent = useAgent();
1617

1718
const {
1819
status,
@@ -27,7 +28,6 @@ export default function Lists() {
2728
queryKey: ["lists"],
2829
queryFn: async ({ pageParam }) => {
2930
if (!session?.user.id) return;
30-
const agent = await getAgentFromClient();
3131
return getLists(session.user.id, pageParam, agent);
3232
},
3333
initialPageParam: "",

src/components/contentDisplay/notification/NotificationContent.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { useEffect, useState } from "react";
1111
import PostHider from "@/components/dataDisplay/postHider/PostHider";
1212
import FeedAlert from "@/components/feedback/feedAlert/FeedAlert";
1313
import NotificationContentSkeleton from "./NotificationContentSkeleton";
14-
import { getAgentFromClient } from "@/lib/api/bsky/agent";
14+
import { useAgent } from "@/app/providers/agent";
1515

1616
interface Props {
1717
uri: string;
@@ -20,12 +20,12 @@ interface Props {
2020

2121
export default function NotificationContnet(props: Props) {
2222
const { uri, filter } = props;
23+
const agent = useAgent();
2324
const router = useRouter();
2425

2526
const { status, data, error, isLoading, isFetching } = useQuery({
2627
queryKey: ["notificationContent", uri],
2728
queryFn: async () => {
28-
const agent = await getAgentFromClient();
2929
return getPost(agent, uri);
3030
},
3131
});

src/components/contentDisplay/notification/NotificationPost.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { AppBskyFeedDefs } from "@atproto/api";
66
import { ContentFilterResult } from "../../../../types/feed";
77
import { useQuery } from "@tanstack/react-query";
88
import NotificationPostSkeleton from "./NotificationPostSkeleton";
9-
import { getAgentFromClient } from "@/lib/api/bsky/agent";
9+
import { useAgent } from "@/app/providers/agent";
1010

1111
interface Props {
1212
uri: string;
@@ -15,6 +15,7 @@ interface Props {
1515

1616
export default function NotificationPost(props: Props) {
1717
const { uri, filter } = props;
18+
const agent = useAgent();
1819

1920
const {
2021
status,
@@ -25,7 +26,6 @@ export default function NotificationPost(props: Props) {
2526
} = useQuery({
2627
queryKey: ["notificationPost", uri],
2728
queryFn: async () => {
28-
const agent = await getAgentFromClient();
2929
return getPost(agent, uri);
3030
},
3131
});

src/components/navigational/appBar/AppBar.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,19 @@ import { PiMagnifyingGlassBold, PiMagnifyingGlassFill } from "react-icons/pi";
99
import { FaRegBell } from "react-icons/fa6";
1010
import { FaBell } from "react-icons/fa";
1111
import { HiClipboardList, HiOutlineClipboardList } from "react-icons/hi";
12-
import { getAgentFromClient } from "@/lib/api/bsky/agent";
12+
import { useAgent } from "@/app/providers/agent";
1313

1414
export default function AppBar() {
1515
const pathname = usePathname();
16+
const agent = useAgent();
17+
1618
const {
1719
data: notificationsCount,
1820
error,
1921
isFetching,
2022
} = useQuery({
2123
queryKey: ["notificationsCount"],
2224
queryFn: async () => {
23-
const agent = await getAgentFromClient();
2425
return getUnreadNotificationsCount(agent);
2526
},
2627
refetchInterval: 10000,

src/components/navigational/feedTabs/FeedTabs.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import FeedTabsSkeleton from "./FeedTabsSkeleton";
88
import React from "react";
99
import { useQuery } from "@tanstack/react-query";
1010
import { useScrollContext } from "@/app/providers/scroll";
11-
import { getAgentFromClient } from "@/lib/api/bsky/agent";
11+
import { useAgent } from "@/app/providers/agent";
1212

1313
export default function FeedTabs() {
14+
const agent = useAgent();
1415
const pathname = usePathname();
1516
const searchParams = useSearchParams();
1617
const uri = searchParams.get("uri");
@@ -26,7 +27,6 @@ export default function FeedTabs() {
2627
} = useQuery({
2728
queryKey: ["savedFeeds"],
2829
queryFn: async () => {
29-
const agent = await getAgentFromClient();
3030
return getSavedFeeds(agent);
3131
},
3232
});

src/components/navigational/navbar/Navbar.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,19 @@ import { HiClipboardList, HiOutlineClipboardList } from "react-icons/hi";
1616
import { FaBell, FaRegBell } from "react-icons/fa6";
1717
import { getUnreadNotificationsCount } from "@/lib/api/bsky/notification";
1818
import { useQuery } from "@tanstack/react-query";
19-
import { getAgentFromClient } from "@/lib/api/bsky/agent";
19+
import { useAgent } from "@/app/providers/agent";
2020

2121
export default function Navbar() {
22+
const agent = useAgent();
2223
const pathname = usePathname();
24+
2325
const {
2426
data: notificationsCount,
2527
error,
2628
isFetching,
2729
} = useQuery({
2830
queryKey: ["notificationsCount"],
2931
queryFn: async () => {
30-
const agent = await getAgentFromClient();
3132
return getUnreadNotificationsCount(agent);
3233
},
3334
refetchInterval: 10000,

src/containers/lists/ListMembersContainer.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ import LoadingSpinner from "@/components/status/loadingSpinner/LoadingSpinner";
88
import { getListMembers } from "@/lib/api/bsky/list";
99
import FeedAlert from "@/components/feedback/feedAlert/FeedAlert";
1010
import InfiniteScroll from "react-infinite-scroll-component";
11-
import { getAgentFromClient } from "@/lib/api/bsky/agent";
11+
import { useAgent } from "@/app/providers/agent";
1212

1313
interface Props {
1414
list: string;
1515
}
1616

1717
export default function ListMembersContainer(props: Props) {
1818
const { list } = props;
19+
const agent = useAgent();
1920

2021
const {
2122
status,
@@ -29,7 +30,6 @@ export default function ListMembersContainer(props: Props) {
2930
} = useInfiniteQuery({
3031
queryKey: ["list members", list],
3132
queryFn: async ({ pageParam }) => {
32-
const agent = await getAgentFromClient();
3333
return getListMembers(agent, list, pageParam);
3434
},
3535
initialPageParam: "",

src/containers/lists/ListsContainer.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
"use client";
22

3+
import { useAgent } from "@/app/providers/agent";
34
import ListItem from "@/components/contentDisplay/listItem/ListItem";
45
import ListsSkeleton from "@/components/contentDisplay/lists/ListsSkeleton";
56
import FeedAlert from "@/components/feedback/feedAlert/FeedAlert";
67
import LoadingSpinner from "@/components/status/loadingSpinner/LoadingSpinner";
78
import { getProfile } from "@/lib/api/bsky/actor";
8-
import { getAgentFromClient } from "@/lib/api/bsky/agent";
99
import { getLists } from "@/lib/api/bsky/list";
1010
import { useInfiniteQuery } from "@tanstack/react-query";
1111
import { Fragment } from "react";
@@ -17,6 +17,7 @@ interface Props {
1717

1818
export default function ListsContainer(props: Props) {
1919
const { handle } = props;
20+
const agent = useAgent();
2021
const {
2122
status,
2223
data: lists,
@@ -29,7 +30,6 @@ export default function ListsContainer(props: Props) {
2930
} = useInfiniteQuery({
3031
queryKey: ["user lists", handle],
3132
queryFn: async ({ pageParam }) => {
32-
const agent = await getAgentFromClient();
3333
const profile = await getProfile(handle, agent);
3434
if (!profile) throw new Error("Could not get user id to show lists");
3535
return getLists(profile.did, pageParam, agent);

src/containers/posts/UserPostsContainer.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import usePreferences from "@/lib/hooks/bsky/actor/usePreferences";
1111
import ComposeButton from "@/components/actions/composeButton/ComposeButton";
1212
import LoadingSpinner from "@/components/status/loadingSpinner/LoadingSpinner";
1313
import InfiniteScroll from "react-infinite-scroll-component";
14-
import { getAgentFromClient } from "@/lib/api/bsky/agent";
14+
import { useAgent } from "@/app/providers/agent";
1515

1616
interface Props {
1717
mode: UserPostMode;
@@ -20,6 +20,7 @@ interface Props {
2020

2121
export default function UserPostsConatiner(props: Props) {
2222
const { mode, handle } = props;
23+
const agent = useAgent();
2324
const {
2425
data: profile,
2526
isLoading,
@@ -28,7 +29,6 @@ export default function UserPostsConatiner(props: Props) {
2829
} = useQuery({
2930
queryKey: ["profile", handle],
3031
queryFn: async () => {
31-
const agent = await getAgentFromClient();
3232
return getProfile(handle, agent);
3333
},
3434
});

0 commit comments

Comments
 (0)