-
-
Notifications
You must be signed in to change notification settings - Fork 37
feat: @robojs/events-manager plugin for event management #455
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: @robojs/events-manager plugin for event management #455
Conversation
|
CLA Assistant Lite bot: I have read the CLA Document and I hereby sign the CLA You can retrigger this bot by commenting recheck in this Pull Request |
1e3411c to
c255945
Compare
I have read the CLA Document and I hereby sign the CLA |
|
recheck |
WalkthroughA new Discord Events Manager plugin is introduced with complete infrastructure for creating, listing, and managing community events. The package includes CRUD operations for events, RSVP tracking, reminder scheduling with periodic processing, command handlers, interaction handlers, and supporting utilities. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Discord
participant Commands
participant Storage
participant Reminders
autonumber
User->>Discord: /event-create
Discord->>Commands: event-create handler
Commands->>Discord: show modal (title, desc, datetime, location, maxAttendees)
User->>Discord: submit modal
Discord->>Commands: modal-handler
Commands->>Commands: validate datetime & inputs
Commands->>Storage: saveEvent()
Storage->>Storage: store event in Flashcore
Commands->>Discord: reply with event embed + buttons
User->>Discord: click "Going" button
Discord->>Commands: button-handler (event-rsvp-yes)
Commands->>Storage: updateRSVP(userId, "yes")
Storage->>Storage: add user to attendees, check capacity
Commands->>Discord: update embed, send confirmation
Note over Reminders: Every 60 seconds
Reminders->>Storage: getAllReminders()
Storage-->>Reminders: reminders list
alt Reminder due (within 2-min window)
Reminders->>Storage: getEvent()
Storage-->>Reminders: event details
Reminders->>Discord: send reminder to channel
Reminders->>Storage: deleteReminder()
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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 |
|
Hi @DevArqf, Thank you for your contribution and for submitting the new @robojs/events-manager plugin! We appreciate the effort you've put into creating this feature for the Robo.js community. Before we can merge this, we have some feedback and required changes to ensure the plugin is robust and works as described. Key areas for improvement:
Fix functionality:
If you have any questions about using Flashcore or anything else, feel free to ask. Thanks again for your contribution! |
Alrighty, I will take all of those into consideration and I will also add the fixes as soon as possible. Currently busy so it might take some time. |
…PR feedback - Remove placeholder files (ping.js, boost/dev.js, messageCreate/example.js) - Add Flashcore-based data persistence for events, RSVPs, and reminders - Implement proper RSVP tracking with user data and capacity management - Fix event listing to use persisted data from Flashcore - Fix reminder scheduling with proper storage - Update README to accurately reflect implemented features - Add storage utility module for centralized data management - Include event ID in button customIds for proper event identification Addresses PR Wave-Play#455 review feedback
PR Feedback AddressedHey @Pkmmte, I've implemented all the requested changes: Changes made:
Details:
The plugin should now be fully functional with persistent data storage. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 13
🧹 Nitpick comments (5)
packages/plugin-events-manager/config/robo.mjs (1)
7-8: Consider removing unnecessary GuildMessages intent.The plugin appears to use slash commands and button interactions exclusively, which only require the
Guildsintent. TheGuildMessagesintent is typically needed for reading message content, which doesn't seem to be utilized here.Apply this diff if message content is not needed:
clientOptions: { - intents: ['Guilds', 'GuildMessages'] + intents: ['Guilds'] },packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js (1)
114-116: Add comment or implementation for the 'today' case.The empty
else ifblock for 'today' should either contain logic or include a comment explaining why no modification totargetDateis needed.} else if (input.includes('today')) { - + // targetDate already initialized to current date, no modification needed } else if (input.includes('next')) {packages/plugin-events-manager/src/events/interactionCreate/button-handler.js (3)
2-2: Remove unused imports.
ActionRowBuilder,ButtonBuilder, andButtonStyleare imported but never used in this file.-import { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } from 'discord.js' +import { EmbedBuilder } from 'discord.js'
161-189: Remove unused parameter 'rsvpType'.The
rsvpTypeparameter is defined but never used in theupdateEventEmbedWithRSVPfunction.-function updateEventEmbedWithRSVP(originalEmbed, eventData, rsvpType) { +function updateEventEmbedWithRSVP(originalEmbed, eventData) {Update the call site at line 51:
- const updatedEmbed = updateEventEmbedWithRSVP(embed, updatedEvent, rsvpType) + const updatedEmbed = updateEventEmbedWithRSVP(embed, updatedEvent)
102-127: Extract repetitive user-fetching logic into a helper function.The pattern of fetching users and handling errors is repeated three times for the three attendee categories. Consider extracting this into a helper function to reduce duplication.
async function fetchAttendeeDetails(interaction, userIds) { const details = [] for (const userId of userIds) { try { const user = await interaction.client.users.fetch(userId) details.push({ id: userId, name: user.displayName || user.username }) } catch { details.push({ id: userId, name: 'Unknown User' }) } } return details }Then use:
attendeeDetails.going = await fetchAttendeeDetails(interaction, event.attendees.going || []) attendeeDetails.maybe = await fetchAttendeeDetails(interaction, event.attendees.maybe || []) attendeeDetails.notGoing = await fetchAttendeeDetails(interaction, event.attendees.notGoing || [])
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
packages/plugin-events-manager/.gitignore(1 hunks)packages/plugin-events-manager/LICENSE(1 hunks)packages/plugin-events-manager/README.md(1 hunks)packages/plugin-events-manager/config/robo.mjs(1 hunks)packages/plugin-events-manager/package.json(1 hunks)packages/plugin-events-manager/src/commands/event-create.js(1 hunks)packages/plugin-events-manager/src/commands/event-list.js(1 hunks)packages/plugin-events-manager/src/commands/event-remind.js(1 hunks)packages/plugin-events-manager/src/core/storage.js(1 hunks)packages/plugin-events-manager/src/events/interactionCreate/button-handler.js(1 hunks)packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js(1 hunks)packages/plugin-events-manager/src/events/ready.js(1 hunks)packages/plugin-events-manager/tsconfig.json(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
packages/{@robojs/*,plugin-*}/**
📄 CodeRabbit inference engine (AGENTS.md)
House plugin packages within packages/@robojs/* or packages/plugin-*
Files:
packages/plugin-events-manager/README.mdpackages/plugin-events-manager/src/commands/event-list.jspackages/plugin-events-manager/package.jsonpackages/plugin-events-manager/LICENSEpackages/plugin-events-manager/src/events/interactionCreate/button-handler.jspackages/plugin-events-manager/src/commands/event-remind.jspackages/plugin-events-manager/config/robo.mjspackages/plugin-events-manager/src/commands/event-create.jspackages/plugin-events-manager/src/events/ready.jspackages/plugin-events-manager/src/events/interactionCreate/modal-handler.jspackages/plugin-events-manager/src/core/storage.jspackages/plugin-events-manager/tsconfig.json
packages/{@robojs/*,plugin-*}/README.md
📄 CodeRabbit inference engine (AGENTS.md)
Each plugin package should include a README with usage instructions
Files:
packages/plugin-events-manager/README.md
🧠 Learnings (1)
📚 Learning: 2025-10-20T07:42:16.211Z
Learnt from: CR
PR: Wave-Play/robo.js#0
File: packages/@robojs/ai/AGENTS.md:0-0
Timestamp: 2025-10-20T07:42:16.211Z
Learning: Applies to packages/robojs/ai/config/plugins/robojs/ai.* : Place plugin configuration under config/plugins/robojs/ai.* with options: instructions, command allow/deny, restrict, whitelist, insight, engine, and optional voice overrides
Applied to files:
packages/plugin-events-manager/config/robo.mjs
🧬 Code graph analysis (10)
packages/plugin-events-manager/src/commands/event-list.js (2)
packages/plugin-events-manager/src/events/interactionCreate/button-handler.js (2)
interaction(5-15)event(87-87)packages/plugin-events-manager/src/core/storage.js (6)
events(56-56)events(241-241)getAllEvents(53-73)event(59-59)event(98-98)event(137-137)
packages/plugin-events-manager/package.json (1)
packages/robo/src/cli/utils/manifest.ts (3)
generateManifest(89-143)key(256-262)middleware(263-267)
packages/plugin-events-manager/src/events/interactionCreate/button-handler.js (3)
packages/plugin-events-manager/src/commands/event-create.js (4)
interaction(17-60)embed(41-41)embed(166-191)eventData(31-31)packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js (4)
interaction(5-11)embed(73-73)embed(168-192)eventData(40-56)packages/plugin-events-manager/src/core/storage.js (6)
eventId(10-10)updateRSVP(96-133)event(59-59)event(98-98)event(137-137)getEvent(31-40)
packages/plugin-events-manager/src/commands/event-remind.js (1)
packages/plugin-events-manager/src/core/storage.js (8)
events(56-56)events(241-241)searchEvents(239-253)event(59-59)event(98-98)event(137-137)reminder(203-203)saveReminder(152-173)
packages/plugin-events-manager/config/robo.mjs (3)
packages/robo/src/cli/utils/manifest.ts (4)
generateManifest(89-143)key(256-262)middleware(263-267)readPluginManifest(145-200)packages/robo/src/types/config.ts (1)
Config(5-49)packages/robo/src/types/manifest.ts (1)
Manifest(7-25)
packages/plugin-events-manager/src/commands/event-create.js (3)
packages/plugin-events-manager/src/events/interactionCreate/button-handler.js (5)
interaction(5-15)embed(50-50)embed(162-167)embed(205-208)eventId(78-78)packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js (11)
interaction(5-11)eventData(40-56)saved(65-65)embed(73-73)embed(168-192)title(15-15)description(16-16)rsvpYes(209-212)rsvpMaybe(214-217)rsvpNo(219-222)viewAttendees(224-227)packages/plugin-events-manager/src/core/storage.js (2)
saveEvent(8-29)eventId(10-10)
packages/plugin-events-manager/src/events/ready.js (2)
packages/robo/src/default/events/ready.ts (1)
client(8-26)packages/robo/src/core/robo.ts (2)
event(80-80)start(38-114)
packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js (3)
packages/plugin-events-manager/src/commands/event-create.js (10)
interaction(17-60)title(68-68)description(70-70)dateTimeInput(132-136)maxAttendeesInput(146-151)eventData(31-31)saved(33-33)embed(41-41)embed(166-191)buttons(42-42)packages/plugin-events-manager/src/events/interactionCreate/button-handler.js (6)
interaction(5-15)embed(50-50)embed(162-167)embed(205-208)buttons(52-52)eventId(78-78)packages/plugin-events-manager/src/core/storage.js (2)
saveEvent(8-29)eventId(10-10)
packages/plugin-events-manager/src/core/storage.js (5)
packages/plugin-events-manager/src/commands/event-create.js (1)
eventData(31-31)packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js (1)
eventData(40-56)packages/plugin-events-manager/src/events/interactionCreate/button-handler.js (4)
eventId(78-78)event(87-87)userId(20-20)rsvpType(19-19)packages/plugin-events-manager/src/commands/event-list.js (1)
events(35-35)packages/plugin-events-manager/src/commands/event-remind.js (3)
events(51-51)event(60-60)reminder(71-79)
packages/plugin-events-manager/tsconfig.json (2)
packages/robo/src/cli/commands/build/plugin.ts (1)
changes(113-135)packages/robo/src/cli/utils/compiler.ts (1)
RoboCompileOptions(121-129)
🪛 ESLint
packages/plugin-events-manager/src/events/interactionCreate/button-handler.js
[error] 2-2: 'ActionRowBuilder' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 2-2: 'ButtonBuilder' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 2-2: 'ButtonStyle' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 161-161: 'rsvpType' is defined but never used.
(@typescript-eslint/no-unused-vars)
packages/plugin-events-manager/src/commands/event-remind.js
[error] 200-200: 'client' is defined but never used.
(@typescript-eslint/no-unused-vars)
packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js
[error] 114-116: Empty block statement.
(no-empty)
🪛 LanguageTool
packages/plugin-events-manager/README.md
[style] ~110-~110: It’s more common nowadays to write this noun as one word.
Context: ...ce - 👥 View Attendees - See actual user names and attendance counts ### Setting Remi...
(RECOMMENDED_COMPOUNDS)
🪛 markdownlint-cli2 (0.18.1)
packages/plugin-events-manager/README.md
212-212: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🔇 Additional comments (4)
packages/plugin-events-manager/src/commands/event-list.js (3)
35-35: Verify persistence implementation in getAllEvents.Per the PR reviewer's feedback, the current implementation uses mock data and does not persist events across restarts. Ensure that
getAllEventsfrom storage.js is updated to use Robo.js's Flashcore for actual persistence before this command will function correctly.Based on PR review feedback requesting Flashcore integration for persistence.
69-81: LGTM - Clean filtering logic.The event filtering by date is straightforward and correct.
97-150: Well-structured embed builder with good UX details.The embed creation includes helpful features like relative timestamps, attendee counts, status indicators, and smart sorting based on filter type. The 100-character description truncation prevents overly long embeds.
packages/plugin-events-manager/src/core/storage.js (1)
1-253: Well-implemented storage layer with proper persistence.The storage module correctly uses Flashcore for persistence (addressing the reviewer's requirement), implements comprehensive CRUD operations with proper error handling, and includes date normalization to handle deserialization. The namespacing by
guildIdensures proper data isolation.
packages/plugin-events-manager/src/events/interactionCreate/button-handler.js
Show resolved
Hide resolved
packages/plugin-events-manager/src/events/interactionCreate/button-handler.js
Outdated
Show resolved
Hide resolved
packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js
Outdated
Show resolved
Hide resolved
…of ManageEvents - Replace invalid 'ManageEvents' with 'ManageGuild' permission check - Update error messages to reflect correct permission name - Update README to document correct permission requirement Fixes CodeRabbit feedback - Discord.js v14 does not have ManageEvents permission
- Remove quick-event parameter and parseQuickEvent function - Simplify parseDateTime to only accept ISO format (YYYY-MM-DD HH:MM) - Remove custom date parsing for 'tomorrow', 'next friday', etc. - Update modal label to specify ISO format - Update README to remove quick event documentation - Update README to clarify only ISO date format is supported Natural language processing is handled by @robojs/ai automatically, so custom date parsing is unnecessary. Simplifying to ISO format only makes the plugin more maintainable and predictable. Addresses CodeRabbit feedback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (5)
packages/plugin-events-manager/src/commands/event-create.js (4)
62-107: Consider removing custom NLP—delegate to @robojs/ai.The reviewer explicitly noted that natural language processing should be handled by
@robojs/airather than custom implementations. ThisparseQuickEventfunction only handles basic "tomorrow + time" patterns and doesn't support richer expressions like "next Friday" (which the README acknowledges on line 58).Consider refactoring to leverage
@robojs/ai's NLP capabilities for date/time parsing, or defer this feature until proper NLP integration is available.Based on learnings.
109-111: Strengthen event ID generation.
Math.random().toString(36)has weak collision resistance for production use. Consider usingcrypto.randomUUID()orcrypto.randomBytes()for more robust uniqueness guarantees.Example:
import { randomBytes } from 'crypto' function generateEventId() { return 'evt_' + randomBytes(8).toString('hex') + Date.now().toString(36) }Note: The same pattern is used in
event-remind.js(line 134-136) forgenerateReminderId()and should be updated consistently.
165-194: Extract duplicated embed builder to shared utility.This
createEventEmbedfunction is nearly identical to the implementation inmodal-handler.js(lines ~167-206). Extract to a shared module (e.g.,src/utils/embed-builder.js) to reduce duplication and ensure consistency.
196-218: Extract duplicated button builder to shared utility.The
createEventButtonsfunction is duplicated inmodal-handler.js(lines ~208-230). Extract to a shared utility alongsidecreateEventEmbedto maintain DRY principles.packages/plugin-events-manager/src/commands/event-remind.js (1)
134-136: Strengthen reminder ID generation.Same issue as in
event-create.js:Math.random()provides weak collision resistance. Usecrypto.randomUUID()orcrypto.randomBytes()for production-grade uniqueness.Example:
import { randomBytes } from 'crypto' function generateReminderId() { return 'rem_' + randomBytes(6).toString('hex') }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/plugin-events-manager/README.md(1 hunks)packages/plugin-events-manager/src/commands/event-create.js(1 hunks)packages/plugin-events-manager/src/commands/event-remind.js(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
packages/{@robojs/*,plugin-*}/**
📄 CodeRabbit inference engine (AGENTS.md)
House plugin packages within packages/@robojs/* or packages/plugin-*
Files:
packages/plugin-events-manager/src/commands/event-create.jspackages/plugin-events-manager/src/commands/event-remind.jspackages/plugin-events-manager/README.md
packages/{@robojs/*,plugin-*}/README.md
📄 CodeRabbit inference engine (AGENTS.md)
Each plugin package should include a README with usage instructions
Files:
packages/plugin-events-manager/README.md
🧬 Code graph analysis (2)
packages/plugin-events-manager/src/commands/event-create.js (3)
packages/plugin-events-manager/src/events/interactionCreate/button-handler.js (6)
interaction(5-15)embed(50-50)embed(162-167)embed(205-208)buttons(52-52)eventId(78-78)packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js (18)
interaction(5-11)eventData(40-56)saved(65-65)embed(73-73)embed(168-192)buttons(74-74)title(15-15)description(16-16)timeMatch(136-136)hour(138-138)minute(139-139)ampm(140-140)dateTimeInput(17-17)maxAttendeesInput(19-19)rsvpYes(209-212)rsvpMaybe(214-217)rsvpNo(219-222)viewAttendees(224-227)packages/plugin-events-manager/src/core/storage.js (2)
saveEvent(8-29)eventId(10-10)
packages/plugin-events-manager/src/commands/event-remind.js (1)
packages/plugin-events-manager/src/core/storage.js (8)
events(56-56)events(241-241)searchEvents(239-253)event(59-59)event(98-98)event(137-137)reminder(203-203)saveReminder(152-173)
🪛 ESLint
packages/plugin-events-manager/src/commands/event-remind.js
[error] 200-200: 'client' is defined but never used.
(@typescript-eslint/no-unused-vars)
🪛 LanguageTool
packages/plugin-events-manager/README.md
[style] ~110-~110: It’s more common nowadays to write this noun as one word.
Context: ...ce - 👥 View Attendees - See actual user names and attendance counts ### Setting Remi...
(RECOMMENDED_COMPOUNDS)
🪛 markdownlint-cli2 (0.18.1)
packages/plugin-events-manager/README.md
212-212: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🔇 Additional comments (3)
packages/plugin-events-manager/README.md (1)
1-212: README accurately reflects implemented features.The past review comment flagged that persistence claims were incorrect because the implementation used mock data. However, the author has since implemented Flashcore-backed storage (confirmed by
src/core/storage.jswithsaveEvent,updateRSVP,saveReminder, etc.), so the README's claims about persistence (lines 16-17, 107-108, 118, 157-162) and the completed roadmap items (lines 187-190) are now accurate.The README also honestly discloses limitations (line 58: "Advanced date parsing like 'Next Friday' is not fully implemented yet"), which aligns with the actual implementation.
packages/plugin-events-manager/src/commands/event-create.js (1)
17-25: Permission check correctly implemented.The permission check now properly uses
ManageGuildinstead of the non-existentManageEventspermission flag. This addresses the previous review feedback.packages/plugin-events-manager/src/commands/event-remind.js (1)
36-44: Permission check correctly implemented.The permission check now uses
ManageGuildinstead of the invalidManageEventspermission, matching Discord.js v14's valid permission flags.
- Create shared utils.js module for ID generation utilities
- Replace Math.random() with crypto.randomBytes() for stronger uniqueness
- Consolidate duplicate generateEventId() implementations
- Consolidate duplicate generateReminderId() implementations
- Use consistent format: evt_{16_hex_chars}_{timestamp_base36}
- Eliminates weak collision resistance of Math.random()
Addresses CodeRabbit feedback on ID generation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (1)
packages/plugin-events-manager/README.md (1)
112-112: Consider using "usernames" as a single word.Modern usage typically writes this as one word. This is a minor style suggestion.
Apply this diff:
-- **👥 View Attendees** - See actual user names and attendance counts +- **👥 View Attendees** - See actual usernames and attendance counts
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/plugin-events-manager/README.md(1 hunks)packages/plugin-events-manager/src/commands/event-create.js(1 hunks)packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js
🧰 Additional context used
📓 Path-based instructions (2)
packages/{@robojs/*,plugin-*}/**
📄 CodeRabbit inference engine (AGENTS.md)
House plugin packages within packages/@robojs/* or packages/plugin-*
Files:
packages/plugin-events-manager/src/commands/event-create.jspackages/plugin-events-manager/README.md
packages/{@robojs/*,plugin-*}/README.md
📄 CodeRabbit inference engine (AGENTS.md)
Each plugin package should include a README with usage instructions
Files:
packages/plugin-events-manager/README.md
🧬 Code graph analysis (1)
packages/plugin-events-manager/src/commands/event-create.js (2)
packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js (10)
interaction(5-11)dateTimeInput(17-17)maxAttendeesInput(19-19)eventData(40-56)embed(73-73)embed(118-142)rsvpYes(159-162)rsvpMaybe(164-167)rsvpNo(169-172)viewAttendees(174-177)packages/plugin-events-manager/src/events/interactionCreate/button-handler.js (5)
interaction(5-15)embed(50-50)embed(162-167)embed(205-208)eventId(78-78)
🪛 ESLint
packages/plugin-events-manager/src/commands/event-create.js
[error] 3-3: 'saveEvent' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 76-76: 'createEventEmbed' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 107-107: 'createEventButtons' is defined but never used.
(@typescript-eslint/no-unused-vars)
🪛 LanguageTool
packages/plugin-events-manager/README.md
[style] ~112-~112: It’s more common nowadays to write this noun as one word.
Context: ...ce - 👥 View Attendees - See actual user names and attendance counts ### Setting Remi...
(RECOMMENDED_COMPOUNDS)
🪛 markdownlint-cli2 (0.18.1)
packages/plugin-events-manager/README.md
213-213: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🔇 Additional comments (4)
packages/plugin-events-manager/src/commands/event-create.js (3)
12-17: Permission check correctly uses ManageGuild.The permission check now uses the valid
'ManageGuild'flag as required by Discord.js v14. This addresses the previous issue with the non-existent'ManageEvents'permission.
24-74: Modal creation is well-structured and properly integrated.The modal setup is correct:
- Appropriate input fields with validation (required, maxLength)
- Clear labels and placeholders
- Modal ID and field customIds match the handler in
modal-handler.js
1-21: Command structure follows Robo.js conventions correctly.The command configuration, exports, logging, and interaction flow are properly implemented according to Robo.js plugin patterns.
packages/plugin-events-manager/README.md (1)
16-17: Persistence is fully implemented as documented—no action required.Verification confirms all three features use Flashcore for persistence:
- Events:
saveEvent()persists event data to Flashcore with guild-scoped keys- RSVPs:
updateRSVP()modifies RSVP data within events and persists viasaveEvent()- Reminders:
saveReminder()persists reminder data to Flashcore with guild-scoped keysAll functions properly implement guild-namespaced storage (e.g.,
event:${eventId},reminder:${reminderId}) and data persists across bot restarts as documented.
…on creation - Move createEventEmbed() to shared utils.js module - Move createEventButtons() to shared utils.js module - Remove duplicate implementations from event-create.js - Remove duplicate implementations from modal-handler.js - Unified embed includes 'Starting Soon' indicator for events within 24 hours - Reduced code duplication by ~80 lines Addresses CodeRabbit feedback on duplicate code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (1)
packages/plugin-events-manager/src/commands/event-remind.js (1)
198-200: Critical:processRemindersstub renders reminder feature non-functional.This function remains unimplemented despite being flagged in previous reviews. Reminders are saved to Flashcore but never actually sent because there's no logic to:
- Check for due reminders (where
reminderTime <= Date.now())- Send them via
sendEventReminder- Delete them after sending
- Schedule periodic execution of this check
The unused
clientparameter (flagged by ESLint) confirms this is still a stub.To make reminders functional, implement the processing logic:
async processReminders(client) { - logger.info('Processing event reminders...') + try { + logger.info('Processing event reminders...') + const now = Date.now() + + // Get all guilds and check their reminders + for (const guild of client.guilds.cache.values()) { + const reminders = await getAllReminders(guild.id) + + for (const reminder of reminders) { + // Check if reminder is due + if (reminder.reminderTime <= now) { + // Get the event + const event = await getEvent(guild.id, reminder.eventId) + if (event) { + // Send the reminder + await this.sendEventReminder(client, reminder, event) + } + // Delete the sent reminder + await deleteReminder(guild.id, reminder.id) + logger.info(`Processed and deleted reminder ${reminder.id}`) + } + } + } + } catch (error) { + logger.error('Error processing reminders:', error) + } }Then add a scheduled task. Create
packages/plugin-events-manager/src/events/_start.js:import { reminderUtils } from '../commands/event-remind.js' import { logger } from 'robo.js' export default async (client) => { // Check for due reminders every minute setInterval(async () => { await reminderUtils.processReminders(client) }, 60 * 1000) logger.info('Reminder processor started') }Note: You'll also need to export
getAllReminders,getEvent, anddeleteReminderfromstorage.jsif they're not already available.Based on learnings (reviewer Pkmmte flagged this as non-functional, requiring Flashcore persistence and scheduled task implementation).
🧹 Nitpick comments (3)
packages/plugin-events-manager/src/core/utils.js (2)
3-10: Documentation mismatch: ID format description is inconsistent with implementation.The JSDoc comment on line 5 describes the format as
evt_{random_hex}_{timestamp}, suggesting an underscore between the random hex and timestamp portions. However, the implementation on line 9 directly concatenates them without a separator, producing IDs likeevt_a1b2c3d4e5f6g7h81b3f4a9.Either update the comment to match the actual format:
/** * Generate a unique event ID with strong collision resistance - * Format: evt_{random_hex}_{timestamp} + * Format: evt_{random_hex}{timestamp} * @returns {string} Unique event ID */Or add the separator to the implementation for better readability:
export function generateEventId() { - return 'evt_' + randomBytes(8).toString('hex') + Date.now().toString(36) + return 'evt_' + randomBytes(8).toString('hex') + '_' + Date.now().toString(36) }
12-19: Documentation mismatch: ID format description is inconsistent with implementation.Same issue as
generateEventId- the JSDoc statesrem_{random_hex}_{timestamp}but the implementation producesrem_{random_hex}{timestamp}without the separator.Apply the same fix as suggested for
generateEventIdabove, either updating the comment or adding the separator to the code.packages/plugin-events-manager/src/commands/event-remind.js (1)
52-61: Inform user when multiple events match the query.When
searchEventsreturns multiple results, the code silently selects the first match without informing the user. This could lead to confusion if the wrong event is selected.Consider adding feedback when multiple events match:
const events = await searchEvents(interaction.guild.id, eventQuery) if (events.length === 0) { return interaction.reply({ content: `❌ Could not find an event matching "${eventQuery}". Use \`/event-list\` to see available events.`, ephemeral: true }) } + if (events.length > 1) { + await interaction.reply({ + content: `ℹ️ Found ${events.length} matching events. Using: **${events[0].title}**`, + ephemeral: true + }) + } + const event = events[0]
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/plugin-events-manager/src/commands/event-remind.js(1 hunks)packages/plugin-events-manager/src/core/utils.js(1 hunks)packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js
🧰 Additional context used
📓 Path-based instructions (1)
packages/{@robojs/*,plugin-*}/**
📄 CodeRabbit inference engine (AGENTS.md)
House plugin packages within packages/@robojs/* or packages/plugin-*
Files:
packages/plugin-events-manager/src/core/utils.jspackages/plugin-events-manager/src/commands/event-remind.js
🧬 Code graph analysis (1)
packages/plugin-events-manager/src/commands/event-remind.js (3)
packages/plugin-events-manager/src/commands/event-create.js (1)
embed(77-102)packages/plugin-events-manager/src/core/storage.js (8)
events(56-56)events(241-241)searchEvents(239-253)event(59-59)event(98-98)event(137-137)reminder(203-203)saveReminder(152-173)packages/plugin-events-manager/src/core/utils.js (1)
generateReminderId(17-19)
🪛 ESLint
packages/plugin-events-manager/src/commands/event-remind.js
[error] 198-198: 'client' is defined but never used.
(@typescript-eslint/no-unused-vars)
🔇 Additional comments (2)
packages/plugin-events-manager/src/commands/event-remind.js (2)
6-35: LGTM!Command configuration is well-structured with appropriate options and validation choices.
108-133: LGTM!Time calculation logic is correct for all reminder offsets with appropriate fallback handling.
- Create reminders.js module with full reminder processing logic - Add _start.js event to initialize reminder checking every minute - Process reminders across all guilds automatically - Send reminder embeds to specified channels when due - Delete reminders after they're sent - Handle missing channels and events gracefully - Add proper error handling and logging - Remove old stub reminderUtils from event-remind.js Reminders now fully functional - checks every 60 seconds for due reminders and sends them to the configured channel, then deletes them. Addresses CodeRabbit feedback on non-functional reminders
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
packages/plugin-events-manager/src/commands/event-create.js (1)
3-3: Remove unused import.The
saveEventimport is never used in this file. Event persistence occurs inmodal-handler.jsafter the modal is submitted.Apply this diff:
import { createCommandConfig, logger } from 'robo.js' import { ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder } from 'discord.js' -import { saveEvent } from '../core/storage.js'
🧹 Nitpick comments (1)
packages/plugin-events-manager/src/core/utils.js (1)
28-70: Well-designed embed with minor refactor opportunity.The embed provides comprehensive event information with proper Discord timestamp formatting and a helpful "Starting Soon" indicator. The creator name fallback chain handles various scenarios gracefully.
Optional refactor: Consider extracting the repeated timestamp calculation to reduce duplication:
export function createEventEmbed(eventData, creatorName = null) { const creator = creatorName || eventData.creatorName || 'Unknown' + const eventTimestamp = Math.floor(eventData.dateTime.getTime() / 1000) const embed = new EmbedBuilder() .setTitle(`📅 ${eventData.title}`) .setDescription(eventData.description) .setColor(0x5865F2) .addFields( { name: '⏰ Date & Time', - value: `<t:${Math.floor(eventData.dateTime.getTime() / 1000)}:F>`, + value: `<t:${eventTimestamp}:F>`, inline: true }, // ... other fields ... ) if (hoursDiff <= 24 && hoursDiff > 0) { embed.addFields({ name: '⚡ Starting Soon', - value: `<t:${Math.floor(eventData.dateTime.getTime() / 1000)}:R>`, + value: `<t:${eventTimestamp}:R>`, inline: false }) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/plugin-events-manager/src/commands/event-create.js(1 hunks)packages/plugin-events-manager/src/core/utils.js(1 hunks)packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
packages/{@robojs/*,plugin-*}/**
📄 CodeRabbit inference engine (AGENTS.md)
House plugin packages within packages/@robojs/* or packages/plugin-*
Files:
packages/plugin-events-manager/src/core/utils.jspackages/plugin-events-manager/src/events/interactionCreate/modal-handler.jspackages/plugin-events-manager/src/commands/event-create.js
🧬 Code graph analysis (3)
packages/plugin-events-manager/src/core/utils.js (2)
packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js (2)
eventData(40-56)embed(73-73)packages/plugin-events-manager/src/commands/event-remind.js (3)
embed(92-92)embed(137-171)embed(204-228)
packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js (3)
packages/plugin-events-manager/src/commands/event-create.js (3)
interaction(9-21)dateTimeInput(43-47)maxAttendeesInput(57-62)packages/plugin-events-manager/src/core/utils.js (4)
generateEventId(9-11)embed(31-55)createEventEmbed(28-70)createEventButtons(77-99)packages/plugin-events-manager/src/core/storage.js (1)
saveEvent(8-29)
packages/plugin-events-manager/src/commands/event-create.js (1)
packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js (3)
interaction(5-11)dateTimeInput(17-17)maxAttendeesInput(19-19)
🪛 ESLint
packages/plugin-events-manager/src/commands/event-create.js
[error] 3-3: 'saveEvent' is defined but never used.
(@typescript-eslint/no-unused-vars)
🔇 Additional comments (6)
packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js (2)
5-11: LGTM!The handler correctly checks for modal submissions and delegates to the appropriate handler function.
13-91: Excellent error handling and validation flow.The function implements comprehensive validation with clear error messages, proper persistence using Flashcore, and appropriate ephemeral replies for errors. The eventData structure is well-formed and includes all necessary fields for event tracking.
packages/plugin-events-manager/src/commands/event-create.js (2)
9-21: LGTM!Permission check correctly uses
ManageGuild(the invalidManageEventspermission from previous reviews has been fixed), and the modal presentation flow is properly implemented.
24-74: Well-structured modal with clear user guidance.The modal inputs are properly configured with appropriate labels, placeholders, and validation. The datetime label clearly documents the expected format (
YYYY-MM-DD HH:MM), which aligns with the strict parser inmodal-handler.js.packages/plugin-events-manager/src/core/utils.js (2)
9-20: LGTM!Both ID generation functions use cryptographically strong randomness combined with timestamps, providing excellent collision resistance. The consistent implementation pattern between
generateEventIdandgenerateReminderIdis well done.
77-99: LGTM!Button implementation is clean with semantically appropriate styles, clear labels, and consistent customId encoding. The eventId is properly embedded in each button's customId for interaction handling.
packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js
Show resolved
Hide resolved
…handler - Check if regex match returns null before destructuring - Prevents potential runtime error if customId format is unexpected - Provide clear error message for invalid button interactions - Remove redundant eventId null check Addresses CodeRabbit feedback on potential null reference error
- Remove Previous/Next pagination buttons from event list - These buttons had no handlers and wouldn't work when clicked - Simplify to only show Refresh button - Update footer message to reflect lack of pagination - Pagination can be added in future with proper state management Addresses CodeRabbit feedback on non-functional navigation buttons
- Fetch event first before updating RSVP - Check if event is at capacity BEFORE updating - Prevents race condition where user is added then immediately removed - More efficient - only updates database once instead of twice - Clearer logic flow and better user experience Previously: Update → Check capacity → Undo if over capacity Now: Check capacity → Update (or add to maybe list) Addresses CodeRabbit feedback on capacity check timing
- Delete ready.js with personal bot activity message - Plugin users should set their own bot activity in their project - Public plugins should not include personal attribution by default - Users maintain full control over their bot's status Addresses CodeRabbit feedback on inappropriate personal branding
- Remove unused saveEvent import from event-create.js - Event saving happens in modal-handler.js after modal submission - Improves code cleanliness Addresses CodeRabbit feedback on unused import
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
♻️ Duplicate comments (2)
packages/plugin-events-manager/src/commands/event-remind.js (2)
154-154: Handle null/undefined location gracefully.Line 154 uses
event.locationdirectly without a fallback. If location is null or undefined, the embed will display "null" or "undefined" instead of a user-friendly message.Apply this fix to match the pattern used in
reminders.js:{ name: '📍 Location', - value: event.location, + value: event.location || 'Not specified', inline: true },
72-80: Critical: Store reminder time as timestamp to avoid serialization errors.Line 76 stores
reminderTimeas a Date object, but Flashcore serializes data to JSON. When retrieved later,reminderTimewill be a string or number, causing runtime errors when line 159 calls.getTime()on it.Store as a numeric timestamp:
const reminder = { id: generateReminderId(), eventId: event.id, eventTitle: event.title, - reminderTime: reminderDateTime, + reminderTime: reminderDateTime.getTime(), channelId: targetChannel.id, createdBy: interaction.user.id, guildId: interaction.guild.id }Then update line 159 in
createReminderConfirmationEmbed:{ name: '🔔 Reminder Time', - value: `<t:${Math.floor(reminder.reminderTime.getTime() / 1000)}:F>`, + value: `<t:${Math.floor(reminder.reminderTime / 1000)}:F>`, inline: false },
🧹 Nitpick comments (9)
packages/plugin-events-manager/src/commands/event-list.js (2)
113-118: Consider avoiding array mutation.The
sort()method mutates the array in place. While this works here sinceeventsis already a filtered copy, it's generally better practice to avoid mutation for predictability.Apply this diff:
-const sortedEvents = events.sort((a, b) => { +const sortedEvents = [...events].sort((a, b) => { if (filter === 'past') { return b.dateTime - a.dateTime } return a.dateTime - b.dateTime })
143-147: Clarify refresh instructions in footer.The footer text says "Run the command again to refresh", but a refresh button is provided below. This creates inconsistent messaging about how users should refresh the list.
Apply this diff to align the message with the available refresh button:
if (sortedEvents.length > maxEvents) { embed.setFooter({ - text: `Showing ${maxEvents} of ${sortedEvents.length} events. Run the command again to refresh.` + text: `Showing ${maxEvents} of ${sortedEvents.length} events. Use the refresh button below to update.` }) }packages/plugin-events-manager/src/events/interactionCreate/button-handler.js (4)
2-2: Remove unused Discord.js imports.The imports
ActionRowBuilder,ButtonBuilder, andButtonStyleare not used anywhere in this file.Apply this diff to clean up the imports:
-import { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } from 'discord.js' +import { EmbedBuilder } from 'discord.js'
121-146: Optimize user fetching with parallel requests.The current implementation fetches user data sequentially, which could cause noticeable delays for events with many attendees (e.g., 30 sequential API calls for 30 attendees). Consider using
Promise.all()to fetch users in parallel.Apply this diff to parallelize the user fetches:
- for (const userId of event.attendees.going || []) { - try { - const user = await interaction.client.users.fetch(userId) - attendeeDetails.going.push({ id: userId, name: user.displayName || user.username }) - } catch { - attendeeDetails.going.push({ id: userId, name: 'Unknown User' }) - } - } - - for (const userId of event.attendees.maybe || []) { - try { - const user = await interaction.client.users.fetch(userId) - attendeeDetails.maybe.push({ id: userId, name: user.displayName || user.username }) - } catch { - attendeeDetails.maybe.push({ id: userId, name: 'Unknown User' }) - } - } - - for (const userId of event.attendees.notGoing || []) { - try { - const user = await interaction.client.users.fetch(userId) - attendeeDetails.notGoing.push({ id: userId, name: user.displayName || user.username }) - } catch { - attendeeDetails.notGoing.push({ id: userId, name: 'Unknown User' }) - } - } + const fetchUser = async (userId) => { + try { + const user = await interaction.client.users.fetch(userId) + return { id: userId, name: user.displayName || user.username } + } catch { + return { id: userId, name: 'Unknown User' } + } + } + + attendeeDetails.going = await Promise.all( + (event.attendees.going || []).map(fetchUser) + ) + + attendeeDetails.maybe = await Promise.all( + (event.attendees.maybe || []).map(fetchUser) + ) + + attendeeDetails.notGoing = await Promise.all( + (event.attendees.notGoing || []).map(fetchUser) + )
180-208: Remove unusedrsvpTypeparameter.The
rsvpTypeparameter is defined but never used in the function body.Apply this diff:
-function updateEventEmbedWithRSVP(originalEmbed, eventData, rsvpType) { +function updateEventEmbedWithRSVP(originalEmbed, eventData) { const embed = new EmbedBuilder() .setTitle(originalEmbed.title)Also update the call site on line 70:
- const updatedEmbed = updateEventEmbedWithRSVP(embed, updatedEvent, rsvpType) + const updatedEmbed = updateEventEmbedWithRSVP(embed, updatedEvent)
253-259: Inconsistent attendee display for "Can't Attend" list.The "Going" and "Maybe" lists display individual attendee names (lines 229-239, 241-251), but the "Can't Attend" list only shows a count without names. This creates an inconsistent user experience.
Consider displaying names consistently across all three lists for better UX:
if (attendees.notGoing.length > 0) { + const notGoingList = attendees.notGoing + .map((attendee, index) => `${index + 1}. ${attendee.name}`) + .join('\n') + embed.addFields({ name: `❌ Can't Attend (${attendees.notGoing.length})`, - value: `${attendees.notGoing.length} member${attendees.notGoing.length === 1 ? '' : 's'} can't attend`, + value: notGoingList.length > 1024 ? `${notGoingList.substring(0, 1020)}...` : notGoingList, inline: false }) }Alternatively, if hiding "Can't Attend" names is intentional (e.g., for privacy), consider documenting this decision in a code comment.
packages/plugin-events-manager/src/events/_start.js (1)
9-10: Minor: run initial pass before scheduling.Running the first pass before scheduling ensures no gap if init is delayed. Covered by the diff above.
Also applies to: 20-26
packages/plugin-events-manager/src/core/reminders.js (2)
58-63: Channel may be uncached; add fetch + text/permission checks.On cold start,
guild.channels.cache.getcan miss. Also guard non-text channels and missing perms to avoid errors.- const channel = guild.channels.cache.get(reminder.channelId) - if (!channel) { - logger.warn(`Channel ${reminder.channelId} not found for reminder ${reminder.id}`) - return - } + let channel = guild.channels.cache.get(reminder.channelId) + if (!channel) { + channel = await guild.channels.fetch(reminder.channelId).catch(() => null) + } + if (!channel || typeof channel.isTextBased !== 'function' || !channel.isTextBased()) { + logger.warn(`Channel ${reminder.channelId} not text-based or not found for reminder ${reminder.id}`) + return + } + const me = guild.members.me ?? await guild.members.fetch(client.user.id).catch(() => null) + const perms = me ? channel.permissionsFor(me) : null + if (!perms?.has(['ViewChannel', 'SendMessages'])) { + logger.warn(`Missing permissions to send in #${reminder.channelId} for reminder ${reminder.id}`) + return + }
22-51: Optional: reuse shared embed builder to avoid duplication.If
core/utils.jsalready builds event embeds, consider reusing and only adjust title/color. Reduces divergence.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
packages/plugin-events-manager/src/commands/event-list.js(1 hunks)packages/plugin-events-manager/src/commands/event-remind.js(1 hunks)packages/plugin-events-manager/src/core/reminders.js(1 hunks)packages/plugin-events-manager/src/events/_start.js(1 hunks)packages/plugin-events-manager/src/events/interactionCreate/button-handler.js(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
packages/{@robojs/*,plugin-*}/**
📄 CodeRabbit inference engine (AGENTS.md)
House plugin packages within packages/@robojs/* or packages/plugin-*
Files:
packages/plugin-events-manager/src/events/_start.jspackages/plugin-events-manager/src/commands/event-list.jspackages/plugin-events-manager/src/events/interactionCreate/button-handler.jspackages/plugin-events-manager/src/commands/event-remind.jspackages/plugin-events-manager/src/core/reminders.js
🧬 Code graph analysis (5)
packages/plugin-events-manager/src/events/_start.js (1)
packages/plugin-events-manager/src/core/reminders.js (1)
processReminders(9-20)
packages/plugin-events-manager/src/commands/event-list.js (2)
packages/plugin-events-manager/src/events/interactionCreate/button-handler.js (3)
interaction(5-15)event(31-31)event(106-106)packages/plugin-events-manager/src/core/storage.js (6)
events(56-56)events(241-241)getAllEvents(53-73)event(59-59)event(98-98)event(137-137)
packages/plugin-events-manager/src/events/interactionCreate/button-handler.js (3)
packages/plugin-events-manager/src/commands/event-list.js (4)
interaction(28-66)embed(51-51)embed(98-100)buttons(52-52)packages/plugin-events-manager/src/events/interactionCreate/modal-handler.js (4)
interaction(5-11)embed(73-73)buttons(74-74)eventData(40-56)packages/plugin-events-manager/src/core/storage.js (6)
eventId(10-10)event(59-59)event(98-98)event(137-137)getEvent(31-40)updateRSVP(96-133)
packages/plugin-events-manager/src/commands/event-remind.js (3)
packages/plugin-events-manager/src/core/reminders.js (4)
reminderTime(32-34)event(65-65)embed(88-112)channel(58-58)packages/plugin-events-manager/src/core/storage.js (8)
events(56-56)events(241-241)searchEvents(239-253)event(59-59)event(98-98)event(137-137)reminder(203-203)saveReminder(152-173)packages/plugin-events-manager/src/core/utils.js (2)
generateReminderId(18-20)embed(31-55)
packages/plugin-events-manager/src/core/reminders.js (3)
packages/plugin-events-manager/src/events/_start.js (1)
client(8-26)packages/plugin-events-manager/src/core/storage.js (3)
getAllReminders(197-217)deleteReminder(219-237)getEvent(31-40)packages/plugin-events-manager/src/commands/event-remind.js (5)
reminder(72-80)reminderTime(48-48)event(61-61)embed(92-92)embed(137-171)
🪛 ESLint
packages/plugin-events-manager/src/events/interactionCreate/button-handler.js
[error] 2-2: 'ActionRowBuilder' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 2-2: 'ButtonBuilder' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 2-2: 'ButtonStyle' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 180-180: 'rsvpType' is defined but never used.
(@typescript-eslint/no-unused-vars)
🔇 Additional comments (11)
packages/plugin-events-manager/src/commands/event-list.js (4)
1-26: LGTM! Command configuration is well-structured.The imports and command configuration follow robo.js conventions correctly, with appropriate option types and clear descriptions.
69-81: LGTM! Filter logic is correct.The function correctly filters events based on their date-time relative to the current time.
83-95: LGTM! User-friendly messaging.The function provides contextual messages based on the filter and user parameters, improving user experience.
152-159: LGTM! Navigation button correctly implemented.The refresh button is properly configured and has a corresponding handler in
button-handler.js(confirmed in relevant code snippets).packages/plugin-events-manager/src/events/interactionCreate/button-handler.js (1)
17-93: LGTM! RSVP capacity handling is now correct.The capacity check logic correctly:
- Filters out the current user before counting (line 41) to handle re-clicks
- Checks capacity before updating RSVP (lines 40-58)
- Falls back to 'maybe' status when at capacity with clear user notification
Past review concerns about race conditions and check-then-act issues have been properly addressed.
packages/plugin-events-manager/src/commands/event-remind.js (6)
1-4: LGTM!Imports are clean and appropriate for the command's functionality.
6-35: LGTM!Command configuration is well-structured with clear descriptions and appropriate option types. The reminder time choices provide good flexibility.
40-45: LGTM!Permission check correctly uses
ManageGuild, which is a valid Discord.js v14 permission.
47-61: LGTM!Event search and validation logic is clear, with helpful error messages guiding users to
/event-listif no match is found.
108-133: LGTM with dependency on date handling fix.The offset calculation logic is correct and handles all the specified reminder time options appropriately. The function will work correctly once the date deserialization handling from line 63 is applied.
98-104: LGTM!Error handling is appropriate with proper logging and user-friendly error messages.
packages/plugin-events-manager/src/events/interactionCreate/button-handler.js
Outdated
Show resolved
Hide resolved
packages/plugin-events-manager/src/events/interactionCreate/button-handler.js
Outdated
Show resolved
Hide resolved
…ization - Store event dateTime as timestamp (number) instead of Date object - Store reminder reminderTime as timestamp (number) instead of Date object - Update utils.js to handle both timestamp and Date object formats - Prevents JSON serialization issues when data is retrieved from Flashcore - Ensures consistent behavior across restarts Date objects don't serialize properly to JSON. When retrieved from storage, they become strings/numbers. Storing as timestamps from the start avoids getTime() errors and ensures type consistency. Addresses CodeRabbit feedback on Date serialization issue
…r embed - Add fallback for null/undefined location in createReminderConfirmationEmbed - Prevents displaying 'null' or 'undefined' to users - Shows 'Not specified' instead, consistent with other embeds Addresses CodeRabbit feedback on graceful null handling
Summary
This PR adds a comprehensive Discord Events Manager plugin (
@robojs/events-manager) to the Robo.js ecosystem. The plugin enables Discord communities to organize events with RSVP tracking, automated reminders, and seamless Discord integration.✨ Features
🎮 Commands Added
/event-create- Create detailed events with modal interface or quick natural language/event-list- Browse and filter community events/event-remind- Schedule automated event reminders🛠️ Technical Details
🎯 Usage Examples
Creating a Quick Event
/event-create quick-event:"Gaming Night - Tomorrow 8PM - Fun multiplayer games!"Browsing Events
Setting Reminders
📋 Completed Roadmap
All major features have been implemented:
• ✅ Event creation and management
• ✅ RSVP system
• ✅ Automated reminders
• ✅ Event discovery and filtering
• ✅ Interactive Discord embeds
• ✅ Natural language parsing
• ✅ Permission-based access control
• ✅ TypeScript support
🤝 Contributing to Hacktoberfest 2025
This plugin was created as part of Hacktoberfest 2025 to contribute a valuable tool to the Robo.js ecosystem.
Made with ❤️ by DevArqf for the Discord community and Hacktoberfest 2025
Summary by CodeRabbit
Release Notes