-
Notifications
You must be signed in to change notification settings - Fork 537
siwa chat widget #7128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
siwa chat widget #7128
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. |
WalkthroughThe changes introduce a new custom chat button and chat content components, replacing the previous Nebula chat button in the support page. The support chat now uses a different label, passes authentication tokens, and updates API parameter handling. Additionally, a feedback feature for assistant messages is added to the chat component, allowing users to rate responses. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant SupportPage
participant CustomChatButton
participant CustomChatContent
participant API
participant Auth
User->>SupportPage: Visits support page
SupportPage->>CustomChatButton: Renders chat button (with authToken)
User->>CustomChatButton: Clicks chat button
CustomChatButton->>CustomChatContent: Opens chat modal
CustomChatContent->>Auth: Checks if user is authenticated
alt Not Authenticated
CustomChatContent->>User: Shows sign-in prompt
else Authenticated
CustomChatContent->>User: Shows chat UI
User->>CustomChatContent: Submits message
CustomChatContent->>API: Sends message with authToken and session info
API-->>CustomChatContent: Streams assistant response
CustomChatContent->>User: Displays assistant response
User->>CustomChatContent: Provides feedback (good/bad)
CustomChatContent->>API: Sends feedback with sessionId, message, rating
API-->>CustomChatContent: Acknowledges feedback
CustomChatContent->>User: Shows thank-you message
end
Note ⚡️ AI Code Reviews for VS Code, Cursor, WindsurfCodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback. Note ⚡️ Faster reviews with cachingCodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 30th. To opt out, configure Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #7128 +/- ##
=======================================
Coverage 55.61% 55.61%
=======================================
Files 902 902
Lines 58177 58177
Branches 4085 4085
=======================================
Hits 32356 32356
Misses 25716 25716
Partials 105 105
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (10)
apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx (2)
13-13
: Prefer path-aliases over deeply-nested relative pathsThe relative import travels 6 directory levels upward/downward.
That becomes fragile the moment one of the segment folders is renamed or moved and is also hard to read.-import { CustomChatButton } from "../../../nebula-app/(app)/components/CustomChat/CustomChatButton"; +import { CustomChatButton } from "@/nebula-app/components/CustomChat/CustomChatButton";Consider adding a
paths
alias (e.g.@/nebula-app
) intsconfig.json
so every file can import this component with a single, stable alias.
This improves maintainability and reduces merge-conflict headaches.
154-156
: Branding inconsistency – “Nebula AI” vs “Siwa AI”The heading still says “Nebula AI”, while the new button and PR description refer to “Siwa AI”.
Keeping both names in the same view is confusing for users and weakens the re-branding attempt.
-Get instant answers with Nebula AI, our onchain support assistant. +Get instant answers with Siwa AI, our on-chain support assistant.apps/dashboard/src/app/nebula-app/(app)/components/Chats.tsx (1)
227-260
: Duplicate rendering path for assistant messagesA dedicated branch for
message.type === "assistant"
is added here, but the generic branch starting at line 262 still includes assistant-specific handling (icon, feedback, etc.).
While the earlyreturn
prevents double-rendering, the duplicate code increases maintenance cost and risks the two branches drifting apart.Consider extracting shared pieces into a helper component or keeping a single rendering path with feature flags.
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx (3)
4-5
: Unused import
ArrowUpRightIcon
is imported but never used – remove to keep the bundle lean.-import { ArrowRightIcon, ArrowUpRightIcon } from "lucide-react"; +import { ArrowRightIcon } from "lucide-react";🧰 Tools
🪛 Biome (1.9.4)
[error] 4-4: This import is unused.
Unused imports might be the result of an incomplete refactoring.
Safe fix: Remove the unused import.(lint/correctness/noUnusedImports)
92-98
:useCallback
dependency list contains an unused item
contextFilters
never appears inside the callback body but is listed as a dependency, causing unnecessary re-creations.- [ - props.authToken, - contextFilters, + [ + props.authToken,Double-check if you really need
contextFilters
here; otherwise remove it to satisfy the linter and save renders.🧰 Tools
🪛 Biome (1.9.4)
[error] 92-92: This hook specifies more dependencies than necessary: contextFilters
This dependency can be removed from the list.
(lint/correctness/useExhaustiveDependencies)
176-180
: Unused caught error
error
is caught but not referenced – prefix with_
or log it for debugging.-} catch (error) { +} catch (_error) {🧰 Tools
🪛 Biome (1.9.4)
[error] 177-177: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend error with an underscore.(lint/correctness/noUnusedVariables)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatButton.tsx (4)
29-31
: Remove or implement commented-out codeThere's a commented section about adding an outside click handler. Either implement this functionality or remove the comment to keep the code clean.
If you decide to implement it, you could add:
useEffect(() => { function handleClickOutside(event: MouseEvent) { if (ref.current && !ref.current.contains(event.target as Node)) { closeModal(); } } document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, [closeModal]);
62-62
: Sort CSS classes for better readabilityThe CSS classes in this line should be sorted for consistency and better maintainability.
- <div className="font-semibold text-lg flex items-center gap-2"> + <div className="flex items-center gap-2 text-lg font-semibold">🧰 Tools
🪛 Biome (1.9.4)
[error] 62-62: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
54-57
: Consider extracting complex className stringsThe className string is quite complex and might be difficult to maintain. Consider extracting it to a separate variable or using a more structured approach.
+ const modalClasses = "slide-in-from-bottom-20 zoom-in-95 fade-in-0 fixed bottom-0 left-0 z-50 flex h-[80vh] w-[100vw] animate-in flex-col overflow-hidden rounded-t-2xl border bg-background shadow-2xl duration-200 lg:right-6 lg:bottom-6 lg:left-auto lg:h-[80vh] lg:max-w-xl lg:rounded-xl"; <div className={cn( - "slide-in-from-bottom-20 zoom-in-95 fade-in-0 fixed bottom-0 left-0 z-50 flex h-[80vh] w-[100vw] animate-in flex-col overflow-hidden rounded-t-2xl border bg-background shadow-2xl duration-200 lg:right-6 lg:bottom-6 lg:left-auto lg:h-[80vh] lg:max-w-xl lg:rounded-xl", + modalClasses, !isOpen && "hidden" )}
40-50
: Consider accessibility improvements for the chat buttonThe button would benefit from additional accessibility attributes to improve user experience for screen reader users.
<Button onClick={() => { setIsOpen(true); setHasBeenOpened(true); }} variant="default" className="gap-2 rounded-full shadow-lg" + aria-label="Open chat" + aria-expanded={isOpen} > <MessageCircleIcon className="size-4" /> {props.label} </Button>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx
(4 hunks)apps/dashboard/src/app/nebula-app/(app)/components/Chats.tsx
(3 hunks)apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatButton.tsx
(1 hunks)apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx (1)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatButton.tsx (1)
CustomChatButton
(11-93)
apps/dashboard/src/app/nebula-app/(app)/components/Chats.tsx (1)
apps/dashboard/src/app/nebula-app/(app)/icons/NebulaIcon.tsx (1)
NebulaIcon
(1-24)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatButton.tsx (3)
apps/dashboard/src/app/nebula-app/(app)/data/examplePrompts.ts (1)
ExamplePrompt
(1-5)apps/dashboard/src/@/components/ui/button.tsx (1)
Button
(67-67)apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx (1)
CustomChatContent
(22-51)
🪛 Biome (1.9.4)
apps/dashboard/src/app/nebula-app/(app)/components/Chats.tsx
[error] 487-487: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 491-491: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 493-493: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 501-501: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 461-461: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend feedback with an underscore.
(lint/correctness/noUnusedVariables)
[error] 479-479: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend e with an underscore.
(lint/correctness/noUnusedVariables)
[error] 492-497: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form
element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
[error] 500-505: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form
element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx
[error] 144-144: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 301-301: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 4-4: This import is unused.
Unused imports might be the result of an incomplete refactoring.
Safe fix: Remove the unused import.
(lint/correctness/noUnusedImports)
[error] 92-92: This hook specifies more dependencies than necessary: contextFilters
This dependency can be removed from the list.
(lint/correctness/useExhaustiveDependencies)
[error] 177-177: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend error with an underscore.
(lint/correctness/noUnusedVariables)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatButton.tsx
[error] 18-18: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 62-62: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 25-25: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend setIsDismissed with an underscore.
(lint/correctness/noUnusedVariables)
🪛 Gitleaks (8.26.0)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx
158-158: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Unit Tests
- GitHub Check: Size
- GitHub Check: Analyze (javascript)
🔇 Additional comments (3)
apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx (1)
159-176
: Optional: remove unused prop when value is always empty
supportPromptPrefix
is now an empty string and passed throughcustomApiParams.messagePrefix
.
If the prefix is deliberately disabled everywhere, consider dropping the prop altogether to avoid sending redundant data over the wire.No action required if you expect this to be repopulated soon.
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatButton.tsx (2)
33-35
: Potentially unreachable conditional renderingThis conditional check on
isDismissed
will never be true sincesetIsDismissed
is never called, making this code block effectively unreachable.Verify if this dismiss functionality is intentional. If so, implement a way to set the
isDismissed
state to true.
11-93
: Overall implementation looks good with minor improvements neededThe component implements a chat button and popup modal with good separation of concerns. The props are passed correctly to the
CustomChatContent
component, and the UI states are managed appropriately. Fix the issues with theany
type, unused state variable, and consider the accessibility improvements suggested.🧰 Tools
🪛 Biome (1.9.4)
[error] 18-18: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 62-62: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 25-25: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend setIsDismissed with an underscore.(lint/correctness/noUnusedVariables)
function FeedbackButtons({ sessionId, messageText }: { sessionId: string | undefined; messageText: string }) { | ||
const [feedback, setFeedback] = useState<"good" | "bad" | null>(null); | ||
const [loading, setLoading] = useState(false); | ||
const [thankYou, setThankYou] = useState(false); | ||
|
||
async function sendFeedback(rating: "good" | "bad") { | ||
setLoading(true); | ||
try { | ||
await fetch("https://siwa-api.thirdweb-dev.com/v1/feedback", { | ||
method: "POST", | ||
headers: { "Content-Type": "application/json" }, | ||
body: JSON.stringify({ | ||
conversationId: sessionId, | ||
message: messageText, | ||
rating, | ||
}), | ||
}); | ||
setFeedback(rating); | ||
setThankYou(true); | ||
} catch (e) { | ||
// handle error | ||
} finally { | ||
setLoading(false); | ||
} | ||
} | ||
|
||
if (thankYou) { | ||
return <div className="mt-2 text-xs text-muted-foreground">Thank you for your feedback!</div>; | ||
} | ||
|
||
return ( | ||
<div className="flex gap-2 mt-2"> | ||
<button | ||
className="p-1 rounded-full border hover:bg-muted-foreground/10" | ||
onClick={() => sendFeedback("good")} | ||
disabled={loading} | ||
aria-label="Thumbs up" | ||
> | ||
<ThumbsUpIcon className="size-4 text-green-500" /> | ||
</button> | ||
<button | ||
className="p-1 rounded-full border hover:bg-muted-foreground/10" | ||
onClick={() => sendFeedback("bad")} | ||
disabled={loading} | ||
aria-label="Thumbs down" | ||
> | ||
<ThumbsDownIcon className="size-4 text-red-500" /> | ||
</button> | ||
</div> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Minor clean-ups in FeedbackButtons
Static analysis correctly flags a few small issues:
feedback
state is set but never read.- Buttons miss an explicit
type="button"
– default “submit” can have side-effects inside<form>
. e
in thecatch
block is unused.- Class lists are unsorted (style-lint).
-const [feedback, setFeedback] = useState<"good" | "bad" | null>(null);
+// local state removed – not used anywhere
+
...
} catch (_err) {
// TODO: surface a toast or log
} finally {
@@
- <button
+ <button
className="rounded-full border p-1 hover:bg-muted-foreground/10"
+ type="button"
onClick={() => sendFeedback("good")}
@@
- <button
+ <button
className="rounded-full border p-1 hover:bg-muted-foreground/10"
+ type="button"
onClick={() => sendFeedback("bad")}
These tweaks silence linters and avoid unintended form submissions.
Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 Biome (1.9.4)
[error] 487-487: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 491-491: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 493-493: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 501-501: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 461-461: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend feedback with an underscore.
(lint/correctness/noUnusedVariables)
[error] 479-479: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend e with an underscore.
(lint/correctness/noUnusedVariables)
[error] 492-497: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form
element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
[error] 500-505: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form
element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
🤖 Prompt for AI Agents
In apps/dashboard/src/app/nebula-app/(app)/components/Chats.tsx around lines 460
to 510, address minor clean-ups in the FeedbackButtons component by removing the
unused feedback state variable since it is set but never read, adding explicit
type="button" attributes to both buttons to prevent unintended form submissions,
removing the unused error variable 'e' from the catch block, and sorting the
className lists alphabetically to comply with style-lint rules.
const payload: any = { | ||
message: messageToSend.content.find((x) => x.type === "text")?.text ?? "", | ||
authToken: props.authToken, | ||
conversationId: "25000000005", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid any
– give payload
a type
Using any
drops all type-safety right before a network request.
Introduce an interface:
interface SiwaPayload {
message: string;
authToken: string;
conversationId: string;
}
...
const payload: SiwaPayload = {
message: ...,
authToken: props.authToken,
conversationId: sessionId ?? "25000000005",
};
This prevents accidental property omissions/typos.
🧰 Tools
🪛 Biome (1.9.4)
[error] 144-144: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx
around lines 144 to 147, the payload object is currently typed as any, which
removes type safety. Define a TypeScript interface named SiwaPayload with
properties message, authToken, and conversationId all as strings. Then, declare
the payload variable with this SiwaPayload type and assign the corresponding
values, replacing any usage of any. This ensures type safety and prevents
property errors.
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx
Outdated
Show resolved
Hide resolved
pageType: "chain" | "contract" | "support"; | ||
label: string; | ||
client: ThirdwebClient; | ||
customApiParams: any; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid using the any
type in TypeScript
The customApiParams
prop is typed as any
, which bypasses TypeScript's type checking and can lead to runtime errors. Based on how this prop is used in CustomChatContent
, you should use a more specific type.
- customApiParams: any;
+ customApiParams: {
+ messagePrefix: string;
+ chainIds: number[];
+ wallet: string | undefined;
+ } | undefined;
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
customApiParams: any; | |
customApiParams: { | |
messagePrefix: string; | |
chainIds: number[]; | |
wallet: string | undefined; | |
} | undefined; |
🧰 Tools
🪛 Biome (1.9.4)
[error] 18-18: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatButton.tsx
at line 18, the prop customApiParams is currently typed as any, which disables
type checking. Review how customApiParams is used in CustomChatContent and
replace the any type with a more specific interface or type that accurately
reflects its structure and expected properties to improve type safety.
}) { | ||
const [isOpen, setIsOpen] = useState(false); | ||
const [hasBeenOpened, setHasBeenOpened] = useState(false); | ||
const [isDismissed, setIsDismissed] = useState(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused state variable setIsDismissed
The setIsDismissed
state setter is defined but never used in the component, while the isDismissed
state is checked for conditional rendering. This suggests incomplete implementation.
Either implement the dismiss functionality or remove the unused state if it's not needed:
- const [isDismissed, setIsDismissed] = useState(false);
If the dismiss functionality is planned for future implementation, consider adding a TODO comment or implementing it now.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const [isDismissed, setIsDismissed] = useState(false); |
🧰 Tools
🪛 Biome (1.9.4)
[error] 25-25: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend setIsDismissed with an underscore.
(lint/correctness/noUnusedVariables)
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatButton.tsx
at line 25, the state setter setIsDismissed is declared but never used,
indicating incomplete dismiss functionality. To fix this, either implement the
dismiss logic by adding an event handler that calls setIsDismissed to update the
state when the chat button is dismissed, or if dismissing is not needed, remove
both isDismissed and setIsDismissed state declarations. If the dismiss feature
is planned but not yet implemented, add a TODO comment explaining this for
future reference.
size-limit report 📦
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (5)
apps/dashboard/src/app/nebula-app/(app)/components/Chats.tsx (1)
460-517
: Fix minor issues in FeedbackButtons componentThere are several minor issues that should be addressed:
- The
feedback
state is set but never read- Buttons miss an explicit
type="button"
attribute - default "submit" can cause unintended form submissions- The error variable
e
in the catch block is unused- Class lists are unsorted (style-lint)
Apply this diff to fix the issues:
-const [feedback, setFeedback] = useState<"good" | "bad" | null>(null); +// State to track user feedback +const [loading, setLoading] = useState(false); +const [thankYou, setThankYou] = useState(false); async function sendFeedback(rating: "good" | "bad") { setLoading(true); try { await fetch("https://siwa-api.thirdweb-dev.com/v1/feedback", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ conversationId: sessionId, message: messageText, rating, }), }); - setFeedback(rating); setThankYou(true); - } catch (e) { + } catch (_error) { // handle error } finally { setLoading(false); } } if (thankYou) { return ( - <div className="mt-2 text-xs text-muted-foreground"> + <div className="text-muted-foreground text-xs mt-2"> Thank you for your feedback! </div> ); } return ( - <div className="flex gap-2 mt-2"> + <div className="flex gap-2 mt-2"> <button - className="p-1 rounded-full border hover:bg-muted-foreground/10" + className="border hover:bg-muted-foreground/10 p-1 rounded-full" + type="button" onClick={() => sendFeedback("good")} disabled={loading} aria-label="Thumbs up" > <ThumbsUpIcon className="size-4 text-green-500" /> </button> <button - className="p-1 rounded-full border hover:bg-muted-foreground/10" + className="border hover:bg-muted-foreground/10 p-1 rounded-full" + type="button" onClick={() => sendFeedback("bad")} disabled={loading} aria-label="Thumbs down" > <ThumbsDownIcon className="size-4 text-red-500" /> </button> </div> );🧰 Tools
🪛 Biome (1.9.4)
[error] 491-491: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 498-498: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 500-500: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 508-508: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 464-464: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend feedback with an underscore.(lint/correctness/noUnusedVariables)
[error] 482-482: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend e with an underscore.(lint/correctness/noUnusedVariables)
[error] 499-504: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a
form
element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset(lint/a11y/useButtonType)
[error] 507-512: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a
form
element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset(lint/a11y/useButtonType)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx (2)
144-147
: Avoidany
– givepayload
a typeUsing
any
drops all type-safety right before a network request.Introduce an interface:
+interface SiwaPayload { + message: string; + authToken: string; + conversationId: string; +} -const payload: any = { +const payload: SiwaPayload = { message: messageToSend.content.find((x) => x.type === "text")?.text ?? "", authToken: props.authToken, conversationId: sessionId ?? "25000000005", };🧰 Tools
🪛 Biome (1.9.4)
[error] 144-144: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
158-160
:⚠️ Potential issueHard-coded CORS-sh proxy key leaked to the client
The header
"x-cors-api-key": "temp_3f2b6d4409a86dc7f4b7c45840dbd8e9"exposes what looks like an API key to every site visitor (this file is shipped to the browser).
Anyone can now abuse the proxy quota.Move this key to a server-side environment variable (e.g.
process.env.CORS_PROXY_KEY
) and inject it only in API routes or get rid of the proxy entirely by enabling CORS on the upstream service.🧰 Tools
🪛 Gitleaks (8.26.0)
159-159: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatButton.tsx (2)
18-18
: Avoid using theany
type in TypeScriptThe
customApiParams
prop is typed asany
, which bypasses TypeScript's type checking and can lead to runtime errors. Based on how this prop is used inCustomChatContent
, you should use a more specific type.- customApiParams: any; + customApiParams: { + messagePrefix: string; + chainIds: number[]; + wallet: string | undefined; + } | undefined;🧰 Tools
🪛 Biome (1.9.4)
[error] 18-18: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
23-35
: Unused state variablesetIsDismissed
The
setIsDismissed
state setter is defined but never used in the component, while theisDismissed
state is checked for conditional rendering. This suggests incomplete implementation.Either implement the dismiss functionality or remove the unused state if it's not needed:
- const [isDismissed, setIsDismissed] = useState(false); + // If dismiss functionality is planned but not yet implemented: + // TODO: Implement dismiss functionality + const [isDismissed] = useState(false);If the dismiss functionality is planned for future implementation, consider adding a TODO comment or implementing it now.
🧰 Tools
🪛 Biome (1.9.4)
[error] 25-25: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend setIsDismissed with an underscore.(lint/correctness/noUnusedVariables)
🧹 Nitpick comments (4)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx (2)
92-204
: Improve error handling and remove unnecessary dependencyThe
contextFilters
dependency is specified in theuseCallback
but is not used within the callback function. Also, the error handling could be improved to provide more specific error messages.const handleSendMessage = useCallback( async (userMessage: NebulaUserMessage) => { // function implementation... }, [ props.authToken, - contextFilters, sessionId, props.customApiParams?.messagePrefix, userHasSubmittedMessage, trackEvent, props.pageType, ], );
Also, improve error handling:
} catch (error) { if (abortController.signal.aborted) { return; } + + const errorMessage = error instanceof Error + ? `Error: ${error.message}` + : "Sorry, something went wrong."; + setMessages((prev) => [ ...prev.slice(0, -1), { type: "assistant", request_id: undefined, - text: "Sorry, something went wrong.", + text: errorMessage, }, ]); }🧰 Tools
🪛 Biome (1.9.4)
[error] 144-144: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 92-92: This hook specifies more dependencies than necessary: contextFilters
This dependency can be removed from the list.
(lint/correctness/useExhaustiveDependencies)
[error] 178-178: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend error with an underscore.(lint/correctness/noUnusedVariables)
🪛 Gitleaks (8.26.0)
159-159: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
154-164
: Consider implementing a retry mechanism for API callsThe current implementation doesn't handle temporary network failures or server issues. Adding a retry mechanism would improve reliability.
+async function fetchWithRetry(url: string, options: RequestInit, maxRetries = 3): Promise<Response> { + let retries = 0; + while (retries < maxRetries) { + try { + return await fetch(url, options); + } catch (error) { + retries++; + if (retries >= maxRetries) throw error; + // Exponential backoff + await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, retries - 1))); + } + } + throw new Error("Max retries exceeded"); +} // Replace the fetch call with: -const response = await fetch( +const response = await fetchWithRetry( "https://proxy.cors.sh/https://siwa-slack-bot-u8ne.chainsaw-dev.zeet.app/siwa", { method: "POST", headers: { "Content-Type": "application/json", "x-cors-api-key": "temp_3f2b6d4409a86dc7f4b7c45840dbd8e9", // replace with your cors.sh API key }, body: JSON.stringify(payload), signal: abortController.signal, }, );🧰 Tools
🪛 Gitleaks (8.26.0)
159-159: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatButton.tsx (2)
62-65
: Sort CSS classes for consistencyThe CSS classes in this line should be sorted for consistency with project standards.
-<div className="font-semibold text-lg flex items-center gap-2"> +<div className="flex items-center gap-2 font-semibold text-lg">🧰 Tools
🪛 Biome (1.9.4)
[error] 62-62: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
37-93
: Consider adding keyboard navigation supportThe chat modal lacks keyboard navigation support (Escape to close, focus trapping). This would improve accessibility.
Consider adding:
- Event listener for Escape key to close modal
- Focus trap to keep keyboard focus within the modal
- Return focus to button when modal closes
+import { useEffect } from "react"; +import FocusTrap from "focus-trap-react"; // You may need to install this // Inside the component: +useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape" && isOpen) { + closeModal(); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); +}, [isOpen, closeModal]); // Wrap modal content with FocusTrap +{isOpen && ( + <FocusTrap focusTrapOptions={{ initialFocus: false }}> <div className={cn(...)} ref={ref}> {/* Modal content */} </div> + </FocusTrap> +)}🧰 Tools
🪛 Biome (1.9.4)
[error] 62-62: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx
(4 hunks)apps/dashboard/src/app/nebula-app/(app)/components/Chats.tsx
(3 hunks)apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatButton.tsx
(1 hunks)apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx
🧰 Additional context used
🧬 Code Graph Analysis (2)
apps/dashboard/src/app/nebula-app/(app)/components/Chats.tsx (1)
apps/dashboard/src/app/nebula-app/(app)/icons/NebulaIcon.tsx (1)
NebulaIcon
(1-24)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatButton.tsx (3)
apps/dashboard/src/app/nebula-app/(app)/data/examplePrompts.ts (1)
ExamplePrompt
(1-5)apps/dashboard/src/@/components/ui/button.tsx (1)
Button
(67-67)apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx (1)
CustomChatContent
(22-51)
🪛 Biome (1.9.4)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx
[error] 144-144: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 302-302: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 92-92: This hook specifies more dependencies than necessary: contextFilters
This dependency can be removed from the list.
(lint/correctness/useExhaustiveDependencies)
[error] 178-178: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend error with an underscore.
(lint/correctness/noUnusedVariables)
apps/dashboard/src/app/nebula-app/(app)/components/Chats.tsx
[error] 491-491: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 498-498: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 500-500: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 508-508: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 464-464: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend feedback with an underscore.
(lint/correctness/noUnusedVariables)
[error] 482-482: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend e with an underscore.
(lint/correctness/noUnusedVariables)
[error] 499-504: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form
element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
[error] 507-512: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form
element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatButton.tsx
[error] 18-18: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 62-62: These CSS classes should be sorted.
Unsafe fix: Sort the classes.
(lint/nursery/useSortedClasses)
[error] 25-25: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend setIsDismissed with an underscore.
(lint/correctness/noUnusedVariables)
🪛 Gitleaks (8.26.0)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx
159-159: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🔇 Additional comments (1)
apps/dashboard/src/app/nebula-app/(app)/components/Chats.tsx (1)
227-259
: Positive: Added dedicated feedback UI for assistant messagesThe new dedicated rendering for assistant messages with integrated feedback buttons creates a cleaner user experience and will help gather useful feedback.
function EmptyStateChatPageContent(props: { | ||
sendMessage: (message: any) => void; | ||
examplePrompts: { title: string; message: string }[]; | ||
}) { | ||
return ( | ||
<div className="flex flex-1 flex-col items-center justify-center overflow-auto p-4 "> | ||
<div className="mb-4 flex justify-center"> | ||
<div className="rounded-full border-[1.5px] border-nebula-pink-foreground/20 bg-[hsl(var(--nebula-pink-foreground)/5%)] p-1"> | ||
<div className="rounded-full border-[1.5px] border-nebula-pink-foreground/40 bg-[hsl(var(--nebula-pink-foreground)/5%)] p-2"> | ||
<NebulaIcon className="size-7 text-nebula-pink-foreground" /> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<h1 className="px-4 text-center font-semibold text-3xl tracking-tight md:text-4xl"> | ||
How can I help you <br className="max-sm:hidden" /> | ||
onchain today? | ||
</h1> | ||
|
||
<div className="h-6" /> | ||
<div className="flex max-w-lg flex-col flex-wrap justify-center gap-2.5"> | ||
{props.examplePrompts.map((prompt) => ( | ||
<Button | ||
key={prompt.title} | ||
variant="outline" | ||
size="sm" | ||
onClick={() => | ||
props.sendMessage({ | ||
role: "user", | ||
content: [ | ||
{ | ||
type: "text", | ||
text: prompt.message, | ||
}, | ||
], | ||
}) | ||
} | ||
disabled={false} | ||
> | ||
{prompt.title} | ||
</Button> | ||
))} | ||
</div> | ||
</div> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Fix any
type in EmptyStateChatPageContent props
The sendMessage
prop in EmptyStateChatPageContent is typed as any
, which reduces type safety.
function EmptyStateChatPageContent(props: {
- sendMessage: (message: any) => void;
+ sendMessage: (message: NebulaUserMessage) => void;
examplePrompts: { title: string; message: string }[];
}) {
// ...
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
function EmptyStateChatPageContent(props: { | |
sendMessage: (message: any) => void; | |
examplePrompts: { title: string; message: string }[]; | |
}) { | |
return ( | |
<div className="flex flex-1 flex-col items-center justify-center overflow-auto p-4 "> | |
<div className="mb-4 flex justify-center"> | |
<div className="rounded-full border-[1.5px] border-nebula-pink-foreground/20 bg-[hsl(var(--nebula-pink-foreground)/5%)] p-1"> | |
<div className="rounded-full border-[1.5px] border-nebula-pink-foreground/40 bg-[hsl(var(--nebula-pink-foreground)/5%)] p-2"> | |
<NebulaIcon className="size-7 text-nebula-pink-foreground" /> | |
</div> | |
</div> | |
</div> | |
<h1 className="px-4 text-center font-semibold text-3xl tracking-tight md:text-4xl"> | |
How can I help you <br className="max-sm:hidden" /> | |
onchain today? | |
</h1> | |
<div className="h-6" /> | |
<div className="flex max-w-lg flex-col flex-wrap justify-center gap-2.5"> | |
{props.examplePrompts.map((prompt) => ( | |
<Button | |
key={prompt.title} | |
variant="outline" | |
size="sm" | |
onClick={() => | |
props.sendMessage({ | |
role: "user", | |
content: [ | |
{ | |
type: "text", | |
text: prompt.message, | |
}, | |
], | |
}) | |
} | |
disabled={false} | |
> | |
{prompt.title} | |
</Button> | |
))} | |
</div> | |
</div> | |
); | |
} | |
function EmptyStateChatPageContent(props: { | |
sendMessage: (message: NebulaUserMessage) => void; | |
examplePrompts: { title: string; message: string }[]; | |
}) { | |
return ( | |
<div className="flex flex-1 flex-col items-center justify-center overflow-auto p-4 "> | |
<div className="mb-4 flex justify-center"> | |
<div className="rounded-full border-[1.5px] border-nebula-pink-foreground/20 bg-[hsl(var(--nebula-pink-foreground)/5%)] p-1"> | |
<div className="rounded-full border-[1.5px] border-nebula-pink-foreground/40 bg-[hsl(var(--nebula-pink-foreground)/5%)] p-2"> | |
<NebulaIcon className="size-7 text-nebula-pink-foreground" /> | |
</div> | |
</div> | |
</div> | |
<h1 className="px-4 text-center font-semibold text-3xl tracking-tight md:text-4xl"> | |
How can I help you <br className="max-sm:hidden" /> | |
onchain today? | |
</h1> | |
<div className="h-6" /> | |
<div className="flex max-w-lg flex-col flex-wrap justify-center gap-2.5"> | |
{props.examplePrompts.map((prompt) => ( | |
<Button | |
key={prompt.title} | |
variant="outline" | |
size="sm" | |
onClick={() => | |
props.sendMessage({ | |
role: "user", | |
content: [ | |
{ | |
type: "text", | |
text: prompt.message, | |
}, | |
], | |
}) | |
} | |
disabled={false} | |
> | |
{prompt.title} | |
</Button> | |
))} | |
</div> | |
</div> | |
); | |
} |
🧰 Tools
🪛 Biome (1.9.4)
[error] 302-302: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx
around lines 301 to 346, the sendMessage prop is currently typed as any, which
reduces type safety. Replace the any type with a more specific type that
accurately represents the message object structure expected by sendMessage, such
as defining an interface or type for the message parameter and using it in the
function signature to improve type safety and clarity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (2)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx (2)
144-149
: Fix theany
type for payload objectUsing
any
drops all type safety right before a network request. Define a proper interface for the payload object.-const payload: any = { +interface SiwaPayload { + message: string; + authToken: string; + conversationId: string; +} + +const payload: SiwaPayload = { message: messageToSend.content.find((x) => x.type === "text")?.text ?? "", authToken: props.authToken, conversationId: "25000000005", };🧰 Tools
🪛 Biome (1.9.4)
[error] 144-144: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
300-302
: Fixany
type in EmptyStateChatPageContent propsThe
sendMessage
prop in EmptyStateChatPageContent is typed asany
, which reduces type safety.function EmptyStateChatPageContent(props: { - sendMessage: (message: any) => void; + sendMessage: (message: NebulaUserMessage) => void; examplePrompts: { title: string; message: string }[]; }) {🧰 Tools
🪛 Biome (1.9.4)
[error] 301-301: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
🧹 Nitpick comments (4)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx (4)
14-14
: Remove commented-out import with "REMOVE" commentThe code contains a commented-out import statement with an explicit "REMOVE" comment. It's best to clean up this code to prevent confusion and maintain a clean codebase.
-// import { createSession } from "../../api/session"; // REMOVE
148-148
: Avoid hardcoding the default conversation IDThe conversation ID "25000000005" is hardcoded in the payload. Consider extracting this to a constant or configuration to improve maintainability.
+const DEFAULT_CONVERSATION_ID = "25000000005"; + const payload: any = { message: messageToSend.content.find((x) => x.type === "text")?.text ?? "", authToken: props.authToken, - conversationId: "25000000005", + conversationId: DEFAULT_CONVERSATION_ID, };
153-163
: Consider extracting API URL to a configuration variableThe API endpoint URL is hardcoded in the fetch call. Extract it to a constant or environment variable for better maintainability and flexibility across environments.
+const SIWA_API_ENDPOINT = "https://siwa-api.thirdweb-dev.com/api/chat"; + const response = await fetch( - "https://siwa-api.thirdweb-dev.com/api/chat", + SIWA_API_ENDPOINT, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(payload), signal: abortController.signal, }, );
177-178
: Utilize the error variable in catch blockThe error variable is caught but not used. Consider logging the error or using it to provide more specific error messages to users.
-} catch (error) { +} catch (error) { + console.error("Chat API error:", error); if (abortController.signal.aborted) { return; } setMessages((prev) => [🧰 Tools
🪛 Biome (1.9.4)
[error] 177-177: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend error with an underscore.(lint/correctness/noUnusedVariables)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx
(1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx
[error] 144-144: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 301-301: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 92-92: This hook specifies more dependencies than necessary: contextFilters
This dependency can be removed from the list.
(lint/correctness/useExhaustiveDependencies)
[error] 177-177: This variable is unused.
Unused variables usually are result of incomplete refactoring, typos and other source of bugs.
Unsafe fix: If this is intentional, prepend error with an underscore.
(lint/correctness/noUnusedVariables)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Size
- GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx (2)
206-226
: The code elegantly handles conditional renderingThe component properly handles different states: showing an empty state when no messages have been submitted, and the chat interface otherwise. The props passed to child components are comprehensive and well-structured.
264-298
: Well-designed login state with clear user guidanceThe logged-out state provides a clear call-to-action for users to sign in, with appropriate styling and a useful link that preserves the current path for redirection after login.
[ | ||
props.authToken, | ||
contextFilters, | ||
sessionId, | ||
props.customApiParams?.messagePrefix, | ||
userHasSubmittedMessage, | ||
trackEvent, | ||
props.pageType, | ||
], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove unused dependency from useCallback
The contextFilters
is included in the dependency array but not used in the function body.
[
props.authToken,
- contextFilters,
sessionId,
props.customApiParams?.messagePrefix,
userHasSubmittedMessage,
trackEvent,
props.pageType,
],
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
[ | |
props.authToken, | |
contextFilters, | |
sessionId, | |
props.customApiParams?.messagePrefix, | |
userHasSubmittedMessage, | |
trackEvent, | |
props.pageType, | |
], | |
[ | |
props.authToken, | |
sessionId, | |
props.customApiParams?.messagePrefix, | |
userHasSubmittedMessage, | |
trackEvent, | |
props.pageType, | |
], |
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx
around lines 194 to 202, the useCallback hook includes contextFilters in its
dependency array, but contextFilters is not used inside the callback function.
Remove contextFilters from the dependency array to avoid unnecessary
re-creations of the callback and keep dependencies accurate.
)} | ||
<ChatBar | ||
onLoginClick={undefined} | ||
client={props.client} | ||
isConnectingWallet={connectionStatus === "connecting"} | ||
context={contextFilters} | ||
setContext={setContextFilters} | ||
showContextSelector={false} | ||
connectedWallets={ | ||
props.customApiParams?.wallet && activeWallet | ||
? [ | ||
{ | ||
address: props.customApiParams.wallet, | ||
walletId: activeWallet.id, | ||
}, | ||
] | ||
: [] | ||
} | ||
setActiveWallet={() => {}} | ||
abortChatStream={() => { | ||
chatAbortController?.abort(); | ||
setChatAbortController(undefined); | ||
setIsChatStreaming(false); | ||
// if last message is presence, remove it | ||
if (messages[messages.length - 1]?.type === "presence") { | ||
setMessages((prev) => prev.slice(0, -1)); | ||
} | ||
}} | ||
isChatStreaming={isChatStreaming} | ||
prefillMessage={undefined} | ||
sendMessage={handleSendMessage} | ||
className="rounded-none border-x-0 border-b-0" | ||
allowImageUpload={false} | ||
/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Consider handling error states for wallet connection
The component passes wallet information when available but doesn't handle potential error states for wallet connection. Consider showing appropriate error messages or fallbacks when wallet connection fails.
🏁 Script executed:
#!/bin/bash
# Check for error handling patterns in wallet-related components
# Look for error handling in wallet connection code
rg -A 10 "useActiveWallet|useActiveWalletConnectionStatus" --type ts
Length of output: 67063
I’ll inspect the CustomChatContent component to see how it’s wiring up wallet connection state and whether any error cases are surfaced.
🏁 Script executed:
#!/bin/bash
set -e
FILE="apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx"
echo "=== Top of file (imports + hook setup) ==="
sed -n '1,50p' "$FILE"
echo
echo "=== Looking for wallet hooks ==="
grep -nE "useActiveWallet|useActiveWalletConnectionStatus" -n "$FILE" || true
echo
echo "=== Searching for any 'error' references ==="
grep -n "error" -n "$FILE" || true
Length of output: 2568
Gathering the logged-in chat component and its error handling around wallet connection…
🏁 Script executed:
#!/bin/bash
set -e
FILE="apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx"
echo "=== CustomChatContentLoggedIn definition (lines 50–150) ==="
sed -n '50,150p' "$FILE"
echo
echo "=== Message send & catch block (lines 150–240) ==="
sed -n '150,240p' "$FILE"
Length of output: 6525
Investigating the ChatBar
component’s props and whether it surfaces wallet errors:
🏁 Script executed:
#!/bin/bash
set -e
# Locate the ChatBar component
echo "=== ChatBar file path ==="
rg -l "export function ChatBar" -n apps/dashboard/src/app/nebula-app/(app)/components
# Print its prop definitions and error-related logic
FILE="apps/dashboard/src/app/nebula-app/(app)/components/ChatBar.tsx"
echo
echo "=== ChatBar props and logic (lines 1–200) ==="
sed -n '1,200p' "$FILE"
# Search for any 'error' references in ChatBar
echo
echo "=== ChatBar error handling references ==="
grep -n "error" -n "$FILE" || true
Length of output: 179
Retrieving the ChatBar
implementation to verify error handling:
🏁 Script executed:
#!/bin/bash
set -e
# Locate ChatBar.tsx within the dashboard components
FILE=$(find apps/dashboard/src/app -type f -name ChatBar.tsx | head -n1)
echo "=== ChatBar file path ==="
echo "$FILE"
echo
echo "=== ChatBar props and logic (first 200 lines) ==="
sed -n '1,200p' "$FILE"
echo
echo "=== References to 'error' or similar inside ChatBar ==="
grep -nE "error|fail|warning" -n "$FILE" || true
Length of output: 7549
Add explicit wallet connection error handling
Right now, we only surface the “connecting” state via a spinner, but if the wallet fails to connect (connectionStatus becomes "disconnected"
or "error"
), there’s no UI or fallback. We should:
• In CustomChatContentLoggedIn (around line 226), pass a real onLoginClick
handler (not undefined
), and detect connectionStatus === "error"
to render an error message or retry button.
• In ChatBar (in ChatBar.tsx
), accept and render an error state when isConnectingWallet === false && connectedWallets.length === 0
or via a new hasConnectionError: boolean
prop.
Example diff in CustomChatContentLoggedIn:
- <ChatBar
- onLoginClick={undefined}
+ <ChatBar
+ onLoginClick={() => /* trigger wallet modal or retry */ }
client={props.client}
- isConnectingWallet={connectionStatus === "connecting"}
+ isConnectingWallet={connectionStatus === "connecting"}
+ hasConnectionError={connectionStatus === "error"}
…
/>
And in ChatBar render near the selector:
{props.hasConnectionError && (
<Badge variant="destructive" className="px-2">
Wallet connection failed. <Button onClick={props.onLoginClick}>Retry</Button>
</Badge>
)}
This ensures users see and can recover from wallet connection failures.
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx
around lines 226 to 259, the component currently passes undefined for
onLoginClick and does not handle wallet connection errors. Fix this by
implementing a real onLoginClick handler to trigger wallet login and detect when
connectionStatus is "error" to render an error message or retry UI. Also, update
the ChatBar component to accept a new prop like hasConnectionError and render an
error badge with a retry button when wallet connection fails or no wallets are
connected, ensuring users can see and recover from connection issues.
PR-Codex overview
This PR focuses on updating the chat support functionality in the
SupportPage
component by replacing theNebulaChatButton
with a newCustomChatButton
, which includes additional features like feedback buttons and a custom chat content component.Detailed summary
NebulaChatButton
withCustomChatButton
inSupportPage
.supportPromptPrefix
.authToken
prop toCustomChatButton
.CustomChatButton
with new functionalities including modal handling and feedback collection.FeedbackButtons
component for user feedback on assistant messages.CustomChatContent
to manage chat sessions and user messages.Summary by CodeRabbit
New Features
Improvements