Skip to content

Commit 1e27491

Browse files
committed
[TOOL-2815] Nebula - handle disconnected wallet state, use connected account address in execute config (#5821)
## Problem solved Short description of the bug fixed or feature added <!-- start pr-codex --> --- ## PR-Codex overview This PR primarily focuses on refining the chat functionality and user experience in the `ChatBar` and `ChatPageContent` components. It enhances wallet connection handling, streamlines message sending, and introduces a dialog for when the wallet is disconnected. ### Detailed summary - Added `e.preventDefault()` in `ChatBar` to prevent default behavior on Enter key. - Removed unused wallet address fetching in several components. - Updated `config` type to allow `null` in `Chat` API. - Introduced `WalletDisconnectedDialog` in `ChatPageContent`. - Enhanced state management for showing different login pages. - Improved context filter updates based on wallet address and active chain. - Added conditional rendering for wallet connection prompts. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 1b103d7 commit 1e27491

File tree

7 files changed

+86
-56
lines changed

7 files changed

+86
-56
lines changed

apps/dashboard/src/app/nebula-app/(app)/api/chat.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export type ContextFilters = {
1313
export async function promptNebula(params: {
1414
message: string;
1515
sessionId: string;
16-
config: ExecuteConfig;
16+
config: ExecuteConfig | null;
1717
authToken: string;
1818
handleStream: (res: ChatStreamedResponse) => void;
1919
abortController: AbortController;
@@ -24,7 +24,6 @@ export async function promptNebula(params: {
2424
user_id: "default-user",
2525
session_id: params.sessionId,
2626
stream: true,
27-
execute_config: params.config,
2827
};
2928

3029
if (params.contextFilters) {
@@ -34,6 +33,10 @@ export async function promptNebula(params: {
3433
};
3534
}
3635

36+
if (params.config) {
37+
body.execute_config = params.config;
38+
}
39+
3740
const events = await stream(`${NEXT_PUBLIC_NEBULA_URL}/chat`, {
3841
method: "POST",
3942
headers: {

apps/dashboard/src/app/nebula-app/(app)/chat/[session_id]/page.tsx

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { redirect } from "next/navigation";
22
import { getValidAccount } from "../../../../account/settings/getAccount";
3-
import {
4-
getAuthToken,
5-
getAuthTokenWalletAddress,
6-
} from "../../../../api/lib/getAuthToken";
3+
import { getAuthToken } from "../../../../api/lib/getAuthToken";
74
import { loginRedirect } from "../../../../login/loginRedirect";
85
import { getSessionById } from "../../api/session";
96
import { ChatPageContent } from "../../components/ChatPageContent";
@@ -22,12 +19,6 @@ export default async function Page(props: {
2219
loginRedirect(pagePath);
2320
}
2421

25-
const accountAddress = await getAuthTokenWalletAddress();
26-
27-
if (!accountAddress) {
28-
loginRedirect(pagePath);
29-
}
30-
3122
const session = await getSessionById({
3223
authToken,
3324
sessionId: params.session_id,
@@ -39,7 +30,6 @@ export default async function Page(props: {
3930

4031
return (
4132
<ChatPageContent
42-
accountAddress={accountAddress}
4333
authToken={authToken}
4434
session={session}
4535
type="new-chat"

apps/dashboard/src/app/nebula-app/(app)/chat/page.tsx

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import { getValidAccount } from "../../../account/settings/getAccount";
2-
import {
3-
getAuthToken,
4-
getAuthTokenWalletAddress,
5-
} from "../../../api/lib/getAuthToken";
2+
import { getAuthToken } from "../../../api/lib/getAuthToken";
63
import { loginRedirect } from "../../../login/loginRedirect";
74
import { ChatPageContent } from "../components/ChatPageContent";
85

@@ -14,15 +11,8 @@ export default async function Page() {
1411
loginRedirect();
1512
}
1613

17-
const accountAddress = await getAuthTokenWalletAddress();
18-
19-
if (!accountAddress) {
20-
loginRedirect();
21-
}
22-
2314
return (
2415
<ChatPageContent
25-
accountAddress={accountAddress}
2616
authToken={authToken}
2717
session={undefined}
2818
type="new-chat"

apps/dashboard/src/app/nebula-app/(app)/components/ChatBar.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export function Chatbar(props: {
2525
return;
2626
}
2727
if (e.key === "Enter" && !props.isChatStreaming) {
28+
e.preventDefault();
2829
setMessage("");
2930
props.sendMessage(message);
3031
}

apps/dashboard/src/app/nebula-app/(app)/components/ChatPageContent.tsx

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
"use client";
2+
import { Button } from "@/components/ui/button";
3+
import {
4+
Dialog,
5+
DialogClose,
6+
DialogContent,
7+
DialogDescription,
8+
DialogHeader,
9+
DialogTitle,
10+
} from "@/components/ui/dialog";
211
import { useThirdwebClient } from "@/constants/thirdweb.client";
312
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
13+
import { ArrowRightIcon } from "lucide-react";
14+
import Link from "next/link";
415
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
516
import { useActiveAccount, useActiveWalletChain } from "thirdweb/react";
617
import { type ContextFilters, promptNebula } from "../api/chat";
@@ -15,7 +26,6 @@ import { EmptyStateChatPageContent } from "./EmptyStateChatPageContent";
1526
export function ChatPageContent(props: {
1627
session: SessionInfo | undefined;
1728
authToken: string;
18-
accountAddress: string;
1929
type: "landing" | "new-chat";
2030
account: Account;
2131
initialPrompt: string | undefined;
@@ -95,12 +105,7 @@ export function ChatPageContent(props: {
95105
// update the context filters to the current user's wallet address and chain id
96106
// eslint-disable-next-line no-restricted-syntax
97107
useEffect(() => {
98-
if (
99-
!isNewSession ||
100-
hasUserUpdatedContextFilters ||
101-
!address ||
102-
!activeChain
103-
) {
108+
if (!isNewSession || hasUserUpdatedContextFilters) {
104109
return;
105110
}
106111

@@ -109,19 +114,23 @@ export function ChatPageContent(props: {
109114
? { ..._contextFilters }
110115
: {};
111116

112-
updatedContextFilters.walletAddresses = [address];
113-
updatedContextFilters.chainIds = [activeChain.id.toString()];
117+
updatedContextFilters.walletAddresses = address ? [address] : [];
118+
updatedContextFilters.chainIds = activeChain
119+
? [activeChain.id.toString()]
120+
: [];
114121

115122
return updatedContextFilters;
116123
});
117124
}, [address, isNewSession, hasUserUpdatedContextFilters, activeChain]);
118125

119-
const config: ExecuteConfig = useMemo(() => {
120-
return {
121-
mode: "client",
122-
signer_wallet_address: props.accountAddress,
123-
};
124-
}, [props.accountAddress]);
126+
const config: ExecuteConfig | null = useMemo(() => {
127+
return address
128+
? {
129+
mode: "client",
130+
signer_wallet_address: address,
131+
}
132+
: null;
133+
}, [address]);
125134

126135
const [sessionId, _setSessionId] = useState<string | undefined>(
127136
props.session?.id,
@@ -150,6 +159,7 @@ export function ChatPageContent(props: {
150159

151160
const [isChatStreaming, setIsChatStreaming] = useState(false);
152161
const [enableAutoScroll, setEnableAutoScroll] = useState(false);
162+
const [showConnectModal, setShowConnectModal] = useState(false);
153163

154164
const initSession = useCallback(async () => {
155165
const session = await createSession({
@@ -163,6 +173,10 @@ export function ChatPageContent(props: {
163173

164174
const handleSendMessage = useCallback(
165175
async (message: string) => {
176+
if (!address) {
177+
setShowConnectModal(true);
178+
return;
179+
}
166180
setUserHasSubmittedMessage(true);
167181
setMessages((prev) => [
168182
...prev,
@@ -329,6 +343,7 @@ export function ChatPageContent(props: {
329343
props.authToken,
330344
messages.length,
331345
initSession,
346+
address,
332347
],
333348
);
334349

@@ -350,6 +365,10 @@ export function ChatPageContent(props: {
350365

351366
return (
352367
<div className="flex grow flex-col overflow-hidden">
368+
<WalletDisconnectedDialog
369+
open={showConnectModal}
370+
onOpenChange={setShowConnectModal}
371+
/>
353372
<header className="flex justify-start border-b bg-background p-4">
354373
<ContextFiltersButton
355374
contextFilters={contextFilters}
@@ -411,3 +430,35 @@ export function ChatPageContent(props: {
411430
</div>
412431
);
413432
}
433+
434+
function WalletDisconnectedDialog(props: {
435+
open: boolean;
436+
onOpenChange: (value: boolean) => void;
437+
}) {
438+
return (
439+
<Dialog open={props.open} onOpenChange={props.onOpenChange}>
440+
<DialogContent className="p-0">
441+
<div className="p-6">
442+
<DialogHeader>
443+
<DialogTitle> Wallet Disconnected </DialogTitle>
444+
<DialogDescription>
445+
Connect your wallet to continue
446+
</DialogDescription>
447+
</DialogHeader>
448+
</div>
449+
450+
<div className="flex justify-end gap-3 border-t bg-muted/50 p-6">
451+
<DialogClose asChild>
452+
<Button variant="outline">Cancel</Button>
453+
</DialogClose>
454+
<Button asChild>
455+
<Link href="/login" className="gap-2">
456+
Connect Wallet
457+
<ArrowRightIcon className="size-4" />
458+
</Link>
459+
</Button>
460+
</div>
461+
</DialogContent>
462+
</Dialog>
463+
);
464+
}

apps/dashboard/src/app/nebula-app/(app)/page.tsx

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import { getValidAccount } from "../../account/settings/getAccount";
2-
import {
3-
getAuthToken,
4-
getAuthTokenWalletAddress,
5-
} from "../../api/lib/getAuthToken";
2+
import { getAuthToken } from "../../api/lib/getAuthToken";
63
import { loginRedirect } from "../../login/loginRedirect";
74
import { ChatPageContent } from "./components/ChatPageContent";
85

@@ -20,16 +17,10 @@ export default async function Page(props: {
2017
loginRedirect();
2118
}
2219

23-
const accountAddress = await getAuthTokenWalletAddress();
2420
const account = await getValidAccount();
2521

26-
if (!accountAddress) {
27-
loginRedirect();
28-
}
29-
3022
return (
3123
<ChatPageContent
32-
accountAddress={accountAddress}
3324
authToken={authToken}
3425
session={undefined}
3526
type="landing"

apps/dashboard/src/app/nebula-app/login/NebulaLoginPage.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ export function NebulaLoginPage(props: {
1212
account: Account | undefined;
1313
}) {
1414
const [message, setMessage] = useState<string | undefined>(undefined);
15-
const [showLoginPage, setShowLoginPage] = useState<boolean>(false);
16-
15+
const [showPage, setShowPage] = useState<"connect" | "welcome">(
16+
props.account ? "connect" : "welcome",
17+
);
1718
return (
1819
<div className="relative flex min-h-screen flex-col overflow-hidden bg-background">
20+
{/* nav */}
1921
<header className="border-b">
2022
<div className="container flex items-center justify-between p-4">
2123
<NebulaIcon className="size-8 shrink-0 text-foreground" />
@@ -37,28 +39,30 @@ export function NebulaLoginPage(props: {
3739
Docs
3840
</Link>
3941

40-
{!showLoginPage && (
41-
<Button size="sm" onClick={() => setShowLoginPage(true)}>
42+
{showPage === "welcome" && (
43+
<Button size="sm" onClick={() => setShowPage("connect")}>
4244
Sign in
4345
</Button>
4446
)}
4547
</div>
4648
</div>
4749
</header>
4850

49-
{showLoginPage ? (
51+
{showPage === "connect" && (
5052
<LoginAndOnboardingPageContent
5153
account={props.account}
5254
redirectPath={
5355
message ? `/?prompt=${encodeURIComponent(message)}` : "/"
5456
}
5557
/>
56-
) : (
58+
)}
59+
60+
{showPage === "welcome" && (
5761
<div className="container relative flex max-w-[800px] grow flex-col justify-center overflow-hidden rounded-lg pb-6">
5862
<EmptyStateChatPageContent
5963
sendMessage={(msg) => {
6064
setMessage(msg);
61-
setShowLoginPage(true);
65+
setShowPage("connect");
6266
}}
6367
/>
6468
</div>

0 commit comments

Comments
 (0)