Skip to content

feat: event page#121

Merged
danielhe4rt merged 6 commits into
3.xfrom
feat/event-page-data
Nov 25, 2025
Merged

feat: event page#121
danielhe4rt merged 6 commits into
3.xfrom
feat/event-page-data

Conversation

@RichardGL11
Copy link
Copy Markdown
Collaborator

@RichardGL11 RichardGL11 commented Nov 24, 2025

wip

Summary by CodeRabbit

  • New Features

    • Event pages now render dynamic event data (title, description, location) with formatted day, start/end times and duration.
    • Schedules display all talks with start times and descriptions; speakers show avatars and talk details.
    • Tenant-aware event landing pages ensure the correct event view is served per site.
  • Bug Fixes / UX

    • Clear empty states added when no talks or speakers are available.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Nov 24, 2025

Walkthrough

Tenant-aware landing page now resolves a tenant and supplies its first event to views; Blade components (hero, info, schedule, speakers) accept an event prop and render dynamic data; Event and Talk models gain formatted accessors; User supports media/avatars and talks relation; media migration and seeder are updated for richer talk/speaker data.

Changes

Cohort / File(s) Summary
Event Blade Components
app-modules/events/resources/views/components/themes/3pontos/components/sections/{hero,info,schedule,speakers}.blade.php
Add @props(['event']) to components and replace hardcoded content with dynamic rendering from $event (title, description, location, formatted times, loops over talks/speakers, empty states).
Event Homepage Layout
app-modules/events/resources/views/components/themes/3pontos/homepage.blade.php
Pass :$event into hero, speakers, schedule, and info components.
Event Landing Page
app-modules/events/src/Filament/Events/EventLandingPage.php
Add public $tenant; resolve tenant in mount() from host/path; use tenant slug in getView(); add getViewData() returning the first related event for the view.
Event Model
app-modules/events/src/Models/EventModel.php
Add Attribute accessors: duration, start, day, end (formatted values); expand speakers() relation via explicit hasManyThrough parameters.
Talk Model
app-modules/events/src/Models/Talk.php
Add Attribute accessors start() and end() that format starts_at/ends_at to HH:mm.
User Model
app-modules/user/src/Models/User.php
Implement HasMedia, use InteractsWithMedia; add talks(): HasMany; add registerMediaCollections() defining avatar collection on public disk.
Media Migration
database/migrations/2025_11_05_135059_create_media_table.php
Replace morphs('model') with explicit model_type (string) and model_id (string); add composite index (model_type, model_id) named media_model_idx.
Seeder
database/seeders/ThreeDotsSeeder.php
Replace simple inline talks factory with a private talks() method that creates speakers (with avatar media) and detailed talks (status, field_type, times); change slug 3-pontos3pontos; use TalkStatusEnum::Accepted.

Sequence Diagram

sequenceDiagram
    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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to tenant slug parsing in mount() and abort conditions in getView().
  • Verify media migration impact: model_id changed to string and composite index name.
  • Review seeder's talk/speaker creation and media attachment paths/visibility.

Possibly related PRs

  • feat: talks time #105 — Overlapping changes around talk start/end timestamps, model accessors, and related validations/migrations that touch the same event/talk model layers.

Poem

🐰 I hopped to the landing page on a breeze,

tenants found, events shown with ease;
talks and speakers now dance in line,
avatars shimmer, times read fine;
a tiny rabbit cheers: "Dynamic, divine!" 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.73% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'feat: event page' is vague and generic, failing to clearly convey the specific changes made (dynamic data binding, media integration, database schema updates). Consider a more descriptive title that highlights the main change, such as 'feat: add dynamic event page with speaker media and talk management' or 'feat: integrate event data into landing page templates'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/event-page-data

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6458432 and 26fe170.

📒 Files selected for processing (1)
  • app-modules/events/resources/views/components/themes/3pontos/homepage.blade.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app-modules/events/resources/views/components/themes/3pontos/homepage.blade.php

Comment @coderabbitai help to get the list of available commands and usage tips.

@RichardGL11 RichardGL11 marked this pull request as ready for review November 24, 2025 19:26
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (6)
database/migrations/2025_11_05_135059_create_media_table.php (1)

16-17: Changing model_id to string & editing migration in-place may need extra care

Making model_id a string and 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‑up Schema::table migration that does the ->string('model_id')->change() and adds the index instead of editing the original file.
  • A string model_id with 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_id being 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 alignment

Implementing HasMedia + InteractsWithMedia and registering an avatar collection on the public disk is the standard Spatie pattern and should work well with the new media table.

Two small checks to keep in mind:

  • Ensure the public disk is configured and exposed the way you expect in all environments (local, staging, prod), otherwise seeded avatars won’t be accessible.
  • With the media migration now using string model_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_idid, user_idid) is coherent with your schema, but note it will return duplicate User rows 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 a belongsToMany via 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_at are 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->day provides a different format (e.g., full date string) than format('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 unused Date facade import.

The Date facade 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

📥 Commits

Reviewing files that changed from the base of the PR and between 8fe2418 and 6458432.

📒 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 correct

The new start/end attribute accessors formatting starts_at / ends_at as 'H:i' align nicely with EventModel’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 a null string 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 flow

The talks() relation on user_id is the right mirror to Talk::user() and fits the EventModel::speakers() hasManyThrough path, so $speaker->talks and $event->speakers should 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 attributes

Using a richer title/description, fixed slug, and explicit event_at / start_at / end_at values is consistent with the new EventModel accessors 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 $diffHours improves 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 start accessor returns $this->start_at?->format('H:i'), producing user-friendly time strings (e.g., "14:00")
  • The end accessor returns $this->end_at?->format('H:i'), similarly formatted
  • The duration accessor returns $this->start_at->diffInHours($this->end_at), returning integer hours suitable for display with the "h" suffix

The 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->title exists as a database column (in $fillable and migrations)
  • $talk->start exists as a protected Attribute accessor (line 71 of Talk.php)

The code safely references these properties.

Comment thread app-modules/events/src/Filament/Events/EventLandingPage.php
Comment thread database/seeders/ThreeDotsSeeder.php
@gvieira18 gvieira18 marked this pull request as draft November 24, 2025 19:36
@gvieira18 gvieira18 marked this pull request as ready for review November 24, 2025 19:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants