feat: improvements events#111
Conversation
…ager into EventResource
…d talk management
WalkthroughAdds Filament relation managers for event attendees and talks, restructures event and talk form/table layouts, introduces a User<->Event many-to-many relation, updates seeding to create talks for events, and adds comprehensive tests for relation manager behavior and talk creation. Changes
Sequence Diagram(s)sequenceDiagram
actor Admin
participant EditEvent as EditEvent Page
participant TalksRM as TalksRelationManager
participant AttendeesRM as AttendeesRelationManager
participant EventModel as Event Model
participant DB as Database
Admin->>EditEvent: open edit page
EditEvent->>TalksRM: render talks relation
EditEvent->>AttendeesRM: render attendees relation
TalksRM->>EventModel: query related talks
EventModel->>DB: SELECT talks
DB-->>EventModel: return talks
EventModel-->>TalksRM: show talks
AttendeesRM->>EventModel: query related attendees
EventModel->>DB: SELECT attendees (pivot)
DB-->>EventModel: return attendees
EventModel-->>AttendeesRM: show attendees
Admin->>TalksRM: CreateAction (fill & submit)
TalksRM->>EventModel: create talk (associate event)
EventModel->>DB: INSERT talk
Admin->>AttendeesRM: DetachAction on attendee
AttendeesRM->>EventModel: call leave(attendeeId)
EventModel->>DB: update/delete pivot row
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
…and updating detach logic
…-api into feat/improvements-events
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (6)
app-modules/user/src/Filament/Admin/Resources/Users/Tables/UsersTable.php (1)
20-23: Email column addition; consider making it searchable/sortableExposing
->searchable()and/or->sortable()to this column for better UX.database/seeders/BaseSeeder.php (1)
50-65: Seeded events & talks look coherent; consider type-hinting and tenant alignmentThe seeding flow for events plus per‑event talks is clear and matches the new relations.
To tighten things up:
- Type‑hint the
$eventinafterCreatingfor better static analysis and safety:- EventModel::factory()->count(5) - ->withStatus() - ->afterCreating(function ($event): void { + EventModel::factory()->count(5) + ->withStatus() + ->afterCreating(function (EventModel $event): void { Talk::factory()->count(5)->create([ 'event_id' => $event->id, ]); })
- Depending on how
Talk’s factory handles tenancy, you may also want to ensure talks share the same tenant as their event (e.g. via->recycle($event->tenant)or equivalent) so multi‑tenant data stays consistent.app-modules/events/src/Filament/Admin/Resources/Talks/Tables/TalksTable.php (1)
19-35: Defensively handle missing user on title descriptionThe dynamic description on
titleis a nice touch, butfn ($record) => $record->user->namewill throw if a talk ever lacks an associated user.Consider making this null‑safe (and optionally type‑hinting the record) to avoid runtime errors:
+use He4rt\Events\Models\Talk; @@ - TextColumn::make('title') - ->description(fn ($record) => $record->user->name) + TextColumn::make('title') + ->description(fn (Talk $record) => $record->user?->name ?? '-')The new
descriptionlimit andstarts_at/ends_atdatetime columns look good as-is.app-modules/events/tests/Feature/Filament/Admin/Event/CreateEventTest.php (1)
102-113: max_attendees validation now asserts on rule key; consider aligning othersSwitching the
max_attendeesdataset to[-1, 'min']is good—it avoids coupling the test to the exact validation message.For consistency and less brittle tests, you may also want to update the other validation datasets (e.g.
title,location) to assert on rule keys ('min','max') rather than including parameters or full messages.app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/TalksRelationManager.php (1)
1-25: Reuse TalksTable configuration in the relation manager for consistencyThe relation manager correctly wires the
talksrelationship and adds aCreateheader action. To keep the talks table under an Event consistent with the standalone Talk resource, consider reusing the existingTalksTableconfiguration:use Filament\Actions\CreateAction; use Filament\Resources\RelationManagers\RelationManager; use Filament\Tables\Table; use He4rt\Events\Filament\Admin\Resources\Talks\TalkResource; +use He4rt\Events\Filament\Admin\Resources\Talks\Tables\TalksTable as TalksTableSchema; @@ public function table(Table $table): Table { - return $table - ->headerActions([ - CreateAction::make(), - ]); + return TalksTableSchema::configure($table) + ->headerActions([ + CreateAction::make(), + ]); }This way, columns/filters/badges stay in sync between the main Talk listing and the event relation.
app-modules/events/tests/Feature/Filament/Admin/Event/AttendeesRelationManagerTest.php (1)
74-98: Use theattend()method in test setup for consistency with production patterns.The counter management in the codebase is actually consistent:
attend()auto-increments andleave()auto-decrements. However, the test uses rawattach()(line 77) instead of the model'sattend()method, requiring manual counter increment (line 81). Since theDetachActionproperly invokesleave()which handles the decrement, the test works correctly—but it would be clearer and more aligned with production code patterns to useattend()for setup instead.Suggested change: Replace lines 77-81 with
$this->event->attend($attendee->getKey(), AttendingStatusEnum::Attending);to eliminate the manual counter management and reflect how the model's API is actually used in production.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
app-modules/events/src/AdminEventPanelPlugin.php(1 hunks)app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php(2 hunks)app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/AttendeesRelationManager.php(1 hunks)app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/TalksRelationManager.php(1 hunks)app-modules/events/src/Filament/Admin/Resources/Events/Schemas/EventForm.php(2 hunks)app-modules/events/src/Filament/Admin/Resources/Events/Tables/EventsTable.php(2 hunks)app-modules/events/src/Filament/Admin/Resources/Talks/Schemas/TalkForm.php(3 hunks)app-modules/events/src/Filament/Admin/Resources/Talks/Tables/TalksTable.php(1 hunks)app-modules/events/tests/Feature/Filament/Admin/Event/AttendeesRelationManagerTest.php(1 hunks)app-modules/events/tests/Feature/Filament/Admin/Event/CreateEventTest.php(2 hunks)app-modules/events/tests/Feature/Filament/Admin/Event/TalkRelationManagerTest.php(1 hunks)app-modules/user/src/Filament/Admin/Resources/Users/Tables/UsersTable.php(1 hunks)app-modules/user/src/Models/User.php(2 hunks)database/seeders/BaseSeeder.php(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
app-modules/user/src/Filament/Admin/Resources/Users/Tables/UsersTable.php (2)
app-modules/integrations/src/Discord/OAuth/DiscordOAuthUser.php (1)
make(13-24)app-modules/integrations/src/Twitch/OAuth/DTO/TwitchOAuthDTO.php (1)
make(13-26)
app-modules/events/tests/Feature/Filament/Admin/Event/AttendeesRelationManagerTest.php (3)
app-modules/events/src/Filament/Admin/Resources/Events/Pages/EditEvent.php (1)
EditEvent(11-21)app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/AttendeesRelationManager.php (1)
AttendeesRelationManager(15-41)app-modules/events/src/Models/EventModel.php (1)
attendees(67-79)
app-modules/events/src/Filament/Admin/Resources/Talks/Schemas/TalkForm.php (1)
app-modules/events/src/Filament/Shared/Schemas/StartEndFieldsSchema.php (2)
make(16-65)StartEndFieldsSchema(14-66)
database/seeders/BaseSeeder.php (2)
app-modules/events/database/factories/EventFactory.php (1)
withStatus(44-63)app-modules/events/src/Models/Talk.php (2)
tenant(54-57)event(46-49)
app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php (2)
app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/AttendeesRelationManager.php (1)
AttendeesRelationManager(15-41)app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/TalksRelationManager.php (1)
TalksRelationManager(12-25)
app-modules/user/src/Models/User.php (3)
app-modules/events/src/Models/Pivot/EventAttend.php (1)
EventAttend(10-24)app-modules/tenant/src/Models/Tenant.php (2)
Tenant(22-94)events(62-65)app-modules/sponsors/src/Models/Sponsor.php (1)
events(51-62)
app-modules/events/tests/Feature/Filament/Admin/Event/TalkRelationManagerTest.php (4)
app-modules/events/src/Filament/Admin/Resources/Events/Pages/EditEvent.php (1)
EditEvent(11-21)app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/TalksRelationManager.php (1)
TalksRelationManager(12-25)app-modules/events/src/Models/Talk.php (1)
event(46-49)app-modules/events/src/Models/EventModel.php (1)
talks(146-149)
app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/AttendeesRelationManager.php (1)
app-modules/user/src/Filament/Admin/Resources/Users/UserResource.php (1)
UserResource(21-56)
🔇 Additional comments (23)
app-modules/events/src/AdminEventPanelPlugin.php (1)
22-27: Whitespace-only change in plugin registrationThis is a formatting-only change to
register(), with no impact on resource registration or behavior.app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php (1)
15-16: Relation managers wiring for EventResource looks correctRegistering
TalksRelationManagerandAttendeesRelationManagerviagetRelations()cleanly exposes talks and participants on the Event resource and matches the underlying relationships.Also applies to: 42-48
app-modules/user/src/Models/User.php (1)
10-12: User–Event many-to-many relation is correctly modeledThe new
events()relation onUserlooks well-aligned with theevents_attendeespivot andEventAttendmodel (includingstatusand timestamps). This should work cleanly withAttendeesRelationManager’s inverse relationship.Also applies to: 19-19, 56-71
app-modules/events/src/Filament/Admin/Resources/Events/Schemas/EventForm.php (4)
26-51: LGTM!The "Informações Gerais" section is well-structured with appropriate validation and a good UX pattern for automatic slug generation from the title field.
53-76: LGTM!The layout grouping of location/capacity and status is logical and user-friendly. The validation on
max_attendees(numeric, minValue 1) is appropriate.
78-94: LGTM!The date/time section correctly validates that
end_atoccurs afterstart_at, preventing invalid event schedules.
96-103: LGTM!The content section with RichEditor is appropriately configured with validation constraints.
app-modules/events/tests/Feature/Filament/Admin/Event/AttendeesRelationManagerTest.php (4)
26-31: LGTM!Basic rendering test is correctly structured.
33-49: LGTM!The test appropriately verifies attendee listing functionality with proper assertions.
51-72: LGTM!Column visibility test comprehensively verifies all expected columns including the pivot status.
100-120: LGTM with verification note.This test follows the same manual counter management pattern as the attendees test. The same verification regarding counter consistency applies here.
app-modules/events/src/Filament/Admin/Resources/Talks/Schemas/TalkForm.php (3)
23-63: LGTM!The talk proposal section is well-organized with appropriate validation. The default status of
Pendingfor new talks is a sensible choice.
65-70: LGTM!Good use of
StartEndFieldsSchemafor code reuse and consistency across forms.
71-80: LGTM!The content section is appropriately structured with RichEditor for detailed descriptions.
app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/AttendeesRelationManager.php (2)
15-24: LGTM!The relation manager configuration is correctly set up with appropriate relationship naming and resource references.
25-40: leave() method is correctly implemented and properly handles counter decrements.Verification confirms the
leave()method in EventModel (lines 101-117) properly:
- Retrieves the attendee record by user ID
- Decrements
attendees_countfor Attending status- Decrements
waitlist_countfor Waitlist status- Detaches the user from the relationship
- Returns the appropriate boolean result
The DetachAction in the RelationManager correctly delegates to this method. No issues found.
app-modules/events/tests/Feature/Filament/Admin/Event/TalkRelationManagerTest.php (4)
27-59: LGTM!The basic tests for rendering, listing, and action existence are well-structured and provide good coverage.
61-94: LGTM!The talk creation test is comprehensive, covering all fields and verifying automatic association with the event. The expectation of
<p>tag wrapping (Line 89) correctly reflects Filament's RichEditor behavior.
96-120: LGTM!This test appropriately verifies the automatic association of talks with their parent event through the relation manager.
122-180: LGTM!The validation, status filtering, and event isolation tests provide excellent coverage. The event isolation test (lines 158-180) is particularly important for preventing data leakage across events.
app-modules/events/src/Filament/Admin/Resources/Events/Tables/EventsTable.php (3)
19-27: LGTM!The title limit of 20 characters improves table readability while maintaining searchability.
29-45: LGTM!The column improvements enhance the table's usability:
- IconColumn for active status provides better visual feedback
- The custom formatter for attendees_count showing "current/max" is user-friendly
- Adding talks_count provides valuable at-a-glance information
47-57: LGTM!The start/end time display formatting and bulk delete functionality are appropriate. The removal of recordActions suggests row-level editing is handled through other means (likely clicking the row).
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/TalksRelationManager.php (2)
21-29: Unused parameters in badge/icon helpers (harmless but flagged by PHPMD)
getBadge()andgetIcon()must keep the Filament signature, but$pageClass(and ingetIcon, also$ownerRecord) are intentionally unused. That’s fine functionally, though PHPMD will keep warning. If you want to silence it, you could either rename to something like$_pageClass/$_ownerRecordor explicitlyunset()them inside the method.
31-37: Relation table is header‑only – consider reusing TalksTable for columnsRight now the relation table config only defines a
CreateActioninheaderActions, so the talks relation manager will render without explicit columns. If you want this view to mirror the main talks listing, consider delegating to your shared table schema, e.g.TalksTable::configure($table)->headerActions([...]), to keep columns/layout consistent across contexts.app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/AttendeesRelationManager.php (1)
28-52: Attendees relation manager looks solid; unused params can be optionally cleaned upThe badge (
attendees()->count()), icon, columns (includingpivot.statusbadge), andDetachActioncalling$this->getOwnerRecord()->leave($record->getKey())all line up with the event–attendee relationship and look correct. As PHPMD notes,$pageClass(and ingetIcon, also$ownerRecord) are unused but required by Filament’s signature; if the warnings are noisy, you can adopt the same pattern as for talks (e.g., rename to$_pageClass/$_ownerRecordorunset()them) to make the intent explicit.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php(3 hunks)app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/AttendeesRelationManager.php(1 hunks)app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/TalksRelationManager.php(1 hunks)app-modules/events/src/Filament/Admin/Resources/Talks/TalkResource.php(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php
🧰 Additional context used
🧬 Code graph analysis (3)
app-modules/events/src/Filament/Admin/Resources/Talks/TalkResource.php (1)
app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php (1)
getNavigationBadge(32-35)
app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/AttendeesRelationManager.php (2)
app-modules/user/src/Filament/Admin/Resources/Users/UserResource.php (1)
UserResource(21-56)app-modules/events/src/Models/EventModel.php (1)
attendees(67-79)
app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/TalksRelationManager.php (1)
app-modules/events/src/Models/EventModel.php (1)
talks(146-149)
🪛 PHPMD (2.15.0)
app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/AttendeesRelationManager.php
28-28: Avoid unused parameters such as '$pageClass'. (undefined)
(UnusedFormalParameter)
33-33: Avoid unused parameters such as '$ownerRecord'. (undefined)
(UnusedFormalParameter)
33-33: Avoid unused parameters such as '$pageClass'. (undefined)
(UnusedFormalParameter)
app-modules/events/src/Filament/Admin/Resources/Events/RelationManagers/TalksRelationManager.php
21-21: Avoid unused parameters such as '$pageClass'. (undefined)
(UnusedFormalParameter)
26-26: Avoid unused parameters such as '$ownerRecord'. (undefined)
(UnusedFormalParameter)
26-26: Avoid unused parameters such as '$pageClass'. (undefined)
(UnusedFormalParameter)
🔇 Additional comments (1)
app-modules/events/src/Filament/Admin/Resources/Talks/TalkResource.php (1)
32-35: Navigation badge implementation is consistent and straightforward
getNavigationBadge()correctly mirrors the existing pattern inEventResource, usingself::$model::count()and returning a string; no functional issues here.
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Attendee relation manager: participant list, status badges, and detach (remove) action * Talks relation manager: create and manage submissions; navigation badges for events and talks * User → events relation added; attendee counts shown in event listings * **Improvements** * Reorganized event and talk forms into clearer sections and responsive layouts * Event table: improved status indicator, truncated titles, attendee/submission counts, sortable dates/times * Added email column to users table * **Tests** * New test suites covering attendee and talk relation managers and related actions * **Chores** * Seeder adjusted to create events with related talks <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Summary by CodeRabbit
New Features
Improvements
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.