add: observer input & tooltips
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
import { useCompanyStore } from '../stores/company';
|
||||
import Swal from 'sweetalert2';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { validateEmail } from '../helpers/validations';
|
||||
|
||||
const props = defineProps({
|
||||
location: {
|
||||
@@ -27,6 +28,8 @@
|
||||
const { t } = useI18n()
|
||||
|
||||
const loading = ref(false);
|
||||
const emails = ref([]);
|
||||
const emailInput = ref('');
|
||||
|
||||
const title = computed(() => {
|
||||
return (props.location) ? t('directory.editLocation') : t('directory.createLocation');
|
||||
@@ -139,6 +142,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
const addObserver = () => {
|
||||
const trimmedEmail = emailInput.value.trim()
|
||||
|
||||
if (trimmedEmail && validateEmail(trimmedEmail)) {
|
||||
if(emails.value.includes(trimmedEmail)) {
|
||||
Swal.fire({
|
||||
title: t('errors.emailExist'),
|
||||
icon: 'error'
|
||||
})
|
||||
return
|
||||
}
|
||||
emails.value.push(trimmedEmail)
|
||||
emailInput.value = ''
|
||||
} else if (trimmedEmail) {
|
||||
Swal.fire({
|
||||
title: t('errors.email'),
|
||||
icon: 'error'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const removeObserver = (email) => {
|
||||
emails.value = emails.value.filter((e) => e !== email)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const validations = () => {
|
||||
errors.value = {
|
||||
branch_name: locationForm.branch_name.length < 2 ? t('errors.nameRequired') : null,
|
||||
@@ -251,6 +281,42 @@
|
||||
v-model="locationForm.description"
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="divider mt-4"></div>
|
||||
<div class="box-observers mt-4">
|
||||
<div class="box-input">
|
||||
<div class="input-observer">
|
||||
<CustomInput
|
||||
label="Agregar observador de bodega"
|
||||
name="email"
|
||||
type="email"
|
||||
v-model:field="emailInput"
|
||||
:filled="false"
|
||||
:tooltip="t('messages.observerWarehouse')"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
@click="addObserver"
|
||||
class="btn btn-dark"
|
||||
>
|
||||
Agregar
|
||||
</button>
|
||||
</div>
|
||||
<h5 v-if="emails.length > 0">Lista de observadores:</h5>
|
||||
<div class="box-emails" v-if="emails.length > 0">
|
||||
<div
|
||||
v-for="(email, index) in emails"
|
||||
:key="email"
|
||||
class="observer-email"
|
||||
>
|
||||
<span>{{ email }}</span>
|
||||
<i
|
||||
@click="removeObserver(email)"
|
||||
class="fa-solid fa-xmark icon-delete">
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 text-center">
|
||||
<Spiner v-if="loading"/>
|
||||
<button
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { computed } from 'vue';
|
||||
import {getDateTime } from '../helpers/date_formats';
|
||||
import { validateEmail } from '../helpers/validations';
|
||||
|
||||
|
||||
const loadStore = useLoadsStore();
|
||||
@@ -43,6 +44,8 @@
|
||||
const locationDownloadSelected = ref(null)
|
||||
const originRef = ref('')
|
||||
const destinationRef = ref('')
|
||||
const emails = ref([]);
|
||||
const emailInput = ref('');
|
||||
|
||||
const errors = ref({
|
||||
segment: null,
|
||||
@@ -362,6 +365,31 @@
|
||||
? t('loads.create')
|
||||
: t('loads.edit')
|
||||
)
|
||||
|
||||
const addObserver = () => {
|
||||
const trimmedEmail = emailInput.value.trim()
|
||||
|
||||
if (trimmedEmail && validateEmail(trimmedEmail)) {
|
||||
if(emails.value.includes(trimmedEmail)) {
|
||||
Swal.fire({
|
||||
title: t('errors.emailExist'),
|
||||
icon: 'error'
|
||||
})
|
||||
return
|
||||
}
|
||||
emails.value.push(trimmedEmail)
|
||||
emailInput.value = ''
|
||||
} else if (trimmedEmail) {
|
||||
Swal.fire({
|
||||
title: t('errors.email'),
|
||||
icon: 'error'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const removeObserver = (email) => {
|
||||
emails.value = emails.value.filter((e) => e !== email)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -425,14 +453,14 @@
|
||||
:error="(submited && !formLoad.weight) ? t('errors.weight') : null"
|
||||
v-model:field="formLoad.weight"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-section">
|
||||
<div class="mb-4 mt-3">
|
||||
<label class="custom-label">{{ t('loads.product') }}</label>
|
||||
<Products
|
||||
v-model="formLoad.terms"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-section">
|
||||
<Custominput
|
||||
:label="t('loads.labelPrice')"
|
||||
type="Number"
|
||||
@@ -455,6 +483,41 @@
|
||||
name="owner"
|
||||
v-model:field="formLoad.owner"
|
||||
/>
|
||||
<div class="box-observers mt-4">
|
||||
<div class="box-input">
|
||||
<div class="input-observer">
|
||||
<Custominput
|
||||
label="Agregar cliente observador"
|
||||
name="email"
|
||||
type="email"
|
||||
v-model:field="emailInput"
|
||||
:filled="false"
|
||||
:tooltip="t('messages.observerClient')"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
@click="addObserver"
|
||||
class="btn btn-dark"
|
||||
>
|
||||
Agregar
|
||||
</button>
|
||||
</div>
|
||||
<h5 v-if="emails.length > 0">Lista de observadores:</h5>
|
||||
<div class="box-emails" v-if="emails.length > 0">
|
||||
<div
|
||||
v-for="(email, index) in emails"
|
||||
:key="email"
|
||||
class="observer-email"
|
||||
>
|
||||
<span>{{ email }}</span>
|
||||
<i
|
||||
@click="removeObserver(email)"
|
||||
class="fa-solid fa-xmark icon-delete">
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-box">
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
step: {
|
||||
type: Number,
|
||||
default: 0.1
|
||||
},
|
||||
tooltip: {
|
||||
type: String,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -48,11 +51,24 @@
|
||||
|
||||
<template>
|
||||
<div class="d-flex flex-column gap-2 mb-4">
|
||||
<label
|
||||
<!-- <label
|
||||
class="custom-label"
|
||||
:class="[label.includes('*') ? 'required' : '']"
|
||||
:for="name"
|
||||
>{{ label }}</label>
|
||||
>{{ label }}</label> -->
|
||||
<div class="label-box">
|
||||
<label
|
||||
class="custom-label label-text"
|
||||
:class="[label.includes('*') ? 'required' : '']"
|
||||
:for="name"
|
||||
>{{ label }}</label>
|
||||
<div class="help-icon" v-if="tooltip">
|
||||
❓
|
||||
<div class="tooltip">
|
||||
{{ tooltip }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
class="custom-input"
|
||||
:class="[
|
||||
@@ -86,4 +102,50 @@
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.label-box {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.label-text {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Estilo del ícono de ayuda */
|
||||
.help-icon {
|
||||
position: relative;
|
||||
font-size: 20px;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Tooltip oculto inicialmente */
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
width: 180px;
|
||||
padding: 8px;
|
||||
background: #333;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
border-radius: 5px;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transform: translateX(-50%);
|
||||
margin-top: 8px;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
/* Mostrar tooltip al pasar el mouse */
|
||||
.help-icon:hover .tooltip,
|
||||
.help-icon:active .tooltip {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user