diff --git a/database/migrations/create_menus_table.php.stub b/database/migrations/create_menus_table.php.stub index ad14dbf..d47e3d2 100644 --- a/database/migrations/create_menus_table.php.stub +++ b/database/migrations/create_menus_table.php.stub @@ -32,10 +32,8 @@ return new class extends Migration Schema::create(config('filament-menu-builder.tables.menu_locations'), function (Blueprint $table) { $table->id(); $table->foreignIdFor(Menu::class)->constrained()->cascadeOnDelete(); - $table->string('location', 50); + $table->string('location')->unique(); $table->timestamps(); - - $table->unique(['menu_id', 'location']); }); } diff --git a/resources/lang/en/menu-builder.php b/resources/lang/en/menu-builder.php index 503f148..adda2bf 100644 --- a/resources/lang/en/menu-builder.php +++ b/resources/lang/en/menu-builder.php @@ -12,22 +12,32 @@ 'label' => 'Name', ], 'locations' => [ - 'label' => 'Locations', - 'description' => 'Choose where to display the menu.', 'empty' => 'Unassigned', - 'actions' => [ - 'select_all' => 'Select all', - 'deselect_all' => 'Deselect all', - ], ], 'is_visible' => [ - 'label' => 'Visible', + 'label' => 'Visibility', + 'visible' => 'Visible', + 'hidden' => 'Hidden', ], ], 'actions' => [ 'add' => [ 'label' => 'Add to Menu', ], + 'locations' => [ + 'label' => 'Locations', + 'heading' => 'Manage Locations', + 'description' => 'Choose which menu appears at each location.', + 'submit' => 'Update', + 'form' => [ + 'location' => [ + 'label' => 'Location', + ], + 'menu' => [ + 'label' => 'Assigned Menu', + ], + ], + ], ], 'items' => [ 'empty' => [ @@ -48,6 +58,9 @@ 'created' => [ 'title' => 'Link created', ], + 'locations' => [ + 'title' => 'Menu locations updated', + ], ], 'panel' => [ 'empty' => [ diff --git a/resources/lang/vi/menu-builder.php b/resources/lang/vi/menu-builder.php index 78f667f..d79f0ff 100644 --- a/resources/lang/vi/menu-builder.php +++ b/resources/lang/vi/menu-builder.php @@ -12,22 +12,32 @@ 'label' => 'Tên', ], 'locations' => [ - 'label' => 'Vị trí', - 'description' => 'Chọn vị trí hiển thị menu.', 'empty' => 'Chưa gán', - 'actions' => [ - 'select_all' => 'Chọn tất cả', - 'deselect_all' => 'Bỏ chọn tất cả', - ], ], 'is_visible' => [ 'label' => 'Hiển thị', + 'visible' => 'Hiển thị', + 'hidden' => 'Ẩn', ], ], 'actions' => [ 'add' => [ 'label' => 'Thêm vào Menu', ], + 'locations' => [ + 'label' => 'Vị trí', + 'heading' => 'Quản lý vị trí', + 'description' => 'Chọn menu nào xuất hiện ở mỗi vị trí.', + 'submit' => 'Cập nhật', + 'form' => [ + 'location' => [ + 'label' => 'Vị trí', + ], + 'menu' => [ + 'label' => 'Menu đã gán', + ], + ], + ], ], 'items' => [ 'empty' => [ @@ -48,6 +58,9 @@ 'created' => [ 'title' => 'Liên kết đã được tạo', ], + 'locations' => [ + 'title' => 'Cập nhật vị trí menu', + ], ], 'panel' => [ 'empty' => [ diff --git a/src/Concerns/HasLocationAction.php b/src/Concerns/HasLocationAction.php new file mode 100644 index 0000000..42ef536 --- /dev/null +++ b/src/Concerns/HasLocationAction.php @@ -0,0 +1,85 @@ +label(__('filament-menu-builder::menu-builder.actions.locations.label')) + ->modalHeading(__('filament-menu-builder::menu-builder.actions.locations.heading')) + ->modalDescription(__('filament-menu-builder::menu-builder.actions.locations.description')) + ->modalSubmitActionLabel(__('filament-menu-builder::menu-builder.actions.locations.submit')) + ->modalWidth(MaxWidth::Large) + ->color('gray') + ->fillForm(fn () => $this->getRegisteredLocations()->map(fn ($location, $key) => [ + 'location' => $location, + 'menu' => $this->getMenuLocations()->where('location', $key)->first()?->menu_id, + ])->all()) + ->action(function (array $data) { + $locations = collect($data) + ->map(fn ($item) => $item['menu'] ?? null) + ->all(); + + $this->getMenuLocations() + ->pluck('location') + ->diff($this->getRegisteredLocations()->keys()) + ->each(fn ($location) => $this->getMenuLocations()->where('location', $location)->each->delete()); + + foreach ($locations as $location => $menu) { + if (! $menu) { + $this->getMenuLocations()->where('location', $location)->each->delete(); + + continue; + } + + MenuLocation::updateOrCreate( + ['location' => $location], + ['menu_id' => $menu] + ); + } + + Notification::make() + ->title(__('filament-menu-builder::menu-builder.notifications.locations.title')) + ->success() + ->send(); + }) + ->form(fn () => $this->getRegisteredLocations()->map( + fn ($location, $key) => Components\Grid::make(2) + ->statePath($key) + ->schema([ + Components\TextInput::make('location') + ->label(__('filament-menu-builder::menu-builder.actions.locations.form.location.label')) + ->hiddenLabel($key !== $this->getRegisteredLocations()->keys()->first()) + ->disabled(), + + Components\Select::make('menu') + ->label(__('filament-menu-builder::menu-builder.actions.locations.form.menu.label')) + ->searchable() + ->hiddenLabel($key !== $this->getRegisteredLocations()->keys()->first()) + ->options($this->getModel()::all()->pluck('name', 'id')->all()), + ]) + )->all()); + } + + protected function getMenuLocations(): Collection + { + return $this->menuLocations ??= MenuLocation::all(); + } + + protected function getRegisteredLocations(): Collection + { + return collect(FilamentMenuBuilderPlugin::get()->getLocations()); + } +} diff --git a/src/Livewire/CreateCustomLink.php b/src/Livewire/CreateCustomLink.php index c1cf328..a87e1e3 100644 --- a/src/Livewire/CreateCustomLink.php +++ b/src/Livewire/CreateCustomLink.php @@ -42,7 +42,7 @@ public function save(): void 'title' => $this->title, 'url' => $this->url, 'target' => $this->target, - 'order' => $this->menu->menuItems()->max('order') + 1, + 'order' => $this->menu->menuItems->max('order') + 1, ]); Notification::make() diff --git a/src/Livewire/MenuItems.php b/src/Livewire/MenuItems.php index 4c40df5..9cb1700 100644 --- a/src/Livewire/MenuItems.php +++ b/src/Livewire/MenuItems.php @@ -39,7 +39,7 @@ class MenuItems extends Component implements HasActions, HasForms #[On('menu:created')] public function menuItems(): Collection { - return $this->menu->menuItems()->get(); + return $this->menu->menuItems; } public function reorder(array $order, ?string $parentId = null): void diff --git a/src/Livewire/MenuPanel.php b/src/Livewire/MenuPanel.php index f54e5b4..90c7b6e 100644 --- a/src/Livewire/MenuPanel.php +++ b/src/Livewire/MenuPanel.php @@ -74,7 +74,7 @@ public function add(): void { $this->validate(); - $order = $this->menu->menuItems()->max('order') ?? 0; + $order = $this->menu->menuItems->max('order') ?? 0; $selectedItems = collect($this->items) ->filter(fn ($item) => in_array($item['title'], $this->data)) diff --git a/src/Models/Menu.php b/src/Models/Menu.php index 9779732..93d068d 100644 --- a/src/Models/Menu.php +++ b/src/Models/Menu.php @@ -36,4 +36,11 @@ public function menuItems(): HasMany ->orderBy('order') ->with('children'); } + + public static function location(string $location): ?self + { + return MenuLocation::with('menu') + ->where('location', $location) + ->first()?->menu; + } } diff --git a/src/Resources/MenuResource.php b/src/Resources/MenuResource.php index 2c011d5..b6f8731 100644 --- a/src/Resources/MenuResource.php +++ b/src/Resources/MenuResource.php @@ -6,15 +6,9 @@ use Datlechin\FilamentMenuBuilder\FilamentMenuBuilderPlugin; use Datlechin\FilamentMenuBuilder\Models\Menu; -use Filament\Forms\Components\Actions\Action; +use Filament\Forms\Components; use Filament\Forms\Components\Component; -use Filament\Forms\Components\Group; -use Filament\Forms\Components\TextInput; -use Filament\Forms\Components\Toggle; -use Filament\Forms\Components\ToggleButtons; use Filament\Forms\Form; -use Filament\Forms\Get; -use Filament\Forms\Set; use Filament\Resources\Resource; use Filament\Tables; use Filament\Tables\Table; @@ -27,36 +21,32 @@ class MenuResource extends Resource public static function form(Form $form): Form { - $locations = FilamentMenuBuilderPlugin::get()->getLocations(); - return $form ->columns(1) ->schema([ - TextInput::make('name') - ->label(__('filament-menu-builder::menu-builder.resource.name.label')) - ->required(), - ToggleButtons::make('locations') - ->multiple() - ->inline() - ->reactive() - ->visible(fn (string $context) => $context === 'edit' && $locations) - ->label(__('filament-menu-builder::menu-builder.resource.locations.label')) - ->afterStateHydrated(fn (Menu $menu, Set $set) => $set('locations', $menu->locations->pluck('location'))) - ->helperText(__('filament-menu-builder::menu-builder.resource.locations.description')) - ->hintActions([ - Action::make(__('filament-menu-builder::menu-builder.resource.locations.actions.select_all')) - ->action(fn (Set $set) => $set('locations', array_keys($locations))) - ->visible(fn (Get $get) => count($get('locations')) !== count($locations)), + Components\Grid::make(4) + ->schema([ + Components\TextInput::make('name') + ->label(__('filament-menu-builder::menu-builder.resource.name.label')) + ->required() + ->columnSpan(3), - Action::make(__('filament-menu-builder::menu-builder.resource.locations.actions.deselect_all')) - ->action(fn (Set $set) => $set('locations', [])) - ->visible(fn (Get $get) => count($get('locations')) === count($locations)), - ]) - ->options($locations), - Toggle::make('is_visible') - ->label(__('filament-menu-builder::menu-builder.resource.is_visible.label')) - ->default(true), - Group::make() + Components\ToggleButtons::make('is_visible') + ->grouped() + ->options([ + true => __('filament-menu-builder::menu-builder.resource.is_visible.visible'), + false => __('filament-menu-builder::menu-builder.resource.is_visible.hidden'), + ]) + ->colors([ + true => 'primary', + false => 'danger', + ]) + ->required() + ->label(__('filament-menu-builder::menu-builder.resource.is_visible.label')) + ->default(true), + ]), + + Components\Group::make() ->visible(fn (Component $component) => $component->evaluate(FilamentMenuBuilderPlugin::get()->getMenuFields()) !== []) ->schema(FilamentMenuBuilderPlugin::get()->getMenuFields()), ]); @@ -73,7 +63,7 @@ public static function table(Table $table): Table ->label(__('filament-menu-builder::menu-builder.resource.name.label')), Tables\Columns\TextColumn::make('locations.location') ->default($default = __('filament-menu-builder::menu-builder.resource.locations.empty')) - ->color(fn (string $state) => $state !== $default ? 'primary' : 'gray') + ->color(fn (string $state) => array_key_exists($state, $locations) ? 'primary' : 'gray') ->formatStateUsing(fn (string $state) => $locations[$state] ?? $state) ->limitList(2) ->badge(), diff --git a/src/Resources/MenuResource/Pages/EditMenu.php b/src/Resources/MenuResource/Pages/EditMenu.php index f20ba61..126fe40 100644 --- a/src/Resources/MenuResource/Pages/EditMenu.php +++ b/src/Resources/MenuResource/Pages/EditMenu.php @@ -4,17 +4,17 @@ namespace Datlechin\FilamentMenuBuilder\Resources\MenuResource\Pages; +use Datlechin\FilamentMenuBuilder\Concerns\HasLocationAction; use Datlechin\FilamentMenuBuilder\FilamentMenuBuilderPlugin; -use Datlechin\FilamentMenuBuilder\Models\Menu; use Filament\Actions; use Filament\Forms\Components\Section; use Filament\Forms\Form; use Filament\Resources\Pages\EditRecord; -use Illuminate\Database\Eloquent\Model; -use Illuminate\Support\Arr; class EditMenu extends EditRecord { + use HasLocationAction; + protected static string $view = 'filament-menu-builder::edit-record'; public static function getResource(): string @@ -34,30 +34,7 @@ protected function getHeaderActions(): array { return [ Actions\DeleteAction::make(), + $this->getLocationAction(), ]; } - - protected function handleRecordUpdate(Model $record, array $data): Model - { - $registeredLocations = FilamentMenuBuilderPlugin::get()->getLocations(); - - $locations = collect(Arr::pull($data, 'locations') ?: []) - ->filter(fn ($location) => array_key_exists($location, $registeredLocations)) - ->values(); - - /** @var Menu */ - $record = parent::handleRecordUpdate($record, $data); - - $record->locations() - ->whereNotIn('location', $locations) - ->delete(); - - foreach ($locations as $location) { - $record->locations()->firstOrCreate([ - 'location' => $location, - ]); - } - - return $record; - } } diff --git a/src/Resources/MenuResource/Pages/ListMenus.php b/src/Resources/MenuResource/Pages/ListMenus.php index 0e64946..5141eab 100644 --- a/src/Resources/MenuResource/Pages/ListMenus.php +++ b/src/Resources/MenuResource/Pages/ListMenus.php @@ -4,12 +4,15 @@ namespace Datlechin\FilamentMenuBuilder\Resources\MenuResource\Pages; +use Datlechin\FilamentMenuBuilder\Concerns\HasLocationAction; use Datlechin\FilamentMenuBuilder\FilamentMenuBuilderPlugin; use Filament\Actions; use Filament\Resources\Pages\ListRecords; class ListMenus extends ListRecords { + use HasLocationAction; + public static function getResource(): string { return FilamentMenuBuilderPlugin::get()->getResource(); @@ -19,6 +22,7 @@ protected function getHeaderActions(): array { return [ Actions\CreateAction::make(), + $this->getLocationAction(), ]; } }