Add new dependencies for calendar and styling support

This commit introduces new dependencies including `dayspan-vuetify`, `bulma-block-list`, `vue-cal`, and `@event-calendar/core` for enhanced calendar functionality and styling options. Additionally, several supporting libraries such as `svelte`, `css-tree`, and `clsx` were added for improved performance and compatibility.
This commit is contained in:
Jepp9350
2025-05-13 08:43:20 +02:00
parent f6e5cfd784
commit 10a320e985
18 changed files with 1340 additions and 5 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
<link rel="stylesheet" href="bulma/css/bulma.min.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.1/css/all.min.css" integrity="sha512-5Hs3dF2AEPkpNAR7UiOHba+lRSJNeM2ECkwxUIxC1Q/FLycGTbNapWXB4tP889k5T5Ju8fs4b1P5z/iB4nMfSQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<title>Truck Wash</title>
<title>Truck Wash</title>
</head>
<body>
<div id="app"></div>
+340
View File
@@ -17,18 +17,21 @@
"animate.css": "^4.1.1",
"axios": "^1.7.8",
"bulma": "^1.0.2",
"bulma-block-list": "^1.1.0",
"bulma-calendar": "^7.1.1",
"bulma-list": "^3.0.0",
"bulma-pageloader": "^0.3.0",
"bulma-quickview": "^2.0.0",
"bulma-switch": "^2.0.4",
"chart.js": "^4.4.7",
"dayspan-vuetify": "^0.4.0",
"flow": "^0.2.3",
"sass": "^1.81.1",
"sweetalert2": "^11.14.5",
"toastify-js": "^1.12.0",
"vite-plugin-singlefile": "^2.1.0",
"vue": "^3.5.12",
"vue-cal": "^5.0.1-rc.20",
"vue-chartjs": "^5.3.2",
"vue-popperjs": "^2.3.0",
"vue-router": "^4.5.0",
@@ -36,6 +39,8 @@
},
"devDependencies": {
"@creativebulma/bulma-divider": "^1.1.0",
"@event-calendar/core": "^4.1.0",
"@types/event-calendar__core": "^3.7.0",
"@vitejs/plugin-vue": "^5.1.4",
"@vitejs/plugin-vue-jsx": "^4.1.2",
"sass-embedded": "^1.81.0",
@@ -1840,6 +1845,15 @@
"node": ">=12"
}
},
"node_modules/@event-calendar/core": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@event-calendar/core/-/core-4.1.0.tgz",
"integrity": "sha512-orU66fl1p9zLVTFkz9WUWH53H6GxMnyxBx7mYMobQO0mbdJ+tbCJ9W9xL00MyHBQk1sJFdINc6YyIlVdqpFTRw==",
"dev": true,
"dependencies": {
"svelte": "^5.28.2"
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
@@ -2453,6 +2467,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@sveltejs/acorn-typescript": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz",
"integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==",
"dev": true,
"peerDependencies": {
"acorn": "^8.9.0"
}
},
"node_modules/@sweetalert2/theme-bulma": {
"version": "5.0.18",
"resolved": "https://registry.npmjs.org/@sweetalert2/theme-bulma/-/theme-bulma-5.0.18.tgz",
@@ -2468,6 +2491,49 @@
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="
},
"node_modules/@types/event-calendar__core": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/@types/event-calendar__core/-/event-calendar__core-3.7.0.tgz",
"integrity": "sha512-mNyYp2PeQ+pP9msbMcDLuYhZwDZDUgQWl/pniZRaNfckPxo31x3ue10Lv7tFlHAKihgw7a2Ogw2S5PHjGm7dLA==",
"dev": true,
"dependencies": {
"svelte": "^4"
}
},
"node_modules/@types/event-calendar__core/node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.0"
}
},
"node_modules/@types/event-calendar__core/node_modules/svelte": {
"version": "4.2.19",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz",
"integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==",
"dev": true,
"dependencies": {
"@ampproject/remapping": "^2.2.1",
"@jridgewell/sourcemap-codec": "^1.4.15",
"@jridgewell/trace-mapping": "^0.3.18",
"@types/estree": "^1.0.1",
"acorn": "^8.9.0",
"aria-query": "^5.3.0",
"axobject-query": "^4.0.0",
"code-red": "^1.0.3",
"css-tree": "^2.3.1",
"estree-walker": "^3.0.3",
"is-reference": "^3.0.1",
"locate-character": "^3.0.0",
"magic-string": "^0.30.4",
"periscopic": "^3.1.0"
},
"engines": {
"node": ">=16"
}
},
"node_modules/@types/web-bluetooth": {
"version": "0.0.20",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
@@ -2837,11 +2903,32 @@
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/acorn": {
"version": "8.14.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/animate.css": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/animate.css/-/animate.css-4.1.1.tgz",
"integrity": "sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ=="
},
"node_modules/aria-query": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
"integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
"dev": true,
"engines": {
"node": ">= 0.4"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -2857,6 +2944,15 @@
"proxy-from-env": "^1.1.0"
}
},
"node_modules/axobject-query": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
"integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
"dev": true,
"engines": {
"node": ">= 0.4"
}
},
"node_modules/babel-plugin-polyfill-corejs2": {
"version": "0.4.13",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz",
@@ -2955,6 +3051,14 @@
"resolved": "https://registry.npmjs.org/bulma/-/bulma-1.0.2.tgz",
"integrity": "sha512-D7GnDuF6seb6HkcnRMM9E739QpEY9chDzzeFrHMyEns/EXyDJuQ0XA0KxbBl/B2NTsKSoDomW61jFGFaAxhK5A=="
},
"node_modules/bulma-block-list": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/bulma-block-list/-/bulma-block-list-1.1.0.tgz",
"integrity": "sha512-GFBRrLs7Wrja+QlGAGDlFu8y+4/9eBaPMN6DdKZ2+se95YjFM6gshRp5FdHwpTCZT9TRpyY+slHTtpOGgEFcKg==",
"dependencies": {
"bulma": "^1.0.0"
}
},
"node_modules/bulma-calendar": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/bulma-calendar/-/bulma-calendar-7.1.1.tgz",
@@ -3048,6 +3152,37 @@
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/clsx": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/code-red": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
"integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==",
"dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15",
"@types/estree": "^1.0.1",
"acorn": "^8.10.0",
"estree-walker": "^3.0.3",
"periscopic": "^3.1.0"
}
},
"node_modules/code-red/node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.0"
}
},
"node_modules/colorjs.io": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz",
@@ -3111,6 +3246,19 @@
"node": ">= 8"
}
},
"node_modules/css-tree": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
"dev": true,
"dependencies": {
"mdn-data": "2.0.30",
"source-map-js": "^1.0.1"
},
"engines": {
"node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
}
},
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -3227,6 +3375,63 @@
"url": "https://opencollective.com/date-fns"
}
},
"node_modules/dayspan": {
"version": "0.12.5",
"resolved": "https://registry.npmjs.org/dayspan/-/dayspan-0.12.5.tgz",
"integrity": "sha512-/IkvULBqTRJjUnmKcu3nAGpo04mIszC+ua1ItZadNRxfMKzplmxEljHytOpHdOyl6GF3V7de8oxgep7emeivNA==",
"engines": {
"node": ">=6.9"
},
"peerDependencies": {
"moment": "^2.24.0"
}
},
"node_modules/dayspan-vuetify": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/dayspan-vuetify/-/dayspan-vuetify-0.4.0.tgz",
"integrity": "sha512-YoCFu1hZsvklDQXm8IBRvY00v/B06F/h6yS0k4GALEqrzlqY0EKF4UUdjlr5xMRoKuw7NTA//4V4twOQ8H3D/A==",
"dependencies": {
"dayspan": "^0.12.2",
"material-design-icons-iconfont": "^3.0.3",
"vue": "^2.3.3",
"vuetify": "^1.3.9"
},
"engines": {
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
}
},
"node_modules/dayspan-vuetify/node_modules/@vue/compiler-sfc": {
"version": "2.7.16",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz",
"integrity": "sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==",
"dependencies": {
"@babel/parser": "^7.23.5",
"postcss": "^8.4.14",
"source-map": "^0.6.1"
},
"optionalDependencies": {
"prettier": "^1.18.2 || ^2.0.0"
}
},
"node_modules/dayspan-vuetify/node_modules/vue": {
"version": "2.7.16",
"resolved": "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz",
"integrity": "sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==",
"deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.",
"dependencies": {
"@vue/compiler-sfc": "2.7.16",
"csstype": "^3.1.0"
}
},
"node_modules/dayspan-vuetify/node_modules/vuetify": {
"version": "1.5.23",
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-1.5.23.tgz",
"integrity": "sha512-T6ZAli8jWHRsDIjQmB4UG4iXJtwH1M+H5/8Cd76m6XKcic93R6qnKI1IK9OFIVqcrZc1Iw1kDeQWG35iQt0M2Q==",
"peerDependencies": {
"vue": "^2.5.18"
}
},
"node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
@@ -3373,6 +3578,21 @@
"node": ">=6"
}
},
"node_modules/esm-env": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
"integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
"dev": true
},
"node_modules/esrap": {
"version": "1.4.6",
"resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.6.tgz",
"integrity": "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw==",
"dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
}
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
@@ -3688,6 +3908,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-reference": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
"integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.6"
}
},
"node_modules/is-stream": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
@@ -3790,6 +4019,12 @@
"integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==",
"dev": true
},
"node_modules/locate-character": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
"dev": true
},
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@@ -3811,6 +4046,17 @@
"@jridgewell/sourcemap-codec": "^1.5.0"
}
},
"node_modules/material-design-icons-iconfont": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-3.0.3.tgz",
"integrity": "sha512-wbvGpfJGLDuL0bj9pFd4sjXvGqukKraViSFRVDLk97s/GrKs/rGv9Eo2286jkxfFqkYXczyJrglUZlbyfFVOFw=="
},
"node_modules/mdn-data": {
"version": "2.0.30",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
"dev": true
},
"node_modules/micromatch": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
@@ -3873,6 +4119,15 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/moment": {
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"peer": true,
"engines": {
"node": "*"
}
},
"node_modules/mrmime": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
@@ -4007,6 +4262,26 @@
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
"dev": true
},
"node_modules/periscopic": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
"integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.0",
"estree-walker": "^3.0.0",
"is-reference": "^3.0.0"
}
},
"node_modules/periscopic/node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.0"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -4061,6 +4336,21 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/prettier": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
"optional": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/pretty-ms": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz",
@@ -4655,6 +4945,14 @@
"node": ">=18"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -4722,6 +5020,31 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/svelte": {
"version": "5.28.2",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.28.2.tgz",
"integrity": "sha512-FbWBxgWOpQfhKvoGJv/TFwzqb4EhJbwCD17dB0tEpQiw1XyUEKZJtgm4nA4xq3LLsMo7hu5UY/BOFmroAxKTMg==",
"dev": true,
"dependencies": {
"@ampproject/remapping": "^2.3.0",
"@jridgewell/sourcemap-codec": "^1.5.0",
"@sveltejs/acorn-typescript": "^1.0.5",
"@types/estree": "^1.0.5",
"acorn": "^8.12.1",
"aria-query": "^5.3.1",
"axobject-query": "^4.1.0",
"clsx": "^2.1.1",
"esm-env": "^1.2.1",
"esrap": "^1.4.6",
"is-reference": "^3.0.3",
"locate-character": "^3.0.0",
"magic-string": "^0.30.11",
"zimmerframe": "^1.1.2"
},
"engines": {
"node": ">=18"
}
},
"node_modules/svg-tags": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
@@ -5058,6 +5381,17 @@
}
}
},
"node_modules/vue-cal": {
"version": "5.0.1-rc.20",
"resolved": "https://registry.npmjs.org/vue-cal/-/vue-cal-5.0.1-rc.20.tgz",
"integrity": "sha512-3Nsngu7MiNmDDf8uQf8nRznRW5VYmRbFC8Yq9rP8vGY7mWYgC6/2BHy3eO2S2gvgvV7nbmSR46lkd8zI5AShgg==",
"funding": {
"url": "https://github.com/sponsors/antoniandre"
},
"peerDependencies": {
"vue": "^3.5.0"
}
},
"node_modules/vue-chartjs": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.3.2.tgz",
@@ -5133,6 +5467,12 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/zimmerframe": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz",
"integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==",
"dev": true
}
}
}
+5
View File
@@ -18,18 +18,21 @@
"animate.css": "^4.1.1",
"axios": "^1.7.8",
"bulma": "^1.0.2",
"bulma-block-list": "^1.1.0",
"bulma-calendar": "^7.1.1",
"bulma-list": "^3.0.0",
"bulma-pageloader": "^0.3.0",
"bulma-quickview": "^2.0.0",
"bulma-switch": "^2.0.4",
"chart.js": "^4.4.7",
"dayspan-vuetify": "^0.4.0",
"flow": "^0.2.3",
"sass": "^1.81.1",
"sweetalert2": "^11.14.5",
"toastify-js": "^1.12.0",
"vite-plugin-singlefile": "^2.1.0",
"vue": "^3.5.12",
"vue-cal": "^5.0.1-rc.20",
"vue-chartjs": "^5.3.2",
"vue-popperjs": "^2.3.0",
"vue-router": "^4.5.0",
@@ -37,6 +40,8 @@
},
"devDependencies": {
"@creativebulma/bulma-divider": "^1.1.0",
"@event-calendar/core": "^4.1.0",
"@types/event-calendar__core": "^3.7.0",
"@vitejs/plugin-vue": "^5.1.4",
"@vitejs/plugin-vue-jsx": "^4.1.2",
"sass-embedded": "^1.81.0",
@@ -3,6 +3,7 @@ import { customer_name, customer_id, customer_data, customer_attributes, loadCus
import { createAttribute, deleteAttribute } from "@/components/shop/CustomerAttributes.vue";
import {ref, watch} from 'vue';
import 'bulma-switch/dist/css/bulma-switch.min.css';
import 'bulma-block-list/src/block-list.scss';
import {SessionUser} from "@/components/session/token/SessionUser.vue";
import {popperBox, popper, removePopperIfOpen, showPopperWithContent, showPopper} from "@/components/displays/PopperDefault.vue";
import RequiresPermission from "@/components/displays/permissionbased/RequiresPermission.vue";
@@ -0,0 +1,98 @@
<script setup>
import EditableTableColumn from "@/components/displays/buttons/EditableTableColumn.vue";
import { loadList } from "@/components/pagination/paginatedList.vue";
const props = defineProps({
objects: {
type: Array,
required: true,
},
});
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import { ref } from 'vue';
import ActionSettingsWheelButton from "@/components/displays/buttons/ActionSettingsWheelButton.vue";
import ActionSettingsWheelItem from "@/components/displays/buttons/ActionSettingsWheelItem.vue";
import RequiresPermission from "@/components/displays/permissionbased/RequiresPermission.vue";
const su_object = SessionUser.objects.department_time_bookings_types;
const hasUpdatePermission = () => {
return (SessionUser.hasPermission('department_timebookings_types_put') || SessionUser.canAccessSuperUser());
};
</script>
<template>
<table class="table is-fullwidth">
<thead>
<tr>
<th>{{su_object.columns.id.label}}</th>
<th>{{su_object.columns.name.label}}</th>
<th>{{su_object.columns.description.label}}</th>
<th>{{su_object.columns.duration.label}}</th>
<th class="has-text-right"></th>
</tr>
</thead>
<tbody>
<tr v-for="obj in objects" :key="obj.id">
<td>{{obj.id}}</td>
<!-- Label -->
<EditableTableColumn
:object="obj"
:loadList="loadList"
:editFunction="su_object.showEditObjectFieldForm"
column="name"
:permission-check-function="hasUpdatePermission"
/>
<!-- Description -->
<EditableTableColumn
:object="obj"
:loadList="loadList"
:editFunction="su_object.showEditObjectFieldForm"
column="description"
:permission-check-function="hasUpdatePermission"
/>
<!-- Duration -->
<EditableTableColumn
:object="obj"
:loadList="loadList"
:editFunction="su_object.showEditObjectFieldForm"
column="duration"
:permission-check-function="hasUpdatePermission"
/>
<!-- Actions -->
<td class="is-float-right">
<ActionSettingsWheelButton>
<template #actions>
<RequiresPermission :permission="'department_timebookings_types_delete'">
<template #default>
<ActionSettingsWheelItem
@click="su_object.functions.showDeleteObjectForm(obj.id, loadList)"
:icon="SessionUser.objects.global.icons.delete"
:label="SessionUser.objects.global.language.delete"
template="danger"
/>
</template>
<template #fail>
<ActionSettingsWheelItem
:icon="SessionUser.objects.global.icons.delete"
:label="SessionUser.objects.global.language.delete"
template="danger"
disabled
/>
</template>
</RequiresPermission>
</template>
</ActionSettingsWheelButton>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="12">{{SessionUser.objects.global.language.showing}} {{ objects.length }} {{su_object.meta.labels.multiple}}</td>
</tr>
</tfoot>
</table>
</template>
<style scoped>
</style>
@@ -0,0 +1,66 @@
<script setup>
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import { useRouter } from "vue-router";
import {
isLoaded,
isLoading,
list,
loadList,
metaCurrentPage,
metaItemsPerPage,
metaTotalItems,
setEndpoint,
setMetaItemsPerPage,
setPage,
metaSearch,
search,
setFilter,
} from "@/components/pagination/paginatedList.vue";
import PaginationNavigation from "@/components/displays/pagination/PaginationNavigation.vue";
import LoadButtonWhileAwait from "@/components/request/LoadButtonWhileAwait.vue";
import PaginationDisplay from "@/components/displays/pagination/PaginationDisplay.vue";
import DepartmentNotificationsPhoneTable
from "@/components/displays/department/notifications/departmentNotificationsPhoneTable.vue";
import DepartmentTimeBookingsTypesTable
from "@/components/displays/department/timebookings/departmentTimeBookingsTypesTable.vue";
const router = useRouter();
// If the departmentId is set, in the route, filter the orders by the departmentId
if (router.currentRoute.value.params.departmentId) {
setEndpoint(SessionUser.objects.department_time_bookings_types.meta.endpoint, false);
setFilter("department", router.currentRoute.value.params.departmentId);
} else {
setEndpoint(SessionUser.objects.department_time_bookings_types.meta.endpoint, true);
}
</script>
<template>
<input @input="search($event.target.value)" class="input" type="text" placeholder="Søg efter telefonnummer" />
<PaginationDisplay :metaItemsPerPage="metaItemsPerPage" :loadFunction="loadList" :isLoading="isLoading" :setMetaItemsPerPage="setMetaItemsPerPage" >
<template #paginationColumns>
<div class="column is-auto-fill"></div>
<div class="column is-narrow">
<label class="label">&nbsp</label>
<div class="control">
<button class="button is-info" @click="SessionUser.objects.department_time_bookings_types.showCreateObjectForm(() => loadList(), {department: parseInt(router.currentRoute.value.params.departmentId)})">
<span class="icon is-small">
<i class="fas fa-plus"></i>
</span>
<span>
{{SessionUser.objects.global.language.add}} {{SessionUser.objects.department_time_bookings_types.meta.labels.single}}
</span>
</button>
</div>
</div>
</template>
</PaginationDisplay>
<DepartmentTimeBookingsTypesTable :objects="list" />
<PaginationNavigation :currentPage="metaCurrentPage" :totalPages="Math.ceil(metaTotalItems / metaItemsPerPage)" :loadFunction="loadList" :setPage="setPage" :isLoading="isLoading" />
<LoadButtonWhileAwait class="is-dark" :isLoading="!isLoaded()" :loadFunction="loadList" icon="fas fa-sync-alt">{{SessionUser.objects.global.language.reload}}</LoadButtonWhileAwait>
</template>
<style scoped>
</style>
@@ -121,6 +121,47 @@ const menu_items = ref([
'list_bookings'
]
},
{
name: 'Tidsbooking',
route: '/admin/' + SessionUser.functions.getDepartmentIdFromUrl() + '/modules/time-bookings',
icon: 'fas fa-exchange-alt',
children: [
{
name: 'Bookinger',
route: '/admin/' + SessionUser.functions.getDepartmentIdFromUrl() + '/modules/time-bookings',
icon: 'fas fa-exchange-alt',
children: [],
hidden: isDepartmentIdUndefined,
permissions: [
'list_time_bookings'
]
},
{
name: 'Åbningstider',
route: '/admin/' + SessionUser.functions.getDepartmentIdFromUrl() + '/modules/time-bookings/opening-hours',
icon: 'fas fa-exchange-alt',
children: [],
hidden: isDepartmentIdUndefined,
permissions: [
'list_opening_hours'
]
},
{
name: 'Opsætning',
route: '/admin/' + SessionUser.functions.getDepartmentIdFromUrl() + '/modules/time-bookings/types',
icon: 'fas fa-exchange-alt',
children: [],
hidden: isDepartmentIdUndefined,
permissions: [
'list_time_bookings_setup'
]
},
],
hidden: isDepartmentIdUndefined,
permissions: [
'list_time_bookings'
]
},
{
name: 'Dagsopgørelse',
route: '/admin/' + SessionUser.functions.getDepartmentIdFromUrl() + '/modules/daily-report',
@@ -24,6 +24,8 @@ import {Forms} from "@/components/session/token/SessionUser/Objects/Forms.vue";
import {Branding} from "@/components/session/token/SessionUser/Objects/Brandings.vue";
import {Vehicles} from "@/components/session/token/SessionUser/Objects/Vehicles.vue";
import {DepartmentNotificationSms} from "@/components/session/token/SessionUser/Objects/DepartmentNotificationSms.vue";
import {DepartmentTimeBookingsOpeningHours} from "@/components/session/token/SessionUser/Objects/DepartmentTimeBookingsOpeningHours.vue";
import {DepartmentTimeBookingsTypes} from "@/components/session/token/SessionUser/Objects/DepartmentTimeBookingsTypes.vue";
import {ObjectsGlobal} from "@/components/session/token/SessionUser/Objects/ObjectsGlobal.vue";
import {useRouter} from "vue-router";
import Swal from "sweetalert2";
@@ -202,6 +204,8 @@ export const SessionUser = {
Branding: Branding,
vehicles: Vehicles,
department_notification_sms: DepartmentNotificationSms,
department_time_bookings_opening_hours: DepartmentTimeBookingsOpeningHours,
department_time_bookings_types: DepartmentTimeBookingsTypes,
global: ObjectsGlobal,
},
/** The user's token & authentication status */
@@ -378,6 +382,16 @@ export const SessionUser = {
getDateYear(date) {
return new Date(date).getFullYear();
},
getDateAtTime(date, hours, minutes, seconds) {
const newDate = new Date(date);
newDate.setHours(hours);
newDate.setMinutes(minutes);
newDate.setSeconds(seconds);
return newDate;
},
getWeekdayNameToLocal(date) {
return new Date(date).toLocaleString('da-DK', { weekday: 'long' });
}
},
/** Redirect to */
redirectTo: {
@@ -0,0 +1,334 @@
<script>
import Swal from "sweetalert2";
import { authenticatedRequest } from "@/components/session/authenticatedRequest.vue";
import { ObjectsGlobal } from "@/components/session/token/SessionUser/Objects/ObjectsGlobal.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import {ref} from "vue";
/**
* The DepartmentTimeBookingsOpeningHours object
*/
export const DepartmentTimeBookingsOpeningHours = {
meta: {
title: "Tidsbookings åbningstider",
icon: "fas fa-list",
description: "Oversigt over afdelings tidsbookings åbningstider.",
endpoint: "/department/timebookings/opening-hours",
labels: {
single: "åbningstid",
multiple: "åbningstider"
}
},
columns: {
id: {
label: "ID",
type: "number",
sortable: true,
creation: {
required: false
}
},
department: {
label: "Afdeling",
type: "select",
sortable: true,
creation: {
required: true
},
options: async () => {
return SessionUser.objects.departments.get.all();
}
},
monday_start: {
label: "Mandag åbningstid",
type: "time",
sortable: true,
creation: {
required: false
}
},
monday_end: {
label: "Mandag lukketid",
type: "time",
sortable: true,
creation: {
required: false
}
},
tuesday_start: {
label: "Tirsdag åbningstid",
type: "time",
sortable: true,
creation: {
required: false
}
},
tuesday_end: {
label: "Tirsdag lukketid",
type: "time",
sortable: true,
creation: {
required: false
}
},
wednesday_start: {
label: "Onsdag åbningstid",
type: "time",
sortable: true,
creation: {
required: false
}
},
wednesday_end: {
label: "Onsdag lukketid",
type: "time",
sortable: true,
creation: {
required: false
}
},
thursday_start: {
label: "Torsdag åbningstid",
type: "time",
sortable: true,
creation: {
required: false
}
},
thursday_end: {
label: "Torsdag lukketid",
type: "time",
sortable: true,
creation: {
required: false
}
},
friday_start: {
label: "Fredag åbningstid",
type: "time",
sortable: true,
creation: {
required: false
}
},
friday_end: {
label: "Fredag lukketid",
type: "time",
sortable: true,
creation: {
required: false
}
},
saturday_start: {
label: "Lørdag åbningstid",
type: "time",
sortable: true,
creation: {
required: false
}
},
saturday_end: {
label: "Lørdag lukketid",
type: "time",
sortable: true,
creation: {
required: false
}
},
sunday_start: {
label: "Søndag åbningstid",
type: "time",
sortable: true,
creation: {
required: false
}
},
sunday_end: {
label: "Søndag lukketid",
type: "time",
sortable: true,
creation: {
required: false
}
}
},
add: async (department, monday_start = null, monday_end = null, tuesday_start = null, tuesday_end = null, wednesday_start = null, wednesday_end = null, thursday_start = null, thursday_end = null, friday_start = null, friday_end = null, saturday_start = null, saturday_end = null, sunday_start = null, sunday_end = null) => {
return ObjectsGlobal.add.object(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
{
department: parseInt(department),
monday_start: monday_start,
monday_end: monday_end,
tuesday_start: tuesday_start,
tuesday_end: tuesday_end,
wednesday_start: wednesday_start,
wednesday_end: wednesday_end,
thursday_start: thursday_start,
thursday_end: thursday_end,
friday_start: friday_start,
friday_end: friday_end,
saturday_start: saturday_start,
saturday_end: saturday_end,
sunday_start: sunday_start,
sunday_end: sunday_end,
}
);
},
set: {
monday_start: async (id, monday_start) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
id,
"monday_start",
monday_start
)
},
monday_end: async (id, monday_end) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
id,
"monday_end",
monday_end
)
},
tuesday_start: async (id, tuesday_start) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
id,
"tuesday_start",
tuesday_start
)
},
tuesday_end: async (id, tuesday_end) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
id,
"tuesday_end",
tuesday_end
)
},
wednesday_start: async (id, wednesday_start) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
id,
"wednesday_start",
wednesday_start
)
},
wednesday_end: async (id, wednesday_end) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
id,
"wednesday_end",
wednesday_end
)
},
thursday_start: async (id, thursday_start) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
id,
"thursday_start",
thursday_start
)
},
thursday_end: async (id, thursday_end) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
id,
"thursday_end",
thursday_end
)
},
friday_start: async (id, friday_start) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
id,
"friday_start",
friday_start
)
},
friday_end: async (id, friday_end) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
id,
"friday_end",
friday_end
)
},
saturday_start: async (id, saturday_start) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
id,
"saturday_start",
saturday_start
)
},
saturday_end: async (id, saturday_end) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
id,
"saturday_end",
saturday_end
)
},
sunday_start: async (id, sunday_start) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
id,
"sunday_start",
sunday_start
)
},
sunday_end: async (id, sunday_end) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsOpeningHours.meta.endpoint,
id,
"sunday_end",
sunday_end
)
},
},
get: {
all: async () => {
return ObjectsGlobal.get.objects(DepartmentTimeBookingsOpeningHours.meta.endpoint);
},
single: async (id) => {
return ObjectsGlobal.get.object(DepartmentTimeBookingsOpeningHours.meta.endpoint, id);
}
},
delete: async (id) => {
return ObjectsGlobal.delete.object(DepartmentTimeBookingsOpeningHours.meta.endpoint, id);
},
functions: {
showDeleteObjectForm: (id, onAfterSubmit = null) => {
return ObjectsGlobal.showDeleteObjectForm(DepartmentTimeBookingsOpeningHours, id, onAfterSubmit);
},
},
/**
* Show the create object form
* @param onAfterSubmit
* @param lockedValues
* @returns {Promise<SweetAlertResult<Awaited<any>>>}
*/
showCreateObjectForm: (onAfterSubmit = null, lockedValues = {}) => {
return ObjectsGlobal.showCreateObjectForm(DepartmentTimeBookingsOpeningHours, onAfterSubmit, lockedValues);
},
/**
* Show the edit object field form
* @param id
* @param column
* @param value
* @param onAfterSubmit
* @returns {Promise<SweetAlertResult<Awaited<any>>>}
*/
showEditObjectFieldForm: (id, column, value, onAfterSubmit = null) => {
return ObjectsGlobal.showEditObjectFieldForm(
DepartmentTimeBookingsOpeningHours,
id,
column,
value,
onAfterSubmit
);
}
};
</script>
@@ -0,0 +1,147 @@
<script>
import Swal from "sweetalert2";
import { authenticatedRequest } from "@/components/session/authenticatedRequest.vue";
import { ObjectsGlobal } from "@/components/session/token/SessionUser/Objects/ObjectsGlobal.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import {ref} from "vue";
/**
* The DepartmentTimeBookingsTypes object
*/
export const DepartmentTimeBookingsTypes = {
meta: {
title: "Tidsbookings typer",
icon: "fas fa-list",
description: "Oversigt over afdelings tidsbookings typer.",
endpoint: "/department/timebookings/types",
labels: {
single: "booking type",
multiple: "booking typer",
}
},
columns: {
id: {
label: "ID",
type: "number",
sortable: true,
creation: {
required: false
}
},
department: {
label: "Afdeling",
type: "select",
sortable: true,
creation: {
required: true
},
options: async () => {
return SessionUser.objects.departments.get.all();
}
},
name: {
label: "Navn",
type: "string",
sortable: true,
creation: {
required: true
}
},
description: {
label: "Beskrivelse",
type: "string",
sortable: true,
creation: {
required: false
}
},
duration: {
label: "Varighed (minutter)",
type: "number",
sortable: true,
creation: {
required: false
}
},
},
add: async (department, name, description, duration) => {
return ObjectsGlobal.add.object(
DepartmentTimeBookingsTypes.meta.endpoint,
{
department: parseInt(department),
name,
description,
duration: parseInt(duration),
}
);
},
set: {
name: async (id, name) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsTypes.meta.endpoint,
id,
"name",
name
)
},
description: async (id, description) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsTypes.meta.endpoint,
id,
"description",
description
)
},
duration: async (id, duration) => {
return ObjectsGlobal.set.column(
DepartmentTimeBookingsTypes.meta.endpoint,
id,
"duration",
parseInt(duration)
)
},
},
get: {
all: async () => {
return ObjectsGlobal.get.objects(DepartmentTimeBookingsTypes.meta.endpoint);
},
single: async (id) => {
return ObjectsGlobal.get.object(DepartmentTimeBookingsTypes.meta.endpoint, id);
}
},
delete: async (id) => {
return ObjectsGlobal.delete.object(DepartmentTimeBookingsTypes.meta.endpoint, id);
},
functions: {
showDeleteObjectForm: (id, onAfterSubmit = null) => {
return ObjectsGlobal.showDeleteObjectForm(DepartmentTimeBookingsTypes, id, onAfterSubmit);
},
},
/**
* Show the create object form
* @param onAfterSubmit
* @param lockedValues
* @returns {Promise<SweetAlertResult<Awaited<any>>>}
*/
showCreateObjectForm: (onAfterSubmit = null, lockedValues = {}) => {
return ObjectsGlobal.showCreateObjectForm(DepartmentTimeBookingsTypes, onAfterSubmit, lockedValues);
},
/**
* Show the edit object field form
* @param id
* @param column
* @param value
* @param onAfterSubmit
* @returns {Promise<SweetAlertResult<Awaited<any>>>}
*/
showEditObjectFieldForm: (id, column, value, onAfterSubmit = null) => {
return ObjectsGlobal.showEditObjectFieldForm(
DepartmentTimeBookingsTypes,
id,
column,
value,
onAfterSubmit
);
}
};
</script>
@@ -23,8 +23,12 @@ export const ObjectsGlobal = {
close: "Luk",
note: "Note",
succeeded: "Fuldførte",
opening_hours: "Åbningstider",
customers: "Kunder",
selected: "Valgt",
weekday: "Ugedag",
opening_hour: "Åbningstid",
closing_hour: "Lukketid",
found: "Fundet",
waiting: "Afventer",
selected_multiple: "Valgte",
@@ -0,0 +1,68 @@
<script setup>
import { ref, defineProps, defineEmits } from 'vue';
import Calendar from "@/components/timebookings/displays/Calendar.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
// Define props and emits
const props = defineProps({
departmentId: {
type: Number,
required: true
}
});
const getRelativeDate = (date, days) => {
// Get the relative date
const newDate = new Date(date);
newDate.setDate(newDate.getDate() + days);
return newDate;
}
</script>
<template>
<div class="timebookings-calendar">
<h1>Time Bookings Calendar</h1>
<p>This is the Time Bookings Calendar component.</p>
<p>Department ID: {{ departmentId }}</p>
<Calendar
:width="500"
:dates="[
// Today
{
start: SessionUser.functions.date.getDateAtTime(getRelativeDate(new Date(), 0), 0, 0, 1),
end: SessionUser.functions.date.getDateAtTime(getRelativeDate(new Date(), 0), 23, 59, 59)
},
// Tomorrow
{
start: SessionUser.functions.date.getDateAtTime(getRelativeDate(new Date(), 1), 0, 0, 1),
end: SessionUser.functions.date.getDateAtTime(getRelativeDate(new Date(), 1), 23, 59, 59)
},
// The next 5 days
{
start: SessionUser.functions.date.getDateAtTime(getRelativeDate(new Date(), 2), 0, 0, 1),
end: SessionUser.functions.date.getDateAtTime(getRelativeDate(new Date(), 2), 23, 59, 59)
},
{
start: SessionUser.functions.date.getDateAtTime(getRelativeDate(new Date(), 3), 0, 0, 1),
end: SessionUser.functions.date.getDateAtTime(getRelativeDate(new Date(), 3), 23, 59, 59)
},
{
start: SessionUser.functions.date.getDateAtTime(getRelativeDate(new Date(), 4), 0, 0, 1),
end: SessionUser.functions.date.getDateAtTime(getRelativeDate(new Date(), 4), 23, 59, 59)
},
{
start: SessionUser.functions.date.getDateAtTime(getRelativeDate(new Date(), 5), 0, 0, 1),
end: SessionUser.functions.date.getDateAtTime(getRelativeDate(new Date(), 5), 23, 59, 59)
},
{
start: SessionUser.functions.date.getDateAtTime(getRelativeDate(new Date(), 6), 0, 0, 1),
end: SessionUser.functions.date.getDateAtTime(getRelativeDate(new Date(), 6), 23, 59, 59)
}
]"
/>
</div>
</template>
<style scoped>
</style>
@@ -0,0 +1,21 @@
<script setup lang="ts">
import { ref, defineProps, defineEmits } from 'vue';
import { SessionUser } from "@/components/session/token/SessionUser.vue";
</script>
<template>
<div class="columns">
<!-- Calendar -->
<div class="column is-12">
<div id="calendar" class="calendar"></div>
<div class="calendar-controls">
</div>
</div>
</div>
</template>
<style scoped>
</style>
+24
View File
@@ -90,6 +90,12 @@ import DepartmentNotifications
import Vehicles from "@/views/dashboards/superUserDashboard/Vehicles.vue";
import ConfigurationXLVask from "@/views/dashboards/superUserDashboard/configuration/ConfigurationXLVask.vue";
import UserXLVask from "@/views/dashboards/superUserDashboard/user/UserXLVask.vue";
import DepartmentTimeBookings
from "@/views/dashboards/departmentDashboard/modules/time-bookings/DepartmentTimeBookings.vue";
import DepartmentTimeBookingsOpeningHours
from "@/views/dashboards/departmentDashboard/modules/time-bookings/DepartmentTimeBookingsOpeningHours.vue";
import DepartmentTimeBookingsTypes
from "@/views/dashboards/departmentDashboard/modules/time-bookings/DepartmentTimeBookingsTypes.vue";
// Export the router as router
export const router = createRouter({
@@ -222,6 +228,24 @@ export const router = createRouter({
component: DepartmentDailyReport,
meta: { middleware: adminMiddleware }
},
{
name: 'timebookings',
path: '/admin/:departmentId/modules/time-bookings',
component: DepartmentTimeBookings,
meta: { middleware: adminMiddleware }
},
{
name: 'timebookingsopeninghours',
path: '/admin/:departmentId/modules/time-bookings/opening-hours',
component: DepartmentTimeBookingsOpeningHours,
meta: { middleware: adminMiddleware }
},
{
name: 'timebookingstypes',
path: '/admin/:departmentId/modules/time-bookings/types',
component: DepartmentTimeBookingsTypes,
meta: { middleware: adminMiddleware }
},
{
name: 'superuser',
path: '/superuser',
@@ -1,8 +1,4 @@
<script setup>
import DepartmentDashboardHero from "@/views/dashboards/departmentDashboard/DepartmentDashboardHero.vue";
import PosDepartmentMVP from "@/components/displays/department/pos/PosDepartmentMVP.vue";
import DepartmentPosNavigation from "@/views/dashboards/departmentDashboard/modules/Pos/DepartmentPosNavigation.vue";
import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrapper.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import BookingsPagination from "@/components/displays/pagination/models/UserDashboard/BookingsPagination.vue";
@@ -0,0 +1,27 @@
<script setup>
import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrapper.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import DepartmentDashboardPageWrapper from "@/views/dashboards/departmentDashboard/DepartmentDashboardPageWrapper.vue";
import NotFoundFallBackPageWrapper from "@/components/page/wrappers/NotFoundFallBackPageWrapper.vue";
import TimeBookingsCalendar from "@/components/timebookings/TimeBookingsCalendar.vue";
</script>
<template>
<RestrictedPageWrapper :hasPermission="SessionUser.canAccessAdmin()">
<DepartmentDashboardPageWrapper
title="Tidsbookinger"
subtitle="Oversigt over tidsbookinger"
>
<NotFoundFallBackPageWrapper :exists="SessionUser.functions.getDepartmentIdFromUrl() && SessionUser.canAccessDepartment(SessionUser.functions.getDepartmentIdFromUrl())" error="Please select a department, that you have access to. If you believe this is an error, please contact support.">
<!-- Calendar -->
<TimeBookingsCalendar
:departmentId="SessionUser.functions.getDepartmentIdFromUrl()"
/>
</NotFoundFallBackPageWrapper>
</DepartmentDashboardPageWrapper>
</RestrictedPageWrapper>
</template>
<style scoped>
</style>
@@ -0,0 +1,123 @@
<script setup>
import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrapper.vue";
import {SessionUser} from "@/components/session/token/SessionUser.vue";
import DepartmentDashboardPageWrapper from "@/views/dashboards/departmentDashboard/DepartmentDashboardPageWrapper.vue";
import NotFoundFallBackPageWrapper from "@/components/page/wrappers/NotFoundFallBackPageWrapper.vue";
import {ref} from 'vue';
const opening_hours = ref(null);
const isOpeningHoursLoaded = () => { return opening_hours.value !== null; }
const weekday_opening_hours = (start, end) => {
return {
start: start,
end: end,
active: function() {
return this.start !== null && this.end !== null;
},
}
}
const generateWeekDay = (name, label, start = null, end = null) => {
return {
name: name,
label: label,
...weekday_opening_hours(start, end),
}
}
const weekdays = ref([
generateWeekDay('monday', 'Mandag'),
generateWeekDay('tuesday', 'Tirsdag'),
generateWeekDay('wednesday', 'Onsdag'),
generateWeekDay('thursday', 'Torsdag'),
generateWeekDay('friday', 'Fredag'),
generateWeekDay('saturday', 'Lørdag'),
generateWeekDay('sunday', 'Søndag'),
]);
const onChangeTime = (name, value) => {
console.log(name, value);
let opening_hours_id = opening_hours.value.id;
SessionUser.objects.department_time_bookings_opening_hours.set[name](opening_hours_id, value);
}
const getControlClass = (weekday, type) => {
return '';
}
const getOpeningHours = (departmentId) => {
// Fetch the opening hours for the department
SessionUser.request(
SessionUser.objects.department_time_bookings_opening_hours.meta.endpoint,
'GET',
{
department: departmentId
}
).then((response) => {
console.log('response', response.data.data);
// Check if there's any object in the response
opening_hours.value = response.data.data;
})
.catch((error) => {
console.error('Error fetching opening hours:', error);
});
}
const departmentId = SessionUser.functions.getDepartmentIdFromUrl();
if (departmentId) {
getOpeningHours(departmentId);
} else {
console.error('Department ID not found in URL');
}
const getOpeningHoursValue = (name) => {
if (opening_hours.value === null) {
return '';
}
return opening_hours.value[name];
}
</script>
<template>
<RestrictedPageWrapper :hasPermission="SessionUser.canAccessAdmin()">
<DepartmentDashboardPageWrapper
:title="SessionUser.objects.global.language.opening_hours"
subtitle="Afdelingens åbningstider"
>
<NotFoundFallBackPageWrapper :exists="SessionUser.functions.getDepartmentIdFromUrl() && SessionUser.canAccessDepartment(SessionUser.functions.getDepartmentIdFromUrl())" error="Please select a department, that you have access to. If you believe this is an error, please contact support.">
<table class="table is-striped is-bordered is-hoverable is-fullwidth">
<thead>
<tr>
<th>{{SessionUser.objects.global.language.weekday}}</th>
<th>{{SessionUser.objects.global.language.opening_hour}}</th>
<th>{{SessionUser.objects.global.language.closing_hour}}</th>
</tr>
</thead>
<tbody>
<tr v-for="(weekday, index) in weekdays" :key="index">
<td>{{ weekday.label }}</td>
<td>
<div class="control" :class="getControlClass(weekday, 'start')">
<input type="time" class="input" @change="onChangeTime(weekday.name + '_start', $event.target.value)" v-if="isOpeningHoursLoaded()" :value="getOpeningHoursValue(weekday.name + '_start')" />
<input type="time" class="input is-skeleton" v-else disabled/>
</div>
</td>
<td>
<div class="control" :class="getControlClass(weekday, 'end')">
<input type="time" class="input" @change="onChangeTime(weekday.name + '_end', $event.target.value)" v-if="isOpeningHoursLoaded()" :value="getOpeningHoursValue(weekday.name + '_end')" />
<input type="time" class="input is-skeleton" v-else disabled/>
</div>
</td>
</tr>
</tbody>
</table>
</NotFoundFallBackPageWrapper>
</DepartmentDashboardPageWrapper>
</RestrictedPageWrapper>
</template>
<style scoped>
</style>
@@ -0,0 +1,26 @@
<script setup>
import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrapper.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import DepartmentDashboardPageWrapper from "@/views/dashboards/departmentDashboard/DepartmentDashboardPageWrapper.vue";
import NotFoundFallBackPageWrapper from "@/components/page/wrappers/NotFoundFallBackPageWrapper.vue";
import TimeBookingsCalendar from "@/components/timebookings/TimeBookingsCalendar.vue";
import TimeBookingsTypesPagination
from "@/components/displays/pagination/models/DepartmentPos/TimeBookingsTypesPagination.vue";
</script>
<template>
<RestrictedPageWrapper :hasPermission="SessionUser.canAccessAdmin()">
<DepartmentDashboardPageWrapper
title="Tidsbookinger"
subtitle="Oversigt over tidsbookinger"
>
<NotFoundFallBackPageWrapper :exists="SessionUser.functions.getDepartmentIdFromUrl() && SessionUser.canAccessDepartment(SessionUser.functions.getDepartmentIdFromUrl())" error="Please select a department, that you have access to. If you believe this is an error, please contact support.">
<TimeBookingsTypesPagination/>
</NotFoundFallBackPageWrapper>
</DepartmentDashboardPageWrapper>
</RestrictedPageWrapper>
</template>
<style scoped>
</style>