resolve merge conflics

This commit is contained in:
Alexandro Uc Santos
2025-04-12 16:53:19 -06:00
32 changed files with 785 additions and 132 deletions

59
package-lock.json generated
View File

@@ -731,11 +731,11 @@
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dependencies": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -789,15 +789,9 @@
}
},
"node_modules/chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
"funding": [
{
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
],
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -810,6 +804,9 @@
"engines": {
"node": ">= 8.10.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
@@ -997,9 +994,9 @@
"integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -1272,9 +1269,9 @@
"dev": true
},
"node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
"funding": [
{
"type": "github",
@@ -1326,9 +1323,9 @@
"optional": true
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
},
"node_modules/picomatch": {
"version": "2.3.1",
@@ -1401,9 +1398,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
"integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
"funding": [
{
"type": "opencollective",
@@ -1419,9 +1416,9 @@
}
],
"dependencies": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
"nanoid": "^3.3.8",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
@@ -1554,9 +1551,9 @@
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"engines": {
"node": ">=0.10.0"
}

View File

@@ -3,6 +3,11 @@ body {
padding: 0px;
}
.flex-d-column {
display: flex;
flex-direction: column;
}
.w-lg-45{
width: 45%;
}
@@ -47,6 +52,10 @@ body {
cursor: pointer;
}
.pointer {
cursor: pointer
}
.btn-lg-block{
width: 100%;
}
@@ -183,6 +192,16 @@ td {
font-size: 1rem;
}
.custom-input-fill {
background-color: white;
border-radius: 8px;
border-width: 1px !important;
border-color: rgb(226, 214, 214) !important;
border-style: solid !important;
padding: 12px 12px;
font-size: 1rem;
}
.custom-input:enabled{
border: none;
}
@@ -202,6 +221,16 @@ td {
gap: 1rem;
}
.required {
/* color: #FBBA33; */
color: black;
}
.border-required {
border-radius: 5px;
border: 1px solid #FBBA33 !important;
}
@media (max-width: 1024px) {
th {
font-size: 13px;

View File

@@ -90,6 +90,11 @@
loadsStore.openProposalsModal = true;
}
const openCarrierInfoModal = () => {
loadsStore.currentLoad = props.load
loadsStore.openCarrierInfoModal = true;
}
const handleTracking = () => {
let code = props.load._id;
window.open('/publico/tracking/' + code, '_blank');
@@ -142,7 +147,18 @@
{{ load.company?.company_name }}
</p>
<div v-if="!readOnly">
<p><span>{{t('loads.postStatus')}}:</span> <span class="simple">{{ getStatusPublished(load) }}</span></p>
<p>
<span>{{t('loads.postStatus')}}: </span>
<span class="simple"> {{ getStatusPublished(load) }}</span>
<i
v-if="load.status !== 'Draft' && load.status !== 'Published'"
class="fa-solid fa-truck me-1 ms-1 pointer"
data-toggle="modal"
data-target="#carrierInfoModal"
@click="openCarrierInfoModal()"
style="color: green; font-size: 20px;"
></i>
</p>
<p :style="{color: getStatusLoad(load).color}"><span>{{t('loads.loadStatus')}}:</span> <span class="simple">{{ getStatusLoad(load).status }}</span></p>
</div>
</div>

View File

@@ -0,0 +1,109 @@
<script setup>
import { getDateMonthDay } from '../helpers/date_formats';
import { useLoadsStore } from '../stores/loads';
import VehicleInfo from './VehicleInfo.vue';
import { useI18n } from 'vue-i18n';
const props = defineProps({
load: {
type: Object,
required: true
}
});
const { t } = useI18n();
const loadsStore = useLoadsStore();
const clearModal = () => {
loadsStore.currentLoad = null;
loadsStore.openCarrierInfoModal = false;
}
</script>
<template>
<div class="modal fade" id="carrierInfoModal" tabindex="-1" role="dialog" aria-labelledby="editcompany" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h2 class="title mt-2 mb-3">Información del transportista</h2>
<button
id="btnCloseCarrierInfoModal"
type="button"
@click="clearModal()"
class="close bg-white" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body view-proposals">
<div>
<div class="row">
<div class="col-lg-6 col-md-12">
<p>{{ t('global.company') }}: <span>{{ load?.carrier?.company_name }}</span></p>
<p>{{ t('proposals.bidder') }}: <span>{{ load?.bidder?.first_name }} {{ load?.bidder?.last_name }}</span></p>
<p>{{ t('proposals.numCarrier') }}: <span>{{load?.carrier?.company_code}}</span></p>
</div>
<div class="col-lg-6 col-md-12">
<p>{{ t('labels.date') }}: <span>{{ getDateMonthDay(load?.carrier?.createdAt) }}</span></p>
<p>RFC: <span v-if="load.vehicle">{{load?.carrier?.rfc}}</span></p>
</div>
</div>
<VehicleInfo
v-if="load.vehicle"
:vehicle="load.vehicle"
:driver="load.driver"
/>
</div>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-dark"
@click="clearModal()"
data-dismiss="modal">{{ t('buttons.close') }}</button>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.view-proposals {
width: 100%;
}
.card-proposal {
flex-direction: column;
width: 100% !important;
}
p {
font-size: 1rem;
font-weight: 400;
color: #323032;
font-weight: 700;
}
p span {
color: #323032;
font-weight: normal;
}
.indicator-check {
width: 120px;
padding: 10px 12px;
background: #FFF;
border: 1px solid green;
border-radius: 50px;
color: green;
}
.box-note {
padding: 12px 16px;
background-color: aqua;
border-radius: 13px;
}
</style>

View File

@@ -182,21 +182,21 @@
:error="errors.address"
/>
<div class="mb-4 mt-3">
<label class="custom-label">{{ t('directory.state')}}*</label>
<label class="custom-label required">{{ t('directory.state')}}*</label>
<States
v-model="locationForm.state"
/>
<span class="error-msg" v-if="errors.state">{{ errors.state }}</span>
</div>
<div class="mb-4 mt-3">
<label class="custom-label">{{ t('directory.city')}}*</label>
<label class="custom-label required">{{ t('directory.city')}}*</label>
<Cities
v-model="locationForm.city"
/>
<span class="error-msg" v-if="errors.city">{{ errors.city }}</span>
</div>
<div class="d-flex flex-column mb-4">
<label class="custom-label" for="role">{{ t('directory.typeDirectory') + '*'}}</label>
<label class="custom-label required" for="role">{{ t('directory.typeDirectory') + '*'}}</label>
<select
class="custom-input-light"
name="type"

View File

@@ -20,14 +20,16 @@
});
const { t } = useI18n();
onMounted(() => {
const authStore = useAuthStore();
const companyStore = useCompanyStore();
onMounted(async() => {
if(props.user) {
console.log(props.user)
userForm.job_role = props.user.job_role;
userForm.name = props.user.first_name;
userForm.last_name = props.user.last_name;
userForm.email = props.user.email;
userForm.phone = props.user.phone;
userForm.job_role = props.user.job_role;
userForm.categories = props.user.categories;
userForm.user_city = props.user.user_city?.map(m =>{
return { city_name: m };
@@ -39,14 +41,15 @@
return { meta_value:m };
});
userForm.user_description = props.user.user_description;
if(props.user.job_role === 'warehouse') {
await loadWarehouses();
userForm.warehouse = warehouses.value.find(w => w._id === props.user.branch?._id);
}
} else {
Object.assign(userForm, initState);
}
})
const authStore = useAuthStore();
const companyStore = useCompanyStore();
const initState = {
name: '',
last_name: '',
@@ -59,6 +62,7 @@
user_state: [],
truck_type: [],
user_description: '',
warehouse: null
};
const userForm = reactive({
@@ -70,10 +74,14 @@
last_name: null,
email: null,
phone: null,
job_role: null,
warehouse: null
})
const formRef = ref(null);
const loading = ref(false);
const loadingWarehouses = ref(false);
const warehouses = ref([]);
const title = computed(() => {
return (props.user) ? t('labels.editUser') : t('labels.createUser');
@@ -83,7 +91,7 @@
const saveUser = async() => {
validations()
if(errors.value.name || errors.value.last_name || errors.value.email || errors.value.phone){
if(errors.value.name || errors.value.last_name || errors.value.email || errors.value.phone || errors.value.job_role || errors.value.warehouse) {
return;
} else {
let userData ={
@@ -98,13 +106,14 @@
user_city: userForm.user_city?.length <= 0 ? null : userForm.user_city?.map((e) => e.city_name),
user_state: userForm.user_state?.length <= 0 ? null : userForm.user_state?.map((e) => e.state_name),
truck_type: userForm.truck_type?.length <= 0 ? null : userForm.truck_type?.map((e) => e.meta_value),
user_description: userForm.user_description
user_description: userForm.user_description,
branch: userForm.warehouse?._id
}
const dataUpdate = {
categories: userForm.categories,
name: userForm.name + ' ' + userForm.last_name
name: userForm.name + ' ' + userForm.last_name,
branch: userForm.warehouse
}
let result = 'error';
@@ -141,8 +150,26 @@
last_name: userForm.last_name.length <= 1 ? t('errors.lastname') : null,
email: !validateEmail(userForm.email) ? t('errors.email') : null,
phone: userForm.phone.length < 10 ? t('errors.phone') : null,
job_role: userForm.job_role === '' ? t('errors.required') : null,
warehouse: (userForm.job_role == 'warehouse' && userForm.warehouse === null)
? t('errors.required')
: null
};
}
const handleRoleChange = async () => {
if (userForm.job_role === "warehouse") {
await loadWarehouses();
}
}
const loadWarehouses = async () => {
loadingWarehouses.value = true;
warehouses.value = await companyStore.getLocationsLoads('loading');
loadingWarehouses.value = false;
}
</script>
<template>
@@ -194,48 +221,81 @@
:filled="false"
:error="errors.email"
/>
<div class="d-flex flex-column">
<label class="custom-label" for="role">{{ t('labels.userRole') }}</label>
<div
v-if="userForm.job_role !== 'owner'"
class="d-flex flex-column"
>
<label class="custom-label required" for="role">{{ t('labels.userRole') }}*</label>
<select
class="custom-input-light"
name="role"
id="role"
v-model="userForm.job_role"
@change="handleRoleChange"
>
<option disabled value="">-- {{ t('labels.selectedRol') }} --</option>
<!-- <option value="owner">Dueño</option> -->
<option value="manager">{{ t('labels.manager') }}</option>
<option value="staff">{{ t('labels.staff') }}</option>
<option v-if="authStore.user?.permissions === 'role_carrier'" value="driver">{{ t('labels.driver') }}</option>
<option
v-if="authStore.user?.permissions === 'role_shipper'"
value="warehouse"
>
{{ t('labels.warehouse') }}
</option>
<option
v-if="authStore.user?.permissions === 'role_carrier'"
value="driver"
>
{{ t('labels.driver') }}
</option>
</select>
<span class="error-msg" v-if="errors.job_role">{{ errors.job_role }}</span>
</div>
<div class="mb-4 mt-3">
<label class="custom-label">{{ t('global.segments') }}</label>
<Segments
v-model="userForm.categories"
:multiple="true"
/>
<div v-if="userForm.job_role === 'warehouse'">
<Spiner v-if="loadingWarehouses"/>
<div class="d-flex flex-column my-4" v-if="!loadingWarehouses">
<label class="custom-label required" for="locationLoad">{{ t('labels.warehouses') }}*</label>
<select
class="custom-input-light"
name="locationLoad"
id="locationLoad"
v-model="userForm.warehouse"
>
<option disabled value="null">-- {{ t('labels.warehouseSelect') }} --</option>
<option v-for="loc in warehouses" :value="loc">{{ loc.branch_name }}</option>
</select>
<span class="error-msg" v-if="errors.warehouse">{{ errors.warehouse }}</span>
</div>
</div>
<div class="mb-4 mt-3">
<label class="custom-label">{{ t('directory.typeTruck') }}</label>
<TruckTypes
v-model="userForm.truck_type"
:multiple="true"
/>
</div>
<div class="mb-4 mt-3">
<label class="custom-label">{{ t('labels.locationLoadState') }}</label>
<States
v-model="userForm.user_state"
:multiple="true"
/>
</div>
<div class="mb-4 mt-3">
<label class="custom-label">{{ t('labels.locationLoadCity') }}</label>
<Cities
v-model="userForm.user_city"
:multiple="true"
/>
<div v-else>
<div class="mb-4 mt-3">
<label class="custom-label">{{ t('global.segments') }}</label>
<Segments
v-model="userForm.categories"
:multiple="true"
/>
</div>
<div class="mb-4 mt-3">
<label class="custom-label">{{ t('directory.typeTruck') }}</label>
<TruckTypes
v-model="userForm.truck_type"
:multiple="true"
/>
</div>
<div class="mb-4 mt-3">
<label class="custom-label">{{ t('labels.locationLoadState') }}</label>
<States
v-model="userForm.user_state"
:multiple="true"
/>
</div>
<div class="mb-4 mt-3">
<label class="custom-label">{{ t('labels.locationLoadCity') }}</label>
<Cities
v-model="userForm.user_city"
:multiple="true"
/>
</div>
</div>
<div class="d-flex flex-column">
<label class="custom-label" for="description">{{ t('labels.userInfo') }}</label>

View File

@@ -163,14 +163,14 @@
<form @submit.prevent="handleSaveVehicle" autocomplete="off" class="vehicle-form">
<div class="row">
<div class="col-lg-6 col-12 mt-4">
<label class="custom-label">{{ t('directory.typeTruck') }}*</label>
<label class="custom-label required">{{ t('directory.typeTruck') }}*</label>
<TruckTypes
v-model="vehicleForm.truck_type"
/>
<span class="error-msg" v-if="errors.truck_type">{{ errors.truck_type }}</span>
</div>
<div class="col-lg-6 col-12 mt-4">
<label class="custom-label">{{ t('vehicles.segments') }}*</label>
<label class="custom-label required">{{ t('vehicles.segments') }}*</label>
<Segments
v-model="vehicleForm.categories"
:multiple="true"
@@ -217,14 +217,14 @@
</div>
<div class="row">
<div class="col-lg-6 col-12 mb-4">
<label class="custom-label">{{ t('labels.stateBase') }}*</label>
<label class="custom-label required">{{ t('labels.stateBase') }}*</label>
<States
v-model="vehicleForm.state"
/>
<span class="error-msg" v-if="errors.state">{{ errors.state }}</span>
</div>
<div class="col-lg-6 col-12 mb-4">
<label class="custom-label">{{ t('labels.cityBase') }}*</label>
<label class="custom-label required">{{ t('labels.cityBase') }}*</label>
<Cities
v-model="vehicleForm.city"
/>
@@ -233,14 +233,14 @@
</div>
<div class="row">
<div class="col-lg-6 col-12 mb-4">
<label class="custom-label">{{t('vehicles.destinationState')}}*</label>
<label class="custom-label required">{{t('vehicles.destinationState')}}*</label>
<States
v-model="vehicleForm.destinoState"
/>
<span class="error-msg" v-if="errors.destinoState">{{ errors.destinoState }}</span>
</div>
<div class="col-lg-6 col-12 mb-4">
<label class="custom-label">{{t('vehicles.destinationCity')}}*</label>
<label class="custom-label required">{{t('vehicles.destinationCity')}}*</label>
<Cities
v-model="vehicleForm.destinoCity"
/>

View File

@@ -75,16 +75,11 @@
onMounted(() => {
window.addEventListener('resize', handleResize);
// mapRef.value = this.$refs.myMap;
if(window.innerWidth <= 1024) {
zoom.value = 4;
heightMap.value = 420;
}
// if(companyStore.locationsLoads.length <= 0) {
// getLocations();
// }
formLoad.owner = auth.user?.first_name + ' ' + auth.user?.last_name;
//origin_formatted_address
if(loadStore.currentLoad){
const dateStart = getDateTime(loadStore.currentLoad.est_loading_date, 0);
const dateEnd = getDateTime(loadStore.currentLoad.est_unloading_date, 0);
@@ -100,10 +95,7 @@
formLoad.weight = loadStore.currentLoad.weight;
formLoad.dateLoad = dateStart.substring(0, 10);
formLoad.dateDownload = dateEnd.substring(0, 10);
// formLoad.dateLoad = loadStore.currentLoad.est_loading_date?.substring(0, 10);
// formLoad.dateDownload = loadStore.currentLoad.est_unloading_date?.substring(0, 10);
formLoad.truckType = loadStore.currentLoad.truck_type ? {meta_value: loadStore.currentLoad.truck_type} : null;
origin.locationName = loadStore.currentLoad.origin.company_name;
origin.address = loadStore.currentLoad.origin.street_address1;
origin.state = loadStore.currentLoad.origin?.state ? { state_name: loadStore.currentLoad.origin.state } : null;
@@ -119,6 +111,7 @@
destination.country = loadStore.currentLoad.destination.country;
destination.postalCode = loadStore.currentLoad.destination.zipcode;
destinationRef.value = loadStore.currentLoad.destination.landmark;
locationLoadSelected.value = loadStore.currentLoad?.shipper_warehouse || null; /// Selected warehouse
getCoordsMap();
}
@@ -197,6 +190,7 @@
});
const origin = reactive({
id: null,
locationName: '',
address: '',
state: '',
@@ -254,10 +248,10 @@
},
company: auth.user.company,
posted_by: auth.user._id,
posted_by_name: formLoad.owner
posted_by_name: formLoad.owner,
shipper_warehouse: locationLoadSelected.value?._id || null,
};
return loadData;
}
@@ -269,7 +263,8 @@
const dataLocal = {
company: auth.user.company,
categories: formLoad.segment || null,
product: formLoad.terms?.length <= 0 ? null : formLoad.terms
product: formLoad.terms?.length <= 0 ? null : formLoad.terms,
shipper_warehouse: locationLoadSelected.value,
};
if(resp) {
const index = loadStore.loads.findIndex((load) => load._id === resp._id);
@@ -289,7 +284,8 @@
const load = {
...resp,
...loadData,
categories: [loadData.categories]
categories: [loadData.categories],
shipper_warehouse: locationLoadSelected.value,
}
loadStore.loads.unshift(load);
@@ -389,14 +385,14 @@
<div class="form-box">
<div class="form-section">
<div class="mb-4 mt-3">
<label class="custom-label">{{ t('global.segment') }}*</label>
<label class="custom-label required">{{ t('global.segment') }}*</label>
<Segments
v-model="formLoad.segment"
/>
<span class="error-msg" v-if="submited && errors.segment">{{ errors.segment }}</span>
</div>
<div class="mb-4 mt-3">
<label class="custom-label">{{ t('directory.typeTruck') }}*</label>
<label class="custom-label required">{{ t('directory.typeTruck') }}*</label>
<TruckTypes
v-model="formLoad.truckType"
/>
@@ -499,14 +495,14 @@
v-model:field="origin.address"
/>
<div class="mb-4 mt-3">
<label class="custom-label">{{ t('global.city') }}*</label>
<label class="custom-label required">{{ t('global.city') }}*</label>
<Cities
v-model="origin.city"
/>
<span class="error-msg" v-if="submited && errors.cityOrigin">{{ errors.cityOrigin }}</span>
</div>
<div class="mb-4 mt-3">
<label class="custom-label">{{ t('global.state') }}*</label>
<label class="custom-label required">{{ t('global.state') }}*</label>
<States
v-model="origin.state"
/>
@@ -570,14 +566,14 @@
v-model:field="destination.address"
/>
<div class="mb-4 mt-3">
<label class="custom-label">{{t('global.city')}}*</label>
<label class="custom-label required">{{t('global.city')}}*</label>
<Cities
v-model="destination.city"
/>
<span class="error-msg" v-if="submited && errors.cityDestination">{{ errors.cityDestination }}</span>
</div>
<div class="mb-4 mt-3">
<label class="custom-label">{{t('global.state')}}*</label>
<label class="custom-label required">{{t('global.state')}}*</label>
<States
v-model="destination.state"
/>

View File

@@ -34,7 +34,7 @@
noty.notifications = resp.data;
}
const roleCheck = 'store';
const roleCheck = 'warehouse';
</script>
<template>

View File

@@ -22,6 +22,7 @@
const getProposalsData = async() => {
isLoading.value = true;
await loadsStore.getProposalsOfLoads(loadsStore.currentLoad._id);
console.log(loadsStore.proposalsOfLoads)
isLoading.value = false;
}
@@ -41,6 +42,8 @@
vehicle: proposal.vehicle._id,
}
console.log(proposal)
isLoadingActions.value = true;
let load = await loadsStore.updateLoad(load_id, loadData);
if(load != null) {
@@ -53,7 +56,9 @@
loadsStore.loads[index] = {
...loadsStore.loads[index],
...load,
...dataLocal
...dataLocal,
carrier: proposal.carrier,
vehicle: proposal.vehicle,
};
const proposal_id = proposal._id;
@@ -185,18 +190,21 @@
<div class="col-lg-6 col-md-12">
<p>{{ t('global.company') }}: <span>{{ proposal.carrier.company_name }}</span></p>
<p>{{ t('proposals.bidder') }}: <span>{{ proposal.bidder.first_name }} {{ proposal.bidder.last_name }}</span></p>
<p>{{ t('proposals.numCarrier') }}: <span v-if="proposal.vehicle">{{proposal.vehicle.vehicle_code}}</span></p>
<p>{{ t('proposals.numCarrier') }}: <span>{{proposal.carrier.company_code}}</span></p>
</div>
<div class="col-lg-6 col-md-12">
<p>{{ t('labels.date') }}: <span>{{ getDateMonthDay(proposal.createdAt) }}</span></p>
<p>{{ t('directory.typeTruck') }}: <span v-if="proposal.vehicle">{{proposal.vehicle.truck_type}}</span></p>
<p>{{ t('global.carrier') }}: <span v-if="proposal._driver">{{proposal._driver}}</span></p>
<p>{{ t('labels.date') }}: <span>{{ getDateMonthDay(proposal.carrier.createdAt) }}</span></p>
<p>RFC: <span>{{proposal.carrier.rfc}}</span></p>
</div>
</div>
<div v-if="proposal.comment" class="box-note">
{{ proposal.comment }}
</div>
<VehicleInfo v-if="proposal.vehicle" :vehicle="proposal.vehicle"/>
<VehicleInfo
v-if="proposal.vehicle"
:vehicle="proposal.vehicle"
:driver="proposal.driver"
/>
<Spiner v-if="isLoadingActions"/>
<div class="d-flex justify-content-end gap-3" v-else>
<div v-if="proposal.is_accepted" class="indicator-check">

View File

@@ -40,7 +40,7 @@
});
}
const roleCheck = 'store';
const roleCheck = 'warehouse';
</script>
@@ -128,7 +128,9 @@
class="nav-link" :to="{name: 'published-trucks'}">{{ t('global.acceptedOffers') }}</RouterLink>
</div>
</li>
<li :class="[route.name === 'calendar' ? 'bg-nav-active' : '']">
<li
v-if="jobRole !== roleCheck"
:class="[route.name === 'calendar' ? 'bg-nav-active' : '']">
<div>
<i class="fa-regular fa-calendar" :class="[route.name === 'calendar' ? 'router-link-active' : '']"></i>
<RouterLink
@@ -136,6 +138,17 @@
class="nav-link" :to="{name: 'calendar'}">{{ t('global.calendar') }}</RouterLink>
</div>
</li>
<li
v-if="jobRole === roleCheck"
:class="[route.name === 'store' ? 'bg-nav-active' : '']"
>
<div>
<i class="fa-solid fa-shop-lock" :class="[route.name === 'store' ? 'router-link-active' : '']"></i>
<RouterLink
active-class="router-link-active"
class="nav-link" :to="{name: 'store'}">{{ t('store.title') }}</RouterLink>
</div>
</li>
<li
v-if="permission === 'role_carrier' && jobRole !== roleCheck"
:class="[route.name === 'calculator' ? 'bg-nav-active' : '']">

View File

@@ -1,11 +1,16 @@
<script setup>
import { computed } from 'vue';
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
defineProps({
const props = defineProps({
vehicle: {
type: Object,
required: true
},
driver: {
type: Object,
required: false
}
})
@@ -16,6 +21,16 @@ import { useI18n } from 'vue-i18n';
const toogle = () => {
isShow.value = !isShow.value;
}
const driver = computed(() => {
console.log(props.driver);
if(props?.driver) {
return !props?.driver ? 'No definido'
: props?.driver.first_name + ' ' + props?.driver.last_name
} else {
return props.vehicle.driver.first_name + ' ' + props.vehicle.driver.last_name;
}
});
</script>
<template>
@@ -31,7 +46,7 @@ import { useI18n } from 'vue-i18n';
<div class="col-lg-6">
<p>{{ t('labels.codeId') }}: <span>{{ vehicle.vehicle_code.toUpperCase() }}</span></p>
<p>{{ t('directory.typeTruck') }}: <span>{{ vehicle.truck_type }}</span></p>
<p>{{ t('vehicles.assignedDriver') }}: <span>{{ vehicle.driver.first_name + ' ' + vehicle.driver.last_name }}</span></p>
<p>{{ t('vehicles.assignedDriver') }}: <span>{{ driver }}</span></p>
<p>{{ t('global.segment') }}: <span>{{ vehicle._categories }}</span></p>
</div>
<div class="col-lg-6">

View File

@@ -19,6 +19,10 @@
disabled: {
type: Boolean,
default: false
},
required: {
type: Boolean,
default: false
}
});
defineEmits(['update:selectedCities', 'clear-option'])
@@ -49,6 +53,9 @@
:selectLabel="t('global.helpSelected')"
:selectedLabel="t('global.selected')"
:deselectLabel="t('global.removeSelected')"
:class="[
required ? 'border-required' : '',
]"
>
<template #noResult>
{{ t('global.notFound') }}

View File

@@ -48,10 +48,17 @@
<template>
<div class="d-flex flex-column gap-2 mb-4">
<label class="custom-label" :for="name">{{ label }}</label>
<label
class="custom-label"
:class="[label.includes('*') ? 'required' : '']"
:for="name"
>{{ label }}</label>
<input
class="custom-input"
:class="[!filled ? 'custom-input-light' : '']"
:class="[
!filled ? 'custom-input-light' : '',
// label.includes('*') ? 'border-required' : ''
]"
:type="type"
:id="name"
:name="name"
@@ -77,6 +84,6 @@
.error-msg {
color: red;
font-size: 12px;
font-weight: 300;
font-weight: 400;
}
</style>

View File

@@ -19,6 +19,10 @@
disabled: {
type: Boolean,
default: false
},
required: {
type: Boolean,
default: false
}
});
defineEmits(['update:selectedProduct', 'clear-option'])
@@ -49,6 +53,9 @@
:selectLabel="t('global.helpSelected')"
:selectedLabel="t('global.selected')"
:deselectLabel="t('global.removeSelected')"
:class="[
required ? 'border-required' : '',
]"
>
<template #noResult>
{{ t('global.notFound') }}

View File

@@ -15,6 +15,10 @@
multiple: {
type: Boolean,
default: false
},
required: {
type: Boolean,
default: false
}
});
defineEmits(['update:selectedCategory', 'clear-option'])
@@ -44,6 +48,9 @@
:selectLabel="t('global.helpSelected')"
:selectedLabel="t('global.selected')"
:deselectLabel="t('global.removeSelected')"
:class="[
required ? 'border-required' : '',
]"
>
<template #noResult>
{{ t('global.notFound') }}

View File

@@ -15,6 +15,10 @@
multiple: {
type: Boolean,
default: false
},
required: {
type: Boolean,
default: false
}
});
defineEmits(['update:selectedState', 'clear-option'])
@@ -45,8 +49,9 @@
:selectLabel="t('global.helpSelected')"
:selectedLabel="t('global.selected')"
:deselectLabel="t('global.removeSelected')"
:class="[
required ? 'border-required' : '',
]"
>
<template #noResult>
{{ t('global.notFound') }}

View File

@@ -19,6 +19,10 @@
disabled: {
type: Boolean,
default: false
},
required: {
type: Boolean,
default: false
}
});
defineEmits(['update:selectedTruckType', 'clear-option'])
@@ -53,6 +57,9 @@
:selectLabel="t('global.helpSelected')"
:selectedLabel="t('global.selected')"
:deselectLabel="t('global.removeSelected')"
:class="[
required ? 'border-required' : '',
]"
>
<template #noResult>
{{ t('global.notFound') }}

View File

@@ -7,7 +7,8 @@ export default function useCalendar() {
const getCalendarDate = async(startDate, endDate, filter) => {
loading.value = true;
const resp = await getCalendar(startDate, endDate, filter);
const filters = `date[lte]=${endDate}&date[gte]=${startDate}&global=${filter}`
const resp = await getCalendar(filters);
if(resp === null) {
loading.value = false;
loads.value = [];

View File

@@ -35,7 +35,7 @@ export const getStatusLoad = (load, locale = 'es') => {
};
}
export const eventStatusLoad = (loadStatus) => {
export const eventStatusLoad = (loadStatus, locale = 'es') => {
let color;
let status;
switch (loadStatus) {
@@ -58,13 +58,15 @@ export const eventStatusLoad = (loadStatus) => {
break;
case 'Delivered':
color = "blue";
status = "#1B70AF";
status = "Entregado";
break;
default:
color = "yellow";
status = 'Sin publicar';
break;
}
status = (locale === 'es') ? status : loadStatus;
return {
color,
status

View File

@@ -8,6 +8,8 @@ export const getTypeUser = (value, locale = 'es') => {
return (locale == 'es') ? 'Gerente' : 'Manager';
case 'owner':
return (locale == 'es') ? 'Propietario' : 'Owner';
case 'warehouse':
return (locale == 'es') ? 'Bodega' : 'Warehouse';
default:
return (locale == 'es') ? 'Personal' : 'Staff';

View File

@@ -51,6 +51,9 @@ const en = {
completed: 'Offers completed',
all: 'All offers',
load: 'Load',
warehouse: 'Warehouse',
warehouses: 'Warehouses',
warehouseSelect: 'Select warehouse',
download: 'Download',
select: 'Select',
additionalInformation: 'Additional information',
@@ -70,6 +73,12 @@ const en = {
originTruckKm1: "Truck origin to load origin(KM)",
originTruckKm2: "Loading origin to unloading destination(KM)",
destinationTruck1: "Unloading destination to base-yard(KM)",
alls: 'All',
published: 'Published',
loading: 'Loading',
transit: 'In transit',
downloading: 'Downloading',
delivered: 'Delivered',
},
buttons: {
enter: "Enter here",
@@ -478,6 +487,9 @@ const en = {
acceptedProposalDesc: 'Your offer has been accepted in the upload',
rejectedProposalDesc: 'Your offer has been rejected on upload',
},
store: {
title: "Warehouse"
}
};
export default en;

View File

@@ -68,11 +68,20 @@ const es = {
vehicle: 'Vehiculo',
comment: 'Comentario',
tons: "Toneladas",
warehouse: 'Bodega',
warehouses: 'Bodegas',
warehouseSelect: 'Seleccionar bodega',
priceTons: "Precio por toneladas",
tonLoad: "Tonelaje aproximado de carga",
originTruckKm1: "Origen del camión al origin de carga(KM)",
originTruckKm2: "Origen de carga a destino de descarga(KM)",
destinationTruck1: "Destino de descarga al patio-base(KM)"
destinationTruck1: "Destino de descarga al patio-base(KM)",
alls: 'Todos',
published: 'Publicado',
loading: 'Cargando',
transit: 'En transito',
downloading: 'Descargando',
delivered: 'Entregado',
},
buttons: {
enter: "Ingresa aqui",
@@ -487,6 +496,9 @@ const es = {
acceptedProposalDesc: 'Tu oferta ha sido aceptada en la carga',
rejectedProposalDesc: 'Tu oferta ha sido rechazada en la carga',
},
store: {
title: "Bodega"
}
};
export default es;

View File

@@ -94,7 +94,10 @@ const router = createRouter({
{
path: 'profile',
name: 'profile',
meta: { permissions: ['role_shipper', 'role_carrier'] },
meta: {
permissions: ['role_shipper', 'role_carrier'],
roles: ['manager', 'staff', 'owner', 'warehouse']
},
component: () => import('../views/EditProfileView.vue'),
},
{
@@ -138,10 +141,19 @@ const router = createRouter({
name: 'calendar',
meta: {
permissions: ['role_shipper', 'role_carrier'],
roles: ['staff', 'manager', 'owner', 'store']
roles: ['staff', 'manager', 'owner']
},
component: () => import('../views/CalendarView.vue'),
},
{
path: 'bodega',
name: 'store',
meta: {
permissions: ['role_shipper'],
roles: ['warehouse']
},
component: () => import('../views/store/StoreView.vue'),
},
{
path: 'cargas',
meta: { permissions: ['role_shipper'] },
@@ -211,15 +223,16 @@ router.beforeEach( async(to, from, next) => {
}
if (permissions && !permissions.includes(permissionUser)) {
if(role === 'store') { /// Check if user is store
return next({name: 'calendar'});
if(role === 'warehouse') { /// Check if user is store
return next({name: 'store'});
} else {
return next({name: 'home'});
}
}
if(roles && !roles.includes(role)) {
return next({name: 'calendar'});
// return next({name: 'calendar'});
return next({name: 'store'});
}
next();

View File

@@ -158,9 +158,9 @@ export const deleteLocation = async(id) => {
}
}
export const getCalendar = async(startDate, endDate, global) => {
export const getCalendar = async(filters) => {
try {
const endpoint = `/v1/loads/calendar?$sort[createdAt]=-1&date[lte]=${endDate}&date[gte]=${startDate}&global=${global}&elements=1000`;
const endpoint = `/v1/loads/calendar?$sort[createdAt]=-1&elements=1000&${filters}`;
const {data} = await api.get(endpoint);
return {
msg: "success",

View File

@@ -1,11 +1,13 @@
import { defineStore } from "pinia";
import { ref } from "vue";
import api from "../lib/axios";
import { getCalendar } from "../services/company";
export const useLoadsStore = defineStore('load', () => {
const currentLoad = ref(null);
const loads = ref([])
const loadsWarehouse = ref([])
const loadsDashboard = ref([]);
const loadsTotal = ref(0)
const loadsCurrentPage = ref(0)
@@ -13,6 +15,7 @@ export const useLoadsStore = defineStore('load', () => {
const openModalEdit = ref(false);
const openAttachmentsModal = ref(false);
const openProposalsModal = ref(false);
const openCarrierInfoModal = ref(false);
const getLoadsAll = async(reload = false) => {
const companyid = localStorage.getItem('id');
@@ -61,6 +64,24 @@ export const useLoadsStore = defineStore('load', () => {
}
}
const getLoadsWarehouse = async(filterQuery, reload = false) => {
let filterArr = Object.values(filterQuery);
let cleanfilterArr = filterArr.filter(n=>n);
var filterStr = "";
if(cleanfilterArr.length >0){
filterStr = cleanfilterArr.join("&");
}
if(loadsWarehouse.value.length <= 0 || reload) {
try {
const endpoint = `/v1/loads/find?${filterStr}`;
const {data} = await api.get(endpoint);
loadsWarehouse.value = data.data;
} catch (error) {
loadsWarehouse.value = [];
}
}
}
const getProposalsOfLoads = async(filterQuery) => {
try {
const endpoint = `/v1/proposals/find?load=${filterQuery}`;
@@ -140,6 +161,7 @@ export const useLoadsStore = defineStore('load', () => {
loadsTotal.value = 0;
loadsCurrentPage.value = 0;
proposalsOfLoads.value = [];
loadsWarehouse.value = [];
openModalEdit.value = false;
openAttachmentsModal.value = false;
openProposalsModal.value = false;
@@ -151,11 +173,14 @@ export const useLoadsStore = defineStore('load', () => {
openModalEdit,
openProposalsModal,
openAttachmentsModal,
openCarrierInfoModal,
getProposalsOfLoads,
getCompanyLoads,
getLoadsAll,
getProposalCompanyAll,
getLoadsWarehouse,
loadsDashboard,
loadsWarehouse,
deleteLoad,
getLoad,
saveLoad,
@@ -167,5 +192,6 @@ export const useLoadsStore = defineStore('load', () => {
loadsTotal,
currentLoad,
proposalsOfLoads,
}
});

View File

@@ -240,7 +240,7 @@
v-model:field="company.rfc"
/>
<div class="mb-4">
<label class="custom-label">{{ t('labels.questionSegments') }} *</label>
<label class="custom-label required">{{ t('labels.questionSegments') }} *</label>
<Segments
v-model="company.segments"
:multiple="true"
@@ -261,7 +261,7 @@
/>
</div>
<div class="mb-4">
<label class="custom-label">{{ t('labels.questionTrucks') }} *</label>
<label class="custom-label required">{{ t('labels.questionTrucks') }} *</label>
<TruckTypes
v-model="company.truckTypes"
:multiple="true"

View File

@@ -61,7 +61,7 @@
const result = await auth.updateProfile(userData)
loading.value = false;
if(result.msg === 'success') {
msgSuccess.value = t('errors.msgUpdateUser');
msgSuccess.value = t('profile.msgUpdateUser');
clearMessages();
} else {
msgError.value = t('errors.generic');

View File

@@ -9,6 +9,7 @@
import CardEmpty from '../components/CardEmpty.vue';
import Pagination from '../components/Pagination.vue';
import { useI18n } from 'vue-i18n';
import CarrierInfoModal from '../components/CarrierInfoModal.vue';
const loadStore = useLoadsStore();
const loading = ref(false);
@@ -94,6 +95,7 @@
<AttachmentsModal v-if="loadStore.openAttachmentsModal"/>
<FormLoadModal v-if="loadStore.openModalEdit"/>
<ProposalsModal v-if="loadStore.openProposalsModal"/>
<CarrierInfoModal :load="loadStore.currentLoad" v-if="loadStore.openCarrierInfoModal"/>
<div>
<h2 class="title mb-5">{{ t('loads.title') }}</h2>
<div>

View File

@@ -10,6 +10,7 @@
import { useI18n } from 'vue-i18n';
import AttachmentsModal from '../components/AttachmentsModal.vue';
import { useLoadsStore } from '../stores/loads';
import CarrierInfoModal from '../components/CarrierInfoModal.vue';
const mapKey = import.meta.env.VITE_MAP_KEY;
@@ -91,10 +92,16 @@
heightMap.value = 768;
}
}
const openModal = () => {
loadStore.openCarrierInfoModal = true;
}
</script>
<template>
<AttachmentsModal v-if="loadStore.openAttachmentsModal"/>
<CarrierInfoModal :load="load" v-if="loadStore.openCarrierInfoModal"/>
<h2 class="title text-center mt-5">{{ t('loads.trackingLoad') }}</h2>
<Spiner v-if="loading"/>
<div v-else>
@@ -119,15 +126,23 @@
>
<Marker v-if="originCoords" :options="{position: originCoords, label: 'O', title: 'Destino'}" />
<Marker v-if="destinationCoords" :options="{position: destinationCoords, label: 'D', title: 'Origen'}" />
<!-- v-if="vehicleLastLocation && load.vehicle.background_tracking && isLoadActive" -->
<!-- <CustomMarker
:options="{position: vehicleLastLocation}"
:clickable="false"
:draggable="false"
> -->
<CustomMarker
v-if="vehicleLastLocation && load.vehicle.background_tracking && isLoadActive"
:options="{position: vehicleLastLocation}"
:clickable="false"
:draggable="false"
>
<div
style="text-align: center"
data-toggle="modal"
data-target="#carrierInfoModal"
@click="openModal()"
>
<div style="text-align: center">
<!-- <img src="/images/freeTruck.png" width="25" height="25" /> -->
<i class="fa-solid fa-truck" :style="{fontSize: 25 + 'px', color: 'green'}"></i>
</div>
</CustomMarker>

View File

@@ -0,0 +1,199 @@
<script setup>
import { ref } from 'vue';
import { onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
import LoadStoreCard from './components/LoadStoreCard.vue';
import { useLoadsStore } from '../../stores/loads';
import { useAuthStore } from '../../stores/auth';
import Spiner from '../../components/ui/Spiner.vue';
import CustomPopup from '../../components/CustomPopup.vue';
const authStore = useAuthStore();
const loadStore = useLoadsStore();
const { t } = useI18n()
const query = ref('');
const date = ref(new Date());
const loadsFilters = ref([]);
const filterQuery = ref([]);
const loading = ref(false);
const openPopup = ref(false);
const status = ref({value: 'all', label: 'Todos'});
const options = ref([]);
onMounted(async() => {
date.value = (new Date()).toISOString().substring(0, 10);
options.value = [
{value: 'all', label: t('labels.alls')},
{value: 'Published',label: t('labels.published')},
{value: 'Loading',label: t('labels.loading')},
{value: 'Transit',label: t('labels.transit')},
]
status.value = {value: 'all', label: t('labels.alls')};
await getDataLoads(false);
})
const getDataLoads = async (reload) => {
loading.value = true;
const dateSelected = new Date(date.value);
const startDate = dateSelected.toISOString();
const endDateSpeac = new Date(dateSelected).setDate(dateSelected.getDate() + 1);
const endDate = (new Date(endDateSpeac)).toISOString();
filterQuery.value.branch = 'shipper_warehouse=' + authStore.user.branch;
filterQuery.value.start = 'est_loading_date[gte]=' + startDate.substring(0, 10).replaceAll('-', '/');
filterQuery.value.end = 'est_loading_date[lte]=' + endDate.substring(0, 10).replaceAll('-', '/');
await loadStore.getLoadsWarehouse(filterQuery.value, reload);
loadsFilters.value = loadStore.loadsWarehouse;
loading.value = false;
}
/// methods:
const search = () => {
if(query.value == "") {
loadsFilters.value = loadStore.loads;
}
if(query.value.length >= 1){
loadsFilters.value = loadStore.loadsWarehouse.filter(
load => load.shipment_code.toLowerCase().includes(query.value.toLowerCase())
|| load?.carrier?.company_name.toLowerCase().includes(query.value.toLowerCase())
|| load?.product?.name.toLowerCase().includes(query.value.toLowerCase())
|| load?.vehicle?.truck_type.toLowerCase().includes(query.value.toLowerCase())
|| load?.vehicle?.circulation_serial_number.toLowerCase().includes(query.value.toLowerCase())
|| load?.vehicle?.trailer_plate_1.toLowerCase().includes(query.value.toLowerCase())
|| load?.vehicle?.trailer_plate_2.toLowerCase().includes(query.value.toLowerCase())
|| load?.driver?.first_name.toLowerCase().includes(query.value.toLowerCase())
);
} else {
loadsFilters.value = loadStore.loadsWarehouse;
}
}
const handleDate = async () => {
status.value = {value: 'all', label: t('labels.alls')};
await getDataLoads(true);
}
const closePopup = () => {
openPopup.value = false
}
const changeStatus = (value) => {
status.value = value;
openPopup.value = false
if(value.value == 'all') {
loadsFilters.value = loadStore.loadsWarehouse;
} else {
loadsFilters.value = loadStore.loadsWarehouse.filter(
load => load.load_status.toLowerCase().includes(value.value.toLowerCase())
);
}
}
</script>
<template>
<div
v-if="openPopup"
>
<CustomPopup
:options="options"
:value="status"
@change-value="changeStatus"
@close-popup="closePopup"
selected-color="#e3a11e"
/>
</div>
<h2 class="title mb-4">{{ t('store.title') }}</h2>
<div class="box-filters">
<div class="box-search">
<input
class="form-control custom-search"
type="search" name=""
:placeholder="t('buttons.search')"
id="store-search"
@:input="search()"
v-model="query"
aria-label="Search"
/>
</div>
<div class="date-filter">
<input
placeholder="Fecha"
type="date"
class="custom-input-fill"
v-model="date"
@change="handleDate($event)"
/>
</div>
<div class="status-filter"
@click="openPopup = true"
>
<span class="clear-sm">{{ status.label }}</span>
<i class="fa-solid fa-filter"></i>
</div>
</div>
<div class="row">
<div v-if="loading" class="d-flex justify-content-center">
<Spiner />
</div>
<LoadStoreCard
v-else
v-for="load in loadsFilters"
:key="load.shipment_code"
:load="load"
/>
</div>
</template>
<style lang="scss" scoped>
.box-filters {
display: flex;
flex-direction: row;
justify-content: end;
gap: 0.5rem;
}
.box-search {
display: flex;
flex: 1;
}
.status-filter {
padding: 12px 8px;
background-color: #FFF;
border-radius: 5px;
display: flex;
flex-direction: row;
border: 1px rgb(186, 175, 175) solid;
gap: 1rem;
align-items: center;
cursor: pointer;
}
.custom-search {
width: 100%;
padding: 12px 20px;
}
.bg-white {
background-color: white;
}
@media (max-width: 768px) {
.box-filters {
gap: 0.2rem;
}
.date-filter input {
padding: 12px 8px;
width: 130px;
}
.box-search {
width: 100%;
}
}
</style>

View File

@@ -0,0 +1,86 @@
<script setup>
import { useI18n } from 'vue-i18n';
import { getDateTime } from '../../../helpers/date_formats';
import { eventStatusLoad } from '../../../helpers/status';
import { computed } from 'vue';
const props = defineProps({
load: {
type: Object,
required: true
}
})
const { t, locale } = useI18n()
const status = eventStatusLoad(props.load.load_status, locale.value);
const driver = computed(() => {
return !props.load?.driver ? 'No definido'
: props.load?.driver.first_name + ' ' + props.load?.driver.last_name
});
</script>
<template>
<div
class="col-lg-6 col-12 mt-4"
>
<div class="card-info flex-d-column">
<div class="d-flex justify-content-between bg-white">
<div class="flex-direction-column">
<h2>{{ load.shipment_code }}</h2>
<p><span class="font-bold">{{ t('labels.date') }}: </span> {{ getDateTime(load.est_loading_date, 0) }}</p>
<p><span class="font-bold" >{{ t('global.company') }}: </span> {{ load?.carrier?.company_name ?? 'No definido' }}</p>
<p><span class="font-bold" >{{ t('loads.product') }}: </span> {{ load.product?.name }}</p>
<p><span class="font-bold" >{{ t('loads.weight') }}: </span> {{ load.weight }}kg</p>
</div>
<div class="flex-direction-column">
<p> <div class="indicator" :style="{backgroundColor: status.color}"></div> <strong :style="{color: status.color}">{{ status.status }}</strong></p>
<p> <span class="font-bold">{{ t('directory.typeTruck') }}: </span> {{ load?.vehicle?.truck_type ?? 'No definido' }}</p>
<p> <span class="font-bold">{{ t('vehicles.truckPlates') }}: </span> {{ load?.vehicle?.circulation_serial_number ?? 'No definido' }}</p>
<p v-if="load?.vehicle?.trailer_plate_1">
<span class="font-bold">{{ t('vehicles.trailerPlates') }} 1: </span> {{ load?.vehicle?.trailer_plate_1 }}
</p>
<p v-if="load?.vehicle?.trailer_plate_2">
<span class="font-bold">{{ t('vehicles.trailerPlates') }} 2: </span> {{ load?.vehicle?.trailer_plate_2 }}
</p>
<p> <span class="font-bold">{{ t('labels.driver') }}: </span> {{ driver }}</p>
</div>
</div>
<div class="box-note" v-if="load.notes">
<span class="label"><i class="fa-solid fa-clipboard" style="color: #FBBA33; font-size: 1.1rem;"></i> Nota:</span>
<span>{{ load.notes }}</span>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.indicator {
width: 12px;
height: 12px;
border-radius: 50%;
display: inline-block;
margin-right: 0.5rem;
}
.box-note {
display: flex;
flex-direction: column;
padding: 0.8rem;
font-size: 1rem;
background-color: #FFF;
border-radius: 13px;
border: 1px solid #E5E5E5;
justify-content: center;
}
.label {
font-weight: bold;
font-size: 0.9rem;
color: #303233;
}
p {
font-size: 0.9rem;
}
</style>