Skip to content

feat: improvements admin ui#117

Merged
danielhe4rt merged 24 commits into
3.xfrom
feat/improvements-admin-ui
Nov 23, 2025
Merged

feat: improvements admin ui#117
danielhe4rt merged 24 commits into
3.xfrom
feat/improvements-admin-ui

Conversation

@Clintonrocha98
Copy link
Copy Markdown
Collaborator

@Clintonrocha98 Clintonrocha98 commented Nov 22, 2025

This pull request introduces new dashboard widgets for the admin panels of the Events, Season, Tenant, and User modules, providing richer statistics and insights for administrators. It also refactors the Season module to use a more consistent directory structure and improves some resource and table definitions for better reliability and navigation.

Dashboard Widget Additions:

  • Added the ActiveEventsStats widget to the Events admin panel, displaying live statistics about the current event, attendees, waitlist, talks, and sponsors. [1] [2] [3]
  • Added the SeasonStatsOverview widget to the Season admin panel, showing statistics about the active season, XP, messages, and participants. [1] [2] [3]
  • Added the TenantsStatsOverview widget to the Tenant admin panel, with stats on active tenants, new tenants this month, tenants with most users, and most messages. [1] [2] [3]
  • Added the UsersStatsOverview widget to the User admin panel, showing users created today, this month, and total donators. [1] [2]

Season Module Refactor:

  • Refactored the Season module to move resources, pages, schemas, and tables under the Filament\Admin\Resources\Seasons namespace for better organization and maintainability. This includes renaming and updating imports in several files. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]

Resource and Table Improvements:

  • Added navigation badges and sorting to Tenant and User resources, making it easier for admins to see counts and organize navigation. [1] [2] [3]
  • Improved reliability of the season table by safely handling nullable ended_at dates.

Other Minor Improvements:

  • Updated the MeetingTypeFactory to use a time string for start_at instead of a number, improving test data realism.

Summary by CodeRabbit

  • New Features

    • Added dashboard stats widgets for events, seasons, tenants and users; header widget on users list
    • Active event/season stats now surface live metrics (attendees, waitlist, talks, messages, participants)
  • UX / Navigation

    • Navigation badges and sort order added to Users and Tenants
    • Admin panel navigation reorganized into grouped sections (Administration, Events, Gamification, Meetings, General)
  • Bug Fixes

    • Improved null-safe handling for date displays
  • Chores

    • Expanded base seeder with additional meetings and messages

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Nov 22, 2025

Walkthrough

Adds Filament StatsOverview widgets (events, seasons, tenants, users), registers them in admin panel plugins, refactors Season resources into an Admin namespace and updates tests, adds navigation sort/badges to resources, introduces User::isAdmin(), reorganizes admin navigation into groups, and extends BaseSeeder with meetings/messages and a shifted season end date.

Changes

Cohort / File(s) Change Summary
New Widgets
app-modules/events/src/Filament/Shared/Widgets/ActiveEventsStats.php, app-modules/season/src/Filament/Shared/Widgets/SeasonStatsOverview.php, app-modules/tenant/src/Filament/Admin/Widgets/TenantsStatsOverview.php, app-modules/user/src/Filament/Shared/Widgets/UsersStatsOverview.php
Adds four Filament StatsOverviewWidget subclasses implementing getStats(), producing localized stats (counts, statuses, colors/icons) with tenant-aware scoping where applicable.
Plugin Widget Registration
app-modules/events/src/AdminEventPanelPlugin.php, app-modules/season/src/AdminSeasonPanelPlugin.php, app-modules/tenant/src/Plugins/AdminTenantPanelPlugin.php, app-modules/user/src/Plugins/AdminUserPanelPlugin.php
Registers the new widgets within the respective admin panel plugins' register() methods.
Season Admin Namespace Refactor
app-modules/season/src/Filament/Admin/Resources/Seasons/*
Moves Season resources/pages/schemas/tables into He4rt\Season\Filament\Admin\Resources\Seasons namespace and updates use statements; SeasonsTable uses nullsafe operator when formatting ended_at.
Season Tests Updated
app-modules/season/tests/Feature/Filament/Admin/*.php
Updates test imports (CreateSeason, EditSeason, ListSeasons) to reference the new Admin namespace.
Resource Navigation Enhancements
app-modules/tenant/src/Filament/Admin/Resources/Tenants/TenantResource.php, app-modules/user/src/Filament/Admin/Resources/Users/UserResource.php
Adds protected static ?int $navigationSort and public static function getNavigationBadge(): ?string to expose navigation ordering and record-count badges.
User Module Changes
app-modules/user/src/Filament/Admin/Resources/Users/Pages/ListUsers.php, app-modules/user/src/Models/User.php, app-modules/user/src/Plugins/AdminUserPanelPlugin.php
ListUsers adds header widget (UsersStatsOverview); User model gains public function isAdmin(): bool and docblock @property string $email; AdminUserPanelPlugin registers the widget.
Admin Panel Reorganization
app/Providers/Filament/AdminPanelProvider.php
Replaces explicit widget imports with NavigationGroup-based navigation organization and adjusts panel configuration to use grouped navigation.
Database Seeder Updates
database/seeders/BaseSeeder.php
Adds Meeting and Message imports, changes seeded Season end date to now()->addMonth(), and seeds 5 Meeting and 5 Message records linked to tenant.
Meeting Factory Change
app-modules/meeting/database/factories/MeetingTypeFactory.php
Changes start_at generation from integer minutes to time string format ('H:i').
Tenant Model Relationship
app-modules/tenant/src/Models/Tenant.php
Adds messages() HasMany relationship to Message with PHPDoc.
Tests / Imports Adjusted
app-modules/season/... tests
Updated imports to match Admin namespace for Season pages used in tests.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor Filament
    participant Widget as StatsOverviewWidget
    participant Auth as Auth
    participant DB as Database

    Filament->>Widget: render()
    Widget->>Auth: auth()->user()
    Auth-->>Widget: User
    alt non-admin (tenant-scoped)
        Widget->>DB: query scoped to tenant (where tenant_id = ...)
    else admin/global
        Widget->>DB: global query
    end
    DB-->>Widget: aggregated metrics (counts, relations)
    Widget->>Filament: render stats (labels/icons/colors)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Focus review on: tenant-scoping logic in widgets (ActiveEventsStats, UsersStatsOverview), Season namespace updates (resource/page/schemas/tables + tests), AdminPanelProvider navigation changes, and the new User::isAdmin() impact.

Possibly related PRs

  • feat: talks time #105 — related: ActiveEventsStats depends on Event->talks() and event/talk timing fields introduced or changed in that PR.

Suggested reviewers

  • danielhe4rt
  • PilsAraujo

Poem

🐰
I hop through panels, tally and peek,
Seasons and events whisper what they seek.
Tenants, users, counts in cheer,
Meetings and messages now appear.
Carrots for dashboards — all is clear.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% 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: improvements admin ui" is vague and generic, using broad terms like "improvements" that don't convey the specific nature or scope of the substantial changes across multiple modules. Clarify the title to be more specific, such as "feat: add dashboard widgets and refactor season module structure" to better reflect the primary changes involving new widgets and module reorganization.
✅ 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/improvements-admin-ui

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

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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app-modules/user/src/Models/User.php (1)

25-29: Define the $email property for static analysis and consider centralizing the admin check

Two points here:

  1. Phpstan failure (undefined property $email)
    The new isAdmin() method accesses $this->email, but the model’s phpdoc only documents id, username, and is_donator. Phpstan is complaining because it doesn’t see an email property on User. You can fix this cleanly by extending the docblock to include the email column:
 /**
  * @property string $id
  * @property string $username
  * @property bool $is_donator
+ * @property string|null $email
  */

This matches the existing fillable array and should satisfy phpstan without changing runtime behavior.

  1. Hard‑coded admin email (optional refactor)
    isAdmin() currently hard‑codes admin@admin.com. That’s fine for now, but if you ever need multiple admins or a configurable address, consider delegating this to a role/permission system or a config value (e.g., config('auth.admin_email')) to avoid scattering this literal across the codebase.

Also applies to: 48-51

🧹 Nitpick comments (4)
app-modules/events/src/Filament/Shared/Widgets/ActiveEventsStats.php (1)

56-59: Inconsistent counting approach across stats.

Line 56 calls $event->talks()->count() (relationship query), while lines 46 and 51 access count attributes (attendees_count, waitlist_count). For consistency and to avoid extra queries, consider loading talks_count via withCount() as well (see earlier comment on lines 20-26) and then accessing it as $event->talks_count.

If you apply the withCount() fix from the earlier comment, also access talks consistently:

-            Stat::make('Talks cadastradas', $event->talks()->count())
+            Stat::make('Talks cadastradas', $event->talks_count)
app/Providers/Filament/AdminPanelProvider.php (1)

12-12: Navigation groups are well structured; consider fixing the “Gamefication” label

The new navigationGroups() call cleanly organizes the admin menu into logical sections and should work well with resources that set protected static ?string $navigationGroup.

Very small nit: if this isn’t intentional branding, you may want to rename:

- NavigationGroup::make()->label('Gamefication'),
+ NavigationGroup::make()->label('Gamification'),

to avoid a visible typo in the UI.

Also applies to: 44-58

app-modules/user/src/Filament/Admin/Resources/Users/UserResource.php (1)

34-34: User navigation sort and badge follow existing resource patterns

Setting protected static ?int $navigationSort = 1; and using getNavigationBadge() to return the user count is consistent with how other resources expose badges and ordering. This should integrate smoothly into the new navigation groups.

If the users table grows very large, you might later consider caching this count, but for typical admin usage this is fine as-is.

Also applies to: 46-49

app-modules/tenant/src/Filament/Admin/Resources/Tenants/TenantResource.php (1)

28-28: Tenant navigation ordering and badge are consistent with the rest of the panel

$navigationSort = 2 positions tenants right after users in the Administration group, and getNavigationBadge() mirrors the count‑badge pattern used in other resources. Implementation looks straightforward and consistent. For very large tenant datasets, you could later cache this value if needed.

Also applies to: 34-37

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 80c1170 and e9cbca3.

📒 Files selected for processing (24)
  • app-modules/events/src/AdminEventPanelPlugin.php (2 hunks)
  • app-modules/events/src/Filament/Shared/Widgets/ActiveEventsStats.php (1 hunks)
  • app-modules/meeting/database/factories/MeetingTypeFactory.php (1 hunks)
  • app-modules/season/src/AdminSeasonPanelPlugin.php (2 hunks)
  • app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/CreateSeason.php (1 hunks)
  • app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/EditSeason.php (1 hunks)
  • app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/ListSeasons.php (1 hunks)
  • app-modules/season/src/Filament/Admin/Resources/Seasons/Schemas/SeasonForm.php (1 hunks)
  • app-modules/season/src/Filament/Admin/Resources/Seasons/SeasonResource.php (1 hunks)
  • app-modules/season/src/Filament/Admin/Resources/Seasons/Tables/SeasonsTable.php (2 hunks)
  • app-modules/season/src/Filament/Shared/Widgets/SeasonStatsOverview.php (1 hunks)
  • app-modules/season/tests/Feature/Filament/Admin/CreateSeasonTest.php (1 hunks)
  • app-modules/season/tests/Feature/Filament/Admin/EditSeasonTest.php (1 hunks)
  • app-modules/season/tests/Feature/Filament/Admin/ListSeasonTest.php (1 hunks)
  • app-modules/tenant/src/Filament/Admin/Resources/Tenants/TenantResource.php (1 hunks)
  • app-modules/tenant/src/Filament/Admin/Widgets/TenantsStatsOverview.php (1 hunks)
  • app-modules/tenant/src/Plugins/AdminTenantPanelPlugin.php (2 hunks)
  • app-modules/user/src/Filament/Admin/Resources/Users/Pages/ListUsers.php (1 hunks)
  • app-modules/user/src/Filament/Admin/Resources/Users/UserResource.php (2 hunks)
  • app-modules/user/src/Filament/Shared/Widgets/UsersStatsOverview.php (1 hunks)
  • app-modules/user/src/Models/User.php (1 hunks)
  • app-modules/user/src/Plugins/AdminUserPanelPlugin.php (2 hunks)
  • app/Providers/Filament/AdminPanelProvider.php (2 hunks)
  • database/seeders/BaseSeeder.php (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (22)
app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/CreateSeason.php (1)
app-modules/season/src/Filament/Admin/Resources/Seasons/SeasonResource.php (1)
  • SeasonResource (20-48)
app-modules/user/src/Filament/Shared/Widgets/UsersStatsOverview.php (1)
app-modules/user/src/Models/User.php (1)
  • isAdmin (48-51)
app-modules/user/src/Filament/Admin/Resources/Users/Pages/ListUsers.php (2)
app-modules/user/src/Filament/Shared/Widgets/UsersStatsOverview.php (1)
  • UsersStatsOverview (13-49)
app-modules/user/src/Filament/Admin/Resources/Users/UserResource.php (1)
  • UserResource (24-69)
app-modules/tenant/src/Filament/Admin/Widgets/TenantsStatsOverview.php (1)
app-modules/tenant/src/Models/Tenant.php (1)
  • Tenant (22-94)
app-modules/user/src/Filament/Admin/Resources/Users/UserResource.php (3)
app-modules/tenant/src/Filament/Admin/Resources/Tenants/TenantResource.php (1)
  • getNavigationBadge (34-37)
app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php (1)
  • getNavigationBadge (32-35)
app-modules/events/src/Filament/Admin/Resources/Talks/TalkResource.php (1)
  • getNavigationBadge (32-35)
app-modules/user/src/Models/User.php (3)
app-modules/user/database/factories/UserFactory.php (2)
  • UserFactory (10-22)
  • definition (14-21)
app-modules/user/src/Repositories/UserEloquentRepository.php (1)
  • createUser (73-88)
app-modules/user/src/Entities/UserEntity.php (1)
  • UserEntity (11-42)
app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/EditSeason.php (1)
app-modules/season/src/Filament/Admin/Resources/Seasons/SeasonResource.php (1)
  • SeasonResource (20-48)
app-modules/tenant/src/Filament/Admin/Resources/Tenants/TenantResource.php (3)
app-modules/user/src/Filament/Admin/Resources/Users/UserResource.php (1)
  • getNavigationBadge (46-49)
app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php (1)
  • getNavigationBadge (32-35)
app-modules/events/src/Filament/Admin/Resources/Talks/TalkResource.php (1)
  • getNavigationBadge (32-35)
app-modules/season/tests/Feature/Filament/Admin/CreateSeasonTest.php (1)
app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/CreateSeason.php (1)
  • CreateSeason (10-13)
database/seeders/BaseSeeder.php (4)
app-modules/meeting/src/Models/Meeting.php (2)
  • Meeting (17-89)
  • Meeting (15-67)
app-modules/message/src/Models/Message.php (1)
  • Message (16-63)
app-modules/meeting/database/factories/MeetingFactory.php (1)
  • MeetingFactory (12-32)
app-modules/season/src/Models/Season.php (1)
  • meetings (39-42)
app-modules/meeting/database/factories/MeetingTypeFactory.php (2)
app-modules/meeting/src/Models/MeetingType.php (5)
  • startAt (35-40)
  • generateStartAt (42-51)
  • value (38-38)
  • MeetingType (18-52)
  • newFactory (30-33)
app-modules/meeting/database/factories/MeetingFactory.php (2)
  • definition (16-26)
  • MeetingFactory (12-32)
app-modules/user/src/Plugins/AdminUserPanelPlugin.php (1)
app-modules/user/src/Filament/Shared/Widgets/UsersStatsOverview.php (1)
  • UsersStatsOverview (13-49)
app-modules/season/src/AdminSeasonPanelPlugin.php (2)
app-modules/season/src/Filament/Admin/Resources/Seasons/SeasonResource.php (1)
  • SeasonResource (20-48)
app-modules/season/src/Filament/Shared/Widgets/SeasonStatsOverview.php (1)
  • SeasonStatsOverview (12-51)
app-modules/season/src/Filament/Admin/Resources/Seasons/SeasonResource.php (5)
app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/CreateSeason.php (1)
  • CreateSeason (10-13)
app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/EditSeason.php (1)
  • EditSeason (11-21)
app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/ListSeasons.php (1)
  • ListSeasons (11-21)
app-modules/season/src/Filament/Admin/Resources/Seasons/Schemas/SeasonForm.php (1)
  • SeasonForm (13-48)
app-modules/season/src/Filament/Admin/Resources/Seasons/Tables/SeasonsTable.php (1)
  • SeasonsTable (13-59)
app-modules/events/src/AdminEventPanelPlugin.php (1)
app-modules/events/src/Filament/Shared/Widgets/ActiveEventsStats.php (1)
  • ActiveEventsStats (12-67)
app-modules/season/tests/Feature/Filament/Admin/ListSeasonTest.php (1)
app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/ListSeasons.php (1)
  • ListSeasons (11-21)
app-modules/season/tests/Feature/Filament/Admin/EditSeasonTest.php (1)
app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/EditSeason.php (1)
  • EditSeason (11-21)
app-modules/season/src/Filament/Shared/Widgets/SeasonStatsOverview.php (2)
app-modules/season/src/Models/Season.php (4)
  • Season (29-85)
  • badges (34-37)
  • Season (15-48)
  • meetings (39-42)
app-modules/season/database/migrations/2023_01_30_174411_create_seasons_table.php (1)
  • Blueprint (17-28)
app-modules/season/src/Filament/Admin/Resources/Seasons/Tables/SeasonsTable.php (4)
app-modules/season/src/Models/Season.php (2)
  • Season (29-85)
  • Season (15-48)
app-modules/season/database/migrations/2023_01_30_174411_create_seasons_table.php (1)
  • Blueprint (17-28)
app-modules/season/src/Entities/SeasonEntity.php (1)
  • SeasonEntity (10-45)
app-modules/season/database/factories/SeasonFactory.php (1)
  • SeasonFactory (10-28)
app-modules/events/src/Filament/Shared/Widgets/ActiveEventsStats.php (4)
app-modules/user/src/Filament/Shared/Widgets/UsersStatsOverview.php (1)
  • getStats (17-48)
app-modules/user/src/Models/User.php (1)
  • isAdmin (48-51)
app-modules/events/src/Models/Talk.php (1)
  • event (46-49)
app-modules/events/src/Models/EventModel.php (2)
  • talks (146-149)
  • attendees (67-79)
app-modules/tenant/src/Plugins/AdminTenantPanelPlugin.php (1)
app-modules/tenant/src/Filament/Admin/Widgets/TenantsStatsOverview.php (1)
  • TenantsStatsOverview (12-55)
app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/ListSeasons.php (1)
app-modules/season/src/Filament/Admin/Resources/Seasons/SeasonResource.php (1)
  • SeasonResource (20-48)
🪛 GitHub Check: Perform Phpstan Check / Run
app-modules/user/src/Models/User.php

[failure] 50-50:
Access to an undefined property He4rt\User\Models\User::$email.

🔇 Additional comments (22)
app-modules/season/tests/Feature/Filament/Admin/ListSeasonTest.php (1)

7-7: LGTM! Namespace refactor aligns with Admin restructuring.

The import path correctly reflects the new Admin namespace structure for Season resources.

app-modules/season/src/Filament/Admin/Resources/Seasons/Schemas/SeasonForm.php (1)

5-5: LGTM! Namespace refactor aligns with Admin restructuring.

The namespace correctly reflects the new Admin structure for Season schemas.

app-modules/season/tests/Feature/Filament/Admin/EditSeasonTest.php (1)

7-7: LGTM! Namespace refactor aligns with Admin restructuring.

The import path correctly reflects the new Admin namespace structure.

app-modules/season/src/AdminSeasonPanelPlugin.php (2)

10-11: LGTM! Namespace refactor and new widget import.

The SeasonResource import is correctly updated to the Admin namespace, and the SeasonStatsOverview widget import aligns with the PR's dashboard widget additions.


25-28: LGTM! Widget registration added.

The SeasonStatsOverview widget is properly registered with the admin panel, enabling the new dashboard statistics for seasons.

app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/ListSeasons.php (1)

5-9: LGTM! Namespace refactor aligns with Admin restructuring.

Both the namespace declaration and the SeasonResource import are correctly updated to the Admin namespace structure.

app-modules/season/tests/Feature/Filament/Admin/CreateSeasonTest.php (1)

7-7: LGTM! Namespace refactor aligns with Admin restructuring.

The import path correctly reflects the new Admin namespace structure.

app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/CreateSeason.php (1)

5-8: LGTM! Namespace refactor aligns with Admin restructuring.

Both the namespace declaration and the SeasonResource import are correctly updated to the Admin namespace structure.

app-modules/season/src/Filament/Admin/Resources/Seasons/Tables/SeasonsTable.php (2)

5-5: LGTM! Namespace refactor aligns with Admin restructuring.

The namespace correctly reflects the new Admin structure for Season tables.


27-27: Excellent defensive improvement with nullsafe operator!

The nullsafe operator (?->) correctly handles the nullable ended_at field, preventing potential null reference errors when formatting the date. This aligns with the database schema where ended_at is nullable, especially for active seasons without an end date.

app-modules/season/src/Filament/Admin/Resources/Seasons/Pages/EditSeason.php (1)

5-9: LGTM! Clean namespace refactor.

The namespace and import path updates correctly align with the Admin directory structure reorganization described in the PR objectives.

app-modules/season/src/Filament/Shared/Widgets/SeasonStatsOverview.php (1)

18-24: LGTM! Active season query logic is sound.

The query correctly identifies the current active season by checking started_at <= now() and either ended_at is null or ended_at > now().

app-modules/season/src/Filament/Admin/Resources/Seasons/SeasonResource.php (1)

5-16: LGTM! Comprehensive namespace migration to Admin structure.

All namespace and import paths have been consistently updated to reflect the new Admin directory organization. The refactor includes the resource itself and all related dependencies (Pages, Schemas, Tables).

app-modules/events/src/Filament/Shared/Widgets/ActiveEventsStats.php (1)

22-24: Admin check relies on hardcoded email comparison.

The isAdmin() method (defined in the User model) checks whether the user's email equals 'admin@admin.com'. While this may be acceptable for a development or proof-of-concept environment, it's a weak authorization mechanism for production.

Consider verifying whether a role-based or permission-based authorization system should be used instead. If this is intentional for the current stage, document it clearly.

Based on learnings.

app-modules/events/src/AdminEventPanelPlugin.php (1)

12-12: LGTM!

The import and registration of the ActiveEventsStats widget follow the standard Filament plugin pattern correctly.

Also applies to: 28-30

database/seeders/BaseSeeder.php (3)

10-11: LGTM!

The imports are correctly added to support the new seeding operations for meetings and messages.


73-73: Good improvement for test data.

Changing the season end date to a future date creates an active season for testing, which is more useful than a season that ends today.


80-83: Original review comment is based on incorrect assumptions about the Message factory structure.

The Message factory does not define a season() relationship. It hardcodes 'season_id' => 2 as a direct integer value. Therefore, the proposed solution using ->recycle($season) will not work—the factory has no relationship to recycle.

While the concern about season associations is valid (the hardcoded season_id of 2 may not exist in a fresh database), the suggested fix is incompatible with the current factory design. If the season ID should be dynamic based on the seeder, the factory definition would need to be modified to define a season relationship, or the seeder would need to override it using ->state(['season_id' => $season->id]).

Likely an incorrect or invalid review comment.

app-modules/tenant/src/Plugins/AdminTenantPanelPlugin.php (1)

11-11: Tenants stats widget registration looks consistent

Importing and registering TenantsStatsOverview via $panel->widgets([...]) aligns with the existing plugin pattern and should correctly expose the new stats widget on the tenant admin panel.

Also applies to: 26-28

app-modules/user/src/Plugins/AdminUserPanelPlugin.php (1)

11-11: Users stats widget is wired correctly into the admin panel

Registering UsersStatsOverview via $panel->widgets([...]) is consistent with the other plugins and should surface the stats overview on the user admin panel as intended.

Also applies to: 26-28

app-modules/user/src/Filament/Admin/Resources/Users/Pages/ListUsers.php (1)

10-21: Header widget integration for user stats looks good

Using getHeaderWidgets() to include UsersStatsOverview::class is idiomatic Filament and will display the stats block at the top of the ListUsers page. No issues spotted.

app-modules/user/src/Filament/Shared/Widgets/UsersStatsOverview.php (1)

7-12: Users stats widget logic is solid; consider guarding against missing tenant in non-admin contexts

The widget’s query composition looks good:

  • Starts from User::query().
  • For non-admins, scopes by tenants so users only see stats for their tenant.
  • Reuses the base query via clone for donators, today, and month counts.
  • Output Stat cards are clear and consistent with the rest of the dashboard.

One thing to double‑check: in the non‑admin branch you call:

$query->whereHas('tenants', fn (Builder $q) => $q->where('tenants.id', Filament::getTenant()->getKey()));

If there is any scenario where a non‑admin can hit this widget without an active tenant (i.e., Filament::getTenant() returns null), this will throw. If that scenario is possible, consider a null‑safe guard, e.g. early‑returning zeros or skipping the whereHas when no tenant is set.

Otherwise, the implementation is concise and matches the intended tenancy behavior.

Also applies to: 17-47

Comment thread app-modules/events/src/Filament/Shared/Widgets/ActiveEventsStats.php Outdated
Comment thread app-modules/meeting/database/factories/MeetingTypeFactory.php
Comment thread database/seeders/BaseSeeder.php
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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9cbca3 and f57e082.

📒 Files selected for processing (4)
  • app-modules/season/src/Filament/Shared/Widgets/SeasonStatsOverview.php (1 hunks)
  • app-modules/tenant/src/Filament/Admin/Widgets/TenantsStatsOverview.php (1 hunks)
  • app-modules/user/src/Models/User.php (2 hunks)
  • database/seeders/BaseSeeder.php (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • app-modules/season/src/Filament/Shared/Widgets/SeasonStatsOverview.php
  • database/seeders/BaseSeeder.php
  • app-modules/user/src/Models/User.php
🧰 Additional context used
🧬 Code graph analysis (1)
app-modules/tenant/src/Filament/Admin/Widgets/TenantsStatsOverview.php (1)
app-modules/tenant/src/Models/Tenant.php (1)
  • Tenant (22-94)
⏰ 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 (2)
app-modules/tenant/src/Filament/Admin/Widgets/TenantsStatsOverview.php (2)

14-26: Overall widget logic and basic stats look solid

getStats() is straightforward and readable: active count, “created this month” window with whereBetween, and withCount('members') for the “most users” tenant are all correct and handle nulls nicely via the null‑safe operator when building the Stat cards. No issues here.


35-55: Stat card rendering is consistent and null‑safe

The four Stat::make(...) calls are cohesive, handle the “no tenant” case gracefully ('Nenhum' + empty description), and use consistent icon/color conventions. This matches the patterns used in other admin widgets and should integrate cleanly into the Filament dashboard.

Comment thread app-modules/tenant/src/Filament/Admin/Widgets/TenantsStatsOverview.php Outdated
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: 1

♻️ Duplicate comments (1)
app-modules/meeting/database/factories/MeetingTypeFactory.php (1)

17-23: Factory generates H:i strings but model accessor still assumes integer minutes, causing incorrect times

MeetingTypeFactory now sets 'start_at' => fake()->time('H:i'), but He4rt\Meeting\Models\MeetingType::startAt() calls generateStartAt($value) which does intdiv($value, 60) and $value % 60. With a value like "14:30", PHP coerces it to 14, producing "00:14" instead of "14:30", so seeded/fixture data will have corrupted times and an inconsistent contract between model and factory.

Unless you simultaneously update generateStartAt() (and possibly the DB column) to work with H:i strings, this change should be reverted to generate integer minutes (0–1439):

-            'start_at' => fake()->time('H:i'),
+            'start_at' => fake()->numberBetween(0, 1439),

If you truly want H:i storage, adjust generateStartAt() to parse H:i (e.g., via explode or Carbon) instead of doing integer division/modulo on the raw string, and ensure migrations and casts are aligned.

🧹 Nitpick comments (1)
database/seeders/BaseSeeder.php (1)

76-79: Consider reusing the existing admin user.

The tenant association is now correctly handled with ->recycle($tenant). However, the factory will create new User instances for the admin_id relationship, which may be unnecessary in a seeding context.

You can optionally reuse the existing $user for the admin relationship to reduce seeded data:

 Meeting::factory()
     ->count(5)
     ->recycle($tenant)
+    ->recycle($user)
     ->create();
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 919ced1 and e5a0cd1.

📒 Files selected for processing (3)
  • app-modules/meeting/database/factories/MeetingTypeFactory.php (1 hunks)
  • app-modules/tenant/src/Filament/Admin/Widgets/TenantsStatsOverview.php (1 hunks)
  • database/seeders/BaseSeeder.php (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app-modules/tenant/src/Filament/Admin/Widgets/TenantsStatsOverview.php
🧰 Additional context used
🧬 Code graph analysis (2)
database/seeders/BaseSeeder.php (3)
app-modules/meeting/src/Models/Meeting.php (2)
  • Meeting (17-89)
  • Meeting (15-67)
app-modules/message/src/Models/Message.php (1)
  • Message (16-63)
app-modules/meeting/database/factories/MeetingFactory.php (1)
  • MeetingFactory (12-32)
app-modules/meeting/database/factories/MeetingTypeFactory.php (1)
app-modules/meeting/src/Models/MeetingType.php (4)
  • value (38-38)
  • startAt (35-40)
  • generateStartAt (42-51)
  • newFactory (30-33)

Comment thread database/seeders/BaseSeeder.php
Comment thread app-modules/user/src/Models/User.php
Comment thread app-modules/tenant/src/Filament/Admin/Widgets/TenantsStatsOverview.php Outdated
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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e5a0cd1 and 7fef552.

📒 Files selected for processing (3)
  • app-modules/tenant/src/Filament/Admin/Widgets/TenantsStatsOverview.php (1 hunks)
  • app-modules/tenant/src/Models/Tenant.php (2 hunks)
  • database/seeders/BaseSeeder.php (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • database/seeders/BaseSeeder.php
🧰 Additional context used
🧬 Code graph analysis (2)
app-modules/tenant/src/Models/Tenant.php (2)
app-modules/message/src/Models/Message.php (2)
  • Message (16-63)
  • Message (12-34)
database/migrations/2023_01_18_211845_create_messages_table.php (1)
  • Blueprint (17-27)
app-modules/tenant/src/Filament/Admin/Widgets/TenantsStatsOverview.php (1)
app-modules/tenant/src/Models/Tenant.php (1)
  • Tenant (23-103)
⏰ 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 (4)
app-modules/tenant/src/Filament/Admin/Widgets/TenantsStatsOverview.php (4)

15-19: LGTM!

The date filtering correctly uses whereBetween() with startOfMonth() and endOfMonth(), which properly restricts to the current month of the current year and is index-friendly. This addresses the previous issue with whereMonth() that ignored the year component.


21-24: LGTM!

The withCount('members') approach correctly leverages Laravel's aggregation and avoids N+1 queries. The members() relationship exists on the Tenant model, so this will work as expected.


26-28: LGTM!

Using withCount('messages') is the correct approach and cleanly avoids the Cartesian product and double-counting issues from the previous LEFT JOIN implementation. This depends on the messages() relationship added to the Tenant model in this PR.


30-51: LGTM!

The stats array properly uses null-safe operators (?->) and ternary checks to handle cases where no tenants are found. The Portuguese labels, icons, and colors are appropriate and consistent.

Comment thread app-modules/tenant/src/Models/Tenant.php
@danielhe4rt danielhe4rt merged commit 11189ab into 3.x Nov 23, 2025
6 checks passed
@danielhe4rt danielhe4rt deleted the feat/improvements-admin-ui branch November 23, 2025 22:11
This was referenced Nov 23, 2025
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.

3 participants