Skip to content

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

siwa chat widget #7128

wants to merge 3 commits into from

Conversation

Yash094
Copy link
Member

@Yash094 Yash094 commented May 22, 2025


PR-Codex overview

This PR focuses on updating the chat support functionality in the SupportPage component by replacing the NebulaChatButton with a new CustomChatButton, which includes additional features like feedback buttons and a custom chat content component.

Detailed summary

  • Replaced NebulaChatButton with CustomChatButton in SupportPage.
  • Removed the predefined supportPromptPrefix.
  • Added authToken prop to CustomChatButton.
  • Introduced CustomChatButton with new functionalities including modal handling and feedback collection.
  • Added FeedbackButtons component for user feedback on assistant messages.
  • Enhanced CustomChatContent to manage chat sessions and user messages.
  • Implemented a logged-out state and empty state handling in chat components.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Introduced a new chat button and modal interface labeled "Ask Siwa AI for support," with improved authentication handling.
    • Added a feedback feature allowing users to rate assistant responses in chat as positive or negative and submit feedback directly.
    • Launched a custom chat experience that supports user authentication, session management, and example prompts, with a dedicated logged-out state prompting sign-in for restricted access.
  • Improvements

    • Updated support chat UI and prompt labeling for a clearer and more personalized experience.

@Yash094 Yash094 requested review from a team as code owners May 22, 2025 18:43
Copy link

changeset-bot bot commented May 22, 2025

⚠️ No Changeset found

Latest commit: c8843ae

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link

vercel bot commented May 22, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
thirdweb-www ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 22, 2025 6:57pm
4 Skipped Deployments
Name Status Preview Comments Updated (UTC)
docs-v2 ⬜️ Skipped (Inspect) May 22, 2025 6:57pm
login ⬜️ Skipped (Inspect) May 22, 2025 6:57pm
thirdweb_playground ⬜️ Skipped (Inspect) May 22, 2025 6:57pm
wallet-ui ⬜️ Skipped (Inspect) May 22, 2025 6:57pm

Copy link
Contributor

graphite-app bot commented May 22, 2025

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

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.

Copy link

coderabbitai bot commented May 22, 2025

Walkthrough

The 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

File(s) Change Summary
apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx Replaced NebulaChatButton with CustomChatButton, updated import paths, changed label to "Ask Siwa AI for support", renamed nebulaParams to customApiParams, cleared supportPromptPrefix, and added authToken prop.
apps/dashboard/src/app/nebula-app/(app)/components/Chats.tsx Added a feedback feature for assistant messages: new FeedbackButtons component allows users to submit positive or negative feedback, sends feedback to an API endpoint, manages loading and thank-you state, and updates UI accordingly. Imports for icons and hooks were updated.
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatButton.tsx Introduced new CustomChatButton React component. Manages modal open/dismiss state, renders chat button and modal, passes authentication token and custom API params, and conditionally renders chat content.
apps/dashboard/src/app/nebula-app/(app)/components/CustomChat/CustomChatContent.tsx Introduced CustomChatContent React component. Handles authentication gating, chat session and message state, streaming assistant responses, analytics tracking, and renders either a logged-out prompt, example prompts, or the chat UI. Includes internal components for logged-out state and empty state with example prompts.

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
Loading

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit 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.
Learn more here.


Note

⚡️ Faster reviews with caching

CodeRabbit 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 Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.
Enjoy the performance boost—your workflow just got faster.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • TEAM-0000: Entity not found: Issue - Could not find referenced Issue.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added the Dashboard Involves changes to the Dashboard. label May 22, 2025
Copy link

codecov bot commented May 22, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 55.61%. Comparing base (526b6b5) to head (c8843ae).

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           
Flag Coverage Δ
packages 55.61% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@coderabbitai coderabbitai bot left a 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 paths

The 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) in tsconfig.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 messages

A 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 early return 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 code

There'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 readability

The 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 strings

The 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 button

The 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

📥 Commits

Reviewing files that changed from the base of the PR and between 526b6b5 and 1e918d0.

📒 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 through customApiParams.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 rendering

This conditional check on isDismissed will never be true since setIsDismissed 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 needed

The 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 the any 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)

Comment on lines 460 to 510
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>
);
}
Copy link

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:

  1. feedback state is set but never read.
  2. Buttons miss an explicit type="button" – default “submit” can have side-effects inside <form>.
  3. e in the catch block is unused.
  4. 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.

Comment on lines 144 to 147
const payload: any = {
message: messageToSend.content.find((x) => x.type === "text")?.text ?? "",
authToken: props.authToken,
conversationId: "25000000005",
Copy link

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.

pageType: "chain" | "contract" | "support";
label: string;
client: ThirdwebClient;
customApiParams: any;
Copy link

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.

Suggested change
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);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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.

@vercel vercel bot temporarily deployed to Preview – wallet-ui May 22, 2025 18:47 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground May 22, 2025 18:47 Inactive
@vercel vercel bot temporarily deployed to Preview – login May 22, 2025 18:47 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 May 22, 2025 18:47 Inactive
Copy link
Contributor

github-actions bot commented May 22, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 56.62 KB (0%) 1.2 s (0%) 262 ms (+78.35% 🔺) 1.4 s
thirdweb (cjs) 309.13 KB (0%) 6.2 s (0%) 1.4 s (-4.76% 🔽) 7.6 s
thirdweb (minimal + tree-shaking) 5.69 KB (0%) 114 ms (0%) 53 ms (+235.97% 🔺) 167 ms
thirdweb/chains (tree-shaking) 531 B (0%) 11 ms (0%) 21 ms (+512.57% 🔺) 31 ms
thirdweb/react (minimal + tree-shaking) 19.5 KB (0%) 390 ms (0%) 82 ms (+127.72% 🔺) 472 ms

@vercel vercel bot temporarily deployed to Preview – docs-v2 May 22, 2025 18:49 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui May 22, 2025 18:50 Inactive
@vercel vercel bot temporarily deployed to Preview – login May 22, 2025 18:50 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground May 22, 2025 18:50 Inactive
Copy link

@coderabbitai coderabbitai bot left a 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 component

There are several minor issues that should be addressed:

  1. The feedback state is set but never read
  2. Buttons miss an explicit type="button" attribute - default "submit" can cause unintended form submissions
  3. The error variable e in the catch block is unused
  4. 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: 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: 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 issue

Hard-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 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;
🧰 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 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 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 dependency

The contextFilters dependency is specified in the useCallback 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 calls

The 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 consistency

The 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 support

The chat modal lacks keyboard navigation support (Escape to close, focus trapping). This would improve accessibility.

Consider adding:

  1. Event listener for Escape key to close modal
  2. Focus trap to keep keyboard focus within the modal
  3. 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1e918d0 and 4994fbe.

📒 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 messages

The new dedicated rendering for assistant messages with integrated feedback buttons creates a cleaner user experience and will help gather useful feedback.

Comment on lines +301 to +346
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>
);
}
Copy link

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.

Suggested change
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.

Copy link

@coderabbitai coderabbitai bot left a 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 the any type for payload object

Using 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: 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 }[];
}) {
🧰 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" comment

The 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 ID

The 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 variable

The 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 block

The 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

📥 Commits

Reviewing files that changed from the base of the PR and between 4994fbe and c8843ae.

📒 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 rendering

The 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 guidance

The 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.

Comment on lines +194 to +202
[
props.authToken,
contextFilters,
sessionId,
props.customApiParams?.messagePrefix,
userHasSubmittedMessage,
trackEvent,
props.pageType,
],
Copy link

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.

Suggested change
[
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.

Comment on lines +226 to +259
)}
<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}
/>
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Dashboard Involves changes to the Dashboard.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant