From 2cc3475431f1e7af99df911a3b90b44b010b9b6b Mon Sep 17 00:00:00 2001 From: A1Gard Date: Mon, 24 Jun 2024 05:56:27 +0330 Subject: [PATCH] save quantities fixed some bugs for update and edit page --- app/Helpers/Helper.php | 26 ++ .../Controllers/Admin/ProductController.php | 28 +- app/Http/Controllers/XController.php | 5 +- app/Models/Product.php | 27 +- resources/js/app.js | 1 + resources/js/components/MetaInput.vue | 283 ++++++++++++++++-- resources/js/components/libs/store.js | 13 +- .../js/panel/product-upload-controller.js | 6 +- .../admin/products/product-form.blade.php | 6 + .../sub-pages/product-step4.blade.php | 6 + 10 files changed, 363 insertions(+), 38 deletions(-) diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index fa7d8f2..762f17c 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -393,6 +393,11 @@ function getModelLink($modelable_type, $modelable_id) } } +/** + * fix action in log + * @param $act + * @return string + */ function getAction($act) { $r = explode('::', $act); @@ -400,6 +405,10 @@ function getAction($act) } +/** + * ge all admin routes array + * @return array + */ function getAdminRoutes() { $routes = []; @@ -414,3 +423,20 @@ function getAdminRoutes() return $routes; } + + +/** + * get model with all custom attributes + * @param $model \Illuminate\Database\Eloquent\Model + * @return void + */ +function modelWithCustomAttrs($model){ + $data = $model->toArray(); + $attrs = $model->getMutatedAttributes(); + $attrs = array_diff($attrs,['translations']); + foreach ($attrs as $attr) { + $data[$attr] = $model->getAttribute($attr); + } + return $data; +} + diff --git a/app/Http/Controllers/Admin/ProductController.php b/app/Http/Controllers/Admin/ProductController.php index 28cf1d0..dd01676 100644 --- a/app/Http/Controllers/Admin/ProductController.php +++ b/app/Http/Controllers/Admin/ProductController.php @@ -8,6 +8,7 @@ use App\Http\Requests\ProductSaveRequest; use App\Models\Access; use App\Models\Category; use App\Models\Product; +use App\Models\Quantity; use Illuminate\Http\Request; use App\Helper; use function App\Helpers\hasCreateRoute; @@ -26,7 +27,6 @@ class ProductController extends XController protected $listView = 'admin.products.product-list'; protected $formView = 'admin.products.product-form'; - protected $buttons = [ 'edit' => ['title' => "Edit", 'class' => 'btn-outline-primary', 'icon' => 'ri-edit-2-line'], @@ -99,6 +99,30 @@ class ProductController extends XController // dd($request->input('meta')); $product->syncMeta(json_decode($request->get('meta','[]'),true)); } + $toRemoveQ = $product->quantities()->pluck('id')->toArray(); + if ($request->has('q')){ + $qz = json_decode($request->input('q')); + foreach ($qz as $qi){ + if ($qi->id == null){ + $q = new Quantity(); + }else{ + $q = Quantity::whereId($qi->id)->first(); + unset($toRemoveQ[array_search($q->id, $toRemoveQ) ]); // remove for to remove IDz + } + $q->image = $qi->image; + $q->count = $qi->count; + $q->price = $qi->price; + $q->product_id = $product->id; + $q->data = json_encode($qi->data); + $q->save(); + } + $product->quantities()->whereIn('id',$toRemoveQ)->delete(); + + $product->stock_quantity = $product->quantities()->sum('count'); + $product->price = $product->quantities()->min('price'); + $product->save(); + } + return $product; @@ -121,6 +145,7 @@ class ProductController extends XController public function edit(Product $item) { // + $cats = Category::all(['id','name','parent_id']); return view($this->formView, compact('item','cats')); } @@ -168,5 +193,6 @@ class ProductController extends XController { return parent::restoreing(Product::withTrashed()->where('id', $item)->first()); } + /*restore**/ } diff --git a/app/Http/Controllers/XController.php b/app/Http/Controllers/XController.php index a886a28..f467137 100644 --- a/app/Http/Controllers/XController.php +++ b/app/Http/Controllers/XController.php @@ -122,6 +122,7 @@ abstract class XController extends Controller if ($request->ajax()) { return ['OK' => true, "message" => __('As you wished created successfully'), "id" => $item->id, + "data" => modelWithCustomAttrs($item) , 'url' => getRoute('edit', $item->{$item->getRouteKeyName()})]; } else { return redirect(getRoute('edit', $item->{$item->getRouteKeyName()})) @@ -150,7 +151,9 @@ abstract class XController extends Controller logAdmin(__METHOD__, $this->_MODEL_, $item->id); if ($request->ajax()) { - return ['OK' => true, "message" => __('As you wished updated successfully'), "id" => $item->id]; + return ['OK' => true, + "data" => modelWithCustomAttrs($item) , + "message" => __('As you wished updated successfully'), "id" => $item->id]; } else { return redirect(getRoute('edit', $item->{$item->getRouteKeyName()})) ->with(['message' => __('As you wished updated successfully')]); diff --git a/app/Models/Product.php b/app/Models/Product.php index c4f6678..f3c7e81 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -16,6 +16,30 @@ class Product extends Model implements HasMedia { use HasFactory, SoftDeletes, InteractsWithMedia, HasTranslations, HasTags, Metable; + protected $casts = [ + 'qz' => 'array', + 'qidz' => 'array' + ]; + + + protected $guarded = []; + + + public function getQzAttribute(){ + $result = []; + foreach ($this->quantities as $q) { + if ($q->count > 0){ + $q->data = json_decode($q->data); + $result[] = $q; + } + } + + return $result; + } + public function getQidzAttribute(){ + return $this->quantities()->pluck('id')->toArray(); + } + public static $stock_status = ['IN_STOCK', 'OUT_STOCK', 'BACK_ORDER']; public $translatable = ['name', 'excerpt', 'description','table']; @@ -83,7 +107,7 @@ class Product extends Model implements HasMedia public function quantities() { - return $this->hasMany(Quantity::class, 'product_id'); + return $this->hasMany(Quantity::class); } public function discounts() @@ -148,4 +172,5 @@ class Product extends Model implements HasMedia } + } diff --git a/resources/js/app.js b/resources/js/app.js index fa7be4f..5517341 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -104,3 +104,4 @@ app.mount('#app'); window.app = app; window.$toast = $toast; +window.store = store; diff --git a/resources/js/components/MetaInput.vue b/resources/js/components/MetaInput.vue index 303b02c..3cca280 100644 --- a/resources/js/components/MetaInput.vue +++ b/resources/js/components/MetaInput.vue @@ -1,15 +1,24 @@ @@ -46,27 +146,60 @@ import {mapState} from "vuex"; import searchableMultiSelect from "./SearchableMultiSelect.vue"; +import CurrencyInput from "./CurrencyInput.vue"; +function arraysEqual(arr1, arr2) { + if (arr1.length !== arr2.length) { + return false; + } + + const sortedArr1 = arr1.slice().sort(); + const sortedArr2 = arr2.slice().sort(); + + return sortedArr1.every((value, index) => value === sortedArr2[index]); +} export default { name: "meta-input", components: { - searchableMultiSelect + searchableMultiSelect, + CurrencyInput }, data: () => { return { properties: [], - meta:{} + meta: {}, + hasPriceable: false, + quantities: [], + qOnEdit: 0, + modal: false, + lastCat: null, } }, props: { - propsApiLink:{ + imgz:{ + default: [] + }, + propsApiLink: { required: true, }, - metaz:{ + metaz: { + default: [], + }, + quantitiez: { default: [], + }, + productId: { + default: null, } - } , + }, mounted() { + // this.quantities = this.quantitiez; + for( const q of this.quantitiez) { + q.data = JSON.parse(q.data); + this.quantities.push(q); + } + + }, computed: { category_id: { @@ -77,40 +210,98 @@ export default { this.$store.commit('UPDATE_CATEGORY', value) } }, + qsid: { + get() { + return this.$store.state.quantities; + }, + set(value) { + // this.$store.commit('UPDATE_CATEGORY', value) + } + }, + qid(){ + let r = []; + for( const q of this.quantities) { + r.push(q.id); + } + + return r; + } }, methods: { - async updateProps(){ + + showModal(i){ + console.log('ii',i); + this.qOnEdit = i; + this.modal = true; + }, + changeImgIndex(i){ + console.log('jjj',i); + this.quantities[this.qOnEdit].image = i; + }, + remQ(i){ + this.quantities.splice(i,1); + }, + addQ() { + let data = { + id: null, + product_id: this.productId, + image: null, + price: 0, + count: 0, + data: {}, + }; + for (const prop of this.properties) { + // check priceable + if (prop.priceable) { + data.data[prop.name] = ''; + } + } + this.quantities.push(data); + }, + async updateProps() { try { - const url = this.propsApiLink + this.category_id; - let resp = await axios.get(url); + const url = this.propsApiLink + this.category_id; + let resp = await axios.get(url); this.properties = resp.data.data; // added don't have - for( const prop of this.properties) { - if (this.meta[prop.name] == undefined){ - if (prop.type == 'multi'){ + for (const prop of this.properties) { + // check priceable + if (prop.priceable) { + this.hasPriceable = true; + } + if (this.meta[prop.name] == undefined) { + if (prop.type == 'multi') { this.meta[prop.name] = []; - }else{ + } else { this.meta[prop.name] = ''; } } } // update by old meta data - for( const meta in this.metaz) { - this.meta[meta] = this.metaz[meta]; + for (const meta in this.metaz) { + this.meta[meta] = this.metaz[meta]; } - - } catch(e) { + } catch (e) { window.$toast.error(e.message); } }, }, watch: { - category_id: function() { - this.updateProps(); + category_id: function (old,n) { + console.log(old,n,'x'); + // if (this.lastCat != this.category_id){ + // this.lastCat = this.category_id; + this.updateProps(); + // } + }, + qsid: function () { + if (!arraysEqual(this.qid,this.qsid)){ + window.location.href = window.redirect; + } } } } @@ -120,7 +311,41 @@ export default { #meta-input { } -.color option{ +.color option { + +} + +.sq { + width: 37px; + height: 37px; + background: transparent; + border: 1px solid black; + position: absolute; + inset-inline-end: 0; + top: 0; + border-radius: 4px; +} + +#img-modal{ + position: fixed; + left: 0; + right: 0; + top: 0; + bottom: 0; + background: #00000033; + backdrop-filter: blur(5px); + z-index: 10; + //display: none; +} + +.img-index{ + width: 100%; + height: 25vh; + min-height: 200px; + object-fit: cover; +} +.selected-img{ + background: darkred; } diff --git a/resources/js/components/libs/store.js b/resources/js/components/libs/store.js index 9ecacf5..402c5d3 100644 --- a/resources/js/components/libs/store.js +++ b/resources/js/components/libs/store.js @@ -3,16 +3,23 @@ import Vuex from 'vuex'; export default new Vuex.Store({ state: { - category: '' + category: '', + quantities: [], }, mutations: { UPDATE_CATEGORY(state, payload) { state.category = payload; - } + }, + UPDATE_QUANTITIES(state, payload) { + state.quantities = payload; + }, }, actions:{ updateCategory(context,cat){ context.commit('UPDATE_CATEGORY',cat); - } + }, + updateQuantities(context,idz){ + context.commit('UPDATE_QUANTITIES',idz); + }, } }); diff --git a/resources/js/panel/product-upload-controller.js b/resources/js/panel/product-upload-controller.js index edf4460..69d0a0a 100644 --- a/resources/js/panel/product-upload-controller.js +++ b/resources/js/panel/product-upload-controller.js @@ -98,10 +98,10 @@ document.addEventListener('DOMContentLoaded', () => { if (res.data.link !== undefined) { this.setAttribute('action', res.data.link); } + window.redirect = currentEditLink + res.data.data.slug; + this.setAttribute('action', currentUpdateLink + res.data.data.slug) $toast.info(res.data.message); - if (document.querySelector('#price-amount').value.trim() !== '') { - window.location.reload(); - } + window.store.dispatch('updateQuantities',res.data.data.qidz); } } }).catch(error => { diff --git a/resources/views/admin/products/product-form.blade.php b/resources/views/admin/products/product-form.blade.php index bc94aa5..6a22ffd 100644 --- a/resources/views/admin/products/product-form.blade.php +++ b/resources/views/admin/products/product-form.blade.php @@ -165,3 +165,9 @@
@yield('out-of-form') @endsection +@section('js-content') + +@endsection diff --git a/resources/views/admin/products/sub-pages/product-step4.blade.php b/resources/views/admin/products/sub-pages/product-step4.blade.php index 97046b2..505b7fa 100644 --- a/resources/views/admin/products/sub-pages/product-step4.blade.php +++ b/resources/views/admin/products/sub-pages/product-step4.blade.php @@ -1,6 +1,12 @@ + +