added xController store ad update

form template
edited menu and order migration
pull/44/head
A1Gard 6 months ago
parent 56110bb254
commit 22c6f45111

@ -92,10 +92,13 @@ function getEmojiLanguagebyCode($lang) : string
* @return bool * @return bool
*/ */
function hasRoute($name,$endRoute = 'index') : bool function hasRoute($name) : bool
{ {
// create route // create route
$cRuote = str_replace($endRoute, $name, request()->route()->getName()); $routes = explode('.',request()->route()->getName());
$routes[count($routes) - 1 ] = $name;
$cRuote = implode('.',$routes);
if (\Illuminate\Support\Facades\Route::has($cRuote)) { if (\Illuminate\Support\Facades\Route::has($cRuote)) {
return true; return true;
} else { } else {
@ -107,13 +110,15 @@ function hasRoute($name,$endRoute = 'index') : bool
* get named route url * get named route url
* @param $name string * @param $name string
* @param $args array * @param $args array
* @param $endRoute string 'index' or alt list
* @return string|null * @return string|null
*/ */
function getRoute($name, $args = [],$endRoute = 'index') : string | null function getRoute($name, $args = []) : string | null
{ {
// create route // create route
$cRuote = str_replace($endRoute, $name, request()->route()->getName()); $routes = explode('.',request()->route()->getName());
$routes[count($routes) - 1 ] = $name;
$cRuote = implode('.',$routes);
if (\Illuminate\Support\Facades\Route::has($cRuote)) { if (\Illuminate\Support\Facades\Route::has($cRuote)) {
return \route($cRuote, $args); return \route($cRuote, $args);
} else { } else {
@ -203,3 +208,15 @@ function logAdmin($method, $cls, $id) :void
'loggable_id' => $id, 'loggable_id' => $id,
]); ]);
} }
function queryBuilder($except = null){
$queries = request()->toArray();
if ($except != null){
unset($queries[$except]);
unset($queries['sortType']);
}
return http_build_query($queries);
}

@ -5,6 +5,8 @@ namespace App\Http\Controllers\Admin;
use App\CreateOrUpdate; use App\CreateOrUpdate;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Controllers\XController; use App\Http\Controllers\XController;
use App\Http\Requests\UserSaveRequest;
use App\Models\Access;
use App\Models\Item; use App\Models\Item;
use App\Models\User; use App\Models\User;
use App\SafeController; use App\SafeController;
@ -19,6 +21,9 @@ class UserController extends XController
protected $searchable = ['name','mobile','email']; protected $searchable = ['name','mobile','email'];
protected const request = UserSaveRequest::class;
protected $buttons = [ protected $buttons = [
'edit' => 'edit' =>
['title' => "Edit", 'class' => 'btn-outline-primary', 'icon' => 'ri-edit-2-line'], ['title' => "Edit", 'class' => 'btn-outline-primary', 'icon' => 'ri-edit-2-line'],
@ -30,12 +35,58 @@ class UserController extends XController
['title' => "Remove", 'class' => 'btn-outline-danger delete-confirm', 'icon' => 'ri-close-line'], ['title' => "Remove", 'class' => 'btn-outline-danger delete-confirm', 'icon' => 'ri-close-line'],
]; ];
public function createOrUpdate( $item, $request) public function save($user, $request)
{ {
$user->name = $request->input('name');
$user->email = $request->input('email');
if (trim($request->input('password')) != '') {
$user->password = bcrypt($request->input('password'));
}
$user->mobile = $request->input('mobile');
$user->role = $request->input('role');
$user->syncRoles($request->input('role'));
$user->save();
if ($request->has('acl')) {
$user->accesses()->delete();
foreach ($request->input('acl', []) as $route) {
$a = new Access();
$a->route = $route;
$a->user_id = $user->id;
$a->save();
$routes = explode('.', $route);
if ($routes[2] == 'store' || $routes[2] == 'update') {
$routes[2] = $routes[2] == 'store' ? 'create' : 'edit';
$a = new Access();
$a->route = implode('.', $routes);
$a->user_id = $user->id;
$a->save();
}
}
}
return $user;
} }
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
return view($this->formView);
}
/**
* Show the form for editing the specified resource.
*/
public function edit(User $item)
{
//
return view($this->formView,compact('item'));
}
public function bulk(Request $request){ public function bulk(Request $request){
// dd($request->all()); // dd($request->all());
@ -45,12 +96,12 @@ class UserController extends XController
switch ($action) { switch ($action) {
case 'delete': case 'delete':
$msg = __(':COUNT items deleted successfully',['COUNT' => count($ids)]); $msg = __(':COUNT items deleted successfully',['COUNT' => count($ids)]);
$this->model::destroy($ids); self::_MODEL_::destroy($ids);
break; break;
case 'restore': case 'restore':
$msg = __(':COUNT items restored successfully',['COUNT' => count($ids)]); $msg = __(':COUNT items restored successfully',['COUNT' => count($ids)]);
foreach ($ids as $id) { foreach ($ids as $id) {
$this->model::withTrashed()->find($id)->restore(); self::_MODEL_::withTrashed()->find($id)->restore();
} }
break; break;
case 'role': case 'role':
@ -74,6 +125,10 @@ class UserController extends XController
return parent::delete($item); return parent::delete($item);
} }
public function update(Request $request,User $item ){
return $this->bringUp($request, $item);
}
public function restore($item) public function restore($item)
{ {

@ -2,15 +2,15 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Http\Requests\UserSaveRequest;
use App\Models\User; use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request; use Illuminate\Http\Request;
abstract class XController extends Controller abstract class XController extends Controller
{ {
protected $model = User::class; protected const _MODEL_ = User::class;
protected $name = "User"; protected const SAVE_REQUEST = UserSaveRequest::class;
protected $cols = []; protected $cols = [];
protected $extra_cols = ['id']; protected $extra_cols = ['id'];
protected $listView = 'admin.users.user-list'; protected $listView = 'admin.users.user-list';
@ -28,7 +28,7 @@ abstract class XController extends Controller
]; ];
public function createOrUpdate($item, $request) public function save($user, $request)
{ {
} }
@ -37,7 +37,7 @@ abstract class XController extends Controller
{ {
if (hasRoute('trashed')){ if (hasRoute('trashed')) {
$this->extra_cols[] = 'deleted_at'; $this->extra_cols[] = 'deleted_at';
} }
$items = $query->paginate(config('app.panel.page_count'), $items = $query->paginate(config('app.panel.page_count'),
@ -52,9 +52,9 @@ abstract class XController extends Controller
if (!\request()->has('sort') || !in_array(\request('sort'), $this->cols)) { if (!\request()->has('sort') || !in_array(\request('sort'), $this->cols)) {
$query = $this->model::orderByDesc('id'); $query = self::_MODEL_::orderByDesc('id');
} else { } else {
$query = $this->model::orderBy(\request('sort'), \request('sortType', 'asc')); $query = self::_MODEL_::orderBy(\request('sort'), \request('sortType', 'asc'));
} }
foreach (\request()->input('filter', []) as $col => $filter) { foreach (\request()->input('filter', []) as $col => $filter) {
@ -95,14 +95,7 @@ abstract class XController extends Controller
} }
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/** /**
* Store a newly created resource in storage. * Store a newly created resource in storage.
@ -110,14 +103,18 @@ abstract class XController extends Controller
public function store(Request $request) public function store(Request $request)
{ {
// //
$item = new $this->model();
$item = $this->create($item,$request); $validatedRequest = app()->make(self::SAVE_REQUEST)->merge($request->all());
logAdmin(__METHOD__, $this->model , $item->id);
$item = new (self::_MODEL_)();
if ($request->ajax()){ $item = $this->save($item, $request);
return ['OK' => true,]; logAdmin(__METHOD__, self::_MODEL_, $item->id);
}else{
return redirect()->route('admin.'.$this->model.'.index')->with(['message' => __('As you wished created successfully')]); if ($request->ajax()) {
return ['OK' => true, __('As you wished created successfully')];
} else {
return redirect(getRoute('edit', $item->{$item->getRouteKeyName()}))
->with(['message' => __('As you wished created successfully')]);
} }
} }
@ -129,20 +126,24 @@ abstract class XController extends Controller
// //
} }
/**
* Show the form for editing the specified resource.
*/
public function edit($user)
{
//
}
/** /**
* Update the specified resource in storage. * Update the specified resource in storage.
*/ */
public function update(Request $request, $user) public function bringUp(Request $request, $item)
{ {
// //
$validatedRequest = app()->make(self::SAVE_REQUEST)->merge($request->all());
$item = $this->save($item, $request);
logAdmin(__METHOD__, self::_MODEL_, $item->id);
if ($request->ajax()) {
return ['OK' => true, __('As you wished updated successfully')];
} else {
return redirect(getRoute('edit', $item->{$item->getRouteKeyName()}))
->with(['message' => __('As you wished updated successfully')]);
}
} }
/** /**
@ -151,7 +152,7 @@ abstract class XController extends Controller
public function delete($item) public function delete($item)
{ {
// //
logAdmin(__METHOD__, $this->model , $item->id); logAdmin(__METHOD__, self::_MODEL_, $item->id);
$item->delete(); $item->delete();
return redirect()->back()->with(['message' => __('As you wished removed successfully')]); return redirect()->back()->with(['message' => __('As you wished removed successfully')]);
} }
@ -162,7 +163,7 @@ abstract class XController extends Controller
public function restoreing($item) public function restoreing($item)
{ {
// //
logAdmin(__METHOD__, $this->model , $item->id); logAdmin(__METHOD__, self::_MODEL_, $item->id);
$item->restore(); $item->restore();
return redirect()->back()->with(['message' => __('As you wished restored successfully')]); return redirect()->back()->with(['message' => __('As you wished restored successfully')]);
} }
@ -177,9 +178,11 @@ abstract class XController extends Controller
return $this->showList($query); return $this->showList($query);
} }
protected function do_bulk($msg,$action,$ids) protected function do_bulk($msg, $action, $ids)
{ {
logAdminBatch(__METHOD__ . '.' . $action, $this->model, $ids); logAdminBatch(__METHOD__ . '.' . $action, self::_MODEL_, $ids);
return redirect()->back()->with(['message' => $msg]); return redirect()->back()->with(['message' => $msg]);
} }
} }

@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UserSaveRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return auth()->check() and auth()->user()->hasRole('developer|admin');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'mobile' => ['required', 'string', 'min:10'],
'role' => ['required', 'string'],
'email' => ['required', 'string', 'email', 'max:255', "unique:users,email,".$this->id],
'password' => ['string', 'min:8', 'confirmed','nullable'],
];
}
}

@ -4,8 +4,26 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Spatie\Translatable\HasTranslations;
class Item extends Model class Item extends Model
{ {
use HasFactory; use HasFactory,HasTranslations;
public $translatable = ['title'];
public function menu()
{
return $this->belongsTo(Menu::class, 'menu_id', 'id');
}
public function parent()
{
return $this->belongsTo(MenuItem::class, 'parent');
}
public function children()
{
return $this->hasMany(MenuItem::class, 'parent');
}
} }

@ -12,6 +12,6 @@ class Menu extends Model
public function menuItems() public function menuItems()
{ {
return $this->hasMany(MenuItem::class, 'menu_id', 'id'); return $this->hasMany(Item::class);
} }
} }

@ -1,29 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Spatie\Translatable\HasTranslations;
class MenuItem extends Model
{
use HasFactory,HasTranslations;
public $translatable = ['title'];
public function menu()
{
return $this->belongsTo(Menu::class, 'menu_id', 'id');
}
public function parent()
{
return $this->belongsTo(MenuItem::class, 'parent');
}
public function children()
{
return $this->hasMany(MenuItem::class, 'parent');
}
}

@ -0,0 +1,11 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
use HasFactory;
}

@ -5,9 +5,9 @@ namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Database\Eloquent\Factories\Factory;
/** /**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\MenuItem> * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Order>
*/ */
class MenuItemFactory extends Factory class OrderFactory extends Factory
{ {
/** /**
* Define the model's default state. * Define the model's default state.

@ -18,6 +18,7 @@ return new class extends Migration
$table->string('tag')->nullable(); $table->string('tag')->nullable();
$table->unsignedBigInteger('user_id'); $table->unsignedBigInteger('user_id');
$table->boolean('active')->default(true); $table->boolean('active')->default(true);
$table->json('data');
$table->timestamps(); $table->timestamps();
$table->foreign('user_id') $table->foreign('user_id')
->references('id')->on('users'); ->references('id')->on('users');

@ -11,7 +11,7 @@ return new class extends Migration
*/ */
public function up(): void public function up(): void
{ {
Schema::create('menu_items', function (Blueprint $table) { Schema::create('items', function (Blueprint $table) {
$table->id(); $table->id();
$table->text('title'); $table->text('title');
// $table->morphs('menuable')->nullable();; // $table->morphs('menuable')->nullable();;
@ -37,6 +37,6 @@ return new class extends Migration
*/ */
public function down(): void public function down(): void
{ {
Schema::dropIfExists('menu_items'); Schema::dropIfExists('items');
} }
}; };

@ -11,7 +11,7 @@ return new class extends Migration
*/ */
public function up(): void public function up(): void
{ {
Schema::create('items', function (Blueprint $table) { Schema::create('orders', function (Blueprint $table) {
$table->id(); $table->id();
$table->unsignedBigInteger('invoice_id'); $table->unsignedBigInteger('invoice_id');
$table->unsignedBigInteger('product_id'); $table->unsignedBigInteger('product_id');
@ -34,6 +34,6 @@ return new class extends Migration
*/ */
public function down(): void public function down(): void
{ {
Schema::dropIfExists('items'); Schema::dropIfExists('orders');
} }
}; };

@ -5,7 +5,7 @@ namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
class MenuItemSeeder extends Seeder class OrderSeeder extends Seeder
{ {
/** /**
* Run the database seeds. * Run the database seeds.

@ -1,17 +1,18 @@
<template> <template>
<div id="searchable-select"> <div id="searchable-select" ref="main">
<div id="ss-modal" @click.self="hideModal" v-if="modalShow"> <div id="ss-modal" @click.self="hideModal" v-if="modalShow">
<div id="ss-selector"> <div id="ss-selector">
<div class="p-2"> <div class="p-2">
<input type="text" class="form-control" v-model="q" :placeholder="xtitle"> <input type="text" class="form-control search" v-model="q" :placeholder="xtitle">
</div> </div>
<div class="p-2"> <div class="p-2">
<ul id="vue-search-list" class="list-group list-group-flush"> <ul id="vue-search-list" class="list-group list-group-flush">
<template v-for="item in items"> <template v-for="(item,i) in items">
<li <li
tabindex="-1"
v-if="(q != '' && item[titleField].toLocaleLowerCase().indexOf(q.toLocaleLowerCase()) != -1) || (q == '')" v-if="(q != '' && item[titleField].toLocaleLowerCase().indexOf(q.toLocaleLowerCase()) != -1) || (q == '')"
@click="selecting(item[valueField])" @click="selecting(item[valueField])"
:class="`list-group-item ${val.indexOf(item[valueField]) !== -1?'selected':''}`"> :class="`list-group-item ${val.indexOf(item[valueField]) !== -1?'selected':''} ${focsed == i?'focused':''}`">
{{ item[titleField] }} {{ item[titleField] }}
</li> </li>
</template> </template>
@ -20,14 +21,14 @@
</div> </div>
</div> </div>
<div class="input-group mb-3"> <div class="input-group mb-3">
<div class="input-group-prepend" id="vue-search-btn" @click="showModal"> <div class="input-group-prepend" id="vue-search-btn">
<span class="input-group-text" id="basic-addon1"> <button class="input-group-text" id="basic-addon1" type="button" @click="showModal">
<i class="ri-check-line"></i> <i class="ri-check-line"></i>
</span> </button>
</div> </div>
<div class="form-control" id="vue-lst" @click.self="showModal"> <div class="form-control" id="vue-lst" @click.self="showModal">
<template v-for="item in items"> <template v-for="item in items">
<span class="tag-select" v-if=" val.indexOf(item[valueField]) !== -1" > <span class="tag-select" v-if=" val.indexOf(item[valueField]) !== -1">
{{ item[titleField] }} {{ item[titleField] }}
<i class="ri-close-line" @click="rem(item[valueField])"></i> <i class="ri-close-line" @click="rem(item[valueField])"></i>
</span> </span>
@ -48,6 +49,7 @@ export default {
modalShow: false, // modal handle modalShow: false, // modal handle
q: '', // search query q: '', // search query
val: [], val: [],
focsed: -1,
} }
}, },
emits: ['update:modelValue'], emits: ['update:modelValue'],
@ -103,7 +105,7 @@ export default {
mounted() { mounted() {
if (this.modelValue != 'nop') { if (this.modelValue != 'nop') {
this.val = this.modelValue; this.val = this.modelValue;
}else{ } else {
this.val = this.xvalue; this.val = this.xvalue;
} }
}, },
@ -116,26 +118,67 @@ export default {
}, },
}, },
methods: { methods: {
rem(i){ rem(i) {
this.val.splice(this.val.indexOf(i),1); this.val.splice(this.val.indexOf(i), 1);
this.onSelect(this.val,i); this.onSelect(this.val, i);
}, },
selecting(i) { selecting(i) {
if (this.val.indexOf(i) == -1){ if (this.val.indexOf(i) == -1) {
this.val.push(i); this.val.push(i);
}else{ } else {
this.val.splice(this.val.indexOf(i),1); this.val.splice(this.val.indexOf(i), 1);
} }
this.onSelect(this.val,i); this.onSelect(this.val, i);
}, },
select() { select() {
this.onSelect(this.val); this.onSelect(this.val);
}, },
hideModal: function () { hideModal: function () {
this.modalShow = false; this.modalShow = false;
document.removeEventListener('keydown', this.keyHandle);
}, },
showModal() { showModal() {
this.modalShow = true; this.modalShow = true;
setTimeout(() => {
if (this.$refs.main.querySelector('.search') != null) {
this.$refs.main.querySelector('.search').focus();
}
}, 100);
// this.$refs.main.querySelector('.search').focus();
document.addEventListener('keydown', this.keyHandle);
},
keyHandle(e) {
if (e.key == 'Escape') {
this.hideModal();
}
try {
if (this.$refs.main.querySelector('.search') == document.activeElement) {
if (e.code == 'Tab') {
e.preventDefault();
this.$refs.main.querySelector('.search').blur();
this.focsed = 0;
}
return;
}
} catch {
}
e.preventDefault();
if (e.key == 'ArrowDown') {
this.focsed++;
if (this.focsed > this.items.length - 1) {
this.focsed = this.items.length - 1;
}
} else if (e.key == 'ArrowUp') {
this.focsed--;
if (this.focsed < -1) {
this.focsed = -1;
}
} else if (e.key == ' ' || e.key == 'Enter') {
this.selecting(this.items[this.focsed][this.valueField]);
}
return false;
// console.log(e.key);
} }
}, },
watch: { watch: {
@ -183,7 +226,7 @@ export default {
max-width: 90%; max-width: 90%;
margin: 20vh auto; margin: 20vh auto;
background: #282D47; background: #282D47;
box-shadow: 0 0 4px gray; box-shadow: 0 0 4px gray;
padding: 5px; padding: 5px;
} }
@ -192,7 +235,7 @@ export default {
overflow-x: auto; overflow-x: auto;
} }
#vue-search-list .list-group-item:hover { #vue-search-list .list-group-item:hover, #vue-search-list .list-group-item.focused {
background: #6610F2; background: #6610F2;
} }
@ -201,14 +244,19 @@ export default {
color: white;; color: white;;
} }
#vue-search-list .list-group-item.selected:hover, #vue-search-list .list-group-item.selected.focused {
background: #6610F2 !important;
}
#vue-lst { #vue-lst {
user-select: none; user-select: none;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
} }
.tag-select{
.tag-select {
display: inline-block; display: inline-block;
padding: 0 4px 0 20px ; padding: 0 4px 0 20px;
margin-right: 5px; margin-right: 5px;
background: #282c34dd; background: #282c34dd;
color: white; color: white;
@ -216,14 +264,14 @@ export default {
border-radius: 3px; border-radius: 3px;
} }
.tag-select i{ .tag-select i {
font-size: 20px; font-size: 20px;
position: absolute; position: absolute;
left: 0; left: 0;
top: -5px; top: -5px;
} }
.tag-select i:hover{ .tag-select i:hover {
color: red; color: red;
} }
</style> </style>

@ -1,16 +1,21 @@
function clearSelection() function clearSelection() {
{ if (window.getSelection) {
if (window.getSelection) {window.getSelection().removeAllRanges();} window.getSelection().removeAllRanges();
else if (document.selection) {document.selection.empty();} } else if (document.selection) {
document.selection.empty();
}
} }
function serializeForm(selector) { function serializeForm(selector) {
let form = document.querySelector(selector); let form = document.querySelector(selector);
if (form == null) {
return [];
}
let formData = new FormData(form); let formData = new FormData(form);
let serializedArray = []; let serializedArray = [];
formData.forEach(function(value, key) { formData.forEach(function (value, key) {
serializedArray.push({ serializedArray.push({
name: key, name: key,
value: value value: value
@ -20,44 +25,52 @@ function serializeForm(selector) {
return serializedArray; return serializedArray;
} }
function handleCheckChange () { function handleCheckChange() {
let frm = serializeForm('#main-form'); let frm = serializeForm('#main-form');
let bi = document.querySelector('#bulk-idz'); let bi = document.querySelector('#bulk-idz');
bi.innerHTML = ''; bi.innerHTML = '';
for( const item of frm) { for (const item of frm) {
let n =document.createElement("input"); let n = document.createElement("input");
n.name = item.name; n.name = item.name;
n.value = item.value; n.value = item.value;
n.type = 'hidden'; n.type = 'hidden';
bi.appendChild(n); bi.appendChild(n);
} }
if (frm.length == 0){ if (frm.length == 0) {
document.querySelector('#bulk-from').style.maxHeight = '0'; document.querySelector('#bulk-from').style.maxHeight = '0';
}else{ } else {
document.querySelector('#bulk-from').style.maxHeight = '250px'; document.querySelector('#bulk-from').style.maxHeight = '250px';
} }
} }
window.addEventListener('load',function () { window.addEventListener('load', function () {
let chkall = document.querySelectorAll(".chkall"); let chkall = document.querySelectorAll(".chkall");
document.querySelector('#toggle-select').addEventListener('click',function () { if (chkall.length == 0){
let checkboxes = document.querySelectorAll(".chkbox"); return false;
checkboxes.forEach(function(checkbox) { }
if (!checkbox.checked){ let toggle = document.querySelector('#toggle-select');
checkbox.checked = true; if (toggle != null) {
checkbox.setAttribute("checked", ""); toggle?.addEventListener('click', function () {
}else{ let checkboxes = document.querySelectorAll(".chkbox");
checkbox.checked = false; checkboxes.forEach(function (checkbox) {
checkbox.removeAttribute("checked"); if (!checkbox.checked) {
} checkbox.checked = true;
checkbox.setAttribute("checked", "");
} else {
checkbox.checked = false;
checkbox.removeAttribute("checked");
}
});
}); });
handleCheckChange(); handleCheckChange();
}); }
// Attach an event listener for "change" and "click" events // Attach an event listener for "change" and "click" events
chkall.forEach(function(chkall) { chkall.forEach(function (chkall) {
chkall.addEventListener("change", handleCheckboxChange); chkall.addEventListener("change", handleCheckboxChange);
chkall.addEventListener("click", handleCheckboxChange); chkall.addEventListener("click", handleCheckboxChange);
}); });
@ -69,14 +82,14 @@ window.addEventListener('load',function () {
if (isChecked) { if (isChecked) {
// Check all checkboxes in the table // Check all checkboxes in the table
let checkboxes = table.querySelectorAll(".chkbox"); let checkboxes = table.querySelectorAll(".chkbox");
checkboxes.forEach(function(checkbox) { checkboxes.forEach(function (checkbox) {
checkbox.checked = true; checkbox.checked = true;
checkbox.setAttribute("checked", ""); checkbox.setAttribute("checked", "");
}); });
} else { } else {
// Uncheck all checkboxes in the table // Uncheck all checkboxes in the table
let checkboxes = table.querySelectorAll(".chkbox"); let checkboxes = table.querySelectorAll(".chkbox");
checkboxes.forEach(function(checkbox) { checkboxes.forEach(function (checkbox) {
checkbox.checked = false; checkbox.checked = false;
checkbox.removeAttribute("checked"); checkbox.removeAttribute("checked");
}); });
@ -85,7 +98,6 @@ window.addEventListener('load',function () {
} }
// select with shift button // select with shift button
const chkboxes = document.querySelectorAll('.chkbox'); const chkboxes = document.querySelectorAll('.chkbox');
let lastChecked = null; let lastChecked = null;
@ -93,14 +105,14 @@ window.addEventListener('load',function () {
chkboxes.forEach(chkbox => { chkboxes.forEach(chkbox => {
chkbox.addEventListener('click', handleCheckboxClick); chkbox.addEventListener('click', handleCheckboxClick);
chkbox.parentNode.querySelector('label').addEventListener('click', handleCheckboxClick); chkbox.parentNode.querySelector('label').addEventListener('click', handleCheckboxClick);
chkbox.addEventListener('change',handleCheckChange); chkbox.addEventListener('change', handleCheckChange);
}); });
function handleCheckboxClick(e) { function handleCheckboxClick(e) {
clearSelection(); clearSelection();
let self = this; let self = this;
if (e.target.tagName === 'LABEL'){ if (e.target.tagName === 'LABEL') {
self = e.target.parentNode.querySelector('input'); self = e.target.parentNode.querySelector('input');
} }
if (!lastChecked) { if (!lastChecked) {
@ -111,7 +123,7 @@ window.addEventListener('load',function () {
if (e.shiftKey) { if (e.shiftKey) {
const start = Array.from(chkboxes).indexOf(self); const start = Array.from(chkboxes).indexOf(self);
const end = Array.from(chkboxes).indexOf(lastChecked); const end = Array.from(chkboxes).indexOf(lastChecked);
const range = Array.from(chkboxes).slice(Math.min(start, end) + 1, Math.max(start, end) ); const range = Array.from(chkboxes).slice(Math.min(start, end) + 1, Math.max(start, end));
range.forEach(chkbox => { range.forEach(chkbox => {
chkbox.checked = lastChecked.checked; chkbox.checked = lastChecked.checked;
@ -123,6 +135,7 @@ window.addEventListener('load',function () {
lastChecked = self; lastChecked = self;
} }
handleCheckChange(); handleCheckChange();
}); });

@ -1,4 +1,12 @@
const hideSidebar = function (e) {
if (!e.target.closest('aside') && !e.target.closest('#sidebar-panel')) {
document.querySelector('#panel').classList.remove('sided');
document.removeEventListener('click', hideSidebar);
}
};
window.addEventListener('load', function () { window.addEventListener('load', function () {
try { try {
document.querySelectorAll('#panel-navbar a')?.forEach(function (el) { document.querySelectorAll('#panel-navbar a')?.forEach(function (el) {
@ -8,9 +16,13 @@ window.addEventListener('load', function () {
e.preventDefault(); e.preventDefault();
document.querySelector('#panel').classList.add('sided'); document.querySelector('#panel').classList.add('sided');
document.querySelector('#sidebar-panel').innerHTML = document.querySelector(href).outerHTML; document.querySelector('#sidebar-panel').innerHTML = document.querySelector(href).outerHTML;
setTimeout(function () {
document.addEventListener('click',hideSidebar);
},50);
} }
}); });
}) });
} catch (e) { } catch (e) {
console.log(e.message); console.log(e.message);
} }

@ -15,6 +15,7 @@ $pnl-brc-height: 50px;
border-radius: 4px ; border-radius: 4px ;
transition: .5s; transition: .5s;
li{ li{
transition: 300ms;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
a,span{ a,span{
@ -30,6 +31,7 @@ $pnl-brc-height: 50px;
} }
&:before { &:before {
transition: 300ms;
content: ""; content: "";
width: 37px; width: 37px;
height: 37px; height: 37px;
@ -48,11 +50,11 @@ $pnl-brc-height: 50px;
&:hover{ &:hover{
background: #444e7c; background: #444e7c;
background-image: url("../images/pattern.png"); //background-image: url("../images/pattern.png");
& + li:before{ & + li:before{
background: #444e7c; background: #444e7c;
background-image: url("../images/pattern.png"); //background-image: url("../images/pattern.png");
} }
} }
} }

@ -51,3 +51,30 @@ a.btn,a.action-btn,a.circle-btn{
bottom: 1rem; bottom: 1rem;
} }
.general-form{
background: $lighter-color;
border-radius: 7px;
margin-bottom: 4rem;
position: relative;
h1{
font-size: 25px;
font-weight: 200;
background: #00000011;
padding: 1rem;
text-align: center;
margin: 0 -1rem;
}
.row{
padding: 0 1rem 2rem ;
}
input[type='submit']{
position: absolute ;
bottom: -1rem;
left: 50%;
transform: translateX(-50%);
min-width: 200px;
}
}

@ -0,0 +1,40 @@
@extends('layouts.app')
@section('content')
@if(hasRoute('create') && isset($item))
<a class="action-btn circle-btn"
data-bs-toggle="tooltip"
data-bs-placement="top"
data-bs-custom-class="custom-tooltip"
data-bs-title="{{__("Add another one")}}"
href="{{getRoute('create')}}"
>
<i class="ri-add-line"></i>
</a>
@else
<a class="action-btn circle-btn"
data-bs-toggle="tooltip"
data-bs-placement="top"
data-bs-custom-class="custom-tooltip"
data-bs-title="{{__("Show list")}}"
href="{{getRoute('index',[])}}"
>
<i class="ri-list-view"></i>
</a>
@endif
<form
@if(isset($item))
id="model-form-edit"
action="{{getRoute('update',$item->{$item->getRouteKeyName()})}}"
@else
id="model-form-create"
action="{{getRoute('store')}}"
@endif
method="post" enctype="multipart/form-data">
@csrf
@if(isset($item))
<input type="hidden" name="id" value="{{$item->id}}"/>
@endif
@yield('form')
</form>
@endsection

@ -71,7 +71,7 @@
<i class="ri-check-double-line"></i> <i class="ri-check-double-line"></i>
{{__("Bulk actions:")}} {{__("Bulk actions:")}}
</h3> </h3>
<form action="{{getRoute('bulk',[],strpos(request()->url(),'trashed') == false?'index':'trashed')}}" id="bulk-from" method="post"> <form action="{{getRoute('bulk',[])}}" id="bulk-from" method="post">
<div class="p-3"> <div class="p-3">
@ -120,7 +120,7 @@
</th> </th>
@foreach($cols as $col) @foreach($cols as $col)
<th> <th>
<a href="?sort={{$col}}{{sortSuffix($col)}}"> <a href="?sort={{$col}}{{sortSuffix($col)}}&{{queryBuilder('sort')}}">
{{__($col)}} {{__($col)}}
</a> </a>
</th> </th>
@ -160,7 +160,7 @@
<td> <td>
@if(strpos(request()->url(),'trashed') != false && hasRoute('restore')) @if(strpos(request()->url(),'trashed') != false && hasRoute('restore'))
<a href="{{getRoute('restore',$item->{$item->getRouteKeyName()},'trashed')}}" <a href="{{getRoute('restore',$item->{$item->getRouteKeyName()})}}"
class="btn btn-success btn-sm mx-1 d-xl-none d-xxl-none" class="btn btn-success btn-sm mx-1 d-xl-none d-xxl-none"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-placement="top" data-bs-placement="top"
@ -205,7 +205,7 @@
@endif @endif
@else @else
@if( hasRoute('restore') && $item->trashed()) @if( hasRoute('restore') && $item->trashed())
<a href="{{getRoute('restore',$item->{$item->getRouteKeyName()},'trashed')}}" <a href="{{getRoute('restore',$item->{$item->getRouteKeyName()})}}"
class="btn btn-success btn-sm mx-1" class="btn btn-success btn-sm mx-1"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-placement="top" data-bs-placement="top"
@ -263,7 +263,6 @@
</div> </div>
{{-- list content end--}} {{-- list content end--}}
</div> </div>
</div>
@if(hasRoute('create')) @if(hasRoute('create'))
<a class="action-btn circle-btn" <a class="action-btn circle-btn"

@ -1 +1,113 @@
<?php @extends('admin.templates.panel-form-template')
@section('title')
@if(isset($item))
{{__("Edit user")}} [{{$item->name}}]
@else
{{__("Add new user")}}
@endif -
@endsection
@section('form')
<div class="row">
<div class="col-lg-3">
<div class="item-list mb-3">
<h3 class="p-3">
<i class="ri-message-3-line"></i>
{{__("Tips")}}
</h3>
<ul>
<li>
{{__("If you want to change the password, choose both the same. Otherwise, leave the password field blank.")}}
</li>
<li>
{{__("E-mail is unique each users")}}
</li>
</ul>
</div>
@include('components.err')
</div>
<div class="col-lg-9 ps-xl-1 ps-xxl-1">
<div class="general-form ">
<h1>
@if(isset($item))
{{__("Edit user")}} [{{$item->name}}]
@else
{{__("Add new user")}}
@endif
</h1>
<div class="row">
<div class="col-md-6 col-xl-6 mt-3">
<div class="form-group">
<label for="name">
{{__('Name')}}
</label>
<input name="name" type="text" class="form-control @error('name') is-invalid @enderror"
placeholder="{{__('Name')}}" value="{{old('name',$item->name??null)}}"/>
</div>
</div>
<div class="col-md-6 col-xl-6 mt-3">
<div class="form-group">
<label for="email">
{{__('Email')}}
</label>
<input name="email" type="email" class="form-control @error('email') is-invalid @enderror"
placeholder="{{__('Email')}}" value="{{old('email',$item->email??null)}}"/>
</div>
</div>
<div class="col-md-6 col-xl-3 mt-3">
<div class="form-group">
<label for="role">
{{__('Role')}}
</label>
<searchable-select
:items='{{arrayNormolizeVueCompatible(\App\Models\User::$roles, true)}}'
title-field="name"
value-field="name"
xname="role"
@error('role') :err="true" @enderror
xvalue='{{old('role',$item->role??null)}}'
:close-on-Select="true"></searchable-select>
</div>
</div>
<div class="col-md-6 col-xl-3 mt-3">
<div class="form-group">
<label for="mobile">
{{__('Mobile')}}
</label>
<input name="mobile" type="text" class="form-control @error('mobile') is-invalid @enderror"
placeholder="{{__('Mobile')}}" value="{{old('mobile',$item->mobile??null)}}"
min-length="10"/>
</div>
</div>
<div class="col-md-6 col-xl-3 mt-3">
<div class="form-group">
<label for="password">
{{__('Password')}}
</label>
<input name="password" type="password"
class="form-control @error('password') is-invalid @enderror"
placeholder="{{__('Password')}}" value="{{old('password',''??null)}}"/>
</div>
</div>
<div class="col-md-6 col-xl-3 mt-3">
<div class="form-group">
<label for="password_confirmation">
{{__('password repeat')}}
</label>
<input name="password_confirmation" type="password"
class="form-control @error('password_confirmation') is-invalid @enderror"
placeholder="{{__('password repeat')}}"
value="{{old('password_confirmation',$item->password_confirmation??null)}}"/>
</div>
</div>
<div class="col-md-12">
<label> &nbsp;</label>
<input name="" type="submit" class="btn btn-primary mt-2" value="{{__('Save')}}"/>
</div>
</div>
</div>
</div>
</div>
@endsection

@ -5,7 +5,7 @@
{{__("Users list")}} {{__("Users list")}}
@endsection @endsection
@section('title') @section('title')
{{__("Users list")}} | {{__("Users list")}} -
@endsection @endsection
@section('filter') @section('filter')
<h2> <h2>

Loading…
Cancel
Save