From 718883ad6b91893eb96b206f426bc41876d25de9 Mon Sep 17 00:00:00 2001 From: Thijn Date: Fri, 27 Dec 2024 16:41:30 +0100 Subject: [PATCH] finished document --- src/entities/document/document.mock.ts | 76 +++++ src/entities/document/document.spec.ts | 12 + src/entities/document/document.ts | 185 ++++++++++++ src/entities/document/document.types.ts | 71 +++++ src/entities/document/index.js | 3 + src/entities/index.js | 1 + src/modals/Modals.vue | 7 + src/modals/documenten/DeleteDocument.vue | 100 +++++++ src/modals/documenten/DocumentForm.vue | 353 +++++++++++++++++++++++ src/store/modules/documenten.spec.ts | 36 +++ src/store/modules/documenten.ts | 205 +++++++++++++ src/store/store.js | 3 + src/views/documenten/ZaakDocumenten.vue | 124 ++++---- src/views/zaken/ZaakDetails.vue | 4 +- 14 files changed, 1121 insertions(+), 59 deletions(-) create mode 100644 src/entities/document/document.mock.ts create mode 100644 src/entities/document/document.spec.ts create mode 100644 src/entities/document/document.ts create mode 100644 src/entities/document/document.types.ts create mode 100644 src/entities/document/index.js create mode 100644 src/modals/documenten/DeleteDocument.vue create mode 100644 src/modals/documenten/DocumentForm.vue create mode 100644 src/store/modules/documenten.spec.ts create mode 100644 src/store/modules/documenten.ts diff --git a/src/entities/document/document.mock.ts b/src/entities/document/document.mock.ts new file mode 100644 index 0000000..2af2310 --- /dev/null +++ b/src/entities/document/document.mock.ts @@ -0,0 +1,76 @@ +import { Document } from './document' +import { TDocument } from './document.types' + +export const mockDocumentData = (): TDocument[] => [ + { + id: '15551d6f-44e3-43f3-a9d2-59e583c91eb0', + zaak: '550e8400-e29b-41d4-a716-446655440000', + url: 'https://example.com/documents/15551d6f-44e3-43f3-a9d2-59e583c91eb0', + identificatie: 'DOC-2023-001', + bronorganisatie: '123456789', + creatiedatum: '2023-01-01T00:00:00Z', + titel: 'Example Document', + vertrouwelijkheidaanduiding: 'openbaar', + auteur: 'John Doe', + status: 'definitief', + inhoudIsVervallen: false, + formaat: 'application/pdf', + taal: 'nld', + versie: 1, + beginRegistratie: '2023-01-01T00:00:00Z', + bestandsnaam: 'example.pdf', + inhoud: 'https://example.com/documents/15551d6f-44e3-43f3-a9d2-59e583c91eb0/download', + bestandsomvang: BigInt(1024), + link: 'https://example.com/viewer', + beschrijving: 'An example document', + indicatieGebruiksrecht: true, + verschijningsvorm: 'digitaal', + ondertekening: { + soort: 'digitaal', + datum: '2023-01-01T00:00:00Z', + }, + integriteit: { + algoritme: 'sha_256', + waarde: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', + datum: '2023-01-01T00:00:00Z', + }, + informatieobjecttype: 'https://example.com/catalogi/informatieobjecttypen/1', + locked: false, + bestandsdelen: [ + { + url: 'https://example.com/documents/15551d6f-44e3-43f3-a9d2-59e583c91eb0/parts/1', + volgnummer: 1, + omvang: 1024, + voltooid: true, + lock: '', + }, + ], + trefwoorden: ['example', 'test'], + _expand: { + informatieobjecttype: { + url: 'https://example.com/catalogi/informatieobjecttypen/1', + catalogus: 'https://example.com/catalogi/1', + omschrijving: 'Example Document Type', + vertrouwelijkheidaanduiding: 'openbaar', + beginGeldigheid: '2023-01-01', + eindeGeldigheid: null, + beginObject: null, + eindeObject: null, + concept: false, + zaaktypen: 'https://example.com/catalogi/zaaktypen/1', + besluittypen: ['https://example.com/catalogi/besluittypen/1'], + informatieobjectcategorie: 'example', + trefwoorden: ['example'], + omschrijvingGeneriek: { + informatieobjecttypeOmschrijvingGeneriek: 'Example Generic Description', + definitieInformatieobjecttypeOmschrijvingGeneriek: 'An example document type', + herkomstInformatieobjecttypeOmschrijvingGeneriek: 'KING', + hierarchieInformatieobjecttypeOmschrijvingGeneriek: 'parent', + opmerkingInformatieobjecttypeOmschrijvingGeneriek: null, + }, + }, + }, + }, +] + +export const mockDocument = (data: TDocument[] = mockDocumentData()): TDocument[] => data.map(item => new Document(item)) diff --git a/src/entities/document/document.spec.ts b/src/entities/document/document.spec.ts new file mode 100644 index 0000000..3af0ae9 --- /dev/null +++ b/src/entities/document/document.spec.ts @@ -0,0 +1,12 @@ +import { Document } from './document' +import { mockDocumentData } from './document.mock' + +describe('Document Entity', () => { + it('should create a Document entity with full data', () => { + const document = new Document(mockDocumentData()[0]) + + expect(document).toBeInstanceOf(Document) + expect(document).toEqual(mockDocumentData()[0]) + expect(document.validate().success).toBe(true) + }) +}) diff --git a/src/entities/document/document.ts b/src/entities/document/document.ts new file mode 100644 index 0000000..42b339e --- /dev/null +++ b/src/entities/document/document.ts @@ -0,0 +1,185 @@ +import { SafeParseReturnType, z } from 'zod' +import { TDocument } from './document.types' + +export class Document implements TDocument { + + public id: string + public zaak?: string + public url: string + public identificatie?: string + public bronorganisatie: string + public creatiedatum: string + public titel: string + public vertrouwelijkheidaanduiding?: 'openbaar' | 'beperkt_openbaar' | 'intern' | 'zaakvertrouwelijk' | 'vertrouwelijk' | 'confidentieel' | 'geheim' | 'zeer_geheim' + public auteur: string + public status?: 'in_bewerking' | 'ter_vaststelling' | 'definitief' | 'gearchiveerd' + public inhoudIsVervallen?: boolean + public formaat?: string + public taal: string + public versie: number + public beginRegistratie: string + public bestandsnaam?: string + public inhoud?: string + public bestandsomvang?: bigint + public link?: string + public beschrijving?: string + public ontvangstdatum?: string + public verzenddatum?: string + public indicatieGebruiksrecht?: boolean + public verschijningsvorm?: string + public ondertekening?: { + soort: 'analoog' | 'digitaal' | 'pki' + datum: string + } + + public integriteit?: { + algoritme: 'crc_16' | 'crc_32' | 'crc_64' | 'fletcher_4' | 'fletcher_8' | 'fletcher_16' | 'fletcher_32' | 'hmac' | 'md5' | 'sha_1' | 'sha_256' | 'sha_512' | 'sha_3' + waarde: string + datum: string + } + + public informatieobjecttype: string + public locked: boolean + public bestandsdelen: { + url: string + volgnummer: number + omvang: number + voltooid: boolean + lock: string + }[] + + public trefwoorden?: string[] + public _expand?: { + informatieobjecttype: { + url: string + catalogus: string + omschrijving: string + vertrouwelijkheidaanduiding: 'openbaar' | 'beperkt_openbaar' | 'intern' | 'zaakvertrouwelijk' | 'vertrouwelijk' | 'confidentieel' | 'geheim' | 'zeer_geheim' + beginGeldigheid: string + eindeGeldigheid?: string + beginObject?: string + eindeObject?: string + concept: boolean + zaaktypen: string + besluittypen: string[] + informatieobjectcategorie: string + trefwoorden?: string[] + omschrijvingGeneriek: { + informatieobjecttypeOmschrijvingGeneriek: string + definitieInformatieobjecttypeOmschrijvingGeneriek: string + herkomstInformatieobjecttypeOmschrijvingGeneriek: string + hierarchieInformatieobjecttypeOmschrijvingGeneriek: string + opmerkingInformatieobjecttypeOmschrijvingGeneriek?: string + } + } + } + + constructor(source: TDocument) { + this.id = source.id || '' + this.zaak = source.zaak || null + this.url = source.url || '' + this.identificatie = source.identificatie || null + this.bronorganisatie = source.bronorganisatie || '' + this.creatiedatum = source.creatiedatum || '' + this.titel = source.titel || '' + this.vertrouwelijkheidaanduiding = source.vertrouwelijkheidaanduiding || null + this.auteur = source.auteur || '' + this.status = source.status || null + this.inhoudIsVervallen = source.inhoudIsVervallen || null + this.formaat = source.formaat || null + this.taal = source.taal || '' + this.versie = source.versie || 0 + this.beginRegistratie = source.beginRegistratie || '' + this.bestandsnaam = source.bestandsnaam || null + this.inhoud = source.inhoud || null + this.bestandsomvang = source.bestandsomvang || null + this.link = source.link || null + this.beschrijving = source.beschrijving || null + this.ontvangstdatum = source.ontvangstdatum || null + this.verzenddatum = source.verzenddatum || null + this.indicatieGebruiksrecht = source.indicatieGebruiksrecht || null + this.verschijningsvorm = source.verschijningsvorm || null + this.ondertekening = source.ondertekening || null + this.integriteit = source.integriteit || null + this.informatieobjecttype = source.informatieobjecttype || '' + this.locked = source.locked || false + this.bestandsdelen = source.bestandsdelen || [] + this.trefwoorden = source.trefwoorden || null + this._expand = source._expand || null + } + + public validate(): SafeParseReturnType { + const schema = z.object({ + id: z.string(), + zaak: z.string().nullable(), + url: z.string().min(1).max(1000).url(), + identificatie: z.string().max(40).nullable(), + bronorganisatie: z.string().max(9), + creatiedatum: z.string(), + titel: z.string().max(200), + vertrouwelijkheidaanduiding: z.enum(['openbaar', 'beperkt_openbaar', 'intern', 'zaakvertrouwelijk', 'vertrouwelijk', 'confidentieel', 'geheim', 'zeer_geheim']).nullable(), + auteur: z.string().max(200), + status: z.enum(['in_bewerking', 'ter_vaststelling', 'definitief', 'gearchiveerd']).nullable(), + inhoudIsVervallen: z.boolean().nullable(), + formaat: z.string().max(255).nullable(), + taal: z.string().length(3), + versie: z.number(), + beginRegistratie: z.string(), + bestandsnaam: z.string().max(255).nullable(), + inhoud: z.string().url().nullable(), + bestandsomvang: z.bigint().nullable(), + link: z.string().max(200).nullable(), + beschrijving: z.string().max(1000).nullable(), + ontvangstdatum: z.string().nullable(), + verzenddatum: z.string().nullable(), + indicatieGebruiksrecht: z.boolean().nullable(), + verschijningsvorm: z.string().nullable(), + ondertekening: z.object({ + soort: z.enum(['analoog', 'digitaal', 'pki']), + datum: z.string(), + }).nullable(), + integriteit: z.object({ + algoritme: z.enum(['crc_16', 'crc_32', 'crc_64', 'fletcher_4', 'fletcher_8', 'fletcher_16', 'fletcher_32', 'hmac', 'md5', 'sha_1', 'sha_256', 'sha_512', 'sha_3']), + waarde: z.string().max(128), + datum: z.string(), + }).nullable(), + informatieobjecttype: z.string().max(200), + locked: z.boolean(), + bestandsdelen: z.array(z.object({ + url: z.string().min(1).max(1000).url(), + volgnummer: z.number(), + omvang: z.number(), + voltooid: z.boolean(), + lock: z.string(), + })), + trefwoorden: z.array(z.string()).nullable(), + _expand: z.object({ + informatieobjecttype: z.object({ + url: z.string().min(1).max(1000).url(), + catalogus: z.string(), + omschrijving: z.string().max(80), + vertrouwelijkheidaanduiding: z.enum(['openbaar', 'beperkt_openbaar', 'intern', 'zaakvertrouwelijk', 'vertrouwelijk', 'confidentieel', 'geheim', 'zeer_geheim']), + beginGeldigheid: z.string(), + eindeGeldigheid: z.string().nullable(), + beginObject: z.string().nullable(), + eindeObject: z.string().nullable(), + concept: z.boolean(), + zaaktypen: z.string(), + besluittypen: z.array(z.string()), + informatieobjectcategorie: z.string().max(80), + trefwoorden: z.array(z.string().max(30)).nullable(), + omschrijvingGeneriek: z.object({ + informatieobjecttypeOmschrijvingGeneriek: z.string().max(80), + definitieInformatieobjecttypeOmschrijvingGeneriek: z.string().max(255), + herkomstInformatieobjecttypeOmschrijvingGeneriek: z.string().max(12), + hierarchieInformatieobjecttypeOmschrijvingGeneriek: z.string().max(80), + opmerkingInformatieobjecttypeOmschrijvingGeneriek: z.string().max(255).nullable(), + }), + }), + }).nullable(), + }) + + return schema.safeParse(this) + } + +} diff --git a/src/entities/document/document.types.ts b/src/entities/document/document.types.ts new file mode 100644 index 0000000..89a7dc0 --- /dev/null +++ b/src/entities/document/document.types.ts @@ -0,0 +1,71 @@ +// https://vng-realisatie.github.io/gemma-zaken/standaard/documenten/redoc-1.5.0#tag/enkelvoudiginformatieobjecten/operation/enkelvoudiginformatieobject_retrieve + +export type TDocument = { + id: string; + zaak?: string; // zaak id property to link to a zaak, this is not in the gemma-zaken documentation + url: string; // min 1 character, max 1000 characters, string as uri + identificatie?: string; // max 40 characters + bronorganisatie: string; // max 9 characters + creatiedatum: string; // string as iso date time string + titel: string; // max 200 characters + vertrouwelijkheidaanduiding?: 'openbaar' | 'beperkt_openbaar' | 'intern' | 'zaakvertrouwelijk' | 'vertrouwelijk' | 'confidentieel' | 'geheim' | 'zeer_geheim'; + auteur: string; // max 200 characters + status?: 'in_bewerking' | 'ter_vaststelling' | 'definitief' | 'gearchiveerd'; + inhoudIsVervallen?: boolean; + formaat?: string; // max 255 characters + taal: string; // 3 characters, ISO 639-2/B language code + versie: number; + beginRegistratie: string; // string as iso date time string + bestandsnaam?: string; // max 255 characters + inhoud?: string; // string as uri + bestandsomvang?: bigint; // int64 + link?: string; // max 200 characters + beschrijving?: string; // max 1000 characters + ontvangstdatum?: string; // deprecated + verzenddatum?: string; // deprecated + indicatieGebruiksrecht?: boolean; + verschijningsvorm?: string; + ondertekening?: { + soort: 'analoog' | 'digitaal' | 'pki'; + datum: string; // string as iso date time string + }; + integriteit?: { + algoritme: 'crc_16' | 'crc_32' | 'crc_64' | 'fletcher_4' | 'fletcher_8' | 'fletcher_16' | 'fletcher_32' | 'hmac' | 'md5' | 'sha_1' | 'sha_256' | 'sha_512' | 'sha_3'; + waarde: string; // max 128 characters + datum: string; + }; + informatieobjecttype: string; // max 200 characters + locked: boolean; + bestandsdelen: { + url: string; // min 1 character, max 1000 characters, string as uri + volgnummer: number; + omvang: number; + voltooid: boolean; + lock: string; + }[]; + trefwoorden?: string[]; + _expand?: { + informatieobjecttype: { + url: string; // min 1 character, max 1000 characters, string as uri + catalogus: string; + omschrijving: string; // max 80 characters + vertrouwelijkheidaanduiding: 'openbaar' | 'beperkt_openbaar' | 'intern' | 'zaakvertrouwelijk' | 'vertrouwelijk' | 'confidentieel' | 'geheim' | 'zeer_geheim'; + beginGeldigheid: string; // string as iso date time string + eindeGeldigheid?: string; // string as iso date time string + beginObject?: string; // string as iso date time string + eindeObject?: string; // string as iso date time string + concept: boolean; + zaaktypen: string; + besluittypen: string[]; // string as uri, has to be unique + informatieobjectcategorie: string; // max 80 characters + trefwoorden?: string[]; // max 30 characters per string + omschrijvingGeneriek: { + informatieobjecttypeOmschrijvingGeneriek: string; // max 80 characters + definitieInformatieobjecttypeOmschrijvingGeneriek: string; // max 255 characters + herkomstInformatieobjecttypeOmschrijvingGeneriek: string; // max 12 characters + hierarchieInformatieobjecttypeOmschrijvingGeneriek: string; // max 80 characters + opmerkingInformatieobjecttypeOmschrijvingGeneriek?: string; // max 255 characters + } + } + } +} diff --git a/src/entities/document/index.js b/src/entities/document/index.js new file mode 100644 index 0000000..7b565d7 --- /dev/null +++ b/src/entities/document/index.js @@ -0,0 +1,3 @@ +export * from './document.ts' +export * from './document.types.ts' +export * from './document.mock.ts' diff --git a/src/entities/index.js b/src/entities/index.js index 4ba60de..d86674f 100644 --- a/src/entities/index.js +++ b/src/entities/index.js @@ -9,3 +9,4 @@ export * from './medewerkers/index.js' export * from './contactmoment/index.js' export * from './resultaat/index.js' export * from './besluit/index.js' +export * from './document/index.js' diff --git a/src/modals/Modals.vue b/src/modals/Modals.vue index b0d4e03..14dba05 100644 --- a/src/modals/Modals.vue +++ b/src/modals/Modals.vue @@ -39,6 +39,9 @@ import { navigationStore } from '../store/store.js' + + + @@ -67,6 +70,8 @@ import DeleteResultaat from './resultaten/DeleteResultaat.vue' import BesluitForm from './besluiten/BesluitForm.vue' import DeleteBesluit from './besluiten/DeleteBesluit.vue' import ViewContactMoment from './contactMomenten/ViewContactMoment.vue' +import DocumentForm from './documenten/DocumentForm.vue' +import DeleteDocument from './documenten/DeleteDocument.vue' export default { name: 'Modals', @@ -95,6 +100,8 @@ export default { BesluitForm, DeleteBesluit, ViewContactMoment, + DocumentForm, + DeleteDocument, }, } diff --git a/src/modals/documenten/DeleteDocument.vue b/src/modals/documenten/DeleteDocument.vue new file mode 100644 index 0000000..7f8a23a --- /dev/null +++ b/src/modals/documenten/DeleteDocument.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/src/modals/documenten/DocumentForm.vue b/src/modals/documenten/DocumentForm.vue new file mode 100644 index 0000000..c221857 --- /dev/null +++ b/src/modals/documenten/DocumentForm.vue @@ -0,0 +1,353 @@ + + + + + + + diff --git a/src/store/modules/documenten.spec.ts b/src/store/modules/documenten.spec.ts new file mode 100644 index 0000000..61550cb --- /dev/null +++ b/src/store/modules/documenten.spec.ts @@ -0,0 +1,36 @@ +/* eslint-disable no-console */ +import { setActivePinia, createPinia } from 'pinia' + +import { useDocumentStore } from './documenten.js' +import { Document, mockDocumentData } from '../../entities/index.js' + +describe('Document Store', () => { + beforeEach(() => { + setActivePinia(createPinia()) + }) + + it('sets document item correctly', () => { + const store = useDocumentStore() + + store.setDocumentItem(mockDocumentData()[0]) + + expect(store.documentItem).toBeInstanceOf(Document) + expect(store.documentItem).toEqual(mockDocumentData()[0]) + + expect(store.documentItem.validate().success).toBe(true) + }) + + it('sets documenten list correctly', () => { + const store = useDocumentStore() + + store.setDocumentenList(mockDocumentData()) + + expect(store.documentenList).toHaveLength(mockDocumentData().length) + + store.documentenList.forEach((item, index) => { + expect(item).toBeInstanceOf(Document) + expect(item).toEqual(mockDocumentData()[index]) + expect(item.validate().success).toBe(true) + }) + }) +}) diff --git a/src/store/modules/documenten.ts b/src/store/modules/documenten.ts new file mode 100644 index 0000000..cd9c40f --- /dev/null +++ b/src/store/modules/documenten.ts @@ -0,0 +1,205 @@ +import { defineStore } from 'pinia' +import { TDocument, Document } from '../../entities/index.js' + +const apiEndpoint = '/index.php/apps/zaakafhandelapp/api/objects/documenten' + +type TOptions = { + /** + * Save the document item to the store in 'documentItem' + */ + setItem?: boolean +} + +export const useDocumentStore = defineStore('documenten', { + state: () => ({ + documentItem: null, + documentenList: [], + /** + * Set the zaakId, used when creating a new document on a zaak. + */ + zaakId: null, + }), + actions: { + setDocumentItem(documentItem: Document | TDocument) { + this.documentItem = documentItem && new Document(documentItem) + console.info('Active document item set to ' + documentItem) + }, + setDocumentenList(documentenList: Document[] | TDocument[]) { + this.documentenList = documentenList.map( + (documentItem) => new Document(documentItem), + ) + console.info('Documenten list set to ' + documentenList.length + ' items') + }, + /** + * Refresh the list of documenten items. + * + * @param search - Optional search query to filter the documenten list. (default: `null`) + * @throws If the HTTP request fails. + * @return { Promise<{ response: Response, data: TDocument[], entities: Document[] }> } The response, raw data, and entities. + */ + async refreshDocumentenList(search: string = null): Promise<{ response: Response, data: TDocument[], entities: Document[] }> { + let endpoint = apiEndpoint + + if (search !== null && search !== '') { + endpoint = endpoint + '?_search=' + search + } + + console.info('Refreshing documenten list with search: ' + search) + + const response = await fetch(endpoint, { + method: 'GET', + }) + + if (!response.ok) { + console.error(response) + throw new Error(`HTTP error! status: ${response.status}`) + } + + const data = (await response.json()).results as TDocument[] + const entities = data.map((documentItem: TDocument) => new Document(documentItem)) + + this.setDocumentenList(data) + + return { response, data, entities } + }, + /** + * Fetch a single document item by its ID. + * + * @param id - The ID of the document item to fetch. + * @param options - Options for fetching the document item. (default: `{}`) + * @throws If the HTTP request fails. + * @return { Promise<{ response: Response, data: TDocument, entity: Document }> } The response, raw data, and entity. + */ + async getDocument( + id: string, + options: TOptions = {}, + ): Promise<{ response: Response, data: TDocument, entity: Document }> { + const endpoint = `${apiEndpoint}/${id}` + + console.info('Fetching document item with id: ' + id) + + const response = await fetch(endpoint, { + method: 'GET', + }) + + if (!response.ok) { + console.error(response) + throw new Error(`HTTP error! status: ${response.status}`) + } + + const data = await response.json() + const entity = new Document(data) + + options.setItem && this.setDocumentItem(data) + + return { response, data, entity } + }, + /** + * Fetch all documenten. + * + * @param zaakId - Optional ID of the zaak to filter documenten by + * @throws If the HTTP request fails. + * @return { Promise<{ response: Response, data: TDocument[], entities: Document[] }> } The response, raw data array, and entity array. + */ + async getDocumenten(zaakId: string = null): Promise<{ response: Response, data: TDocument[], entities: Document[] }> { + const params = new URLSearchParams() + if (zaakId) { + params.append('zaak', zaakId) + } + + const queryString = params.toString() + const endpoint = queryString + ? `${apiEndpoint}?${queryString}` + : apiEndpoint + + console.info('Fetching documenten') + + const response = await fetch(endpoint, { + method: 'GET', + }) + + if (!response.ok) { + console.error(response) + throw new Error(`HTTP error! status: ${response.status}`) + } + + const data = (await response.json()).results as TDocument[] + const entities = data.map((item: TDocument) => new Document(item)) + + return { response, data, entities } + }, + /** + * Delete a document item from the store. + * + * @param id - The ID of the document item to delete. + * @throws If the HTTP request fails. + * @return {Promise<{ response: Response }>} The response from the delete request. + */ + async deleteDocument(id: string): Promise<{ response: Response }> { + if (!id) { + throw new Error('No id for document item to delete') + } + + const endpoint = `${apiEndpoint}/${id}` + + console.info('Deleting document item with id: ' + id) + + const response = await fetch(endpoint, { + method: 'DELETE', + }) + + this.refreshDocumentenList() + + return { response } + }, + /** + * Save a document item to the store. If the document item does not have a uuid, it will be created. + * Otherwise, it will be updated. + * + * @param documentItem - The document item to save. + * @param options - Options for saving the document item. (default: `{ setItem: true }`) + * @throws If there is no document item to save or if the HTTP request fails. + * @return {Promise<{ response: Response, data: TDocument, entity: Document }>} The response, raw data, and entity. + */ + async saveDocument( + documentItem: Document | TDocument, + options: TOptions = { setItem: true }, + ): Promise<{ response: Response, data: TDocument, entity: Document }> { + if (!documentItem) { + throw new Error('No document item to save') + } + + const isNewDocument = !documentItem?.id + const endpoint = isNewDocument + ? `${apiEndpoint}` + : `${apiEndpoint}/${documentItem?.id}` + const method = isNewDocument ? 'POST' : 'PUT' + + console.info('Saving document item with id: ' + documentItem?.id) + + const response = await fetch( + endpoint, + { + method, + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(documentItem), + }, + ) + + if (!response.ok) { + console.error(response) + throw new Error(response.statusText || 'Failed to save document') + } + + const data = await response.json() as TDocument + const entity = new Document(data) + + options.setItem && this.setDocumentItem(data) + this.refreshDocumentenList() + + return { response, data, entity } + }, + }, +}) diff --git a/src/store/store.js b/src/store/store.js index d2c2fce..4c57c68 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -12,6 +12,7 @@ import { useContactMomentStore } from './modules/contactmoment.ts' import { useMedewerkerStore } from './modules/medewerkers.js' import { useResultaatStore } from './modules/resultaten.ts' import { useBesluitStore } from './modules/besluiten.ts' +import { useDocumentStore } from './modules/documenten.ts' const berichtStore = useBerichtStore(pinia) const klantStore = useKlantStore(pinia) @@ -25,6 +26,7 @@ const contactMomentStore = useContactMomentStore(pinia) const medewerkerStore = useMedewerkerStore(pinia) const resultaatStore = useResultaatStore(pinia) const besluitStore = useBesluitStore(pinia) +const documentStore = useDocumentStore(pinia) export { berichtStore, @@ -39,4 +41,5 @@ export { medewerkerStore, resultaatStore, besluitStore, + documentStore, } diff --git a/src/views/documenten/ZaakDocumenten.vue b/src/views/documenten/ZaakDocumenten.vue index 1c3208e..e2ea81a 100644 --- a/src/views/documenten/ZaakDocumenten.vue +++ b/src/views/documenten/ZaakDocumenten.vue @@ -1,63 +1,69 @@ + + diff --git a/src/views/zaken/ZaakDetails.vue b/src/views/zaken/ZaakDetails.vue index 5ea06f2..3650023 100644 --- a/src/views/zaken/ZaakDetails.vue +++ b/src/views/zaken/ZaakDetails.vue @@ -1,5 +1,5 @@ Bewerken - +