¨4.0.1¨

This commit is contained in:
¨NW¨
2023-12-03 14:07:47 +00:00
parent c08b36d1b6
commit f35052522d
1112 changed files with 43019 additions and 24987 deletions

View File

@@ -0,0 +1,68 @@
import Vue from "vue";
import VariationMixin from "./mixins/VariationMixin";
import { toaster } from "@admin/js/Toaster";
new Vue({
el: "#app",
mixins: [VariationMixin],
created() {
this.setFormDefaultData();
},
mounted() {
this.focusInitialField();
},
methods: {
setFormDefaultData() {
this.form = {
uid: this.uid(),
type: "",
values: [
{
uid: this.uid(),
image: {
id: null,
path: null,
},
},
],
};
},
focusInitialField() {
this.$nextTick(() => {
$("#name").trigger("focus");
});
},
submit() {
this.formSubmitting = true;
$.ajax({
type: "POST",
url: route("admin.variations.store"),
data: this.transformData(this.form),
dataType: "json",
success: (response) => {
toaster(response.message, {
type: "success",
});
this.resetForm();
this.errors.reset();
},
})
.catch((error) => {
this.errors.reset();
this.errors.record(error.responseJSON.errors);
this.scrollToFirstErrorField(this.$refs.form.elements);
})
.always(() => {
this.formSubmitting = false;
});
},
},
});

View File

@@ -0,0 +1,55 @@
import Vue from "vue";
import VariationMixin from "./mixins/VariationMixin";
import { toaster } from "@admin/js/Toaster";
new Vue({
el: "#app",
mixins: [VariationMixin],
created() {
this.form = this.prepareFormData(FleetCart.data["variation"]);
},
mounted() {
this.initColorPicker();
},
methods: {
prepareFormData(formData) {
formData.uid = this.uid();
formData.values.forEach((value) => {
value.uid = this.uid();
});
return formData;
},
submit() {
this.formSubmitting = true;
$.ajax({
type: "PUT",
url: route("admin.variations.update", this.form.id),
data: this.transformData(this.form),
dataType: "json",
success: (response) => {
toaster(response.message, {
type: "success",
});
this.errors.reset();
},
})
.catch((error) => {
this.errors.reset();
this.errors.record(error.responseJSON.errors);
this.scrollToFirstErrorField(this.$refs.form.elements);
})
.always(() => {
this.formSubmitting = false;
});
},
},
});

View File

@@ -0,0 +1,242 @@
import draggable from "vuedraggable";
import Errors from "@admin/js/Errors";
import Coloris from "@melloware/coloris";
export default {
components: {
draggable,
},
data: {
formSubmitting: false,
form: {},
errors: new Errors(),
},
computed: {
isEmptyVariationType() {
return this.form.type === "";
},
},
mounted() {
this.hideColorPicker();
},
methods: {
uid() {
return Math.random().toString(36).slice(3);
},
changeVariationType(value) {
const values = this.form.values;
if (value !== "" && values.length === 1) {
this.$nextTick(() => {
$(`#values-${values[0].uid}-label`).trigger("focus");
});
}
if (value === "text") {
values.forEach((value) => {
this.errors.clear(`values.${value.uid}.color`);
this.errors.clear(`values.${value.uid}.image`);
});
} else if (value === "color") {
values.forEach((value) => {
this.errors.clear(`values.${value.uid}.image`);
});
this.$nextTick(() => {
this.initColorPicker();
});
} else if (value === "image") {
values.forEach((value, index) => {
if (!value.image) {
this.$set(values[index], "image", {
id: null,
path: null,
});
}
});
values.forEach((value) => {
this.errors.clear(`values.${value.uid}.color`);
});
} else {
this.clearValueErrors();
}
},
addRow() {
const values = this.form.values;
const uid = this.uid();
values.push({
uid,
image: {
id: null,
path: null,
},
});
this.$nextTick(() => {
$(`#values-${uid}-label`).trigger("focus");
if (this.form.type === "color") {
this.initColorPicker();
}
});
},
addRowOnPressEnter(event, index) {
const values = this.form.values;
if (event.target.value === "") return;
if (values.length - 1 === index) {
this.addRow();
return;
}
if (index < values.length - 1) {
$(`#values-${values[index + 1].uid}-label`).trigger("focus");
}
},
deleteRow(index, uid) {
const values = this.form.values;
values.splice(index, 1);
if (values.length === 0) {
this.addRow();
}
this.clearValueRowErrors(uid);
this.updateColorThumbnails();
},
updateColorThumbnails() {
if (this.form.type !== "color") return;
const elements = document.querySelectorAll(".clr-field");
this.form.values.forEach((value, index) => {
elements[index].style.color = value.color || "";
});
},
initColorPicker() {
Coloris.init();
Coloris({
el: ".color-picker",
alpha: false,
rtl: FleetCart.rtl,
theme: "large",
wrap: true,
format: "hex",
selectInput: true,
swatches: [
"#D01C1F",
"#3AA845",
"#118257",
"#0A33AE",
"#0D46A0",
"#000000",
"#5F4C3A",
"#726E6E",
"#F6D100",
"#C0E506",
"#FF540A",
"#C5A996",
"#4B80BE",
"#A1C3DA",
"#C8BFC2",
"#A9A270",
],
});
},
hideColorPicker() {
$(document).on("click", "#clr-swatches button", (e) => {
$(e.currentTarget)
.parents("#clr-picker")
.removeClass("clr-open");
});
},
chooseImage(index, uid) {
let picker = new MediaPicker({ type: "image" });
picker.on("select", ({ id, path }) => {
this.errors.clear(`values.${uid}.image`);
this.form.values[index].image = {
id: +id,
path,
};
});
},
resetForm() {
this.setFormDefaultData();
this.focusInitialField();
},
clearValueErrors() {
Object.keys(this.errors.errors).forEach((key) => {
if (key.startsWith("values")) {
this.errors.clear(key);
}
});
},
clearValueRowErrors(uid) {
Object.keys(this.errors.errors).forEach((key) => {
if (key.startsWith(`values.${uid}`)) {
this.errors.clear(key);
}
});
},
scrollToFirstErrorField(elements) {
this.$nextTick(() => {
[...elements]
.find(
(el) => el.name === Object.keys(this.errors.errors)[0]
)
.focus();
});
},
transformData(data) {
const formData = JSON.parse(JSON.stringify(data));
const PATHS = {
text: ["id", "uid", "label"],
color: ["id", "uid", "label", "color"],
image: ["id", "uid", "label", "image"],
};
if (formData.type === "") {
formData.values = [];
return formData;
}
formData.values = formData.values.reduce((accumulator, value) => {
value = _.pick(value, PATHS[formData.type]);
if (formData.type === "image") {
value.image = value.image.id;
}
return { ...accumulator, [value.uid]: value };
}, {});
return formData;
},
},
};

View File

@@ -0,0 +1,127 @@
/*rtl:begin:ignore*/
@import "@melloware/coloris/dist/coloris.css";
/*rtl:end:ignore*/
.form {
.has-variation-type {
margin-bottom: 10px;
}
}
.clr-field {
width: 100%;
button {
top: 4px;
right: 4px;
bottom: 4px;
height: auto;
width: 28px;
border-radius: 3px;
transform: none;
}
input {
padding-right: 40px;
}
}
.variations-group {
.variation-values {
margin-top: 15px;
}
}
.variation-values {
.table-responsive {
margin-bottom: 15px;
}
.options {
&.type-text {
.option-row {
td {
&:nth-child(2) {
width: 100%;
min-width: 180px;
}
}
}
}
}
.options {
&.type-color,
&.type-image {
.option-row {
td {
&:nth-child(2) {
width: 75%;
min-width: 160px;
}
&:nth-child(3) {
width: 25%;
min-width: 135px;
.image-holder {
height: 36px;
width: 36px;
margin: 0;
> i {
font-size: 20px;
}
}
}
}
}
}
}
}
@media screen and (min-width: 1200px) {
.variation-values {
.options {
&.type-color {
.option-row {
td:nth-child(3) {
min-width: 200px;
}
}
}
}
}
}
@media screen and (max-width: 767px) {
.box-body {
padding: 15px;
}
.form {
.has-variation-type {
margin-bottom: 5px;
}
> .row {
> div {
&:first-child {
margin-bottom: 10px;
}
}
&:last-child {
> div {
margin-bottom: 0;
}
}
}
}
.variations-group {
.variation-values {
margin-top: 20px;
}
}
}

View File

@@ -0,0 +1,10 @@
<?php
return [
'name' => 'Name',
'type' => 'Type',
'values' => 'Values',
'values.*.label' => 'Label',
'values.*.color' => 'Color',
'values.*.image' => 'Image',
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'variations' => [
'index' => 'Index Variations',
'create' => 'Create Variations',
'edit' => 'Edit Variations',
'destroy' => 'Delete Variations',
],
];

View File

@@ -0,0 +1,5 @@
<?php
return [
'variations' => 'Variations',
];

View File

@@ -0,0 +1,32 @@
<?php
return [
'variation' => 'Variation',
'variations' => 'Variations',
'table' => [
'name' => 'Name',
'type' => 'Type',
],
'group' => [
'general' => 'General',
'values' => 'Values',
],
'form' => [
'name' => 'Name',
'type' => 'Type',
'values' => 'Values',
'label' => 'Label',
'color' => 'Color',
'image' => 'Image',
'variation_types' => [
'please_select' => 'Please Select',
'text' => 'Text',
'color' => 'Color',
'image' => 'Image',
],
'add_row' => 'Add Row',
],
];

View File

@@ -0,0 +1,38 @@
@extends('admin::layout')
@component('admin::components.page.header')
@slot('title', trans('admin::resource.create', ['resource' => trans('variation::variations.variation')]))
<li><a href="{{ route('admin.variations.index') }}">{{ trans('variation::variations.variations') }}</a></li>
<li class="active">{{ trans('admin::resource.create', ['resource' => trans('variation::variations.variation')]) }}</li>
@endcomponent
@section('content')
<div class="box">
<div class="box-body">
<div id="app">
<form
class="form"
@input="errors.clear($event.target.name)"
@submit.prevent
ref="form"
>
@include('variation::admin.variations.partials.general')
@include('variation::admin.variations.partials.values')
@include('variation::admin.variations.partials.submit')
</form>
</div>
</div>
</div>
@endsection
@include('variation::admin.variations.partials.scripts')
@push('globals')
@vite([
'Modules/Variation/Resources/assets/admin/sass/main.scss',
'Modules/Variation/Resources/assets/admin/js/create.js',
'Modules/Media/Resources/assets/admin/sass/main.scss',
'Modules/Media/Resources/assets/admin/js/main.js',
])
@endpush

View File

@@ -0,0 +1,43 @@
@extends('admin::layout')
@component('admin::components.page.header')
@slot('title', trans('admin::resource.edit', ['resource' => trans('variation::variations.variation')]))
@slot('subtitle', $variation->name)
<li><a href="{{ route('admin.variations.index') }}">{{ trans('variation::variations.variations') }}</a></li>
<li class="active">{{ trans('admin::resource.edit', ['resource' => trans('variation::variations.variation')]) }}</li>
@endcomponent
@section('content')
<div class="box">
<div class="box-body">
<div id="app">
<form
class="form"
@input="errors.clear($event.target.name)"
@submit.prevent
ref="form"
>
@include('variation::admin.variations.partials.general')
@include('variation::admin.variations.partials.values')
@include('variation::admin.variations.partials.submit')
</form>
</div>
</div>
</div>
@endsection
@include('variation::admin.variations.partials.scripts')
@push('globals')
<script type="module">
FleetCart.data['variation'] = {!! $variation_resource !!};
</script>
@vite([
'Modules/Variation/Resources/assets/admin/sass/main.scss',
'Modules/Variation/Resources/assets/admin/js/edit.js',
'Modules/Media/Resources/assets/admin/sass/main.scss',
'Modules/Media/Resources/assets/admin/js/main.js',
])
@endpush

View File

@@ -0,0 +1,38 @@
@extends('admin::layout')
@component('admin::components.page.header')
@slot('title', trans('variation::variations.variations'))
<li class="active">{{ trans('variation::variations.variations') }}</li>
@endcomponent
@component('admin::components.page.index_table')
@slot('buttons', ['create'])
@slot('resource', 'variations')
@slot('name', trans('variation::variations.variation'))
@slot('thead')
<tr>
@include('admin::partials.table.select_all')
<th>{{ trans('admin::admin.table.id') }}</th>
<th>{{ trans('variation::variations.table.name') }}</th>
<th>{{ trans('variation::variations.table.type') }}</th>
<th data-sort>{{ trans('admin::admin.table.updated') }}</th>
</tr>
@endslot
@endcomponent
@push('scripts')
<script type="module">
new DataTable('#variations-table .table', {
columns: [
{ data: 'checkbox', orderable: false, searchable: false, width: '3%' },
{ data: 'id', width: '5%' },
{ data: 'name', name: 'translations.name', orderable: false, defaultContent: '' },
{ data: 'type', name: 'type' },
{ data: 'updated', name: 'updated_at' },
],
});
</script>
@endpush

View File

@@ -0,0 +1,57 @@
<div class="row" :class="{ 'has-variation-type': !isEmptyVariationType }">
<div class="col-lg-2 col-sm-2">
<h5>{{ trans('variation::variations.group.general') }}</h5>
</div>
<div class="col-lg-7 col-sm-10">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="name">
{{ trans('variation::attributes.name') }}
<span class="text-red">*</span>
</label>
<input type="text" name="name" id="name" class="form-control" v-model="form.name">
<span class="help-block text-red" v-if="errors.has('name')" v-text="errors.get('name')"></span>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="type">
{{ trans('variation::attributes.type') }}
<span class="text-red">*</span>
</label>
<select
name="type"
id="type"
class="form-control custom-select-black"
@change="changeVariationType($event.target.value)"
v-model="form.type"
>
<option value="">
{{ trans('variation::variations.form.variation_types.please_select') }}
</option>
<option value="text">
{{ trans('variation::variations.form.variation_types.text') }}
</option>
<option value="color">
{{ trans('variation::variations.form.variation_types.color') }}
</option>
<option value="image">
{{ trans('variation::variations.form.variation_types.image') }}
</option>
</select>
<span class="help-block text-red" v-if="errors.has('type')" v-text="errors.get('type')"></span>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,15 @@
@push('shortcuts')
<dl class="dl-horizontal">
<dt><code>b</code></dt>
<dd>{{ trans('admin::admin.shortcuts.back_to_index', ['name' => trans('variation::variations.variation')]) }}</dd>
</dl>
@endpush
@push('scripts')
<script type="module">
keypressAction([{
key: 'b',
route: "{{ route('admin.variations.index') }}"
}, ]);
</script>
@endpush

View File

@@ -0,0 +1,15 @@
<div class="row">
<div class="col-lg-7 col-lg-offset-2 col-md-12 text-right">
<button
type="button"
class="btn btn-primary"
:class="{
'btn-loading': formSubmitting
}"
:disabled="formSubmitting"
@click="submit"
>
{{ trans('admin::admin.buttons.save') }}
</button>
</div>
</div>

View File

@@ -0,0 +1,123 @@
<div v-cloak class="row" v-if="!isEmptyVariationType">
<div class="col-lg-2 col-sm-2">
<h5>{{ trans('variation::variations.group.values') }}</h5>
</div>
<div class="col-lg-7 col-sm-10">
<div class="variation-values clearfix">
<div class="table-responsive">
<table
class="options table table-bordered table-striped"
:class="form.type !== '' ? `type-${form.type}` : ''"
>
<thead>
<tr>
<th></th>
<th>
{{ trans('variation::variations.form.label') }}
<span class="text-red">*</span>
</th>
<th v-if="form.type === 'color'">
{{ trans('variation::variations.form.color') }}
<span class="text-red">*</span>
</th>
<th v-else-if="form.type === 'image'">
{{ trans('variation::variations.form.image') }}
<span class="text-red">*</span>
</th>
<th></th>
</tr>
</thead>
<tbody
is="draggable"
tag="tbody"
handle=".drag-handle"
animation="150"
:list="form.values"
@end="updateColorThumbnails"
>
<tr v-for="(value, index) in form.values" class="option-row" :key="index">
<td class="text-center">
<span class="drag-handle">
<i class="fa">&#xf142;</i>
<i class="fa">&#xf142;</i>
</span>
</td>
<td>
<input
type="text"
:name="`values.${value.uid}.label`"
:id="`values-${value.uid}-label`"
class="form-control"
@keyup.enter="addRowOnPressEnter($event, index)"
v-model="value.label"
>
<span
class="help-block text-red"
v-if="errors.has(`values.${value.uid}.label`)"
v-text="errors.get(`values.${value.uid}.label`)"
>
</span>
</td>
<td v-if="form.type === 'color'">
<div>
<input
type="text"
:name="`values.${value.uid}.color`"
:id="`values-${value.uid}-color`"
class="form-control color-picker"
v-model="value.color"
>
</div>
<span
class="help-block text-red"
v-if="errors.has(`values.${value.uid}.color`)"
v-text="errors.get(`values.${value.uid}.color`)"
>
</span>
</td>
<td v-else-if="form.type === 'image'">
<div class="d-flex">
<div
class="image-holder"
@click="chooseImage(index, value.uid)"
>
<template v-if="value.image.id">
<img :src="value.image.path" alt="variation image">
</template>
<img v-else src="{{ asset('build/assets/placeholder_image.png') }}" class="placeholder-image" alt="Placeholder image">
</div>
</div>
<span
class="help-block text-red"
v-if="errors.has(`values.${value.uid}.image`)"
v-text="errors.get(`values.${value.uid}.image`)"
>
</span>
</td>
<td class="text-center">
<button
type="button"
tabindex="-1"
class="btn btn-default delete-row"
@click="deleteRow(index, value.uid)"
>
<i class="fa fa-trash"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
<button type="button" class="btn btn-default" @click="addRow">
{{ trans('variation::variations.form.add_row') }}
</button>
</div>
</div>
</div>