diff --git a/.github/workflows/pull-request-from-branch-check.yaml b/.github/workflows/pull-request-from-branch-check.yaml new file mode 100644 index 0000000..a40f09f --- /dev/null +++ b/.github/workflows/pull-request-from-branch-check.yaml @@ -0,0 +1,18 @@ +name: Main Branch Protection + +on: + pull_request: + branches: + - master + +jobs: + check-branch: + runs-on: ubuntu-latest + steps: + - name: Check branch + run: | + if [[ ${GITHUB_HEAD_REF} != development ]] && [[ ${GITHUB_HEAD_REF} != documentation ]] && ! [[ ${GITHUB_HEAD_REF} =~ ^hotfix/ ]]; + then + echo "Error: Pull request must come from 'development', 'documentation' or 'hotfix/' branch" + exit 1 + fi diff --git a/.github/workflows/pull-request-lint-check.yaml b/.github/workflows/pull-request-lint-check.yaml new file mode 100644 index 0000000..0c04e87 --- /dev/null +++ b/.github/workflows/pull-request-lint-check.yaml @@ -0,0 +1,20 @@ +name: Lint Check + +on: + pull_request: + branches: + - never + +jobs: + lint-check: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install dependencies + run: npm i + + - name: Linting + run: npm run lint diff --git a/appinfo/routes.php b/appinfo/routes.php index aa002e4..34334e4 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -24,6 +24,7 @@ 'taken' => ['url' => 'api/taken'], 'klanten' => ['url' => 'api/klanten'], 'berichten' => ['url' => 'api/berichten'], + 'contactmomenten' => ['url' => 'api/contactmomenten'], ], 'routes' => [ diff --git a/composer.json b/composer.json index 3ddf648..d89172d 100644 --- a/composer.json +++ b/composer.json @@ -44,7 +44,9 @@ "bamarni/composer-bin-plugin": "^1.8", "elasticsearch/elasticsearch": "^v8.14.0", "guzzlehttp/guzzle": "^7.0", - "symfony/uid": "^6.4" + "symfony/uid": "^6.4", + "symfony/yaml": "^6.4" + }, "require-dev": { "nextcloud/ocp": "dev-stable29", diff --git a/lib/Controller/ContactMomentenController.php b/lib/Controller/ContactMomentenController.php new file mode 100644 index 0000000..05a1fd4 --- /dev/null +++ b/lib/Controller/ContactMomentenController.php @@ -0,0 +1,134 @@ +request->getParams(); + + // Fetch contact moments based on filters and order + $data = $this->objectService->getResultArrayForRequest('contactmomenten', $requestParams); + + // Return JSON response + return new JSONResponse($data); + } + + /** + * Read a single contact moment + * + * @NoAdminRequired + * @NoCSRFRequired + * + * @return JSONResponse + */ + public function show(string $id): JSONResponse + { + // Fetch the contact moment by its ID + $object = $this->objectService->getObject('contactmomenten', $id); + + // Return the contact moment as a JSON response + return new JSONResponse($object); + } + + /** + * Create a contact moment + * + * @NoAdminRequired + * @NoCSRFRequired + * + * @return JSONResponse + */ + public function create(): JSONResponse + { + // Get all parameters from the request + $data = $this->request->getParams(); + + // Remove the 'id' field if it exists, as we're creating a new contact moment + unset($data['id']); + + // Save the new contact moment + $object = $this->objectService->saveObject('contactmomenten', $data); + + // Return the created contact moment as a JSON response + return new JSONResponse($object); + } + + /** + * Update a contact moment + * + * @NoAdminRequired + * @NoCSRFRequired + * + * @return JSONResponse + */ + public function update(string $id): JSONResponse + { + // Get all parameters from the request + $data = $this->request->getParams(); + + // Save the updated contact moment + $object = $this->objectService->saveObject('contactmomenten', $data); + + // Return the updated contact moment as a JSON response + return new JSONResponse($object); + } + + /** + * Delete a contact moment + * + * @NoAdminRequired + * @NoCSRFRequired + * + * @return JSONResponse + */ + public function destroy(string $id): JSONResponse + { + // Delete the contact moment + $result = $this->objectService->deleteObject('contactmomenten', $id); + + // Return the result as a JSON response + return new JSONResponse(['success' => $result], $result === true ? '200' : '404'); + } + + /** + * Get audit trail for a specific contact moment + * + * @NoAdminRequired + * @NoCSRFRequired + * + * @return JSONResponse + */ + public function getAuditTrail(string $id): JSONResponse + { + $auditTrail = $this->objectService->getAuditTrail('contactmomenten', $id); + return new JSONResponse($auditTrail); + } +} diff --git a/package-lock.json b/package-lock.json index 6159537..91c1b3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,6 +46,10 @@ "ts-loader": "^9.5.1", "typescript": "^5.5.4", "vue-jest": "^3.0.7" + }, + "engines": { + "node": "^20.0.0", + "npm": "^10.0.0" } }, "node_modules/@ampproject/remapping": { diff --git a/package.json b/package.json index 88ee6e6..2be7d13 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,10 @@ "name": "zaakafhandelapp", "version": "1.0.0", "license": "AGPL-3.0-or-later", + "engines": { + "node": "^20.0.0", + "npm": "^10.0.0" + }, "scripts": { "build": "NODE_ENV=production webpack --config webpack.config.js --progress", "dev": "NODE_ENV=development webpack --config webpack.config.js --progress", diff --git a/src/entities/zaak/zaak.mock.ts b/src/entities/zaak/zaak.mock.ts index 020c8f5..8e5197d 100644 --- a/src/entities/zaak/zaak.mock.ts +++ b/src/entities/zaak/zaak.mock.ts @@ -25,6 +25,7 @@ export const mockZaakData = (): TZaak[] => [ laatsteBetaaldatum: '2019-08-24T14:15:22Z', selectielijstklasse: 'http://example.com', hoofdzaak: 'http://example.com', + klant: '15551d6f-44e3-43f3-a9d2-59e583c91eb0', }, ] diff --git a/src/entities/zaak/zaak.ts b/src/entities/zaak/zaak.ts index ba1ff03..57a1515 100644 --- a/src/entities/zaak/zaak.ts +++ b/src/entities/zaak/zaak.ts @@ -25,6 +25,7 @@ export class Zaak implements TZaak { public laatsteBetaaldatum: string public selectielijstklasse: string public hoofdzaak: string + public klant: string constructor(source: TZaak) { this.id = source.id || '' @@ -49,6 +50,7 @@ export class Zaak implements TZaak { this.laatsteBetaaldatum = source.laatsteBetaaldatum || '' this.selectielijstklasse = source.selectielijstklasse || '' this.hoofdzaak = source.hoofdzaak || '' + this.klant = source.klant || '' } public validate(): SafeParseReturnType { @@ -75,6 +77,7 @@ export class Zaak implements TZaak { laatsteBetaaldatum: z.string(), selectielijstklasse: z.string(), hoofdzaak: z.string(), + klant: z.string(), }) return schema.safeParse(this) diff --git a/src/entities/zaak/zaak.types.ts b/src/entities/zaak/zaak.types.ts index c9d45fc..791fd4a 100644 --- a/src/entities/zaak/zaak.types.ts +++ b/src/entities/zaak/zaak.types.ts @@ -23,4 +23,5 @@ export type TZaak = { laatsteBetaaldatum: string; selectielijstklasse: string; hoofdzaak: string; + klant: string; } diff --git a/src/modals/Modals.vue b/src/modals/Modals.vue index bd37f4e..65c4e2c 100644 --- a/src/modals/Modals.vue +++ b/src/modals/Modals.vue @@ -6,20 +6,24 @@ import { navigationStore } from '../store/store.js'
+ + +
diff --git a/src/modals/berichten/EditBericht.vue b/src/modals/berichten/EditBericht.vue index 5c44d87..0be901c 100644 --- a/src/modals/berichten/EditBericht.vue +++ b/src/modals/berichten/EditBericht.vue @@ -220,6 +220,8 @@ export default { gebruikerID: '', volgorde: '', } + this.$emit('close-modal') + }, async editBericht() { this.loading = true diff --git a/src/modals/klantRegister/ViewKlantRegister.vue b/src/modals/klantRegister/ViewKlantRegister.vue new file mode 100644 index 0000000..b742149 --- /dev/null +++ b/src/modals/klantRegister/ViewKlantRegister.vue @@ -0,0 +1,411 @@ + + + + + + diff --git a/src/modals/taken/EditTaak.vue b/src/modals/taken/EditTaak.vue index 06b9a75..2edec57 100644 --- a/src/modals/taken/EditTaak.vue +++ b/src/modals/taken/EditTaak.vue @@ -167,8 +167,10 @@ export default { toelichting: taakStore.taakItem.toelichting || '', klant: klantStore.klantItem?.id || '', } + this.fetchKlanten() } else { this.taakItem.klant = klantStore.klantItem?.id || '' + this.fetchKlanten() } this.hasUpdated = true } diff --git a/src/modals/taken/WidgetTaakForm.vue b/src/modals/taken/WidgetTaakForm.vue new file mode 100644 index 0000000..bb852ff --- /dev/null +++ b/src/modals/taken/WidgetTaakForm.vue @@ -0,0 +1,382 @@ + + + + + diff --git a/src/modals/zaken/WidgetZaakForm.vue b/src/modals/zaken/WidgetZaakForm.vue new file mode 100644 index 0000000..708e9cd --- /dev/null +++ b/src/modals/zaken/WidgetZaakForm.vue @@ -0,0 +1,310 @@ + + + + + + + diff --git a/src/store/modules/klanten.js b/src/store/modules/klanten.js index ce929dd..7318878 100644 --- a/src/store/modules/klanten.js +++ b/src/store/modules/klanten.js @@ -8,6 +8,7 @@ export const useKlantStore = defineStore('klanten', { state: () => ({ klantItem: false, klantenList: [], + widgetKlantId: null, auditTrailItem: null, }), actions: { @@ -15,6 +16,10 @@ export const useKlantStore = defineStore('klanten', { this.klantItem = klantItem && new Klant(klantItem) console.log('Active klant item set to ' + klantItem) }, + setWidgetKlantId(widgetKlantId) { + this.widgetKlantId = widgetKlantId + console.log('Widget klant id set to ' + widgetKlantId) + }, setKlantenList(klantenList) { this.klantenList = klantenList.map( (klantItem) => new Klant(klantItem), diff --git a/src/views/klanten/KlantenIndex.vue b/src/views/klanten/KlantenIndex.vue index 5dcd5e1..d5adc0a 100644 --- a/src/views/klanten/KlantenIndex.vue +++ b/src/views/klanten/KlantenIndex.vue @@ -30,8 +30,7 @@ import { navigationStore, klantStore } from '../../store/store.js' import { NcAppContent, NcEmptyContent, NcButton } from '@nextcloud/vue' import KlantenList from './KlantenList.vue' import KlantDetails from './KlantDetails.vue' -// eslint-disable-next-line n/no-missing-import -import AccountOutline from 'vue-material-design-icons/AccountOutline' +import AccountOutline from 'vue-material-design-icons/AccountOutline.vue' export default { name: 'KlantenIndex', diff --git a/src/views/widgets/ContactMomentenWidget.vue b/src/views/widgets/ContactMomentenWidget.vue index f85042c..037623f 100644 --- a/src/views/widgets/ContactMomentenWidget.vue +++ b/src/views/widgets/ContactMomentenWidget.vue @@ -84,7 +84,14 @@ export default { }, getItemIcon() { const theme = getTheme() - return theme === 'light' ? '/apps-extra/zaakafhandelapp/img/chat-outline-dark.svg' : '/apps-extra/zaakafhandelapp/img/chat-outline.svg' + + let appLocation = '/custom_apps' + + if (window.location.hostname === 'nextcloud.local') { + appLocation = '/apps-extra' + } + + return theme === 'light' ? `${appLocation}/zaakafhandelapp/img/chat-outline-dark.svg` : `${appLocation}/zaakafhandelapp/img/chat-outline.svg` }, openModal() { this.isModalOpen = true diff --git a/src/views/widgets/OpenZakenWidget.vue b/src/views/widgets/OpenZakenWidget.vue index 364c750..4975a8f 100644 --- a/src/views/widgets/OpenZakenWidget.vue +++ b/src/views/widgets/OpenZakenWidget.vue @@ -77,7 +77,14 @@ export default { }, getItemIcon() { const theme = getTheme() - return theme === 'light' ? '/apps-extra/zaakafhandelapp/img/briefcase-account-outline-dark.svg' : '/apps-extra/zaakafhandelapp/img/briefcase-account-outline.svg' + + let appLocation = '/custom_apps' + + if (window.location.hostname === 'nextcloud.local') { + appLocation = '/apps-extra' + } + + return theme === 'light' ? `${appLocation}/zaakafhandelapp/img/briefcase-account-outline-dark.svg` : `${appLocation}/zaakafhandelapp/img/briefcase-account-outline.svg` }, search() { console.info('click') diff --git a/src/views/widgets/OrganisatiesWidget.vue b/src/views/widgets/OrganisatiesWidget.vue index 82375b6..d61d580 100644 --- a/src/views/widgets/OrganisatiesWidget.vue +++ b/src/views/widgets/OrganisatiesWidget.vue @@ -1,5 +1,5 @@ @@ -44,6 +50,7 @@ import { NcDashboardWidget, NcEmptyContent, NcButton, NcTextField } from '@nextc import { getTheme } from '../../services/getTheme.js' import Search from 'vue-material-design-icons/Magnify.vue' import OfficeBuildingOutline from 'vue-material-design-icons/OfficeBuildingOutline.vue' +import ViewKlantRegister from '../../modals/klantRegister/ViewKlantRegister.vue' export default { name: 'OrganisatiesWidget', @@ -54,13 +61,23 @@ export default { NcButton, Search, NcTextField, + OfficeBuildingOutline, + ViewKlantRegister, }, data() { return { loading: false, + isModalOpen: false, organisatieItems: [], searchOrganisatie: '', + selectedKlantId: '', + itemMenu: { + show: { + text: 'Bekijk', + icon: 'icon-toggle', + }, + }, } }, @@ -107,11 +124,22 @@ export default { }, getItemIcon() { const theme = getTheme() - return theme === 'light' ? '/apps-extra/zaakafhandelapp/img/office-building-outline-dark.svg' : '/apps-extra/zaakafhandelapp/img/office-building-outline.svg' + + let appLocation = '/custom_apps' + + if (window.location.hostname === 'nextcloud.local') { + appLocation = '/apps-extra' + } + + return theme === 'light' ? `${appLocation}/zaakafhandelapp/img/office-building-outline-dark.svg` : `${appLocation}/zaakafhandelapp/img/office-building-outline.svg` }, - onShow() { - window.open('/apps/opencatalogi/catalogi', '_self') + onShow(item) { + klantStore.setWidgetKlantId(item.id) + this.isModalOpen = true + navigationStore.setModal('viewKlantRegister') + }, + }, } diff --git a/src/views/widgets/PersonenWidget.vue b/src/views/widgets/PersonenWidget.vue index ea64ed6..61ff41d 100644 --- a/src/views/widgets/PersonenWidget.vue +++ b/src/views/widgets/PersonenWidget.vue @@ -1,5 +1,5 @@ @@ -44,6 +50,7 @@ import { NcDashboardWidget, NcEmptyContent, NcButton, NcTextField } from '@nextc import { getTheme } from '../../services/getTheme.js' import Search from 'vue-material-design-icons/Magnify.vue' import AccountOutline from 'vue-material-design-icons/AccountOutline.vue' +import ViewKlantRegister from '../../modals/klantRegister/ViewKlantRegister.vue' export default { name: 'PersonenWidget', @@ -55,6 +62,7 @@ export default { Search, NcTextField, AccountOutline, + ViewKlantRegister, }, data() { @@ -63,6 +71,13 @@ export default { isModalOpen: false, personenItems: [], searchPerson: '', + selectedKlantId: '', + itemMenu: { + show: { + text: 'Bekijk', + icon: 'icon-toggle', + }, + }, } }, @@ -108,10 +123,21 @@ export default { }, getItemIcon() { const theme = getTheme() - return theme === 'light' ? '/apps-extra/zaakafhandelapp/img/account-outline-dark.svg' : '/apps-extra/zaakafhandelapp/img/account-outline.svg' + + let appLocation = '/custom_apps' + + if (window.location.hostname === 'nextcloud.local') { + appLocation = '/apps-extra' + } + + return theme === 'light' ? `${appLocation}/zaakafhandelapp/img/account-outline-dark.svg` : `${appLocation}/zaakafhandelapp/img/account-outline.svg` }, - onShow() { - window.open('/apps/opencatalogi/catalogi', '_self') + onShow(item) { + klantStore.setWidgetKlantId(item.id) + + this.isModalOpen = true + navigationStore.setModal('viewKlantRegister') + }, }, diff --git a/src/views/widgets/TakenWidget.vue b/src/views/widgets/TakenWidget.vue index 1fbaa27..3cd7c39 100644 --- a/src/views/widgets/TakenWidget.vue +++ b/src/views/widgets/TakenWidget.vue @@ -27,7 +27,8 @@ import { taakStore, navigationStore } from '../../store/store.js' + @save-success="fetchTaakItems" + @close-modal="closeModal" /> @@ -84,7 +85,14 @@ export default { }, getItemIcon() { const theme = getTheme() - return theme === 'light' ? '/apps-extra/zaakafhandelapp/img/calendar-month-outline-dark.svg' : '/apps-extra/zaakafhandelapp/img/calendar-month-outline.svg' + + let appLocation = '/custom_apps' + + if (window.location.hostname === 'nextcloud.local') { + appLocation = '/apps-extra' + } + + return theme === 'light' ? `${appLocation}/zaakafhandelapp/img/calendar-month-outline-dark.svg` : `${appLocation}/zaakafhandelapp/img/calendar-month-outline.svg` }, openModal() { this.isModalOpen = true diff --git a/src/views/widgets/ZakenWidget.vue b/src/views/widgets/ZakenWidget.vue index 8af17dc..4fb032a 100644 --- a/src/views/widgets/ZakenWidget.vue +++ b/src/views/widgets/ZakenWidget.vue @@ -39,7 +39,7 @@ import { getTheme } from '../../services/getTheme.js' import Plus from 'vue-material-design-icons/Plus.vue' import Folder from 'vue-material-design-icons/Folder.vue' -import ZaakForm from '../../modals/zaken/ZaakForm.vue' +import ZaakForm from '../../modals/zaken/WidgetZaakForm.vue' export default { name: 'ZakenWidget', @@ -91,7 +91,14 @@ export default { }, getItemIcon() { const theme = getTheme() - return theme === 'light' ? '/apps-extra/zaakafhandelapp/img/briefcase-account-outline-dark.svg' : '/apps-extra/zaakafhandelapp/img/briefcase-account-outline.svg' + + let appLocation = '/custom_apps' + + if (window.location.hostname === 'nextcloud.local') { + appLocation = '/apps-extra' + } + + return theme === 'light' ? `${appLocation}/zaakafhandelapp/img/briefcase-account-outline-dark.svg` : `${appLocation}/zaakafhandelapp/img/briefcase-account-outline.svg` }, search() { console.info('click')