From 788ced37a157c6b53ce98117354c8329bcdb74fb Mon Sep 17 00:00:00 2001 From: Remko Date: Wed, 18 Dec 2024 09:32:37 +0100 Subject: [PATCH 1/4] added view contactmoment --- src/modals/Modals.vue | 3 + .../contactMomenten/ContactMomentenForm.vue | 51 +- .../contactMomenten/ViewContactMoment.vue | 1035 +++++++++++++++++ src/modals/zaken/ZaakForm.vue | 2 +- src/store/modules/navigation.ts | 7 + 5 files changed, 1092 insertions(+), 6 deletions(-) create mode 100644 src/modals/contactMomenten/ViewContactMoment.vue diff --git a/src/modals/Modals.vue b/src/modals/Modals.vue index 75895c0..da20130 100644 --- a/src/modals/Modals.vue +++ b/src/modals/Modals.vue @@ -14,6 +14,7 @@ import { navigationStore } from '../store/store.js' + @@ -55,6 +56,7 @@ import AddBerichtToZaak from './zaken/AddBerichtToZaak.vue' import AddTaakToZaak from './zaken/AddTaakToZaak.vue' import ContactMomentenForm from './contactMomenten/ContactMomentenForm.vue' import AddRolToZaak from './zaken/AddRolToZaak.vue' +import ViewContactMoment from './contactMomenten/ViewContactMoment.vue' export default { name: 'Modals', @@ -78,6 +80,7 @@ export default { AddTaakToZaak, ContactMomentenForm, AddRolToZaak, + ViewContactMoment, }, } diff --git a/src/modals/contactMomenten/ContactMomentenForm.vue b/src/modals/contactMomenten/ContactMomentenForm.vue index d296226..f1bc2aa 100644 --- a/src/modals/contactMomenten/ContactMomentenForm.vue +++ b/src/modals/contactMomenten/ContactMomentenForm.vue @@ -89,7 +89,7 @@ import { contactMomentStore, navigationStore, taakStore, zaakStore } from '../.. :disabled="loading" :loading="fetchLoading" type="primary" - @click="contactMomenten[i].klant = null"> + @click="removeKlant(i)"> @@ -131,6 +131,14 @@ import { contactMomentStore, navigationStore, taakStore, zaakStore } from '../.. + @@ -476,7 +484,7 @@ import { contactMomentStore, navigationStore, taakStore, zaakStore } from '../.. Klant taak aanmaken - + @@ -503,16 +511,22 @@ import { contactMomentStore, navigationStore, taakStore, zaakStore } from '../.. + + @@ -529,6 +543,7 @@ import getValidISOstring from '../../services/getValidISOstring.js' import SearchKlantModal from '../../modals/klanten/SearchKlantModal.vue' import EditTaak from '../../modals/taken/EditTaak.vue' import ZaakForm from '../../modals/zaken/ZaakForm.vue' +import ViewContactMoment from '../../modals/contactMomenten/ViewContactMoment.vue' // Entities import { ContactMoment } from '../../entities/index.js' @@ -542,6 +557,7 @@ import DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue' import Cancel from 'vue-material-design-icons/Cancel.vue' import Minus from 'vue-material-design-icons/Minus.vue' import ProgressClose from 'vue-material-design-icons/ProgressClose.vue' +import Eye from 'vue-material-design-icons/Eye.vue' export default { name: 'ContactMomentenForm', @@ -641,6 +657,9 @@ export default { taakFormOpen: false, taakClientType: 'both', zaakFormOpen: false, + viewContactMomentIsView: false, + viewContactMomentId: null, + isContactMomentFormOpen: false, tabs: [1], tabCounter: 1, @@ -821,6 +840,28 @@ export default { closeTaakForm() { this.taakFormOpen = false + this.fetchKlantData(this.contactMomenten[this.selectedContactMoment].klant.id) + }, + + viewContactMoment(id) { + this.isContactMomentFormOpen = true + this.viewContactMomentIsView = true + this.viewContactMomentId = id + navigationStore.setViewModal('viewContactMoment') + }, + + closeViewContactMomentModal() { + this.isContactMomentFormOpen = false + navigationStore.setViewModal(null) + }, + + removeKlant(i) { + this.contactMomenten[i].klant = null + this.contactMomenten[i].taken = null + this.contactMomenten[i].zaken = null + this.contactMomenten[i].berichten = null + this.contactMomenten[i].klantContactmomenten = null + this.contactMomenten[i].auditTrails = null }, // zaak functions @@ -831,7 +872,7 @@ export default { zaakFormSaveSuccess() { this.zaakFormOpen = false - this.fetchKlantData(this.klant.id) + this.fetchKlantData(this.contactMomenten[this.selectedContactMoment].klant.id) }, async closeContactMoment(id) { diff --git a/src/modals/contactMomenten/ViewContactMoment.vue b/src/modals/contactMomenten/ViewContactMoment.vue new file mode 100644 index 0000000..45fa866 --- /dev/null +++ b/src/modals/contactMomenten/ViewContactMoment.vue @@ -0,0 +1,1035 @@ + + + + + + + + + diff --git a/src/modals/zaken/ZaakForm.vue b/src/modals/zaken/ZaakForm.vue index 0d66c89..88ea9d3 100644 --- a/src/modals/zaken/ZaakForm.vue +++ b/src/modals/zaken/ZaakForm.vue @@ -191,7 +191,7 @@ export default { methods: { closeModal() { navigationStore.setModal(null) - this?.dashboardWidget && this.$emit('close') + this?.dashboardWidget && this.$emit('close-modal') }, fetchZaakType() { this.zaakTypeLoading = true diff --git a/src/store/modules/navigation.ts b/src/store/modules/navigation.ts index 3afe94d..57de284 100644 --- a/src/store/modules/navigation.ts +++ b/src/store/modules/navigation.ts @@ -4,6 +4,7 @@ import { defineStore } from 'pinia' interface NavigationStoreState { selected: 'dashboard' | 'berichten' | 'klanten' | 'rollen' | 'taken' | 'zaken' | 'zaakTypen' | 'search' | 'auditTrail' | 'contactMomenten' | 'medewerkers'; modal: string; + viewModal: string; dialog: string; transferData: string; } @@ -14,6 +15,8 @@ export const useNavigationStore = defineStore('ui', { selected: 'dashboard', // The currently active modal, managed trough the state to ensure that only one modal can be active at the same time modal: null, + // The currently active view modal, managed trough the state to ensure that only one view modal can be active at the same time + viewModal: null, // The currently active dialog dialog: null, // Any data needed in various models, dialogs, views which cannot be transferred through normal means or without writing bad/excessive code @@ -28,6 +31,10 @@ export const useNavigationStore = defineStore('ui', { this.modal = modal console.log('Active modal set to ' + modal) }, + setViewModal(modal: NavigationStoreState['modal']) { + this.viewModal = modal + console.log('Active modal set to ' + modal) + }, setDialog(dialog: NavigationStoreState['dialog']) { this.dialog = dialog console.log('Active dialog set to ' + dialog) From 261d6b1454ee0422ec7cdbda5315f0ed3ef1a5fd Mon Sep 17 00:00:00 2001 From: Thijn Date: Wed, 18 Dec 2024 11:45:48 +0100 Subject: [PATCH 2/4] fixed a bug while loading data in parralel if the result is 500 --- .../contactMomenten/ContactMomentenForm.vue | 70 ++++++++++++++----- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/src/modals/contactMomenten/ContactMomentenForm.vue b/src/modals/contactMomenten/ContactMomentenForm.vue index f1bc2aa..b980d6a 100644 --- a/src/modals/contactMomenten/ContactMomentenForm.vue +++ b/src/modals/contactMomenten/ContactMomentenForm.vue @@ -906,8 +906,33 @@ export default { this.contactMomenten[this.selectedContactMoment].klant = await klantResponse.json() } - // fetch all data in parallel - const [zakenRes, takenRes, berichtenRes, auditTrailRes, contactMomentenRes] = await Promise.all([ + /** + * This code block handles parallel fetching and parsing of multiple API endpoints in a fault-tolerant way. + * Here's what happens step by step: + * + * 1. First, we initiate 5 parallel fetch requests using Promise.allSettled(): + * - This allows all requests to run simultaneously rather than sequentially + * - Unlike Promise.all(), allSettled() won't fail if some requests fail + * - Each request fetches different data for the same klant ID (cases, tasks, messages etc) + * + * 2. Once all fetches complete (successfully or not), we process the responses: + * - results contains an array of 5 promise results + * - Each result is either {status: 'fulfilled', value: Response} or {status: 'rejected', reason: Error} + * + * 3. We then parse the JSON from successful responses using another Promise.allSettled(): + * - For each fulfilled fetch with ok status, we parse the JSON asynchronously + * - For failed fetches or non-ok responses, we return null + * - This creates another layer of fault tolerance during JSON parsing + * + * 4. Finally, we destructure the parsed results into separate variables: + * - Each variable gets either the parsed JSON data or null if any step failed + * - This gives us clean variables to work with, regardless of failures + * + * The end result is we get all our data in parallel, with proper error handling, + * and clean null values for any failed requests rather than thrown exceptions. + */ + // #1 + const results = await Promise.allSettled([ fetch(`/index.php/apps/zaakafhandelapp/api/klanten/${id}/zaken`), fetch(`/index.php/apps/zaakafhandelapp/api/klanten/${id}/taken`), fetch(`/index.php/apps/zaakafhandelapp/api/klanten/${id}/berichten`), @@ -915,45 +940,55 @@ export default { fetch(`/index.php/apps/zaakafhandelapp/api/klanten/${id}/contactmomenten`), ]) - // parse all data - const [zakenData, takenData, berichtenData, auditTrailData, contactMomentenData] = await Promise.all([ - zakenRes.json(), - takenRes.json(), - berichtenRes.json(), - auditTrailRes.json(), - contactMomentenRes.json(), - ]) + // #2 & #3 + const parsedResults = await Promise.allSettled( + results.map(async (result) => { + if (result.status === 'fulfilled' && result.value.ok) { + return await result.value.json() + } + return null + }), + ) + + // #4 + const [zakenData, takenData, berichtenData, auditTrailData, contactMomentenData] = parsedResults.map(result => + result.status === 'fulfilled' ? result.value : null, + ) - // set data - if (Array.isArray(zakenData.results)) { + // set data, checking for null values + if (zakenData?.results && Array.isArray(zakenData.results)) { if (this.isView) { this.zaken = zakenData.results } else { this.contactMomenten[this.selectedContactMoment].zaken = zakenData.results } } - if (Array.isArray(takenData.results)) { + + if (takenData?.results && Array.isArray(takenData.results)) { if (this.isView) { this.taken = takenData.results } else { this.contactMomenten[this.selectedContactMoment].taken = takenData.results } } - if (Array.isArray(berichtenData.results)) { + + if (berichtenData?.results && Array.isArray(berichtenData.results)) { if (this.isView) { this.berichten = berichtenData.results } else { this.contactMomenten[this.selectedContactMoment].berichten = berichtenData.results } } - if (Array.isArray(auditTrailData)) { + + if (auditTrailData && Array.isArray(auditTrailData)) { if (this.isView) { this.auditTrails = auditTrailData } else { this.contactMomenten[this.selectedContactMoment].auditTrails = auditTrailData } } - if (Array.isArray(contactMomentenData.results)) { + + if (contactMomentenData?.results && Array.isArray(contactMomentenData.results)) { if (this.isView) { this.klantContactmomenten = contactMomentenData.results } else { @@ -963,7 +998,8 @@ export default { } catch (error) { console.error('Error in fetchKlantData:', error) - throw error + // Don't throw the error, as we want the component to continue working + // even if some data failed to load } }, From 3c780d35c4c717a7d8103c017b1ce92921c58679 Mon Sep 17 00:00:00 2001 From: Remko Date: Wed, 18 Dec 2024 12:06:36 +0100 Subject: [PATCH 3/4] lint --- src/modals/contactMomenten/ContactMomentenForm.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modals/contactMomenten/ContactMomentenForm.vue b/src/modals/contactMomenten/ContactMomentenForm.vue index b6e9c79..cba982b 100644 --- a/src/modals/contactMomenten/ContactMomentenForm.vue +++ b/src/modals/contactMomenten/ContactMomentenForm.vue @@ -489,7 +489,9 @@ import { contactMomentStore, navigationStore, taakStore, zaakStore } from '../.. Klant taak aanmaken - + From 56b09b867f4e21d5707c47c3cd27a7d08598845a Mon Sep 17 00:00:00 2001 From: Remko Date: Wed, 18 Dec 2024 12:08:13 +0100 Subject: [PATCH 4/4] requested changes --- src/store/modules/navigation.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/store/modules/navigation.ts b/src/store/modules/navigation.ts index 57de284..79a521e 100644 --- a/src/store/modules/navigation.ts +++ b/src/store/modules/navigation.ts @@ -31,9 +31,9 @@ export const useNavigationStore = defineStore('ui', { this.modal = modal console.log('Active modal set to ' + modal) }, - setViewModal(modal: NavigationStoreState['modal']) { - this.viewModal = modal - console.log('Active modal set to ' + modal) + setViewModal(viewModal: NavigationStoreState['viewModal']) { + this.viewModal = viewModal + console.log('Active view modal set to ' + viewModal) }, setDialog(dialog: NavigationStoreState['dialog']) { this.dialog = dialog