add: services

This commit is contained in:
Alexandro Uc
2026-03-30 21:01:23 -06:00
parent 291dbd2f35
commit 9e6e0948d4
15 changed files with 332 additions and 122 deletions

View File

@@ -27,7 +27,7 @@ const toggle = (event) => {
<template> <template>
<label class="switch-container"> <label class="switch-container">
<span v-if="label" class="custom-label label-text">{{ label }}</span> <span v-if="label" class="custom-label label-text flex1">{{ label }}</span>
<input <input
type="checkbox" type="checkbox"
@@ -41,6 +41,9 @@ const toggle = (event) => {
</template> </template>
<style scoped> <style scoped>
.flex1 {
flex: 1;
}
.switch-container { .switch-container {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -1,9 +1,10 @@
<script setup> <script setup>
import LoadingModal from '../components/ui/LoadingModal.vue'; import LoadingModal from '../components/ui/LoadingModal.vue';
import NavBar from '../components/NavBar.vue'; import NavBar from './components/NavBar.vue';
import Sidebar from '../components/Sidebar.vue'; import Sidebar from './components/Sidebar.vue';
import ProfilePopup from '../views/profile/modals/ProfilePopup.vue'; import ProfilePopup from '../views/profile/modals/ProfilePopup.vue';
import NotificationsPopup from '../components/NotificationsPopup.vue'; import NotificationsPopup from './components/NotificationsPopup.vue';
import ConfigPopup from './components/ConfigPopup.vue';
</script> </script>
@@ -19,6 +20,7 @@
</div> </div>
<LoadingModal/> <LoadingModal/>
<ProfilePopup/> <ProfilePopup/>
<ConfigPopup/>
<NotificationsPopup/> <NotificationsPopup/>
</template> </template>

View File

@@ -0,0 +1,99 @@
<script setup>
import { useNotificationsStore } from '../../stores/notifications';
import CustomSwitch from '../../components/CustomSwitch.vue'
import { useI18n } from 'vue-i18n';
import { ref } from 'vue';
import { onMounted } from 'vue';
import { watch } from 'vue';
import { usePrivacyStore } from '../../stores/privacy';
const lang = ref(null);
const privacy = ref(false);
const noty = useNotificationsStore();
const privacyStore = usePrivacyStore();
const { t, locale } = useI18n();
onMounted(() => {
lang.value = localStorage.getItem('lang') ?? 'es';
locale.value = lang.value;
privacy.value = privacyStore.privacy;
});
watch(lang, () => {
locale.value = lang.value
localStorage.setItem('lang', lang.value)
})
watch(privacy, () => {
privacyStore.updatePrivacy(privacy.value);
})
const closePopup = () => {
noty.toggleConfig();
}
</script>
<template>
<div
v-if="noty.openConfig"
>
<div
class="content-popup"
@click="closePopup()"
>
</div>
<div
class="profile-card">
<i class="fa-solid fa-xmark close-icon" @click="closePopup()"></i>
<br>
<CustomSwitch
label="Activar configuracion de privacidad"
v-model="privacy"
name="privacity"
/>
</div>
</div>
</template>
<style scoped>
.content-popup {
position: fixed;
z-index: 1000;
width: 100wv;
right: 0px;
top: 0px;
left: 0px;
cursor: pointer;
bottom: 0px;
background-color: #000;
opacity: 0.2;
}
.profile-card {
position: fixed;
flex: 1;
right: 20px;
top: 70px;
z-index: 2000;
width: 340px;
background-color: #FFF;
opacity: 1;
border-radius: 13px;
padding: 20px 20px;
display: flex;
flex-direction: column;
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.10));
}
.close-icon {
display: flex;
position: absolute;
right: 20px;
top: 16px;
cursor: pointer;
font-size: 24px;
}
</style>

View File

@@ -1,10 +1,10 @@
<script setup> <script setup>
import { RouterLink } from 'vue-router'; import { RouterLink } from 'vue-router';
import { useAuthStore } from '../stores/auth'; import { useAuthStore } from '../../stores/auth';
import { useNotificationsStore } from '../stores/notifications'; import { useNotificationsStore } from '../../stores/notifications';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import { getNotificationsCompany } from '../services/company'; import { getNotificationsCompany } from '../../services/company';
const auth = useAuthStore(); const auth = useAuthStore();
const noty = useNotificationsStore(); const noty = useNotificationsStore();
@@ -76,6 +76,12 @@
active-class="router-link-active" active-class="router-link-active"
@click="noty.toggleProfile" @click="noty.toggleProfile"
class="nav-link"><i class="fa-regular fa-user"></i></a> class="nav-link"><i class="fa-regular fa-user"></i></a>
<a
active-class="router-link-active"
@click="noty.toggleConfig"
class="nav-link">
<i class="fa-solid fa-gear"></i>
</a>
</div> </div>
</div> </div>
</nav> </nav>

View File

@@ -2,10 +2,10 @@
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import {getDateTime} from '../helpers/date_formats'; import {getDateTime} from '../../helpers/date_formats';
import { deleteNotification } from '../services/company'; import { deleteNotification } from '../../services/company';
import { useNotificationsStore } from '../stores/notifications'; import { useNotificationsStore } from '../../stores/notifications';
import Spiner from './ui/Spiner.vue'; import Spiner from '../../components/ui/Spiner.vue';
const props = defineProps({ const props = defineProps({
noty: { noty: {

View File

@@ -1,5 +1,5 @@
<script setup> <script setup>
import { useNotificationsStore } from '../stores/notifications'; import { useNotificationsStore } from '../../stores/notifications';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import NotificationCard from './NotificationCard.vue'; import NotificationCard from './NotificationCard.vue';

View File

@@ -1,12 +1,12 @@
<script setup> <script setup>
import { RouterLink, useRoute, useRouter } from 'vue-router'; import { RouterLink, useRoute, useRouter } from 'vue-router';
import { useAuthStore } from '../stores/auth'; import { useAuthStore } from '../../stores/auth';
import Swal from 'sweetalert2'; import Swal from 'sweetalert2';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useCompanyStore } from '../stores/company'; import { useCompanyStore } from '../../stores/company';
import { useVehiclesStore } from '../stores/vehicles'; import { useVehiclesStore } from '../../stores/vehicles';
import { useLoadsStore } from '../stores/loads'; import { useLoadsStore } from '../../stores/loads';
import { useNotificationsStore } from '../stores/notifications'; import { useNotificationsStore } from '../../stores/notifications';
const route = useRoute(); const route = useRoute();
const auth = useAuthStore(); const auth = useAuthStore();

View File

@@ -202,3 +202,68 @@ export const deleteNotification = async(id) => {
}; };
} }
} }
export const enablePrivacyCompany = async(formData) => {
try {
const endpoint = '/v1/companies/own';
const {data} = await api.patch(endpoint, formData);
return {
msg: 'success',
data: data
};
} catch (error) {
return {
msg: error.response.data.error ?? "Algo salió mal, intente nás tarde",
data: null
};
}
}
export const getPrivateListService = async() => {
try {
const endpoint = `/v1/groups/private`;
const {data} = await api.get(endpoint);
console.log(data);
return {
msg: 'success',
data: data
};
} catch (error) {
return {
msg: error.response.data.error ?? "Algo salió mal, intente nás tarde",
data: null
};
}
}
export const addCompanyPrivicyListService = async(id) => {
try {
const endpoint = `/v1/groups/private/${id}`;
const {data} = await api.patch(endpoint);
return {
msg: 'success',
data: data
};
} catch (error) {
return {
msg: error.response.data.error ?? "Algo salió mal, intente nás tarde",
data: null
};
}
}
export const deleteCompanyPrivicyListService = async(id) => {
try {
const endpoint = `/v1/groups/private/${id}`;
const {data} = await api.delete(endpoint);
return {
msg: 'success',
data: data
};
} catch (error) {
return {
msg: error.response.data.error ?? "Algo salió mal, intente nás tarde",
data: null
};
}
}

View File

@@ -5,12 +5,14 @@ import { renewToken } from '../services/auth';
import {useNotificationsStore} from './notifications'; import {useNotificationsStore} from './notifications';
import { useLoadsStore } from "./loads"; import { useLoadsStore } from "./loads";
import { updateMyUserProfile } from "../services/company"; import { updateMyUserProfile } from "../services/company";
import { usePrivacyStore } from "./privacy";
export const useAuthStore = defineStore('auth', () => { export const useAuthStore = defineStore('auth', () => {
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const noty = useNotificationsStore(); const noty = useNotificationsStore();
const privicyStore = usePrivacyStore();
const loadStore = useLoadsStore(); const loadStore = useLoadsStore();
const sesion = ref('') const sesion = ref('')
const checking = ref(false); const checking = ref(false);
@@ -39,6 +41,7 @@ export const useAuthStore = defineStore('auth', () => {
if(resp.msg === 'success') { if(resp.msg === 'success') {
user.value = resp.data.user; user.value = resp.data.user;
sesion.value = resp.data.session_token; sesion.value = resp.data.session_token;
privicyStore.privacy = resp.data.user?.company?.privacy || false;
token.value = resp.data.accessToken; token.value = resp.data.accessToken;
localStorage.setItem('session', resp.data.session_token); localStorage.setItem('session', resp.data.session_token);
localStorage.setItem('access', resp.data.accessToken); localStorage.setItem('access', resp.data.accessToken);

View File

@@ -1,66 +0,0 @@
import { defineStore } from "pinia"
import { ref } from "vue";
export const useContactsStore = defineStore('contacts', () => {
const contacts = ref([
{
"id": 13,
"company": "Altos",
"companyId": 929,
"rfc": "USKSK00101",
"category": "Agricola"
},
{
"id": 15,
"company": "Altos logos",
"companyId": 2018,
"rfc": "USKSK0010a",
"category": "Agricola"
},
{
"id": 18,
"company": "Bravos SA",
"companyId": 199,
"rfc": "UJSK8991",
"category": "Materiales"
},
{
"id": 10,
"company": "Kolo",
"companyId": 1993,
"rfc": "JKDKD91001",
"category": "Servicios"
},
{
"id": 39,
"company": "Altos",
"companyId": 929,
"rfc": "USKSK00101",
"category": "Agricola"
},
{
"id": 19,
"company": "Altos",
"companyId": 929,
"rfc": "USKSK00101",
"category": "Agricola"
},
{
"id": 934,
"company": "Altos",
"companyId": 929,
"rfc": "USKSK00101",
"category": "Agricola"
},
]);
const removeContact = (id) => {
contacts.value = contacts.value.filter((e) => e.id !== id);
}
return {
contacts,
removeContact
}
});

View File

@@ -8,6 +8,7 @@ export const useNotificationsStore = defineStore('notifications', () => {
const error = ref(false) const error = ref(false)
const show = ref(false); const show = ref(false);
const openProfile = ref(false); const openProfile = ref(false);
const openConfig = ref(false);
const openNotifications = ref(false); const openNotifications = ref(false);
const notifications = ref([]); const notifications = ref([]);
const newNoty = ref(false); const newNoty = ref(false);
@@ -26,6 +27,10 @@ export const useNotificationsStore = defineStore('notifications', () => {
openProfile.value = !openProfile.value; openProfile.value = !openProfile.value;
} }
const toggleConfig = () => {
openConfig.value = !openConfig.value;
}
const toggleNotifications = () => { const toggleNotifications = () => {
openNotifications.value = !openNotifications.value; openNotifications.value = !openNotifications.value;
} }
@@ -39,6 +44,7 @@ export const useNotificationsStore = defineStore('notifications', () => {
newNoty.value = false; newNoty.value = false;
show.value = false; show.value = false;
openNotifications.value = false; openNotifications.value = false;
openConfig.value = false;
toggleProfile.value = false; toggleProfile.value = false;
} }
@@ -51,8 +57,10 @@ export const useNotificationsStore = defineStore('notifications', () => {
notifications, notifications,
newNoty, newNoty,
openProfile, openProfile,
openConfig,
removeNoty, removeNoty,
toggleProfile, toggleProfile,
toggleConfig,
openNotifications, openNotifications,
toggleNotifications, toggleNotifications,
clear clear

74
src/stores/privacy.js Normal file
View File

@@ -0,0 +1,74 @@
import { defineStore } from "pinia"
import { ref } from "vue";
import { addCompanyPrivicyListService, deleteCompanyPrivicyListService, enablePrivacyCompany, getPrivateListService } from "../services/company";
export const usePrivacyStore = defineStore('privacy', () => {
const privacy = ref(false);
const privateListRef = ref([]);
const privateList = ref([]);
const updatePrivacy = async (value) => {
const data = {
"privacy": value
};
const response = await enablePrivacyCompany(data);
if(response.msg == 'success') {
privacy.value = response.data.privacy || false;
}
}
const getPrivateList = async (id) => {
const response = await getPrivateListService();
if(response.msg == 'success') {
privateList.value = response.data.allowedCompanies || [];
return 'success';
} else {
return response.msg;
}
}
const addCompanyToPrivateList = async (id) => {
const response = await addCompanyPrivicyListService(id);
if(response.msg == 'success') {
privateListRef.value = [
...privateListRef.value,
id
];
return 'success';
} else {
return response.msg;
}
}
const deleteCompanyToPrivateList = async (id) => {
const response = await deleteCompanyPrivicyListService(id);
if(response.msg == 'success') {
privateListRef.value = [
...privateListRef.value,
id
]
return 'success';
} else {
return response.msg;
}
}
/// State
const removeContact = (id) => {
privateList.value = privateList.value.filter((e) => e.id !== id);
}
return {
privacy,
privateListRef,
privateList,
removeContact,
updatePrivacy,
getPrivateList,
deleteCompanyToPrivateList,
addCompanyToPrivateList
}
});

View File

@@ -1,22 +1,20 @@
<script setup> <script setup>
import { ref, watch } from 'vue'; import { onMounted, ref, watch } from 'vue';
import { useContactsStore } from '../../stores/contacts'; import { usePrivacyStore } from '../../stores/privacy';
import ContactCard from './components/ContactCard.vue'; import ContactCard from './components/ContactCard.vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import CustomSearchInput from '../../components/CustomSearchInput.vue'; import CustomSearchInput from '../../components/CustomSearchInput.vue';
import Spiner from '../../components/ui/Spiner.vue'; import Spiner from '../../components/ui/Spiner.vue';
const contactsStore = useContactsStore(); const privateStore = usePrivacyStore();
const { t } = useI18n(); const { t } = useI18n();
const loading = ref(false); const loading = ref(false);
const query = ref(''); const query = ref('');
let timeout = null; let timeout = null;
onMounted(() => {
const search = () => { privateStore.getPrivateList();
console.log('Searching:', query.value); });
};
watch(query, (newValue) => { watch(query, (newValue) => {
clearTimeout(timeout); clearTimeout(timeout);
@@ -28,6 +26,10 @@
}, 400); }, 400);
}); });
const search = () => {
console.log('Searching:', query.value);
};
</script> </script>
<template> <template>
@@ -41,7 +43,7 @@
</div> </div>
<ContactCard <ContactCard
v-else v-else
v-for="contact in contactsStore.contacts" v-for="contact in privateStore.privateList"
:key="contact.id" :key="contact.id"
:contact="contact" :contact="contact"
/> />

View File

@@ -2,7 +2,8 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useAuthStore } from '../../../stores/auth'; import { useAuthStore } from '../../../stores/auth';
import Swal from 'sweetalert2'; import Swal from 'sweetalert2';
import { useContactsStore } from '../../../stores/contacts'; import { usePrivacyStore } from '../../../stores/privacy';
import { computed } from 'vue';
const props = defineProps({ const props = defineProps({
@@ -14,7 +15,7 @@ import { useContactsStore } from '../../../stores/contacts';
const { t } = useI18n(); const { t } = useI18n();
const authStore = useAuthStore(); const authStore = useAuthStore();
const contactsStore = useContactsStore(); const contactsStore = usePrivacyStore();
const handleDeleteContact = async() => { const handleDeleteContact = async() => {
Swal.fire({ Swal.fire({
@@ -60,13 +61,23 @@ import { useContactsStore } from '../../../stores/contacts';
} }
const categories = computed(() => (props.contact.categories)
? props.contact.categories.map((e) => e.name).join(', ')
: ''
)
const truckTypes = computed(() => (props.contact.truck_type)
? props.contact.truck_type.join(', ')
: ''
)
</script> </script>
<template> <template>
<div class="col-lg-6 col-12"> <div class="col-lg-6 col-12">
<div class="card-fixed flex-d-column"> <div class="card-fixed flex-d-column">
<div class="d-flex"> <div class="d-flex">
<h2 class="flex1">{{ contact.company }}</h2> <h2 class="flex1">{{ contact.company_name }}</h2>
<button <button
v-if="(authStore.user?.job_role === 'owner' || authStore.user?.job_role === 'manager')" v-if="(authStore.user?.job_role === 'owner' || authStore.user?.job_role === 'manager')"
class="btn-primary-sm bg-danger" class="btn-primary-sm bg-danger"
@@ -76,8 +87,8 @@ import { useContactsStore } from '../../../stores/contacts';
</button> </button>
</div> </div>
<p><span class="font-bold">RFC: </span> {{ contact.rfc}}</p> <p><span class="font-bold">RFC: </span> {{ contact.rfc}}</p>
<p><span class="font-bold">{{ t('global.segments') }}:</span> {{contact.category}}</p> <p><span class="font-bold">{{ t('global.segments') }}:</span> {{ categories }}</p>
<p><span class="font-bold">{{ t('directory.typeTruckNeed') }}: </span> Torton</p> <p><span class="font-bold">{{ t('directory.typeTruckNeed') }}: </span> {{ truckTypes }}</p>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -3,20 +3,27 @@
import { getDateMonthDay } from '../../../helpers/date_formats'; import { getDateMonthDay } from '../../../helpers/date_formats';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import Swal from 'sweetalert2'; import Swal from 'sweetalert2';
import { ref } from 'vue'; import { onMounted, ref } from 'vue';
import { useAuthStore } from '../../../stores/auth'; import { useAuthStore } from '../../../stores/auth';
import { usePrivacyStore } from '../../../stores/privacy';
defineProps({ const props = defineProps({
company: { company: {
type: Object, type: Object,
required: true, required: true,
} }
}); });
const authStore = useAuthStore(); const authStore = useAuthStore();
let existInPrivateList = ref(false); const privacyStore = usePrivacyStore();
const existInPrivateList = ref(false);
const handleAddPrivateList = async() => { onMounted(() => {
const id = props.company._id;
existInPrivateList.value = privacyStore.privateListRef.includes(id);
})
const handleAddPrivateList = async() => {
Swal.fire({ Swal.fire({
title: 'Lista privadad', title: 'Lista privadad',
text: '¿Estas seguro de añadir a este transportista de la lista privada?', text: '¿Estas seguro de añadir a este transportista de la lista privada?',
@@ -34,26 +41,22 @@
Swal.showLoading() Swal.showLoading()
}, },
}); });
let resp = null; const response = await privacyStore.addCompanyToPrivateList(props.company._id);
setTimeout(() => { Swal.close();
resp = true if(response === 'success') {
Swal.close(); existInPrivateList.value = true;
if(resp != null) { Swal.fire({
// contactsStore.removeContact(id); title: 'Transportista añadido',
existInPrivateList.value = true; text: 'Se ha añadido este transportista a la lista privada',
Swal.fire({ icon: "success"
title: 'Transportista añadido', });
text: 'Se ha añadido este transportista a la lista privada', } else {
icon: "success" Swal.fire({
}); title: 'Error',
} else { text: response,
Swal.fire({ icon: "error"
title: t('errors.msgTitleNotDel'), });
text: 'No se pudo completar la añadir este transportista a la lista privada', }
icon: "error"
});
}
}, 500);
} }
}); });