diff --git a/src/boot/mainShortcutMixin.js b/src/boot/mainShortcutMixin.js new file mode 100644 index 000000000..481077e37 --- /dev/null +++ b/src/boot/mainShortcutMixin.js @@ -0,0 +1,36 @@ +import routes from 'src/router/modules'; +import { useRouter } from 'vue-router'; + +let isNotified = false; + +export default { + created: function () { + const router = useRouter(); + const keyBindingMap = routes + .filter((route) => route.meta.keyBinding) + .reduce((map, route) => { + map['Key' + route.meta.keyBinding.toUpperCase()] = route.path; + return map; + }, {}); + + const handleKeyDown = (event) => { + const { ctrlKey, altKey, code } = event; + + if (ctrlKey && altKey && keyBindingMap[code] && !isNotified) { + event.preventDefault(); + router.push(keyBindingMap[code]); + isNotified = true; + } + }; + + const handleKeyUp = (event) => { + const { ctrlKey, altKey } = event; + if (!ctrlKey || !altKey) { + isNotified = false; + } + }; + + window.addEventListener('keydown', handleKeyDown); + window.addEventListener('keyup', handleKeyUp); + }, +}; diff --git a/src/boot/qformMixin.js b/src/boot/qformMixin.js index fc7852369..8a75e1af7 100644 --- a/src/boot/qformMixin.js +++ b/src/boot/qformMixin.js @@ -1,30 +1,52 @@ -import { getCurrentInstance } from 'vue'; - +function focusFirstInput(input) { + input.focus(); + return; +} export default { mounted: function () { - const vm = getCurrentInstance(); - if (vm.type.name === 'QForm') { - if (!['searchbarForm', 'filterPanelForm'].includes(this.$el?.id)) { - // TODO: AUTOFOCUS IS NOT FOCUSING - const that = this; - this.$el.addEventListener('keyup', function (evt) { - if (evt.key === 'Enter') { - const input = evt.target; - if (input.type == 'textarea' && evt.shiftKey) { - evt.preventDefault(); - let { selectionStart, selectionEnd } = input; - input.value = - input.value.substring(0, selectionStart) + - '\n' + - input.value.substring(selectionEnd); - selectionStart = selectionEnd = selectionStart + 1; - return; - } - evt.preventDefault(); - that.onSubmit(); - } - }); + const that = this; + + const form = document.querySelector('.q-form#formModel'); + if (!form) return; + try { + const inputsFormCard = form.querySelectorAll( + `input:not([disabled]):not([type="checkbox"])` + ); + if (inputsFormCard.length) { + focusFirstInput(inputsFormCard[0]); } + const textareas = document.querySelectorAll( + 'textarea:not([disabled]), [contenteditable]:not([disabled])' + ); + if (textareas.length) { + focusFirstInput(textareas[textareas.length - 1]); + } + const inputs = document.querySelectorAll( + 'form#formModel input:not([disabled]):not([type="checkbox"])' + ); + const input = inputs[0]; + if (!input) return; + + focusFirstInput(input); + } catch (error) { + console.error(error); } + form.addEventListener('keyup', function (evt) { + if (evt.key === 'Enter') { + const input = evt.target; + if (input.type == 'textarea' && evt.shiftKey) { + evt.preventDefault(); + let { selectionStart, selectionEnd } = input; + input.value = + input.value.substring(0, selectionStart) + + '\n' + + input.value.substring(selectionEnd); + selectionStart = selectionEnd = selectionStart + 1; + return; + } + evt.preventDefault(); + that.onSubmit(); + } + }); }, }; diff --git a/src/boot/quasar.js b/src/boot/quasar.js index 01fe68d8b..d375c2f69 100644 --- a/src/boot/quasar.js +++ b/src/boot/quasar.js @@ -3,11 +3,16 @@ import qFormMixin from './qformMixin'; import keyShortcut from './keyShortcut'; import useNotify from 'src/composables/useNotify.js'; import { CanceledError } from 'axios'; +import { QForm } from 'quasar'; +import { QLayout } from 'quasar'; +import mainShortcutMixin from './mainShortcutMixin'; const { notify } = useNotify(); export default boot(({ app }) => { - app.mixin(qFormMixin); + QForm.mixins = [qFormMixin]; + QLayout.mixins = [mainShortcutMixin]; + app.directive('shortcut', keyShortcut); app.config.errorHandler = (error) => { let message; diff --git a/src/components/LeftMenu.vue b/src/components/LeftMenu.vue index ab2931dfd..31ad9ebed 100644 --- a/src/components/LeftMenu.vue +++ b/src/components/LeftMenu.vue @@ -177,6 +177,7 @@ function normalize(text) { class="full-width" filled dense + autofocus /> diff --git a/src/components/common/VnSelectWorker.vue b/src/components/common/VnSelectWorker.vue new file mode 100644 index 000000000..b0fef4443 --- /dev/null +++ b/src/components/common/VnSelectWorker.vue @@ -0,0 +1,85 @@ + + + + + +es: + Responsible for approving invoices: Responsable de aprobar las facturas + diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index 754b084fc..2a84e5aa1 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -1,50 +1,10 @@ - diff --git a/src/pages/Customer/Card/CustomerBasicData.vue b/src/pages/Customer/Card/CustomerBasicData.vue index 1a86d9f31..768c66f32 100644 --- a/src/pages/Customer/Card/CustomerBasicData.vue +++ b/src/pages/Customer/Card/CustomerBasicData.vue @@ -8,7 +8,7 @@ import FormModel from 'components/FormModel.vue'; import VnRow from 'components/ui/VnRow.vue'; import VnInput from 'src/components/common/VnInput.vue'; import VnSelect from 'src/components/common/VnSelect.vue'; -import VnAvatar from 'src/components/ui/VnAvatar.vue'; +import VnSelectWorker from 'src/components/common/VnSelectWorker.vue'; import { getDifferences, getUpdatedValues } from 'src/filters'; const route = useRoute(); @@ -16,7 +16,6 @@ const { t } = useI18n(); const businessTypes = ref([]); const contactChannels = ref([]); -const title = ref(); const handleSalesModelValue = (val) => ({ or: [ { id: val }, @@ -117,41 +116,17 @@ function onBeforeSave(formData, originalData) { /> - - - - + /> { - { outlined rounded :input-debounce="0" - > - + /> diff --git a/src/pages/Customer/CustomerList.vue b/src/pages/Customer/CustomerList.vue index 865287aeb..e86e35966 100644 --- a/src/pages/Customer/CustomerList.vue +++ b/src/pages/Customer/CustomerList.vue @@ -2,7 +2,6 @@ import { ref, computed, markRaw } from 'vue'; import { useI18n } from 'vue-i18n'; import { useRouter } from 'vue-router'; -import VnSelect from 'src/components/common/VnSelect.vue'; import VnTable from 'components/VnTable/VnTable.vue'; import VnLocation from 'src/components/common/VnLocation.vue'; import VnSearchbar from 'components/ui/VnSearchbar.vue'; @@ -12,7 +11,7 @@ import RightMenu from 'src/components/common/RightMenu.vue'; import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue'; import { toDate } from 'src/filters'; import CustomerFilter from './CustomerFilter.vue'; -import VnAvatar from 'src/components/ui/VnAvatar.vue'; +import VnSelectWorker from 'src/components/common/VnSelectWorker.vue'; const { t } = useI18n(); const router = useRouter(); @@ -422,40 +421,17 @@ function handleLocation(data, location) { auto-load >