FileMaster
Search
Toggle Dark Mode
Home
/
.
/
wp-content
/
plugins
/
ameliabooking
/
assets
/
views
/
backend
/
services
Edit File: DialogService.vue
<template> <div> <!-- Dialog Loader --> <div class="am-dialog-loader" v-show="passedService === null || dialogLoading"> <div class="am-dialog-loader-content"> <img :src="$root.getUrl+'public/img/spinner.svg'" class=""> <p>{{ $root.labels.loader_message }}</p> </div> </div> <div class="am-dialog-scrollable" :class="{'am-edit':service.id !== 0}" v-if="passedService !== null && !dialogLoading"> <!-- Dialog Header --> <div class="am-dialog-header"> <el-row> <el-col :span="18"> <h2 v-if="service.id !== 0">{{ $root.labels.edit_service }}</h2> <h2 v-else>{{ $root.labels.new_service }}</h2> </el-col> <el-col :span="6" class="align-right"> <el-button @click="closeDialog" class="am-dialog-close" size="small" icon="el-icon-close"></el-button> </el-col> </el-row> </div> <!-- Form --> <el-form :model="service" ref="service" :rules="rulesService" label-position="top"> <el-tabs v-model="serviceTabs"> <!-- Service Details --> <el-tab-pane :label="$root.labels.details" name="service_details"> <!-- Profile Photo --> <div class="am-service-profile"> <picture-upload :delete-icon-visibility="service.pictureThumbPath && service.pictureFullPath" :edited-entity="this.service" :entity-name="'service'" @pictureSelected="servicePictureSelected" v-on:deleteImage="() => deleteImage(service)" > </picture-upload> <el-popover ref="color-popover" v-model="colorPopover" placement="bottom" width="160" trigger="click" popper-class="am-color-popover" > <span v-for="color in serviceColors" :key="color" class="am-service-color" :class="{ 'color-active' : '#' + color === service.color}" @click="changeServiceColor" :data-color="'#'+color" :style="'background-color:#'+color" > </span> <el-form-item :label="$root.labels.hex + ':'"> <el-input v-model="service.color" auto-complete="off"></el-input> </el-form-item> <div class="align-right"> <el-button type="primary" size="mini" @click="colorPopover = false">{{ $root.labels.ok }}</el-button> </div> </el-popover> <span class="am-service-color" :style="bgColor(service.color)" v-popover:color-popover></span> <h2>{{ service.name }}</h2> </div> <!-- Name --> <el-form-item prop="name"> <label slot="label"> {{ $root.labels.name + ':' }} <div class="am-service-translate" @click="showDialogTranslate('serviceName')"> <img class="am-dialog-translate-svg" width="16px" :src="$root.getUrl+'public/img/translate.svg'"> {{ $root.labels.translate }} </div> </label> <el-input id="am-service-name" v-model="service.name" auto-complete="off" @input="clearValidation()" @change="trimProperty(service, 'name')"></el-input> </el-form-item> <!-- Category --> <el-form-item :label="$root.labels.category + ':'" prop="categoryId"> <el-select v-model="service.categoryId" placeholder="" @change="clearValidation()" > <el-option v-for="item in visibleCategories" :disabled="item.disabled" :key="item.id" :label="item.name" :value="item.id"> </el-option> </el-select> <img :src="$root.getUrl+'public/img/oval-spinner.svg'" class="svg-amelia is-spinner"> </el-form-item> <!-- Show On Front --> <div :class="licenceClass('starter')" class="am-setting-box am-switch-box"> <el-row type="flex" align="middle" :gutter="24"> <el-col :span="19"> {{ $root.labels.service_show_on_site }} <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.service_show_on_site_tooltip"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </el-col> <el-col :span="5" class="align-right"> <el-switch v-model="service.show" :disabled="notInLicence('starter')" active-text="" inactive-text="" > </el-switch> </el-col> </el-row> <LicenceBlock :licence="'starter'"/> </div> <el-row :class="licenceClass()"> <el-form-item label="placeholder" :label="$root.labels.service_recurring_cycle + ':'"> <label slot="label"> {{ $root.labels.service_recurring_cycle }}: <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.service_recurring_cycle_tooltip"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </label> <el-select v-model="service.recurringCycle" :disabled="notInLicence()" @change="clearValidation()" > <el-option v-for="cycle in recurringCycles" :key="cycle.value" :label="cycle.label" :value="cycle.value" > </el-option> </el-select> </el-form-item> <LicenceBlock/> </el-row> <el-row v-if="service.recurringCycle !== 'disabled'"> <el-form-item label="placeholder" :label="$root.labels.service_recurring_sub + ':'"> <label slot="label"> {{ $root.labels.service_recurring_sub }}: <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.service_recurring_sub_tooltip"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </label> <el-select v-model="service.recurringSub" @change="clearValidation()" > <el-option v-for="cycle in recurringSubs" :key="cycle.value" :label="cycle.label" :value="cycle.value" > </el-option> </el-select> </el-form-item> </el-row> <el-row v-if="service.recurringCycle !== 'disabled'"> <el-form-item label="placeholder" :label="$root.labels.service_recurring_payment + ':'"> <label slot="label"> {{ $root.labels.service_recurring_payment }}: <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.service_recurring_payment_tooltip"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </label> <el-select v-model="service.recurringPayment" @change="clearValidation()" > <el-option v-for="cycle in recurringPayments" :key="cycle.value" :label="cycle.label" :value="cycle.value" > </el-option> </el-select> </el-form-item> </el-row> <!-- Limit Appointments per Customer --> <div :class="licenceClass()" class="am-setting-box am-switch-box"> <el-row type="flex" align="middle" :gutter="24"> <el-col :span="19"> {{ $root.labels.limit_app_per_customer }} <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.limit_app_per_customer_tt"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </el-col> <el-col :span="5" class="align-right"> <el-switch v-model="service.limitPerCustomer.enabled" :disabled="notInLicence()" > </el-switch> </el-col> </el-row> <el-row :gutter="24" v-if="service.limitPerCustomer.enabled"> <el-col> <el-form-item> <label slot="label"> {{ $root.labels.number_of_appointments }}: </label> <el-input-number :min="0" id="am-limit-service-number" :placeholder="$root.settings.roles.limitPerCustomerService.numberOfApp.toString()" v-model="service.limitPerCustomer.numberOfApp"> </el-input-number> </el-form-item> </el-col> </el-row> <el-row :gutter="24" v-if="service.limitPerCustomer.enabled"> <el-col :span="12"> <el-form-item> <label slot="label"> {{ $root.labels.time_frame }}: </label> <el-select v-model="service.limitPerCustomer.timeFrame" clearable :placeholder="limitPerCustomerTimeFrames.find(t => t.value === $root.settings.roles.limitPerCustomerService.timeFrame).label" > <el-option v-for="timeFrame in limitPerCustomerTimeFrames" :key="timeFrame.value" :label="timeFrame.label" :value="timeFrame.value" > </el-option> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item> <label slot="label"> {{ $root.labels.period }}: </label> <el-input-number :min="0" id="am-limit-service-period" v-model="service.limitPerCustomer.period" :placeholder="$root.settings.roles.limitPerCustomerService.period.toString()" ></el-input-number> </el-form-item> </el-col> </el-row> <el-row v-if="service.limitPerCustomer.enabled" :gutter="24" style="margin-top: 10px; display: flex;align-items: baseline;"> <el-col :span="12"> {{ $root.labels.limit_app_per_customer_from }}: <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.limit_app_per_customer_from_tt"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </el-col> <el-col :span="12"> <el-select v-model="service.limitPerCustomer.from" :placeholder="limitPerCustomerFrom.find(t => t.value === $root.settings.roles.limitPerCustomerService.from).label" clearable > <el-option v-for="option in limitPerCustomerFrom" :key="option.value" :label="option.label" :value="option.value" > </el-option> </el-select> </el-col> </el-row> <LicenceBlock/> </div> <!-- Employees --> <el-form-item v-if="!notInLicence('starter')" :label="$root.labels.employees + ':'" prop="providers" id="providersElement"> <el-select v-model="service.providers" value-key="id" placeholder="" multiple collapse-tags @change="changeEmployees" > <el-option v-for="item in visibleEmployees" :key="item.id" :label="item.firstName + ' ' + item.lastName" :value="item" > </el-option> </el-select> </el-form-item> <!-- Description --> <content-block :label="$root.labels.description" :entity="service" textProperty="description" htmlProperty="descriptionHtml" @showDialogTranslate="showDialogTranslate('serviceDescription')" :hasTranslation="true" :hasQuill="true" :textModeProp="true" :allowImage="false" > </content-block> </el-tab-pane> <!-- Duration & Pricing --> <el-tab-pane :label="$root.labels.duration_and_pricing" name="pricing"> <el-row :gutter="24"> <!-- Duration --> <el-col :span="12"> <el-form-item :label="$root.labels.duration + ':'" prop="duration"> <el-select v-model="service.duration" placeholder="" @change="clearValidation()" > <el-option v-for="item in getPossibleDurationsInSeconds(service.duration)" :key="item" :label="secondsToNiceDuration(item)" :disabled="isDurationSelected(item)" :value="item" > </el-option> </el-select> </el-form-item> </el-col> <!-- Price --> <el-col :span="12"> <el-form-item :label="$root.labels.price + ':'" prop="price"> <div class="el-input"> <money v-model="service.price" v-bind="moneyComponentData" @input="priceChanged" class="el-input__inner"></money> </div> </el-form-item> </el-col> </el-row> <!-- Pending Time --> <div :class="licenceClass('starter')"> <el-row :gutter="24"> <!-- Buffer Time Before --> <el-col :span="12"> <el-form-item label="placeholder"> <label slot="label"> {{ $root.labels.service_buffer_time_before }}: <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.service_buffer_time_before_tooltip"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </label> <el-select v-model="service.timeBefore" :disabled="notInLicence('starter')" placeholder="" clearable @change="clearValidation()" > <el-option v-for="item in getPossibleDurationsInSeconds(service.timeBefore)" :key="item" :label="secondsToNiceDuration(item)" :value="item" > </el-option> </el-select> </el-form-item> </el-col> <!-- Buffer Time After --> <el-col :span="12"> <el-form-item label="placeholder"> <label slot="label"> {{ $root.labels.service_buffer_time_after }}: <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.service_buffer_time_after_tooltip"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </label> <el-select v-model="service.timeAfter" :disabled="notInLicence('starter')" placeholder="" clearable @change="clearValidation()" > <el-option v-for="item in getPossibleDurationsInSeconds(service.timeAfter)" :key="item" :label="secondsToNiceDuration(item)" :value="item" > </el-option> </el-select> </el-form-item> </el-col> </el-row> <LicenceBlock :licence="'starter'"/> </div> <!-- Capacity --> <div :class="licenceClass('starter')"> <el-row :gutter="24"> <!-- Minimum Capacity --> <el-col :span="12"> <el-form-item label="placeholder"> <label slot="label"> {{ $root.labels.minimum_capacity }}: <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.minimum_capacity_tooltip"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </label> <el-input-number v-model="service.minCapacity" :min="1" :disabled="notInLicence('starter')" @input="checkCapacityLimits()" > </el-input-number> </el-form-item> </el-col> <!-- Maximum Capacity --> <el-col :span="12"> <el-form-item label="placeholder"> <label slot="label"> {{ $root.labels.maximum_capacity }}: <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.maximum_capacity_tooltip"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </label> <el-input-number v-model="service.maxCapacity" :disabled="notInLicence('starter')" :min="service.minCapacity" @input="changeCapacity" > </el-input-number> </el-form-item> </el-col> </el-row> <LicenceBlock :licence="'starter'"/> </div> <!-- Bringing Anyone --> <div class="am-setting-box am-switch-box" v-if="service.maxCapacity > 1"> <el-row type="flex" align="middle" :gutter="24"> <el-col :span="19"> {{ $root.labels.limit_extra_people }} <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.limit_extra_people_tooltip"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </el-col> <el-col :span="5" class="align-right"> <el-switch v-model="maxExtraPeopleEnabled" active-text="" inactive-text="" @change="changeMaxExtraPeople" > </el-switch> </el-col> </el-row> <el-row v-if="maxExtraPeopleEnabled" style="margin-top: 10px"> <el-col> <el-form-item label="placeholder"> <label slot="label"> {{ $root.labels.limit_extra_people_set }}: </label> <el-input-number v-model="service.maxExtraPeople" :min="service.minCapacity - 1" :max="service.maxCapacity - 1" @input="clearValidation()" > </el-input-number> </el-form-item> </el-col> </el-row> </div> <!-- Bringing Anyone --> <div class="am-setting-box am-switch-box" v-if="service.maxCapacity > 1"> <el-row type="flex" align="middle" :gutter="24"> <el-col :span="19"> {{ $root.labels.bringing_anyone }} <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.bringing_anyone_tooltip"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </el-col> <el-col :span="5" class="align-right"> <el-switch v-model="service.bringingAnyone" active-text="" inactive-text="" > </el-switch> </el-col> </el-row> </div> <!-- Aggregated Price --> <div class="am-setting-box am-switch-box" v-if="service.maxCapacity > 1 && service.bringingAnyone"> <el-row type="flex" align="middle" :gutter="24"> <el-col :span="19"> {{ $root.labels.aggregated_price }} <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.aggregated_price_tooltip"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </el-col> <el-col :span="5" class="align-right"> <el-switch v-model="service.aggregatedPrice" active-text="" inactive-text="" > </el-switch> </el-col> </el-row> </div> <div v-if="service.maxCapacity > 1 || service.duration" class="am-custom-pricing"> <div class="am-custom-pricing-label">{{ $root.labels.custom_pricing }}</div> <div id="am-service-pricing-person" class="am-setting-box am-switch-box" :class="licenceClass()" v-if="service.maxCapacity > 1"> <!-- Person Pricing Enabled --> <el-row type="flex" align="middle" :gutter="24"> <el-col :span="19"> {{ $root.labels.custom_person_pricing_enabled }} </el-col> <el-col :span="5" class="align-right"> <el-switch v-model="personPricingEnabled" :disabled="notInLicence()" active-text="" inactive-text="" @change="togglePersonPricing" > </el-switch> </el-col> </el-row> <person-price v-if="isPersonPricingEnabled(service.customPricing)" :service="service" :enabledDelete="true" :enabledRange="true" @disable="personPricingEnabled = false" > </person-price> <LicenceBlock/> </div> <div id="am-service-pricing-period" class="am-setting-box am-switch-box" :class="licenceClass('pro')"> <!-- Person Pricing Enabled --> <el-row type="flex" align="middle" :gutter="24"> <el-col :span="19" class="am-custom-pricing-label-new"> {{ $root.labels.custom_period_pricing_enabled }} <span> {{ $root.labels.new_caps }} </span> </el-col> <el-col :span="5" class="align-right"> <el-switch v-model="periodPricingEnabled" :disabled="notInLicence('pro')" active-text="" inactive-text="" @change="togglePeriodPricing" > </el-switch> </el-col> </el-row> <period-price v-if="isPeriodPricingEnabled(service.customPricing) && !$root.licence.isLite && !$root.licence.isStarter && !$root.licence.isBasic" :service="service" :enabledAdd="true" :enabledEdit="true" :enabledDelete="true" @disable="periodPricingEnabled = false" > </period-price> <LicenceBlock :licence="'pro'"/> </div> <div id="am-service-pricing-duration" class="am-setting-box am-switch-box" :class="licenceClass()" v-if="service.duration"> <!-- Custom Duration Enabled --> <el-row type="flex" align="middle" :gutter="24"> <el-col :span="19"> {{ $root.labels.custom_duration_pricing_enabled }} </el-col> <el-col :span="5" class="align-right"> <el-switch v-model="durationPricingEnabled" :disabled="notInLicence()" active-text="" inactive-text="" @change="toggleDurationPricing" > </el-switch> </el-col> </el-row> <custom-duration v-if="isDurationPricingEnabled(service.customPricing)" :service="service" :enabledDelete="true" :enabledAdd="true" :enabledDuration="true" > </custom-duration> <LicenceBlock/> </div> </div> <div id="am-service-deposit" class="am-setting-box am-switch-box" :class="licenceClass()" v-if="depositAvailable()"> <!-- Deposit Enabled --> <el-row type="flex" align="middle" :gutter="24"> <el-col :span="19"> {{ $root.labels.deposit_enabled }} </el-col> <el-col :span="5" class="align-right"> <el-switch v-model="depositEnabled" :disabled="notInLicence()" active-text="" inactive-text="" @change="depositEnabledChanged" > </el-switch> </el-col> </el-row> <el-row :gutter="24" v-if="depositEnabled" class="am-service-deposit"> <el-col :span="12"> <el-form-item> <label slot="label"> {{ $root.labels.deposit_payment }}: <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.deposit_payment_tooltip"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </label> <el-select v-model="depositPayment" placeholder="" @change="depositChanged()" > <el-option v-for="(item, index) in depositOptions" :key="index" :label="item.label" :value="item.value" > </el-option> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item :label="$root.labels.deposit_amount + (depositPayment === 'fixed' ? ' (' + getCurrencySymbol() + ')' : '') + (depositPayment === 'percentage' ? ' (%)' : '') + ':'" prop="deposit"> <div v-if="depositPayment === 'fixed'" class="el-input"> <money v-model="service.deposit" v-bind="moneyComponentData" @input="depositChanged" class="el-input__inner"></money> </div> <el-input-number v-if="depositPayment === 'percentage'" v-model="service.deposit" :min="0" :max="100" @input="depositChanged()" > </el-input-number> </el-form-item> </el-col> </el-row> <el-row :gutter="24" v-if="depositEnabled && service.aggregatedPrice && service.maxCapacity > 1 && depositPayment === 'fixed'"> <el-col> <el-checkbox v-model="service.depositPerPerson"> {{$root.labels.deposit_per_person}} <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.deposit_by_the_number_of_people"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </el-checkbox> </el-col> </el-row> <el-row class="am-service-deposit" :gutter="24" v-if="depositEnabled"> <el-col> <el-checkbox v-model="service.fullPayment"> {{$root.labels.allow_total_amount}} <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.allow_customers_to_pay_total"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </el-checkbox> <hr> </el-col> </el-row> <el-row :gutter="24" v-if="depositEnabled" class="am-service-deposit"> <el-col :span="24" :style="{display: 'flex'}"> <i class="el-icon-warning-outline" :style="{marginRight: '8px'}"></i> <label> {{service.extras.length === 0 ? $root.labels.deposit_info : depositPayment === 'fixed' ? $root.labels.deposit_info_fixed : $root.labels.deposit_info_percentage}} </label> </el-col> </el-row> <LicenceBlock/> </div> </el-tab-pane> <!-- Gallery --> <el-tab-pane :label="$root.labels.gallery" name="gallery"> <div class="am-gallery-images"> <el-row :gutter="24"> <draggable v-model="service.gallery" :options="draggableOptions" @end="dropGalleryImage"> <el-col :sm="12" v-for="(galleryImage, index) in service.gallery" :key="index"> <div class="am-gallery-image-wrapper"> <div class="am-gallery-image" :style="{'background-image': 'url(' + galleryImage.pictureFullPath + ')'}"> <i class="el-icon-delete" @click="deleteGalleryImage(index)"></i> </div> <div class="am-gallery-image-title"> <span class="am-drag-handle"> <img class="svg-amelia" width="20px" :src="$root.getUrl+'public/img/burger-menu.svg'"> </span> <span>{{ galleryImage.pictureFullPath.substring(galleryImage.pictureFullPath.lastIndexOf('/')+1) }}</span> </div> </div> </el-col> </draggable> <!-- Add Gallery --> <el-col :sm="12"> <div class="am-gallery-image-add"> <div> <picture-upload :multiple="true" :edited-entity="null" :entity-name="'gallery'" @pictureSelected="galleryPictureSelected" > </picture-upload> </div> </div> </el-col> </el-row> </div> </el-tab-pane> <!-- Extras --> <el-tab-pane v-if="notInLicence('starter') ? licenceVisible() : true" :label="$root.labels.extras" name="extras"> <LicenceBlockHeader :licence="'starter'"/> <div :class="licenceClassDisabled('starter')" class="am-setting-box am-switch-box" v-if="service.extras.length > 0"> <!-- mandatory extras --> <el-row type="flex" align="middle" :gutter="24"> <el-col :span="19"> {{ $root.labels.mandatory_extra_enable }} </el-col> <el-col :span="5" class="align-right"> <el-switch v-model="service.mandatoryExtra" active-text="" inactive-text="" > </el-switch> </el-col> </el-row> <el-row :gutter="24" v-if="service.mandatoryExtra" class="am-service-deposit"> <el-col :span="24"> <el-form-item> <label slot="label"> {{ $root.labels.min_required_extras }}: </label> <el-input-number v-model="service.minSelectedExtras" :min="1" :max="service.extras.length" @input="minSelectedExtrasChanged()" > </el-input-number> </el-form-item> </el-col> </el-row> </div> <div class="am-extra-list" :class="licenceClassDisabled('starter')" > <el-button :disabled="notInLicence('starter')" @click="addExtra" size="large" type="primary" class="am-dialog-create" > <i class="el-icon-plus"></i> <span class="button-text">{{ $root.labels.add_extra }}</span> </el-button> <draggable v-model="service.extras" :options="draggableOptions" @end="dropExtra"> <transition-group name="list-complete"> <div class="am-extra-item" v-loading="extraToDeleteLoading && index === service.extras.indexOf(extraToDelete)" v-for="(extra, index) in service.extras" :key="index + 1" :id="'extra' + index"> <!-- Extra Preview --> <el-row type="flex" align="top" class=""> <el-col :span="2"> <span class="am-drag-handle"> <img class="svg-amelia" width="20px" :src="$root.getUrl+'public/img/burger-menu.svg'"> </span> </el-col> <el-col :span="22"> <el-row type="flex" align="middle"> <el-col :span="18"> <h3>{{ extra.name }}</h3> </el-col> <el-col v-show="index !== service.extras.indexOf(editedExtra) || editedExtraOld !== null" :span="6" class="extra-item-actions align-right"> <span @click="showEditExtraDialog(extra)"> <img class="svg-amelia edit" width="16px" :src="$root.getUrl+'public/img/edit.svg'"> </span> <span v-if="$root.settings.capabilities.canDelete === true" @click="showDeleteExtraDialog(extra)" > <img class="svg-amelia" width="16px" :src="$root.getUrl+'public/img/delete.svg'"> </span> </el-col> </el-row> <div class="am-extra-item-data" v-show="(editedExtra === null || index !== service.extras.indexOf(editedExtra)) && (extraToDelete === null || index !== service.extras.indexOf(extraToDelete))"> <el-row :gutter="24"> <el-col :sm="7"> <span class="data-title">{{ $root.labels.duration }}:</span> <span class="data-value"> {{ extra.duration ? secondsToNiceDuration(extra.duration) : '/'}} </span> </el-col> <el-col :sm="7"> <span class="data-title">{{ $root.labels.price }}:</span> <span class="data-value">{{ getFormattedPrice(extra.price) }}</span> </el-col> <el-col :sm="10"> <span class="data-title">{{ $root.labels.maximum_quantity }}:</span> <span class="data-value">{{ extra.maxQuantity }}</span> </el-col> </el-row> </div> </el-col> </el-row> <!-- Extra Delete --> <el-collapse-transition> <div class="am-confirmation" v-show="extraToDelete !== null && index === service.extras.indexOf(extraToDelete)"> <p>{{ $root.labels.delete_extra_confirmation }}?</p> <div class="align-right"> <el-button size="small" @click="hideDeleteExtraDialog()">{{ $root.labels.cancel }}</el-button> <el-button size="small" @click="deleteExtra(extra)" type="primary">{{ $root.labels.delete }} </el-button> </div> </div> </el-collapse-transition> <!-- Extra Edit --> <el-collapse-transition> <div v-show="extraEditDialog === true && index === service.extras.indexOf(editedExtra)"> <el-form :model="extra" ref="extra" :rules="rulesExtra" label-position="top"> <!-- Extra Name --> <el-form-item prop="name"> <label slot="label" class="am-service-name-label"> {{ $root.labels.name + ':' }} <div class="am-service-translate" @click="showDialogTranslate('extraName', index)"> <img class="am-dialog-translate-svg" width="16px" :src="$root.getUrl+'public/img/translate.svg'"> {{ $root.labels.translate }} </div> </label> <el-input v-model="extra.name" auto-complete="off"></el-input> </el-form-item> <!-- Duration & Price --> <el-row :gutter="24"> <!-- Duration --> <el-col :sm="8" :xs="12"> <el-form-item :label="$root.labels.duration + ':'"> <el-select v-model="extra.duration" clearable placeholder="" > <el-option v-for="item in getPossibleDurationsInSeconds(extra.duration)" :key="item" :label="secondsToNiceDuration(item)" :value="item" > </el-option> </el-select> </el-form-item> </el-col> <!-- Price --> <el-col :sm="8" :xs="12"> <el-form-item :label="$root.labels.price + ':'" prop="price"> <div class="el-input"> <money v-model="extra.price" v-bind="moneyComponentData" class="el-input__inner"></money> </div> </el-form-item> </el-col> <!-- Maximum Capacity --> <el-col :sm="8" :xs="24"> <el-form-item :label="$root.labels.maximum_quantity + ':'"> <el-input-number v-model="extra.maxQuantity" :min="1"></el-input-number> </el-form-item> </el-col> </el-row> <!-- Aggregated Price --> <div class="am-setting-box am-switch-box" v-if="service.maxCapacity > 1 && extra.aggregatedPrice !== null && service.bringingAnyone"> <el-row type="flex" align="middle" :gutter="24"> <el-col :span="19"> {{ $root.labels.aggregated_price }} <el-tooltip placement="top"> <div slot="content" v-html="$root.labels.aggregated_price_tooltip"></div> <i class="el-icon-question am-tooltip-icon"></i> </el-tooltip> </el-col> <el-col :span="5" class="align-right"> <el-switch v-model="extra.aggregatedPrice" active-text="" inactive-text="" > </el-switch> </el-col> </el-row> </div> <!-- Description --> <content-block :label="$root.labels.description" :entity="service.extras[index]" textProperty="description" htmlProperty="descriptionHtml" @showDialogTranslate="showDialogTranslate('extraDescription', index)" :hasTranslation="true" :hasQuill="true" :textModeProp="true" :allowImage="false" > </content-block> <!-- Cancel & Save --> <div class="align-right"> <el-button @click="cancelExtra(extra)" size="small">{{ $root.labels.cancel }} </el-button> <el-button size="small" @click="saveExtra(extra)" type="primary">{{ $root.labels.save }} </el-button> </div> </el-form> </div> </el-collapse-transition> </div> </transition-group> </draggable> </div> </el-tab-pane> <el-tab-pane :label="$root.labels.settings" name="settings"> <entity-settings :settings="settings" :paymentsSettings="service.settings.payments" :generalSettings="service.settings.general" :zoomSettings="service.settings.zoom" :lessonSpaceSettings="service.settings.lessonSpace" :google-meet-settings="service.settings.googleMeet" :microsoft-teams-settings="service.settings.microsoftTeams" :providers="service.providers" > </entity-settings> </el-tab-pane> </el-tabs> </el-form> </div> <dialog-actions v-if="!dialogLoading" formName="service" urlName="services" :isNew="service.id === 0" :entity="service" :getParsedEntity="getParsedEntity" @validationTabFailCallback="validationTabFailCallback" :haveSaveConfirmation="haveSaveConfirmation" @validationFailCallback="validationFailCallback" :hasIcons="true" :updateStash="true" :status="{ on: 'visible', off: 'hidden' }" :buttonText="{ confirm: { save: { yes: $root.labels.update_for_all, no: $root.labels.no }, status: { yes: service.status === 'visible' ? $root.labels.visibility_hide : $root.labels.visibility_show, no: $root.labels.visibility_show } } }" :action="{ haveAdd: true, haveEdit: true, haveStatus: true, haveRemove: $root.settings.capabilities.canDelete === true, haveRemoveEffect: true, haveDuplicate: true }" :message="{ success: { save: $root.labels.service_saved, remove: $root.labels.service_deleted, show: $root.labels.service_visible, hide: $root.labels.service_hidden }, confirm: { save: $root.labels.confirm_global_change_service, remove: $root.labels.confirm_delete_service, show: $root.labels.confirm_show_service, hide: $root.labels.confirm_hide_service, duplicate: $root.labels.confirm_duplicate_service }, }" > </dialog-actions> </div> </template> <script> import licenceMixin from '../../../js/common/mixins/licenceMixin' import imageMixin from '../../../js/common/mixins/imageMixin' import dateMixin from '../../../js/common/mixins/dateMixin' import durationMixin from '../../../js/common/mixins/durationMixin' import priceMixin from '../../../js/common/mixins/priceMixin' import helperMixin from '../../../js/backend/mixins/helperMixin' import settingsMixin from '../../../js/common/mixins/settingsMixin' import serviceMixin from '../../../js/common/mixins/serviceMixin' import servicePriceMixin from '../../../js/common/mixins/servicePriceMixin' import PictureUpload from '../parts/PictureUpload.vue' import Form from 'form-object' import Draggable from 'vuedraggable' import { Money } from 'v-money' import notifyMixin from '../../../js/backend/mixins/notifyMixin' import DialogActions from '../parts/DialogActions.vue' import EntitySettings from '../parts/EntitySettings.vue' import DialogTranslate from '../parts/DialogTranslate' import ContentBlock from '../parts/ContentBlock' import CustomDuration from '../../parts/assignedServices/CustomDuration' import PersonPrice from '../../parts/assignedServices/PersonPrice' import PeriodPrice from '../../parts/assignedServices/PeriodPrice' export default { mixins: [ licenceMixin, imageMixin, dateMixin, durationMixin, priceMixin, serviceMixin, servicePriceMixin, notifyMixin, helperMixin, settingsMixin ], props: { categories: null, passedService: null, employees: null, settings: null, futureAppointments: null, newExtraTranslations: null }, data () { let validateNonNegativePrice = (rule, price, callback) => { if (price < 0) { callback(new Error(this.$root.labels.enter_non_negative_price_warning)) } else { callback() } } let validatePositiveValue = (rule, price, callback) => { if (price <= 0) { this.serviceTabs = 'pricing' callback(new Error(this.$root.labels.enter_positive_price_warning)) } else { callback() } } return { durationPricingEnabled: false, personPricingEnabled: false, periodPricingEnabled: false, durations: [], depositEnabled: false, mandatoryExtraEnabled: false, depositPayment: 'fixed', depositOptions: [ { value: 'fixed', label: this.$root.labels.amount_fixed }, { value: 'percentage', label: this.$root.labels.amount_percentage } ], executeUpdate: true, dialogLoading: true, appointmentsEmployees: [], colorPopover: false, draggableOptions: { animation: 150, group: 'people', handle: '.am-drag-handle' }, editedExtra: null, editedExtraOld: null, extraEditDialog: false, extraToDelete: null, extraToDeleteLoading: false, form: new Form(), rulesExtra: { name: [ {required: true, message: this.$root.labels.enter_extra_name_warning, trigger: 'submit'} ], price: [ {validator: validateNonNegativePrice, trigger: 'submit'}, {required: true, message: this.$root.labels.enter_extra_price_warning, trigger: 'submit', type: 'number'} ] }, rulesService: { name: [ {required: true, message: this.$root.labels.enter_name_warning, trigger: 'submit'} ], categoryId: [ { required: true, message: this.$root.labels.select_service_category_warning, trigger: 'submit', type: 'number' } ], duration: [ { required: true, message: this.$root.labels.select_service_duration_warning, trigger: 'submit', type: 'number' } ], price: [ {validator: validateNonNegativePrice, trigger: 'submit'}, {required: true, message: this.$root.labels.enter_service_price_warning, trigger: 'submit', type: 'number'} ], deposit: [ {validator: validatePositiveValue, trigger: 'submit'} ], providers: [ {required: true, message: this.$root.labels.select_service_employee_warning, trigger: 'submit'} ] }, recurringCycles: [ { label: this.$root.labels.disabled, value: 'disabled' }, { label: this.$root.labels.all, value: 'all' }, { label: this.$root.labels.recurring_type_daily, value: 'daily' }, { label: this.$root.labels.recurring_type_weekly, value: 'weekly' }, { label: this.$root.labels.recurring_type_monthly, value: 'monthly' } ], recurringSubs: [ { label: this.$root.labels.disabled, value: 'disabled' }, { label: this.$root.labels.service_recurring_sub_future, value: 'future' }, { label: this.$root.labels.service_recurring_sub_past, value: 'past' }, { label: this.$root.labels.service_recurring_sub_both, value: 'both' } ], recurringPayments: [ { label: this.$root.labels.service_recurring_payment_none, value: 0 }, { label: this.$root.labels.service_recurring_payment_all, value: 999 } ], limitPerCustomerTimeFrames: [ { label: this.$root.labels.hour, value: 'hour' }, { label: this.$root.labels.day, value: 'day' }, { label: this.$root.labels.week, value: 'week' }, { label: this.$root.labels.month, value: 'month' }, { label: this.$root.labels.year, value: 'year' } ], limitPerCustomerFrom: [ { label: this.$root.labels.limit_app_date_booked, value: 'dateBooked' }, { label: this.$root.labels.limit_app_booking_date, value: 'bookingDate' } ], service: null, serviceColors: [ '1788FB', '4BBEC6', 'FBC22D', 'FA3C52', 'D696B8', '689BCA', '26CC2B', 'FD7E35', 'E38587', '774DFB' ], serviceTabs: 'service_details', style: '', maxExtraPeopleEnabled: false } }, created () { Form.defaults.axios = this.$http this.instantiateDialog() }, updated () { this.instantiateDialog() if (this.service && (!this.service.limitPerCustomer || !this.service.limitPerCustomer.period)) { let element = document.getElementById('am-limit-service-period') if (element) { element.getElementsByClassName('el-input__inner')[0].value = '' } } if (this.service && (!this.service.limitPerCustomer || !this.service.limitPerCustomer.numberOfApp)) { let element = document.getElementById('am-limit-service-number') if (element) { element.getElementsByClassName('el-input__inner')[0].value = '' } } }, methods: { changeMaxExtraPeople () { if (this.maxExtraPeopleEnabled && this.service.maxExtraPeople === null) { this.service.maxExtraPeople = this.service.minCapacity - 1 } }, minSelectedExtrasChanged () { if (this.service.minSelectedExtras > this.service.extras.length) { this.service.minSelectedExtras = this.service.extras.length } }, toggleDurationPricing () { this.service.customPricing.enabled = this.durationPricingEnabled ? 'duration' : null this.personPricingEnabled = false this.periodPricingEnabled = false }, togglePersonPricing () { this.service.customPricing.enabled = this.personPricingEnabled ? 'person' : null this.durationPricingEnabled = false this.periodPricingEnabled = false }, togglePeriodPricing () { this.service.customPricing.enabled = this.periodPricingEnabled ? 'period' : null this.durationPricingEnabled = false this.personPricingEnabled = false }, changeCapacity () { if (this.service.customPricing.persons.length) { this.service.customPricing.persons[this.service.customPricing.persons.length - 1].range = null let invalidRangeIndex = null this.service.customPricing.persons.forEach((item, index) => { if (invalidRangeIndex === null && index > 0) { if (this.service.customPricing.persons[index - 1].range >= this.service.maxCapacity) { invalidRangeIndex = index } } else if (invalidRangeIndex === null && (this.service.customPricing.persons[index].range ? this.service.customPricing.persons[index].range : this.service.maxCapacity) >= this.service.maxCapacity) { invalidRangeIndex = 0 } }) if (invalidRangeIndex !== null && invalidRangeIndex !== 0) { this.service.customPricing.persons = this.service.customPricing.persons.filter( (i, index) => index < invalidRangeIndex ) this.service.customPricing.persons[this.service.customPricing.persons.length - 1].range = null } if (this.service.customPricing.persons.length <= 1 || invalidRangeIndex === 0) { this.service.customPricing.persons = [] this.service.customPricing.enabled = this.service.customPricing.enabled === 'person' ? null : this.service.customPricing.enabled this.personPricingEnabled = false } } this.clearValidation() }, depositAvailable () { let depositAvailable = parseFloat(this.service.price) > 0 if (this.isDurationPricingEnabled(this.service.customPricing)) { depositAvailable = depositAvailable || this.service.customPricing.durations.filter(i => i.price).length } if (this.isPersonPricingEnabled(this.service.customPricing)) { depositAvailable = depositAvailable || this.service.customPricing.persons.filter(i => i.price).length } if (this.isPeriodPricingEnabled(this.service.customPricing)) { depositAvailable = depositAvailable || this.service.customPricing.periods.default.filter(i => i.ranges.filter(j => j.price > 0).length).length || this.service.customPricing.periods.custom.filter(i => i.ranges.filter(j => j.price > 0).length).length } return depositAvailable }, depositEnabledChanged () { if (this.depositEnabled) { this.service.depositPayment = this.depositPayment } else { this.service.depositPayment = 'disabled' } }, getMaxPrice () { let maxPrice = this.service.price if (this.isDurationPricingEnabled(this.service.customPricing)) { this.service.customPricing.durations.forEach((item) => { if (item.price > maxPrice) { maxPrice = item.price } }) } if (this.isPersonPricingEnabled(this.service.customPricing)) { this.service.customPricing.persons.forEach((item) => { if (item.price > maxPrice) { maxPrice = item.price } }) } return maxPrice }, depositChanged () { let maxPrice = this.getMaxPrice() if (this.service.deposit > maxPrice && this.depositPayment === 'fixed') { this.service.deposit = maxPrice } }, priceChanged () { let maxPrice = this.getMaxPrice() if (this.service.deposit > maxPrice && this.depositPayment === 'fixed') { this.service.deposit = maxPrice } if (this.service.customPricing.persons.length) { this.service.customPricing.persons[0].price = this.service.price } }, isDurationSelected (duration) { return this.isDurationPricingEnabled(this.service.customPricing) && this.service.customPricing.durations.map(i => i.duration).includes(duration) }, instantiateDialog () { if (this.passedService !== null && this.executeUpdate === true) { this.service = JSON.parse(JSON.stringify(this.passedService)) this.maxExtraPeopleEnabled = this.service.maxExtraPeople !== null if (this.service.description && this.service.description.startsWith('<!-- Content -->')) { this.service.descriptionHtml = this.service.description } if (this.service.depositPayment === 'disabled') { this.depositEnabled = false } else { this.depositEnabled = true this.depositPayment = this.service.depositPayment } // If service is duplicated use duplicated service employees if (this.service.duplicated !== true) { this.$set(this.service, 'providers', this.selectedVisibleEmployees) } if (this.service.limitPerCustomer === null) { this.service.limitPerCustomer = {enabled: this.$root.settings.roles.limitPerCustomerService.enabled, numberOfApp: null, period: null, timeFrame: null, from: null} } else if (this.service.id !== 0) { this.service.limitPerCustomer = JSON.parse(this.service.limitPerCustomer) } // Set extra duration to empty string if duration is null, because of element-ui select clearable button for (let i = 0; i < this.service.extras.length; i++) { if (this.service.extras[i].duration === null) { this.service.extras[i].duration = '' } } if (this.service.id in this.futureAppointments) { this.appointmentsEmployees = this.futureAppointments[this.service.id] } this.service.extras.sort((a, b) => (a.position > b.position) ? 1 : -1) if (this.employees.length === 1) { this.service.providers = [this.employees[0]] } if (!this.service.recurringCycle) { this.service.recurringCycle = 'disabled' } this.durationPricingEnabled = this.isDurationPricingEnabled(this.service.customPricing) this.personPricingEnabled = this.isPersonPricingEnabled(this.service.customPricing) this.periodPricingEnabled = this.isPeriodPricingEnabled(this.service.customPricing) this.dialogLoading = false this.executeUpdate = false } }, validationFailCallback () { if (this.service.providers.length === 0) { this.serviceTabs = 'service_details' this.scrollViewInModal('providersElement') } }, galleryUpdated (gallery) { this.service.gallery = gallery }, closeDialog () { this.$emit('closeDialog') }, getParsedEntity (applyGlobally) { if (typeof this.$refs.extra !== 'undefined') { for (let i = 0; i < this.$refs.extra.length; i++) { this.$refs.extra[i].validate((valid) => { if (valid) { this.$refs.extra[i].clearValidate() return true } else { this.serviceTabs = 'extras' return false } }) } } let serviceSettings = this.prepareBookableEntityPaymentsForSave(this.prepareServiceSettingsForSave(this.service)) this.service.providers = this.service.providers.map(employee => employee.id) this.service.applyGlobally = applyGlobally if (!this.depositEnabled) { this.service.depositPayment = 'disabled' } else { this.service.depositPayment = this.depositPayment } if (!this.service.aggregatedPrice) { this.service.depositPerPerson = 0 } if (!this.maxExtraPeopleEnabled || this.service.maxCapacity <= 1) { this.service.maxExtraPeople = null } return Object.assign( JSON.parse(JSON.stringify(this.service)), { settings: serviceSettings ? JSON.stringify(serviceSettings) : null, customPricing: this.getJsonCustomPricing(this.service), limitPerCustomer: JSON.stringify(this.service.limitPerCustomer) } ) }, haveSaveConfirmation () { let customDurationChanged = false let customPersonsChanged = false let customPeriodsChanged = false this.service.customPricing.durations = this.service.customPricing.durations.filter(item => item.duration) this.service.customPricing.durations.forEach((serviceItem) => { this.passedService.customPricing.durations.forEach((passedServiceItem) => { if (serviceItem.duration === passedServiceItem.duration && serviceItem.price !== passedServiceItem.price) { customDurationChanged = true } }) }) this.service.customPricing.persons.forEach((serviceItem) => { this.passedService.customPricing.persons.forEach((passedServiceItem) => { if (serviceItem.range === passedServiceItem.range && serviceItem.price !== passedServiceItem.price) { customPersonsChanged = true } }) }) this.service.customPricing.periods.default.forEach((dayData, indexService) => { dayData.ranges.forEach((serviceRange) => { this.passedService.customPricing.periods.default.forEach((passedServiceItem, indexProvider) => { if (indexService === indexProvider) { passedServiceItem.ranges.forEach((passedRange) => { if (serviceRange.from === passedRange.from && serviceRange.to === passedRange.to && serviceRange.price !== passedRange.price ) { customPeriodsChanged = true } }) } }) }) }) this.service.customPricing.periods.custom.forEach((dayData) => { dayData.ranges.forEach((serviceRange) => { this.passedService.customPricing.periods.custom.forEach((passedServiceItem) => { if (dayData.dates.start === passedServiceItem.dates.start && dayData.dates.end === passedServiceItem.dates.end ) { passedServiceItem.ranges.forEach((passedRange) => { if (serviceRange.from === passedRange.from && serviceRange.to === passedRange.to && serviceRange.price !== passedRange.price ) { customPeriodsChanged = true } }) } }) }) }) return this.service.id && ( this.passedService.price !== this.service.price || this.passedService.minCapacity !== this.service.minCapacity || this.passedService.maxCapacity !== this.service.maxCapacity || customDurationChanged || customPersonsChanged || customPeriodsChanged ) }, bgColor (color) { return {'background-color': color} }, servicePictureSelected (pictureFullPath, pictureThumbPath) { this.service.pictureFullPath = pictureFullPath this.service.pictureThumbPath = pictureThumbPath }, galleryPictureSelected (pictureFullPath, pictureThumbPath) { this.clearValidation() this.service.gallery.push({ id: 0, pictureFullPath: pictureFullPath, pictureThumbPath: pictureThumbPath, position: this.service.gallery.length + 1 }) }, deleteGalleryImage (index) { this.service.gallery.splice(index, 1) for (let i = 0; i < this.service.gallery.length; i++) { this.service.gallery[i].position = i + 1 } }, dropGalleryImage (e) { if (e.newIndex !== e.oldIndex) { let that = this this.service.gallery.forEach((image) => { image.position = that.service.gallery.indexOf(image) + 1 }) } }, changeServiceColor (e) { let siblings = Array.from(e.target.parentNode.children) siblings.forEach(function (sib) { if (sib.className.includes('color-active')) { sib.classList.remove('color-active') } }) e.target.className = e.target.className + ' color-active' this.service.color = e.target.getAttribute('data-color') }, checkCapacityLimits () { this.clearValidation() if (this.service.minCapacity > this.service.maxCapacity) { this.service.maxCapacity = this.service.minCapacity } if (this.maxExtraPeopleEnabled && this.service.maxExtraPeople < this.service.minCapacity - 1) { this.service.maxExtraPeople = this.service.minCapacity - 1 } }, showEditExtraDialog (extra) { if (extra.aggregatedPrice === null) { extra.aggregatedPrice = this.service.aggregatedPrice } this.handleExtraForm() this.editedExtra = extra this.editedExtraOld = Object.assign({}, extra) this.extraToDelete = null this.extraEditDialog = true }, cancelExtra (extra) { if (this.editedExtraOld !== null) { extra.name = this.editedExtraOld.name extra.duration = this.editedExtraOld.duration extra.price = this.editedExtraOld.price extra.maxQuantity = this.editedExtraOld.maxQuantity extra.description = this.editedExtraOld.description } this.editedExtra = null this.editedExtraOld = null this.extraEditDialog = false // Remove newly created extra if it is not saved if (typeof extra.id === 'undefined' && extra.isNew === true) { this.service.extras.splice(-1, 1) } }, addExtra () { this.handleExtraForm() this.extraEditDialog = true this.editedExtra = { name: '', duration: '', price: '', maxQuantity: 1, description: '', serviceId: this.service.id, position: this.service.extras.length + 1, isNew: true } this.service.extras.push(this.editedExtra) this.scrollViewInModal('extra' + (this.service.extras.length - 1)) }, saveExtra (extra) { let index = this.service.extras.indexOf(extra) if (this.passedService.extras[index]) { this.service.extras[index].translations = this.passedService.extras[index].translations } else { this.service.extras[index].translations = this.newExtraTranslations } this.$refs.extra[index].validate((valid) => { if (valid) { this.editedExtra = null this.editedExtraOld = null this.extraEditDialog = false this.$refs.extra[index].clearValidate() } else { return false } }) this.service.extras[index].isNew = false this.$emit('extraSaved', this.service.extras[index], index) }, showDeleteExtraDialog (extra) { this.handleExtraForm() this.extraToDelete = extra this.editedExtra = null this.extraEditDialog = false }, handleExtraForm () { // If new extra form is active, remove this extra if (this.editedExtra !== null && typeof this.editedExtra.id === 'undefined') { this.service.extras.splice(-1, 1) } // If edit extra form is active, revert extra to old state if (this.editedExtraOld !== null) { this.cancelExtra(this.editedExtra) } }, hideDeleteExtraDialog () { this.extraToDelete = null this.extraEditDialog = true }, deleteExtra (extra) { if (typeof extra.id === 'undefined') { let index = this.service.extras.indexOf(extra) this.service.extras.splice(index, 1) } else { this.extraToDeleteLoading = true this.$http.post(`${this.$root.getAjaxUrl}/extras/delete/` + extra.id) .then(() => { let index = this.service.extras.indexOf(extra) this.service.extras.splice(index, 1) this.passedService.extras.splice(index, 1) if (this.passedService.minSelectedExtras > this.passedService.extras.length) { this.passedService.minSelectedExtras = this.passedService.extras.length } if (this.service.minSelectedExtras > this.service.extras.length) { this.service.minSelectedExtras = this.service.extras.length } if (this.service.minSelectedExtras === 0 || this.passedService.minSelectedExtras === 0) { this.service.mandatoryExtra = false this.passedService.mandatoryExtra = false } this.extraToDeleteLoading = false }) .catch(() => { this.extraToDeleteLoading = false this.notify(this.$root.labels.error, this.$root.labels.extra_delete_fail, 'error') }) } for (let i = 0; i < this.service.extras.length; i++) { this.service.extras[i].position = i + 1 } }, dropExtra (e) { if (e.newIndex !== e.oldIndex) { let that = this this.service.extras.forEach((extra) => { extra.position = that.service.extras.indexOf(extra) + 1 }) } }, clearValidation () { if (typeof this.$refs.service !== 'undefined') { this.$refs.service.clearValidate() } }, changeEmployees () { let selectedEmployees = this.service.providers.map(employee => employee.id) let intersection = this.appointmentsEmployees.filter(x => !selectedEmployees.includes(x)) if (intersection.length) { let $this = this let unselectedEmployees = [] intersection.forEach(function (employeeId) { unselectedEmployees.push($this.visibleEmployees.filter(employee => employee.id === employeeId)[0]) $this.notify($this.$root.labels.error, $this.$root.labels.service_provider_remove_fail, 'error') }) this.service.providers = this.service.providers.concat(unselectedEmployees).sort(function (a, b) { return (a.firstName + ' ' + a.lastName).localeCompare((b.firstName + ' ' + b.lastName)) }) } }, showDialogTranslate (dialogType, extraIndex = 0) { switch (dialogType) { case 'serviceName': this.$emit('showDialogTranslate', 'name', 'service') break case 'serviceDescription': this.$emit('showDialogTranslate', 'description', 'service') break case 'extraName': this.$emit('showDialogTranslate', 'name', 'extra', extraIndex) break case 'extraDescription': this.$emit('showDialogTranslate', 'description', 'extra', extraIndex) break } }, validationTabFailCallback () { this.serviceTabs = 'pricing' } }, computed: { visibleCategories () { return this.categories.filter(category => category.status === 'visible') }, visibleEmployees () { return this.employees.filter(employee => (employee.status === 'visible') || (employee.status === 'hidden' && employee.serviceList.map(service => service.id).indexOf(this.service.id) !== -1) ) }, selectedVisibleEmployees () { return this.employees.filter(employee => employee.serviceList.map(service => service.id).indexOf(this.service.id) !== -1 ) } }, watch: { 'service.price' () { this.clearValidation() }, 'passedService.translations' () { if (this.service) { this.service.translations = this.passedService.translations } } }, components: { DialogTranslate, PictureUpload, Draggable, Money, EntitySettings, ContentBlock, DialogActions, CustomDuration, PersonPrice, PeriodPrice } } </script>
Save
Back