iachat/app/javascript/dashboard/routes/dashboard/settings/sla/SlaForm.vue
Sivin Varghese 84c380c8c4
feat: Replace SLA validationMixin within the component (#9804)
# Pull Request Template

## Description

This PR will completely remove the SLA `validationMixin` and be used in
the component as it is with a name change.

Fixes
https://linear.app/chatwoot/issue/CW-3456/rewrite-sla-validationmixin-mixin-to-a-composable

## Type of change

- [x] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

Take a look at these components
1. `dashboard/routes/dashboard/settings/sla/AddSLA.vue` **(Not used)**
2. `dashboard/routes/dashboard/settings/sla/SlaForm.vue`
3. `dashboard/routes/dashboard/settings/sla/SlaTimeInput.vue`


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
2024-07-22 13:05:55 +05:30

219 lines
6.2 KiB
Vue

<template>
<div class="flex flex-col h-auto overflow-auto">
<form class="flex flex-wrap mx-0" @submit.prevent="onSubmit">
<woot-input
v-model="name"
:class="{ error: $v.name.$error }"
class="w-full"
:styles="{
borderRadius: '12px',
padding: '6px 12px',
fontSize: '14px',
}"
:label="$t('SLA.FORM.NAME.LABEL')"
:placeholder="$t('SLA.FORM.NAME.PLACEHOLDER')"
:error="slaNameErrorMessage"
@input="$v.name.$touch"
/>
<woot-input
v-model="description"
class="w-full"
:styles="{
borderRadius: '12px',
padding: '6px 12px',
fontSize: '14px',
}"
:label="$t('SLA.FORM.DESCRIPTION.LABEL')"
:placeholder="$t('SLA.FORM.DESCRIPTION.PLACEHOLDER')"
/>
<sla-time-input
v-for="(input, index) in slaTimeInputs"
:key="index"
:threshold="input.threshold"
:threshold-unit="input.unit"
:label="$t(input.label)"
:placeholder="$t(input.placeholder)"
@input="updateThreshold(index, $event)"
@unit="updateUnit(index, $event)"
@isInValid="handleIsInvalid(index, $event)"
/>
<div
class="mt-3 flex h-10 items-center text-sm w-full gap-2 border border-solid border-slate-200 dark:border-slate-600 px-3 py-1.5 rounded-xl justify-between"
>
<span for="sla_bh" class="text-slate-700 dark:text-slate-200">
{{ $t('SLA.FORM.BUSINESS_HOURS.PLACEHOLDER') }}
</span>
<woot-switch id="sla_bh" v-model="onlyDuringBusinessHours" />
</div>
<div class="flex items-center justify-end w-full gap-2 mt-8">
<woot-button
class="px-4 rounded-xl button clear outline-woot-200/50 outline"
@click.prevent="onClose"
>
{{ $t('SLA.FORM.CANCEL') }}
</woot-button>
<woot-button
:is-disabled="isSubmitDisabled"
class="px-4 rounded-xl"
:is-loading="uiFlags.isUpdating"
>
{{ submitLabel }}
</woot-button>
</div>
</form>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import { convertSecondsToTimeUnit } from '@chatwoot/utils';
import validations from './validations';
import SlaTimeInput from './SlaTimeInput.vue';
export default {
components: {
SlaTimeInput,
},
props: {
selectedResponse: {
type: Object,
default: () => {},
},
submitLabel: {
type: String,
required: true,
},
},
data() {
return {
name: '',
description: '',
isSlaTimeInputsInvalid: false,
slaTimeInputsValidation: {},
slaTimeInputs: [
{
threshold: null,
unit: 'Minutes',
label: 'SLA.FORM.FIRST_RESPONSE_TIME.LABEL',
placeholder: 'SLA.FORM.FIRST_RESPONSE_TIME.PLACEHOLDER',
},
{
threshold: null,
unit: 'Minutes',
label: 'SLA.FORM.NEXT_RESPONSE_TIME.LABEL',
placeholder: 'SLA.FORM.NEXT_RESPONSE_TIME.PLACEHOLDER',
},
{
threshold: null,
unit: 'Minutes',
label: 'SLA.FORM.RESOLUTION_TIME.LABEL',
placeholder: 'SLA.FORM.RESOLUTION_TIME.PLACEHOLDER',
},
],
onlyDuringBusinessHours: false,
};
},
validations,
computed: {
...mapGetters({
uiFlags: 'sla/getUIFlags',
}),
isSubmitDisabled() {
return (
this.$v.name.$invalid ||
this.isSlaTimeInputsInvalid ||
this.uiFlags.isUpdating
);
},
slaNameErrorMessage() {
let errorMessage = '';
if (this.$v.name.$error) {
if (!this.$v.name.required) {
errorMessage = this.$t('SLA.FORM.NAME.REQUIRED_ERROR');
} else if (!this.$v.name.minLength) {
errorMessage = this.$t('SLA.FORM.NAME.MINIMUM_LENGTH_ERROR');
}
}
return errorMessage;
},
},
mounted() {
if (this.selectedResponse) this.setFormValues();
},
methods: {
onClose() {
this.$emit('close');
},
setFormValues() {
const {
name,
description,
first_response_time_threshold: firstResponseTimeThreshold,
next_response_time_threshold: nextResponseTimeThreshold,
resolution_time_threshold: resolutionTimeThreshold,
only_during_business_hours: onlyDuringBusinessHours,
} = this.selectedResponse;
this.name = name;
this.description = description;
this.onlyDuringBusinessHours = onlyDuringBusinessHours;
const thresholds = [
firstResponseTimeThreshold,
nextResponseTimeThreshold,
resolutionTimeThreshold,
];
this.slaTimeInputs.forEach((input, index) => {
const converted = convertSecondsToTimeUnit(thresholds[index], {
minute: 'Minutes',
hour: 'Hours',
day: 'Days',
});
input.threshold = converted.time;
input.unit = converted.unit;
});
},
updateThreshold(index, value) {
this.slaTimeInputs[index].threshold = value;
},
updateUnit(index, unit) {
this.slaTimeInputs[index].unit = unit;
},
onSubmit() {
const payload = {
name: this.name,
description: this.description,
first_response_time_threshold: this.convertToSeconds(0),
next_response_time_threshold: this.convertToSeconds(1),
resolution_time_threshold: this.convertToSeconds(2),
only_during_business_hours: this.onlyDuringBusinessHours,
};
this.$emit('submit', payload);
},
convertToSeconds(index) {
const { threshold, unit } = this.slaTimeInputs[index];
if (threshold === null || threshold === 0) return null;
const unitsToSeconds = { Minutes: 60, Hours: 3600, Days: 86400 };
return Number(threshold * (unitsToSeconds[unit] || 1));
},
handleIsInvalid(index, isInvalid) {
this.slaTimeInputsValidation = {
...this.slaTimeInputsValidation,
[index]: isInvalid,
};
this.checkValidationState();
},
checkValidationState() {
const isAnyInvalid = Object.values(this.slaTimeInputsValidation).some(
isInvalid => isInvalid
);
this.isSlaTimeInputsInvalid = isAnyInvalid;
},
},
};
</script>