jeffgreco13 / filament-breezy

MIT License
738 stars 131 forks source link

Overwrite PersonalInfo component and add extra field #207

Open bernhardh opened 1 year ago

bernhardh commented 1 year ago

I have created a class to overwrite the PersonalInfo component:

class PersonalInfo extends \Jeffgreco13\FilamentBreezy\Livewire\PersonalInfo
{
    public array $only = ['name','name_display', 'email'];

    public function getProfileFormSchema(): array
    {
        return [
            TextInput::make("name")
                ->columnSpanFull()
                ->label("Benutzername")
                ->hint("Änderbar nur durch Admins")
                ->disabled(fn(): bool => ! $this->user->hasRole([User::ROLE_SUPER_ADMIN, User::ROLE_ADMIN])),
            TextInput::make("name_display")
                ->label("Anzeigename")
                ->columnSpanFull()
                ->hint("zB. Vor- und Familienname"),
            TextInput::make("email")->unique(config('filament-breezy.user_model'), ignorable: $this->user)
                ->disabled(fn(): bool => ! $this->user->hasRole([User::ROLE_SUPER_ADMIN, User::ROLE_ADMIN]))
                ->hint("Änderbar nur durch Admins")
                ->columnSpanFull()
                ->label("E-Mail"),
        ];
    }
}

and registered it:

BreezyCore::make()
    ->myProfileComponents([
        'personal_info' => PersonalInfo::class
    ])

The field exists in the table:

image

But I cant update it. After save the field disapears. When I reload the page, the old value is show:

https://github.com/jeffgreco13/filament-breezy/assets/642292/27bbfee6-8733-4425-9935-d9908fd0d72d

jeffgreco13 commented 1 year ago

Did you add name_display to your fillable property on the User model?

bernhardh commented 1 year ago

I am using Model::unguard(); in Service Provider. Tried it now with adding it to the $fillable as well.

Nearly the same code worked in v1 (Filament v2).

bernhardh commented 1 year ago

I tried now to add the component instead of overwriting it, with the same result:

->myProfileComponents([
    PersonalInfo::class
])
jeffgreco13 commented 1 year ago

Can you ensure the ->myProfile() method is added to BreezyCore?

BreezyCore::make()
    ->myProfile()
    ->myProfileComponents([
        'personal_info' => PersonalInfo::class
    ])
bernhardh commented 1 year ago

Thanks for reply.

Yes. Thats the full code:

BreezyCore::make()
    ->myProfileComponents([
        'personal_info' => PersonalInfo::class
    ])
    ->myProfile(
        shouldRegisterUserMenu: true, // Sets the 'account' link in the panel User Menu (default = true),
        shouldRegisterNavigation: false, // Adds a main navigation item for the My Profile page (default = false)
        hasAvatars: false // enables the avatar upload form component. (default = false)
    )

In the meantime, I have created a custom page with a form on it which does the same job and i have disabled now the shouldRegisterUserMenu as well. This workaround is ok for me.

fordiquez commented 1 year ago

The same error occurs when trying to upload a new avatar

LucVK commented 1 year ago

I have exactly the same problem. See my issue #219 and the workaround.

0proboy0 commented 1 year ago

I have exactly the same problem, Laravel 10, Filament 3. Is there any solution please? @jeffgreco13

jeffgreco13 commented 1 year ago

Everyone here is suffering from the same problem where the component is "resetting" back to the original PersonalInfo::class after submit?

I was able to override my component successfully: https://share.getcloudapp.com/GGu5GKnb?embed=true

My new component:

<?php

namespace App\Livewire;

use Filament\Forms;

class TestPersonalInfo extends \Jeffgreco13\FilamentBreezy\Livewire\PersonalInfo
{
    public array $only = ['name','team_id'];

    public function getProfileFormSchema(): array
    {
        return [
            Forms\Components\TextInput::make("name")
                ->columnSpanFull()
                ->label("Benutzername")
                ->hint("Änderbar nur durch Admins"),
            Forms\Components\TextInput::make("team_id")
        ];
    }
}

Registering BreezyCore in AdminPanelServiceProvider:

          ->plugin(
                BreezyCore::make()
                    ->myProfile(hasAvatars:false)
                    ->myProfileComponents([
                        'personal_info' => TestPersonalInfo::class
                    ])
                    ->enableTwoFactorAuthentication()
            );

If someone could provide the following details, then I can try to recreate the error in my own installation and provide a patch:

Please also make sure you are on latest versions: composer update && php artisan filament:upgrade && php artisan optimize:clear

0proboy0 commented 1 year ago

@jeffgreco13 Composer.json

{
    "name": "laravel/laravel",
    "type": "project",
    "description": "The skeleton application for the Laravel framework.",
    "keywords": [
        "laravel",
        "framework"
    ],
    "license": "MIT",
    "require": {
        "php": "^8.1",
        "filament/filament": "^3.0-stable",
        "guzzlehttp/guzzle": "^7.2",
        "jeffgreco13/filament-breezy": "^2.1",
        "laravel/fortify": "^1.17",
        "laravel/framework": "^10.10",
        "laravel/sanctum": "^3.2",
        "laravel/tinker": "^2.8"
    },
    "require-dev": {
        "fakerphp/faker": "^1.9.1",
        "laravel/pint": "^1.0",
        "laravel/sail": "^1.18",
        "mockery/mockery": "^1.4.4",
        "nunomaduro/collision": "^7.0",
        "phpunit/phpunit": "^10.1",
        "spatie/laravel-ignition": "^2.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Database\\Factories\\": "database/factories/",
            "Database\\Seeders\\": "database/seeders/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    },
    "scripts": {
        "post-autoload-dump": [
            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
            "@php artisan package:discover --ansi",
            "@php artisan filament:upgrade"
        ],
        "post-update-cmd": [
            "@php artisan vendor:publish --tag=laravel-assets --ansi --force"
        ],
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "@php artisan key:generate --ansi"
        ]
    },
    "extra": {
        "laravel": {
            "dont-discover": []
        }
    },
    "config": {
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true,
        "allow-plugins": {
            "pestphp/pest-plugin": true,
            "php-http/discovery": true
        }
    },
    "minimum-stability": "dev",
    "prefer-stable": true
}

AdminPanelProvider.php

<?php

namespace App\Providers\Filament;

use App\Filament\Pages\Auth\Register;
use App\Livewire\Overwritten\Filament\FilamentBreezy\PersonalInfo;
use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Pages;
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Widgets;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\AuthenticateSession;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;
use Jeffgreco13\FilamentBreezy\BreezyCore;

class AdminPanelProvider extends PanelProvider
{
    public function panel(Panel $panel): Panel
    {
        return $panel
            ->default()
            ->id('dashboard')
            ->path('dashboard')
            ->login()
            ->registration(Register::class)
            ->passwordReset()
            ->emailVerification()
            ->colors([
                'primary' => '#5e047a',
            ])
            ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
            ->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
            ->pages([
                Pages\Dashboard::class,
            ])
            ->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
            ->widgets([
                Widgets\AccountWidget::class,
                Widgets\FilamentInfoWidget::class,
            ])
            ->middleware([
                EncryptCookies::class,
                AddQueuedCookiesToResponse::class,
                StartSession::class,
                AuthenticateSession::class,
                ShareErrorsFromSession::class,
                VerifyCsrfToken::class,
                SubstituteBindings::class,
                DisableBladeIconComponents::class,
                DispatchServingFilamentEvent::class,
            ])
            ->authMiddleware([
                Authenticate::class,
            ])
            ->plugin(
                BreezyCore::make()
                    ->myProfile(
                        slug: 'profile',
                        hasAvatars: false
                    )
                    ->myProfileComponents([
                        'personal_info' => PersonalInfo::class,
                    ])
            )
            ->favicon(asset('images/favicon.ico'));
    }
}

My Custom PersonalProfile.php

<?php

namespace App\Livewire\Overwritten\Filament\FilamentBreezy;

use App\Models\User;
use Jeffgreco13\FilamentBreezy\Livewire\PersonalInfo as BasePersonalInfo;
use Filament\Forms;

class PersonalInfo extends BasePersonalInfo
{
    protected string $view = "livewire.Overwritten.Filament.FilamentBreezy.personal-info";

    public array $only = ['name', 'email', 'phone'];

    protected function getProfileFormSchema()
    {
        $name = Forms\Components\TextInput::make('name')
            ->required()
            ->label(__('filament-breezy::default.fields.name'));
        $email = Forms\Components\TextInput::make('email')
            ->required()
            ->email()
            ->unique($this->userClass, ignorable: $this->user)
            ->label(__('filament-breezy::default.fields.email'));
        $phone = Forms\Components\TextInput::make('phone')
            ->required()
            ->unique(table: User::class, ignoreRecord: true)
            ->rules(['numeric', 'digits:10'])
            ->label(__('filament-panels::pages/auth/edit-profile.form.phone.label'));

        if ($this->hasAvatars) {
            return [
                filament('filament-breezy')->getAvatarUploadComponent(),
                Forms\Components\Group::make([
                    $name,
                    $email,
                    $phone
                ])->columnSpan(2),
            ];
        } else {
            return [
                Forms\Components\Group::make([
                    $name,
                    $email,
                    $phone
                ])->columnSpan(3)
            ];
        }
    }
}

presonal-info.blade.php

<x-filament-breezy::grid-section md=2 title="{{ __('filament-breezy::default.profile.personal_info.heading') }}" description="{{ __('filament-breezy::default.profile.personal_info.subheading') }}">
    <x-filament::card>
        <form wire:submit.prevent="submit" class="space-y-6">

            {{ $this->form }}

            <div class="text-right">
                <x-filament::button type="submit" form="submit" class="align-right">
                    {{ __('filament-breezy::default.profile.personal_info.submit.label') }}
                </x-filament::button>
            </div>
        </form>
    </x-filament::card>
</x-filament-breezy::grid-section>
DSpeichert commented 1 year ago

I think I found the cause. I believe the root cause of the problem is that the custom Livewire component that myself and @bernhardh were using to override personal_info was ALSO called PersonalInfo (i.e. the classname was likely App\Livewire\PersonalInfo).

This works if we comment out this line: https://github.com/jeffgreco13/filament-breezy/blob/dfe347184687215048c9cba403ee2ab3a50a613a/src/BreezyCore.php#L98

Another workaround is to simply rename the custom PersonalInfo class to any other name. I'm guessing (because I don't know 100% how Livewire works under the hood) Livewire produces an alias of personal_info from the class name of App\Livewire\PersonalInfo automatically and that is then (sometimes?) overriden by that line in boot() of BreezyCore.php.

xalabama commented 5 months ago

Thanks @DSpeichert. In addition to your comment, its also possible to overwrite the registration of the livewire component inside the boot method of your AppServiceProvider.