From 6ae38d26119baf867d039ee29682ed26f360072f Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Mon, 29 Apr 2024 09:49:06 +0200 Subject: [PATCH 1/6] refactor: refs #6887 pending claim changes --- src/i18n/locale/en.yml | 3 +- src/i18n/locale/es.yml | 3 +- src/pages/Claim/Card/ClaimDescriptor.vue | 14 +- src/pages/Claim/Card/ClaimSummary.vue | 45 ++++++- src/pages/Zone/Card/ZoneDescriptor.vue | 127 ++++++++++++++++++ .../Zone/Card/ZoneDescriptorMenuItems.vue | 108 +++++++++++++++ src/pages/Zone/Card/ZoneDescriptorProxy.vue | 16 +++ 7 files changed, 309 insertions(+), 7 deletions(-) create mode 100644 src/pages/Zone/Card/ZoneDescriptor.vue create mode 100644 src/pages/Zone/Card/ZoneDescriptorMenuItems.vue create mode 100644 src/pages/Zone/Card/ZoneDescriptorProxy.vue diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index ff57bf968..942018b84 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -513,7 +513,7 @@ claim: records: records card: claimId: Claim ID - assignedTo: Assigned + attendedBy: Attended by created: Created state: State ticketId: Ticket ID @@ -551,6 +551,7 @@ claim: responsible: Responsible worker: Worker redelivery: Redelivery + changeState: Change state basicData: customer: Customer assignedTo: Assigned diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index f9278a9b0..3de5af50c 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -511,7 +511,7 @@ claim: records: registros card: claimId: ID reclamación - assignedTo: Asignada a + attendedBy: Atendida por created: Creada state: Estado ticketId: ID ticket @@ -549,6 +549,7 @@ claim: responsible: Responsable worker: Trabajador redelivery: Devolución + changeState: Cambiar estado basicData: customer: Cliente assignedTo: Asignada a diff --git a/src/pages/Claim/Card/ClaimDescriptor.vue b/src/pages/Claim/Card/ClaimDescriptor.vue index 968f1e294..3b5dd82b8 100644 --- a/src/pages/Claim/Card/ClaimDescriptor.vue +++ b/src/pages/Claim/Card/ClaimDescriptor.vue @@ -11,6 +11,7 @@ import VnLv from 'src/components/ui/VnLv.vue'; import useCardDescription from 'src/composables/useCardDescription'; import VnUserLink from 'src/components/ui/VnUserLink.vue'; import { getUrl } from 'src/composables/getUrl'; +import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue'; const $props = defineProps({ id: { @@ -127,17 +128,24 @@ onMounted(async () => { </VnLv> <VnLv v-if="entity.worker" - :label="t('claim.card.assignedTo')" + :label="t('claim.card.attendedBy')" :value="entity.worker.user.name" > <template #value> <VnUserLink - :name="entity.worker.user.name" + :name="entity.worker.user.nickname" :worker-id="entity.worker.id" /> </template> </VnLv> - <VnLv :label="t('claim.card.zone')" :value="entity.ticket?.zone?.name" /> + <VnLv :label="t('claim.card.zone')"> + <template #value> + <span class="link"> + {{ entity.ticket?.zone?.name }} + <ZoneDescriptorProxy :id="entity.ticket?.zoneFk" /> + </span> + </template> + </VnLv> <VnLv :label="t('claim.card.province')" :value="entity.ticket?.address?.province?.name" diff --git a/src/pages/Claim/Card/ClaimSummary.vue b/src/pages/Claim/Card/ClaimSummary.vue index f45d5765d..c4c2785d5 100644 --- a/src/pages/Claim/Card/ClaimSummary.vue +++ b/src/pages/Claim/Card/ClaimSummary.vue @@ -1,6 +1,6 @@ <script setup> import { onMounted, ref, computed } from 'vue'; -import { useRoute } from 'vue-router'; +import { useRoute, useRouter } from 'vue-router'; import { useI18n } from 'vue-i18n'; import { toDate, toCurrency } from 'src/filters'; import CardSummary from 'components/ui/CardSummary.vue'; @@ -13,8 +13,10 @@ import VnUserLink from 'src/components/ui/VnUserLink.vue'; import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; import VnTitle from 'src/components/common/VnTitle.vue'; import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue'; +import axios from 'axios'; const route = useRoute(); +const router = useRouter(); const { t } = useI18n(); const { getTokenMultimedia } = useSession(); const token = getTokenMultimedia(); @@ -27,7 +29,7 @@ const $props = defineProps({ }); const entityId = computed(() => $props.id || route.params.id); - +const ClaimStates = ref([]); const claimUrl = ref(); const salixUrl = ref(); const claimDmsRef = ref(); @@ -162,6 +164,10 @@ function openDialog(dmsId) { multimediaSlide.value = dmsId; multimediaDialog.value = true; } +async function changeState(value) { + await axios.patch(`Claims/updateClaim/${entityId.value}`, { claimStateFk: value }); + router.go(route.fullPath); +} </script> <template> @@ -171,6 +177,7 @@ function openDialog(dmsId) { @on-fetch="(data) => setClaimDms(data)" ref="claimDmsRef" /> + <FetchData url="ClaimStates" @on-fetch="(data) => (ClaimStates = data)" auto-load /> <CardSummary ref="summary" :url="`Claims/${entityId}/getSummary`" @@ -180,6 +187,36 @@ function openDialog(dmsId) { <template #header="{ entity: { claim } }"> {{ claim.id }} - {{ claim.client.name }} ({{ claim.client.id }}) </template> + <template #header-right> + <QBtnDropdown + side + top + color="black" + text-color="white" + :label="t('ticket.summary.changeState')" + > + <QList> + <QVirtualScroll + style="max-height: 300px" + :items="ClaimStates" + separator + v-slot="{ item, index }" + > + <QItem + :key="index" + dense + clickable + v-close-popup + @click="changeState(item.id)" + > + <QItemSection> + <QItemLabel>{{ item.description }}</QItemLabel> + </QItemSection> + </QItem> + </QVirtualScroll> + </QList> + </QBtnDropdown> + </template> <template #body="{ entity: { claim, salesClaimed, developments } }"> <QCard class="vn-one"> <VnTitle @@ -447,4 +484,8 @@ function openDialog(dmsId) { .zindex { z-index: 1; } + +.change-state { + width: 10%; +} </style> diff --git a/src/pages/Zone/Card/ZoneDescriptor.vue b/src/pages/Zone/Card/ZoneDescriptor.vue new file mode 100644 index 000000000..665cb6f0e --- /dev/null +++ b/src/pages/Zone/Card/ZoneDescriptor.vue @@ -0,0 +1,127 @@ +<script setup> +import { ref, computed } from 'vue'; +import { useRoute } from 'vue-router'; +import { useI18n } from 'vue-i18n'; + +import CardDescriptor from 'components/ui/CardDescriptor.vue'; +import VnLv from 'src/components/ui/VnLv.vue'; +import ZoneDescriptorMenuItems from './ZoneDescriptorMenuItems.vue'; + +import useCardDescription from 'src/composables/useCardDescription'; +import { toDate } from 'src/filters'; + +const $props = defineProps({ + id: { + type: Number, + required: false, + default: null, + }, +}); + +const route = useRoute(); +const { t } = useI18n(); + +const filter = { + fields: [ + 'id', + 'ref', + 'shipped', + 'landed', + 'totalEntries', + 'warehouseInFk', + 'warehouseOutFk', + 'cargoSupplierFk', + 'agencyModeFk', + ], + include: [ + { + relation: 'warehouseIn', + scope: { + fields: ['name'], + }, + }, + { + relation: 'warehouseOut', + scope: { + fields: ['name'], + }, + }, + ], +}; + +const entityId = computed(() => { + return $props.id || route.params.id; +}); + +const data = ref(useCardDescription()); + +const setData = (entity) => { + data.value = useCardDescription(entity.ref, entity.id); +}; +</script> + +<template> + <CardDescriptor + module="Zone" + :url="`Zones/${entityId}`" + :title="data.title" + :subtitle="data.subtitle" + :filter="filter" + @on-fetch="setData" + data-key="travelData" + > + <template #header-extra-action> + <QBtn + round + flat + dense + size="md" + icon="local_airport" + color="white" + class="link" + :to="{ name: 'ZoneList' }" + > + <QTooltip> + {{ t('Go to module index') }} + </QTooltip> + </QBtn> + </template> + <template #menu="{ entity }"> + <ZoneDescriptorMenuItems :travel="entity" /> + </template> + <template #body="{ entity }"> + <VnLv :label="t('globals.wareHouseIn')" :value="entity.warehouseIn.name" /> + <VnLv :label="t('globals.wareHouseOut')" :value="entity.warehouseOut.name" /> + <VnLv :label="t('globals.shipped')" :value="toDate(entity.shipped)" /> + <VnLv :label="t('globals.landed')" :value="toDate(entity.landed)" /> + <VnLv :label="t('globals.totalEntries')" :value="entity.totalEntries" /> + </template> + <template #actions="{ entity }"> + <QCardActions> + <QBtn + :to="{ + name: 'ZoneList', + query: { + params: JSON.stringify({ + agencyModeFk: entity.agencyModeFk, + }), + }, + }" + size="md" + icon="local_airport" + color="primary" + > + <QTooltip>{{ t('All travels with current agency') }}</QTooltip> + </QBtn> + </QCardActions> + </template> + </CardDescriptor> +</template> + +<i18n> +es: + Go to module index: Ir al índice del módulo + The travel will be deleted: El envío será eliminado + Do you want to delete this travel?: ¿Quieres eliminar este envío? + All travels with current agency: Todos los envíos con la agencia actual +</i18n> diff --git a/src/pages/Zone/Card/ZoneDescriptorMenuItems.vue b/src/pages/Zone/Card/ZoneDescriptorMenuItems.vue new file mode 100644 index 000000000..920d83dfe --- /dev/null +++ b/src/pages/Zone/Card/ZoneDescriptorMenuItems.vue @@ -0,0 +1,108 @@ +<script setup> +import { computed } from 'vue'; +import { useQuasar } from 'quasar'; +import { useRouter } from 'vue-router'; +import { useI18n } from 'vue-i18n'; + +import VnConfirm from 'components/ui/VnConfirm.vue'; + +import axios from 'axios'; +import useNotify from 'src/composables/useNotify.js'; +import { useRole } from 'src/composables/useRole'; + +const $props = defineProps({ + travel: { + type: Object, + default: () => {}, + }, +}); + +const { t } = useI18n(); +const router = useRouter(); +const quasar = useQuasar(); +const { notify } = useNotify(); +const role = useRole(); + +const redirectToCreateView = (queryParams) => { + router.push({ name: 'ZoneCreate', query: { travelData: queryParams } }); +}; + +const cloneZone = () => { + const stringifiedZoneData = JSON.stringify($props.travel); + redirectToCreateView(stringifiedZoneData); +}; + +const cloneZoneWithEntries = () => { + try { + axios.post(`Zones/${$props.travel.id}/cloneWithEntries`); + notify('globals.dataSaved', 'positive'); + } catch (err) { + console.err('Error cloning travel with entries'); + } +}; + +const isBuyer = computed(() => { + return role.hasAny(['buyer']); +}); + +const openDeleteEntryDialog = (id) => { + quasar + .dialog({ + component: VnConfirm, + componentProps: { + title: t('The travel will be deleted'), + message: t('Do you want to delete this travel?'), + }, + }) + .onOk(async () => { + await deleteZone(id); + }); +}; + +const deleteZone = async (id) => { + try { + await axios.delete(`Zones/${id}`); + router.push({ name: 'ZoneList' }); + notify('globals.dataDeleted', 'positive'); + } catch (err) { + console.error('Error deleting travel'); + } +}; +</script> + +<template> + <QItem v-ripple clickable @click="cloneZone(travel)"> + <QItemSection>{{ t('travel.summary.cloneShipping') }}</QItemSection> + </QItem> + <QItem v-ripple clickable @click="cloneZoneWithEntries()"> + <QItemSection> + {{ t('travel.summary.CloneZoneAndEntries') }} + </QItemSection> + </QItem> + <QItem + v-if="isBuyer && travel.totalEntries === 0" + v-ripple + clickable + @click="openDeleteEntryDialog(travel.id)" + > + <QItemSection> + {{ t('travel.summary.deleteZone') }} + </QItemSection> + </QItem> + <QItem v-ripple clickable> + <QItemSection> + <RouterLink + :to="{ name: 'EntryCreate', query: { travelFk: travel.id } }" + class="color-vn-text" + > + {{ t('travel.summary.AddEntry') }} + </RouterLink> + </QItemSection> + </QItem> +</template> + +<i18n> +es: + The travel will be deleted: El envío será eliminado + Do you want to delete this travel?: ¿Quieres eliminar este envío? +</i18n> diff --git a/src/pages/Zone/Card/ZoneDescriptorProxy.vue b/src/pages/Zone/Card/ZoneDescriptorProxy.vue new file mode 100644 index 000000000..15c5fb0e5 --- /dev/null +++ b/src/pages/Zone/Card/ZoneDescriptorProxy.vue @@ -0,0 +1,16 @@ +<script setup> +import ZoneDescriptor from './ZoneDescriptor.vue'; + +const $props = defineProps({ + id: { + type: Number, + required: true, + }, +}); +</script> + +<template> + <QPopupProxy> + <ZoneDescriptor v-if="$props.id" :id="$props.id" /> + </QPopupProxy> +</template> From a5d6ca447bb37092b259aab3cc32ffa729eed0e2 Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Mon, 29 Apr 2024 12:12:20 +0200 Subject: [PATCH 2/6] fix: TicketSummary.packages label --- src/pages/Ticket/Card/TicketSummary.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Ticket/Card/TicketSummary.vue b/src/pages/Ticket/Card/TicketSummary.vue index 364ae04a6..af501240b 100644 --- a/src/pages/Ticket/Card/TicketSummary.vue +++ b/src/pages/Ticket/Card/TicketSummary.vue @@ -188,7 +188,7 @@ async function changeState(value) { :label="t('ticket.summary.landed')" :value="toDate(ticket.landed)" /> - <VnLv :label="t('global.packages')" :value="ticket.packages" /> + <VnLv :label="t('globals.packages')" :value="ticket.packages" /> <VnLv :value="ticket.address.phone"> <template #label> {{ t('ticket.summary.consigneePhone') }} From 5b15558dbf4dd017c0588ffd64cf2f64307799a4 Mon Sep 17 00:00:00 2001 From: Jon <jon@verdnatura.es> Date: Tue, 30 Apr 2024 10:32:32 +0200 Subject: [PATCH 3/6] refactor: refs #6887 fixed errors --- src/css/app.scss | 9 -- src/i18n/locale/en.yml | 6 + src/i18n/locale/es.yml | 6 + src/pages/Claim/Card/ClaimDescriptor.vue | 5 +- src/pages/Claim/Card/ClaimSummary.vue | 6 +- src/pages/Zone/Card/ZoneCard.vue | 6 + src/pages/Zone/Card/ZoneDescriptor.vue | 72 ++++------- src/router/modules/index.js | 2 + src/router/modules/zone.js | 158 +++++++++++++++++++++++ src/router/routes.js | 2 + src/stores/useNavigationStore.js | 1 + 11 files changed, 212 insertions(+), 61 deletions(-) create mode 100644 src/pages/Zone/Card/ZoneCard.vue create mode 100644 src/router/modules/zone.js diff --git a/src/css/app.scss b/src/css/app.scss index 770df8e01..2e524e693 100644 --- a/src/css/app.scss +++ b/src/css/app.scss @@ -141,15 +141,6 @@ select:-webkit-autofill { background-color: var(--vn-section-color); } -.q-checkbox { - & .q-checkbox__label { - color: var(--vn-text-color); - } - & .q-checkbox__inner { - color: var(--vn-label-color); - } -} - .tr-header { color: var(--vn-label-color); } diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index 942018b84..7a341dded 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -1166,6 +1166,12 @@ item: type: Type intrastat: Intrastat origin: Origin +zone: + pageTitles: + zones: Zone + zonesList: Zones + deliveryList: Delivery days + upcomingList: Upcoming deliveries components: topbar: {} itemsFilterPanel: diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index 3de5af50c..9286cbccb 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -1165,6 +1165,12 @@ item: type: Tipo intrastat: Intrastat origin: Origen +zone: + pageTitles: + zones: Zona + zonesList: Zonas + deliveryList: Días de entrega + upcomingList: Próximos repartos components: topbar: {} itemsFilterPanel: diff --git a/src/pages/Claim/Card/ClaimDescriptor.vue b/src/pages/Claim/Card/ClaimDescriptor.vue index 3b5dd82b8..aae999117 100644 --- a/src/pages/Claim/Card/ClaimDescriptor.vue +++ b/src/pages/Claim/Card/ClaimDescriptor.vue @@ -74,8 +74,9 @@ const filter = { const STATE_COLOR = { pending: 'warning', - managed: 'info', + incomplete: 'info', resolved: 'positive', + canceled: 'negative', }; function stateColor(code) { return STATE_COLOR[code]; @@ -142,7 +143,7 @@ onMounted(async () => { <template #value> <span class="link"> {{ entity.ticket?.zone?.name }} - <ZoneDescriptorProxy :id="entity.ticket?.zoneFk" /> + <ZoneDescriptorProxy :id="entity.ticket?.zone?.id" /> </span> </template> </VnLv> diff --git a/src/pages/Claim/Card/ClaimSummary.vue b/src/pages/Claim/Card/ClaimSummary.vue index c4c2785d5..36a26008e 100644 --- a/src/pages/Claim/Card/ClaimSummary.vue +++ b/src/pages/Claim/Card/ClaimSummary.vue @@ -14,6 +14,7 @@ import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; import VnTitle from 'src/components/common/VnTitle.vue'; import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue'; import axios from 'axios'; +import dashIfEmpty from 'src/filters/dashIfEmpty'; const route = useRoute(); const router = useRouter(); @@ -101,8 +102,9 @@ const detailsColumns = ref([ const STATE_COLOR = { pending: 'warning', - managed: 'info', + incomplete: 'info', resolved: 'positive', + canceled: 'negative', }; function stateColor(code) { return STATE_COLOR[code]; @@ -260,7 +262,7 @@ async function changeState(value) { </VnLv> <VnLv :label="t('claim.basicData.pickup')" - :value="t(`claim.basicData.${claim.pickup}`)" + :value="`${dashIfEmpty(claim.pickup)}`" /> </QCard> <QCard class="vn-three"> diff --git a/src/pages/Zone/Card/ZoneCard.vue b/src/pages/Zone/Card/ZoneCard.vue new file mode 100644 index 000000000..948636c55 --- /dev/null +++ b/src/pages/Zone/Card/ZoneCard.vue @@ -0,0 +1,6 @@ +<script setup> +import VnCard from 'components/common/VnCard.vue'; +</script> +<template> + <VnCard data-key="Zone" base-url="Zones" /> +</template> diff --git a/src/pages/Zone/Card/ZoneDescriptor.vue b/src/pages/Zone/Card/ZoneDescriptor.vue index 665cb6f0e..b56443c84 100644 --- a/src/pages/Zone/Card/ZoneDescriptor.vue +++ b/src/pages/Zone/Card/ZoneDescriptor.vue @@ -8,7 +8,6 @@ import VnLv from 'src/components/ui/VnLv.vue'; import ZoneDescriptorMenuItems from './ZoneDescriptorMenuItems.vue'; import useCardDescription from 'src/composables/useCardDescription'; -import { toDate } from 'src/filters'; const $props = defineProps({ id: { @@ -22,28 +21,11 @@ const route = useRoute(); const { t } = useI18n(); const filter = { - fields: [ - 'id', - 'ref', - 'shipped', - 'landed', - 'totalEntries', - 'warehouseInFk', - 'warehouseOutFk', - 'cargoSupplierFk', - 'agencyModeFk', - ], include: [ { - relation: 'warehouseIn', + relation: 'agencyMode', scope: { - fields: ['name'], - }, - }, - { - relation: 'warehouseOut', - scope: { - fields: ['name'], + fields: ['name', 'id'], }, }, ], @@ -58,6 +40,13 @@ const data = ref(useCardDescription()); const setData = (entity) => { data.value = useCardDescription(entity.ref, entity.id); }; + +function extractHour(dateTime) { + const date = new Date(dateTime); + const hours = date.getHours().toString().padStart(2, '0'); + const minutes = date.getMinutes().toString().padStart(2, '0'); + return `${hours}:${minutes}`; +} </script> <template> @@ -76,52 +65,39 @@ const setData = (entity) => { flat dense size="md" - icon="local_airport" + icon="preview" color="white" class="link" :to="{ name: 'ZoneList' }" > <QTooltip> - {{ t('Go to module index') }} + {{ t('Summary') }} </QTooltip> </QBtn> </template> <template #menu="{ entity }"> - <ZoneDescriptorMenuItems :travel="entity" /> + <ZoneDescriptorMenuItems :zone="entity" /> </template> <template #body="{ entity }"> - <VnLv :label="t('globals.wareHouseIn')" :value="entity.warehouseIn.name" /> - <VnLv :label="t('globals.wareHouseOut')" :value="entity.warehouseOut.name" /> - <VnLv :label="t('globals.shipped')" :value="toDate(entity.shipped)" /> - <VnLv :label="t('globals.landed')" :value="toDate(entity.landed)" /> - <VnLv :label="t('globals.totalEntries')" :value="entity.totalEntries" /> - </template> - <template #actions="{ entity }"> - <QCardActions> - <QBtn - :to="{ - name: 'ZoneList', - query: { - params: JSON.stringify({ - agencyModeFk: entity.agencyModeFk, - }), - }, - }" - size="md" - icon="local_airport" - color="primary" - > - <QTooltip>{{ t('All travels with current agency') }}</QTooltip> - </QBtn> - </QCardActions> + {{ console.log('entity', entity) }} + <VnLv :label="t('Agency')" :value="entity.agencyMode.name" /> + <VnLv :label="t('Closing hour')" :value="extractHour(entity.hour)" /> + <VnLv :label="t('traveling days')" :value="entity.travelingDays" /> + <VnLv :label="t('Price')" :value="entity.price" /> + <VnLv :label="t('Bonus')" :value="entity.bonus" /> </template> </CardDescriptor> </template> <i18n> es: - Go to module index: Ir al índice del módulo + Summary: Detalles The travel will be deleted: El envío será eliminado Do you want to delete this travel?: ¿Quieres eliminar este envío? All travels with current agency: Todos los envíos con la agencia actual + Agency: Agencia + Closing hour: Hora de cierre + traveling days: Días de viaje + Price: Precio + Bonus: Bonificación </i18n> diff --git a/src/router/modules/index.js b/src/router/modules/index.js index 302ba7fe0..2fe40038f 100644 --- a/src/router/modules/index.js +++ b/src/router/modules/index.js @@ -15,6 +15,7 @@ import Department from './department'; import Entry from './entry'; import roadmap from './roadmap'; import Parking from './parking'; +import Zone from './zone'; export default [ Item, @@ -34,4 +35,5 @@ export default [ Entry, roadmap, Parking, + Zone, ]; diff --git a/src/router/modules/zone.js b/src/router/modules/zone.js new file mode 100644 index 000000000..bd74a76f3 --- /dev/null +++ b/src/router/modules/zone.js @@ -0,0 +1,158 @@ +import { RouterView } from 'vue-router'; + +export default { + path: '/zone', + name: 'Zone', + meta: { + title: 'zones', + icon: 'vn:zone', + moduleName: 'Zone', + }, + component: RouterView, + redirect: { name: 'ZoneMain' }, + menus: { + main: ['ZoneList' /*'ZoneDeliveryList', 'ZoneUpcomingList'*/], + card: [ + // + ], + }, + children: [ + { + path: '/zone', + name: 'ZoneMain', + component: () => import('src/pages/Zone/ZoneMain.vue'), + redirect: { name: 'ZoneList' }, + children: [ + { + path: 'list', + name: 'ZoneList', + meta: { + title: 'zonesList', + icon: 'vn:zone', + }, + component: () => import('src/pages/Zone/ZoneList.vue'), + }, + // { + // path: 'create', + // name: 'ZoneCreate', + // meta: { + // title: 'zoneCreate', + // icon: 'create', + // }, + // component: () => import('src/pages/Zone/ZoneCreate.vue'), + // }, + // { + // path: ':id/edit', + // name: 'ZoneEdit', + // meta: { + // title: 'zoneEdit', + // icon: 'edit', + // }, + // component: () => import('src/pages/Zone/ZoneCreate.vue'), + // }, + // { + // path: 'counter', + // name: 'ZoneCounter', + // meta: { + // title: 'zoneCounter', + // icon: 'add_circle', + // }, + // component: () => import('src/pages/Zone/ZoneCounter.vue'), + // }, + ], + }, + { + name: 'ZoneCard', + path: ':id', + component: () => import('src/pages/Zone/Card/ZoneCard.vue'), + redirect: { name: 'ZoneSummary' }, + children: [ + { + name: 'ZoneSummary', + path: 'summary', + meta: { + title: 'summary', + icon: 'launch', + }, + component: () => import('src/pages/Zone/Card/ZoneSummary.vue'), + }, + // { + // path: '/zone/delivery', + // name: 'ZoneDeliveryMain', + // component: () => import('src/pages/Zone/ZoneMain.vue'), + // redirect: { name: 'ZoneDeliveryList' }, + // children: [ + // { + // path: 'list', + // name: 'ZoneDeliveryList', + // meta: { + // title: 'deliveryList', + // icon: 'today', + // }, + // component: () => + // import('src/pages/Zone/Delivery/ZoneDeliveryList.vue'), + // }, + // { + // path: 'create', + // name: 'ZoneDeliveryCreate', + // meta: { + // title: 'deliveryCreate', + // icon: 'create', + // }, + // component: () => + // import('src/pages/Zone/Delivery/ZoneDeliveryCreate.vue'), + // }, + // { + // path: ':id/edit', + // name: 'ZoneDeliveryEdit', + // meta: { + // title: 'deliveryEdit', + // icon: 'edit', + // }, + // component: () => + // import('src/pages/Zone/Delivery/ZoneDeliveryCreate.vue'), + // }, + // ], + // }, + // { + // path: '/zone/upcoming', + // name: 'ZoneUpcomingMain', + // component: () => import('src/pages/Zone/ZoneMain.vue'), + // redirect: { name: 'ZoneUpcomingList' }, + // children: [ + // { + // path: 'list', + // name: 'ZoneUpcomingList', + // meta: { + // title: 'upcomingList', + // icon: 'today', + // }, + // component: () => + // import('src/pages/Zone/Upcoming/ZoneUpcomingList.vue'), + // }, + // { + // path: 'create', + // name: 'ZoneUpcomingCreate', + // meta: { + // title: 'upcomingCreate', + // icon: 'create', + // }, + // component: () => + // import('src/pages/Zone/Upcoming/ZoneUpcomingCreate.vue'), + // }, + // { + // path: ':id/edit', + // name: 'ZoneUpcomingEdit', + // meta: { + // title: 'upcomingEdit', + // icon: 'edit', + // }, + // component: () => + // import('src/pages/Zone/Upcoming/ZoneUpcomingCreate.vue'), + // }, + // ], + // }, + ], + }, + ], +}; diff --git a/src/router/routes.js b/src/router/routes.js index 51e726a62..14bf6665f 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -15,6 +15,7 @@ import order from 'src/router/modules/order'; import entry from 'src/router/modules/entry'; import roadmap from 'src/router/modules/roadmap'; import parking from 'src/router/modules/parking'; +import zone from 'src/router/modules/zone'; const routes = [ { @@ -71,6 +72,7 @@ const routes = [ roadmap, entry, parking, + zone, { path: '/:catchAll(.*)*', name: 'NotFound', diff --git a/src/stores/useNavigationStore.js b/src/stores/useNavigationStore.js index f075301f6..ee1e04e9b 100644 --- a/src/stores/useNavigationStore.js +++ b/src/stores/useNavigationStore.js @@ -21,6 +21,7 @@ export const useNavigationStore = defineStore('navigationStore', () => { 'ticket', 'worker', 'wagon', + 'zone', ]; const pinnedModules = ref([]); const role = useRole(); From a512f094d6950375135b4d0d5d9e7d337c497a5f Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Tue, 30 Apr 2024 12:06:24 +0200 Subject: [PATCH 4/6] perf: ZoneDescriptor --- src/pages/Zone/Card/ZoneDescriptor.vue | 16 +- .../Zone/Card/ZoneDescriptorMenuItems.vue | 143 ++++++++---------- 2 files changed, 72 insertions(+), 87 deletions(-) diff --git a/src/pages/Zone/Card/ZoneDescriptor.vue b/src/pages/Zone/Card/ZoneDescriptor.vue index b56443c84..486e4f063 100644 --- a/src/pages/Zone/Card/ZoneDescriptor.vue +++ b/src/pages/Zone/Card/ZoneDescriptor.vue @@ -57,7 +57,7 @@ function extractHour(dateTime) { :subtitle="data.subtitle" :filter="filter" @on-fetch="setData" - data-key="travelData" + data-key="zoneData" > <template #header-extra-action> <QBtn @@ -75,14 +75,14 @@ function extractHour(dateTime) { </QTooltip> </QBtn> </template> - <template #menu="{ entity }"> + <!-- <template #menu="{ entity }"> <ZoneDescriptorMenuItems :zone="entity" /> - </template> + </template> --> <template #body="{ entity }"> {{ console.log('entity', entity) }} <VnLv :label="t('Agency')" :value="entity.agencyMode.name" /> <VnLv :label="t('Closing hour')" :value="extractHour(entity.hour)" /> - <VnLv :label="t('traveling days')" :value="entity.travelingDays" /> + <VnLv :label="t('zoneing days')" :value="entity.zoneingDays" /> <VnLv :label="t('Price')" :value="entity.price" /> <VnLv :label="t('Bonus')" :value="entity.bonus" /> </template> @@ -92,12 +92,12 @@ function extractHour(dateTime) { <i18n> es: Summary: Detalles - The travel will be deleted: El envío será eliminado - Do you want to delete this travel?: ¿Quieres eliminar este envío? - All travels with current agency: Todos los envíos con la agencia actual + The zone will be deleted: El envío será eliminado + Do you want to delete this zone?: ¿Quieres eliminar este envío? + All zones with current agency: Todos los envíos con la agencia actual Agency: Agencia Closing hour: Hora de cierre - traveling days: Días de viaje + zoneing days: Días de viaje Price: Precio Bonus: Bonificación </i18n> diff --git a/src/pages/Zone/Card/ZoneDescriptorMenuItems.vue b/src/pages/Zone/Card/ZoneDescriptorMenuItems.vue index 920d83dfe..b6c7f28b3 100644 --- a/src/pages/Zone/Card/ZoneDescriptorMenuItems.vue +++ b/src/pages/Zone/Card/ZoneDescriptorMenuItems.vue @@ -1,108 +1,93 @@ <script setup> -import { computed } from 'vue'; import { useQuasar } from 'quasar'; import { useRouter } from 'vue-router'; import { useI18n } from 'vue-i18n'; +const { dialog, notify } = useQuasar(); import VnConfirm from 'components/ui/VnConfirm.vue'; import axios from 'axios'; -import useNotify from 'src/composables/useNotify.js'; -import { useRole } from 'src/composables/useRole'; const $props = defineProps({ - travel: { + zone: { type: Object, default: () => {}, }, }); const { t } = useI18n(); -const router = useRouter(); -const quasar = useQuasar(); -const { notify } = useNotify(); -const role = useRole(); +const { push, currentRoute } = useRouter(); +const zoneId = currentRoute.value.params.id; -const redirectToCreateView = (queryParams) => { - router.push({ name: 'ZoneCreate', query: { travelData: queryParams } }); -}; - -const cloneZone = () => { - const stringifiedZoneData = JSON.stringify($props.travel); - redirectToCreateView(stringifiedZoneData); -}; - -const cloneZoneWithEntries = () => { - try { - axios.post(`Zones/${$props.travel.id}/cloneWithEntries`); - notify('globals.dataSaved', 'positive'); - } catch (err) { - console.err('Error cloning travel with entries'); - } -}; - -const isBuyer = computed(() => { - return role.hasAny(['buyer']); -}); - -const openDeleteEntryDialog = (id) => { - quasar - .dialog({ - component: VnConfirm, - componentProps: { - title: t('The travel will be deleted'), - message: t('Do you want to delete this travel?'), - }, - }) - .onOk(async () => { - await deleteZone(id); - }); -}; - -const deleteZone = async (id) => { - try { - await axios.delete(`Zones/${id}`); - router.push({ name: 'ZoneList' }); - notify('globals.dataDeleted', 'positive'); - } catch (err) { - console.error('Error deleting travel'); - } +const actions = { + clone: async () => { + const opts = { message: t('Zone cloned'), type: 'positive' }; + let clonedZoneId; + + try { + const { data } = await axios.post(`Zones/${zoneId}/clone`, { + shipped: $props.zone.value.shipped, + }); + clonedZoneId = data; + } catch (e) { + opts.message = t('It was not able to clone the zone'); + opts.type = 'negative'; + } finally { + notify(opts); + + if (clonedZoneId) push({ name: 'ZoneSummary', params: { id: clonedZoneId } }); + } + }, + remove: async () => { + try { + await axios.post(`Zones/${zoneId}/setDeleted`); + + notify({ message: t('Zone deleted'), type: 'positive' }); + notify({ + message: t('You can undo this action within the first hour'), + icon: 'info', + }); + + push({ name: 'ZoneList' }); + } catch (e) { + notify({ message: e.message, type: 'negative' }); + } + }, }; +function openConfirmDialog(callback) { + dialog({ + component: VnConfirm, + componentProps: { + promise: actions[callback], + }, + }); +} </script> - <template> - <QItem v-ripple clickable @click="cloneZone(travel)"> - <QItemSection>{{ t('travel.summary.cloneShipping') }}</QItemSection> - </QItem> - <QItem v-ripple clickable @click="cloneZoneWithEntries()"> - <QItemSection> - {{ t('travel.summary.CloneZoneAndEntries') }} + <QItem @click="openConfirmDialog('clone')" v-ripple clickable> + <QItemSection avatar> + <QIcon name="content_copy" /> </QItemSection> + <QItemSection>{{ t('To clone zone') }}</QItemSection> </QItem> - <QItem - v-if="isBuyer && travel.totalEntries === 0" - v-ripple - clickable - @click="openDeleteEntryDialog(travel.id)" - > - <QItemSection> - {{ t('travel.summary.deleteZone') }} - </QItemSection> - </QItem> - <QItem v-ripple clickable> - <QItemSection> - <RouterLink - :to="{ name: 'EntryCreate', query: { travelFk: travel.id } }" - class="color-vn-text" - > - {{ t('travel.summary.AddEntry') }} - </RouterLink> + <QItem @click="openConfirmDialog('remove')" v-ripple clickable> + <QItemSection avatar> + <QIcon name="delete" /> </QItemSection> + <QItemSection>{{ t('deleteOrder') }}</QItemSection> </QItem> </template> <i18n> +en: + deleteOrder: Delete order + confirmDeletion: Confirm deletion + confirmDeletionMessage: Are you sure you want to delete this order? + es: - The travel will be deleted: El envío será eliminado - Do you want to delete this travel?: ¿Quieres eliminar este envío? + To clone zone: Clonar zone + deleteOrder: Eliminar pedido + confirmDeletion: Confirmar eliminación + confirmDeletionMessage: Seguro que quieres eliminar este pedido? + </i18n> From 167591980108fda44d1d7b1272d21e707b05c05a Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 2 May 2024 14:33:24 +0200 Subject: [PATCH 5/6] fix: minor build bugs --- src/pages/Claim/Card/ClaimBasicData.vue | 4 -- src/router/modules/zone.js | 92 +++++++++++++------------ 2 files changed, 47 insertions(+), 49 deletions(-) diff --git a/src/pages/Claim/Card/ClaimBasicData.vue b/src/pages/Claim/Card/ClaimBasicData.vue index be2efa31a..e2450a5e5 100644 --- a/src/pages/Claim/Card/ClaimBasicData.vue +++ b/src/pages/Claim/Card/ClaimBasicData.vue @@ -41,10 +41,6 @@ const claimStates = ref([]); const claimStatesCopy = ref([]); const optionsList = ref([]); -function setWorkers(data) { - workers.value = data; - workersCopy.value = data; -} const workersOptions = ref([]); function setClaimStates(data) { diff --git a/src/router/modules/zone.js b/src/router/modules/zone.js index bd74a76f3..079dfaa84 100644 --- a/src/router/modules/zone.js +++ b/src/router/modules/zone.js @@ -11,56 +11,58 @@ export default { component: RouterView, redirect: { name: 'ZoneMain' }, menus: { - main: ['ZoneList' /*'ZoneDeliveryList', 'ZoneUpcomingList'*/], + main: [ + /*'ZoneList', 'ZoneDeliveryList', 'ZoneUpcomingList'*/ + ], card: [ // ], }, children: [ - { - path: '/zone', - name: 'ZoneMain', - component: () => import('src/pages/Zone/ZoneMain.vue'), - redirect: { name: 'ZoneList' }, - children: [ - { - path: 'list', - name: 'ZoneList', - meta: { - title: 'zonesList', - icon: 'vn:zone', - }, - component: () => import('src/pages/Zone/ZoneList.vue'), - }, - // { - // path: 'create', - // name: 'ZoneCreate', - // meta: { - // title: 'zoneCreate', - // icon: 'create', - // }, - // component: () => import('src/pages/Zone/ZoneCreate.vue'), - // }, - // { - // path: ':id/edit', - // name: 'ZoneEdit', - // meta: { - // title: 'zoneEdit', - // icon: 'edit', - // }, - // component: () => import('src/pages/Zone/ZoneCreate.vue'), - // }, - // { - // path: 'counter', - // name: 'ZoneCounter', - // meta: { - // title: 'zoneCounter', - // icon: 'add_circle', - // }, - // component: () => import('src/pages/Zone/ZoneCounter.vue'), - // }, - ], - }, + // { + // path: '/zone', + // name: 'ZoneMain', + // component: () => import('src/pages/Zone/ZoneMain.vue'), + // redirect: { name: 'ZoneList' }, + // children: [ + // { + // path: 'list', + // name: 'ZoneList', + // meta: { + // title: 'zonesList', + // icon: 'vn:zone', + // }, + // component: () => import('src/pages/Zone/ZoneList.vue'), + // }, + // { + // path: 'create', + // name: 'ZoneCreate', + // meta: { + // title: 'zoneCreate', + // icon: 'create', + // }, + // component: () => import('src/pages/Zone/ZoneCreate.vue'), + // }, + // { + // path: ':id/edit', + // name: 'ZoneEdit', + // meta: { + // title: 'zoneEdit', + // icon: 'edit', + // }, + // component: () => import('src/pages/Zone/ZoneCreate.vue'), + // }, + // { + // path: 'counter', + // name: 'ZoneCounter', + // meta: { + // title: 'zoneCounter', + // icon: 'add_circle', + // }, + // component: () => import('src/pages/Zone/ZoneCounter.vue'), + // }, + // ], + // }, { name: 'ZoneCard', path: ':id', From 1a79bd6fb8a30637b49680dcf83b8b45006308db Mon Sep 17 00:00:00 2001 From: Javier Segarra <jsegarra@verdnatura.es> Date: Thu, 2 May 2024 14:40:56 +0200 Subject: [PATCH 6/6] feat: zoneSummary --- src/pages/Zone/Card/ZoneSummary.vue | 94 +++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/pages/Zone/Card/ZoneSummary.vue diff --git a/src/pages/Zone/Card/ZoneSummary.vue b/src/pages/Zone/Card/ZoneSummary.vue new file mode 100644 index 000000000..00df03cb0 --- /dev/null +++ b/src/pages/Zone/Card/ZoneSummary.vue @@ -0,0 +1,94 @@ +<script setup> +import { ref, onMounted, computed } from 'vue'; +import { useRoute } from 'vue-router'; +import { useI18n } from 'vue-i18n'; +import { dashIfEmpty } from 'src/filters'; +import { getUrl } from 'src/composables/getUrl'; +import VnLv from 'src/components/ui/VnLv.vue'; +import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue'; +import CardSummary from 'components/ui/CardSummary.vue'; +import VnUserLink from 'src/components/ui/VnUserLink.vue'; +import VnTitle from 'src/components/common/VnTitle.vue'; + +const route = useRoute(); +const { t } = useI18n(); + +const $props = defineProps({ + id: { + type: Number, + default: 0, + }, +}); + +const entityId = computed(() => $props.id || route.params.id); +const zoneUrl = ref(); + +onMounted(async () => { + zoneUrl.value = (await getUrl('')) + `zone/${entityId.value}/`; +}); + +const filter = computed(() => { + return { where: { id: entityId.value } }; +}); +</script> + +<template> + <CardSummary + data-key="zoneData" + ref="summary" + :url="`Zones/summary`" + :filter="filter" + > + <template #header="{ entity }"> + <div>{{ entity.id }} - {{ entity.firstName }} {{ entity.lastName }}</div> + </template> + <template #body="{ entity: zone }"> + <QCard class="vn-one"> + <VnTitle + :url="zoneUrl + `basic-data`" + :text="t('zone.summary.basicData')" + /> + <VnLv :label="t('zone.card.name')" :value="zone.user?.nickname" /> + <VnLv + :label="t('zone.list.department')" + :value="zone.department?.department?.name" + /> + <VnLv :label="t('zone.list.email')" :value="zone.user.email" copy /> + <VnLv :label="t('zone.summary.boss')" link> + <template #value> + <VnUserLink + v-if="zone.boss" + :name="dashIfEmpty(zone.boss?.name)" + :zone-id="zone.bossFk" + /> + </template> + </VnLv> + <VnLv :value="zone.mobileExtension"> + <template #label> + {{ t('zone.summary.phoneExtension') }} + <VnLinkPhone :phone-number="zone.mobileExtension" /> + </template> + </VnLv> + <VnLv :value="zone.phone"> + <template #label> + {{ t('zone.summary.entPhone') }} + <VnLinkPhone :phone-number="zone.phone" /> + </template> + </VnLv> + <VnLv :label="t('zone.summary.locker')" :value="zone.locker" /> + </QCard> + <QCard class="vn-one"> + <VnTitle :text="t('zone.summary.userData')" /> + <VnLv :label="t('zone.summary.userId')" :value="zone.user.id" /> + <VnLv :label="t('zone.card.name')" :value="zone.user.nickname" /> + <VnLv :label="t('zone.summary.role')" :value="zone.user.role.name" /> + <VnLv :value="zone?.sip?.extension"> + <template #label> + {{ t('zone.summary.sipExtension') }} + <VnLinkPhone :phone-number="zone?.sip?.extension" /> + </template> + </VnLv> + </QCard> + </template> + </CardSummary> +</template>