From 41cf6eb5308015e65d804b855b3d92f17cbb32e5 Mon Sep 17 00:00:00 2001 From: Amir Date: Tue, 15 Nov 2022 16:39:10 +0400 Subject: [PATCH] Structuring Menu with hierarchy Model --- app/Http/Livewire/Admin/Menu/MenuParent.php | 33 +++-- .../Admin/Menu/MenuParentDatatable.php | 9 +- app/Models/Menu.php | 8 ++ app/Traits/Data.php | 8 ++ app/View/Components/Item/Select.php | 28 +++++ app/View/Components/Svg/Security.php | 28 +++++ composer.json | 3 +- composer.lock | 116 +++++++++++++++++- .../2022_11_09_085026_create_menus_table.php | 6 +- .../components/item/elements/select.blade.php | 14 +++ .../views/components/item/select.blade.php | 40 ++++++ .../views/components/layout/content.blade.php | 2 +- .../views/components/layout/main.blade.php | 2 +- .../views/components/svg/security.blade.php | 3 + .../views/livewire/admin/dashboard.blade.php | 14 +++ .../views/livewire/admin/menu/level.blade.php | 2 +- .../livewire/admin/menu/menu-parent.blade.php | 53 ++++++-- tailwind.config.js | 2 + 18 files changed, 346 insertions(+), 25 deletions(-) create mode 100644 app/View/Components/Item/Select.php create mode 100644 app/View/Components/Svg/Security.php create mode 100644 resources/views/components/item/elements/select.blade.php create mode 100644 resources/views/components/item/select.blade.php create mode 100644 resources/views/components/svg/security.blade.php create mode 100644 resources/views/livewire/admin/dashboard.blade.php diff --git a/app/Http/Livewire/Admin/Menu/MenuParent.php b/app/Http/Livewire/Admin/Menu/MenuParent.php index ef2a70a..bb30a63 100644 --- a/app/Http/Livewire/Admin/Menu/MenuParent.php +++ b/app/Http/Livewire/Admin/Menu/MenuParent.php @@ -3,6 +3,7 @@ namespace App\Http\Livewire\Admin\Menu; use App\Models\Menu; +use App\Traits\Data; use App\Traits\General; use Illuminate\Database\Eloquent\Model; use Livewire\Component; @@ -10,13 +11,17 @@ class MenuParent extends Component { use General; + use Data; public string $pageHeader = 'Menu'; public array $menu; public ?int $rowID = null; + public ?int $menuID = null; public $menuRecord = null; + public array $parentData = []; + protected $listeners = ['createMenu', 'editMenu', 'deleteMenu']; @@ -37,12 +42,15 @@ public function resetForm() 'menu.name.required' => 'Menu name is required.', 'menu.name.min' => 'Menu must be at-least 4 letters long.', 'menu.name.unique' => ':attribute menu already exists!.', + 'menu.parent_id.integer' => ':attribute must be integer.', + 'menu.parent_id.gt' => ':attribute must be positive integer.', ]; protected function rules() { return [ - 'menu.name' => 'required|min:4|unique:menus,name,' . $this->rowID + 'menu.name' => 'required|min:4|unique:menus,name,' . $this->rowID, + 'menu.parent_id'=>'numeric|gt:0' ]; } @@ -50,25 +58,31 @@ protected function validationAttributes() { return [ 'menu.name' => $this->menu['name'], + 'menu.menuID' => $this->menu['menuID'], ]; } public function resetInput() { - $this->menu = ['name' => '']; + $this->menu = ['name' => '','menuID'=>null]; } protected function getRecord($row) { $this->rowID = $row['id']; - $this->menuRecord = Menu::find($row)->first(); + $this->menuRecord = Menu::find($this->rowID)->first(); } - public function createMenu() + public function createMenu($id=null) { + + $this->resetForm(); + if($id !== null) $this->menu['menuID']= $id; $this->modelInfo('create', 'Menu'); + $this->parentData = $this->get_array_for_select_input(Menu::select('id', 'name')->where('parent_id',null)->where('id',$id)->get()); + $this->dispatchBrowserEvent('FirstModel', ['show' => true]); } @@ -88,12 +102,13 @@ public function deleteMenu($row) $this->dispatchBrowserEvent('FirstModel', ['show' => true]); } - protected function afterSave($formType){ + protected function afterSave($formType) + { $this->emit('refreshDatatable'); $this->resetForm(); $this->dispatchBrowserEvent('FirstModel', ['show' => false]); - switch($formType){ + switch ($formType) { case 'create': $this->dispatchBrowserEvent('Toast', ['show' => true, 'type' => 'success', 'message' => "'" . $this->menuRecord->name . "'" . ' was added to Menu Level!']); break; @@ -112,13 +127,13 @@ protected function afterSave($formType){ public function submit() { - switch ($this->formType) { case 'create': $this->validate(); $this->menuRecord = new Menu(); $this->menuRecord->name = $this->menu['name']; + ($this->menu['menuID'] !== null) ? $this->menuRecord->parent_id = $this->menu['menuID'] : $this->menuRecord->parent_id=null; $this->menuRecord->save(); $this->afterSave($this->formType); break; @@ -126,6 +141,7 @@ public function submit() case 'update': $this->validate(); $this->menuRecord->name = $this->menu['name']; + $this->menuRecord->menus_id = $this->menu['menuID']; $this->menuRecord->save(); $this->afterSave($this->formType); break; @@ -141,6 +157,7 @@ public function submit() public function render() { - return view('livewire.admin.menu.menu-parent'); + $menus = Menu::with('childMenus')->where('parent_id','=',null)->get(); + return view('livewire.admin.menu.menu-parent',['menus'=>$menus]); } } diff --git a/app/Http/Livewire/Admin/Menu/MenuParentDatatable.php b/app/Http/Livewire/Admin/Menu/MenuParentDatatable.php index 59e9be1..a4fa879 100644 --- a/app/Http/Livewire/Admin/Menu/MenuParentDatatable.php +++ b/app/Http/Livewire/Admin/Menu/MenuParentDatatable.php @@ -38,7 +38,11 @@ public function configure(): void ]; } elseif ($column->isField('name')) { return [ - 'class' => '!w-[60%]', + 'class' => '!w-[50%]', + ]; + }elseif ($column->isField('parent_id')) { + return [ + 'class' => '!w-[10%]', ]; } elseif ($column->isField('created_at')) { return [ @@ -91,6 +95,9 @@ public function columns(): array Column::make("Name", "name") ->searchable() ->sortable(), + Column::make("Belongs to", "parent_id") + ->searchable() + ->sortable(), Column::make("Created at", "created_at") ->format(fn($value, $row, Column $column) => $row->created_at->diffForHumans()) ->sortable(), diff --git a/app/Models/Menu.php b/app/Models/Menu.php index 17f7ad2..b78a6fe 100644 --- a/app/Models/Menu.php +++ b/app/Models/Menu.php @@ -4,8 +4,16 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; class Menu extends Model { use HasFactory; +// use HasRecursiveRelationships; + public function childMenus() + { + return $this->hasMany(Menu::class, 'parent_id', 'id')->with('childMenus'); + } + + } diff --git a/app/Traits/Data.php b/app/Traits/Data.php index 05dd26a..e512832 100644 --- a/app/Traits/Data.php +++ b/app/Traits/Data.php @@ -8,4 +8,12 @@ public static function uri_guard($request) { return explode('/', $request->getRequestUri())[1]; } + + public function get_array_for_select_input($record){ + $array=[]; + foreach ($record as $data){ + $array[$data->id]=$data->name; + } + return $array; + } } diff --git a/app/View/Components/Item/Select.php b/app/View/Components/Item/Select.php new file mode 100644 index 0000000..cd902a5 --- /dev/null +++ b/app/View/Components/Item/Select.php @@ -0,0 +1,28 @@ +id(); $table->string('name')->unique(); $table->string('svg')->unique()->nullable(); - $table->unsignedBigInteger('menu_levels_id'); + $table->unsignedBigInteger('parent_id')->nullable(); $table->timestamps(); //FOREIGN KEYS - $table->foreign('menu_levels_id','menus_fk0')->on('menu_levels')->references('id')->onUpdate('cascade')->onDelete('cascade'); + $table->foreign('parent_id','menus_fk0')->on('menus')->references('id')->onUpdate('cascade')->onDelete('cascade'); }); } @@ -32,7 +32,7 @@ public function up() */ public function down() { - Schema::table('menu_items', function (Blueprint $table) { + Schema::table('menus', function (Blueprint $table) { $table->dropForeign('menus_fk0'); }); Schema::dropIfExists('menus'); diff --git a/resources/views/components/item/elements/select.blade.php b/resources/views/components/item/elements/select.blade.php new file mode 100644 index 0000000..f6e83b2 --- /dev/null +++ b/resources/views/components/item/elements/select.blade.php @@ -0,0 +1,14 @@ +@props([ +'wireName', +'size'=>'small', +'label', +'name', +'placeholder', +'data'=>[] +]) + +
merge(['class']) }}> + + + +
diff --git a/resources/views/components/item/select.blade.php b/resources/views/components/item/select.blade.php new file mode 100644 index 0000000..7d1b652 --- /dev/null +++ b/resources/views/components/item/select.blade.php @@ -0,0 +1,40 @@ +@props([ +'name'=>'', +'placeholder'=>'', +'data'=>[], +'size'=>'small', +'sizeSmall'=>'disabled py-2 px-3 pr-9 text-sm block w-full border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-oblue-300 dark:border-gray-700 dark:text-gray-400 invalid:text-red-500', +'sizeMedium'=>'py-3 px-4 pr-9 block w-full border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-oblue-300 dark:border-gray-700 dark:text-gray-400 sm:p-4', +'sizeLarge'=>'py-3 px-4 pr-9 block w-full border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-oblue-300 dark:border-gray-700 dark:text-gray-400 sm:p-5', + +]) + + +
+ +
diff --git a/resources/views/components/layout/content.blade.php b/resources/views/components/layout/content.blade.php index 5796e9d..158f8e3 100644 --- a/resources/views/components/layout/content.blade.php +++ b/resources/views/components/layout/content.blade.php @@ -1,3 +1,3 @@ -
+
{{$slot}}
diff --git a/resources/views/components/layout/main.blade.php b/resources/views/components/layout/main.blade.php index e642a1c..679c571 100644 --- a/resources/views/components/layout/main.blade.php +++ b/resources/views/components/layout/main.blade.php @@ -1,5 +1,5 @@ @props(['pageHeader']) -
+
@livewire('layout.navigation') @livewire('layout.toggle') @livewire('layout.sidebar') diff --git a/resources/views/components/svg/security.blade.php b/resources/views/components/svg/security.blade.php new file mode 100644 index 0000000..ede5ef8 --- /dev/null +++ b/resources/views/components/svg/security.blade.php @@ -0,0 +1,3 @@ +merge(['class' => 'flex-none w-3.5 h-3.5']) }} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" > + + diff --git a/resources/views/livewire/admin/dashboard.blade.php b/resources/views/livewire/admin/dashboard.blade.php new file mode 100644 index 0000000..382abdc --- /dev/null +++ b/resources/views/livewire/admin/dashboard.blade.php @@ -0,0 +1,14 @@ +
+ @livewire('layout.navigation') + @livewire('layout.toggle') + @livewire('layout.sidebar') + @livewire('layout.header',['header'=>$pageHeader]) + + + +
+ Some quick example text to build on the card title and make up the bulk of the card's content. +
+
+ +
diff --git a/resources/views/livewire/admin/menu/level.blade.php b/resources/views/livewire/admin/menu/level.blade.php index 4ca51e3..328d2e8 100644 --- a/resources/views/livewire/admin/menu/level.blade.php +++ b/resources/views/livewire/admin/menu/level.blade.php @@ -28,7 +28,7 @@
- +
diff --git a/resources/views/livewire/admin/menu/menu-parent.blade.php b/resources/views/livewire/admin/menu/menu-parent.blade.php index d302796..955ae03 100644 --- a/resources/views/livewire/admin/menu/menu-parent.blade.php +++ b/resources/views/livewire/admin/menu/menu-parent.blade.php @@ -5,7 +5,8 @@ - {{__('Create')}} + + {{__('Create')}} @@ -14,21 +15,57 @@
+
+ + + {{-- --}} + @endif - @if($formType === 'delete' ) -
-

Are you sure you want to delete {{$menuRecord->name}} ?

-
- @endif + @if($formType === 'delete' ) +
+

Are you sure you want to delete {{$menuRecord->name}} ?

+
+ @endif
-
- +
+ +
+ @foreach($menus as $menu) +
+
+
+ +

+ {{$menu->name}} +

+
+ +
+
+
+
+ +
+ +
+
+
+ @endforeach +
+ + {{-- --}}
diff --git a/tailwind.config.js b/tailwind.config.js index cd6e69d..4ff0175 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -18,6 +18,7 @@ module.exports = { variants: { scrollbar: ['dark'] }, + theme: { colors: { @@ -103,5 +104,6 @@ module.exports = { require('@tailwindcss/typography'), require('prettier-plugin-tailwindcss'), require('preline/plugin'), + ], };