0
1
Fork 0

Update branch and resolve conflicts

This commit is contained in:
William Buezas 2024-10-08 15:53:27 -03:00
commit cd7a4b13f6
16 changed files with 161 additions and 86 deletions

View File

@ -70,6 +70,7 @@ onMounted(() => {
bg-color="white"
is-outlined
:clearable="false"
class="searchbar"
>
<template #prepend>
<QIcon name="search" class="cursor-pointer" @click="search()" />
@ -77,6 +78,15 @@ onMounted(() => {
</VnInput>
</template>
<style lang="scss" scoped>
@import 'src/css/responsive';
.searchbar {
@include mobile {
max-width: 120px;
}
}
</style>
<i18n lang="yaml">
en-US:
search: Search

View File

@ -5,8 +5,7 @@ import { useQuasar } from 'quasar';
export function usePrintService() {
const quasar = useQuasar();
const userStore = useUserStore();
const token = userStore.token;
const { getTokenMultimedia } = useUserStore();
function sendEmail(path, params) {
return axios.post(path, params).then(() =>
@ -18,17 +17,17 @@ export function usePrintService() {
);
}
function openReport(path, params) {
function openReport(path, params, isNewTab = '_self') {
if (typeof params === 'string') params = JSON.parse(params);
params = Object.assign(
{
access_token: token
access_token: getTokenMultimedia()
},
params
);
const query = new URLSearchParams(params).toString();
window.open(`api/${path}?${query}`);
window.open(`api/${path}?${query}`, isNewTab);
}
return {

View File

@ -9,3 +9,9 @@
@content;
}
}
@mixin desktop {
@media screen and (min-width: 1025px) {
@content;
}
}

View File

@ -119,6 +119,7 @@ export default {
confirmDelete: 'Estàs segur que vols esborrar la línia?',
emptyList: 'Llista buida',
logInAsGuest: `Accedir com a convidat`,
logIn: 'Iniciar sessió',
haveForgottenPassword: '¿Has oblidat la teva contrasenya?',
signUp: 'Registrar-me',
notACustomerYet: `Encara no ets client?`,

View File

@ -153,7 +153,8 @@ export default {
save: 'Save',
cancel: 'Cancel',
of: 'of',
loginAsGuest: 'Login as guest',
logInAsGuest: 'Login as guest',
logIn: 'Log in',
haveForgottenPassword: 'Have you forgotten your password?',
signUp: 'Sign up',
notACustomerYet: 'Not a customer yet?',

View File

@ -108,7 +108,7 @@ export default {
Connections: 'Conexiones',
Visits: 'Visitas',
News: 'Noticias',
Photos: 'Imágenes',
Photos: 'Fotos',
Items: 'Artículos',
Account: 'Cuenta',
Addresses: 'Direcciones'

View File

@ -120,6 +120,7 @@ export default {
emptyList: 'Vider la liste',
confirmDelete: 'Voulez-vous vraiment supprimer la ligne?',
logInAsGuest: `Entrez en tant qu'invité`,
logIn: 'Se connecter',
haveForgottenPassword: 'Avez-vous oublié votre mot de passe?',
signUp: `S'inscrire`,
notACustomerYet: `Pas encore client?`,

View File

@ -117,6 +117,7 @@ export default {
confirmDelete: 'Tens certeza que queres eliminar esta linha?',
emptyList: 'Lista vazia',
logInAsGuest: 'Entrar como convidado',
logIn: 'Iniciar sessão',
haveForgottenPassword: 'Esqueceu a senha?',
signUp: 'Registar',
notACustomerYet: 'Ainda não é cliente?',

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, onMounted, computed } from 'vue';
import { ref, onMounted } from 'vue';
import { storeToRefs } from 'pinia';
import { useRouter } from 'vue-router';
@ -10,19 +10,19 @@ import { useAppStore } from 'stores/app';
const router = useRouter();
const userStore = useUserStore();
const appStore = useAppStore();
const hiddenMenuItems = new Set(['Reports']);
const refreshContentKey = ref(0);
const { mainUser, supplantedUser } = storeToRefs(userStore);
const { menuEssentialLinks, title, subtitle, useRightDrawer, rightDrawerOpen } =
storeToRefs(appStore);
const {
menuTitle,
subtitle,
useRightDrawer,
rightDrawerOpen,
filteredMenuItems
} = storeToRefs(appStore);
const actions = ref(null);
const leftDrawerOpen = ref(false);
const filteredMenuItems = computed(() =>
menuEssentialLinks.value.filter(
item => !hiddenMenuItems.has(item.description)
)
);
const toggleLeftDrawer = () => {
leftDrawerOpen.value = !leftDrawerOpen.value;
};
@ -58,7 +58,7 @@ const logoutSupplantedUser = async () => {
@click="toggleLeftDrawer"
/>
<QToolbarTitle>
{{ title }}
{{ menuTitle }}
<div v-if="subtitle" class="subtitle text-caption">
{{ subtitle }}
</div>

View File

@ -57,6 +57,15 @@ const formatMailData = data => {
data.isToBeMailed = Boolean(data.isToBeMailed);
};
const updateConfigLang = async lang => {
try {
await vnFormRef.value.submit();
userStore.updateUserLang(lang);
} catch (error) {
console.error(error);
}
};
onMounted(() => fetchLanguagesSql());
</script>
@ -113,9 +122,7 @@ onMounted(() => fetchLanguagesSql());
option-label="name"
option-value="code"
:options="langOptions"
@update:model-value="
userStore.updateUserLang(data.lang)
"
@update:model-value="updateConfigLang(data.lang)"
/>
</template>
<template #extraForm>

View File

@ -1,6 +1,6 @@
<template>
<Teleport v-if="isHeaderMounted" to="#actions">
<div class="q-gutter-x-sm row">
<div class="row">
<VnSearchBar :search-term="search" @on-search-error="items = []" />
<QBtn
:icon="viewTypeButtonContent.icon"
@ -24,6 +24,15 @@
{{ t('shoppingCart') }}
</QTooltip>
</QBtn>
<QBtn
v-if="!isDesktop"
flat
dense
round
icon="menu"
aria-label="Menu"
@click="toggleRightDrawer()"
/>
</div>
</Teleport>
<div style="padding-bottom: 5em">
@ -290,7 +299,7 @@ const appStore = useAppStore();
const userStore = useUserStore();
const route = useRoute();
const router = useRouter();
const { isHeaderMounted, rightDrawerOpen, basketOrderId } =
const { isHeaderMounted, rightDrawerOpen, basketOrderId, isDesktop } =
storeToRefs(appStore);
const { isGuest } = storeToRefs(userStore);
const { notify } = useNotify();
@ -617,7 +626,7 @@ const getItemFamilies = async () => {
JOIN vn.itemTypeL10n l ON l.id = t.id
WHERE t.order >= 0
AND t.categoryFk = #category
ORDER BY t.order, l.name;
ORDER BY t.order, l.name ASC;
DROP TEMPORARY TABLE tmp.itemAvailable`,
{
category: selectedCategory.value,
@ -641,7 +650,7 @@ const getItemColors = async () => {
JOIN tmp.itemAvailable a ON a.id = i.id
JOIN vn.inkL10n l ON l.id = i.inkFk
WHERE (${queryFilter.value})
ORDER BY name;
ORDER BY name ASC;
DROP TEMPORARY TABLE tmp.itemAvailable;`,
{
orderId: basketOrderId.value
@ -674,7 +683,7 @@ const getProducers = async () => {
JOIN tmp.itemAvailable a ON a.id = i.id
JOIN vn.producer p ON p.id = i.producerFk
WHERE (${queryFilter.value})
ORDER BY name;
ORDER BY name ASC;
DROP TEMPORARY TABLE tmp.itemAvailable;`,
{ orderId: basketOrderId.value }
);
@ -695,7 +704,7 @@ const getOrigins = async () => {
JOIN vn.origin o ON o.id = i.originFk
JOIN vn.originL10n l ON l.id = o.id
WHERE (${queryFilter.value})
ORDER BY name;
ORDER BY name ASC;
DROP TEMPORARY TABLE tmp.itemAvailable;`,
{ orderId: basketOrderId.value }
);
@ -714,7 +723,7 @@ const getSubcategories = async () => {
JOIN vn.itemType t ON t.id = i.typeFk
JOIN tmp.itemAvailable a ON a.id = i.id
WHERE (${queryFilter.value})
ORDER BY category;
ORDER BY category ASC;
DROP TEMPORARY TABLE tmp.itemAvailable;`,
{ orderId: basketOrderId.value }
);
@ -915,6 +924,10 @@ const redirectToBasket = () => {
router.push({ name: 'basket' });
};
const toggleRightDrawer = () => {
rightDrawerOpen.value = !rightDrawerOpen.value;
};
watch(
() => route.query.search,
val => {

View File

@ -5,17 +5,16 @@ import { useI18n } from 'vue-i18n';
import TicketDetails from 'src/pages/Ecomerce/TicketDetails.vue';
import { useUserStore } from 'stores/user';
import { useAppStore } from 'stores/app';
import { storeToRefs } from 'pinia';
import { usePrintService } from 'src/composables/usePrintService';
const { t } = useI18n();
const jApi = inject('jApi');
const route = useRoute();
const userStore = useUserStore();
const appStore = useAppStore();
const { isHeaderMounted } = storeToRefs(appStore);
const { user, token } = storeToRefs(userStore);
const { openReport } = usePrintService();
const ticket = ref({});
const rows = ref([]);
@ -38,16 +37,8 @@ onMounted(async () => {
);
});
const onPrintClick = () => {
const params = new URLSearchParams({
access_token: token.value,
recipientId: user.value.id,
type: 'deliveryNote'
});
window.open(
`/api/Tickets/${ticket.value.id}/delivery-note-pdf?${params.toString()}`
);
};
const onPrintClick = () =>
openReport(`Tickets/${ticket.value.id}/delivery-note-pdf`, {}, '_blank');
</script>
<template>

View File

@ -5,14 +5,18 @@ import { useI18n } from 'vue-i18n';
import { useUserStore } from 'stores/user';
import useNotify from 'src/composables/useNotify.js';
import { useRouter, useRoute } from 'vue-router';
import { storeToRefs } from 'pinia';
import { useAppStore } from 'src/stores/app';
const { notify } = useNotify();
const { t } = useI18n();
const { locale } = useI18n({ useScope: 'global' });
const userStore = useUserStore();
const appStore = useAppStore();
const route = useRoute();
const router = useRouter();
const { siteLang, localeOptions } = storeToRefs(appStore);
const email = ref(null);
const password = ref(null);
const remember = ref(false);
@ -20,12 +24,11 @@ const showPwd = ref(false);
const selectedLocaleValue = computed({
get() {
return userStore.localeOptions.find(
option => option.lang === locale.value
).value;
return siteLang.value;
},
set(value) {
locale.value = value;
appStore.updateSiteLocale(value);
}
});
@ -44,7 +47,6 @@ onMounted(() => {
const onLogin = async () => {
await userStore.fetchUser();
await userStore.updateUserLang(selectedLocaleValue.value);
await router.push({ name: 'home' });
};
@ -99,7 +101,7 @@ const loginAsGuest = async () => {
<QSelect
data-testid="switchLanguage"
v-model="selectedLocaleValue"
:options="userStore.localeOptions"
:options="localeOptions"
:label="t('language')"
option-value="lang"
dense

View File

@ -7,7 +7,6 @@ import {
createWebHashHistory
} from 'vue-router';
import routes from './routes';
import { i18n } from 'src/boot/i18n';
/*
* If not building with SSR mode, you can
@ -40,10 +39,9 @@ export default route(function (/* { store, ssrContext } */) {
Router.afterEach((to, from) => {
if (from.name === to.name) return;
const app = useAppStore();
app.$patch({
title: i18n.global.t(
to.meta.title ? `titles.${to.meta.title}` : 'titles.Home'
),
title: to.meta.title || 'Home',
subtitle: null,
useRightDrawer: false,
rightDrawerOpen: true

View File

@ -6,6 +6,7 @@ import { useQuasar } from 'quasar';
const { notify } = useNotify();
const storageOrderName = 'hederaBasket';
const { t } = i18n.global;
export const useAppStore = defineStore('hedera', {
state: () => ({
@ -16,15 +17,23 @@ export const useAppStore = defineStore('hedera', {
rightDrawerOpen: false,
isHeaderMounted: false,
menuEssentialLinks: [],
hiddenMenuLinks: new Set(['Reports']),
basketOrderId: null,
localeDates: {
days: [],
months: [],
daysShort: [],
monthsShort: []
}
},
siteLang: null,
localeOptions: [
{ label: t('langs.en'), lang: 'en-US', value: 'en' },
{ label: t('langs.es'), lang: 'es-ES', value: 'es' },
{ label: t('langs.ca'), lang: 'ca-ES', value: 'ca' },
{ label: t('langs.fr'), lang: 'fr-FR', value: 'fr' },
{ label: t('langs.pt'), lang: 'pt-PT', value: 'pt' }
]
}),
actions: {
async getMenuLinks() {
const sections = await jApi.query('SELECT * FROM myMenu');
@ -51,7 +60,6 @@ export const useAppStore = defineStore('hedera', {
this.menuEssentialLinks = sectionTree;
},
async loadConfig() {
const imageUrl = await jApi.getValue('SELECT url FROM imageConfig');
this.$patch({ imageUrl });
@ -68,6 +76,7 @@ export const useAppStore = defineStore('hedera', {
},
async init() {
this.updateSiteLocale(localStorage.getItem('siteLang') || 'es-ES');
this.getBasketOrderId();
this.getLocaleDates();
},
@ -144,9 +153,24 @@ export const useAppStore = defineStore('hedera', {
onLogout() {
this.unloadOrder();
this.menuEssentialLinks = [];
},
updateSiteLocale(locale = null) {
const _locale = locale || 'es-ES';
i18n.global.locale.value = _locale;
this.siteLang = _locale;
localStorage.setItem('siteLang', _locale);
}
},
getters: {
filteredMenuItems: state => {
return (state.menuEssentialLinks || []).filter(
item => !state.hiddenMenuLinks.has(item.description)
);
},
siteLocaleOption: state =>
state.localeOptions.find(l => l.value === state.siteLang),
menuTitle: state => t(`titles.${state.title}`),
isMobile() {
const $q = useQuasar();
return $q?.screen?.width <= 768;

View File

@ -1,26 +1,21 @@
import { defineStore } from 'pinia';
import { ref, computed, watch } from 'vue';
import { api, jApi } from 'boot/axios';
import { i18n } from 'src/boot/i18n';
import useNotify from 'src/composables/useNotify.js';
import { useAppStore } from 'src/stores/app.js';
const { t } = i18n.global;
const { notify } = useNotify();
const TOKEN_MULTIMEDIA = 'tokenMultimedia';
const TOKEN = 'token';
export const useUserStore = defineStore('user', () => {
const token = ref('');
const tokenMultimedia = ref('');
const isGuest = ref(false);
const user = ref(null); // Usuario en uso => supplantedUser || mainUser
const supplantedUser = ref(null); // Usuario suplantado
const mainUser = ref(null); // Usuario principal logueado
const localeOptions = ref([
{ label: t('langs.en'), lang: 'en-US', value: 'en' },
{ label: t('langs.es'), lang: 'es-ES', value: 'es' },
{ label: t('langs.ca'), lang: 'ca-ES', value: 'ca' },
{ label: t('langs.fr'), lang: 'fr-FR', value: 'fr' },
{ label: t('langs.pt'), lang: 'pt-PT', value: 'pt' }
]);
const keepLogin = ref(false);
const intervalId = ref(null);
const isCheckingToken = ref(false);
@ -28,9 +23,6 @@ export const useUserStore = defineStore('user', () => {
let router;
const loggedIn = computed(() => !!token.value);
const userLocaleOption = computed(() =>
localeOptions.value?.find(l => l.value === user.value?.lang)
);
const storage = computed(() =>
keepLogin.value ? localStorage : sessionStorage
);
@ -48,21 +40,29 @@ export const useUserStore = defineStore('user', () => {
await fetchTokenConfig();
await fetchUser();
await supplantInit();
updateSiteLocale();
startInterval();
};
const getToken = () => {
const tokenValue =
sessionStorage.getItem('vnToken') ||
localStorage.getItem('vnToken');
sessionStorage.getItem(TOKEN) || localStorage.getItem(TOKEN);
token.value = tokenValue;
return tokenValue;
};
const setToken = _token => {
storage.value.setItem('vnToken', _token);
const getTokenMultimedia = () => {
const tokenMultimediaValue =
sessionStorage.getItem(TOKEN_MULTIMEDIA) ||
localStorage.getItem(TOKEN_MULTIMEDIA);
tokenMultimedia.value = tokenMultimediaValue;
return tokenMultimediaValue;
};
const setToken = ({ _token, _tokenMultimedia }) => {
storage.value.setItem(TOKEN, _token);
storage.value.setItem(TOKEN_MULTIMEDIA, _tokenMultimedia);
token.value = _token;
tokenMultimedia.value = _tokenMultimedia;
};
const destroyToken = async (url, storageType, key) => {
@ -106,18 +106,39 @@ export const useUserStore = defineStore('user', () => {
};
const setSession = data => {
setToken({
_token: data.token,
_tokenMultimedia: data.tokenMultimedia
});
storage.value.setItem('hederaLastUser', data.username);
storage.value.setItem('created', data.created);
storage.value.setItem('ttl', data.ttl);
localStorage.setItem('keepLogin', keepLogin.value);
};
const fetchMultimediaToken = async data => {
const {
data: { multimediaToken }
} = await api.get('VnUsers/ShareToken', {
headers: { Authorization: data.token }
});
return multimediaToken;
};
const login = async (username, password, remember) => {
const params = { user: username, password };
const { data } = await api.post('Accounts/login', params);
const multimediaToken = await fetchMultimediaToken(data);
if (!multimediaToken) return;
keepLogin.value = remember;
storage.value.setItem('hederaLastUser', username);
setToken(data.token);
setSession({ created: Date.now(), ...data });
setSession({
created: Date.now(),
tokenMultimedia: multimediaToken.id,
username,
...data
});
await fetchTokenConfig();
startInterval();
};
@ -164,7 +185,16 @@ export const useUserStore = defineStore('user', () => {
const tokenData = await api.post('VnUsers/renewToken', {
headers: { Authorization: _token }
});
setToken(tokenData.data.id);
const _tokenMultimedia = getTokenMultimedia();
const tokenMultimedia = await api.post('VnUsers/renewToken', {
headers: { Authorization: _tokenMultimedia }
});
setToken({
_token: tokenData.data.id,
_tokenMultimedia: tokenMultimedia.data.id
});
};
const checkValidity = async () => {
@ -235,17 +265,9 @@ export const useUserStore = defineStore('user', () => {
await fetchUser();
};
const updateSiteLocale = (locale = null) => {
i18n.global.locale.value =
locale || userLocaleOption.value?.lang || 'en-US';
};
const updateUserLang = async lang => {
if (!user.value || user.value.lang === lang) return;
user.value.lang = lang;
updateSiteLocale();
notify(t('dataSaved'), 'positive');
};
const $reset = () => {
@ -269,19 +291,19 @@ export const useUserStore = defineStore('user', () => {
return {
token,
tokenMultimedia,
isGuest,
user,
supplantedUser,
mainUser,
localeOptions,
keepLogin,
intervalId,
isCheckingToken,
tokenConfig,
loggedIn,
userLocaleOption,
storage,
getToken,
getTokenMultimedia,
setToken,
destroyToken,
destroy,
@ -298,7 +320,6 @@ export const useUserStore = defineStore('user', () => {
supplantUser,
supplantInit,
logoutSupplantedUser,
updateSiteLocale,
updateUserLang,
init,
$reset