Add Chatbot on IssueHub V0.2#26
Conversation
📝 WalkthroughWalkthroughAdds a persistent floating Chatbot with canned responses, a one-time welcome prompt, an email-capture flow (zod + EmailJS), full UI rendering, and stylesheet; the Chatbot is mounted in the root layout. ChangesChatbot Widget Implementation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed: one or more packages not found in the registry. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces a new Chatbot component to the application, integrated into the root layout. The implementation includes a dedicated CSS file for styling and a React component that handles user interactions, simple command responses, and an email notification flow using EmailJS and Zod validation. Feedback focuses on critical security improvements by moving hardcoded credentials to environment variables, enhancing maintainability by replacing hardcoded colors with CSS variables and removing magic strings, and improving React patterns by scoping ID generation to the component instance. Additionally, an accessibility improvement was suggested to ensure the chat window behaves correctly as a modal dialog.
| await emailjs.send( | ||
| 'service_2fc5v5k', | ||
| 'template_d3d70zp', | ||
| { user_email: email, user: 'IssueHub' }, | ||
| { publicKey: 'De3J97q5iJ8M72LB0' } | ||
| ); |
There was a problem hiding this comment.
Hardcoding credentials like the EmailJS service ID, template ID, and public key directly in the source code is a significant security risk. These values are exposed in the client-side bundle, allowing anyone to potentially misuse them.
These secrets should be moved to environment variables (e.g., a .env.local file) and accessed via process.env. For Next.js, remember to prefix client-side environment variables with NEXT_PUBLIC_.
Note: The suggestion below uses the non-null assertion operator (!). It's crucial to add runtime checks to ensure these environment variables are actually present before calling emailjs.send to avoid runtime errors.
| await emailjs.send( | |
| 'service_2fc5v5k', | |
| 'template_d3d70zp', | |
| { user_email: email, user: 'IssueHub' }, | |
| { publicKey: 'De3J97q5iJ8M72LB0' } | |
| ); | |
| await emailjs.send( | |
| process.env.NEXT_PUBLIC_EMAILJS_SERVICE_ID!, | |
| process.env.NEXT_PUBLIC_EMAILJS_TEMPLATE_ID!, | |
| { user_email: email, user: 'IssueHub' }, | |
| { publicKey: process.env.NEXT_PUBLIC_EMAILJS_PUBLIC_KEY! } | |
| ); |
| background: #18181b; /* --muted: zinc-900 */ | ||
| border: 1px solid #27272a; /* --border: zinc-800 */ |
There was a problem hiding this comment.
This component uses hardcoded hex color codes (e.g., #18181b, #27272a). The project defines a theme with CSS variables in globals.css (like --muted and --border) to ensure visual consistency.
To align with the project's design system and improve maintainability, please replace the hardcoded colors in this file with the corresponding CSS variables.
For example:
#fafafashould bevar(--foreground)#0a0a0bshould bevar(--background)#18181bshould bevar(--muted)#27272ashould bevar(--border)#a1a1aashould bevar(--muted-foreground)
| background: #18181b; /* --muted: zinc-900 */ | |
| border: 1px solid #27272a; /* --border: zinc-800 */ | |
| background: var(--muted); /* --muted: zinc-900 */ | |
| border: 1px solid var(--border); /* --border: zinc-800 */ |
| let msgId = 0; | ||
| const nextId = () => ++msgId; |
There was a problem hiding this comment.
Using a module-level mutable variable (msgId) to generate React keys is not a safe pattern. In React's Strict Mode, components can render twice in development, which would cause this counter to increment unexpectedly and could lead to key-related issues. State for generating IDs should be scoped to the component instance.
Please remove these lines and add the following inside your Chatbot component to manage the ID generation safely:
const msgIdCounter = useRef(0);
const nextId = () => ++msgIdCounter.current;| setTimeout(() => { | ||
| const res = responseObj[text.toLowerCase()]; | ||
|
|
||
| if (typeof res === 'function') { | ||
| const result = res(); | ||
| if (result === '__EMAIL_FLOW__') { | ||
| startEmailFlow(); | ||
| } else if (typeof result === 'string') { | ||
| addMessage(result); | ||
| } | ||
| } else if (typeof res === 'string') { | ||
| addMessage(res); | ||
| } else { | ||
| addMessage("Sorry, I didn't understand that. Try: hello, today, time, ping, rn."); | ||
| } | ||
| }, 500); |
There was a problem hiding this comment.
The current logic for triggering the email flow relies on a magic string __EMAIL_FLOW__ which makes the code less direct and harder to maintain. A clearer approach is to handle the rn command explicitly.
I recommend removing the 'rn' entry from responseObj (on line 18) and modifying this block to handle it directly.
setTimeout(() => {
const command = text.toLowerCase();
if (command === 'rn') {
startEmailFlow();
return;
}
const res = responseObj[command];
if (typeof res === 'function') {
const result = res();
if (typeof result === 'string') {
addMessage(result);
}
} else if (typeof res === 'string') {
addMessage(res);
} else {
addMessage("Sorry, I didn't understand that. Try: hello, today, time, ping.");
}
}, 500);
| className={`chatbot-container${isOpen ? ' open' : ''}`} | ||
| role="dialog" | ||
| aria-label="IssueBot chat" | ||
| aria-modal="false" |
There was a problem hiding this comment.
The chat window is marked with role="dialog" but aria-modal="false". While the chat is open, keyboard focus is not trapped within it, allowing users to tab to interactive elements on the page behind the chat window. This can create a confusing experience, especially for users of assistive technologies.
To improve accessibility, this should behave as a modal dialog. Please change aria-modal to "true" and implement focus trapping to keep the user's focus within the chat component while it is open.
| aria-modal="false" | |
| aria-modal="true" |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (7)
src/components/Chatbot/Chatbot.tsx (5)
58-58: 💤 Low valueMagic number timeouts lack documentation.
The delays of 260ms (line 58), 50ms (line 77), and 500ms (line 139) have no comments explaining their purpose (e.g., animation timing, perceived responsiveness). This harms maintainability.
Consider extracting these as named constants at the top of the file:
const FOCUS_DELAY_MS = 260; // Wait for open animation const EMAIL_FOCUS_DELAY_MS = 50; const BOT_RESPONSE_DELAY_MS = 500; // Simulate typing delayAlso applies to: 77-77, 139-139
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/Chatbot/Chatbot.tsx` at line 58, Replace the three magic-number timeouts used in setTimeout calls (e.g., the call that invokes inputRef.current?.focus(), the timeout used around EMAIL focus, and the BOT response delay) with descriptive named constants defined at the top of the Chatbot component file (for example FOCUS_DELAY_MS, EMAIL_FOCUS_DELAY_MS, BOT_RESPONSE_DELAY_MS) and add brief comments explaining each constant's purpose (e.g., "wait for open animation", "small email input focus latency", "simulate bot typing delay"); then update the setTimeout invocations to use these constants so the intent is documented and maintainable.
82-84: ⚡ Quick winInvalid email error does not clear the input field.
When validation fails, the bot shows "Invalid email. Please try again." but leaves the malformed email in the input. Users must manually select and delete it, which is a minor UX friction.
✨ Proposed fix: clear input on validation failure
const result = emailSchema.safeParse(email); if (!result.success) { + setInputValue(''); addMessage('Invalid email. Please try again.'); return; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/Chatbot/Chatbot.tsx` around lines 82 - 84, The email validation branch currently shows an error message but leaves the malformed value in the input; in the handler that checks result.success (likely the email submit handler in Chatbot component, e.g., handleEmailSubmit or the function where result and addMessage are used) after calling addMessage('Invalid email. Please try again.') also clear the input state (call the component's input state setter such as setInput('') or reset the controlled input value) and ensure any related validation state is reset so the UI empties the field on validation failure.
80-109: ⚖️ Poor tradeoffEmail submission lacks rate limiting or abuse prevention.
A user can repeatedly click the send button or use the
rncommand to trigger unlimited email submissions without throttling, potentially exhausting your EmailJS quota.Consider adding client-side rate limiting (e.g., disable submission for 60 seconds after success) or a simple cooldown state. For a v0.2 prototype this may be deferred, but plan to add server-side validation and rate limiting before broader release.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/Chatbot/Chatbot.tsx` around lines 80 - 109, The submitEmail flow can be abused by repeated submissions; add a client-side cooldown state (e.g., emailCooldown boolean or emailCooldownUntil timestamp) checked at the start of submitEmail to short-circuit and show a message if still cooling down, set that state when a send succeeds (or on attempt) and use setTimeout or calculating remaining time to clear it after ~60s, and ensure the UI/send button is disabled using that state; update places that toggle email mode (setIsEmailMode, setPlaceholder) to respect the cooldown and keep addMessage/removeLastMessage behavior consistent while preventing multiple concurrent sends by guarding submitEmail against re-entry.
10-10: ⚡ Quick win
ResponseValuetype includes() => void, but void return is not explicitly handled.Line 10 declares
type ResponseValue = string | (() => string) | (() => void);, yet lines 127–133 only check for'__EMAIL_FLOW__'ortypeof result === 'string'. If a function returnsundefined(matching() => void), it silently falls through to theelsebranch at line 136, triggering the "didn't understand" fallback. Either remove() => voidfrom the type or add explicit handling.♻️ Proposed fix: remove unused `() => void` alternative
-type ResponseValue = string | (() => string) | (() => void); +type ResponseValue = string | (() => string);If you intend to support side-effect-only responses in the future, add a comment or explicit branch.
Also applies to: 127-138
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/Chatbot/Chatbot.tsx` at line 10, The ResponseValue union currently includes an unused (() => void) variant which allows handler functions to return undefined and then fall through to the "didn't understand" fallback; remove (() => void) from the ResponseValue type declaration so ResponseValue is only string | (() => string), and confirm any call-sites that invoke response functions (the logic that checks for '__EMAIL_FLOW__' and uses typeof result === 'string') still match the new type; if you intend to support side-effect-only handlers later, instead keep the union but add an explicit branch that treats undefined results as a valid no-op response (with a clear comment) so the fallback is not triggered inadvertently.
152-154: 💤 Low valueVerify dialog semantics:
role="dialog"witharia-modal="false"is uncommon.Typically,
role="dialog"implies a modal that requires user interaction before returning to the main content. Since this chatbot is non-blocking and the page remains interactive, consider whetherrole="complementary"orrole="region"witharia-labelis more semantically accurate, or confirm thataria-modal="false"is intentional for a non-modal dialog pattern.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/Chatbot/Chatbot.tsx` around lines 152 - 154, The element in Chatbot (component Chatbot, attributes role="dialog" and aria-modal="false") uses dialog semantics but is non-modal; update the role to a more accurate landmark (e.g., role="complementary" or role="region") and remove aria-modal, or explicitly document/justify keeping role="dialog" and set aria-modal="true" if it truly should be modal. Locate the JSX in Chatbot where role="dialog" and aria-modal="false" are set and replace the role and remove aria-modal (or set aria-modal to true) so semantics match the interactive behavior.src/app/layout.tsx (1)
35-35: 💤 Low valueConsider future provider access when extending Chatbot.
The
<Chatbot />is rendered outside theMuiProviderandQueryProviderwrappers (line 35). For the current v0.2 implementation this is fine, but if you later add React Query hooks for backend integration or MUI components, you'll need to move it inside the providers or duplicate provider setup.For now, this placement works. Just be aware of the scoping when planning backend integration or UI library usage in future versions.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/layout.tsx` at line 35, Chatbot is rendered outside the providers which will block future use of React Query or MUI inside it; move the <Chatbot /> element so it is nested inside the existing MuiProvider and QueryProvider (or duplicate the providers around Chatbot) so that any future additions using useQuery/useMutation or MUI components in the Chatbot component have access to those contexts; update the JSX where Chatbot is mounted to be enclosed by the MuiProvider and QueryProvider components (references: Chatbot, MuiProvider, QueryProvider).src/components/Chatbot/Chatbot.css (1)
77-79: 💤 Low valueRemove empty line before
transform-originto satisfy linter.Stylelint reports an empty line violation before the
transform-origindeclaration (line 78). While minor, this creates linter noise.🎨 Proposed fix
font-family: var(--font-geist-sans, sans-serif); color: `#fafafa`; - transform-origin: bottom right;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/Chatbot/Chatbot.css` around lines 77 - 79, Remove the blank line immediately before the transform-origin declaration so the rule reads consecutively with transform-origin: bottom right; followed by transform: scale(0.85) translateY(16px);; edit the block containing the transform-origin and transform declarations (the transform-origin declaration and the transform: scale(...) line) to eliminate the empty line to satisfy Stylelint.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/Chatbot/Chatbot.css`:
- Line 169: In src/components/Chatbot/Chatbot.css replace the deprecated CSS
declaration "word-break: break-word" with the modern equivalent "overflow-wrap:
break-word" in the rule that currently contains that property; locate the
occurrence of the "word-break: break-word" declaration and remove or replace it
with "overflow-wrap: break-word" so the element keeps the same wrapping behavior
without using the deprecated property.
In `@src/components/Chatbot/Chatbot.tsx`:
- Line 137: The fallback message shown via addMessage("Sorry, I didn't
understand that. Try: hello, today, time, ping, rn."); omits the 'about' and
'hey' commands defined in responseObj; update the fallback text in the Chatbot
component to include all keys from responseObj (e.g., hello, hey, about, today,
time, ping, rn) or generate the list dynamically from Object.keys(responseObj)
so the message always matches available commands.
- Around line 93-98: The EmailJS service/template/public key values are
hardcoded in the Chatbot component (the emailjs.send call) which prevents
rotation and exposes credentials; replace the literal strings 'service_2fc5v5k',
'template_d3d70zp', and 'De3J97q5iJ8M72LB0' with environment variables (e.g.
process.env.NEXT_PUBLIC_EMAILJS_SERVICE_ID,
process.env.NEXT_PUBLIC_EMAILJS_TEMPLATE_ID,
process.env.NEXT_PUBLIC_EMAILJS_PUBLIC_KEY), add those vars to .env.local as
suggested, and add a runtime check in the Chatbot component (before calling
emailjs.send) to log/throw a clear error if any of the required env vars are
missing so the app fails fast and credentials can be rotated without code
changes.
- Around line 33-34: The module-level counter (msgId) and generator (nextId) can
collide under React 19 Strict Mode and across multiple Chatbot instances; move
the counter into the Chatbot component scope using a persistent per-instance ref
or state (e.g. useRef in the Chatbot component) and replace usages of
nextId()/msgId with the per-instance ref (increment and read ref.current) so IDs
are stable per mount and not incremented globally across double-mounts or
multiple instances; update any references to nextId() to use the new
per-instance generator logic inside Chatbot.
---
Nitpick comments:
In `@src/app/layout.tsx`:
- Line 35: Chatbot is rendered outside the providers which will block future use
of React Query or MUI inside it; move the <Chatbot /> element so it is nested
inside the existing MuiProvider and QueryProvider (or duplicate the providers
around Chatbot) so that any future additions using useQuery/useMutation or MUI
components in the Chatbot component have access to those contexts; update the
JSX where Chatbot is mounted to be enclosed by the MuiProvider and QueryProvider
components (references: Chatbot, MuiProvider, QueryProvider).
In `@src/components/Chatbot/Chatbot.css`:
- Around line 77-79: Remove the blank line immediately before the
transform-origin declaration so the rule reads consecutively with
transform-origin: bottom right; followed by transform: scale(0.85)
translateY(16px);; edit the block containing the transform-origin and transform
declarations (the transform-origin declaration and the transform: scale(...)
line) to eliminate the empty line to satisfy Stylelint.
In `@src/components/Chatbot/Chatbot.tsx`:
- Line 58: Replace the three magic-number timeouts used in setTimeout calls
(e.g., the call that invokes inputRef.current?.focus(), the timeout used around
EMAIL focus, and the BOT response delay) with descriptive named constants
defined at the top of the Chatbot component file (for example FOCUS_DELAY_MS,
EMAIL_FOCUS_DELAY_MS, BOT_RESPONSE_DELAY_MS) and add brief comments explaining
each constant's purpose (e.g., "wait for open animation", "small email input
focus latency", "simulate bot typing delay"); then update the setTimeout
invocations to use these constants so the intent is documented and maintainable.
- Around line 82-84: The email validation branch currently shows an error
message but leaves the malformed value in the input; in the handler that checks
result.success (likely the email submit handler in Chatbot component, e.g.,
handleEmailSubmit or the function where result and addMessage are used) after
calling addMessage('Invalid email. Please try again.') also clear the input
state (call the component's input state setter such as setInput('') or reset the
controlled input value) and ensure any related validation state is reset so the
UI empties the field on validation failure.
- Around line 80-109: The submitEmail flow can be abused by repeated
submissions; add a client-side cooldown state (e.g., emailCooldown boolean or
emailCooldownUntil timestamp) checked at the start of submitEmail to
short-circuit and show a message if still cooling down, set that state when a
send succeeds (or on attempt) and use setTimeout or calculating remaining time
to clear it after ~60s, and ensure the UI/send button is disabled using that
state; update places that toggle email mode (setIsEmailMode, setPlaceholder) to
respect the cooldown and keep addMessage/removeLastMessage behavior consistent
while preventing multiple concurrent sends by guarding submitEmail against
re-entry.
- Line 10: The ResponseValue union currently includes an unused (() => void)
variant which allows handler functions to return undefined and then fall through
to the "didn't understand" fallback; remove (() => void) from the ResponseValue
type declaration so ResponseValue is only string | (() => string), and confirm
any call-sites that invoke response functions (the logic that checks for
'__EMAIL_FLOW__' and uses typeof result === 'string') still match the new type;
if you intend to support side-effect-only handlers later, instead keep the union
but add an explicit branch that treats undefined results as a valid no-op
response (with a clear comment) so the fallback is not triggered inadvertently.
- Around line 152-154: The element in Chatbot (component Chatbot, attributes
role="dialog" and aria-modal="false") uses dialog semantics but is non-modal;
update the role to a more accurate landmark (e.g., role="complementary" or
role="region") and remove aria-modal, or explicitly document/justify keeping
role="dialog" and set aria-modal="true" if it truly should be modal. Locate the
JSX in Chatbot where role="dialog" and aria-modal="false" are set and replace
the role and remove aria-modal (or set aria-modal to true) so semantics match
the interactive behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b11b9d52-776c-4831-b5f1-6bfddb2dbdbe
⛔ Files ignored due to path filters (2)
public/images/logo.pngis excluded by!**/*.pngpublic/images/send.pngis excluded by!**/*.png
📒 Files selected for processing (3)
src/app/layout.tsxsrc/components/Chatbot/Chatbot.csssrc/components/Chatbot/Chatbot.tsx
| max-width: 82%; | ||
| font-size: 0.875rem; | ||
| line-height: 1.45; | ||
| word-break: break-word; |
There was a problem hiding this comment.
Replace deprecated word-break: break-word with modern property.
word-break: break-word is deprecated. Use overflow-wrap: break-word instead for the same behavior without the deprecation warning.
🔧 Proposed fix
max-width: 82%;
font-size: 0.875rem;
line-height: 1.45;
- word-break: break-word;
+ overflow-wrap: break-word;
}📝 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.
| word-break: break-word; | |
| max-width: 82%; | |
| font-size: 0.875rem; | |
| line-height: 1.45; | |
| overflow-wrap: break-word; | |
| } |
🧰 Tools
🪛 Stylelint (17.11.1)
[error] 169-169: Deprecated keyword "break-word" for property "word-break" (declaration-property-value-keyword-no-deprecated)
(declaration-property-value-keyword-no-deprecated)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/Chatbot/Chatbot.css` at line 169, In
src/components/Chatbot/Chatbot.css replace the deprecated CSS declaration
"word-break: break-word" with the modern equivalent "overflow-wrap: break-word"
in the rule that currently contains that property; locate the occurrence of the
"word-break: break-word" declaration and remove or replace it with
"overflow-wrap: break-word" so the element keeps the same wrapping behavior
without using the deprecated property.
| let msgId = 0; | ||
| const nextId = () => ++msgId; |
There was a problem hiding this comment.
Global message ID counter may cause collisions in React 19 Strict Mode.
React 19 Strict Mode double-mounts components in development, and this module-level counter will increment across both mount cycles, potentially skipping IDs or causing inconsistencies if multiple Chatbot instances ever exist.
♻️ Proposed fix: move counter into component state
-let msgId = 0;
-const nextId = () => ++msgId;
export default function Chatbot() {
+ const nextIdRef = useRef(0);
+ const nextId = () => ++nextIdRef.current;
+
const [isOpen, setIsOpen] = useState(false);📝 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.
| let msgId = 0; | |
| const nextId = () => ++msgId; | |
| export default function Chatbot() { | |
| const nextIdRef = useRef(0); | |
| const nextId = () => ++nextIdRef.current; | |
| const [isOpen, setIsOpen] = useState(false); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/Chatbot/Chatbot.tsx` around lines 33 - 34, The module-level
counter (msgId) and generator (nextId) can collide under React 19 Strict Mode
and across multiple Chatbot instances; move the counter into the Chatbot
component scope using a persistent per-instance ref or state (e.g. useRef in the
Chatbot component) and replace usages of nextId()/msgId with the per-instance
ref (increment and read ref.current) so IDs are stable per mount and not
incremented globally across double-mounts or multiple instances; update any
references to nextId() to use the new per-instance generator logic inside
Chatbot.
| } else if (typeof res === 'string') { | ||
| addMessage(res); | ||
| } else { | ||
| addMessage("Sorry, I didn't understand that. Try: hello, today, time, ping, rn."); |
There was a problem hiding this comment.
Fallback message does not list all available commands.
The fallback mentions hello, today, time, ping, rn but omits about and hey, which are also defined in responseObj (lines 13, 19). This may confuse users who see incomplete help.
📝 Proposed fix
} else {
- addMessage("Sorry, I didn't understand that. Try: hello, today, time, ping, rn.");
+ addMessage("Sorry, I didn't understand that. Try: hello, hey, today, time, ping, about, rn.");
}📝 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.
| addMessage("Sorry, I didn't understand that. Try: hello, today, time, ping, rn."); | |
| addMessage("Sorry, I didn't understand that. Try: hello, hey, today, time, ping, about, rn."); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/Chatbot/Chatbot.tsx` at line 137, The fallback message shown
via addMessage("Sorry, I didn't understand that. Try: hello, today, time, ping,
rn."); omits the 'about' and 'hey' commands defined in responseObj; update the
fallback text in the Chatbot component to include all keys from responseObj
(e.g., hello, hey, about, today, time, ping, rn) or generate the list
dynamically from Object.keys(responseObj) so the message always matches
available commands.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/Chatbot/Chatbot.tsx`:
- Around line 93-98: Replace the hardcoded EmailJS placeholders in Chatbot.tsx
by reading service ID, template ID and public API key from environment variables
(e.g., process.env.EMAILJS_SERVICE_ID, process.env.EMAILJS_TEMPLATE_ID,
process.env.EMAILJS_PUBLIC_KEY) and validate they exist before calling
emailjs.send (return or show error if missing); update the emailjs.send call in
the Chatbot component to pass those env values instead of
'YOUR_SERVICE'/'YOUR_TEMPLATE'/'YOUR_APIKEY'. Also add `@emailjs/browser` to
package.json dependencies (use a v4-compatible version that supports the
fourth-argument { publicKey }) and run npm/yarn install so the import of emailjs
in Chatbot.tsx resolves at build/runtime.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7d76275e-6c1e-4738-be0c-0c83edfa7f05
📒 Files selected for processing (1)
src/components/Chatbot/Chatbot.tsx
| await emailjs.send( | ||
| 'YOUR_SERVICE', | ||
| 'YOUR_TEMPLATE', | ||
| { user_email: email, user: 'IssueHub' }, | ||
| { publicKey: 'YOUR_APIKEY' } | ||
| ); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check that `@emailjs/browser` is declared and inspect the pinned version range
fd -t f 'package.json' -E 'node_modules' --exec sh -c 'echo "== {} =="; jq ".dependencies[\"`@emailjs/browser`\"] // .devDependencies[\"`@emailjs/browser`\"]" "{}"'Repository: kanywst/IssueHub
Length of output: 86
🌐 Web query:
Does @emailjs/browser v4 send() accept an options object with publicKey as the 4th argument, and how does this differ from v3?
💡 Result:
Yes. In @emailjs/browser v4, emailjs.send(serviceId, templateId, templateParams, options) accepts an options object as the 4th argument, and that options object can include { publicKey: 'YOUR_PUBLIC_KEY' } [1][2]. The docs also state that options can be declared globally via emailjs.init(...) or locally as the fourth parameter, with the local parameter having higher priority [1]. How this differs from v3: I could not find v3-specific, official API documentation in the sources I retrieved that clearly states the v3 send signature or whether v3’s 4th argument is an options object. However, v3 client usage widely referenced in community material indicates supplying the public key as a positional argument to send (i.e., not an options object) [3]. Example (v4): emailjs.send('YOUR_SERVICE_ID', 'YOUR_TEMPLATE_ID', templateParams, { publicKey: 'YOUR_PUBLIC_KEY' }) [1][2].
Citations:
- 1: https://www.npmjs.com/package/@emailjs/browser
- 2: https://registry.npmjs.org/%40emailjs%2Fbrowser
- 3: https://stackoverflow.com/questions/71883246/user-id-required-to-send-mail-with-email-js
Fix EmailJS subscription send: hardcoded placeholders + undeclared dependency
- In
src/components/Chatbot/Chatbot.tsx(lines 93-98),'YOUR_SERVICE','YOUR_TEMPLATE', andpublicKey: 'YOUR_APIKEY'are non-functional placeholders; load these from environment variables and guard for missing values before callingemailjs.send. @emailjs/browseris imported but not declared inpackage.json, so the module may fail to resolve at build/runtime. Add@emailjs/browserto dependencies and ensure the installed version supports the current v4-style{ publicKey }4th-argument options.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/Chatbot/Chatbot.tsx` around lines 93 - 98, Replace the
hardcoded EmailJS placeholders in Chatbot.tsx by reading service ID, template ID
and public API key from environment variables (e.g.,
process.env.EMAILJS_SERVICE_ID, process.env.EMAILJS_TEMPLATE_ID,
process.env.EMAILJS_PUBLIC_KEY) and validate they exist before calling
emailjs.send (return or show error if missing); update the emailjs.send call in
the Chatbot component to pass those env values instead of
'YOUR_SERVICE'/'YOUR_TEMPLATE'/'YOUR_APIKEY'. Also add `@emailjs/browser` to
package.json dependencies (use a v4-compatible version that supports the
fourth-argument { publicKey }) and run npm/yarn install so the import of emailjs
in Chatbot.tsx resolves at build/runtime.
Add IssueBot – Floating ChatBot (v0.2)
What is this?
This PR introduces IssueBot, a lightweight floating chatbot widget built from scratch and integrated into IssueHub as a client-side React component.
IssueBot was created by students from U.T.U (Universidad del Trabajo del Uruguay) as their first open source contribution, with the goal of making information on the site more accessible — directly through the interface, without having to navigate away.
How it works
A floating bubble sits in the bottom-right corner of every page. Clicking it opens a chat window where users can interact with the bot via predefined commands or quick-action buttons.
The main feature in this version allows users to subscribe for notifications via email, using EmailJS as the delivery layer — no backend required.
Tech stack
@emailjs/browserpackage)Current functionality (v0.2)
hello,hey,ping,today,time,about)rnshortcut triggers the notification flow via textKnown limitations / out of scope for this version
Changes from v0.1 — addressing reviewer feedback
<Chatbot />is now rendered insrc/app/layout.tsx<img src="/Imagenes/...">withnext/image, which correctly applies the/IssueHubbasePath<div onClick>to<button type="button">, with properaria-labelattributes@emailjs/browseradded as a proper package dependency instead of a CDN script injection#18181b,#27272a) matching the rest of the projecttoday/timefix — values are now computed at call time, not frozen at module loadincludes('@')check withzod(z.string().email()), which is already a project dependencytitle="Minimizar"; renamedImagenes/→images/@types/reactbump — removed from this PR, split out as unrelatedFiles changed
Notes
This is our first contribution to an open source project. We are open to feedback and any further changes needed to meet the project's standards. Thank you for the detailed review on v0.1 — it helped us improve a lot! 🙏
Summary by CodeRabbit