diff --git a/package-lock.json b/package-lock.json index 2e96d2ccf..a3a9dcc63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "salix-front", - "version": "23.36.01", + "version": "23.40.01", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/package.json b/package.json index b713c906a..3e26b483b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "salix-front", - "version": "23.36.01", + "version": "23.40.01", "description": "Salix frontend", "productName": "Salix", "author": "Verdnatura", @@ -9,7 +9,7 @@ "lint": "eslint --ext .js,.vue ./", "format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore", "test:e2e": "cypress open", - "test:e2e:ci": "cypress run --browser chromium", + "test:e2e:ci": "cd ../salix && gulp docker && cd ../salix-front && cypress run --browser chromium", "test": "echo \"See package.json => scripts for available tests.\" && exit 0", "test:unit": "vitest", "test:unit:ci": "vitest run" diff --git a/src/assets/logo.svg b/src/assets/salix.svg similarity index 100% rename from src/assets/logo.svg rename to src/assets/salix.svg diff --git a/src/assets/salix_dark.svg b/src/assets/salix_dark.svg new file mode 100644 index 000000000..10de3af4f --- /dev/null +++ b/src/assets/salix_dark.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/logo_icon.svg b/src/assets/salix_icon.svg similarity index 100% rename from src/assets/logo_icon.svg rename to src/assets/salix_icon.svg diff --git a/src/assets/vn.svg b/src/assets/vn.svg new file mode 100644 index 000000000..23b6df49c --- /dev/null +++ b/src/assets/vn.svg @@ -0,0 +1,158 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/vn_dark.svg b/src/assets/vn_dark.svg new file mode 100644 index 000000000..4d53b7b39 --- /dev/null +++ b/src/assets/vn_dark.svg @@ -0,0 +1,161 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/vn_icon.svg b/src/assets/vn_icon.svg new file mode 100644 index 000000000..738c8157c --- /dev/null +++ b/src/assets/vn_icon.svg @@ -0,0 +1,72 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/src/boot/axios.js b/src/boot/axios.js index bdc661ae2..c58cc2d08 100644 --- a/src/boot/axios.js +++ b/src/boot/axios.js @@ -46,7 +46,7 @@ const onResponseError = (error) => { message = responseError.message; } - switch (response.status) { + switch (response?.status) { case 500: message = 'errors.statusInternalServerError'; break; @@ -58,7 +58,7 @@ const onResponseError = (error) => { break; } - if (session.isLoggedIn() && response.status === 401) { + if (session.isLoggedIn() && response?.status === 401) { session.destroy(); const hash = window.location.hash; const url = hash.slice(1); diff --git a/src/components/CrudModel.vue b/src/components/CrudModel.vue index ed869a565..2a4982fce 100644 --- a/src/components/CrudModel.vue +++ b/src/components/CrudModel.vue @@ -8,6 +8,7 @@ import { useStateStore } from 'stores/useStateStore'; import VnPaginate from 'components/ui/VnPaginate.vue'; import VnConfirm from 'components/ui/VnConfirm.vue'; import SkeletonTable from 'components/ui/SkeletonTable.vue'; +import { tMobile } from 'src/composables/tMobile'; const quasar = useQuasar(); const stateStore = useStateStore(); @@ -62,9 +63,10 @@ const hasChanges = ref(false); const originalData = ref(); const vnPaginateRef = ref(); const formData = ref(); +const saveButtonRef = ref(null); const formUrl = computed(() => $props.url); -const emit = defineEmits(['onFetch', 'update:selected']); +const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']); defineExpose({ reload, @@ -73,12 +75,9 @@ defineExpose({ onSubmit, reset, hasChanges, + saveChanges, }); -function tMobile(...args) { - if (!quasar.platform.is.mobile) return t(...args); -} - async function fetch(data) { if (data && Array.isArray(data)) { let $index = 0; @@ -135,6 +134,7 @@ async function saveChanges(data) { hasChanges.value = false; isLoading.value = false; + emit('saveChanges', data); } async function insert() { @@ -269,7 +269,7 @@ watch(formUrl, async () => { - + { /> { :title="t('globals.save')" v-if="$props.defaultSave" /> + { {{ t('globals.changesToSave') }} - - - +
+ + + + + +
@@ -156,3 +171,12 @@ watch(formUrl, async () => { color="primary" /> + diff --git a/src/components/NavBar.vue b/src/components/NavBar.vue index 7d09b09b8..778f6bfb9 100644 --- a/src/components/NavBar.vue +++ b/src/components/NavBar.vue @@ -7,6 +7,7 @@ import { useStateStore } from 'stores/useStateStore'; import { useQuasar } from 'quasar'; import PinnedModules from './PinnedModules.vue'; import UserPanel from 'components/UserPanel.vue'; +import VnBreadcrumbs from './common/VnBreadcrumbs.vue'; const { t } = useI18n(); const session = useSession(); @@ -47,7 +48,7 @@ const pinnedModulesRef = ref(); > @@ -57,10 +58,7 @@ const pinnedModulesRef = ref(); - - {{ appName }} - - + @@ -112,6 +110,7 @@ const pinnedModulesRef = ref();
+ diff --git a/src/components/common/VnBreadcrumbs.vue b/src/components/common/VnBreadcrumbs.vue new file mode 100644 index 000000000..792671e21 --- /dev/null +++ b/src/components/common/VnBreadcrumbs.vue @@ -0,0 +1,82 @@ + + + diff --git a/src/components/common/VnSelectFilter.vue b/src/components/common/VnSelectFilter.vue index 9ccb94e33..55395f260 100644 --- a/src/components/common/VnSelectFilter.vue +++ b/src/components/common/VnSelectFilter.vue @@ -19,6 +19,8 @@ const $props = defineProps({ const { optionLabel, options } = toRefs($props); const myOptions = ref([]); const myOptionsOriginal = ref([]); +const vnSelectRef = ref(null); + function setOptions(data) { myOptions.value = JSON.parse(JSON.stringify(data)); myOptionsOriginal.value = JSON.parse(JSON.stringify(data)); @@ -29,6 +31,7 @@ const filter = (val, options) => { const search = val.toLowerCase(); if (val === '') return options; + return options.filter((row) => { const id = row.id; const name = row[$props.optionLabel].toLowerCase(); @@ -41,9 +44,17 @@ const filter = (val, options) => { }; const filterHandler = (val, update) => { - update(() => { - myOptions.value = filter(val, myOptionsOriginal.value); - }); + update( + () => { + myOptions.value = filter(val, myOptionsOriginal.value); + }, + (ref) => { + if (val !== '' && ref.options.length > 0) { + ref.setOptionIndex(-1); + ref.moveOptionSelection(1, true); + } + } + ); }; watch(options, (newValue) => { @@ -70,7 +81,15 @@ const value = computed({ map-options use-input @filter="filterHandler" - clearable - clear-icon="close" - /> + hide-selected + fill-input + ref="vnSelectRef" + > + + + diff --git a/src/components/ui/VnFilterPanel.vue b/src/components/ui/VnFilterPanel.vue index 68b3a7676..d78c3ba13 100644 --- a/src/components/ui/VnFilterPanel.vue +++ b/src/components/ui/VnFilterPanel.vue @@ -20,6 +20,10 @@ const props = defineProps({ required: false, default: null, }, + showAll: { + type: Boolean, + default: true, + }, }); const emit = defineEmits(['refresh', 'clear']); @@ -29,31 +33,34 @@ const store = arrayData.store; const userParams = ref({}); onMounted(() => { - if (props.params) userParams.value = props.params; - const params = store.userParams; - if (Object.keys(params).length > 0) { - userParams.value = Object.assign({}, params); + if (props.params) userParams.value = JSON.parse(JSON.stringify(props.params)); + if (Object.keys(store.userParams).length > 0) { + userParams.value = JSON.parse(JSON.stringify(store.userParams)); } }); const isLoading = ref(false); async function search() { - const params = userParams.value; - for (const param in params) { - if (params[param] === '' || params[param] === null) { + for (const param in userParams.value) { + if (userParams.value[param] === '' || userParams.value[param] === null) { delete userParams.value[param]; delete store.userParams[param]; } } - + const params = { ...userParams.value }; isLoading.value = true; await arrayData.addFilter({ params }); + if (!props.showAll && !Object.values(params).length) store.data = []; + isLoading.value = false; } async function reload() { isLoading.value = true; + const params = Object.values(userParams.value).filter((param) => param); + await arrayData.fetch({ append: false }); + if (!props.showAll && !params.length) store.data = []; isLoading.value = false; emit('refresh'); } @@ -62,6 +69,7 @@ async function clearFilters() { userParams.value = {}; isLoading.value = true; await arrayData.applyFilter({ params: {} }); + if (!props.showAll) store.data = []; isLoading.value = false; emit('clear'); diff --git a/src/components/ui/VnLogo.vue b/src/components/ui/VnLogo.vue new file mode 100644 index 000000000..3b955289d --- /dev/null +++ b/src/components/ui/VnLogo.vue @@ -0,0 +1,24 @@ + + + diff --git a/src/components/ui/VnPaginate.vue b/src/components/ui/VnPaginate.vue index 2475f56e9..d21d073f2 100644 --- a/src/components/ui/VnPaginate.vue +++ b/src/components/ui/VnPaginate.vue @@ -140,14 +140,6 @@ async function onLoad(...params) { {{ t('No data to display') }} -
-
- {{ t('No results found') }} -
-
+
+ +
+ + diff --git a/src/components/ui/VnSearchbar.vue b/src/components/ui/VnSearchbar.vue index af6999b5b..693d6fce2 100644 --- a/src/components/ui/VnSearchbar.vue +++ b/src/components/ui/VnSearchbar.vue @@ -105,7 +105,11 @@ async function search() { class="cursor-pointer" /> - + {{ props.info }} diff --git a/src/composables/getUrl.js b/src/composables/getUrl.js index e020d7f18..f2bd9ddb9 100644 --- a/src/composables/getUrl.js +++ b/src/composables/getUrl.js @@ -1,14 +1,11 @@ import axios from 'axios'; export async function getUrl(route, appName = 'salix') { - let url; const filter = { where: { and: [{ appName: appName }, { environment: process.env.NODE_ENV }] }, }; - await axios.get('Urls/findOne', { params: { filter } }).then((res) => { - url = res.data.url + route; - }); - - return url; + const { data } = await axios.get('Urls/findOne', { params: { filter } }); + const url = data.url; + return route ? url + route : url; } diff --git a/src/composables/tMobile.js b/src/composables/tMobile.js new file mode 100644 index 000000000..a6a000b81 --- /dev/null +++ b/src/composables/tMobile.js @@ -0,0 +1,8 @@ +import { useQuasar } from 'quasar'; +import { useI18n } from 'vue-i18n'; + +export function tMobile(...args) { + const quasar = useQuasar(); + const { t } = useI18n(); + if (!quasar.platform.is.mobile) return t(...args); +} diff --git a/src/composables/useArrayData.js b/src/composables/useArrayData.js index 4535cde0f..9aff0eaa8 100644 --- a/src/composables/useArrayData.js +++ b/src/composables/useArrayData.js @@ -136,7 +136,7 @@ export function useArrayData(key, userOptions) { } async function refresh() { - await fetch({ append: false }); + if (Object.values(store.userParams).length) await fetch({ append: false }); } function updateStateParams() { diff --git a/src/composables/useCamelCase.js b/src/composables/useCamelCase.js new file mode 100644 index 000000000..5285b022a --- /dev/null +++ b/src/composables/useCamelCase.js @@ -0,0 +1,3 @@ +export function useCamelCase(value) { + return value.replace(/[-_](.)/g, (_, char) => char.toUpperCase()); +} diff --git a/src/composables/useFirstUpper.js b/src/composables/useFirstUpper.js new file mode 100644 index 000000000..36378c05f --- /dev/null +++ b/src/composables/useFirstUpper.js @@ -0,0 +1,3 @@ +export function useFirstUpper(str) { + return str && str.charAt(0).toUpperCase() + str.substr(1); +} diff --git a/src/css/quasar.variables.scss b/src/css/quasar.variables.scss index 808bf3468..6a3700561 100644 --- a/src/css/quasar.variables.scss +++ b/src/css/quasar.variables.scss @@ -21,6 +21,7 @@ $positive: #21ba45; $negative: #c10015; $info: #31ccec; $warning: #f2c037; +$vnColor: #8ebb27; // Pendiente de cuadrar con la base de datos $success: $positive; diff --git a/src/i18n/en/index.js b/src/i18n/en/index.js index ed97a6155..4744aae9f 100644 --- a/src/i18n/en/index.js +++ b/src/i18n/en/index.js @@ -69,6 +69,11 @@ export default { twoFactor: 'Two-Factor', }, }, + verifyEmail: { + pageTitles: { + verifyEmail: 'Email verification', + }, + }, dashboard: { pageTitles: { dashboard: 'Dashboard', diff --git a/src/i18n/es/index.js b/src/i18n/es/index.js index 983043fe4..8a2b17f0d 100644 --- a/src/i18n/es/index.js +++ b/src/i18n/es/index.js @@ -69,6 +69,11 @@ export default { twoFactor: 'Doble factor', }, }, + verifyEmail: { + pageTitles: { + verifyEmail: 'Verificación de correo', + }, + }, dashboard: { pageTitles: { dashboard: 'Tablón', diff --git a/src/layouts/OutLayout.vue b/src/layouts/OutLayout.vue index 6ea14622f..f21e6e568 100644 --- a/src/layouts/OutLayout.vue +++ b/src/layouts/OutLayout.vue @@ -80,7 +80,7 @@ const langs = ['en', 'es'];
- +
@@ -97,15 +97,4 @@ const langs = ['en', 'es']; min-height: inherit; flex-direction: column; } - -.formCard { - max-width: 350px; - min-width: 300px; -} - -@media (max-width: $breakpoint-xs-max) { - .formCard { - min-width: 100%; - } -} diff --git a/src/pages/Claim/Card/ClaimBasicData.vue b/src/pages/Claim/Card/ClaimBasicData.vue index ddf669dd0..94e447e13 100644 --- a/src/pages/Claim/Card/ClaimBasicData.vue +++ b/src/pages/Claim/Card/ClaimBasicData.vue @@ -6,6 +6,7 @@ import { useI18n } from 'vue-i18n'; import { useSession } from 'src/composables/useSession'; import FetchData from 'components/FetchData.vue'; import FormModel from 'components/FormModel.vue'; +import VnRow from 'components/ui/VnRow.vue'; const route = useRoute(); const { t } = useI18n(); @@ -90,138 +91,119 @@ const statesFilter = { auto-load /> - -
- - - - - -
+ + + - - diff --git a/src/pages/Claim/Card/ClaimDevelopment.vue b/src/pages/Claim/Card/ClaimDevelopment.vue index ea4b178b5..0c83bdadd 100644 --- a/src/pages/Claim/Card/ClaimDevelopment.vue +++ b/src/pages/Claim/Card/ClaimDevelopment.vue @@ -1,12 +1,15 @@ diff --git a/src/pages/Claim/Card/ClaimLines.vue b/src/pages/Claim/Card/ClaimLines.vue index 8680ff922..c03291b85 100644 --- a/src/pages/Claim/Card/ClaimLines.vue +++ b/src/pages/Claim/Card/ClaimLines.vue @@ -40,7 +40,6 @@ const claimLinesForm = ref(); const claim = ref(null); async function onFetchClaim(data) { claim.value = data; - fetchMana(); } @@ -147,8 +146,11 @@ function showImportDialog() { quasar .dialog({ component: ClaimLinesImport, + componentProps: { + ticketId: claim.value.ticketFk, + }, }) - .onOk(() => arrayData.refresh()); + .onOk(() => claimLinesForm.value.reload()); } diff --git a/src/pages/Customer/CustomerPayments.vue b/src/pages/Customer/CustomerPayments.vue index 608aca2af..24e5efa39 100644 --- a/src/pages/Customer/CustomerPayments.vue +++ b/src/pages/Customer/CustomerPayments.vue @@ -110,12 +110,18 @@ function stateColor(row) {
- + - +
{{ t('Web Payments') }} @@ -138,7 +144,7 @@ function stateColor(row) { order="created DESC" :limit="20" :offset="50" - auto-load + :auto-load="!!$route?.query.params" >