From a20dc807487a03a183e956931510f6e29790390e Mon Sep 17 00:00:00 2001 From: A1Gard Date: Mon, 17 Jun 2024 14:31:05 +0330 Subject: [PATCH] added adv xcontroller added disable date picker --- app/Http/Controllers/Admin/AdvController.php | 132 ++++++++++++++++++ app/Http/Requests/AdvSaveRequest.php | 33 +++++ app/Models/Adv.php | 4 +- .../2024_05_07_125917_create_advs_table.php | 4 +- .../js/components/vueDateRangePicker.vue | 70 ++++++---- resources/js/components/vueDateTimePicker.vue | 88 ++++++++---- resources/views/admin/advs/adv-form.blade.php | 120 ++++++++++++++++ resources/views/admin/advs/adv-list.blade.php | 15 ++ .../components/panel-side-navbar.blade.php | 2 +- routes/web.php | 13 ++ 10 files changed, 423 insertions(+), 58 deletions(-) create mode 100644 app/Http/Controllers/Admin/AdvController.php create mode 100644 app/Http/Requests/AdvSaveRequest.php create mode 100644 resources/views/admin/advs/adv-form.blade.php create mode 100644 resources/views/admin/advs/adv-list.blade.php diff --git a/app/Http/Controllers/Admin/AdvController.php b/app/Http/Controllers/Admin/AdvController.php new file mode 100644 index 0000000..0986119 --- /dev/null +++ b/app/Http/Controllers/Admin/AdvController.php @@ -0,0 +1,132 @@ + + ['title' => "Edit", 'class' => 'btn-outline-primary', 'icon' => 'ri-edit-2-line'], + 'show' => + ['title' => "Detail", 'class' => 'btn-outline-light', 'icon' => 'ri-eye-line'], + 'destroy' => + ['title' => "Remove", 'class' => 'btn-outline-danger delete-confirm', 'icon' => 'ri-close-line'], + ]; + + + public function __construct() + { + parent::__construct(Adv::class, AdvSaveRequest::class); + } + + /** + * @param $adv Adv + * @param $request AdvSaveRequest + * @return Adv + */ + public function save($adv, $request) + { + + $adv->title = $request->input('title'); + $adv->max_click = $request->input('max_click'); + $adv->link = $request->input('link'); + $adv->expire = date('Y-m-d',$request->input('expire')); + $adv->user_id = auth()->id(); + $adv->status = $request->input('status'); + + if ($request->has('image')){ + $adv->image = $this->storeFile('image',$adv, 'ad'); + } + + $adv->save(); + return $adv; + + } + + + /** + * 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(Adv $item) + { + // + return view($this->formView, compact('item')); + } + + public function bulk(Request $request) + { + +// dd($request->all()); + $data = explode('.', $request->input('action')); + $action = $data[0]; + $ids = $request->input('id'); + switch ($action) { + case 'delete': + $msg = __(':COUNT items deleted successfully', ['COUNT' => count($ids)]); + $this->_MODEL_::destroy($ids); + break; + /**restore*/ + case 'restore': + $msg = __(':COUNT items restored successfully', ['COUNT' => count($ids)]); + foreach ($ids as $id) { + $this->_MODEL_::withTrashed()->find($id)->restore(); + } + break; + /*restore**/ + default: + $msg = __('Unknown bulk action : :ACTION', ["ACTION" => $action]); + } + + return $this->do_bulk($msg, $action, $ids); + } + + public function destroy(Adv $item) + { + return parent::delete($item); + } + + + public function update(Request $request, Adv $item) + { + return $this->bringUp($request, $item); + } + + /**restore*/ + public function restore($item) + { + return parent::restoreing(Adv::withTrashed()->where('id', $item)->first()); + } + /*restore**/ +} diff --git a/app/Http/Requests/AdvSaveRequest.php b/app/Http/Requests/AdvSaveRequest.php new file mode 100644 index 0000000..4393785 --- /dev/null +++ b/app/Http/Requests/AdvSaveRequest.php @@ -0,0 +1,33 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array|string> + */ + public function rules(): array + { + return [ + // + 'title' => ['required', 'string', 'max:255','min:5'], + 'link' => ['required', 'string', 'max:255','min:5'], + 'status' => ['required', 'boolean'], + 'image' => ['nullable', 'image', 'mimes:jpeg,png,jpg,gif,svg', 'max:2048'], + 'max_click' => ['required','numeric'], + ]; + } +} diff --git a/app/Models/Adv.php b/app/Models/Adv.php index ee495ce..5e0dbaa 100644 --- a/app/Models/Adv.php +++ b/app/Models/Adv.php @@ -12,9 +12,9 @@ class Adv extends Model public function imgUrl() { if ($this->image == null) { - return null; + return asset('assets/upload/logo.svg'); } - return \Storage::url('advs/' . $this->image); + return \Storage::url('ad/' . $this->image); } } diff --git a/database/migrations/2024_05_07_125917_create_advs_table.php b/database/migrations/2024_05_07_125917_create_advs_table.php index 91f3742..36ddd0b 100644 --- a/database/migrations/2024_05_07_125917_create_advs_table.php +++ b/database/migrations/2024_05_07_125917_create_advs_table.php @@ -14,11 +14,11 @@ return new class extends Migration Schema::create('advs', function (Blueprint $table) { $table->id(); $table->string('title'); - $table->timestamp('expire'); + $table->date('expire'); $table->string('image'); $table->unsignedInteger('max_click')->default(0); $table->unsignedInteger('click')->default(0); - $table->boolean('active')->default(true); + $table->boolean('status')->default(0); $table->string('link'); $table->unsignedBigInteger('user_id'); $table->softDeletes(); diff --git a/resources/js/components/vueDateRangePicker.vue b/resources/js/components/vueDateRangePicker.vue index 3f0c9e1..8dba389 100644 --- a/resources/js/components/vueDateRangePicker.vue +++ b/resources/js/components/vueDateRangePicker.vue @@ -346,6 +346,14 @@ export default { default: false, type: Boolean, }, + xmax: { + default: null, + type: Number, + }, + xmin: { + default: null, + type: Number, + }, }, mounted() { this.pDate = new persianDate(); @@ -364,7 +372,7 @@ export default { this.current = new Date(parseInt(this.modelValue)); this.val = this.modelValue; } - }else{ + } else { if (this.xvalue == null || this.xvalue == '' || this.xvalue == 'null') { dt = new Date(); this.val = null; @@ -375,7 +383,8 @@ export default { } } - + // tab fix + this.tabIndex = parseInt(this.defTab); } else { @@ -388,8 +397,8 @@ export default { // } }, computed: { - vals(){ - return JSON.stringify([this.startDate,this.endDate]); + vals() { + return JSON.stringify([this.startDate, this.endDate]); }, // get input class getClass: function () { @@ -513,10 +522,10 @@ export default { }, }, methods: { - onMouseEnter(obj){ + onMouseEnter(obj) { this.hoverDate = obj.unix; }, - onMouseLeave(){ + onMouseLeave() { this.hoverDate = null; }, // clear input @@ -532,6 +541,12 @@ export default { }, // handle select select(obj) { + if (this.xmax != null && obj.unix > this.xmax) { + return; + } + if (this.xmin != null && obj.unix < this.xmin) { + return; + } if (this.isSwiping) { return false; } @@ -694,19 +709,26 @@ export default { }, // is selected this td isActive(obj) { + let r = ''; if (obj.unix == this.startDate) { - return 'active-selected'; + r = 'active-selected'; } - if (this.endDate != null){ - if (obj.unix > this.startDate && obj.unix <= this.endDate){ - return 'active-selected'; + if (this.endDate != null) { + if (obj.unix > this.startDate && obj.unix <= this.endDate) { + r = 'active-selected'; } - }else if (this.startDate != null && this.hoverDate != null){ - if (obj.unix > this.startDate && obj.unix <= this.hoverDate){ - return 'active-selected'; + } else if (this.startDate != null && this.hoverDate != null) { + if (obj.unix > this.startDate && obj.unix <= this.hoverDate) { + r = 'active-selected'; } } - return ''; + if (this.xmax != null && obj.unix > this.xmax) { + r += ' disabled-date'; + } + if (this.xmin != null && obj.unix < this.xmin) { + r += ' disabled-date'; + } + return r; }, // select hour pickHour(i, ignore = false) { @@ -882,16 +904,16 @@ export default { } }, - convertToHuman(unix){ - if (unix == null || unix == ''){ - return ''; - } - let dt = new Date(unix * 1000); - if (this.tabIndex == 0){ - return this.pDate.parseHindi( this.pDate.convertDate2Persian(dt).join('/')); - }else{ - return dt.getFullYear() + '-' + dt.getMonth() + '-' + dt.getDate(); - } + convertToHuman(unix) { + if (unix == null || unix == '') { + return ''; + } + let dt = new Date(unix * 1000); + if (this.tabIndex == 0) { + return this.pDate.parseHindi(this.pDate.convertDate2Persian(dt).join('/')); + } else { + return dt.getFullYear() + '-' + dt.getMonth() + '-' + dt.getDate(); + } }, // hide modal hideModal() { diff --git a/resources/js/components/vueDateTimePicker.vue b/resources/js/components/vueDateTimePicker.vue index 6dbb45c..d1ef618 100644 --- a/resources/js/components/vueDateTimePicker.vue +++ b/resources/js/components/vueDateTimePicker.vue @@ -143,16 +143,16 @@ > AM -
PM
- {{pDate.make2number(cTime[0])}} : - {{pDate.make2number(cTime[1])}} + {{ pDate.make2number(cTime[0]) }} : + {{ pDate.make2number(cTime[1]) }}
@@ -282,6 +282,14 @@ export default { default: null, type: Number, }, + xmax: { + default: null, + type: Number, + }, + xmin: { + default: null, + type: Number, + }, xshow: { default: 'pdate', // show value type: String, @@ -339,7 +347,7 @@ export default { }, mounted() { this.pDate = new persianDate(); - let dt ; + let dt; // check value changed by user or not, then ignore xvalue if (this.val == null) { @@ -354,7 +362,7 @@ export default { this.current = new Date(parseInt(this.modelValue)); this.val = this.modelValue; } - }else{ + } else { dt = new Date(parseInt(this.xvalue) * 1000); if (this.xvalue == null || this.xvalue == '' || this.xvalue == 'null') { dt = new Date(); @@ -365,6 +373,8 @@ export default { this.val = this.xvalue; } } + // tab fix + this.tabIndex = parseInt(this.defTab); } else { @@ -377,7 +387,7 @@ export default { // } }, computed: { - selectedDateTime(){ + selectedDateTime() { // fullData[xshow] const dt = new Date(this.val * 1000); return this.makeDateObject(dt)[this.xshow]; @@ -517,6 +527,13 @@ export default { }, // handle select select(obj) { + + if (this.xmax != null && obj.unix > this.xmax) { + return; + } + if (this.xmin != null && obj.unix < this.xmin) { + return; + } if (this.isSwiping) { return false; } @@ -533,7 +550,7 @@ export default { this.val = obj.unix; this.fullData = obj; this.current = this.val = obj.unix; - if (this.closeOnSelect){ + if (this.closeOnSelect) { this.canCloseModal = true; this.hideModal(); } @@ -619,7 +636,7 @@ export default { this.current = Math.floor(dt / 1000); }, makeDateObject(dt, cls) { - dt.setHours(this.cTime[0],this.cTime[1]); + dt.setHours(this.cTime[0], this.cTime[1]); return { day: this.pDate.make2number(dt.getDate()), // day pDay: this.pDate.convertDate2Persian(dt)[2], // persian date @@ -669,18 +686,25 @@ export default { // is selected this td isActive(obj) { let dt = new Date(this.val * 1000); + let r = ''; if (dt.getFullYear() + '-' + dt.getMonth() + '-' + dt.getDate() == obj.date) { - return 'active-selected'; + r = 'active-selected'; + } + if (this.xmax != null && obj.unix > this.xmax) { + r += ' disabled-date'; } - return ''; + if (this.xmin != null && obj.unix < this.xmin) { + r += ' disabled-date'; + } + return r; }, // select hour pickHour(i, ignore = false) { let dt = new Date(this.val * 1000); - if (ignore){ + if (ignore) { dt.setHours(i); - }else{ - dt.setHours((this.mode == 'AM'? i : (i + 12) )); + } else { + dt.setHours((this.mode == 'AM' ? i : (i + 12))); } dt.setMinutes(this.cTime[1]); this.val = Math.floor(dt.getTime() / 1000); @@ -804,7 +828,7 @@ export default { triggerSwipe(direction) { // Update content padding based on swipe direction let y = parseInt(this.peDate[0]); - if (this.tabIndex == 1){ + if (this.tabIndex == 1) { y = parseInt(this.geDate[1]); } switch (direction) { @@ -826,29 +850,29 @@ export default { // change mode am/pm - changeMode(mode){ + changeMode(mode) { // ignore AM while AM - if (this.mode == 'AM' && mode == 'AM'){ - return ; + if (this.mode == 'AM' && mode == 'AM') { + return; } // ignore PM while PM - if (this.mode == 'PM' && mode == 'PM'){ - return ; + if (this.mode == 'PM' && mode == 'PM') { + return; } - if (mode == 'AM'){ + if (mode == 'AM') { - if (this.cTime[0] == 12){ + if (this.cTime[0] == 12) { this.pickHour(12); - }else{ + } else { this.pickHour(this.cTime[0] - 12, true); } - }else{ + } else { this.pickHour(this.cTime[0] + 12, true); } }, - selfUpdate(){ + selfUpdate() { let dt; // check value changed by user or not, then ignore xvalue if (this.val == null) { @@ -1169,21 +1193,27 @@ export default { border-radius: 2px; } -#modes{ +#modes { position: absolute; left: 5px; top: 5px; } -#modes .vuejs-btn{ + +#modes .vuejs-btn { padding: 5px; width: 40px; text-align: center; padding-top: 10px; } -#time{ + +#time { position: absolute; right: 5px; top: 5px; font-size: 25px; } + +.disabled-date { + background: silver; +} diff --git a/resources/views/admin/advs/adv-form.blade.php b/resources/views/admin/advs/adv-form.blade.php new file mode 100644 index 0000000..2a6455b --- /dev/null +++ b/resources/views/admin/advs/adv-form.blade.php @@ -0,0 +1,120 @@ +@extends('admin.templates.panel-form-template') +@section('title') + @if(isset($item)) + {{__("Edit adv")}} [{{$item->title}}] + @else + {{__("Add new adv")}} + @endif - +@endsection +@section('form') + +
+
+ + @include('components.err') +
+

+ + {{__("Tips")}} +

+
    +
  • + {{__("Max click zero is unlimited")}} +
  • +
  • + {{__("If not choose expire expire time will be unlimited")}} +
  • +
+
+ @if (isset($item)) +
+

+ + {{__("Image")}} +

+
+ {{$item->title}} +
+
+ @endif + +
+
+
+ +

+ @if(isset($item)) + {{__("Edit adv")}} [{{$item->title}}] + @else + {{__("Add new adv")}} + @endif +

+ +
+
+
+ + +
+
+
+
+ + +
+
+ +
+
+ + +
+
+
+
+ + +
+
+ +
+
+ + +
+
+
+ +{{-- WIP for lang change def tab--}} + +
+
+ + +
+
+
+
+
+@endsection diff --git a/resources/views/admin/advs/adv-list.blade.php b/resources/views/admin/advs/adv-list.blade.php new file mode 100644 index 0000000..4f5e88e --- /dev/null +++ b/resources/views/admin/advs/adv-list.blade.php @@ -0,0 +1,15 @@ +@extends('admin.templates.panel-list-template') + +@section('list-title') + + {{__("Advs list")}} +@endsection +@section('title') + {{__("Advs list")}} - +@endsection +@section('filter') + {{-- Other filters --}} +@endsection +@section('bulk') + {{-- --}} +@endsection diff --git a/resources/views/components/panel-side-navbar.blade.php b/resources/views/components/panel-side-navbar.blade.php index 69863d9..9d32fce 100644 --- a/resources/views/components/panel-side-navbar.blade.php +++ b/resources/views/components/panel-side-navbar.blade.php @@ -85,7 +85,7 @@
  • - + {{__("Advertise")}} diff --git a/routes/web.php b/routes/web.php index bfeb01c..78f1733 100644 --- a/routes/web.php +++ b/routes/web.php @@ -91,6 +91,19 @@ Route::prefix(config('app.panel.prefix'))->name('admin.')->group( Route::post('bulk', [\App\Http\Controllers\Admin\ClipController::class, "bulk"])->name('bulk'); Route::get('trashed', [\App\Http\Controllers\Admin\ClipController::class, "trashed"])->name('trashed'); }); + Route::prefix('adv')->name('adv.')->group( + function () { + Route::get('', [\App\Http\Controllers\Admin\AdvController::class, 'index'])->name('index'); + Route::get('create', [\App\Http\Controllers\Admin\AdvController::class, 'create'])->name('create'); + Route::post('store', [\App\Http\Controllers\Admin\AdvController::class, 'store'])->name('store'); + Route::get('show/{item}', [\App\Http\Controllers\Admin\AdvController::class, 'show'])->name('show'); + Route::get('edit/{item}', [\App\Http\Controllers\Admin\AdvController::class, 'edit'])->name('edit'); + Route::post('update/{item}', [\App\Http\Controllers\Admin\AdvController::class, 'update'])->name('update'); + Route::get('delete/{item}', [\App\Http\Controllers\Admin\AdvController::class, 'destroy'])->name('destroy'); + Route::get('restore/{item}', [\App\Http\Controllers\Admin\AdvController::class, 'restore'])->name('restore'); + Route::post('bulk', [\App\Http\Controllers\Admin\AdvController::class, "bulk"])->name('bulk'); + Route::get('trashed', [\App\Http\Controllers\Admin\AdvController::class, "trashed"])->name('trashed'); + }); Route::prefix('galleries')->name('gallery.')->group( function () { Route::get('', [\App\Http\Controllers\Admin\GalleryController::class, 'index'])->name('index');