From 6a89b7bc4779483a1f353c73cf0d4402ee2c8347 Mon Sep 17 00:00:00 2001 From: JakubPapso Date: Tue, 6 Feb 2024 19:20:09 +0100 Subject: [PATCH] [timeblocks] --- .../tm@modal/_mixins/vuetify-fix-focus.ts | 6 + .../tm@modal/blocker/z-blocker-modal.vue | 5 +- .../master-task/z-master-task-modal.vue | 1 + .../tm@modal/task/_components/a-timeblock.vue | 103 +++++++++++++++ .../plugins/tm@modal/task/z-task-modal.vue | 120 +++++++++++++++--- 5 files changed, 218 insertions(+), 17 deletions(-) create mode 100644 app/src/plugins/tm@modal/task/_components/a-timeblock.vue diff --git a/app/src/plugins/tm@modal/_mixins/vuetify-fix-focus.ts b/app/src/plugins/tm@modal/_mixins/vuetify-fix-focus.ts index cadcb57..7e55738 100644 --- a/app/src/plugins/tm@modal/_mixins/vuetify-fix-focus.ts +++ b/app/src/plugins/tm@modal/_mixins/vuetify-fix-focus.ts @@ -7,6 +7,12 @@ export default { }, methods: { + setFocusEvent() { + document.querySelectorAll('.v-autocomplete input').forEach(input => { + input.addEventListener('focus', this.onInputFocus) + }) + }, + onDateFocus($event) { if ($event == undefined) { this.preventInputFocus = true diff --git a/app/src/plugins/tm@modal/blocker/z-blocker-modal.vue b/app/src/plugins/tm@modal/blocker/z-blocker-modal.vue index eda6ef9..c93cf23 100644 --- a/app/src/plugins/tm@modal/blocker/z-blocker-modal.vue +++ b/app/src/plugins/tm@modal/blocker/z-blocker-modal.vue @@ -98,7 +98,10 @@ export default { this.starts_at_time = null this.ends_at_time = null - this.$nextTick(() => this.v$.$reset()) + this.$nextTick(() => { + this.setFocusEvent() + this.v$.$reset() + }) try { if (blocker?.id) { diff --git a/app/src/plugins/tm@modal/master-task/z-master-task-modal.vue b/app/src/plugins/tm@modal/master-task/z-master-task-modal.vue index d786a4a..ff75880 100644 --- a/app/src/plugins/tm@modal/master-task/z-master-task-modal.vue +++ b/app/src/plugins/tm@modal/master-task/z-master-task-modal.vue @@ -260,6 +260,7 @@ export default { this.visible = true this.mastertask = null this.$nextTick(() => { + this.setFocusEvent() this.v$.$reset() }) diff --git a/app/src/plugins/tm@modal/task/_components/a-timeblock.vue b/app/src/plugins/tm@modal/task/_components/a-timeblock.vue new file mode 100644 index 0000000..9ee7d38 --- /dev/null +++ b/app/src/plugins/tm@modal/task/_components/a-timeblock.vue @@ -0,0 +1,103 @@ + + + + +e \ No newline at end of file diff --git a/app/src/plugins/tm@modal/task/z-task-modal.vue b/app/src/plugins/tm@modal/task/z-task-modal.vue index 9f26eba..b67a629 100644 --- a/app/src/plugins/tm@modal/task/z-task-modal.vue +++ b/app/src/plugins/tm@modal/task/z-task-modal.vue @@ -16,7 +16,7 @@
- +
@@ -62,11 +62,28 @@ + + +
+ +
+ + +
+
+ @@ -123,7 +140,7 @@ import Datepicker from '@vuepic/vue-datepicker' import ZFilesUpload from '@/plugins/tm@_components/z-files-upload.vue' import ATaskTimeblocks from '@/plugins/tm@modal/task/_components/_components/a-task-timeblocks.vue' import useVuelidate from '@vuelidate/core' -import { required, requiredIf } from '@vuelidate/validators' +import { required, requiredIf, optional } from '@vuelidate/validators' import errorUtils from '@/plugins/lib@auth/_utils/error.utils' import { QuillEditor } from '@vueup/vue-quill' import VuetifyFixFocusMixin from '@/plugins/tm@modal/_mixins/vuetify-fix-focus' @@ -135,15 +152,19 @@ import '@vueup/vue-quill/dist/vue-quill.snow.css' import AutocompleteMixin from '@/plugins/tm@_mixins/autocomplete.mixin' import ZTaskReadonlyInfo from './_components/z-task-readonly-info.vue' +import ATimeblock from './_components/a-timeblock.vue' import { mapGetters } from 'vuex' import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin' +import axios from 'axios' + export default { emits: ['close', 'refresh'], mixins: [VuetifyFixFocusMixin, SelectsMixin, AutocompleteMixin, modalMixin], components: { ZTaskReadonlyInfo, + ATimeblock, ZFilesUpload, Datepicker, // ATaskTimeblocks, @@ -160,9 +181,13 @@ export default { errorUtils, v$: useVuelidate(), employeeValidations: [], - preventInputFocus: false, showDatePicker: false, - selectedNewDate: [] + selectedNewDate: [], + timeblocks: [{ + date: null, + starts_at_time: null, + ends_at_time: null + }] } }, @@ -176,9 +201,6 @@ export default { master_task_id: { required }, deadline: { required }, _deadline_time: { required }, - // starts_at_time: { requiredIf: requiredIf(this.subtask.date) }, - // ends_at_time: { requiredIf: requiredIf(this.subtask.starts_at_time) } - // description: { required } } } }, @@ -210,11 +232,28 @@ export default { }, methods: { + updateTimeblock(val, index) { + this.timeblocks[index] = val + }, + + removeTimeblock(index) { + this.timeblocks.splice(index, 1) + }, + async showModal({ subtask, editMode = false, mastertask = {} }) { + console.log(subtask) this.isSaving = false this.subtask = null this.visible = true - this.$nextTick(() => this.v$.$reset()) + this.timeblocks = [{ + date: null, + starts_at_time: null, + ends_at_time: null + }] + this.$nextTick(() => { + this.v$.$reset() + this.setFocusEvent() + }) try { if (subtask?.id) { @@ -263,9 +302,10 @@ export default { async save() { const employeesValid = await this._validateEmployees() + const timeblocksValid = this.subtask?.id ? true : await this._validateTimeblocks() if (!(await this.v$.$validate())) return - if (!employeesValid) return + if (!employeesValid || !timeblocksValid) return this.subtask.description = this.$refs['description'].getHTML() this._mergeDeadlineTimeDate() @@ -286,7 +326,13 @@ export default { this.$store.commit('tm/update_subtask', subtask) this.$events.emit('on-subtask-edited', this.subtask) } else { - const { subtasks } = await this.$axios.post_auth(`v1/mastertasks/${this.subtask.master_task_id}/subtasks`, this.subtask) + this.subtask.employees.forEach(employee => { + if (employee.id) + employee.timeblocks = this.timeblocks.filter(timeblock => timeblock.date).map(timeblock => { return { start: `${moment(timeblock.date).format('YYYY-MM-DD')} ${timeblock.starts_at_time}:00`, end: `${moment(timeblock.date).format('YYYY-MM-DD')} ${timeblock.ends_at_time}:00`, id: null } }) + }) + const subtaskCopy = JSON.parse(JSON.stringify(this.subtask)) + delete subtaskCopy._master_task + const { subtasks } = await this.$axios.post_auth(`v1/mastertasks/${this.subtask.master_task_id}/subtasks`, subtaskCopy) this.subtask.id = subtasks[0].id subtasks.forEach((subtask) => { @@ -364,6 +410,15 @@ export default { }) }, + async _validateTimeblocks() { + let invalid = false + for(let i = 0; i < this.timeblocks.length; i++) { + const ref = this.$refs[`timetable-${i}`] + invalid = await ref[0].v$.$validate() || invalid + } + return invalid + }, + _enrichTask(subtask) { return { ...subtask, @@ -470,8 +525,41 @@ export default { .files margin-top: 104px !important -// .splitted-time-inputs -// display: flex !important -// flex-direction: row !important -// gap: 15px +.timeblocks + display: flex + flex-direction: column + align-items: center + border-bottom: 1px solid #e0e0e0 + + .end-button + width: 100% + display: flex + justify-content: flex-end + align-items: center + border-top: 1px solid #e0e0e0 + height: 70px + + button + background: #7f39fb !important + border-radius: 4px !important + color: #fff !important + height: 50px + width: 203px + + .splitted-time-inputs + display: flex !important + flex-direction: row !important + gap: 15px + margin-bottom: -11px + +.timeblock + position: relative + border-top: 1px solid #e0e0e0 + padding: 20px 0 10px 0 + + .splitted-time-inputs + display: flex !important + flex-direction: row !important + gap: 15px + margin-bottom: -11px