feat: implement hierarchical category selection with a tree view in product and category forms.
This commit is contained in:
@@ -27,7 +27,10 @@ class ProductCategoryController extends Controller
|
||||
|
||||
public function create()
|
||||
{
|
||||
$categories = \App\Models\ProductCategories::all();
|
||||
$categories = \App\Models\ProductCategories::with('children')
|
||||
->whereNull('parent_id')
|
||||
->orderBy('sort_order')
|
||||
->get();
|
||||
return view('administrator.pages.product.categories.create', compact('categories'));
|
||||
}
|
||||
|
||||
@@ -43,7 +46,11 @@ class ProductCategoryController extends Controller
|
||||
if (!$category) {
|
||||
return redirect()->route('products.group.index')->with('error', 'Category not found');
|
||||
}
|
||||
$categories = \App\Models\ProductCategories::where('id', '!=', $id)->get();
|
||||
$categories = \App\Models\ProductCategories::with('children')
|
||||
->whereNull('parent_id')
|
||||
->where('id', '!=', $id)
|
||||
->orderBy('sort_order')
|
||||
->get();
|
||||
return view('administrator.pages.product.categories.edit', compact('category', 'categories'));
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
['label' => 'Product'],
|
||||
['label' => 'Product / Services', 'url' => route('products.index')],
|
||||
['label' => 'Product Categories', 'url' => route('products.group.index')],
|
||||
['label' => 'Add Product Group', 'active' => true],
|
||||
['label' => 'Create Category', 'active' => true],
|
||||
];
|
||||
@endphp
|
||||
<x-admin-breadcrumb :items="$breadcrumbItems" />
|
||||
@@ -39,51 +39,53 @@
|
||||
@csrf
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card card-primary card-outline rounded-4 shadow-none">
|
||||
<div class="card card-primary card-outline rounded-4 mb-3 shadow-none">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title m-0">Basic Information</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group mb-3">
|
||||
<label for="name">Group Name <span class="text-danger">*</span></label>
|
||||
<input type="text" id="name" name="name" value="{{ old('name') }}" class="form-control" required
|
||||
<label for="name">Category Name <span class="text-danger">*</span></label>
|
||||
<input type="text" id="name" name="name" value="{{ old('name') }}"
|
||||
class="form-control @error('name') is-invalid @enderror" required
|
||||
placeholder="Enter category name">
|
||||
@error('name')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="slug">Slug</label>
|
||||
<input type="text" id="slug" name="slug" value="{{ old('slug') }}" class="form-control"
|
||||
placeholder="auto-generated-if-empty">
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="parent_id">Parent Category</label>
|
||||
<select name="parent_id" id="parent_id" class="form-control select2">
|
||||
<option value="">-- Root --</option>
|
||||
@if(isset($categories))
|
||||
@foreach($categories as $category)
|
||||
<option value="{{ $category->id }}" {{ old('parent_id') == $category->id ? 'selected' : '' }}>
|
||||
{{ $category->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
@endif
|
||||
</select>
|
||||
</div>
|
||||
<div class="card card-outline rounded-4 shadow-none">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title m-0">Parent Category</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@include('administrator.pages.product.categories.partials.category-tree', [
|
||||
'categories' => $categories,
|
||||
'selected' => old('parent_id'),
|
||||
'name' => 'parent_id',
|
||||
])
|
||||
@error('parent_id')
|
||||
<div class="text-danger small mt-1">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card card-secondary card-outline shadow-none rounded-4">
|
||||
<div class="card card-secondary card-outline rounded-4 shadow-none">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title m-0">Classification</h5>
|
||||
<h5 class="card-title m-0">Settings</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group mb-3">
|
||||
<label for="is_active">Status</label>
|
||||
|
||||
<label for=" is_active">Status</label>
|
||||
<select name="is_active" id="is_active" class="form-control select2">
|
||||
@foreach(\App\Enums\Status::cases() as $status)
|
||||
<option value="{{ $status->value }}" {{ old('is_active', \App\Enums\Status::ACTIVE->value) == $status->value ? 'selected' : '' }}>
|
||||
@foreach (\App\Enums\Status::cases() as $status)
|
||||
<option value="{{ $status->value }}"
|
||||
{{ old('is_active', \App\Enums\Status::ACTIVE->value) == $status->value ? 'selected' : '' }}>
|
||||
{{ $status->label() }}
|
||||
</option>
|
||||
@endforeach
|
||||
@@ -92,20 +94,24 @@
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="sort_order">Sort Order</label>
|
||||
<input type="number" name="sort_order" id="sort_order" class="form-control"
|
||||
value="{{ old('sort_order', 0) }}">
|
||||
<input type="number" name="sort_order" id="sort_order"
|
||||
class="form-control @error('sort_order') is-invalid @enderror"
|
||||
value="{{ old('sort_order', 0) }}" min="0">
|
||||
@error('sort_order')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<x-fixed-action-bar>
|
||||
<x-button-crm type="button" variant="outline-info" size="sm" icon="arrow-left"
|
||||
route="products.group.index">Back</x-button-crm>
|
||||
<x-button-crm type="submit" variant="outline-primary" size="sm" icon="plus-circle">Create
|
||||
Category</x-button-crm>
|
||||
</x-fixed-action-bar>
|
||||
<x-fixed-action-bar>
|
||||
<x-button-crm type="button" variant="outline-info" size="sm" icon="arrow-left"
|
||||
route="products.group.index">Back</x-button-crm>
|
||||
<x-button-crm type="submit" variant="outline-primary" size="sm" icon="plus-circle">Create
|
||||
Category</x-button-crm>
|
||||
</x-fixed-action-bar>
|
||||
</form>
|
||||
@endsection
|
||||
|
||||
@@ -113,11 +119,7 @@
|
||||
@foreach (config('assets.datatable.js') as $datatable)
|
||||
<script src="{{ asset($datatable) }}"></script>
|
||||
@endforeach
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
if ($(".select2").length) {
|
||||
$(".select2").select2();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@endpush
|
||||
@push('custom-scripts')
|
||||
@include('administrator.pages.product.categories.partials.category-tree-scripts')
|
||||
@endpush
|
||||
|
||||
@@ -16,104 +16,111 @@
|
||||
@endphp
|
||||
<x-admin-breadcrumb :items="$breadcrumbItems" />
|
||||
@endsection
|
||||
@section('tab')
|
||||
@php
|
||||
$tabs = [
|
||||
[
|
||||
'label' => 'Product',
|
||||
'route' => 'products.index',
|
||||
'icon' => 'server',
|
||||
],
|
||||
[
|
||||
'label' => 'Product Group',
|
||||
'route' => 'products.group.index',
|
||||
'icon' => 'server',
|
||||
],
|
||||
];
|
||||
@endphp
|
||||
<x-admin-tab :items="$tabs" />
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<form action="{{ route('products.group.update', ['id' => $category->id]) }}" method="post">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card card-primary card-outline">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title m-0">Basic Information</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group mb-3">
|
||||
<label for="name">Group Name <span class="text-danger">*</span></label>
|
||||
<input type="text" id="name" name="name" value="{{ old('name', $category->name) }}"
|
||||
class="form-control" required placeholder="Enter category name">
|
||||
</div>
|
||||
@section('tab')
|
||||
@php
|
||||
$tabs = [
|
||||
[
|
||||
'label' => 'Product',
|
||||
'route' => 'products.index',
|
||||
'icon' => 'server',
|
||||
],
|
||||
[
|
||||
'label' => 'Product Group',
|
||||
'route' => 'products.group.index',
|
||||
'icon' => 'server',
|
||||
],
|
||||
];
|
||||
@endphp
|
||||
<x-admin-tab :items="$tabs" />
|
||||
@endsection
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="slug">Slug</label>
|
||||
<input type="text" id="slug" name="slug" value="{{ old('slug', $category->slug) }}"
|
||||
class="form-control" placeholder="auto-generated-if-empty">
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="parent_id">Parent Category</label>
|
||||
<select name="parent_id" id="parent_id" class="form-control select2">
|
||||
<option value="">-- Root --</option>
|
||||
@if(isset($categories))
|
||||
@foreach($categories as $cat)
|
||||
<option value="{{ $cat->id }}" {{ old('parent_id', $category->parent_id) == $cat->id ? 'selected' : '' }}>{{ $cat->name }}</option>
|
||||
@endforeach
|
||||
@endif
|
||||
</select>
|
||||
</div>
|
||||
@section('content')
|
||||
<form action="{{ route('products.group.update', ['id' => $category->id]) }}" method="post">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card card-primary card-outline rounded-4 shadow-none">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title m-0">Basic Information</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group mb-3">
|
||||
<label for="name">Category Name <span class="text-danger">*</span></label>
|
||||
<input type="text" id="name" name="name" value="{{ old('name', $category->name) }}"
|
||||
class="form-control @error('name') is-invalid @enderror" required
|
||||
placeholder="Enter category name">
|
||||
@error('name')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card card-secondary card-outline">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title m-0">Classification</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group mb-3">
|
||||
<label for="is_active">Status</label>
|
||||
<select name="is_active" id="is_active" class="form-control select2">
|
||||
@foreach(\App\Enums\Status::cases() as $status)
|
||||
<option value="{{ $status->value }}" {{ old('is_active', $category->is_active) == $status->value ? 'selected' : '' }}>
|
||||
{{ $status->label() }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="sort_order">Sort Order</label>
|
||||
<input type="number" name="sort_order" id="sort_order" class="form-control" value="{{ old('sort_order', $category->sort_order) }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card card-outline rounded-4 shadow-none">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title m-0">Parent Category</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@include('administrator.pages.product.categories.partials.category-tree', [
|
||||
'categories' => $categories,
|
||||
'selected' => old('parent_id', $category->parent_id),
|
||||
'name' => 'parent_id',
|
||||
'exclude' => $category->id,
|
||||
])
|
||||
@error('parent_id')
|
||||
<div class="text-danger small mt-1">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<x-fixed-action-bar>
|
||||
<x-button-crm type="button" variant="secondary" size="sm" icon="arrow-left" route="products.group.index">Cancel</x-button-crm>
|
||||
<x-button-crm type="submit" variant="primary" size="sm" icon="save">Update Category</x-button-crm>
|
||||
</x-fixed-action-bar>
|
||||
</form>
|
||||
@endsection
|
||||
<div class="col-md-4">
|
||||
<div class="card card-secondary card-outline shadow-none rounded-4">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title m-0">Settings</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group mb-3">
|
||||
<label for="is_active">Status</label>
|
||||
<select name="is_active" id="is_active" class="form-control select2">
|
||||
@foreach(\App\Enums\Status::cases() as $status)
|
||||
<option value="{{ $status->value }}" {{ old('is_active', $category->is_active) == $status->value ? 'selected' : '' }}>
|
||||
{{ $status->label() }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="sort_order">Sort Order</label>
|
||||
<input type="number" name="sort_order" id="sort_order"
|
||||
class="form-control @error('sort_order') is-invalid @enderror"
|
||||
value="{{ old('sort_order', $category->sort_order) }}" min="0">
|
||||
@error('sort_order')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<x-fixed-action-bar>
|
||||
<x-button-crm type="button" variant="secondary" size="sm" icon="arrow-left"
|
||||
route="products.group.index">Cancel</x-button-crm>
|
||||
<x-button-crm type="submit" variant="primary" size="sm" icon="save">Update
|
||||
Category</x-button-crm>
|
||||
</x-fixed-action-bar>
|
||||
</form>
|
||||
@endsection
|
||||
|
||||
@push('plugin-scripts')
|
||||
@foreach (config('assets.datatable.js') as $datatable)
|
||||
<script src="{{ asset($datatable) }}"></script>
|
||||
@endforeach
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
if ($(".select2").length) {
|
||||
$(".select2").select2();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@push('custom-scripts')
|
||||
@include('administrator.pages.product.categories.partials.category-tree-scripts')
|
||||
@endpush
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<option value="{{ $category->id }}" {{ $selected == $category->id ? 'selected' : '' }}>
|
||||
{{ str_repeat('— ', $depth) }}{{ $category->name }}
|
||||
</option>
|
||||
@if($category->children->isNotEmpty())
|
||||
@foreach($category->children as $child)
|
||||
@include('administrator.pages.product.categories.partials.category-option', [
|
||||
'category' => $child,
|
||||
'depth' => $depth + 1,
|
||||
'selected' => $selected,
|
||||
])
|
||||
@endforeach
|
||||
@endif
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
@if(!$exclude || $category->id != $exclude)
|
||||
<a href="#" class="list-group-item list-group-item-action category-tree-item py-2 px-3 {{ $selected == $category->id ? 'active' : '' }}"
|
||||
data-id="{{ $category->id }}" data-name="{{ $category->name }}">
|
||||
<div class="d-flex align-items-center" style="padding-left: {{ $depth * 20 }}px;">
|
||||
@if($category->children->isNotEmpty())
|
||||
<span class="category-tree-toggle me-1" data-target="{{ $treeId }}-children-{{ $category->id }}">
|
||||
<i data-lucide="chevron-right" width="14" height="14" class="tree-arrow"></i>
|
||||
</span>
|
||||
@else
|
||||
<span class="me-1" style="width: 14px; display: inline-block;"></span>
|
||||
@endif
|
||||
<i data-lucide="folder" width="14" height="14" class="me-2 text-warning"></i>
|
||||
<span>{{ $category->name }}</span>
|
||||
@if(!$category->is_active)
|
||||
<span class="badge bg-secondary ms-2" style="font-size: 0.65rem;">Inactive</span>
|
||||
@endif
|
||||
</div>
|
||||
</a>
|
||||
@if($category->children->isNotEmpty())
|
||||
<div class="category-tree-children" id="{{ $treeId }}-children-{{ $category->id }}" style="display: none;">
|
||||
@foreach($category->children as $child)
|
||||
@include('administrator.pages.product.categories.partials.category-tree-item', [
|
||||
'category' => $child,
|
||||
'depth' => $depth + 1,
|
||||
'selected' => $selected,
|
||||
'exclude' => $exclude,
|
||||
'treeId' => $treeId,
|
||||
])
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
document.querySelectorAll('.category-tree-picker').forEach(function (picker) {
|
||||
var treeId = picker.dataset.treeId;
|
||||
var hiddenInput = document.getElementById(treeId + '-input');
|
||||
var selectedDisplay = picker.querySelector('.tree-selected-display');
|
||||
var selectedLabel = picker.querySelector('.tree-selected-label');
|
||||
var clearBtn = picker.querySelector('.tree-clear-btn');
|
||||
var searchInput = picker.querySelector('.tree-search-input');
|
||||
|
||||
function expandParents(el) {
|
||||
var parent = el.closest('.category-tree-children');
|
||||
while (parent) {
|
||||
parent.style.display = '';
|
||||
var prev = parent.previousElementSibling;
|
||||
if (prev) {
|
||||
var toggleIcon = prev.querySelector('.tree-arrow');
|
||||
if (toggleIcon) {
|
||||
toggleIcon.style.transform = 'rotate(90deg)';
|
||||
}
|
||||
}
|
||||
parent = parent.parentElement
|
||||
? parent.parentElement.closest('.category-tree-children')
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
var activeItem = picker.querySelector('.category-tree-item.active');
|
||||
if (activeItem && activeItem.dataset.id) {
|
||||
expandParents(activeItem);
|
||||
selectedLabel.textContent = activeItem.dataset.name;
|
||||
selectedDisplay.style.display = '';
|
||||
}
|
||||
|
||||
picker.querySelectorAll('.category-tree-toggle').forEach(function (toggle) {
|
||||
toggle.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var target = document.getElementById(this.dataset.target);
|
||||
var arrow = this.querySelector('.tree-arrow');
|
||||
if (target) {
|
||||
if (target.style.display === 'none') {
|
||||
target.style.display = '';
|
||||
arrow.style.transform = 'rotate(90deg)';
|
||||
} else {
|
||||
target.style.display = 'none';
|
||||
arrow.style.transform = 'rotate(0deg)';
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
picker.querySelectorAll('.category-tree-item').forEach(function (item) {
|
||||
item.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
picker.querySelectorAll('.category-tree-item').forEach(function (i) {
|
||||
i.classList.remove('active');
|
||||
});
|
||||
this.classList.add('active');
|
||||
hiddenInput.value = this.dataset.id;
|
||||
|
||||
if (this.dataset.id) {
|
||||
selectedLabel.textContent = this.dataset.name;
|
||||
selectedDisplay.style.display = '';
|
||||
} else {
|
||||
selectedDisplay.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
clearBtn.addEventListener('click', function () {
|
||||
hiddenInput.value = '';
|
||||
selectedDisplay.style.display = 'none';
|
||||
picker.querySelectorAll('.category-tree-item').forEach(function (i) {
|
||||
i.classList.remove('active');
|
||||
});
|
||||
picker.querySelector('.category-tree-item[data-id=""]').classList.add('active');
|
||||
});
|
||||
|
||||
searchInput.addEventListener('input', function () {
|
||||
var query = this.value.toLowerCase().trim();
|
||||
picker.querySelectorAll('.category-tree-children').forEach(function (el) {
|
||||
el.style.display = query ? '' : 'none';
|
||||
});
|
||||
picker.querySelectorAll('.tree-arrow').forEach(function (arrow) {
|
||||
arrow.style.transform = query ? 'rotate(90deg)' : 'rotate(0deg)';
|
||||
});
|
||||
|
||||
picker.querySelectorAll('.category-tree-item').forEach(function (item) {
|
||||
if (!item.dataset.id && item.dataset.id !== '0') {
|
||||
item.style.display = query ? 'none' : '';
|
||||
return;
|
||||
}
|
||||
var name = (item.dataset.name || '').toLowerCase();
|
||||
item.style.display = (!query || name.includes(query)) ? '' : 'none';
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (typeof lucide !== 'undefined') {
|
||||
lucide.createIcons();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
.category-tree-container .list-group-item {
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
font-size: 0.875rem;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
.category-tree-container .list-group-item:first-child {
|
||||
border-top: 0;
|
||||
}
|
||||
.category-tree-container .list-group-item:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.category-tree-container .list-group-item.active {
|
||||
background-color: #e8f0fe;
|
||||
border-color: transparent;
|
||||
color: #1a73e8;
|
||||
}
|
||||
.category-tree-toggle {
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
.tree-arrow {
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
</style>
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
@props(['categories', 'selected' => null, 'name' => 'parent_id', 'exclude' => null])
|
||||
|
||||
@php $treeId = str_replace(['[', ']', '.'], '-', $name); @endphp
|
||||
|
||||
<input type="hidden" name="{{ $name }}" id="{{ $treeId }}-input" value="{{ $selected }}">
|
||||
|
||||
<div class="category-tree-picker" data-tree-id="{{ $treeId }}">
|
||||
<div class="category-tree-search mb-2">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text bg-white border-end-0">
|
||||
<i data-lucide="search" width="14" height="14"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control border-start-0 shadow-none tree-search-input"
|
||||
placeholder="Search categories...">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="category-tree-selected-display mb-2 tree-selected-display" style="display: none;">
|
||||
<span class="badge bg-primary d-inline-flex align-items-center gap-1 px-2 py-1">
|
||||
<span class="tree-selected-label"></span>
|
||||
<button type="button" class="btn-close btn-close-white ms-1 tree-clear-btn" style="font-size: 0.5rem;"></button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="category-tree-container border rounded" style="max-height: 300px; overflow-y: auto;">
|
||||
<div class="list-group list-group-flush">
|
||||
<a href="#" class="list-group-item list-group-item-action category-tree-item py-2 px-3 {{ !$selected ? 'active' : '' }}"
|
||||
data-id="" data-name="Root (No Parent)">
|
||||
<div class="d-flex align-items-center">
|
||||
<i data-lucide="home" width="14" height="14" class="me-2 text-muted"></i>
|
||||
<span class="fw-medium">Root (No Parent)</span>
|
||||
</div>
|
||||
</a>
|
||||
@foreach($categories as $category)
|
||||
@include('administrator.pages.product.categories.partials.category-tree-item', [
|
||||
'category' => $category,
|
||||
'depth' => 0,
|
||||
'selected' => $selected,
|
||||
'exclude' => $exclude,
|
||||
'treeId' => $treeId,
|
||||
])
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -204,18 +204,20 @@
|
||||
<div class="form-group mb-3">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<label for="product_categories_id">Group</label>
|
||||
<a href={{ route('products.group.index') }}
|
||||
<a href="{{ route('products.group.index') }}"
|
||||
class="text-primary text-decoration-underline">
|
||||
<i data-lucide="plus" class="w-12px h-12px"></i>
|
||||
Thêm Group
|
||||
</a>
|
||||
</div>
|
||||
<select class="form-control select2" name="product_categories_id" id="product_categories_id">
|
||||
<option value="">-- Select Group --</option>
|
||||
@foreach ($group as $item)
|
||||
@include('administrator.pages.product.partials.category_options', ['item' => $item, 'level' => 0, 'selected' => old('product_categories_id')])
|
||||
@endforeach
|
||||
</select>
|
||||
@include('administrator.pages.product.categories.partials.category-tree', [
|
||||
'categories' => $group,
|
||||
'selected' => old('product_categories_id'),
|
||||
'name' => 'product_categories_id',
|
||||
])
|
||||
@error('product_categories_id')
|
||||
<div class="text-danger small mt-1">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
{{-- Product Type --}}
|
||||
<div class="form-group mb-3">
|
||||
@@ -406,3 +408,7 @@
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@push('custom-scripts')
|
||||
@include('administrator.pages.product.categories.partials.category-tree-scripts')
|
||||
@endpush
|
||||
|
||||
@@ -209,12 +209,14 @@ $breadcrumbItems = [
|
||||
Thêm Group
|
||||
</a>
|
||||
</div>
|
||||
<select class="form-control select2" name="product_categories_id" id="product_categories_id">
|
||||
<option value="">-- Select Group --</option>
|
||||
@foreach ($group as $item)
|
||||
@include('administrator.pages.product.partials.category_options', ['item' => $item, 'level' => 0, 'selected' => old('product_categories_id', $product->product_categories_id)])
|
||||
@endforeach
|
||||
</select>
|
||||
@include('administrator.pages.product.categories.partials.category-tree', [
|
||||
'categories' => $group,
|
||||
'selected' => old('product_categories_id', $product->product_categories_id),
|
||||
'name' => 'product_categories_id',
|
||||
])
|
||||
@error('product_categories_id')
|
||||
<div class="text-danger small mt-1">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
{{-- Operating System (for VPS) --}}
|
||||
@@ -424,3 +426,7 @@ $breadcrumbItems = [
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@push('custom-scripts')
|
||||
@include('administrator.pages.product.categories.partials.category-tree-scripts')
|
||||
@endpush
|
||||
Reference in New Issue
Block a user