Implement IRCv3 reaction#63
Conversation
- Remove problematic IRC link handling code that was causing parse errors - Fix syntax issues in MessageItem component by properly structuring conditional returns - Add missing imports (useEffect, useRef, useState, ircColors, uuidv4, platform, hooks) - Reorganize imports for better consistency
- Clean up import organization - Fix EnhancedLinkWrapper component formatting
- Implement handleIrcLinkClick function to connect to IRC servers from irc:// and ircs:// links - Update MessageItem component to accept onIrcLinkClick prop - Pass handleIrcLinkClick to all EnhancedLinkWrapper components in MessageItem - Fix parseInt radix warning in linting
- Update biome.json schema version to 2.2.4 - Run biome migrate to fix configuration format - Format all files according to current biome rules
- Change IRC link clicks to open the 'Connect to server' modal with pre-filled server details - Remove automatic connection logic - Add toggleAddServerModal to useStore destructuring - Parse IRC URL and populate modal with host, port, and current username
- Parse IRC URLs with proper handling of channels in pathname or hash - Extract nick and password from URL query parameters - Reuse existing server connections to avoid duplicates - Clean trailing punctuation from URLs in chat text - Connect directly instead of opening modal for better UX - Fix linting issues with void return in forEach callback
- Update @biomejs/biome from 2.2.0 to 2.2.4 in package.json - Update biome.json schema version to 2.2.4 - Run biome migrate to update configuration - Format all files to match CI expectations
- Remove automatic connection logic from IRC link clicks - Open the 'Connect to server' modal with pre-filled server details - Add toggleAddServerModal back to useStore destructuring - Make handleIrcLinkClick synchronous since no async operations - Fix default ports (6697 for ircs, 6667 for irc)
- Add ReactionModal component with emoji selector - Update Message type to track reactions with user information - Implement react button on messages that opens emoji modal - Send TAGMSG with draft/react tag when reacting to messages - Handle incoming reaction TAGMSG to update message reactions - Display reactions below messages with emoji, count, and user tooltips - Support reaction toggling (click same emoji to remove) The reaction feature allows users to react to messages with emojis, with reactions being synchronized across all clients in the channel using the IRC draft/react TAGMSG extension.
|
Warning Rate limit exceeded@ValwareIRC has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 20 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
WalkthroughAdds message reactions (data model, store handling, and UI modal), propagates msgid on messages, forwards IRC/IRCS link clicks to prefill server-join UI, and bumps Biome tooling from 2.2.0 → 2.2.4. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant U as User
participant MI as MessageItem
participant CA as ChatArea
participant RM as ReactionModal
participant ST as Store
U->>MI: Click react button
MI->>CA: onReactClick(message, anchorEl)
CA->>RM: open modal (isOpen = true)
U->>RM: Select emoji
RM-->>CA: onSelectEmoji(emoji)
CA->>ST: dispatch +draft/react (msgid, emoji)
ST-->>CA: updated message.reactions
CA-->>MI: rerender message with reactions
sequenceDiagram
autonumber
participant U as User
participant EL as EnhancedLinkWrapper
participant CA as ChatArea
participant UI as ServerAddUI
U->>EL: Click `irc://` or `ircs://` link
EL->>CA: onIrcLinkClick(url)
CA->>CA: parse host/port/channel/nick
CA->>UI: open server-add modal prefilled with params
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
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 |
|
Automated deployment preview for the PR in the Cloudflare Pages. |
- Format reaction display code in ChatArea.tsx - Format reaction handling code in store/index.ts - Format ReactionModal component
- Center ReactionModal on screen with backdrop overlay - Add msgid field to Message interface to store IRC message ID - Update message creation to capture msgid from IRC message tags - Use msgid in TAGMSG reactions instead of internal message ID - Remove position-based modal positioning logic The emoji picker now appears centered on screen, and reactions use the proper IRC msgid for the +reply tag as required by the draft/react TAGMSG specification.
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (6)
biome.json(1 hunks)package.json(1 hunks)src/components/layout/ChatArea.tsx(13 hunks)src/components/ui/ReactionModal.tsx(1 hunks)src/store/index.ts(3 hunks)src/types/index.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/store/index.ts (1)
src/types/index.ts (2)
Channel(35-46)PrivateChat(48-55)
src/components/layout/ChatArea.tsx (3)
src/lib/ircUtils.tsx (1)
mircToHtml(167-279)src/hooks/useTabCompletion.ts (1)
useTabCompletion(31-154)src/lib/ircClient.ts (1)
ircClient(561-561)
🔇 Additional comments (2)
package.json (1)
44-44: Biome devDependency bump LGTM. Keeping@biomejs/biomeat 2.2.4 aligns tooling with the updated schema and doesn’t perturb other dependencies, so this looks good.biome.json (1)
2-2: Schema URL matches upgraded tooling. Pointing to the 2.2.4 schema keeps the config in lockstep with the new Biome release, so no issues here.
| const messages = getChannelMessages(server.id, channel.id); | ||
| const messageIndex = messages.findIndex((m) => m.id === replyMessageId); | ||
| if (messageIndex === -1) return; | ||
|
|
||
| const message = messages[messageIndex]; | ||
| const existingReactionIndex = message.reactions.findIndex( | ||
| (r) => r.emoji === emoji && r.userId === `${server.id}-${sender}`, | ||
| ); | ||
|
|
||
| useStore.setState((state) => { | ||
| const updatedMessages = [...messages]; | ||
| if (existingReactionIndex === -1) { | ||
| // Add new reaction | ||
| updatedMessages[messageIndex] = { | ||
| ...message, | ||
| reactions: [ | ||
| ...message.reactions, | ||
| { emoji, userId: `${server.id}-${sender}` }, | ||
| ], | ||
| }; | ||
| } else { | ||
| // Remove existing reaction (toggle behavior) | ||
| updatedMessages[messageIndex] = { | ||
| ...message, | ||
| reactions: message.reactions.filter( | ||
| (_, i) => i !== existingReactionIndex, | ||
| ), | ||
| }; | ||
| } | ||
|
|
||
| const key = `${server.id}-${channel.id}`; | ||
| return { | ||
| messages: { | ||
| ...state.messages, | ||
| [key]: updatedMessages, | ||
| }, | ||
| }; |
There was a problem hiding this comment.
Fix reaction lookup to match msgid.
+draft/react messages carry the parent msgid, but the handler searches messages by our local id. As soon as the server echoes a reaction, messageIndex stays -1, so nothing is added or toggled. Reactions never show up in the UI. Please key the lookup against msgid (falling back to id for safety) so the new feature actually works.
Apply this diff:
- const messageIndex = messages.findIndex((m) => m.id === replyMessageId);
+ const messageIndex = messages.findIndex(
+ (m) => m.msgid === replyMessageId || m.id === replyMessageId,
+ );📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const messages = getChannelMessages(server.id, channel.id); | |
| const messageIndex = messages.findIndex((m) => m.id === replyMessageId); | |
| if (messageIndex === -1) return; | |
| const message = messages[messageIndex]; | |
| const existingReactionIndex = message.reactions.findIndex( | |
| (r) => r.emoji === emoji && r.userId === `${server.id}-${sender}`, | |
| ); | |
| useStore.setState((state) => { | |
| const updatedMessages = [...messages]; | |
| if (existingReactionIndex === -1) { | |
| // Add new reaction | |
| updatedMessages[messageIndex] = { | |
| ...message, | |
| reactions: [ | |
| ...message.reactions, | |
| { emoji, userId: `${server.id}-${sender}` }, | |
| ], | |
| }; | |
| } else { | |
| // Remove existing reaction (toggle behavior) | |
| updatedMessages[messageIndex] = { | |
| ...message, | |
| reactions: message.reactions.filter( | |
| (_, i) => i !== existingReactionIndex, | |
| ), | |
| }; | |
| } | |
| const key = `${server.id}-${channel.id}`; | |
| return { | |
| messages: { | |
| ...state.messages, | |
| [key]: updatedMessages, | |
| }, | |
| }; | |
| const messages = getChannelMessages(server.id, channel.id); | |
| const messageIndex = messages.findIndex( | |
| (m) => m.msgid === replyMessageId || m.id === replyMessageId, | |
| ); | |
| if (messageIndex === -1) return; | |
| const message = messages[messageIndex]; | |
| const existingReactionIndex = message.reactions.findIndex( | |
| (r) => r.emoji === emoji && r.userId === `${server.id}-${sender}`, | |
| ); | |
| useStore.setState((state) => { | |
| const updatedMessages = [...messages]; | |
| if (existingReactionIndex === -1) { | |
| // Add new reaction | |
| updatedMessages[messageIndex] = { | |
| ...message, | |
| reactions: [ | |
| ...message.reactions, | |
| { emoji, userId: `${server.id}-${sender}` }, | |
| ], | |
| }; | |
| } else { | |
| // Remove existing reaction (toggle behavior) | |
| updatedMessages[messageIndex] = { | |
| ...message, | |
| reactions: message.reactions.filter( | |
| (_, i) => i !== existingReactionIndex, | |
| ), | |
| }; | |
| } | |
| const key = `${server.id}-${channel.id}`; | |
| return { | |
| messages: { | |
| ...state.messages, | |
| [key]: updatedMessages, | |
| }, | |
| }; | |
| }); |
🤖 Prompt for AI Agents
In src/store/index.ts around lines 1438 to 1474, the handler currently finds the
target message by comparing message.id to replyMessageId which fails for
+draft/react events that carry the parent msgid; change the lookup to match
m.msgid === replyMessageId and fall back to m.id === replyMessageId (e.g.,
findIndex(m => m.msgid === replyMessageId || m.id === replyMessageId)), leaving
the rest of the reaction toggle logic unchanged so reactions are applied to the
correct message.
…es with msgid - Change TAGMSG to use +reply instead of reply for msgid reference - Only show react button for messages that have msgid stored - Ensure msgid is properly stored from IRC message tags - Reactions now require msgid to be present on target message This ensures that reactions can only be sent for messages that have msgid, and the +reply tag properly references the target message's msgid as required by the IRC draft/react specification.
- Remove extra closing div tag causing JSX structure corruption - Add missing React hooks (useState, useEffect, useRef) to imports - Import missing dependencies (useTabCompletion, useMediaQuery, uuidv4, platform, ircColors) - Fix lastTypingTime variable declaration from const to let - Correct store and Message type import paths - Ensure reaction badges display properly at bottom-left of messages with hover tooltips
- Remove unused useKeyboardShortcuts import - Apply proper import sorting and formatting - Fix reaction tooltip formatting (quotes, parentheses, line breaks)
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/layout/ChatArea.tsx(13 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/layout/ChatArea.tsx (2)
src/lib/ircUtils.tsx (1)
mircToHtml(167-279)src/lib/ircClient.ts (1)
ircClient(561-561)
🪛 GitHub Actions: Lint and Tests
src/components/layout/ChatArea.tsx
[error] 29-31: This import is unused.
[error] 393-404: File content differs from formatting output. Run the formatter to fix.
🔇 Additional comments (2)
src/components/layout/ChatArea.tsx (2)
1088-1095: Re-enable reactions in private chats.This still only targets channels, so reacting in a DM silently drops the TAGMSG—exactly what the earlier review called out. Please locate the matching private chat and fall back to its username when no channel is found:
- const channel = server?.channels.find( - (c) => c.id === reactionModal.message?.channelId, - ); - if (server && channel) { - const tagMsg = `@+draft/react=${emoji};+draft/reply=${reactionModal.message.msgid} TAGMSG ${channel.name}`; + const channel = server?.channels.find( + (c) => c.id === reactionModal.message?.channelId, + ); + const privateChat = server?.privateChats?.find( + (pc) => pc.id === reactionModal.message?.channelId, + ); + const target = channel?.name ?? privateChat?.username; + + if (server && target) { + const tagMsg = `@+draft/react=${emoji};+draft/reply=${reactionModal.message.msgid} TAGMSG ${target}`; ircClient.sendRaw(server.id, tagMsg); }
488-492: Fix the IRC default port handling.When an IRC/IRCS URL omits the explicit port, you’re defaulting to 8000/443, which will fail against standard networks. The usual defaults are 6667 for plain IRC and 6697 for TLS. Please update the fallback logic accordingly.
⛔ Skipped due to learnings
Learnt from: ValwareIRC PR: ObsidianIRC/ObsidianIRC#62 File: src/components/layout/ChatArea.tsx:0-0 Timestamp: 2025-09-28T19:37:34.200Z Learning: ObsidianIRC uses websockets for IRC connections, not traditional IRC protocol. Default ports are 443 for secure connections (ircs://) and 8000 for plain connections (irc://), not the standard IRC ports 6667/6697.
- Move reply and react buttons back inside message container with proper hover visibility - Add relative positioning to message content container for absolute reaction positioning - Ensure reactions display at bottom-left of message content with proper tooltips - Fix incoming reaction display functionality
- Change mtags.reply to mtags['+draft/reply'] for IRC draft/react spec compliance - Change message.id comparison to message.msgid for proper message matching - Ensure incoming TAGMSG reactions are properly added to messages with matching msgid
- Move reaction badges below message content instead of absolute positioning - Use flex layout with margin-top for proper spacing - Remove absolute positioning that was causing text overlap - Maintain hover tooltips and reaction functionality
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/layout/ChatArea.tsx(14 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/layout/ChatArea.tsx (3)
src/lib/ircUtils.tsx (1)
mircToHtml(167-279)src/hooks/useTabCompletion.ts (1)
useTabCompletion(31-154)src/lib/ircClient.ts (1)
ircClient(561-561)
🔇 Additional comments (2)
src/components/layout/ChatArea.tsx (2)
1087-1099: Reactions still ignore private messages.
handleReactionSelectonly targets channels, so reacting inside a DM silently does nothing. Resolve the private chat like we do elsewhere and send the TAGMSG to that nickname.- const channel = server?.channels.find( - (c) => c.id === reactionModal.message?.channelId, - ); - if (server && channel) { - const tagMsg = `@+draft/react=${emoji};+draft/reply=${reactionModal.message.msgid} TAGMSG ${channel.name}`; + const channel = server?.channels.find( + (c) => c.id === reactionModal.message?.channelId, + ); + const privateChat = server?.privateChats?.find( + (pc) => pc.id === reactionModal.message?.channelId, + ); + const target = channel?.name ?? privateChat?.username; + + if (server && target) { + const tagMsg = `@+draft/react=${emoji};+draft/reply=${reactionModal.message.msgid} TAGMSG ${target}`; ircClient.sendRaw(server.id, tagMsg); }
490-525: Fix default IRC port selection.We default TLS connections to 443 and plain IRC to 8000, but the established defaults are 6697 (IRCS) and 6667 (IRC). Using the wrong ports will fail to connect to most networks when the URL omits
:port.- const port = urlObj.port - ? Number.parseInt(urlObj.port, 10) - : scheme === "ircs" - ? 443 - : 8000; + const port = urlObj.port + ? Number.parseInt(urlObj.port, 10) + : scheme === "ircs" + ? 6697 + : 6667;⛔ Skipped due to learnings
Learnt from: ValwareIRC PR: ObsidianIRC/ObsidianIRC#62 File: src/components/layout/ChatArea.tsx:0-0 Timestamp: 2025-09-28T19:37:34.200Z Learning: ObsidianIRC uses websockets for IRC connections, not traditional IRC protocol. Default ports are 443 for secure connections (ircs://) and 8000 for plain connections (irc://), not the standard IRC ports 6667/6697.
| if ( | ||
| (matches[index].startsWith("ircs://") || | ||
| matches[index].startsWith("irc://")) && | ||
| onIrcLinkClick | ||
| ) { | ||
| e.preventDefault(); | ||
| onIrcLinkClick(matches[index]); | ||
| } | ||
| }} |
There was a problem hiding this comment.
Allow uppercase IRC schemes in link handler.
startsWith("irc://") is case-sensitive, so IRC:// or IRCS:// links won’t trigger the join modal. Normalize the scheme before comparing so we honor the URI spec’s case-insensitive requirement.
- if (
- (matches[index].startsWith("ircs://") ||
- matches[index].startsWith("irc://")) &&
+ const normalized = matches[index].toLowerCase();
+ if (
+ (normalized.startsWith("ircs://") ||
+ normalized.startsWith("irc://")) &&
onIrcLinkClick
) {📝 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.
| if ( | |
| (matches[index].startsWith("ircs://") || | |
| matches[index].startsWith("irc://")) && | |
| onIrcLinkClick | |
| ) { | |
| e.preventDefault(); | |
| onIrcLinkClick(matches[index]); | |
| } | |
| }} | |
| const normalized = matches[index].toLowerCase(); | |
| if ( | |
| (normalized.startsWith("ircs://") || | |
| normalized.startsWith("irc://")) && | |
| onIrcLinkClick | |
| ) { | |
| e.preventDefault(); | |
| onIrcLinkClick(matches[index]); | |
| } |
🤖 Prompt for AI Agents
In src/components/layout/ChatArea.tsx around lines 124 to 132, the link handler
checks for "ircs://" or "irc://" using case-sensitive startsWith, so uppercase
variants like "IRC://" are ignored; normalize the link's scheme to lowercase
before comparing (e.g., call toLowerCase() on matches[index] or its scheme
substring) and then check startsWith("ircs://") or startsWith("irc://"),
preserving the existing e.preventDefault() and onIrcLinkClick call when matched.
There was a problem hiding this comment.
oh how did this get in this PR
There was a problem hiding this comment.
@ValwareIRC It looks like the IRC link handling functionality got mixed into this reactions PR! The EnhancedLinkWrapper changes that add onIrcLinkClick support and the handleIrcLinkClick function seem like they should be in a separate PR focused on IRC link handling, rather than bundled with the reaction feature.
Would you like to:
- Move the IRC link handling code to a separate PR, or
- Remove it from this PR to keep the scope focused on just reactions?
The reactions functionality itself looks solid - it's just the link handling that seems out of place for this PR's objectives.
🐰💭
- Add unreact TAGMSG handler in store for +draft/unreact messages - Modify ChatArea reaction selection to send appropriate react/unreact messages - Enable users to both add and remove emoji reactions with proper IRC protocol compliance
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/components/layout/ChatArea.tsx(14 hunks)src/store/index.ts(3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/store/index.ts (1)
src/types/index.ts (2)
Channel(35-46)PrivateChat(48-55)
src/components/layout/ChatArea.tsx (3)
src/lib/ircUtils.tsx (1)
mircToHtml(167-279)src/hooks/useTabCompletion.ts (1)
useTabCompletion(31-154)src/lib/ircClient.ts (1)
ircClient(561-561)
🔇 Additional comments (3)
src/store/index.ts (1)
1438-1475: Reactions still can’t bind to messages without a msgid fallback.Line [1439] (and the unreact block at Line [1501]) only compare
m.msgidagainstreplyMessageId. As noted earlier,+draft/reactevents carry the parent msgid, but our history (and even freshly received messages while msgid support is flaky) may only haveid. Without the fallback,messageIndexstays-1and reactions never stick. Please fall back to the local id in both blocks.- const messageIndex = messages.findIndex((m) => m.msgid === replyMessageId); + const messageIndex = messages.findIndex( + (m) => m.msgid === replyMessageId || m.id === replyMessageId, + );Apply the same change inside the unreact handler.
Also applies to: 1499-1527
src/components/layout/ChatArea.tsx (2)
124-132: IRC links are still case-sensitive.Line [125] keeps checking
startsWith("irc://")andstartsWith("ircs://"), soIRC:///IRCS://links silently fall through. Normalize the matched URI before comparing so we satisfy the scheme’s case-insensitivity.- if ( - (matches[index].startsWith("ircs://") || - matches[index].startsWith("irc://")) && + const normalized = matches[index].toLowerCase(); + if ( + (normalized.startsWith("ircs://") || + normalized.startsWith("irc://")) &&
1087-1113: DM reactions never fire.Line [1092] only looks for a channel object, so
privateChattargets always fall through and we never emit the TAGMSG. Resolve the private chat (username) and reuse it as the target; the same logic should apply to both react and unreact paths.- const channel = server?.channels.find( - (c) => c.id === reactionModal.message?.channelId, - ); - if (server && channel) { + const channel = server?.channels.find( + (c) => c.id === reactionModal.message?.channelId, + ); + const privateChat = server?.privateChats?.find( + (pc) => pc.id === reactionModal.message?.channelId, + ); + const target = channel?.name ?? privateChat?.username; + + if (server && target) { // Check if user has already reacted with this emoji const existingReaction = reactionModal.message.reactions.find( @@ - const tagMsg = `@+draft/unreact=${emoji};+draft/reply=${reactionModal.message.msgid} TAGMSG ${channel.name}`; + const tagMsg = `@+draft/unreact=${emoji};+draft/reply=${reactionModal.message.msgid} TAGMSG ${target}`; @@ - const tagMsg = `@+draft/react=${emoji};+draft/reply=${reactionModal.message.msgid} TAGMSG ${channel.name}`; + const tagMsg = `@+draft/react=${emoji};+draft/reply=${reactionModal.message.msgid} TAGMSG ${target}`;Mirror the
privateChat/targethandling inside the unreact branch as well.
| const newMessage = { | ||
| id: replyId ? replyId : uuidv4(), | ||
| msgid: mtags?.msgid, | ||
| content: message, | ||
| timestamp, | ||
| userId: response.sender, | ||
| channelId: channel.id, | ||
| serverId: server.id, | ||
| type: "message" as const, | ||
| reacts: [], | ||
| reactions: [], | ||
| replyMessage: replyMessage, | ||
| mentioned: [], // Add logic for mentions if needed | ||
| }; |
There was a problem hiding this comment.
Stop copying the parent reply id into new message IDs.
Line [899] currently sets id to the replied-to msgid, so every reply reuses its parent’s identifier. That breaks React keys (duplicates), makes replies overwrite each other in state, and still doesn’t give the reply a unique identifier. Instead, derive the id from the message’s own msgid (fall back to uuidv4() when absent) and keep replyMessage referencing the parent.
- const newMessage = {
- id: replyId ? replyId : uuidv4(),
+ const messageId = mtags?.msgid ?? uuidv4();
+ const newMessage = {
+ id: messageId,
msgid: mtags?.msgid,📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const newMessage = { | |
| id: replyId ? replyId : uuidv4(), | |
| msgid: mtags?.msgid, | |
| content: message, | |
| timestamp, | |
| userId: response.sender, | |
| channelId: channel.id, | |
| serverId: server.id, | |
| type: "message" as const, | |
| reacts: [], | |
| reactions: [], | |
| replyMessage: replyMessage, | |
| mentioned: [], // Add logic for mentions if needed | |
| }; | |
| const messageId = mtags?.msgid ?? uuidv4(); | |
| const newMessage = { | |
| id: messageId, | |
| msgid: mtags?.msgid, | |
| content: message, | |
| timestamp, | |
| userId: response.sender, | |
| channelId: channel.id, | |
| serverId: server.id, | |
| type: "message" as const, | |
| reactions: [], | |
| replyMessage: replyMessage, | |
| mentioned: [], // Add logic for mentions if needed | |
| }; |
🤖 Prompt for AI Agents
In src/store/index.ts around lines 897 to 909, the new message id is incorrectly
set to the parent reply id (replyId) which causes duplicate ids; change the id
assignment to derive from the message's own msgid (use mtags?.msgid) and fall
back to uuidv4() when absent (i.e. id = mtags?.msgid ?? uuidv4()), remove using
replyId for id, and keep replyMessage pointing to the parent reply so replies
remain linked but have unique ids.
- Display red X button on reactions made by current user - X button appears on hover with smooth opacity transition - Clicking X button immediately removes the reaction - Clicking reaction badge toggles between add/remove based on user state - Enhanced reaction UI with better user interaction feedback
- Store reaction userIds as just the username instead of serverId-username - Update all reaction checking logic to match new userId format - Fix tooltip display to show usernames directly without parsing - Ensure consistent user identification across react/unreact operations
- Format arrow function in ChatArea.tsx reaction checking - Format array/object literals in store TAGMSG handlers
Implement IRCv3 reaction
Summary by CodeRabbit
New Features
Improvements
Chores