feat: event page#121
Conversation
WalkthroughTenant-aware landing page now resolves a tenant and supplies its first event to views; Blade components (hero, info, schedule, speakers) accept an Changes
Sequence DiagramsequenceDiagram
participant Client
participant EventLandingPage
participant Tenant
participant DB as EventModel/DB
participant View as HomepageView
participant Components
Client->>EventLandingPage: HTTP request (host/path)
EventLandingPage->>EventLandingPage: mount() — resolve slug from host/path
EventLandingPage->>Tenant: Tenant::firstOrFail(slug)
Tenant-->>EventLandingPage: Tenant loaded
EventLandingPage->>DB: getViewData() → fetch first event (with talks/speakers)
DB-->>EventLandingPage: Event model (with accessors)
EventLandingPage->>View: render(viewPathFromTenant, ['event' => $event])
View->>Components: pass $event to hero, info, schedule, speakers
Components->>Components: render dynamic content (title, times, talks, speakers, media)
Components-->>Client: HTML response
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (6)
database/migrations/2025_11_05_135059_create_media_table.php (1)
16-17: Changingmodel_idto string & editing migration in-place may need extra careMaking
model_idastringand adding the composite index is a reasonable choice for UUID-backed models, but a couple of points to double‑check:
- If this migration has already run in any shared environment, changing the column type in-place here will leave schema drift between DBs and
migrate:fresh. In that case, prefer a follow‑upSchema::tablemigration that does the->string('model_id')->change()and adds the index instead of editing the original file.- A string
model_idwith a composite index is fine but heavier than an integer key; make sure this is acceptable for expected media volume.- Since this table backs the media library, ensure your Spatie medialibrary configuration (and any published migrations) are consistent with
model_idbeing a string instead of the default integer.If you decide to migrate via a separate alter migration, that file would look roughly like:
+Schema::table('media', function (Blueprint $table): void { + $table->string('model_id')->change(); + $table->index(['model_type', 'model_id'], 'media_model_idx'); +});Also applies to: 32-32
app-modules/user/src/Models/User.php (1)
25-27: Media library integration looks correct; just confirm disk & schema alignmentImplementing
HasMedia+InteractsWithMediaand registering anavatarcollection on thepublicdisk is the standard Spatie pattern and should work well with the newmediatable.Two small checks to keep in mind:
- Ensure the
publicdisk is configured and exposed the way you expect in all environments (local, staging, prod), otherwise seeded avatars won’t be accessible.- With the
mediamigration now using stringmodel_id, confirm that your medialibrary config and any published migrations aren’t still assuming an integer key type.If you want to be defensive against future changes, you could also add a short doc comment on
registerMediaCollections()indicating this collection is used for speaker avatars, which ties it back to the seeder.Also applies to: 35-40, 120-124
app-modules/events/src/Models/EventModel.php (1)
158-187: Speakers relation and time accessors are useful, but consider null-safety and duplicates
- The
speakers()hasManyThrough mapping (event_id→id,user_id→id) is coherent with your schema, but note it will return duplicateUserrows when someone has multiple talks in the same event. If you want unique speakers, consider adding->distinct('users.id')on the relation or switching to abelongsToManyvia the talks table.duration()currently calls$this->start_at->diffInHours($this->end_at)without null checks. If either timestamp can be null for some events, this will throw at runtime, unlike the other accessors which use?->.You could harden
duration()like this:protected function duration(): Attribute { return Attribute::make( - get: fn () => $this->start_at->diffInHours($this->end_at), + get: fn () => $this->start_at && $this->end_at + ? $this->start_at->diffInHours($this->end_at) + : null, ); }Please confirm whether
start_at/end_atare guaranteed non‑null in all real events; if not, the above change will avoid hard failures while still giving you a meaningful duration when both are set.app-modules/events/resources/views/components/themes/3pontos/components/sections/info.blade.php (1)
29-32: Clarify the date/time format and avoid potential redundancy.Line 30 displays both
$event->start_at->format('D')(abbreviated day name like "Mon", "Tue") and$event->day. This might result in redundant or confusing output if both represent similar information. Verify that:
$event->dayprovides a different format (e.g., full date string) thanformat('D')- The combined output produces the intended user-facing format
If they are redundant, consider using only one format:
-Horário: {{ $event->start_at->format('D') }} {{ $event->day }} - {{ $event->start }} -até {{ $event->end }} +Horário: {{ $event->day }} - {{ $event->start }} até {{ $event->end }}app-modules/events/src/Filament/Events/EventLandingPage.php (1)
19-33: Consider extracting tenant slug resolution to a dedicated method.The
mount()method mixes environment detection with tenant resolution logic. Consider extracting slug resolution to improve testability and maintainability.public function mount(): void { $tenantSlug = $this->resolveTenantSlug(); $this->tenant = Tenant::query()->where('slug', $tenantSlug)->firstOrFail(); } protected function resolveTenantSlug(): string { if (app()->isLocal()) { $tenantSlug = str(request()->path())->explode('/') ->get(1); } else { $path = explode('.', request()->header('host')); $tenantSlug = array_shift($path); } return str($tenantSlug)->replace(['.', '-'], '')->toString(); }app-modules/events/resources/views/components/themes/3pontos/components/sections/hero.blade.php (1)
1-3: Remove the unusedDatefacade import.The
Datefacade is imported on line 2 but never used anywhere in the file. Remove it to keep imports clean.@php use Illuminate\Support\Facades\Date; @endphp
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
app-modules/events/resources/views/components/themes/3pontos/components/sections/hero.blade.php(3 hunks)app-modules/events/resources/views/components/themes/3pontos/components/sections/info.blade.php(2 hunks)app-modules/events/resources/views/components/themes/3pontos/components/sections/schedule.blade.php(2 hunks)app-modules/events/resources/views/components/themes/3pontos/components/sections/speakers.blade.php(2 hunks)app-modules/events/resources/views/components/themes/3pontos/homepage.blade.php(1 hunks)app-modules/events/src/Filament/Events/EventLandingPage.php(3 hunks)app-modules/events/src/Models/EventModel.php(3 hunks)app-modules/events/src/Models/Talk.php(2 hunks)app-modules/user/src/Models/User.php(5 hunks)database/migrations/2025_11_05_135059_create_media_table.php(2 hunks)database/seeders/ThreeDotsSeeder.php(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
app-modules/user/src/Models/User.php (3)
app-modules/events/src/Models/EventModel.php (1)
talks(148-151)database/seeders/ThreeDotsSeeder.php (1)
talks(53-99)app-modules/sponsors/src/Models/Sponsor.php (1)
registerMediaCollections(64-68)
app-modules/events/src/Models/EventModel.php (1)
app-modules/events/src/Models/Talk.php (2)
start(71-76)end(78-83)
app-modules/events/src/Filament/Events/EventLandingPage.php (2)
app-modules/tenant/src/Models/Tenant.php (1)
Tenant(23-103)app-modules/events/src/Models/EventModel.php (1)
tenant(140-143)
app-modules/events/src/Models/Talk.php (2)
app-modules/events/database/factories/TalkFactory.php (1)
TalkFactory(18-38)app-modules/events/src/Models/EventModel.php (2)
start(168-173)end(182-187)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Perform Pest Tests / Run
🔇 Additional comments (7)
app-modules/events/src/Models/Talk.php (1)
7-7: Talk start/end accessors are consistent with EventModel and look correctThe new
start/endattribute accessors formattingstarts_at/ends_atas'H:i'align nicely withEventModel’s API and the casts, and the nullsafe calls avoid errors on missing datetimes. This should make the Blade usage ($talk->start,$talk->end) straightforward.If you expect any talks without
starts_at/ends_at, confirm consumers are fine with anullstring result here. Otherwise this implementation is good to go.Also applies to: 13-14, 18-27, 71-83
app-modules/user/src/Models/User.php (1)
12-12: User→Talks relation wiring matches the event speakers flowThe
talks()relation onuser_idis the right mirror toTalk::user()and fits theEventModel::speakers()hasManyThrough path, so$speaker->talksand$event->speakersshould both behave as expected.It’s worth quickly hitting this via Tinker (
User::first()->talks) to confirm key names match the actual schema, especially if user IDs can be non‑standard (UUIDs, different connection, etc.).Also applies to: 99-105
database/seeders/ThreeDotsSeeder.php (1)
30-31: Event base data seeding looks coherent with the new attributesUsing a richer title/description, fixed slug, and explicit
event_at/start_at/end_atvalues is consistent with the newEventModelaccessors and should support the dynamic landing page well.Also applies to: 35-48
app-modules/events/resources/views/components/themes/3pontos/homepage.blade.php (1)
2-11: LGTM! Event prop passed consistently.The homepage correctly passes the event context to hero, speakers, schedule, and info sections, enabling data-driven rendering across all components.
app-modules/events/resources/views/components/themes/3pontos/components/sections/hero.blade.php (2)
8-12: Good approach to computing derived values.Extracting
$eventStart,$eventEnd, and$diffHoursimproves readability and avoids repeated accessor calls in the template.
59-61: No issues found—accessors properly format output for display.Verification confirms all three accessors in EventModel are correctly formatting their output:
- The
startaccessor returns$this->start_at?->format('H:i'), producing user-friendly time strings (e.g., "14:00")- The
endaccessor returns$this->end_at?->format('H:i'), similarly formatted- The
durationaccessor returns$this->start_at->diffInHours($this->end_at), returning integer hours suitable for display with the "h" suffixThe blade template displays these properly formatted values, producing output like "14:00 ~ 17:00 Duração: 3h"—exactly what users expect.
app-modules/events/resources/views/components/themes/3pontos/components/sections/schedule.blade.php (1)
19-25: No issues found.Both properties are properly defined on the Talk model:
$talk->titleexists as a database column (in$fillableand migrations)$talk->startexists as a protectedAttributeaccessor (line 71 of Talk.php)The code safely references these properties.
wip
Summary by CodeRabbit
New Features
Bug Fixes / UX
✏️ Tip: You can customize this high-level summary in your review settings.