Skip to content

Commit dca105c

Browse files
fixes
1 parent c8843ae commit dca105c

File tree

13 files changed

+150
-170
lines changed

13 files changed

+150
-170
lines changed

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { supportedERCs } from "./_utils/detectedFeatures/supportedERCs";
2020
import { getContractPageParamsInfo } from "./_utils/getContractFromParams";
2121
import { getContractPageMetadata } from "./_utils/getContractPageMetadata";
2222
import { getContractPageSidebarLinks } from "./_utils/getContractPageSidebarLinks";
23+
import { examplePrompts } from "../../../../../nebula-app/(app)/data/examplePrompts";
2324

2425
export default async function Layout(props: {
2526
params: Promise<{
@@ -94,14 +95,6 @@ Users may be considering integrating the contract into their applications. Discu
9495
9596
The following is the user's message:`;
9697

97-
const examplePrompts: string[] = [
98-
"What does this contract do?",
99-
"What permissions or roles exist in this contract?",
100-
"Which functions are used the most?",
101-
"Has this contract been used recently?",
102-
"Who are the largest holders/users of this?",
103-
];
104-
10598
return (
10699
<ContractPageLayout
107100
chainMetadata={chainMetadata}
@@ -124,10 +117,7 @@ The following is the user's message:`;
124117
chainIds: [chainId],
125118
wallet: accountAddress ?? undefined,
126119
}}
127-
examplePrompts={examplePrompts.map((prompt) => ({
128-
title: prompt,
129-
message: prompt,
130-
}))}
120+
examplePrompts={examplePrompts}
131121
/>
132122
{props.children}
133123
</ContractPageLayout>

apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Button } from "@/components/ui/button";
22
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
3-
import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
43
import { BookOpenIcon, ChevronRightIcon } from "lucide-react";
54
import type { Metadata } from "next";
65
import Image from "next/image";
@@ -10,6 +9,7 @@ import contractsIcon from "../../../../../public/assets/support/contracts.png";
109
import engineIcon from "../../../../../public/assets/support/engine.png";
1110
import miscIcon from "../../../../../public/assets/support/misc.svg";
1211
import connectIcon from "../../../../../public/assets/support/wallets.png";
12+
import { getTeams } from "../../../../@/api/team";
1313
import { CustomChatButton } from "../../../nebula-app/(app)/components/CustomChat/CustomChatButton";
1414
import {
1515
getAuthToken,
@@ -118,24 +118,21 @@ const HELP_PRODUCTS = [
118118
},
119119
] as const;
120120

121+
export const siwaExamplePrompts = [
122+
"I see thirdweb support reference # in my console log please help me",
123+
"What does this contract revert error mean",
124+
"I want to add inapp wallet with sign in with X/twitter auth to my react app",
125+
"Here is my code can you tell me why i'm seeing this error",
126+
];
127+
121128
export default async function SupportPage() {
122129
const [authToken, accountAddress] = await Promise.all([
123130
getAuthToken(),
124131
getAuthTokenWalletAddress(),
125132
]);
126133

127-
const client = getClientThirdwebClient({
128-
jwt: authToken,
129-
teamId: undefined,
130-
});
131-
132-
const supportPromptPrefix = "";
133-
const examplePrompts = [
134-
"ERC20 - Transfer Amount Exceeds Allowance",
135-
"Replacement transaction underpriced / Replacement fee too low",
136-
"Nonce too low: next nonce #, tx nonce #",
137-
"Nonce too high",
138-
];
134+
const teams = await getTeams();
135+
const teamId = teams?.[0]?.id ?? undefined;
139136

140137
return (
141138
<main className="flex flex-col gap-12 pb-12">
@@ -161,18 +158,14 @@ export default async function SupportPage() {
161158
networks="all"
162159
isFloating={false}
163160
pageType="support"
164-
label="Ask Siwa AI for support"
165-
client={client}
166-
customApiParams={{
167-
messagePrefix: supportPromptPrefix,
168-
chainIds: [],
169-
wallet: accountAddress ?? undefined,
170-
}}
161+
label="Ask AI for support"
171162
examplePrompts={examplePrompts.map((prompt) => ({
172163
title: prompt,
173164
message: prompt,
174165
}))}
175166
authToken={authToken || undefined}
167+
teamId={teamId}
168+
clientId={undefined}
176169
/>
177170

178171
<Link

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { TabPathLinks } from "@/components/ui/tabs";
55
import { AnnouncementBanner } from "components/notices/AnnouncementBanner";
66
import { redirect } from "next/navigation";
77
import { getClientThirdwebClient } from "../../../../../@/constants/thirdweb-client.client";
8+
import { CustomChatButton } from "../../../../nebula-app/(app)/components/CustomChat/CustomChatButton";
9+
import { examplePrompts } from "../../../../nebula-app/(app)/data/examplePrompts";
810
import { getValidAccount } from "../../../account/settings/getAccount";
911
import {
1012
getAuthToken,
@@ -91,6 +93,23 @@ export default async function TeamLayout(props: {
9193
</div>
9294

9395
<main className="flex grow flex-col">{props.children}</main>
96+
<div className="fixed right-6 bottom-6 z-50">
97+
<CustomChatButton
98+
isLoggedIn={true}
99+
networks="all"
100+
isFloating={true}
101+
pageType="support"
102+
label="Ask AI Assistant"
103+
customApiParams={{
104+
messagePrefix: `You are helping a user in the team "${team.name}". `,
105+
chainIds: [],
106+
wallet: undefined,
107+
}}
108+
examplePrompts={examplePrompts}
109+
teamId={team.id}
110+
authToken={authToken}
111+
/>
112+
</div>
94113
<AppFooter />
95114
</div>
96115
);

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/layout.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
import { TeamHeaderLoggedIn } from "../../components/TeamHeader/team-header-logged-in.client";
1313
import { ProjectSidebarLayout } from "./components/ProjectSidebarLayout";
1414
import { SaveLastUsedProject } from "./components/SaveLastUsedProject";
15+
import { CustomChatButton } from "../../../../nebula-app/(app)/components/CustomChat/CustomChatButton";
16+
import { siwaExamplePrompts } from "../../../(dashboard)/support/page";
1517

1618
export default async function ProjectLayout(props: {
1719
children: React.ReactNode;
@@ -78,6 +80,19 @@ export default async function ProjectLayout(props: {
7880
{props.children}
7981
</ProjectSidebarLayout>
8082
</div>
83+
<div className="fixed right-6 bottom-6 z-50">
84+
<CustomChatButton
85+
isLoggedIn={true}
86+
networks="all"
87+
isFloating={true}
88+
pageType="support"
89+
label="Ask AI Assistant"
90+
examplePrompts={siwaExamplePrompts}
91+
teamId={team.id}
92+
clientId={project.publishableKey}
93+
authToken={authToken}
94+
/>
95+
</div>
8196
<SaveLastUsedProject projectId={project.id} teamId={team.id} />
8297
</SidebarProvider>
8398
);

apps/dashboard/src/app/(app)/team/[team_slug]/layout.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ArrowRightIcon } from "lucide-react";
55
import Link from "next/link";
66
import { redirect } from "next/navigation";
77
import { Suspense } from "react";
8+
import { getAuthToken } from "../../api/lib/getAuthToken";
89
import { EnsureValidConnectedWalletLoginServer } from "../../components/EnsureValidConnectedWalletLogin/EnsureValidConnectedWalletLoginServer";
910
import { isTeamOnboardingComplete } from "../../login/onboarding/isOnboardingRequired";
1011
import { SaveLastVisitedTeamPage } from "../components/last-visited-page/SaveLastVisitedPage";
@@ -18,12 +19,17 @@ export default async function RootTeamLayout(props: {
1819
params: Promise<{ team_slug: string }>;
1920
}) {
2021
const { team_slug } = await props.params;
22+
const authToken = await getAuthToken();
2123
const team = await getTeamBySlug(team_slug).catch(() => null);
2224

2325
if (!team) {
2426
redirect("/team");
2527
}
2628

29+
if (!authToken) {
30+
redirect("/login");
31+
}
32+
2733
if (!isTeamOnboardingComplete(team)) {
2834
redirect(`/get-started/team/${team.slug}`);
2935
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export function ChatBar(props: {
6868
isConnectingWallet: boolean;
6969
allowImageUpload: boolean;
7070
onLoginClick: undefined | (() => void);
71+
placeholder: string;
7172
}) {
7273
const [message, setMessage] = useState(props.prefillMessage || "");
7374
const selectedChainIds = props.context?.chainIds?.map((x) => Number(x)) || [];
@@ -142,7 +143,7 @@ export function ChatBar(props: {
142143
<div className="p-2">
143144
<div className="max-h-[200px] overflow-y-auto">
144145
<AutoResizeTextarea
145-
placeholder={"Ask Nebula"}
146+
placeholder={props.placeholder}
146147
value={message}
147148
onChange={(e) => setMessage(e.target.value)}
148149
onKeyDown={(e) => {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ export function ChatPageContent(props: {
353353

354354
<div className="container max-w-[800px]">
355355
<ChatBar
356+
placeholder="Ask Nebula"
356357
isConnectingWallet={connectionStatus === "connecting"}
357358
showContextSelector={true}
358359
connectedWallets={connectedWalletsMeta}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ function Variant(props: {
166166
return (
167167
<BadgeContainer label={props.label}>
168168
<ChatBar
169+
placeholder={"Ask Nebula"}
169170
isConnectingWallet={props.isConnectingWallet || false}
170171
client={storybookThirdwebClient}
171172
abortChatStream={() => {}}

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

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { MarkdownRenderer } from "components/contract-components/published-contr
44
import { AlertCircleIcon, ThumbsDownIcon, ThumbsUpIcon } from "lucide-react";
55
import { useEffect, useRef, useState } from "react";
66
import type { ThirdwebClient } from "thirdweb";
7+
import { Button } from "../../../../@/components/ui/button";
78
import type { NebulaSwapData } from "../api/chat";
89
import type { NebulaUserMessage, NebulaUserMessageContent } from "../api/types";
910
import { NebulaIcon } from "../icons/NebulaIcon";
@@ -72,6 +73,7 @@ export function Chats(props: {
7273
enableAutoScroll: boolean;
7374
useSmallText?: boolean;
7475
sendMessage: (message: NebulaUserMessage) => void;
76+
teamId: string | undefined;
7577
}) {
7678
const { messages, setEnableAutoScroll, enableAutoScroll } = props;
7779
const scrollAnchorRef = useRef<HTMLDivElement>(null);
@@ -153,6 +155,7 @@ export function Chats(props: {
153155
nextMessage={props.messages[index + 1]}
154156
authToken={props.authToken}
155157
sessionId={props.sessionId}
158+
teamId={props.teamId}
156159
/>
157160
</div>
158161
);
@@ -172,6 +175,7 @@ function RenderMessage(props: {
172175
sendMessage: (message: NebulaUserMessage) => void;
173176
nextMessage: ChatMessage | undefined;
174177
authToken: string;
178+
teamId: string | undefined;
175179
sessionId: string | undefined;
176180
}) {
177181
const { message } = props;
@@ -251,6 +255,8 @@ function RenderMessage(props: {
251255
<FeedbackButtons
252256
sessionId={props.sessionId}
253257
messageText={message.type === "assistant" ? message.text : ""}
258+
authToken={props.authToken}
259+
teamId={props.teamId}
254260
/>
255261
</div>
256262
</div>
@@ -460,17 +466,29 @@ function StyledMarkdownRenderer(props: {
460466
function FeedbackButtons({
461467
sessionId,
462468
messageText,
463-
}: { sessionId: string | undefined; messageText: string }) {
464-
const [feedback, setFeedback] = useState<"good" | "bad" | null>(null);
469+
authToken,
470+
teamId,
471+
}: {
472+
sessionId: string | undefined;
473+
messageText: string;
474+
authToken: string;
475+
teamId: string | undefined;
476+
}) {
477+
const [, setFeedback] = useState<"good" | "bad" | null>(null);
465478
const [loading, setLoading] = useState(false);
466479
const [thankYou, setThankYou] = useState(false);
467480

468481
async function sendFeedback(rating: "good" | "bad") {
469482
setLoading(true);
470483
try {
471-
await fetch("https://siwa-api.thirdweb-dev.com/v1/feedback", {
484+
const apiUrl = process.env.NEXT_PUBLIC_SIWA_URL;
485+
await fetch(`${apiUrl}/v1/chat/feedback`, {
472486
method: "POST",
473-
headers: { "Content-Type": "application/json" },
487+
headers: {
488+
"Content-Type": "application/json",
489+
Authorization: `Bearer ${authToken}`,
490+
...(teamId ? { "x-team-id": teamId } : {}),
491+
},
474492
body: JSON.stringify({
475493
conversationId: sessionId,
476494
message: messageText,
@@ -479,39 +497,41 @@ function FeedbackButtons({
479497
});
480498
setFeedback(rating);
481499
setThankYou(true);
482-
} catch (e) {
483-
// handle error
500+
} catch {
501+
// TODO handle error
484502
} finally {
485503
setLoading(false);
486504
}
487505
}
488506

489507
if (thankYou) {
490508
return (
491-
<div className="mt-2 text-xs text-muted-foreground">
509+
<div className="mt-2 text-muted-foreground text-xs">
492510
Thank you for your feedback!
493511
</div>
494512
);
495513
}
496514

497515
return (
498-
<div className="flex gap-2 mt-2">
499-
<button
500-
className="p-1 rounded-full border hover:bg-muted-foreground/10"
501-
onClick={() => sendFeedback("good")}
502-
disabled={loading}
503-
aria-label="Thumbs up"
504-
>
505-
<ThumbsUpIcon className="size-4 text-green-500" />
506-
</button>
507-
<button
508-
className="p-1 rounded-full border hover:bg-muted-foreground/10"
516+
<div className="mt-2 flex gap-2">
517+
<Button
518+
className="rounded-full border p-2 hover:bg-muted-foreground/10"
519+
variant="ghost"
509520
onClick={() => sendFeedback("bad")}
510521
disabled={loading}
511522
aria-label="Thumbs down"
512523
>
513524
<ThumbsDownIcon className="size-4 text-red-500" />
514-
</button>
525+
</Button>
526+
<Button
527+
className="rounded-full border p-2 hover:bg-muted-foreground/10"
528+
variant="ghost"
529+
onClick={() => sendFeedback("good")}
530+
disabled={loading}
531+
aria-label="Thumbs up"
532+
>
533+
<ThumbsUpIcon className="size-4 text-green-500" />
534+
</Button>
515535
</div>
516536
);
517537
}

0 commit comments

Comments
 (0)