From fc15e7f9df02ccd1a354b573f68acdb840b53158 Mon Sep 17 00:00:00 2001 From: RichardGL11 Date: Mon, 10 Nov 2025 18:46:28 -0300 Subject: [PATCH 01/25] wip --- .../character/src/Entities/LevelEntity.php | 5 + .../character/src/Models/Character.php | 15 ++ app-modules/tenant/src/Models/Tenant.php | 28 +++ .../views/filament/app-dashboard.blade.php | 204 ++++++++++++++++++ .../src/Filament/User/Pages/Dashboard.php | 35 +++ .../user/src/Plugins/AppUserPanelPlugin.php | 2 + .../src/Providers/UserServiceProvider.php | 1 + .../Filament/App/Pages/DashboardPageTest.php | 70 ++++++ app/Providers/Filament/UserPanelProvider.php | 2 +- database/seeders/DatabaseSeeder.php | 21 +- 10 files changed, 380 insertions(+), 3 deletions(-) create mode 100644 app-modules/user/resources/views/filament/app-dashboard.blade.php create mode 100644 app-modules/user/src/Filament/User/Pages/Dashboard.php create mode 100644 app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php diff --git a/app-modules/character/src/Entities/LevelEntity.php b/app-modules/character/src/Entities/LevelEntity.php index c5731604d..250cddd11 100644 --- a/app-modules/character/src/Entities/LevelEntity.php +++ b/app-modules/character/src/Entities/LevelEntity.php @@ -73,6 +73,11 @@ public function getPercentageExperience(): float return floor($difference / (100 * 89) * 100); } + public function experiencePercentageRemaining(): float + { + return ($this->experience * ($this->getPercentageExperience())) / 100; + } + private function addExperience(int $experience): void { $this->experience += $experience; diff --git a/app-modules/character/src/Models/Character.php b/app-modules/character/src/Models/Character.php index f6cafca7c..4b1bf12ab 100644 --- a/app-modules/character/src/Models/Character.php +++ b/app-modules/character/src/Models/Character.php @@ -101,4 +101,19 @@ protected function getLevelAttribute(): int { return (new LevelEntity($this->experience))->getLevel(); } + + protected function getExperienceProgressAttribute(): int + { + return (new LevelEntity($this->experience))->getLevelUpStatus(); + } + + protected function getPercentageExperienceAttribute(): float + { + return (new LevelEntity($this->experience))->getPercentageExperience(); + } + + protected function getExperiencePercentageRemainingAttribute(): float + { + return (new LevelEntity($this->experience))->experiencePercentageRemaining(); + } } diff --git a/app-modules/tenant/src/Models/Tenant.php b/app-modules/tenant/src/Models/Tenant.php index 7c8ac75c2..751709b2b 100644 --- a/app-modules/tenant/src/Models/Tenant.php +++ b/app-modules/tenant/src/Models/Tenant.php @@ -4,13 +4,17 @@ namespace He4rt\Tenant\Models; +use He4rt\Character\Models\PastSeason; +use He4rt\Events\Models\EventModel; use He4rt\Provider\Models\Provider; +use He4rt\Season\Models\Season; use He4rt\Tenant\Database\Factories\TenantFactory; use He4rt\User\Models\User; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\Eloquent\Relations\Pivot; use Illuminate\Database\Eloquent\SoftDeletes; @@ -52,6 +56,30 @@ public function providers(): MorphMany return $this->morphMany(Provider::class, 'model'); } + /** + * @return HasMany + */ + public function events(): HasMany + { + return $this->hasMany(EventModel::class); + } + + /** + * @return HasMany + */ + public function seasons(): HasMany + { + return $this->hasMany(Season::class); + } + + /** + * @return HasMany + */ + public function pastSeasons(): HasMany + { + return $this->hasMany(PastSeason::class); + } + protected static function newFactory(): TenantFactory { return TenantFactory::new(); diff --git a/app-modules/user/resources/views/filament/app-dashboard.blade.php b/app-modules/user/resources/views/filament/app-dashboard.blade.php new file mode 100644 index 000000000..b99fcc16d --- /dev/null +++ b/app-modules/user/resources/views/filament/app-dashboard.blade.php @@ -0,0 +1,204 @@ +@php + use Carbon\Carbon; + use Illuminate\Support\Facades\Date; + $userExperience = $this->stats->experience; + $nextLevelXp = $this->stats->percentageExperience + $this->stats->experience; + $level = $this->stats->level; + + $reputation = $this->stats->reputation; + $xpProgress = $this->stats->experienceProgress; + $xpRemaining = $this->stats->experiencePercentageRemaining; + + $address = auth()->user()?->address; + $about = auth()->user()?->information?->about; +@endphp + + +
+ + +
+
Profile
+
+
+
+ + + +

{{ auth()->user()->name }}

+
+

+ Full-stack developer passionate about open source and community building. +

+
+ + + + + São Paulo, SP, Brazil +
+ +
+
+ + + + + Character Stats + + +
+ +
+
+
+ + + Level + {{ $level }} + +
+ + {{ $userExperience }} + / + {{ $nextLevelXp }} + XP + +
+ + +
+
+
+ +
+ {{ (int) $xpRemaining }}% + to next level +
+
+ + +
+
+ +
+

Reputation

+

{{ $reputation }}

+
+
+ +
+ +
+

Daily Bonus

+

+ {{ Date::today()->format('d/M/Y') }} +

+
+
+
+
+
+
+ + +
+ + + Events + + +
+ @forelse ($this->events as $event) +
+ +
+

{{ $event->title }}

+ + {{ $event->end_at < now() ? 'Past' : 'Upcoming' }} + +
+ + +
+ +
+ + {{ Carbon::parse($event->start_at)->format('l') }} +
+ + +
+ + + {{ Carbon::parse($event->starts_at)->format('h:i A') }} + - + {{ Carbon::parse($event->ends_at)->format('h:i A') }} + +
+ + +
+ + {{ $event->participants_count }} participants +
+
+
+ @empty +

No events scheduled for now.

+ @endforelse +
+
+
+
diff --git a/app-modules/user/src/Filament/User/Pages/Dashboard.php b/app-modules/user/src/Filament/User/Pages/Dashboard.php new file mode 100644 index 000000000..386405686 --- /dev/null +++ b/app-modules/user/src/Filament/User/Pages/Dashboard.php @@ -0,0 +1,35 @@ +tenant = auth()->user()->tenants()->where('slug', '=', $tenant->slug)->first(); + } + + #[Computed] + public function events() + { + return $this->tenant->events->where('active', true)->take(5); + } + + #[Computed] + public function stats() + { + return auth()->user()->character()->where('tenant_id', '=', $this->tenant->getKey())->first(); + } +} diff --git a/app-modules/user/src/Plugins/AppUserPanelPlugin.php b/app-modules/user/src/Plugins/AppUserPanelPlugin.php index 3345558ea..557c6b8cc 100644 --- a/app-modules/user/src/Plugins/AppUserPanelPlugin.php +++ b/app-modules/user/src/Plugins/AppUserPanelPlugin.php @@ -7,6 +7,7 @@ use App\Enums\FilamentPanel; use Filament\Contracts\Plugin; use Filament\Panel; +use He4rt\User\Filament\User\Pages\Dashboard; use He4rt\User\Filament\User\Pages\UserProfile; class AppUserPanelPlugin implements Plugin @@ -20,6 +21,7 @@ public function register(Panel $panel): void { $panel->pages([ UserProfile::class, + Dashboard::class, ]); } diff --git a/app-modules/user/src/Providers/UserServiceProvider.php b/app-modules/user/src/Providers/UserServiceProvider.php index bd17496d9..ce04606e3 100644 --- a/app-modules/user/src/Providers/UserServiceProvider.php +++ b/app-modules/user/src/Providers/UserServiceProvider.php @@ -30,5 +30,6 @@ public function register(): void public function boot(): void { $this->loadMigrationsFrom(__DIR__.'/../../database/migrations'); + $this->loadViewsFrom(__DIR__.'/../../resources/views', 'users'); } } diff --git a/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php b/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php new file mode 100644 index 000000000..ec11236cb --- /dev/null +++ b/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php @@ -0,0 +1,70 @@ +user = User::factory()->create(); + $tenant = Tenant::factory() + ->for($this->user, 'owner') + ->afterCreating(fn (Tenant $tenant) => $tenant->members()->attach($this->user)) + ->create(); + + actingAs($this->user); + + Filament::setTenant($tenant); + + $this->character = Character::factory()->create([ + 'user_id' => $this->user->getKey(), + 'tenant_id' => $tenant->getKey(), + ]); + $this->events = EventModel::factory()->count(5)->create([ + 'tenant_id' => $tenant->getKey(), + ]); + Season::factory() + ->recycle($tenant) + ->create([ + 'name' => 'Season 1', + 'started_at' => now()->subMonth(), + 'ended_at' => today(), + ]); +}); + +it('should render', function (): void { + livewire(Dashboard::class) + ->assertOk(); +}); + +it('should be able to see user experience/stats', function (): void { + $nextLevelXp = $this->character->percentageExperience + $this->character->experience; + + livewire(Dashboard::class) + ->assertOk() + ->assertSeeTextInOrder(['Level', $this->character->level]) + ->assertSeeTextInOrder(['Reputation', $this->character->reputation]) + ->assertSeeTextInOrder([$this->character->experience, '/', $nextLevelXp]) + ->assertSeeTextInOrder([(int) $this->character->experiencePercentageRemaining, '%', 'to next level']); +}); + +it('should be able to see events details', function (): void { + $this->events->each(function (EventModel $event): void { + livewire(Dashboard::class) + ->assertOk() + ->assertSeeText($event->title) + ->assertSeeText('Past') + ->assertSeeText(Date::parse($event->starts_at)->format('h:i A')) + ->assertSeeText(Date::parse($event->ends_at)->format('h:i A')); + }); +}); diff --git a/app/Providers/Filament/UserPanelProvider.php b/app/Providers/Filament/UserPanelProvider.php index b60ccc92f..f6e126f07 100644 --- a/app/Providers/Filament/UserPanelProvider.php +++ b/app/Providers/Filament/UserPanelProvider.php @@ -4,12 +4,12 @@ namespace App\Providers\Filament; +use He4rt\User\Filament\User\Pages\Dashboard; use Filament\Actions\Action; use Filament\Http\Middleware\Authenticate; use Filament\Http\Middleware\AuthenticateSession; use Filament\Http\Middleware\DisableBladeIconComponents; use Filament\Http\Middleware\DispatchServingFilamentEvent; -use Filament\Pages\Dashboard; use Filament\Panel; use Filament\PanelProvider; use Filament\Support\Colors\Color; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 276f797a3..4b39424b2 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -5,6 +5,9 @@ namespace Database\Seeders; // use Illuminate\Database\Console\Seeds\WithoutModelEvents; +use He4rt\Character\Models\Character; +use He4rt\Events\Models\EventModel; +use He4rt\Season\Models\Season; use He4rt\Tenant\Models\Tenant; use He4rt\User\Models\User; use Illuminate\Database\Seeder; @@ -25,8 +28,7 @@ public function run(): void 'email' => 'admin@admin.com', 'password' => Hash::make('admin'), ]); - - Tenant::factory() + $tenant = Tenant::factory() ->for($user, 'owner') ->afterCreating(fn (Tenant $tenant) => $tenant->members()->attach($user)) ->create([ @@ -34,5 +36,20 @@ public function run(): void 'slug' => 'he4rt', ]); + Character::factory()->create([ + 'user_id' => $user->getKey(), + 'tenant_id' => $tenant->getKey(), + ]); + EventModel::factory()->count(10)->create([ + 'tenant_id' => $tenant->getKey(), + ]); + + Season::factory() + ->recycle($tenant) + ->create([ + 'name' => 'Season 1', + 'started_at' => now()->subMonth(), + 'ended_at' => today(), + ]); } } From 91929612c93ddbcd14fb18a33b8756b7298de18b Mon Sep 17 00:00:00 2001 From: RichardGL11 Date: Mon, 10 Nov 2025 18:47:51 -0300 Subject: [PATCH 02/25] style: pint --- .../user/tests/Feature/Filament/App/Pages/DashboardPageTest.php | 2 +- app/Providers/Filament/UserPanelProvider.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php b/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php index ec11236cb..f9ae86db3 100644 --- a/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php +++ b/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php @@ -2,7 +2,6 @@ declare(strict_types=1); -use Illuminate\Support\Facades\Date; use Filament\Facades\Filament; use He4rt\Character\Models\Character; use He4rt\Events\Models\EventModel; @@ -10,6 +9,7 @@ use He4rt\Tenant\Models\Tenant; use He4rt\User\Filament\User\Pages\Dashboard; use He4rt\User\Models\User; +use Illuminate\Support\Facades\Date; use function Pest\Laravel\actingAs; use function Pest\Livewire\livewire; diff --git a/app/Providers/Filament/UserPanelProvider.php b/app/Providers/Filament/UserPanelProvider.php index f6e126f07..17eb204b0 100644 --- a/app/Providers/Filament/UserPanelProvider.php +++ b/app/Providers/Filament/UserPanelProvider.php @@ -4,7 +4,6 @@ namespace App\Providers\Filament; -use He4rt\User\Filament\User\Pages\Dashboard; use Filament\Actions\Action; use Filament\Http\Middleware\Authenticate; use Filament\Http\Middleware\AuthenticateSession; @@ -14,6 +13,7 @@ use Filament\PanelProvider; use Filament\Support\Colors\Color; use He4rt\Tenant\Models\Tenant; +use He4rt\User\Filament\User\Pages\Dashboard; use He4rt\User\Filament\User\Pages\UserProfile; use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; use Illuminate\Cookie\Middleware\EncryptCookies; From 2a994d0fc748e493e5b356603ee8f0a1cbd16859 Mon Sep 17 00:00:00 2001 From: RichardGL11 Date: Tue, 11 Nov 2025 17:20:45 -0300 Subject: [PATCH 03/25] fix: fixing bug on Dashboard --- app-modules/user/src/Filament/User/Pages/Dashboard.php | 4 ++-- app/Providers/Filament/UserPanelProvider.php | 2 +- package-lock.json | 4 ---- resources/css/filament/user/theme.css | 5 +++++ vite.config.js | 7 ++++++- 5 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 resources/css/filament/user/theme.css diff --git a/app-modules/user/src/Filament/User/Pages/Dashboard.php b/app-modules/user/src/Filament/User/Pages/Dashboard.php index 386405686..0d1d26a32 100644 --- a/app-modules/user/src/Filament/User/Pages/Dashboard.php +++ b/app-modules/user/src/Filament/User/Pages/Dashboard.php @@ -10,10 +10,10 @@ class Dashboard extends \Filament\Pages\Dashboard { - public Tenant $tenant; - protected string $view = 'users::filament.app-dashboard'; + private Tenant $tenant; + public function mount(): void { /** @var Tenant $tenant */ diff --git a/app/Providers/Filament/UserPanelProvider.php b/app/Providers/Filament/UserPanelProvider.php index 17eb204b0..4086d50f8 100644 --- a/app/Providers/Filament/UserPanelProvider.php +++ b/app/Providers/Filament/UserPanelProvider.php @@ -32,7 +32,7 @@ public function panel(Panel $panel): Panel ->path('app') ->login() ->sidebarCollapsibleOnDesktop() - ->viteTheme('resources/css/filament/admin/theme.css') + ->viteTheme('resources/css/filament/user/theme.css') ->tenant(Tenant::class, 'slug', 'ownedTenants') ->userMenuItems([ Action::make('settings') diff --git a/package-lock.json b/package-lock.json index 38e365a02..9c8c66c00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2347,7 +2347,6 @@ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -2726,7 +2725,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -2770,7 +2768,6 @@ "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -2873,7 +2870,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, diff --git a/resources/css/filament/user/theme.css b/resources/css/filament/user/theme.css new file mode 100644 index 000000000..403f3c778 --- /dev/null +++ b/resources/css/filament/user/theme.css @@ -0,0 +1,5 @@ +@import '../../../../vendor/filament/filament/resources/css/theme.css'; + +@source '../../../../app/Filament/**/*'; +@source '../../../../resources/views/filament/**/*'; +@source '../../../../app-modules/**/resources/views/**/*'; diff --git a/vite.config.js b/vite.config.js index c1a8fd56c..bb9c16ad0 100644 --- a/vite.config.js +++ b/vite.config.js @@ -5,7 +5,12 @@ import tailwindcss from '@tailwindcss/vite'; export default defineConfig({ plugins: [ laravel({ - input: ['resources/css/app.css', 'resources/js/app.js', 'resources/css/filament/admin/theme.css'], + input: [ + 'resources/css/app.css', + 'resources/js/app.js', + 'resources/css/filament/admin/theme.css', + 'resources/css/filament/user/theme.css', + ], refresh: true, }), tailwindcss(), From 4410f55cd83870a7147cb066f4a51713d2948fd4 Mon Sep 17 00:00:00 2001 From: RichardGL11 Date: Tue, 11 Nov 2025 22:14:52 -0300 Subject: [PATCH 04/25] wip: list events page --- .../resources/views/app/list-events.blade.php | 164 ++++++++++++++++++ .../events/src/AdminEventPanelPlugin.php | 4 +- .../events/src/AppEventPanelPlugin.php | 27 +++ .../Resources/Events/EventResource.php | 12 +- .../Resources/Events/Pages/CreateEvent.php | 4 +- .../Resources/Events/Pages/EditEvent.php | 4 +- .../Resources/Events/Pages/ListEvents.php | 4 +- .../Resources/Events/Schemas/EventForm.php | 2 +- .../Resources/Events/Tables/EventsTable.php | 2 +- .../Resources/Talks/Pages/CreateTalk.php | 4 +- .../Resources/Talks/Pages/EditTalk.php | 4 +- .../Resources/Talks/Pages/ListTalks.php | 4 +- .../Resources/Talks/Schemas/TalkForm.php | 2 +- .../Resources/Talks/Tables/TalksTable.php | 2 +- .../Resources/Talks/TalkResource.php | 12 +- .../App/EventModels/EventModelResource.php | 31 ++++ .../App/EventModels/Pages/EditEventModel.php | 21 +++ .../App/EventModels/Pages/ListEventModels.php | 21 +++ .../src/Providers/EventsServiceProvider.php | 3 + .../Filament/Admin/Event/CreateEventTest.php | 2 +- .../Filament/Admin/Event/EditEventTest.php | 2 +- .../Filament/Admin/Event/ListEventsTest.php | 2 +- .../Filament/Admin/Talk/CreateTalk.php | 1 - .../Feature/Filament/Admin/Talk/EditTalk.php | 1 - .../Feature/Filament/Admin/Talk/ListTalks.php | 1 - .../Filament/App/Events/ListEventsTest.php | 73 ++++++++ database/seeders/DatabaseSeeder.php | 17 +- 27 files changed, 387 insertions(+), 39 deletions(-) create mode 100644 app-modules/events/resources/views/app/list-events.blade.php create mode 100644 app-modules/events/src/AppEventPanelPlugin.php rename app-modules/events/src/Filament/{ => Admin}/Resources/Events/EventResource.php (70%) rename app-modules/events/src/Filament/{ => Admin}/Resources/Events/Pages/CreateEvent.php (59%) rename app-modules/events/src/Filament/{ => Admin}/Resources/Events/Pages/EditEvent.php (72%) rename app-modules/events/src/Filament/{ => Admin}/Resources/Events/Pages/ListEvents.php (72%) rename app-modules/events/src/Filament/{ => Admin}/Resources/Events/Schemas/EventForm.php (97%) rename app-modules/events/src/Filament/{ => Admin}/Resources/Events/Tables/EventsTable.php (95%) rename app-modules/events/src/Filament/{ => Admin}/Resources/Talks/Pages/CreateTalk.php (59%) rename app-modules/events/src/Filament/{ => Admin}/Resources/Talks/Pages/EditTalk.php (73%) rename app-modules/events/src/Filament/{ => Admin}/Resources/Talks/Pages/ListTalks.php (73%) rename app-modules/events/src/Filament/{ => Admin}/Resources/Talks/Schemas/TalkForm.php (96%) rename app-modules/events/src/Filament/{ => Admin}/Resources/Talks/Tables/TalksTable.php (93%) rename app-modules/events/src/Filament/{ => Admin}/Resources/Talks/TalkResource.php (73%) create mode 100644 app-modules/events/src/Filament/App/EventModels/EventModelResource.php create mode 100644 app-modules/events/src/Filament/App/EventModels/Pages/EditEventModel.php create mode 100644 app-modules/events/src/Filament/App/EventModels/Pages/ListEventModels.php create mode 100644 app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php diff --git a/app-modules/events/resources/views/app/list-events.blade.php b/app-modules/events/resources/views/app/list-events.blade.php new file mode 100644 index 000000000..8d422a2c7 --- /dev/null +++ b/app-modules/events/resources/views/app/list-events.blade.php @@ -0,0 +1,164 @@ + + @php + $events = $this->getTableRecords(); + @endphp + +
+ @foreach ($events as $event) +
+
+
+ {{-- CardTitle: text-base leading-tight --}} +

+ {{ $event->title }} +

+ + {{-- Badge Status: text-xs, shrink-0 --}} + + {{ $event->end_at < now() ? 'Past' : 'Upcoming' }} + +
+ + + + + + + {{ $event->event_type->getLabel() }} + +
+ + {{-- CardContent: space-y-3 --}} +
+

{{ $event->description }}

+ + {{-- Informações Detalhadas: space-y-2 text-xs text-muted-foreground --}} +
+ {{-- Date --}} +
+ {{-- Icon Calendar --}} + + + + + + + + {{ \Carbon\Carbon::parse($event->event_at)->format('d/m/Y') }} + +
+ + {{-- Time --}} +
+ + + + + + {{ \Carbon\Carbon::parse($event->start_at)->format('H:i:s') }} - + {{ \Carbon\Carbon::parse($event->end_at)->format('H:i:s') }} + +
+ + {{-- Location --}} +
+ {{-- Icon MapPin --}} + + + + + {{ $event->location }} +
+ + {{-- Participants --}} +
+ + + + + + + {{ $event->attendees_count }} / {{ $event->max_attendees }} participants +
+
+ @if ($event->attendees()->first()->pivot->status === \He4rt\Events\Enums\AttendingStatusEnum::Attending) + + @elseif ($event->attendees()->first()->pivot->status === \He4rt\Events\Enums\AttendingStatusEnum::Waitlist) + + @endif +
+
+ @endforeach +
+
diff --git a/app-modules/events/src/AdminEventPanelPlugin.php b/app-modules/events/src/AdminEventPanelPlugin.php index c5fb9b2f6..51bfaf0ef 100644 --- a/app-modules/events/src/AdminEventPanelPlugin.php +++ b/app-modules/events/src/AdminEventPanelPlugin.php @@ -7,8 +7,8 @@ use App\Enums\FilamentPanel; use Filament\Contracts\Plugin; use Filament\Panel; -use He4rt\Events\Filament\Resources\Events\EventResource; -use He4rt\Events\Filament\Resources\Talks\TalkResource; +use He4rt\Events\Filament\Admin\Resources\Events\EventResource; +use He4rt\Events\Filament\Admin\Resources\Talks\TalkResource; class AdminEventPanelPlugin implements Plugin { diff --git a/app-modules/events/src/AppEventPanelPlugin.php b/app-modules/events/src/AppEventPanelPlugin.php new file mode 100644 index 000000000..e3d8a6ca6 --- /dev/null +++ b/app-modules/events/src/AppEventPanelPlugin.php @@ -0,0 +1,27 @@ +moduleName('event'); + } + + public function register(Panel $panel): void + { + $panel->resources([ + EventModelResource::class, + ]); + } + + public function boot(Panel $panel): void {} +} diff --git a/app-modules/events/src/Filament/Resources/Events/EventResource.php b/app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php similarity index 70% rename from app-modules/events/src/Filament/Resources/Events/EventResource.php rename to app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php index 4f62281d3..861dda14b 100644 --- a/app-modules/events/src/Filament/Resources/Events/EventResource.php +++ b/app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php @@ -2,18 +2,18 @@ declare(strict_types=1); -namespace He4rt\Events\Filament\Resources\Events; +namespace He4rt\Events\Filament\Admin\Resources\Events; use BackedEnum; use Filament\Resources\Resource; use Filament\Schemas\Schema; use Filament\Support\Icons\Heroicon; use Filament\Tables\Table; -use He4rt\Events\Filament\Resources\Events\Pages\CreateEvent; -use He4rt\Events\Filament\Resources\Events\Pages\EditEvent; -use He4rt\Events\Filament\Resources\Events\Pages\ListEvents; -use He4rt\Events\Filament\Resources\Events\Schemas\EventForm; -use He4rt\Events\Filament\Resources\Events\Tables\EventsTable; +use He4rt\Events\Filament\Admin\Resources\Events\Pages\CreateEvent; +use He4rt\Events\Filament\Admin\Resources\Events\Pages\EditEvent; +use He4rt\Events\Filament\Admin\Resources\Events\Pages\ListEvents; +use He4rt\Events\Filament\Admin\Resources\Events\Schemas\EventForm; +use He4rt\Events\Filament\Admin\Resources\Events\Tables\EventsTable; use He4rt\Events\Models\EventModel; use UnitEnum; diff --git a/app-modules/events/src/Filament/Resources/Events/Pages/CreateEvent.php b/app-modules/events/src/Filament/Admin/Resources/Events/Pages/CreateEvent.php similarity index 59% rename from app-modules/events/src/Filament/Resources/Events/Pages/CreateEvent.php rename to app-modules/events/src/Filament/Admin/Resources/Events/Pages/CreateEvent.php index 066eefc33..dfe249658 100644 --- a/app-modules/events/src/Filament/Resources/Events/Pages/CreateEvent.php +++ b/app-modules/events/src/Filament/Admin/Resources/Events/Pages/CreateEvent.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace He4rt\Events\Filament\Resources\Events\Pages; +namespace He4rt\Events\Filament\Admin\Resources\Events\Pages; use Filament\Resources\Pages\CreateRecord; -use He4rt\Events\Filament\Resources\Events\EventResource; +use He4rt\Events\Filament\Admin\Resources\Events\EventResource; class CreateEvent extends CreateRecord { diff --git a/app-modules/events/src/Filament/Resources/Events/Pages/EditEvent.php b/app-modules/events/src/Filament/Admin/Resources/Events/Pages/EditEvent.php similarity index 72% rename from app-modules/events/src/Filament/Resources/Events/Pages/EditEvent.php rename to app-modules/events/src/Filament/Admin/Resources/Events/Pages/EditEvent.php index e28e20165..70b254a73 100644 --- a/app-modules/events/src/Filament/Resources/Events/Pages/EditEvent.php +++ b/app-modules/events/src/Filament/Admin/Resources/Events/Pages/EditEvent.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace He4rt\Events\Filament\Resources\Events\Pages; +namespace He4rt\Events\Filament\Admin\Resources\Events\Pages; use Filament\Actions\DeleteAction; use Filament\Resources\Pages\EditRecord; -use He4rt\Events\Filament\Resources\Events\EventResource; +use He4rt\Events\Filament\Admin\Resources\Events\EventResource; class EditEvent extends EditRecord { diff --git a/app-modules/events/src/Filament/Resources/Events/Pages/ListEvents.php b/app-modules/events/src/Filament/Admin/Resources/Events/Pages/ListEvents.php similarity index 72% rename from app-modules/events/src/Filament/Resources/Events/Pages/ListEvents.php rename to app-modules/events/src/Filament/Admin/Resources/Events/Pages/ListEvents.php index 75745956d..039da9803 100644 --- a/app-modules/events/src/Filament/Resources/Events/Pages/ListEvents.php +++ b/app-modules/events/src/Filament/Admin/Resources/Events/Pages/ListEvents.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace He4rt\Events\Filament\Resources\Events\Pages; +namespace He4rt\Events\Filament\Admin\Resources\Events\Pages; use Filament\Actions\CreateAction; use Filament\Resources\Pages\ListRecords; -use He4rt\Events\Filament\Resources\Events\EventResource; +use He4rt\Events\Filament\Admin\Resources\Events\EventResource; class ListEvents extends ListRecords { diff --git a/app-modules/events/src/Filament/Resources/Events/Schemas/EventForm.php b/app-modules/events/src/Filament/Admin/Resources/Events/Schemas/EventForm.php similarity index 97% rename from app-modules/events/src/Filament/Resources/Events/Schemas/EventForm.php rename to app-modules/events/src/Filament/Admin/Resources/Events/Schemas/EventForm.php index 61593b7a4..945984964 100644 --- a/app-modules/events/src/Filament/Resources/Events/Schemas/EventForm.php +++ b/app-modules/events/src/Filament/Admin/Resources/Events/Schemas/EventForm.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace He4rt\Events\Filament\Resources\Events\Schemas; +namespace He4rt\Events\Filament\Admin\Resources\Events\Schemas; use Filament\Forms\Components\DateTimePicker; use Filament\Forms\Components\RichEditor; diff --git a/app-modules/events/src/Filament/Resources/Events/Tables/EventsTable.php b/app-modules/events/src/Filament/Admin/Resources/Events/Tables/EventsTable.php similarity index 95% rename from app-modules/events/src/Filament/Resources/Events/Tables/EventsTable.php rename to app-modules/events/src/Filament/Admin/Resources/Events/Tables/EventsTable.php index 7a3592b68..f6260f2e0 100644 --- a/app-modules/events/src/Filament/Resources/Events/Tables/EventsTable.php +++ b/app-modules/events/src/Filament/Admin/Resources/Events/Tables/EventsTable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace He4rt\Events\Filament\Resources\Events\Tables; +namespace He4rt\Events\Filament\Admin\Resources\Events\Tables; use Filament\Actions\BulkActionGroup; use Filament\Actions\DeleteBulkAction; diff --git a/app-modules/events/src/Filament/Resources/Talks/Pages/CreateTalk.php b/app-modules/events/src/Filament/Admin/Resources/Talks/Pages/CreateTalk.php similarity index 59% rename from app-modules/events/src/Filament/Resources/Talks/Pages/CreateTalk.php rename to app-modules/events/src/Filament/Admin/Resources/Talks/Pages/CreateTalk.php index e6dcdd41b..c0cf24a48 100644 --- a/app-modules/events/src/Filament/Resources/Talks/Pages/CreateTalk.php +++ b/app-modules/events/src/Filament/Admin/Resources/Talks/Pages/CreateTalk.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace He4rt\Events\Filament\Resources\Talks\Pages; +namespace He4rt\Events\Filament\Admin\Resources\Talks\Pages; use Filament\Resources\Pages\CreateRecord; -use He4rt\Events\Filament\Resources\Talks\TalkResource; +use He4rt\Events\Filament\Admin\Resources\Talks\TalkResource; class CreateTalk extends CreateRecord { diff --git a/app-modules/events/src/Filament/Resources/Talks/Pages/EditTalk.php b/app-modules/events/src/Filament/Admin/Resources/Talks/Pages/EditTalk.php similarity index 73% rename from app-modules/events/src/Filament/Resources/Talks/Pages/EditTalk.php rename to app-modules/events/src/Filament/Admin/Resources/Talks/Pages/EditTalk.php index 4772d67e5..d13001002 100644 --- a/app-modules/events/src/Filament/Resources/Talks/Pages/EditTalk.php +++ b/app-modules/events/src/Filament/Admin/Resources/Talks/Pages/EditTalk.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace He4rt\Events\Filament\Resources\Talks\Pages; +namespace He4rt\Events\Filament\Admin\Resources\Talks\Pages; use Filament\Actions\DeleteAction; use Filament\Resources\Pages\EditRecord; -use He4rt\Events\Filament\Resources\Talks\TalkResource; +use He4rt\Events\Filament\Admin\Resources\Talks\TalkResource; class EditTalk extends EditRecord { diff --git a/app-modules/events/src/Filament/Resources/Talks/Pages/ListTalks.php b/app-modules/events/src/Filament/Admin/Resources/Talks/Pages/ListTalks.php similarity index 73% rename from app-modules/events/src/Filament/Resources/Talks/Pages/ListTalks.php rename to app-modules/events/src/Filament/Admin/Resources/Talks/Pages/ListTalks.php index 241be2817..4e61d016c 100644 --- a/app-modules/events/src/Filament/Resources/Talks/Pages/ListTalks.php +++ b/app-modules/events/src/Filament/Admin/Resources/Talks/Pages/ListTalks.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace He4rt\Events\Filament\Resources\Talks\Pages; +namespace He4rt\Events\Filament\Admin\Resources\Talks\Pages; use Filament\Actions\CreateAction; use Filament\Resources\Pages\ListRecords; -use He4rt\Events\Filament\Resources\Talks\TalkResource; +use He4rt\Events\Filament\Admin\Resources\Talks\TalkResource; class ListTalks extends ListRecords { diff --git a/app-modules/events/src/Filament/Resources/Talks/Schemas/TalkForm.php b/app-modules/events/src/Filament/Admin/Resources/Talks/Schemas/TalkForm.php similarity index 96% rename from app-modules/events/src/Filament/Resources/Talks/Schemas/TalkForm.php rename to app-modules/events/src/Filament/Admin/Resources/Talks/Schemas/TalkForm.php index 9fb5fdf4d..8bbac6c65 100644 --- a/app-modules/events/src/Filament/Resources/Talks/Schemas/TalkForm.php +++ b/app-modules/events/src/Filament/Admin/Resources/Talks/Schemas/TalkForm.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace He4rt\Events\Filament\Resources\Talks\Schemas; +namespace He4rt\Events\Filament\Admin\Resources\Talks\Schemas; use Filament\Forms\Components\RichEditor; use Filament\Forms\Components\Select; diff --git a/app-modules/events/src/Filament/Resources/Talks/Tables/TalksTable.php b/app-modules/events/src/Filament/Admin/Resources/Talks/Tables/TalksTable.php similarity index 93% rename from app-modules/events/src/Filament/Resources/Talks/Tables/TalksTable.php rename to app-modules/events/src/Filament/Admin/Resources/Talks/Tables/TalksTable.php index 5c3c3ad6c..290660cd3 100644 --- a/app-modules/events/src/Filament/Resources/Talks/Tables/TalksTable.php +++ b/app-modules/events/src/Filament/Admin/Resources/Talks/Tables/TalksTable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace He4rt\Events\Filament\Resources\Talks\Tables; +namespace He4rt\Events\Filament\Admin\Resources\Talks\Tables; use Filament\Actions\BulkActionGroup; use Filament\Actions\DeleteBulkAction; diff --git a/app-modules/events/src/Filament/Resources/Talks/TalkResource.php b/app-modules/events/src/Filament/Admin/Resources/Talks/TalkResource.php similarity index 73% rename from app-modules/events/src/Filament/Resources/Talks/TalkResource.php rename to app-modules/events/src/Filament/Admin/Resources/Talks/TalkResource.php index 1d30ff45b..32c18fe59 100644 --- a/app-modules/events/src/Filament/Resources/Talks/TalkResource.php +++ b/app-modules/events/src/Filament/Admin/Resources/Talks/TalkResource.php @@ -2,18 +2,18 @@ declare(strict_types=1); -namespace He4rt\Events\Filament\Resources\Talks; +namespace He4rt\Events\Filament\Admin\Resources\Talks; use BackedEnum; use Filament\Resources\Resource; use Filament\Schemas\Schema; use Filament\Support\Icons\Heroicon; use Filament\Tables\Table; -use He4rt\Events\Filament\Resources\Talks\Pages\CreateTalk; -use He4rt\Events\Filament\Resources\Talks\Pages\EditTalk; -use He4rt\Events\Filament\Resources\Talks\Pages\ListTalks; -use He4rt\Events\Filament\Resources\Talks\Schemas\TalkForm; -use He4rt\Events\Filament\Resources\Talks\Tables\TalksTable; +use He4rt\Events\Filament\Admin\Resources\Talks\Pages\CreateTalk; +use He4rt\Events\Filament\Admin\Resources\Talks\Pages\EditTalk; +use He4rt\Events\Filament\Admin\Resources\Talks\Pages\ListTalks; +use He4rt\Events\Filament\Admin\Resources\Talks\Schemas\TalkForm; +use He4rt\Events\Filament\Admin\Resources\Talks\Tables\TalksTable; use He4rt\Events\Models\Talk; use UnitEnum; diff --git a/app-modules/events/src/Filament/App/EventModels/EventModelResource.php b/app-modules/events/src/Filament/App/EventModels/EventModelResource.php new file mode 100644 index 000000000..8f182702c --- /dev/null +++ b/app-modules/events/src/Filament/App/EventModels/EventModelResource.php @@ -0,0 +1,31 @@ + ListEventModels::route('/'), + ]; + } +} diff --git a/app-modules/events/src/Filament/App/EventModels/Pages/EditEventModel.php b/app-modules/events/src/Filament/App/EventModels/Pages/EditEventModel.php new file mode 100644 index 000000000..816ba664e --- /dev/null +++ b/app-modules/events/src/Filament/App/EventModels/Pages/EditEventModel.php @@ -0,0 +1,21 @@ +where('active', true)->with('attendees'); + } +} diff --git a/app-modules/events/src/Providers/EventsServiceProvider.php b/app-modules/events/src/Providers/EventsServiceProvider.php index 75e199726..7ea32b505 100644 --- a/app-modules/events/src/Providers/EventsServiceProvider.php +++ b/app-modules/events/src/Providers/EventsServiceProvider.php @@ -7,6 +7,7 @@ use App\Enums\FilamentPanel; use Filament\Panel; use He4rt\Events\AdminEventPanelPlugin; +use He4rt\Events\AppEventPanelPlugin; use Illuminate\Support\ServiceProvider; class EventsServiceProvider extends ServiceProvider @@ -16,6 +17,7 @@ public function register(): void Panel::configureUsing(function (Panel $panel): void { match ($panel->currentPanel()) { FilamentPanel::Admin => $panel->plugin(new AdminEventPanelPlugin), + FilamentPanel::User => $panel->plugin(new AppEventPanelPlugin), default => null, }; }); @@ -24,5 +26,6 @@ public function register(): void public function boot(): void { $this->loadMigrationsFrom(__DIR__.'/../../database/migrations'); + $this->loadViewsFrom(__DIR__.'/../../resources/views', 'events'); } } diff --git a/app-modules/events/tests/Feature/Filament/Admin/Event/CreateEventTest.php b/app-modules/events/tests/Feature/Filament/Admin/Event/CreateEventTest.php index cb236ecfe..72b5749b8 100644 --- a/app-modules/events/tests/Feature/Filament/Admin/Event/CreateEventTest.php +++ b/app-modules/events/tests/Feature/Filament/Admin/Event/CreateEventTest.php @@ -5,7 +5,7 @@ use App\Enums\FilamentPanel; use Filament\Facades\Filament; use He4rt\Events\Enums\EventTypeEnum; -use He4rt\Events\Filament\Resources\Events\Pages\CreateEvent; +use He4rt\Events\Filament\Admin\Resources\Events\Pages\CreateEvent; use He4rt\Events\Models\EventModel; use Illuminate\Support\Facades\Date; diff --git a/app-modules/events/tests/Feature/Filament/Admin/Event/EditEventTest.php b/app-modules/events/tests/Feature/Filament/Admin/Event/EditEventTest.php index f324bdb53..12ba92a84 100644 --- a/app-modules/events/tests/Feature/Filament/Admin/Event/EditEventTest.php +++ b/app-modules/events/tests/Feature/Filament/Admin/Event/EditEventTest.php @@ -4,7 +4,7 @@ use App\Enums\FilamentPanel; use Filament\Facades\Filament; -use He4rt\Events\Filament\Resources\Events\Pages\EditEvent; +use He4rt\Events\Filament\Admin\Resources\Events\Pages\EditEvent; use He4rt\Events\Models\EventModel; use function Pest\Livewire\livewire; diff --git a/app-modules/events/tests/Feature/Filament/Admin/Event/ListEventsTest.php b/app-modules/events/tests/Feature/Filament/Admin/Event/ListEventsTest.php index 200ff7b72..6db39eb71 100644 --- a/app-modules/events/tests/Feature/Filament/Admin/Event/ListEventsTest.php +++ b/app-modules/events/tests/Feature/Filament/Admin/Event/ListEventsTest.php @@ -4,7 +4,7 @@ use App\Enums\FilamentPanel; use Filament\Facades\Filament; -use He4rt\Events\Filament\Resources\Events\Pages\ListEvents; +use He4rt\Events\Filament\Admin\Resources\Events\Pages\ListEvents; use function Pest\Livewire\livewire; diff --git a/app-modules/events/tests/Feature/Filament/Admin/Talk/CreateTalk.php b/app-modules/events/tests/Feature/Filament/Admin/Talk/CreateTalk.php index 032605cd4..6790311d7 100644 --- a/app-modules/events/tests/Feature/Filament/Admin/Talk/CreateTalk.php +++ b/app-modules/events/tests/Feature/Filament/Admin/Talk/CreateTalk.php @@ -5,7 +5,6 @@ use App\Enums\FilamentPanel; use Filament\Facades\Filament; use He4rt\Events\Enums\Talks\TalkStatusEnum; -use He4rt\Events\Filament\Resources\Talks\Pages\CreateTalk; use He4rt\Events\Models\EventModel; use He4rt\Events\Models\Talk; use He4rt\User\Models\User; diff --git a/app-modules/events/tests/Feature/Filament/Admin/Talk/EditTalk.php b/app-modules/events/tests/Feature/Filament/Admin/Talk/EditTalk.php index 545e976dd..5c4e9732d 100644 --- a/app-modules/events/tests/Feature/Filament/Admin/Talk/EditTalk.php +++ b/app-modules/events/tests/Feature/Filament/Admin/Talk/EditTalk.php @@ -4,7 +4,6 @@ use App\Enums\FilamentPanel; use Filament\Facades\Filament; -use He4rt\Events\Filament\Resources\Talks\Pages\EditTalk; use He4rt\Events\Models\Talk; use function Pest\Livewire\livewire; diff --git a/app-modules/events/tests/Feature/Filament/Admin/Talk/ListTalks.php b/app-modules/events/tests/Feature/Filament/Admin/Talk/ListTalks.php index db0cb4469..a6b7d8b83 100644 --- a/app-modules/events/tests/Feature/Filament/Admin/Talk/ListTalks.php +++ b/app-modules/events/tests/Feature/Filament/Admin/Talk/ListTalks.php @@ -4,7 +4,6 @@ use App\Enums\FilamentPanel; use Filament\Facades\Filament; -use He4rt\Events\Filament\Resources\Talks\Pages\ListTalks; use function Pest\Livewire\livewire; diff --git a/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php b/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php new file mode 100644 index 000000000..50fb6a4b5 --- /dev/null +++ b/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php @@ -0,0 +1,73 @@ +value); + actingAs(User::factory()->create()); + $this->tenant = Tenant::factory()->create(); + Filament::setTenant($this->tenant); + + $this->events = EventModel::factory()->count(10) + ->afterCreating(function (EventModel $event): void { + $attendees = User::factory()->count(fake()->numberBetween(3, 10))->create(); + + foreach ($attendees as $user) { + $event->attendees()->attach($user->id, [ + 'status' => fake()->randomElement(AttendingStatusEnum::cases()), + ]); + } + }) + ->create([ + 'tenant_id' => $this->tenant->getKey(), + ]); +}); + +it('should render', function (): void { + livewire(ListEventModels::class, ['tenant' => $this->tenant->slug]) + ->assertOk(); +}); + +it('should render events', function (): void { + $this->events->each(function (EventModel $event): void { + livewire(ListEventModels::class, ['tenant' => $this->tenant->slug]) + ->assertOk() + ->assertSeeText($event->title) + ->assertSeeText($event->location) + ->assertSeeText(Date::parse($event->event_at)->format('d/m/Y')) + ->assertSeeText(Date::parse($event->start_at)->format('H:i:s')) + ->assertSeeText(Date::parse($event->end_at)->format('H:i:s')) + ->assertSeeText($event->event_type->getLabel()); + }); +}); + +it('should see Register or Join Waitlist based on status', function ($status, $text, $dontSeeText): void { + $this->events->each(function (EventModel $event) use ($status): void { + $attendeeIds = $event->attendees->pluck('id'); + $event->attendees()->updateExistingPivot( + $attendeeIds, + ['status' => $status] + ); + }); + + $this->events->fresh(); + livewire(ListEventModels::class, ['tenant' => $this->tenant->slug]) + ->assertOk() + ->assertSeeText($text) + ->assertDontSeeText($dontSeeText); +})->with([ + 'attending' => [AttendingStatusEnum::Attending->value, 'Join', 'Join Waitlist'], + 'waitlist' => [AttendingStatusEnum::Waitlist->value, 'Join Waitlist', 'Join123'], +]); diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 4b39424b2..2ef2a9e65 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -6,6 +6,7 @@ // use Illuminate\Database\Console\Seeds\WithoutModelEvents; use He4rt\Character\Models\Character; +use He4rt\Events\Enums\AttendingStatusEnum; use He4rt\Events\Models\EventModel; use He4rt\Season\Models\Season; use He4rt\Tenant\Models\Tenant; @@ -40,9 +41,19 @@ public function run(): void 'user_id' => $user->getKey(), 'tenant_id' => $tenant->getKey(), ]); - EventModel::factory()->count(10)->create([ - 'tenant_id' => $tenant->getKey(), - ]); + EventModel::factory()->count(10) + ->afterCreating(function (EventModel $event): void { + $attendees = User::factory()->count(fake()->numberBetween(3, 10))->create(); + + foreach ($attendees as $user) { + $event->attendees()->attach($user->id, [ + 'status' => fake()->randomElement(AttendingStatusEnum::cases()), + ]); + } + }) + ->create([ + 'tenant_id' => $tenant->getKey(), + ]); Season::factory() ->recycle($tenant) From 646d0dff195a6379eb34c08d7eaa12d7ceadde49 Mon Sep 17 00:00:00 2001 From: Clintonrocha98 Date: Tue, 11 Nov 2025 23:33:13 -0300 Subject: [PATCH 05/25] feat(seeder): add user information and address factories to DatabaseSeeder --- database/seeders/DatabaseSeeder.php | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 2ef2a9e65..d5367d892 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -10,6 +10,8 @@ use He4rt\Events\Models\EventModel; use He4rt\Season\Models\Season; use He4rt\Tenant\Models\Tenant; +use He4rt\User\Models\Address; +use He4rt\User\Models\Information; use He4rt\User\Models\User; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\Hash; @@ -23,12 +25,17 @@ public function run(): void { // \App\Models\User::factory(10)->create(); - $user = User::factory()->create([ - 'username' => 'admin', - 'name' => 'admin', - 'email' => 'admin@admin.com', - 'password' => Hash::make('admin'), - ]); + $user = User::factory() + ->create([ + 'username' => 'admin', + 'name' => 'admin', + 'email' => 'admin@admin.com', + 'password' => Hash::make('admin'), + ]); + + Information::factory()->recycle($user)->create(); + Address::factory()->recycle($user)->create(); + $tenant = Tenant::factory() ->for($user, 'owner') ->afterCreating(fn (Tenant $tenant) => $tenant->members()->attach($user)) @@ -62,5 +69,6 @@ public function run(): void 'started_at' => now()->subMonth(), 'ended_at' => today(), ]); + } } From 24bf2f026d6b8ff9f387603aea6a1df14f7f933c Mon Sep 17 00:00:00 2001 From: Clintonrocha98 Date: Tue, 11 Nov 2025 23:33:55 -0300 Subject: [PATCH 06/25] feat(dashboard): enhance user profile display and character stats calculations --- .../views/filament/app-dashboard.blade.php | 137 +++++++++--------- 1 file changed, 66 insertions(+), 71 deletions(-) diff --git a/app-modules/user/resources/views/filament/app-dashboard.blade.php b/app-modules/user/resources/views/filament/app-dashboard.blade.php index b99fcc16d..68c3eddc1 100644 --- a/app-modules/user/resources/views/filament/app-dashboard.blade.php +++ b/app-modules/user/resources/views/filament/app-dashboard.blade.php @@ -2,94 +2,89 @@ use Carbon\Carbon; use Illuminate\Support\Facades\Date; $userExperience = $this->stats->experience; - $nextLevelXp = $this->stats->percentageExperience + $this->stats->experience; $level = $this->stats->level; $reputation = $this->stats->reputation; - $xpProgress = $this->stats->experienceProgress; - $xpRemaining = $this->stats->experiencePercentageRemaining; + $experienceRequiredForNextLevel = $this->stats->experienceProgress; + $experienceRemaining = $this->stats->experiencePercentageRemaining; + $nextLevelExperience = $experienceRequiredForNextLevel + $this->stats->experience; + $experiencePercentage = $nextLevelExperience > 0 ? ($userExperience / $nextLevelExperience) * 100 : 0; - $address = auth()->user()?->address; - $about = auth()->user()?->information?->about; + $user = auth()->user(); + + $address = $user?->address; + + $userFullAddress = $address ? implode(', ', array_filter([$address->city ?? null, $address->state ?? null, $address->country ?? null])) : ''; + + $userName = $user?->name ?? ''; + $profileAbout = $user?->information?->about ?? ''; + $profileAvatarUrl = 'https://ui-avatars.com/api/?name=' . urlencode($user?->name ?? '') . '&background=0D8ABC&color=fff'; + $githubUrl = $user?->information?->github_url ?? null; + $linkedinUrl = $user?->information?->linkedin_url ?? null; @endphp
-
-
Profile
-
-
+

Profile

+ +
- + -

{{ auth()->user()->name }}

+

{{ $userName }}

-

- Full-stack developer passionate about open source and community building. +

+ {{ $profileAbout }}

-
- - - - - São Paulo, SP, Brazil -
- + + @if (! empty($userFullAddress)) +
+ + {{ $userFullAddress }} +
+ @endif + + @if (! empty($githubUrl) || ! empty($linkedinUrl)) +
+ @if (! empty($githubUrl)) + + + GitHub + + @endif + + @if (! empty($linkedinUrl)) + + + LinkedIn + + @endif +
+ @endif
- - Character Stats - +

Character Stats

@@ -105,7 +100,7 @@ class="focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-de {{ $userExperience }} / - {{ $nextLevelXp }} + {{ $nextLevelExperience }} XP
@@ -116,12 +111,12 @@ class="fi-progress fi-color-primary relative h-2 w-full overflow-hidden rounded- >
-
- {{ (int) $xpRemaining }}% +
+ {{ (int) $experienceRequiredForNextLevel }} to next level
@@ -132,7 +127,7 @@ class="fi-progress-bar bg-primary-500 absolute top-0 left-0 h-full transition-al

Reputation

-

{{ $reputation }}

+

{{ $reputation }}

@@ -140,7 +135,7 @@ class="fi-progress-bar bg-primary-500 absolute top-0 left-0 h-full transition-al

Daily Bonus

-

+

{{ Date::today()->format('d/M/Y') }}

From f6aa06c1f4bbbdcdefadb5bd007b3d7d6e0e68d6 Mon Sep 17 00:00:00 2001 From: Clintonrocha98 Date: Tue, 11 Nov 2025 23:37:36 -0300 Subject: [PATCH 07/25] style: pint and rector --- .../events/tests/Feature/Filament/App/Events/ListEventsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php b/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php index 50fb6a4b5..779b8f2b0 100644 --- a/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php +++ b/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php @@ -2,7 +2,6 @@ declare(strict_types=1); -use Illuminate\Support\Facades\Date; use App\Enums\FilamentPanel; use Filament\Facades\Filament; use He4rt\Events\Enums\AttendingStatusEnum; @@ -10,6 +9,7 @@ use He4rt\Events\Models\EventModel; use He4rt\Tenant\Models\Tenant; use He4rt\User\Models\User; +use Illuminate\Support\Facades\Date; use function Pest\Laravel\actingAs; use function Pest\Livewire\livewire; From fbd5fa3977be11e36e8c8cba5c2c4006bc6ce6c1 Mon Sep 17 00:00:00 2001 From: RichardGL11 Date: Wed, 12 Nov 2025 16:02:40 -0300 Subject: [PATCH 08/25] feat: list events page --- .../resources/views/app/list-events.blade.php | 131 ++++-------------- .../events/src/Actions/AttendEventAction.php | 19 +++ .../App/EventModels/EventModelResource.php | 2 +- .../App/EventModels/Pages/ListEventModels.php | 25 ++++ app-modules/events/src/Models/EventModel.php | 10 ++ .../Filament/App/Events/ListEventsTest.php | 61 +++++++- 6 files changed, 143 insertions(+), 105 deletions(-) create mode 100644 app-modules/events/src/Actions/AttendEventAction.php diff --git a/app-modules/events/resources/views/app/list-events.blade.php b/app-modules/events/resources/views/app/list-events.blade.php index 8d422a2c7..306606d51 100644 --- a/app-modules/events/resources/views/app/list-events.blade.php +++ b/app-modules/events/resources/views/app/list-events.blade.php @@ -6,159 +6,84 @@
@foreach ($events as $event)
- {{-- CardTitle: text-base leading-tight --}}

{{ $event->title }}

- - {{-- Badge Status: text-xs, shrink-0 --}} - {{ $event->end_at < now() ? 'Past' : 'Upcoming' }} - +
- - - - - {{ $event->event_type->getLabel() }} - +
- {{-- CardContent: space-y-3 --}}

{{ $event->description }}

- {{-- Informações Detalhadas: space-y-2 text-xs text-muted-foreground --}}
{{-- Date --}}
- {{-- Icon Calendar --}} - - - - - - + {{ \Carbon\Carbon::parse($event->event_at)->format('d/m/Y') }}
- {{-- Time --}}
- - - - + {{ \Carbon\Carbon::parse($event->start_at)->format('H:i:s') }} - {{ \Carbon\Carbon::parse($event->end_at)->format('H:i:s') }}
- {{-- Location --}}
- {{-- Icon MapPin --}} - - - - + {{ $event->location }}
- {{-- Participants --}}
- - - - - - + {{ $event->attendees_count }} / {{ $event->max_attendees }} participants
- @if ($event->attendees()->first()->pivot->status === \He4rt\Events\Enums\AttendingStatusEnum::Attending) - - @elseif ($event->attendees()->first()->pivot->status === \He4rt\Events\Enums\AttendingStatusEnum::Waitlist) - + + @elseif ($event->participate(auth()->user()->getKey()) === true && ! $event->isPast()) + + Leave + @endif
@endforeach
+
diff --git a/app-modules/events/src/Actions/AttendEventAction.php b/app-modules/events/src/Actions/AttendEventAction.php new file mode 100644 index 000000000..db367897f --- /dev/null +++ b/app-modules/events/src/Actions/AttendEventAction.php @@ -0,0 +1,19 @@ +attendees()->first()->pivot->status; + $eventModel->attend(auth()->user()->id, $attendingStatus); + } +} diff --git a/app-modules/events/src/Filament/App/EventModels/EventModelResource.php b/app-modules/events/src/Filament/App/EventModels/EventModelResource.php index 8f182702c..a2912d86b 100644 --- a/app-modules/events/src/Filament/App/EventModels/EventModelResource.php +++ b/app-modules/events/src/Filament/App/EventModels/EventModelResource.php @@ -14,7 +14,7 @@ class EventModelResource extends Resource { protected static ?string $model = EventModel::class; - protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack; + protected static string|BackedEnum|null $navigationIcon = Heroicon::Ticket; protected static ?string $recordTitleAttribute = 'title'; diff --git a/app-modules/events/src/Filament/App/EventModels/Pages/ListEventModels.php b/app-modules/events/src/Filament/App/EventModels/Pages/ListEventModels.php index 3e41c6f7f..87cd96bc4 100644 --- a/app-modules/events/src/Filament/App/EventModels/Pages/ListEventModels.php +++ b/app-modules/events/src/Filament/App/EventModels/Pages/ListEventModels.php @@ -4,8 +4,11 @@ namespace He4rt\Events\Filament\App\EventModels\Pages; +use Filament\Notifications\Notification; use Filament\Resources\Pages\ListRecords; +use He4rt\Events\Actions\AttendEventAction; use He4rt\Events\Filament\App\EventModels\EventModelResource; +use He4rt\Events\Models\EventModel; use Illuminate\Database\Eloquent\Builder; class ListEventModels extends ListRecords @@ -14,6 +17,28 @@ class ListEventModels extends ListRecords protected static string $resource = EventModelResource::class; + public function attend(string|int $eventModelId): void + { + $eventModel = EventModel::query()->find($eventModelId); + app(AttendEventAction::class)->execute($eventModel); + + Notification::make() + ->success() + ->body('Send Successfully') + ->send(); + } + + public function leave(string|int $eventModelId): void + { + $eventModel = EventModel::query()->find($eventModelId); + $eventModel->leave(auth()->user()->getKey()); + + Notification::make() + ->success() + ->body('Leaved Event Successfully') + ->send(); + } + protected function modifyQueryWithActiveTab(Builder $query): Builder { return $query->where('active', true)->with('attendees'); diff --git a/app-modules/events/src/Models/EventModel.php b/app-modules/events/src/Models/EventModel.php index ccdb12728..dc2ea9dc1 100644 --- a/app-modules/events/src/Models/EventModel.php +++ b/app-modules/events/src/Models/EventModel.php @@ -84,6 +84,11 @@ public function attend(mixed $userId, AttendingStatusEnum $status = AttendingSta return true; } + public function isPast(): bool + { + return $this->end_at < now(); + } + public function leave(mixed $userId): bool { $eventAttend = $this->attendees()->where('user_id', $userId)->first(); @@ -103,6 +108,11 @@ public function leave(mixed $userId): bool return true; } + public function participate($userId): bool + { + return $this->attendees()->where('user_id', $userId)->exists(); + } + /** * @return BelongsTo */ diff --git a/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php b/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php index 779b8f2b0..4296009b4 100644 --- a/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php +++ b/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php @@ -4,6 +4,7 @@ use App\Enums\FilamentPanel; use Filament\Facades\Filament; +use Filament\Notifications\Notification; use He4rt\Events\Enums\AttendingStatusEnum; use He4rt\Events\Filament\App\EventModels\Pages\ListEventModels; use He4rt\Events\Models\EventModel; @@ -22,7 +23,7 @@ $this->events = EventModel::factory()->count(10) ->afterCreating(function (EventModel $event): void { - $attendees = User::factory()->count(fake()->numberBetween(3, 10))->create(); + $attendees = User::factory()->count(4)->create(); foreach ($attendees as $user) { $event->attendees()->attach($user->id, [ @@ -32,6 +33,7 @@ }) ->create([ 'tenant_id' => $this->tenant->getKey(), + 'end_at' => Date::tomorrow(), ]); }); @@ -71,3 +73,60 @@ 'attending' => [AttendingStatusEnum::Attending->value, 'Join', 'Join Waitlist'], 'waitlist' => [AttendingStatusEnum::Waitlist->value, 'Join Waitlist', 'Join123'], ]); + +it('should be able to participate to an event', function (): void { + $event = $this->events->first(); + livewire(ListEventModels::class, ['tenant' => $this->tenant->slug]) + ->assertOk() + ->call('attend', $event->getKey()) + ->assertNotified( + Notification::make() + ->success() + ->body('Send Successfully'), + ); + + expect($event->attendees()->count())->toBe(5) + ->and($event->attendees()->get()->last()->getKey())->toBe(auth()->user()->getKey()); +}); + +it('should go to waitlist', function (): void { + $event = $this->events->first(); + $attendeeIds = $event->attendees->pluck('id'); + + $event->attendees()->updateExistingPivot( + $attendeeIds, + ['status' => AttendingStatusEnum::Waitlist], + ); + + livewire(ListEventModels::class, ['tenant' => $this->tenant->slug]) + ->assertOk() + ->call('attend', $event->getKey()) + ->assertNotified( + Notification::make() + ->success() + ->body('Send Successfully'), + ); + + expect($event->attendees()->count())->toBe(5) + ->and($event->fresh()->waitlist_count)->toBe(1) + ->and($event->participate(auth()->user()->id))->toBeTrue(); +}); + +it('should be able to leave an event', function (): void { + $event = $this->events->first(); + $event->attendees()->attach( + auth()->user()->getKey(), + ['status' => AttendingStatusEnum::Waitlist] + ); + livewire(ListEventModels::class, ['tenant' => $this->tenant->slug]) + ->assertOk() + ->call('leave', $event->getKey()) + ->assertNotified(Notification::make() + ->success() + ->body('Leaved Event Successfully') + ->send()); + + $event->refresh(); + expect($event->attendees()->count())->toBe(4) + ->and($event->participate(auth()->user()->id))->tobeFalse(); +}); From 28db8cefa9af27d29de17ebf308b70f7a60ded42 Mon Sep 17 00:00:00 2001 From: RichardGL11 Date: Wed, 12 Nov 2025 17:32:20 -0300 Subject: [PATCH 09/25] feat(app-panel): talk resource --- .../events/database/factories/TalkFactory.php | 3 +- .../events/src/AppEventPanelPlugin.php | 2 + .../Filament/App/Talks/Pages/CreateTalk.php | 13 +++ .../Filament/App/Talks/Pages/ListTalks.php | 21 +++++ .../Filament/App/Talks/Schemas/TalkForm.php | 56 +++++++++++++ .../Filament/App/Talks/Tables/TalksTable.php | 51 ++++++++++++ .../src/Filament/App/Talks/TalkResource.php | 45 +++++++++++ .../Filament/App/Events/ListEventsTest.php | 6 ++ .../Filament/App/Talks/CreateTalkTest.php | 80 +++++++++++++++++++ .../Filament/App/Talks/ListTalkTest.php | 33 ++++++++ .../Filament/App/Pages/DashboardPageTest.php | 2 +- 11 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 app-modules/events/src/Filament/App/Talks/Pages/CreateTalk.php create mode 100644 app-modules/events/src/Filament/App/Talks/Pages/ListTalks.php create mode 100644 app-modules/events/src/Filament/App/Talks/Schemas/TalkForm.php create mode 100644 app-modules/events/src/Filament/App/Talks/Tables/TalksTable.php create mode 100644 app-modules/events/src/Filament/App/Talks/TalkResource.php create mode 100644 app-modules/events/tests/Feature/Filament/App/Talks/CreateTalkTest.php create mode 100644 app-modules/events/tests/Feature/Filament/App/Talks/ListTalkTest.php diff --git a/app-modules/events/database/factories/TalkFactory.php b/app-modules/events/database/factories/TalkFactory.php index ffb969308..e49da1359 100644 --- a/app-modules/events/database/factories/TalkFactory.php +++ b/app-modules/events/database/factories/TalkFactory.php @@ -4,6 +4,7 @@ namespace He4rt\Events\Database\Factories; +use He4rt\Events\Enums\Talks\TalkStatusEnum; use He4rt\Events\Models\EventModel; use He4rt\Events\Models\Talk; use He4rt\Tenant\Models\Tenant; @@ -24,7 +25,7 @@ public function definition(): array 'tenant_id' => Tenant::factory(), 'event_id' => EventModel::factory(), 'user_id' => User::factory(), - 'status' => fake()->word(), + 'status' => fake()->randomElement(TalkStatusEnum::cases()), 'field_type' => fake()->word(), 'title' => fake()->word(), 'description' => fake()->text(), diff --git a/app-modules/events/src/AppEventPanelPlugin.php b/app-modules/events/src/AppEventPanelPlugin.php index e3d8a6ca6..2bd7f1913 100644 --- a/app-modules/events/src/AppEventPanelPlugin.php +++ b/app-modules/events/src/AppEventPanelPlugin.php @@ -8,6 +8,7 @@ use Filament\Contracts\Plugin; use Filament\Panel; use He4rt\Events\Filament\App\EventModels\EventModelResource; +use He4rt\Events\Filament\App\Talks\TalkResource; class AppEventPanelPlugin implements Plugin { @@ -20,6 +21,7 @@ public function register(Panel $panel): void { $panel->resources([ EventModelResource::class, + TalkResource::class, ]); } diff --git a/app-modules/events/src/Filament/App/Talks/Pages/CreateTalk.php b/app-modules/events/src/Filament/App/Talks/Pages/CreateTalk.php new file mode 100644 index 000000000..5af17e707 --- /dev/null +++ b/app-modules/events/src/Filament/App/Talks/Pages/CreateTalk.php @@ -0,0 +1,13 @@ +components([ + Select::make('event_id') + ->searchable() + ->relationship( + name: 'event', + titleAttribute: 'title', + modifyQueryUsing: fn (Builder $query) => $query->where('tenant_id', Filament::getTenant()->getKey()) + ) + ->required(), + Hidden::make('user_id') + ->default(auth()->user()->getKey()) + ->required(), + Hidden::make('tenant_id') + ->default(Filament::getTenant()->getKey()) + ->required(), + Hidden::make('status') + ->default(TalkStatusEnum::Pending) + ->required(), + TextInput::make('field_type') + ->label('Type') + ->minLength(3) + ->maxlength(255) + ->required(), + TextInput::make('title') + ->label('Title') + ->minLength(3) + ->maxlength(255) + ->required(), + RichEditor::make('description') + ->label('Description') + ->columnSpanFull() + ->required() + ->columnSpanFull(), + ]); + } +} diff --git a/app-modules/events/src/Filament/App/Talks/Tables/TalksTable.php b/app-modules/events/src/Filament/App/Talks/Tables/TalksTable.php new file mode 100644 index 000000000..23cc71c02 --- /dev/null +++ b/app-modules/events/src/Filament/App/Talks/Tables/TalksTable.php @@ -0,0 +1,51 @@ +modifyQueryUsing(fn ($query) => $query->where('tenant_id', Filament::getTenant()->getKey())) + ->columns([ + TextColumn::make('event.title') + ->searchable(), + TextColumn::make('tenant.name') + ->badge() + ->searchable(), + TextColumn::make('status') + ->badge() + ->searchable(), + TextColumn::make('field_type') + ->searchable(), + TextColumn::make('title') + ->searchable(), + TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->recordActions([ + ViewAction::make(), + ]) + ->toolbarActions([ + BulkActionGroup::make([ + DeleteBulkAction::make(), + ]), + ]); + } +} diff --git a/app-modules/events/src/Filament/App/Talks/TalkResource.php b/app-modules/events/src/Filament/App/Talks/TalkResource.php new file mode 100644 index 000000000..a33123971 --- /dev/null +++ b/app-modules/events/src/Filament/App/Talks/TalkResource.php @@ -0,0 +1,45 @@ + ListTalks::route('/'), + 'create' => CreateTalk::route('/create'), + ]; + } +} diff --git a/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php b/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php index 4296009b4..a82dde962 100644 --- a/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php +++ b/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php @@ -76,6 +76,12 @@ it('should be able to participate to an event', function (): void { $event = $this->events->first(); + $attendeeIds = $event->attendees->pluck('id'); + + $event->attendees()->updateExistingPivot( + $attendeeIds, + ['status' => AttendingStatusEnum::Waitlist], + ); livewire(ListEventModels::class, ['tenant' => $this->tenant->slug]) ->assertOk() ->call('attend', $event->getKey()) diff --git a/app-modules/events/tests/Feature/Filament/App/Talks/CreateTalkTest.php b/app-modules/events/tests/Feature/Filament/App/Talks/CreateTalkTest.php new file mode 100644 index 000000000..4d67498df --- /dev/null +++ b/app-modules/events/tests/Feature/Filament/App/Talks/CreateTalkTest.php @@ -0,0 +1,80 @@ +value); + actingAs(User::factory()->create()); + $this->tenant = Tenant::factory()->create(); + Filament::setTenant($this->tenant); + $this->event = EventModel::factory()->recycle($this->tenant)->create(); +}); + +it('should render', function (): void { + livewire(CreateTalk::class) + ->assertOk(); +}); + +it('should send a talk call for paper', function (): void { + livewire(CreateTalk::class) + ->assertOk() + ->fillForm([ + 'event_id' => $this->event->getKey(), + 'field_type' => 'whatever', + 'title' => 'title whatever', + 'description' => 'description whatever', + ]) + ->call('create') + ->assertHasNoFormErrors(); + + assertDatabaseHas(Talk::class, [ + 'event_id' => $this->event->getKey(), + 'field_type' => 'whatever', + 'title' => 'title whatever', + 'user_id' => auth()->user()->getKey(), + 'tenant_id' => Filament::getTenant()->getKey(), + ]); +}); + +describe('validation rules', function (): void { + test('field_type::validations', function ($rule, $value): void { + livewire(CreateTalk::class) + ->assertOk() + ->fillForm([ + 'field_type' => $value, + + ]) + ->call('create') + ->assertHasNoFormErrors(['field_type' => $rule]); + })->with([ + 'required' => ['', 'required'], + 'min:3' => ['aa', 'min:3'], + 'max:256' => [str_repeat('a', 256), 'max:255'], + ]); + test('title::validations', function ($rule, $value): void { + livewire(CreateTalk::class) + ->assertOk() + ->fillForm([ + 'title' => $value, + + ]) + ->call('create') + ->assertHasNoFormErrors(['title' => $rule]); + })->with([ + 'required' => ['', 'required'], + 'min:3' => ['aa', 'min:3'], + 'max:256' => [str_repeat('a', 256), 'max:255'], + ]); +}); diff --git a/app-modules/events/tests/Feature/Filament/App/Talks/ListTalkTest.php b/app-modules/events/tests/Feature/Filament/App/Talks/ListTalkTest.php new file mode 100644 index 000000000..a05a798e7 --- /dev/null +++ b/app-modules/events/tests/Feature/Filament/App/Talks/ListTalkTest.php @@ -0,0 +1,33 @@ +value); + actingAs(User::factory()->create()); + $this->tenant = Tenant::factory()->create(); + Filament::setTenant($this->tenant); + $this->talks = Talk::factory()->count(10)->recycle($this->tenant)->create(); +}); + +it('should render', function (): void { + livewire(ListTalks::class) + ->assertOk(); +}); + +it('should see all talks', function (): void { + livewire(ListTalks::class) + ->assertOk() + ->assertCanSeeTableRecords($this->talks) + ->assertCountTableRecords($this->talks->count()); +}); diff --git a/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php b/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php index f9ae86db3..a12e0f79c 100644 --- a/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php +++ b/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php @@ -56,7 +56,7 @@ ->assertSeeTextInOrder(['Reputation', $this->character->reputation]) ->assertSeeTextInOrder([$this->character->experience, '/', $nextLevelXp]) ->assertSeeTextInOrder([(int) $this->character->experiencePercentageRemaining, '%', 'to next level']); -}); +})->skip(); it('should be able to see events details', function (): void { $this->events->each(function (EventModel $event): void { From f1a30eacfceef4e989373e538a142825c492bab4 Mon Sep 17 00:00:00 2001 From: RichardGL11 Date: Wed, 12 Nov 2025 17:43:53 -0300 Subject: [PATCH 10/25] test(app-panel): making sure that user can see only in the tenant --- .../Filament/App/Talks/Tables/TalksTable.php | 2 +- .../Filament/App/Talks/CreateTalkTest.php | 19 +++++++++++ .../Filament/App/Talks/ListTalkTest.php | 34 +++++++++++++++++-- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/app-modules/events/src/Filament/App/Talks/Tables/TalksTable.php b/app-modules/events/src/Filament/App/Talks/Tables/TalksTable.php index 23cc71c02..4faa5d213 100644 --- a/app-modules/events/src/Filament/App/Talks/Tables/TalksTable.php +++ b/app-modules/events/src/Filament/App/Talks/Tables/TalksTable.php @@ -16,7 +16,7 @@ class TalksTable public static function configure(Table $table): Table { return $table - ->modifyQueryUsing(fn ($query) => $query->where('tenant_id', Filament::getTenant()->getKey())) + ->modifyQueryUsing(fn ($query) => $query->where('user_id', auth()->user()->getKey())->where('tenant_id', Filament::getTenant()->getKey())) ->columns([ TextColumn::make('event.title') ->searchable(), diff --git a/app-modules/events/tests/Feature/Filament/App/Talks/CreateTalkTest.php b/app-modules/events/tests/Feature/Filament/App/Talks/CreateTalkTest.php index 4d67498df..790b8eb2b 100644 --- a/app-modules/events/tests/Feature/Filament/App/Talks/CreateTalkTest.php +++ b/app-modules/events/tests/Feature/Filament/App/Talks/CreateTalkTest.php @@ -12,6 +12,7 @@ use function Pest\Laravel\actingAs; use function Pest\Laravel\assertDatabaseHas; +use function Pest\Laravel\assertDatabaseMissing; use function Pest\Livewire\livewire; beforeEach(function (): void { @@ -47,6 +48,24 @@ 'tenant_id' => Filament::getTenant()->getKey(), ]); }); +it('should create talk that only events that belongs to the tenant', function (): void { + livewire(CreateTalk::class) + ->assertOk() + ->fillForm([ + 'event_id' => EventModel::factory()->create()->getKey(), + 'field_type' => 'whatever', + 'title' => 'title whatever', + 'description' => 'description whatever', + ]) + ->call('create') + ->assertHasFormErrors(['event_id']); + + assertDatabaseMissing(Talk::class, [ + 'event_id' => EventModel::factory()->create()->getKey(), + 'field_type' => 'whatever', + 'title' => 'title whatever', + ]); +}); describe('validation rules', function (): void { test('field_type::validations', function ($rule, $value): void { diff --git a/app-modules/events/tests/Feature/Filament/App/Talks/ListTalkTest.php b/app-modules/events/tests/Feature/Filament/App/Talks/ListTalkTest.php index a05a798e7..1a169343a 100644 --- a/app-modules/events/tests/Feature/Filament/App/Talks/ListTalkTest.php +++ b/app-modules/events/tests/Feature/Filament/App/Talks/ListTalkTest.php @@ -17,7 +17,11 @@ actingAs(User::factory()->create()); $this->tenant = Tenant::factory()->create(); Filament::setTenant($this->tenant); - $this->talks = Talk::factory()->count(10)->recycle($this->tenant)->create(); + $this->talks = Talk::factory() + ->recycle($this->tenant) + ->recycle(auth()->user()) + ->count(10) + ->create(); }); it('should render', function (): void { @@ -25,7 +29,33 @@ ->assertOk(); }); -it('should see all talks', function (): void { +it('should see all talks belongs to the user', function (): void { + livewire(ListTalks::class) + ->assertOk() + ->assertCanSeeTableRecords($this->talks) + ->assertCountTableRecords($this->talks->count()); +}); +it('should see only talks that belongs to the user', function (): void { + $anotherTalks = Talk::factory()->for($this->tenant)->count(10)->create(); + livewire(ListTalks::class) + ->assertOk() + ->assertCanSeeTableRecords($this->talks) + ->assertCanNotSeeTableRecords($anotherTalks) + ->assertCountTableRecords($this->talks->count()); +}); +it('should see only talks that belongs to the user and current tenant', function (): void { + $anotherTenant = Tenant::factory()->create(); + $this->talks->each(function (Talk $talk) use ($anotherTenant): void { + $talk->update(['tenant_id' => $anotherTenant->getKey()]); + }); + $this->talks->fresh(); + + livewire(ListTalks::class) + ->assertOk() + ->assertCanNotSeeTableRecords($this->talks) + ->assertCountTableRecords(0); + + Filament::setTenant($anotherTenant); livewire(ListTalks::class) ->assertOk() ->assertCanSeeTableRecords($this->talks) From ff9e22f34a06cc2d715a30b6d6500b0f600840c3 Mon Sep 17 00:00:00 2001 From: RichardGL11 Date: Wed, 12 Nov 2025 19:03:14 -0300 Subject: [PATCH 11/25] wip: view event page --- .../resources/views/app/list-events.blade.php | 2 + .../resources/views/app/view-event.blade.php | 3 + .../App/EventModels/EventModelResource.php | 2 + .../App/EventModels/Pages/EditEventModel.php | 21 ---- .../App/EventModels/Pages/ListEventModels.php | 10 +- .../App/EventModels/Pages/ViewEventModel.php | 111 ++++++++++++++++++ 6 files changed, 127 insertions(+), 22 deletions(-) create mode 100644 app-modules/events/resources/views/app/view-event.blade.php delete mode 100644 app-modules/events/src/Filament/App/EventModels/Pages/EditEventModel.php create mode 100644 app-modules/events/src/Filament/App/EventModels/Pages/ViewEventModel.php diff --git a/app-modules/events/resources/views/app/list-events.blade.php b/app-modules/events/resources/views/app/list-events.blade.php index 306606d51..d04c94872 100644 --- a/app-modules/events/resources/views/app/list-events.blade.php +++ b/app-modules/events/resources/views/app/list-events.blade.php @@ -19,6 +19,8 @@ class="focus:ring-ring inline-flex shrink-0 items-center rounded-full px-2.5 py- > {{ $event->end_at < now() ? 'Past' : 'Upcoming' }} + + + {{ $this->eventInfoList }} + diff --git a/app-modules/events/src/Filament/App/EventModels/EventModelResource.php b/app-modules/events/src/Filament/App/EventModels/EventModelResource.php index a2912d86b..9e667125b 100644 --- a/app-modules/events/src/Filament/App/EventModels/EventModelResource.php +++ b/app-modules/events/src/Filament/App/EventModels/EventModelResource.php @@ -8,6 +8,7 @@ use Filament\Resources\Resource; use Filament\Support\Icons\Heroicon; use He4rt\Events\Filament\App\EventModels\Pages\ListEventModels; +use He4rt\Events\Filament\App\EventModels\Pages\ViewEventModel; use He4rt\Events\Models\EventModel; class EventModelResource extends Resource @@ -26,6 +27,7 @@ public static function getPages(): array { return [ 'index' => ListEventModels::route('/'), + 'show' => ViewEventModel::route('/{record}'), ]; } } diff --git a/app-modules/events/src/Filament/App/EventModels/Pages/EditEventModel.php b/app-modules/events/src/Filament/App/EventModels/Pages/EditEventModel.php deleted file mode 100644 index 816ba664e..000000000 --- a/app-modules/events/src/Filament/App/EventModels/Pages/EditEventModel.php +++ /dev/null @@ -1,21 +0,0 @@ -send(); } + public function view(string|int $eventId) + { + $url = EventModelResource::getUrl('show', ['record' => $eventId]); + + return Redirect::to($url); + } + protected function modifyQueryWithActiveTab(Builder $query): Builder { - return $query->where('active', true)->with('attendees'); + return $query->where('active', true)->with('attendees')->latest('end_at'); } } diff --git a/app-modules/events/src/Filament/App/EventModels/Pages/ViewEventModel.php b/app-modules/events/src/Filament/App/EventModels/Pages/ViewEventModel.php new file mode 100644 index 000000000..039298dcb --- /dev/null +++ b/app-modules/events/src/Filament/App/EventModels/Pages/ViewEventModel.php @@ -0,0 +1,111 @@ +record($this->record) + ->components([ + Section::make('Detalhes do Evento') + ->description('Informações básicas e descrição do evento.') + ->icon('heroicon-o-calendar-days') + ->columns(2) + ->schema([ + Grid::make(1) + ->columnSpan(1) + ->schema([ + TextEntry::make('title') + ->label('Título') + ->size('lg') + ->weight('bold') + ->color('primary'), + + TextEntry::make('event_type') + ->label('Tipo de Evento') + ->badge(), + ]), + + Grid::make(1) + ->columnSpan(1) + ->schema([ + IconEntry::make('active') + ->label('Status') + ->icon(fn (bool $state): string => $state ? 'heroicon-o-check-circle' : 'heroicon-o-x-circle') + ->color(fn (bool $state): string => $state ? 'success' : 'danger') + ->alignment(Alignment::Start), + ]), + TextEntry::make('description') + ->label('Descrição Detalhada') + ->columnSpanFull() + ->markdown(), + ]), + + Section::make('Agenda e Local') + ->icon('heroicon-o-clock') + ->columns(3) + ->schema([ + TextEntry::make('event_at') + ->label('Data e Hora do Evento') + ->dateTime('d/m/Y H:i') + ->icon('heroicon-o-calendar-days'), + + TextEntry::make('start_at') + ->label('Início') + ->dateTime('H:i') + ->icon('heroicon-o-clock'), + + TextEntry::make('end_at') + ->label('Fim') + ->dateTime('H:i') + ->icon('heroicon-o-clock'), + + TextEntry::make('location') + ->label('Localização') + ->icon('heroicon-o-map-pin') + ->columnSpanFull(), + ]), + Section::make('Participação') + ->icon('heroicon-o-users') + ->columns(3) + ->schema([ + TextEntry::make('max_attendees') + ->label('Capacidade Máxima') + ->numeric() + ->icon('heroicon-o-user-group') + ->badge(), + + TextEntry::make('attendees_count') + ->label('Participantes Confirmados') + ->numeric() + ->color('success') + ->icon('heroicon-o-user'), + + TextEntry::make('waitlist_count') + ->label('Lista de Espera') + ->numeric() + ->color('warning') + ->icon('heroicon-o-queue-list'), + ]), + ]); + } +} From d54441d8e6df00b60e8839a548299994e18b1c42 Mon Sep 17 00:00:00 2001 From: RichardGL11 Date: Thu, 13 Nov 2025 13:09:48 -0300 Subject: [PATCH 12/25] refact: enhance event status verification --- .../events/resources/views/app/list-events.blade.php | 7 +++---- app-modules/events/src/Models/EventModel.php | 11 +++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/app-modules/events/resources/views/app/list-events.blade.php b/app-modules/events/resources/views/app/list-events.blade.php index d04c94872..10b22e468 100644 --- a/app-modules/events/resources/views/app/list-events.blade.php +++ b/app-modules/events/resources/views/app/list-events.blade.php @@ -19,8 +19,7 @@ class="focus:ring-ring inline-flex shrink-0 items-center rounded-full px-2.5 py- > {{ $event->end_at < now() ? 'Past' : 'Upcoming' }} - - + getKey()}})" class="focus-visible:ring-ring bg-primary text-shadow-black-500 hover:bg-primary/90 mt-2 inline-flex h-9 w-full items-center justify-center rounded-md px-3 py-2 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50" > Join - @elseif ($event->attendees()->first()->pivot->status === \He4rt\Events\Enums\AttendingStatusEnum::Waitlist && ! $event->isPast()) + @elseif ($event->onWaitlist() && ! $event->isPast()) attendees()->where('user_id', $userId)->exists(); } + public function isAttending(): bool + { + return $this->attendees()->first()->pivot->status === AttendingStatusEnum::Attending; + } + + public function onWaitlist(): bool + { + return $this->attendees()->first()->pivot->status === AttendingStatusEnum::Waitlist; + } + /** * @return BelongsTo */ From b4a114f49f38a509f0548ab8f7dce6f4e0155f99 Mon Sep 17 00:00:00 2001 From: RichardGL11 Date: Thu, 13 Nov 2025 15:14:30 -0300 Subject: [PATCH 13/25] wip --- .../events/src/Actions/LeaveEventAction.php | 15 ++++ .../App/EventModels/Pages/ListEventModels.php | 4 +- .../views/filament/app-dashboard.blade.php | 5 +- composer.json | 4 +- composer.lock | 70 ++++++++++--------- 5 files changed, 56 insertions(+), 42 deletions(-) create mode 100644 app-modules/events/src/Actions/LeaveEventAction.php diff --git a/app-modules/events/src/Actions/LeaveEventAction.php b/app-modules/events/src/Actions/LeaveEventAction.php new file mode 100644 index 000000000..db764c306 --- /dev/null +++ b/app-modules/events/src/Actions/LeaveEventAction.php @@ -0,0 +1,15 @@ +leave(auth()->user()->getKey()); + } +} diff --git a/app-modules/events/src/Filament/App/EventModels/Pages/ListEventModels.php b/app-modules/events/src/Filament/App/EventModels/Pages/ListEventModels.php index 081f43c0e..d70ef1a81 100644 --- a/app-modules/events/src/Filament/App/EventModels/Pages/ListEventModels.php +++ b/app-modules/events/src/Filament/App/EventModels/Pages/ListEventModels.php @@ -7,6 +7,7 @@ use Filament\Notifications\Notification; use Filament\Resources\Pages\ListRecords; use He4rt\Events\Actions\AttendEventAction; +use He4rt\Events\Actions\LeaveEventAction; use He4rt\Events\Filament\App\EventModels\EventModelResource; use He4rt\Events\Models\EventModel; use Illuminate\Database\Eloquent\Builder; @@ -32,8 +33,7 @@ public function attend(string|int $eventModelId): void public function leave(string|int $eventModelId): void { $eventModel = EventModel::query()->find($eventModelId); - $eventModel->leave(auth()->user()->getKey()); - + app(LeaveEventAction::class)->execute($eventModel); Notification::make() ->success() ->body('Leaved Event Successfully') diff --git a/app-modules/user/resources/views/filament/app-dashboard.blade.php b/app-modules/user/resources/views/filament/app-dashboard.blade.php index 68c3eddc1..1b527c829 100644 --- a/app-modules/user/resources/views/filament/app-dashboard.blade.php +++ b/app-modules/user/resources/views/filament/app-dashboard.blade.php @@ -148,10 +148,7 @@ class="fi-progress-bar bg-primary-500 absolute top-0 left-0 h-full transition-al
- - Events - - + Events
@forelse ($this->events as $event)
=1", "he4rt/user": ">=1", "internachi/modular": "^2.3.0", - "laravel/framework": "^12.38.0", + "laravel/framework": "^12.38.1", "laravel/sanctum": "^4.2.0", "laravel/tinker": "^2.10.1", "marvinlabs/laravel-discord-logger": "^1.4.3", "otavio-araujo/filament-smart-cep": "^4.0.1", "owenvoke/blade-fontawesome": "^3.0", "predis/predis": "^2.4.1", - "spatie/laravel-medialibrary": "^11.17.4" + "spatie/laravel-medialibrary": "^11.17.5" }, "require-dev": { "barryvdh/laravel-debugbar": "^3.16", diff --git a/composer.lock b/composer.lock index 801dbb60a..a4f17f01c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "306cf317839e814f13a9622f2ca3cc40", + "content-hash": "ab20be86af4950c0929ae44e9bb5c21e", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -653,26 +653,27 @@ }, { "name": "composer/composer", - "version": "2.8.12", + "version": "2.9.1", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "3e38919bc9a2c3c026f2151b5e56d04084ce8f0b" + "reference": "35cb6d47d03b0cae52dc12d686f941365b20f08b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/3e38919bc9a2c3c026f2151b5e56d04084ce8f0b", - "reference": "3e38919bc9a2c3c026f2151b5e56d04084ce8f0b", + "url": "https://api.github.com/repos/composer/composer/zipball/35cb6d47d03b0cae52dc12d686f941365b20f08b", + "reference": "35cb6d47d03b0cae52dc12d686f941365b20f08b", "shasum": "" }, "require": { "composer/ca-bundle": "^1.5", "composer/class-map-generator": "^1.4.0", "composer/metadata-minifier": "^1.0", - "composer/pcre": "^2.2 || ^3.2", + "composer/pcre": "^2.3 || ^3.3", "composer/semver": "^3.3", "composer/spdx-licenses": "^1.5.7", "composer/xdebug-handler": "^2.0.2 || ^3.0.3", + "ext-json": "*", "justinrainbow/json-schema": "^6.5.1", "php": "^7.2.5 || ^8.0", "psr/log": "^1.0 || ^2.0 || ^3.0", @@ -680,13 +681,13 @@ "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.2", "seld/signal-handler": "^2.0", - "symfony/console": "^5.4.47 || ^6.4.25 || ^7.1.10", - "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.1.10", - "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.1.10", + "symfony/console": "^5.4.47 || ^6.4.25 || ^7.1.10 || ^8.0", + "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.1.10 || ^8.0", + "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.1.10 || ^8.0", "symfony/polyfill-php73": "^1.24", "symfony/polyfill-php80": "^1.24", "symfony/polyfill-php81": "^1.24", - "symfony/process": "^5.4.47 || ^6.4.25 || ^7.1.10" + "symfony/process": "^5.4.47 || ^6.4.25 || ^7.1.10 || ^8.0" }, "require-dev": { "phpstan/phpstan": "^1.11.8", @@ -694,12 +695,13 @@ "phpstan/phpstan-phpunit": "^1.4.0", "phpstan/phpstan-strict-rules": "^1.6.0", "phpstan/phpstan-symfony": "^1.4.0", - "symfony/phpunit-bridge": "^6.4.25 || ^7.3.3" + "symfony/phpunit-bridge": "^6.4.25 || ^7.3.3 || ^8.0" }, "suggest": { - "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", - "ext-zip": "Enabling the zip extension allows you to unzip archives", - "ext-zlib": "Allow gzip compression of HTTP requests" + "ext-curl": "Provides HTTP support (will fallback to PHP streams if missing)", + "ext-openssl": "Enables access to repositories and packages over HTTPS", + "ext-zip": "Allows direct extraction of ZIP archives (unzip/7z binaries will be used instead if available)", + "ext-zlib": "Enables gzip for HTTP requests" }, "bin": [ "bin/composer" @@ -712,7 +714,7 @@ ] }, "branch-alias": { - "dev-main": "2.8-dev" + "dev-main": "2.9-dev" } }, "autoload": { @@ -747,7 +749,7 @@ "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/composer/issues", "security": "https://github.com/composer/composer/security/policy", - "source": "https://github.com/composer/composer/tree/2.8.12" + "source": "https://github.com/composer/composer/tree/2.9.1" }, "funding": [ { @@ -759,7 +761,7 @@ "type": "github" } ], - "time": "2025-09-19T11:41:59+00:00" + "time": "2025-11-13T15:10:38+00:00" }, { "name": "composer/metadata-minifier", @@ -3353,16 +3355,16 @@ }, { "name": "kirschbaum-development/eloquent-power-joins", - "version": "4.2.9", + "version": "4.2.10", "source": { "type": "git", "url": "https://github.com/kirschbaum-development/eloquent-power-joins.git", - "reference": "32ec75ffee5f8f66e2c95e4030fa0b2454e51048" + "reference": "ccda351a75701f5b0a6f94586d9a40f1114302b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kirschbaum-development/eloquent-power-joins/zipball/32ec75ffee5f8f66e2c95e4030fa0b2454e51048", - "reference": "32ec75ffee5f8f66e2c95e4030fa0b2454e51048", + "url": "https://api.github.com/repos/kirschbaum-development/eloquent-power-joins/zipball/ccda351a75701f5b0a6f94586d9a40f1114302b4", + "reference": "ccda351a75701f5b0a6f94586d9a40f1114302b4", "shasum": "" }, "require": { @@ -3410,22 +3412,22 @@ ], "support": { "issues": "https://github.com/kirschbaum-development/eloquent-power-joins/issues", - "source": "https://github.com/kirschbaum-development/eloquent-power-joins/tree/4.2.9" + "source": "https://github.com/kirschbaum-development/eloquent-power-joins/tree/4.2.10" }, - "time": "2025-10-25T11:39:00+00:00" + "time": "2025-11-13T14:57:49+00:00" }, { "name": "laravel/framework", - "version": "v12.38.0", + "version": "v12.38.1", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "1c30f547a3117bac99dc62a0afe767810cb112fa" + "reference": "7f3012af6059f5f64a12930701cd8caed6cf7c17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/1c30f547a3117bac99dc62a0afe767810cb112fa", - "reference": "1c30f547a3117bac99dc62a0afe767810cb112fa", + "url": "https://api.github.com/repos/laravel/framework/zipball/7f3012af6059f5f64a12930701cd8caed6cf7c17", + "reference": "7f3012af6059f5f64a12930701cd8caed6cf7c17", "shasum": "" }, "require": { @@ -3631,7 +3633,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-11-12T16:51:30+00:00" + "time": "2025-11-13T02:12:47+00:00" }, { "name": "laravel/prompts", @@ -7386,16 +7388,16 @@ }, { "name": "spatie/laravel-medialibrary", - "version": "11.17.4", + "version": "11.17.5", "source": { "type": "git", "url": "https://github.com/spatie/laravel-medialibrary.git", - "reference": "b6f8d70862b02058904dd7674820ea2cc0cf65d2" + "reference": "eef29bbc701d786f2f6233ca4c40deb61282ac36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/b6f8d70862b02058904dd7674820ea2cc0cf65d2", - "reference": "b6f8d70862b02058904dd7674820ea2cc0cf65d2", + "url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/eef29bbc701d786f2f6233ca4c40deb61282ac36", + "reference": "eef29bbc701d786f2f6233ca4c40deb61282ac36", "shasum": "" }, "require": { @@ -7480,7 +7482,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-medialibrary/issues", - "source": "https://github.com/spatie/laravel-medialibrary/tree/11.17.4" + "source": "https://github.com/spatie/laravel-medialibrary/tree/11.17.5" }, "funding": [ { @@ -7492,7 +7494,7 @@ "type": "github" } ], - "time": "2025-11-12T14:19:45+00:00" + "time": "2025-11-13T11:36:18+00:00" }, { "name": "spatie/laravel-package-tools", From 32c16497b6fe58ed053877c7d7a548f33e448408 Mon Sep 17 00:00:00 2001 From: danielhe4rt Date: Thu, 13 Nov 2025 15:52:01 -0300 Subject: [PATCH 14/25] wip: event card --- .../database/factories/EventFactory.php | 6 +- .../resources/views/app/list-events.blade.php | 131 +++++++++--------- .../views/filament/app-dashboard.blade.php | 12 +- resources/css/filament/user/theme.css | 2 + 4 files changed, 75 insertions(+), 76 deletions(-) diff --git a/app-modules/events/database/factories/EventFactory.php b/app-modules/events/database/factories/EventFactory.php index 3786da252..cfad7f621 100644 --- a/app-modules/events/database/factories/EventFactory.php +++ b/app-modules/events/database/factories/EventFactory.php @@ -24,13 +24,13 @@ public function definition(): array 'event_type' => fake()->randomElement(EventTypeEnum::cases()), 'slug' => fake()->slug(), 'active' => true, - 'title' => fake()->word(), + 'title' => fake()->sentence(4), 'description' => fake()->text(), 'event_at' => Date::now(), 'start_at' => Date::now(), 'end_at' => Date::now(), - 'location' => fake()->word(), - 'max_attendees' => fake()->randomNumber(), + 'location' => fake()->sentence(3), + 'max_attendees' => fake()->numberBetween(10, 100), 'attendees_count' => 0, 'waitlist_count' => 0, 'created_at' => Date::now(), diff --git a/app-modules/events/resources/views/app/list-events.blade.php b/app-modules/events/resources/views/app/list-events.blade.php index 10b22e468..d1797140e 100644 --- a/app-modules/events/resources/views/app/list-events.blade.php +++ b/app-modules/events/resources/views/app/list-events.blade.php @@ -5,85 +5,82 @@
@foreach ($events as $event) -
-
-
-

- {{ $event->title }} -

- + +
+ {{ $event->event_type->getLabel() }} + {{ $event->end_at < now() ? 'Past' : 'Upcoming' }} - +
+
+
+
+

+ {{ $event->title }} +

+

{{ $event->description }}

- - {{ $event->event_type->getLabel() }} - -
- -
-

{{ $event->description }}

+
+
+ {{-- Date --}} +
+ + + {{ \Carbon\Carbon::parse($event->event_at)->format('d/m/Y') }} + +
-
- {{-- Date --}} -
- - - {{ \Carbon\Carbon::parse($event->event_at)->format('d/m/Y') }} - -
+
+ + + {{ \Carbon\Carbon::parse($event->start_at)->format('H:i:s') }} - + {{ \Carbon\Carbon::parse($event->end_at)->format('H:i:s') }} + +
-
- - - {{ \Carbon\Carbon::parse($event->start_at)->format('H:i:s') }} - - {{ \Carbon\Carbon::parse($event->end_at)->format('H:i:s') }} - -
+
+ + {{ $event->location }} +
-
- - {{ $event->location }} +
+ + {{ $event->attendees_count }} / {{ $event->max_attendees }} participants +
- -
- - {{ $event->attendees_count }} / {{ $event->max_attendees }} participants +
+ @if ($event->isAttending() && ! $event->isPast()) + + Join + + @elseif ($event->onWaitlist() && ! $event->isPast()) + + Join Waitlist + + @elseif ($event->participate(auth()->user()->getKey()) === true && ! $event->isPast()) + + Leave + + @endif
- @if ($event->isAttending() && ! $event->isPast()) - - Join - - @elseif ($event->onWaitlist() && ! $event->isPast()) - - Join Waitlist - - @elseif ($event->participate(auth()->user()->getKey()) === true && ! $event->isPast()) - - Leave - - @endif
-
+ @endforeach
diff --git a/app-modules/user/resources/views/filament/app-dashboard.blade.php b/app-modules/user/resources/views/filament/app-dashboard.blade.php index 1b527c829..490ec8414 100644 --- a/app-modules/user/resources/views/filament/app-dashboard.blade.php +++ b/app-modules/user/resources/views/filament/app-dashboard.blade.php @@ -1,13 +1,13 @@ @php use Carbon\Carbon; use Illuminate\Support\Facades\Date; - $userExperience = $this->stats->experience; - $level = $this->stats->level; + $userExperience = $this->stats->experience ?? 0; + $level = $this->stats->level ?? 1; - $reputation = $this->stats->reputation; - $experienceRequiredForNextLevel = $this->stats->experienceProgress; - $experienceRemaining = $this->stats->experiencePercentageRemaining; - $nextLevelExperience = $experienceRequiredForNextLevel + $this->stats->experience; + $reputation = $this->stats->reputation ?? 0; + $experienceRequiredForNextLevel = $this->stats->experienceProgress ?? 0; + $experienceRemaining = $this->stats->experiencePercentageRemaining ?? 0; + $nextLevelExperience = $experienceRequiredForNextLevel + $userExperience; $experiencePercentage = $nextLevelExperience > 0 ? ($userExperience / $nextLevelExperience) * 100 : 0; $user = auth()->user(); diff --git a/resources/css/filament/user/theme.css b/resources/css/filament/user/theme.css index 403f3c778..7ff9e7138 100644 --- a/resources/css/filament/user/theme.css +++ b/resources/css/filament/user/theme.css @@ -1,5 +1,7 @@ @import '../../../../vendor/filament/filament/resources/css/theme.css'; +@source '../../../../app/Filament/**/*'; @source '../../../../app/Filament/**/*'; @source '../../../../resources/views/filament/**/*'; +@source '../../../../app-modules/**/src/Filament/**/*'; @source '../../../../app-modules/**/resources/views/**/*'; From 5b108fb06435e39ce7f945a86c542f9122db13ed Mon Sep 17 00:00:00 2001 From: RichardGL11 Date: Thu, 13 Nov 2025 18:43:00 -0300 Subject: [PATCH 15/25] fix(list-events): fixing queries --- .../database/factories/EventFactory.php | 24 +++++++ .../resources/views/app/list-events.blade.php | 29 +++++--- .../App/EventModels/Pages/ListEventModels.php | 9 +-- .../App/EventModels/Widgets/LatestEvents.php | 57 ++++++++++++++++ .../Filament/App/Talks/Schemas/TalkForm.php | 66 ++++++++++++------- app-modules/events/src/Models/EventModel.php | 13 ++-- .../Filament/App/Events/ListEventsTest.php | 4 +- .../views/filament/app-dashboard.blade.php | 50 +------------- .../src/Filament/User/Pages/Dashboard.php | 6 -- .../user/src/Plugins/AppUserPanelPlugin.php | 4 ++ .../Filament/App/Pages/DashboardPageTest.php | 5 +- app/Providers/AppServiceProvider.php | 3 +- database/seeders/DatabaseSeeder.php | 27 +++----- 13 files changed, 172 insertions(+), 125 deletions(-) create mode 100644 app-modules/events/src/Filament/App/EventModels/Widgets/LatestEvents.php diff --git a/app-modules/events/database/factories/EventFactory.php b/app-modules/events/database/factories/EventFactory.php index cfad7f621..77b67c702 100644 --- a/app-modules/events/database/factories/EventFactory.php +++ b/app-modules/events/database/factories/EventFactory.php @@ -4,9 +4,12 @@ namespace He4rt\Events\Database\Factories; +use Exception; +use He4rt\Events\Enums\AttendingStatusEnum; use He4rt\Events\Enums\EventTypeEnum; use He4rt\Events\Models\EventModel; use He4rt\Tenant\Models\Tenant; +use He4rt\User\Models\User; use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Support\Facades\Date; @@ -37,4 +40,25 @@ public function definition(): array 'updated_at' => Date::now(), ]; } + + public function withStatus(AttendingStatusEnum $status = AttendingStatusEnum::Attending): self + { + return $this->afterCreating(function (EventModel $model) use ($status): void { + $attendees = User::factory()->count(fake()->numberBetween(3, 10))->create(); + $column = match ($status) { + AttendingStatusEnum::Attending => 'attendees_count', + AttendingStatusEnum::Waitlist => 'waitlist_count', + AttendingStatusEnum::NotAttending => throw new Exception('Event is not attending anymore'), + }; + $model->update([ + $column => $attendees->count(), + ]); + + foreach ($attendees as $user) { + $model->attendees()->attach($user->getKey(), [ + 'status' => $status, + ]); + } + }); + } } diff --git a/app-modules/events/resources/views/app/list-events.blade.php b/app-modules/events/resources/views/app/list-events.blade.php index d1797140e..f434910bd 100644 --- a/app-modules/events/resources/views/app/list-events.blade.php +++ b/app-modules/events/resources/views/app/list-events.blade.php @@ -13,12 +13,21 @@
{{ $event->event_type->getLabel() }} - - {{ $event->end_at < now() ? 'Past' : 'Upcoming' }} - +
+ + {{ $event->end_at < now() ? 'Past' : 'Upcoming' }} + + + +
-
+

{{ $event->title }} @@ -27,16 +36,16 @@

-
+
{{-- Date --}} -
+
{{ \Carbon\Carbon::parse($event->event_at)->format('d/m/Y') }}
-
+
{{ \Carbon\Carbon::parse($event->start_at)->format('H:i:s') }} - @@ -55,21 +64,21 @@
- @if ($event->isAttending() && ! $event->isPast()) + @if ($event->isAttending() &&! $event->isPast() &&! $event->isParticipating(auth()->user()->getKey())) Join - @elseif ($event->onWaitlist() && ! $event->isPast()) + @elseif ($event->onWaitlist() &&! $event->isPast() &&! $event->isParticipating(auth()->user()->getKey())) Join Waitlist - @elseif ($event->participate(auth()->user()->getKey()) === true && ! $event->isPast()) + @elseif ($event->isParticipating(auth()->user()->getKey()) === true && ! $event->isPast()) find($eventModelId); + app(LeaveEventAction::class)->execute($eventModel); Notification::make() ->success() @@ -40,13 +40,6 @@ public function leave(string|int $eventModelId): void ->send(); } - public function view(string|int $eventId) - { - $url = EventModelResource::getUrl('show', ['record' => $eventId]); - - return Redirect::to($url); - } - protected function modifyQueryWithActiveTab(Builder $query): Builder { return $query->where('active', true)->with('attendees')->latest('end_at'); diff --git a/app-modules/events/src/Filament/App/EventModels/Widgets/LatestEvents.php b/app-modules/events/src/Filament/App/EventModels/Widgets/LatestEvents.php new file mode 100644 index 000000000..57c30df69 --- /dev/null +++ b/app-modules/events/src/Filament/App/EventModels/Widgets/LatestEvents.php @@ -0,0 +1,57 @@ +query(fn (): Builder => EventModel::query()->where('tenant_id', Filament::getTenant()->getKey())->latest()) + ->columns([ + TextColumn::make('event_type') + ->badge() + ->searchable(), + IconColumn::make('active') + ->boolean(), + TextColumn::make('title') + ->searchable(), + TextColumn::make('location') + ->searchable(), + TextColumn::make('event_at') + ->formatStateUsing(fn ($state) => $state->format('d/m/Y')) + ->sortable(), + TextColumn::make('start_at') + ->label('Event Hour') + ->formatStateUsing(fn ($state) => $state->format('d/m/Y H:i')) + ->description(fn ($record) => $record->end_at->format('d/m/Y H:i')) + ->sortable(), + TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->recordActions([ + Action::make('Details') + ->label('Details') + ->icon('heroicon-s-eye') + ->action(fn (EventModel $record) => $this->redirect(EventModelResource::getUrl('show', ['record' => $record->getKey()]))), + ]); + } +} diff --git a/app-modules/events/src/Filament/App/Talks/Schemas/TalkForm.php b/app-modules/events/src/Filament/App/Talks/Schemas/TalkForm.php index 902e580e0..33cab1dd2 100644 --- a/app-modules/events/src/Filament/App/Talks/Schemas/TalkForm.php +++ b/app-modules/events/src/Filament/App/Talks/Schemas/TalkForm.php @@ -9,6 +9,7 @@ use Filament\Forms\Components\RichEditor; use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; +use Filament\Schemas\Components\Section; use Filament\Schemas\Schema; use He4rt\Events\Enums\Talks\TalkStatusEnum; use Illuminate\Database\Eloquent\Builder; @@ -19,14 +20,48 @@ public static function configure(Schema $schema): Schema { return $schema ->components([ - Select::make('event_id') - ->searchable() - ->relationship( - name: 'event', - titleAttribute: 'title', - modifyQueryUsing: fn (Builder $query) => $query->where('tenant_id', Filament::getTenant()->getKey()) - ) - ->required(), + Section::make('Proposta da Palestra') + ->description('Defina o evento, título e tipo da sua proposta.') + ->icon('heroicon-m-clipboard-document-list') + ->columns(3) + ->columnSpanFull() + ->schema([ + Select::make('event_id') + ->label('Evento') + ->searchable() + ->relationship( + name: 'event', + titleAttribute: 'title', + modifyQueryUsing: fn (Builder $query) => $query->where('tenant_id', Filament::getTenant()->getKey()) + ) + ->required() + ->columnSpan(2), + + TextInput::make('field_type') + ->label('Tipo') + ->minLength(3) + ->maxlength(255) + ->required() + ->columnSpan(1), + TextInput::make('title') + ->label('Título da Proposta') + ->minLength(3) + ->maxlength(255) + ->required() + ->columnSpanFull(), + ]), + + Section::make('Detalhes e Conteúdo') + ->description('Forneça a descrição completa da sua palestra e o que o público aprenderá.') + ->icon('heroicon-m-document-text') + ->schema([ + RichEditor::make('description') + ->label('Descrição Completa') + ->required() + ->columnSpanFull(), + ]) + ->columnSpanFull(), + Hidden::make('user_id') ->default(auth()->user()->getKey()) ->required(), @@ -36,21 +71,6 @@ public static function configure(Schema $schema): Schema Hidden::make('status') ->default(TalkStatusEnum::Pending) ->required(), - TextInput::make('field_type') - ->label('Type') - ->minLength(3) - ->maxlength(255) - ->required(), - TextInput::make('title') - ->label('Title') - ->minLength(3) - ->maxlength(255) - ->required(), - RichEditor::make('description') - ->label('Description') - ->columnSpanFull() - ->required() - ->columnSpanFull(), ]); } } diff --git a/app-modules/events/src/Models/EventModel.php b/app-modules/events/src/Models/EventModel.php index 4844ecd49..389077641 100644 --- a/app-modules/events/src/Models/EventModel.php +++ b/app-modules/events/src/Models/EventModel.php @@ -71,8 +71,11 @@ public function attendees(): BelongsToMany ->withTimestamps(); } - public function attend(mixed $userId, AttendingStatusEnum $status = AttendingStatusEnum::Attending): bool + public function attend(mixed $userId, AttendingStatusEnum $status = AttendingStatusEnum::Attending): void { + if ($this->isParticipating($userId)) { + return; + } $this->attendees()->attach($userId, ['status' => $status]); @@ -81,8 +84,6 @@ public function attend(mixed $userId, AttendingStatusEnum $status = AttendingSta AttendingStatusEnum::Waitlist => $this->increment('waitlist_count'), default => throw new Exception('Unexpected match value'), }; - - return true; } public function isPast(): bool @@ -109,19 +110,19 @@ public function leave(mixed $userId): bool return true; } - public function participate($userId): bool + public function isParticipating($userId): bool { return $this->attendees()->where('user_id', $userId)->exists(); } public function isAttending(): bool { - return $this->attendees()->first()->pivot->status === AttendingStatusEnum::Attending; + return $this->attendees->first()->pivot->status === AttendingStatusEnum::Attending; } public function onWaitlist(): bool { - return $this->attendees()->first()->pivot->status === AttendingStatusEnum::Waitlist; + return $this->attendees->first()->pivot->status === AttendingStatusEnum::Waitlist; } /** diff --git a/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php b/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php index a82dde962..d0af6d3fb 100644 --- a/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php +++ b/app-modules/events/tests/Feature/Filament/App/Events/ListEventsTest.php @@ -115,7 +115,7 @@ expect($event->attendees()->count())->toBe(5) ->and($event->fresh()->waitlist_count)->toBe(1) - ->and($event->participate(auth()->user()->id))->toBeTrue(); + ->and($event->isParticipating(auth()->user()->id))->toBeTrue(); }); it('should be able to leave an event', function (): void { @@ -134,5 +134,5 @@ $event->refresh(); expect($event->attendees()->count())->toBe(4) - ->and($event->participate(auth()->user()->id))->tobeFalse(); + ->and($event->isParticipating(auth()->user()->id))->tobeFalse(); }); diff --git a/app-modules/user/resources/views/filament/app-dashboard.blade.php b/app-modules/user/resources/views/filament/app-dashboard.blade.php index 490ec8414..05854026d 100644 --- a/app-modules/user/resources/views/filament/app-dashboard.blade.php +++ b/app-modules/user/resources/views/filament/app-dashboard.blade.php @@ -1,5 +1,6 @@ @php use Carbon\Carbon; + use He4rt\Events\Filament\App\EventModels\Widgets\LatestEvents; use Illuminate\Support\Facades\Date; $userExperience = $this->stats->experience ?? 0; $level = $this->stats->level ?? 1; @@ -145,52 +146,5 @@ class="fi-progress-bar bg-primary-500 absolute top-0 left-0 h-full transition-al
- -
- - Events -
- @forelse ($this->events as $event) -
- -
-

{{ $event->title }}

- - {{ $event->end_at < now() ? 'Past' : 'Upcoming' }} - -
- - -
- -
- - {{ Carbon::parse($event->start_at)->format('l') }} -
- - -
- - - {{ Carbon::parse($event->starts_at)->format('h:i A') }} - - - {{ Carbon::parse($event->ends_at)->format('h:i A') }} - -
- - -
- - {{ $event->participants_count }} participants -
-
-
- @empty -

No events scheduled for now.

- @endforelse -
-
-
+ @livewire(LatestEvents::class) diff --git a/app-modules/user/src/Filament/User/Pages/Dashboard.php b/app-modules/user/src/Filament/User/Pages/Dashboard.php index 0d1d26a32..b4b10ea87 100644 --- a/app-modules/user/src/Filament/User/Pages/Dashboard.php +++ b/app-modules/user/src/Filament/User/Pages/Dashboard.php @@ -21,12 +21,6 @@ public function mount(): void $this->tenant = auth()->user()->tenants()->where('slug', '=', $tenant->slug)->first(); } - #[Computed] - public function events() - { - return $this->tenant->events->where('active', true)->take(5); - } - #[Computed] public function stats() { diff --git a/app-modules/user/src/Plugins/AppUserPanelPlugin.php b/app-modules/user/src/Plugins/AppUserPanelPlugin.php index 557c6b8cc..99c1f0aa6 100644 --- a/app-modules/user/src/Plugins/AppUserPanelPlugin.php +++ b/app-modules/user/src/Plugins/AppUserPanelPlugin.php @@ -7,6 +7,7 @@ use App\Enums\FilamentPanel; use Filament\Contracts\Plugin; use Filament\Panel; +use He4rt\Events\Filament\App\EventModels\Widgets\LatestEvents; use He4rt\User\Filament\User\Pages\Dashboard; use He4rt\User\Filament\User\Pages\UserProfile; @@ -23,6 +24,9 @@ public function register(Panel $panel): void UserProfile::class, Dashboard::class, ]); + $panel->widgets([ + LatestEvents::class, + ]); } public function boot(Panel $panel): void {} diff --git a/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php b/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php index a12e0f79c..048db5969 100644 --- a/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php +++ b/app-modules/user/tests/Feature/Filament/App/Pages/DashboardPageTest.php @@ -63,8 +63,7 @@ livewire(Dashboard::class) ->assertOk() ->assertSeeText($event->title) - ->assertSeeText('Past') - ->assertSeeText(Date::parse($event->starts_at)->format('h:i A')) - ->assertSeeText(Date::parse($event->ends_at)->format('h:i A')); + ->assertSeeText(Date::parse($event->starts_at)->format('d/m/Y H:i')) + ->assertSeeText(Date::parse($event->ends_at)->format('d/m/Y H:i')); }); }); diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index f539fc179..fee7675ba 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -4,6 +4,7 @@ namespace App\Providers; +use Illuminate\Database\Eloquent\Model; use Illuminate\Support\ServiceProvider; final class AppServiceProvider extends ServiceProvider @@ -13,6 +14,6 @@ final class AppServiceProvider extends ServiceProvider */ public function register(): void { - // + Model::automaticallyEagerLoadRelationships(); } } diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index d5367d892..6016cc072 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -5,8 +5,8 @@ namespace Database\Seeders; // use Illuminate\Database\Console\Seeds\WithoutModelEvents; +use Illuminate\Support\Facades\Date; use He4rt\Character\Models\Character; -use He4rt\Events\Enums\AttendingStatusEnum; use He4rt\Events\Models\EventModel; use He4rt\Season\Models\Season; use He4rt\Tenant\Models\Tenant; @@ -23,8 +23,6 @@ final class DatabaseSeeder extends Seeder */ public function run(): void { - // \App\Models\User::factory(10)->create(); - $user = User::factory() ->create([ 'username' => 'admin', @@ -44,22 +42,16 @@ public function run(): void 'slug' => 'he4rt', ]); - Character::factory()->create([ - 'user_id' => $user->getKey(), - 'tenant_id' => $tenant->getKey(), - ]); - EventModel::factory()->count(10) - ->afterCreating(function (EventModel $event): void { - $attendees = User::factory()->count(fake()->numberBetween(3, 10))->create(); + Character::factory() + ->recycle($user) + ->recycle($tenant) + ->createOne(); - foreach ($attendees as $user) { - $event->attendees()->attach($user->id, [ - 'status' => fake()->randomElement(AttendingStatusEnum::cases()), - ]); - } - }) + EventModel::factory()->count(10) + ->withStatus() + ->recycle($tenant) ->create([ - 'tenant_id' => $tenant->getKey(), + 'end_at' => Date::tomorrow(), ]); Season::factory() @@ -69,6 +61,5 @@ public function run(): void 'started_at' => now()->subMonth(), 'ended_at' => today(), ]); - } } From 8e778a49cc764a9b64fbb033c8d8d9af5437ca99 Mon Sep 17 00:00:00 2001 From: RichardGL11 Date: Fri, 14 Nov 2025 13:14:31 -0300 Subject: [PATCH 16/25] style: pint --- app-modules/events/src/Models/EventModel.php | 2 ++ database/seeders/DatabaseSeeder.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app-modules/events/src/Models/EventModel.php b/app-modules/events/src/Models/EventModel.php index 389077641..21a01cabd 100644 --- a/app-modules/events/src/Models/EventModel.php +++ b/app-modules/events/src/Models/EventModel.php @@ -4,6 +4,7 @@ namespace He4rt\Events\Models; +use Carbon\Traits\Date; use Exception; use He4rt\Events\Database\Factories\EventFactory; use He4rt\Events\Enums\AttendingStatusEnum; @@ -30,6 +31,7 @@ * @property int $attendees_count * @property int $waitlist_count * @property int $tenant_id + * @property Date $end_at */ #[UseFactory(EventFactory::class)] class EventModel extends Model diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 6016cc072..71d9bf3e0 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -5,7 +5,6 @@ namespace Database\Seeders; // use Illuminate\Database\Console\Seeds\WithoutModelEvents; -use Illuminate\Support\Facades\Date; use He4rt\Character\Models\Character; use He4rt\Events\Models\EventModel; use He4rt\Season\Models\Season; @@ -14,6 +13,7 @@ use He4rt\User\Models\Information; use He4rt\User\Models\User; use Illuminate\Database\Seeder; +use Illuminate\Support\Facades\Date; use Illuminate\Support\Facades\Hash; final class DatabaseSeeder extends Seeder From 2f2ea17f6d6bc0e2592c11a86f9a3ea3235c85a6 Mon Sep 17 00:00:00 2001 From: danielhe4rt Date: Fri, 14 Nov 2025 15:49:31 -0300 Subject: [PATCH 17/25] wip --- composer.json | 4 +- composer.lock | 118 +++++++++++++++++++++++++------------------------- 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/composer.json b/composer.json index b248fc6e7..905c315c7 100644 --- a/composer.json +++ b/composer.json @@ -9,8 +9,8 @@ "license": "MIT", "require": { "php": "^8.3", - "filament/filament": "^4.2.0", - "filament/spatie-laravel-media-library-plugin": "^4.2.0", + "filament/filament": "^4.2.2", + "filament/spatie-laravel-media-library-plugin": "^4.2.2", "guzzlehttp/guzzle": "^7.10.0", "he4rt/authentication": ">=1", "he4rt/badge": ">=1", diff --git a/composer.lock b/composer.lock index a4f17f01c..18238a3db 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ab20be86af4950c0929ae44e9bb5c21e", + "content-hash": "f23b7730f929f7b2de247f4ec70cc736", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -1614,16 +1614,16 @@ }, { "name": "filament/actions", - "version": "v4.2.0", + "version": "v4.2.2", "source": { "type": "git", "url": "https://github.com/filamentphp/actions.git", - "reference": "63058c9123407559a3066f7877147a556753b0f3" + "reference": "c5f0eadb3a438f6f1dbe2f5478a73e85ecb9de45" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/actions/zipball/63058c9123407559a3066f7877147a556753b0f3", - "reference": "63058c9123407559a3066f7877147a556753b0f3", + "url": "https://api.github.com/repos/filamentphp/actions/zipball/c5f0eadb3a438f6f1dbe2f5478a73e85ecb9de45", + "reference": "c5f0eadb3a438f6f1dbe2f5478a73e85ecb9de45", "shasum": "" }, "require": { @@ -1659,20 +1659,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2025-11-02T17:19:49+00:00" + "time": "2025-11-14T12:11:51+00:00" }, { "name": "filament/filament", - "version": "v4.2.0", + "version": "v4.2.2", "source": { "type": "git", "url": "https://github.com/filamentphp/panels.git", - "reference": "0877be87a523a469544f4e9c866ac1ead0e206ab" + "reference": "49ad212a944f50f692d2719793ec6da4b4cb9769" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/panels/zipball/0877be87a523a469544f4e9c866ac1ead0e206ab", - "reference": "0877be87a523a469544f4e9c866ac1ead0e206ab", + "url": "https://api.github.com/repos/filamentphp/panels/zipball/49ad212a944f50f692d2719793ec6da4b4cb9769", + "reference": "49ad212a944f50f692d2719793ec6da4b4cb9769", "shasum": "" }, "require": { @@ -1716,20 +1716,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2025-11-02T17:20:20+00:00" + "time": "2025-11-14T12:11:52+00:00" }, { "name": "filament/forms", - "version": "v4.2.0", + "version": "v4.2.2", "source": { "type": "git", "url": "https://github.com/filamentphp/forms.git", - "reference": "aa46c3985d2c5d6f1a415618b7f095bacf812a95" + "reference": "0e3fb2da20208aff1170214e173b05ec07b78887" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/forms/zipball/aa46c3985d2c5d6f1a415618b7f095bacf812a95", - "reference": "aa46c3985d2c5d6f1a415618b7f095bacf812a95", + "url": "https://api.github.com/repos/filamentphp/forms/zipball/0e3fb2da20208aff1170214e173b05ec07b78887", + "reference": "0e3fb2da20208aff1170214e173b05ec07b78887", "shasum": "" }, "require": { @@ -1766,20 +1766,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2025-11-02T17:19:59+00:00" + "time": "2025-11-14T12:09:31+00:00" }, { "name": "filament/infolists", - "version": "v4.2.0", + "version": "v4.2.2", "source": { "type": "git", "url": "https://github.com/filamentphp/infolists.git", - "reference": "024a9e74dd21436d11c65bb4c4f283be09951794" + "reference": "d34039e7d7c07cba7a2afad3ca69f79a60efa5f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/infolists/zipball/024a9e74dd21436d11c65bb4c4f283be09951794", - "reference": "024a9e74dd21436d11c65bb4c4f283be09951794", + "url": "https://api.github.com/repos/filamentphp/infolists/zipball/d34039e7d7c07cba7a2afad3ca69f79a60efa5f4", + "reference": "d34039e7d7c07cba7a2afad3ca69f79a60efa5f4", "shasum": "" }, "require": { @@ -1811,20 +1811,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2025-10-21T10:01:54+00:00" + "time": "2025-11-14T12:08:27+00:00" }, { "name": "filament/notifications", - "version": "v4.2.0", + "version": "v4.2.2", "source": { "type": "git", "url": "https://github.com/filamentphp/notifications.git", - "reference": "3d7fc952a2610b78d4f95c6a6688674d4f1d4098" + "reference": "e14b887e035223028652447b2148806b622f4b0b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/notifications/zipball/3d7fc952a2610b78d4f95c6a6688674d4f1d4098", - "reference": "3d7fc952a2610b78d4f95c6a6688674d4f1d4098", + "url": "https://api.github.com/repos/filamentphp/notifications/zipball/e14b887e035223028652447b2148806b622f4b0b", + "reference": "e14b887e035223028652447b2148806b622f4b0b", "shasum": "" }, "require": { @@ -1858,20 +1858,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2025-11-02T17:19:40+00:00" + "time": "2025-11-14T12:11:36+00:00" }, { "name": "filament/query-builder", - "version": "v4.2.0", + "version": "v4.2.2", "source": { "type": "git", "url": "https://github.com/filamentphp/query-builder.git", - "reference": "9304ff5fbe7480e7ed06269aa0168dfac716b8a2" + "reference": "0387b4192f8428d88effe19bf83fe0869096aabd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/query-builder/zipball/9304ff5fbe7480e7ed06269aa0168dfac716b8a2", - "reference": "9304ff5fbe7480e7ed06269aa0168dfac716b8a2", + "url": "https://api.github.com/repos/filamentphp/query-builder/zipball/0387b4192f8428d88effe19bf83fe0869096aabd", + "reference": "0387b4192f8428d88effe19bf83fe0869096aabd", "shasum": "" }, "require": { @@ -1904,20 +1904,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2025-11-02T16:56:49+00:00" + "time": "2025-11-14T12:09:18+00:00" }, { "name": "filament/schemas", - "version": "v4.2.0", + "version": "v4.2.2", "source": { "type": "git", "url": "https://github.com/filamentphp/schemas.git", - "reference": "157e01ad569225b304e5b28ea3bde8f8cc6d2192" + "reference": "5b8b8c6c769627e99edd66e6ed2c7e66d85b209b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/schemas/zipball/157e01ad569225b304e5b28ea3bde8f8cc6d2192", - "reference": "157e01ad569225b304e5b28ea3bde8f8cc6d2192", + "url": "https://api.github.com/repos/filamentphp/schemas/zipball/5b8b8c6c769627e99edd66e6ed2c7e66d85b209b", + "reference": "5b8b8c6c769627e99edd66e6ed2c7e66d85b209b", "shasum": "" }, "require": { @@ -1949,11 +1949,11 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2025-11-02T17:20:05+00:00" + "time": "2025-11-11T10:16:25+00:00" }, { "name": "filament/spatie-laravel-media-library-plugin", - "version": "v4.2.0", + "version": "v4.2.2", "source": { "type": "git", "url": "https://github.com/filamentphp/spatie-laravel-media-library-plugin.git", @@ -1990,16 +1990,16 @@ }, { "name": "filament/support", - "version": "v4.2.0", + "version": "v4.2.2", "source": { "type": "git", "url": "https://github.com/filamentphp/support.git", - "reference": "06bafcfc604fe4acc5494cd5193909b51911aeeb" + "reference": "05d57ad1d227fe8f6afa3fbd3141e3d32d24f046" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/support/zipball/06bafcfc604fe4acc5494cd5193909b51911aeeb", - "reference": "06bafcfc604fe4acc5494cd5193909b51911aeeb", + "url": "https://api.github.com/repos/filamentphp/support/zipball/05d57ad1d227fe8f6afa3fbd3141e3d32d24f046", + "reference": "05d57ad1d227fe8f6afa3fbd3141e3d32d24f046", "shasum": "" }, "require": { @@ -2044,20 +2044,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2025-11-02T17:20:06+00:00" + "time": "2025-11-14T12:11:01+00:00" }, { "name": "filament/tables", - "version": "v4.2.0", + "version": "v4.2.2", "source": { "type": "git", "url": "https://github.com/filamentphp/tables.git", - "reference": "8ff5191cc7a33db20856600cd5b1f5f137847111" + "reference": "7d6e4213a886a5fe680a93da2318b29b7c01617e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/tables/zipball/8ff5191cc7a33db20856600cd5b1f5f137847111", - "reference": "8ff5191cc7a33db20856600cd5b1f5f137847111", + "url": "https://api.github.com/repos/filamentphp/tables/zipball/7d6e4213a886a5fe680a93da2318b29b7c01617e", + "reference": "7d6e4213a886a5fe680a93da2318b29b7c01617e", "shasum": "" }, "require": { @@ -2090,20 +2090,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2025-11-02T17:20:05+00:00" + "time": "2025-11-14T12:11:23+00:00" }, { "name": "filament/widgets", - "version": "v4.2.0", + "version": "v4.2.2", "source": { "type": "git", "url": "https://github.com/filamentphp/widgets.git", - "reference": "9ad4b80ae890768f38bc5e773fde7fc980375f22" + "reference": "2d9068f65e8981b468daab00672027b9c64b66dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/widgets/zipball/9ad4b80ae890768f38bc5e773fde7fc980375f22", - "reference": "9ad4b80ae890768f38bc5e773fde7fc980375f22", + "url": "https://api.github.com/repos/filamentphp/widgets/zipball/2d9068f65e8981b468daab00672027b9c64b66dd", + "reference": "2d9068f65e8981b468daab00672027b9c64b66dd", "shasum": "" }, "require": { @@ -2134,7 +2134,7 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2025-10-21T10:01:25+00:00" + "time": "2025-11-14T12:11:44+00:00" }, { "name": "fruitcake/php-cors", @@ -15015,16 +15015,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.3", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/d74205c497bfbca49f34d4bc4c19c17e22db4ebb", + "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb", "shasum": "" }, "require": { @@ -15053,7 +15053,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + "source": "https://github.com/theseer/tokenizer/tree/1.3.0" }, "funding": [ { @@ -15061,7 +15061,7 @@ "type": "github" } ], - "time": "2024-03-03T12:36:25+00:00" + "time": "2025-11-13T13:44:09+00:00" }, { "name": "webmozart/assert", @@ -15131,5 +15131,5 @@ "php": "^8.3" }, "platform-dev": {}, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } From c1599d5870648fc41fb5f48bed8b1f22c0ab2c6c Mon Sep 17 00:00:00 2001 From: danielhe4rt Date: Fri, 14 Nov 2025 15:58:49 -0300 Subject: [PATCH 18/25] wip --- rector.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rector.php b/rector.php index d2c85a57e..354694af6 100644 --- a/rector.php +++ b/rector.php @@ -35,7 +35,10 @@ __DIR__.'/app-modules/*/routes', __DIR__.'/app-modules/*/tests', ]) - ->withSkip([__DIR__.'/bootstrap/cache']) + ->withSkip([ + __DIR__.'/bootstrap/cache', + __DIR__.'/storage', + ]) ->withCache(cacheDirectory: sys_get_temp_dir().'/rector_cache', cacheClass: FileCacheStorage::class) ->withImportNames(importShortClasses: false, removeUnusedImports: true) ->withRootFiles() From 1b4267fbfdb065eafec1032c9417bdd5aa5b12f9 Mon Sep 17 00:00:00 2001 From: RichardGL11 Date: Fri, 14 Nov 2025 17:00:18 -0300 Subject: [PATCH 19/25] chore: adding icons for resources and fixing tenant table --- .../Admin/Resources/Events/EventResource.php | 2 ++ .../Resources/Feedback/FeedbackResource.php | 2 +- .../Resources/Messages/MessageResource.php | 2 +- app-modules/season/src/Models/Season.php | 20 +++++++++++++++++++ .../Resources/Sponsors/SponsorResource.php | 2 +- .../Resources/Tenants/Schemas/TenantForm.php | 4 +++- .../Resources/Tenants/Tables/TenantsTable.php | 14 +++++++++---- .../Resources/Tenants/TenantResource.php | 2 +- .../Admin/Resources/Users/UserResource.php | 2 +- 9 files changed, 40 insertions(+), 10 deletions(-) diff --git a/app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php b/app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php index 861dda14b..86fda7823 100644 --- a/app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php +++ b/app-modules/events/src/Filament/Admin/Resources/Events/EventResource.php @@ -25,6 +25,8 @@ class EventResource extends Resource protected static string|BackedEnum|null $navigationIcon = Heroicon::Calendar; + protected static ?string $label = 'Events'; + public static function form(Schema $schema): Schema { return EventForm::configure($schema); diff --git a/app-modules/feedback/src/Filament/Admin/Resources/Feedback/FeedbackResource.php b/app-modules/feedback/src/Filament/Admin/Resources/Feedback/FeedbackResource.php index 5e69e9bc4..0141fe720 100644 --- a/app-modules/feedback/src/Filament/Admin/Resources/Feedback/FeedbackResource.php +++ b/app-modules/feedback/src/Filament/Admin/Resources/Feedback/FeedbackResource.php @@ -23,7 +23,7 @@ class FeedbackResource extends Resource protected static string|UnitEnum|null $navigationGroup = 'General'; - protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack; + protected static string|BackedEnum|null $navigationIcon = Heroicon::SpeakerWave; protected static ?string $recordTitleAttribute = 'message'; diff --git a/app-modules/message/src/Filament/Admin/Resources/Messages/MessageResource.php b/app-modules/message/src/Filament/Admin/Resources/Messages/MessageResource.php index 9217d053c..5b79e15af 100644 --- a/app-modules/message/src/Filament/Admin/Resources/Messages/MessageResource.php +++ b/app-modules/message/src/Filament/Admin/Resources/Messages/MessageResource.php @@ -23,7 +23,7 @@ class MessageResource extends Resource protected static string|UnitEnum|null $navigationGroup = 'Gamefication'; - protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack; + protected static string|BackedEnum|null $navigationIcon = Heroicon::ChatBubbleBottomCenter; protected static ?string $recordTitleAttribute = 'content'; diff --git a/app-modules/season/src/Models/Season.php b/app-modules/season/src/Models/Season.php index e34cd9452..279bfa666 100644 --- a/app-modules/season/src/Models/Season.php +++ b/app-modules/season/src/Models/Season.php @@ -13,7 +13,19 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Support\Facades\Date; +/** + * @property int $tenant_id + * @property string $name + * @property string $description + * @property int $messages_count + * @property int $participants_count + * @property int $meetings_count + * @property int $badges_count + * @property Date $started_at + * @property Date $ended_at + */ final class Season extends Model { use HasFactory; @@ -62,4 +74,12 @@ protected static function newFactory(): SeasonFactory { return SeasonFactory::new(); } + + protected function casts(): array + { + return [ + 'started_at' => 'datetime', + 'ended_at' => 'datetime', + ]; + } } diff --git a/app-modules/sponsors/src/Filament/Resources/Sponsors/SponsorResource.php b/app-modules/sponsors/src/Filament/Resources/Sponsors/SponsorResource.php index 063c8d052..825e1e297 100644 --- a/app-modules/sponsors/src/Filament/Resources/Sponsors/SponsorResource.php +++ b/app-modules/sponsors/src/Filament/Resources/Sponsors/SponsorResource.php @@ -23,7 +23,7 @@ class SponsorResource extends Resource protected static string|UnitEnum|null $navigationGroup = 'General'; - protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack; + protected static string|BackedEnum|null $navigationIcon = Heroicon::Banknotes; protected static ?string $recordTitleAttribute = 'name'; diff --git a/app-modules/tenant/src/Filament/Admin/Resources/Tenants/Schemas/TenantForm.php b/app-modules/tenant/src/Filament/Admin/Resources/Tenants/Schemas/TenantForm.php index cb3540d35..fb43c874c 100644 --- a/app-modules/tenant/src/Filament/Admin/Resources/Tenants/Schemas/TenantForm.php +++ b/app-modules/tenant/src/Filament/Admin/Resources/Tenants/Schemas/TenantForm.php @@ -6,6 +6,7 @@ use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; +use Filament\Forms\Components\Toggle; use Filament\Schemas\Schema; class TenantForm @@ -18,7 +19,8 @@ public static function configure(Schema $schema): Schema TextInput::make('slug'), Select::make('owner_id') ->relationship('owner', 'name'), - Select::make('active')->boolean(), + Toggle::make('active') + ->required(), ]); } } diff --git a/app-modules/tenant/src/Filament/Admin/Resources/Tenants/Tables/TenantsTable.php b/app-modules/tenant/src/Filament/Admin/Resources/Tenants/Tables/TenantsTable.php index 428839ae2..b7d834491 100644 --- a/app-modules/tenant/src/Filament/Admin/Resources/Tenants/Tables/TenantsTable.php +++ b/app-modules/tenant/src/Filament/Admin/Resources/Tenants/Tables/TenantsTable.php @@ -7,6 +7,8 @@ use Filament\Actions\BulkActionGroup; use Filament\Actions\DeleteBulkAction; use Filament\Actions\EditAction; +use Filament\Tables\Columns\IconColumn; +use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; class TenantsTable @@ -15,10 +17,14 @@ public static function configure(Table $table): Table { return $table ->columns([ - // - ]) - ->filters([ - // + TextColumn::make('name') + ->searchable(), + TextColumn::make('slug') + ->searchable(), + TextColumn::make('owner.name') + ->searchable(), + IconColumn::make('active') + ->boolean(), ]) ->recordActions([ EditAction::make(), diff --git a/app-modules/tenant/src/Filament/Admin/Resources/Tenants/TenantResource.php b/app-modules/tenant/src/Filament/Admin/Resources/Tenants/TenantResource.php index 6424e4068..1939cb522 100644 --- a/app-modules/tenant/src/Filament/Admin/Resources/Tenants/TenantResource.php +++ b/app-modules/tenant/src/Filament/Admin/Resources/Tenants/TenantResource.php @@ -23,7 +23,7 @@ class TenantResource extends Resource protected static string|UnitEnum|null $navigationGroup = 'Administration'; - protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack; + protected static string|BackedEnum|null $navigationIcon = Heroicon::Cube; protected static ?string $recordTitleAttribute = 'name'; diff --git a/app-modules/user/src/Filament/Admin/Resources/Users/UserResource.php b/app-modules/user/src/Filament/Admin/Resources/Users/UserResource.php index 05f9743b1..f0b4a691a 100644 --- a/app-modules/user/src/Filament/Admin/Resources/Users/UserResource.php +++ b/app-modules/user/src/Filament/Admin/Resources/Users/UserResource.php @@ -24,7 +24,7 @@ class UserResource extends Resource protected static string|UnitEnum|null $navigationGroup = 'Administration'; - protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack; + protected static string|BackedEnum|null $navigationIcon = Heroicon::Users; protected static ?string $recordTitleAttribute = 'name'; From 1153abc6dd1ffa6e248376fb7cf34814f6a4daf6 Mon Sep 17 00:00:00 2001 From: danielhe4rt Date: Fri, 14 Nov 2025 17:43:21 -0300 Subject: [PATCH 20/25] wip: update rector --- composer.json | 2 +- composer.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 905c315c7..7f093f430 100644 --- a/composer.json +++ b/composer.json @@ -57,7 +57,7 @@ "pestphp/pest-plugin-laravel": "^4.0.0", "pestphp/pest-plugin-livewire": "^4.0.1", "phpstan/extension-installer": "^1.4.3", - "rector/rector": "2.2.7" + "rector/rector": "^2.2.8" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 18238a3db..bdd850159 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f23b7730f929f7b2de247f4ec70cc736", + "content-hash": "928fdc506212d35d819c245b46199748", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -13871,21 +13871,21 @@ }, { "name": "rector/rector", - "version": "2.2.7", + "version": "2.2.8", "source": { "type": "git", "url": "https://github.com/rectorphp/rector.git", - "reference": "022038537838bc8a4e526af86c2d6e38eaeff7ef" + "reference": "303aa811649ccd1d32e51e62d5c85949d01b5f1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/022038537838bc8a4e526af86c2d6e38eaeff7ef", - "reference": "022038537838bc8a4e526af86c2d6e38eaeff7ef", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/303aa811649ccd1d32e51e62d5c85949d01b5f1b", + "reference": "303aa811649ccd1d32e51e62d5c85949d01b5f1b", "shasum": "" }, "require": { "php": "^7.4|^8.0", - "phpstan/phpstan": "^2.1.26" + "phpstan/phpstan": "^2.1.32" }, "conflict": { "rector/rector-doctrine": "*", @@ -13919,7 +13919,7 @@ ], "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/2.2.7" + "source": "https://github.com/rectorphp/rector/tree/2.2.8" }, "funding": [ { @@ -13927,7 +13927,7 @@ "type": "github" } ], - "time": "2025-10-29T15:46:12+00:00" + "time": "2025-11-12T18:38:00+00:00" }, { "name": "sebastian/cli-parser", From f09ddf8892746a72856bb25b1883119cb1e9e717 Mon Sep 17 00:00:00 2001 From: danielhe4rt Date: Fri, 14 Nov 2025 17:46:16 -0300 Subject: [PATCH 21/25] wip --- .github/workflows/_rector.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/_rector.yml b/.github/workflows/_rector.yml index 435f3f978..ae703c20a 100644 --- a/.github/workflows/_rector.yml +++ b/.github/workflows/_rector.yml @@ -48,4 +48,4 @@ jobs: - name: Run Rector run: | - vendor/bin/rector --debug --dry-run --output-format=github + vendor/bin/rector --dry-run --output-format=github From 73c4074db6cffc76fccfca165ba87fa48acc11d1 Mon Sep 17 00:00:00 2001 From: Gabriel do Carmo Vieira <48625433+gvieira18@users.noreply.github.com> Date: Fri, 14 Nov 2025 19:55:07 -0300 Subject: [PATCH 22/25] revert: remove unused cache and re-add --debug to pipeline --- .github/workflows/_rector.yml | 2 +- rector.php | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/_rector.yml b/.github/workflows/_rector.yml index ae703c20a..435f3f978 100644 --- a/.github/workflows/_rector.yml +++ b/.github/workflows/_rector.yml @@ -48,4 +48,4 @@ jobs: - name: Run Rector run: | - vendor/bin/rector --dry-run --output-format=github + vendor/bin/rector --debug --dry-run --output-format=github diff --git a/rector.php b/rector.php index 354694af6..d2c85a57e 100644 --- a/rector.php +++ b/rector.php @@ -35,10 +35,7 @@ __DIR__.'/app-modules/*/routes', __DIR__.'/app-modules/*/tests', ]) - ->withSkip([ - __DIR__.'/bootstrap/cache', - __DIR__.'/storage', - ]) + ->withSkip([__DIR__.'/bootstrap/cache']) ->withCache(cacheDirectory: sys_get_temp_dir().'/rector_cache', cacheClass: FileCacheStorage::class) ->withImportNames(importShortClasses: false, removeUnusedImports: true) ->withRootFiles() From 5384bbfbbd33d00eee3f62f97ea3ca9113472205 Mon Sep 17 00:00:00 2001 From: Gabriel do Carmo Vieira <48625433+gvieira18@users.noreply.github.com> Date: Fri, 14 Nov 2025 19:55:29 -0300 Subject: [PATCH 23/25] fix: update final class and method settings in configuration --- pint.json | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pint.json b/pint.json index 34df4b964..50e3b984b 100644 --- a/pint.json +++ b/pint.json @@ -13,11 +13,8 @@ "lowercase_keywords": true, "lowercase_static_reference": true, "final_class": false, - "final_internal_class": { - "annotation_include": [], - "annotation_exclude": ["internal"] - }, - "final_public_method_for_abstract_class": true, + "final_internal_class": false, + "final_public_method_for_abstract_class": false, "fully_qualified_strict_types": true, "global_namespace_import": { "import_classes": true, From 9a6364d289357457ea78b40cecbd838d680b6fb5 Mon Sep 17 00:00:00 2001 From: Gabriel do Carmo Vieira <48625433+gvieira18@users.noreply.github.com> Date: Fri, 14 Nov 2025 19:56:03 -0300 Subject: [PATCH 24/25] fix: rector for Dashboard and UserProfile classes --- app-modules/user/src/Filament/User/Pages/Dashboard.php | 5 +++-- app-modules/user/src/Filament/User/Pages/UserProfile.php | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app-modules/user/src/Filament/User/Pages/Dashboard.php b/app-modules/user/src/Filament/User/Pages/Dashboard.php index b4b10ea87..488536c69 100644 --- a/app-modules/user/src/Filament/User/Pages/Dashboard.php +++ b/app-modules/user/src/Filament/User/Pages/Dashboard.php @@ -5,14 +5,15 @@ namespace He4rt\User\Filament\User\Pages; use Filament\Facades\Filament; +use Filament\Pages\Dashboard as FilamentDashboard; use He4rt\Tenant\Models\Tenant; use Livewire\Attributes\Computed; -class Dashboard extends \Filament\Pages\Dashboard +class Dashboard extends FilamentDashboard { protected string $view = 'users::filament.app-dashboard'; - private Tenant $tenant; + private ?Tenant $tenant = null; public function mount(): void { diff --git a/app-modules/user/src/Filament/User/Pages/UserProfile.php b/app-modules/user/src/Filament/User/Pages/UserProfile.php index edc21196a..1e96877fc 100644 --- a/app-modules/user/src/Filament/User/Pages/UserProfile.php +++ b/app-modules/user/src/Filament/User/Pages/UserProfile.php @@ -50,7 +50,7 @@ /** * @property-read Schema $form */ -final class UserProfile extends Page +class UserProfile extends Page { use CanUseDatabaseTransactions; use HasMaxWidth; From bf02e3aad99e0fd79f16b1d965ce20bd9ee63723 Mon Sep 17 00:00:00 2001 From: Gabriel do Carmo Vieira <48625433+gvieira18@users.noreply.github.com> Date: Fri, 14 Nov 2025 19:58:46 -0300 Subject: [PATCH 25/25] ci: use rector on parallel mode --- .github/workflows/_rector.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/_rector.yml b/.github/workflows/_rector.yml index 435f3f978..ae703c20a 100644 --- a/.github/workflows/_rector.yml +++ b/.github/workflows/_rector.yml @@ -48,4 +48,4 @@ jobs: - name: Run Rector run: | - vendor/bin/rector --debug --dry-run --output-format=github + vendor/bin/rector --dry-run --output-format=github