mirror of
https://bitbucket.org/studiotem/jandl-taskmanager-app.git
synced 2026-10-21 06:20:21 +00:00
feat(modals): replace datepicker and time fields with employee timeblock component for improved time management
This commit is contained in:
1 parent
fdb4452447
commit
1ce56c544c
2 files changed
+111
-81
No files matched your search
@@ -46,49 +46,14 @@
|
|||||||
variant="solo"
|
variant="solo"
|
||||||
class="modal-input"
|
class="modal-input"
|
||||||
/>
|
/>
|
||||||
<!-- <Z-autocomplete label="Vyhľadať zamestnanca" :value="blocker?.employee ? `${blocker?.employee?.name} ${blocker?.employee?.surname}` : ''" :options="enrichedEmployees.map(employee => ({key: employee.id, value: employee._fullName}))" :clear-on-submit="false" :class="{ error: v$.blocker.employee.$errors.length }" class="modal-input" @option-selected="onEmployeeSelected" /> -->
|
|
||||||
<Z-datepicker
|
<!-- Timeblock Component -->
|
||||||
v-model="datepicker"
|
<a-employee-timeblock
|
||||||
class="modal-input mb-5"
|
ref="employeeTimeblockRef"
|
||||||
:auto-apply="true"
|
v-model="timeblockData"
|
||||||
format="dd.MM.yyyy"
|
:employee="selectedEmployee"
|
||||||
locale="sk"
|
:deletable="false"
|
||||||
:class="{ error: v$.datepicker.$errors?.length }"
|
:index="0"
|
||||||
:validations="v$.datepicker"
|
|
||||||
select-text="Vybrať"
|
|
||||||
cancel-text="Zrušiť"
|
|
||||||
placeholder="Dátum"
|
|
||||||
label="Dátum"
|
|
||||||
:enable-time-picker="false"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<v-text-field
|
|
||||||
v-model="starts_at_time"
|
|
||||||
type="time"
|
|
||||||
variant="solo"
|
|
||||||
bg-color="white"
|
|
||||||
:hint="
|
|
||||||
v$.starts_at_time.$errors
|
|
||||||
? errorUtils.parseErrors(v$.starts_at_time.$errors)
|
|
||||||
: null
|
|
||||||
"
|
|
||||||
:class="{ error: v$.starts_at_time.$errors.length }"
|
|
||||||
class="mb-1 modal-input"
|
|
||||||
label="Začiatok"
|
|
||||||
/>
|
|
||||||
<v-text-field
|
|
||||||
v-model="ends_at_time"
|
|
||||||
type="time"
|
|
||||||
variant="solo"
|
|
||||||
bg-color="white"
|
|
||||||
:hint="
|
|
||||||
v$.ends_at_time.$errors
|
|
||||||
? errorUtils.parseErrors(v$.ends_at_time.$errors)
|
|
||||||
: null
|
|
||||||
"
|
|
||||||
:class="{ error: v$.ends_at_time.$errors.length }"
|
|
||||||
class="modal-input"
|
|
||||||
label="Koniec"
|
|
||||||
/>
|
/>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
|
|
||||||
@@ -107,7 +72,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ZDatepicker from '@/plugins/tm@_components/z-datepicker.vue';
|
|
||||||
import useVuelidate from '@vuelidate/core';
|
import useVuelidate from '@vuelidate/core';
|
||||||
import { required } from '@vuelidate/validators';
|
import { required } from '@vuelidate/validators';
|
||||||
import errorUtils from '@/plugins/lib@auth/_utils/error.utils';
|
import errorUtils from '@/plugins/lib@auth/_utils/error.utils';
|
||||||
@@ -118,14 +82,14 @@ import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
|
|||||||
import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue';
|
import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue';
|
||||||
import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue';
|
import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue';
|
||||||
import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue';
|
import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue';
|
||||||
|
import AEmployeeTimeblock from '@/plugins/tm@modal/task/_components/employees/a-employee-timeblock.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
ZDatepicker,
|
|
||||||
// ZAutocomplete
|
|
||||||
AResizeHandle,
|
AResizeHandle,
|
||||||
AResetSizeButton,
|
AResetSizeButton,
|
||||||
ACloseButton,
|
ACloseButton,
|
||||||
|
AEmployeeTimeblock,
|
||||||
},
|
},
|
||||||
mixins: [AutocompleteMixin, modalMixin],
|
mixins: [AutocompleteMixin, modalMixin],
|
||||||
|
|
||||||
@@ -137,9 +101,13 @@ export default {
|
|||||||
v$: useVuelidate(),
|
v$: useVuelidate(),
|
||||||
errorUtils,
|
errorUtils,
|
||||||
blocker: null,
|
blocker: null,
|
||||||
datepicker: null,
|
timeblockData: {
|
||||||
starts_at_time: null,
|
id: null,
|
||||||
ends_at_time: null,
|
date: new Date(),
|
||||||
|
starts_at_time: null,
|
||||||
|
ends_at_time: null,
|
||||||
|
employee_id: null,
|
||||||
|
},
|
||||||
employee: null,
|
employee: null,
|
||||||
modalName: 'z-blocker-modal',
|
modalName: 'z-blocker-modal',
|
||||||
modalSize: 'large',
|
modalSize: 'large',
|
||||||
@@ -150,6 +118,13 @@ export default {
|
|||||||
...mapGetters('tm', ['enrichedEmployees']),
|
...mapGetters('tm', ['enrichedEmployees']),
|
||||||
|
|
||||||
...mapGetters('auth', ['user']),
|
...mapGetters('auth', ['user']),
|
||||||
|
|
||||||
|
selectedEmployee() {
|
||||||
|
if (!this.blocker?.employee_id) return null;
|
||||||
|
return this.enrichedEmployees.find(
|
||||||
|
(emp) => emp.id === this.blocker.employee_id,
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
validations() {
|
validations() {
|
||||||
@@ -158,25 +133,27 @@ export default {
|
|||||||
name: { required },
|
name: { required },
|
||||||
start: { required },
|
start: { required },
|
||||||
end: { required },
|
end: { required },
|
||||||
// employee: { required }
|
|
||||||
},
|
},
|
||||||
|
|
||||||
starts_at_time: { required },
|
|
||||||
ends_at_time: { required },
|
|
||||||
datepicker: { required },
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
ends_at_time() {
|
'blocker.employee_id'(newEmployeeId) {
|
||||||
|
// Update timeblock employee_id when blocker employee changes
|
||||||
|
if (this.timeblockData) {
|
||||||
|
this.timeblockData.employee_id = newEmployeeId;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
'timeblockData.date'() {
|
||||||
this._syncDatesTimes();
|
this._syncDatesTimes();
|
||||||
},
|
},
|
||||||
|
|
||||||
starts_at_time() {
|
'timeblockData.starts_at_time'() {
|
||||||
this._syncDatesTimes();
|
this._syncDatesTimes();
|
||||||
},
|
},
|
||||||
|
|
||||||
datepicker() {
|
'timeblockData.ends_at_time'() {
|
||||||
this._syncDatesTimes();
|
this._syncDatesTimes();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -185,9 +162,13 @@ export default {
|
|||||||
async showModal({ blocker }) {
|
async showModal({ blocker }) {
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
this.blocker = null;
|
this.blocker = null;
|
||||||
this.datepicker = null;
|
this.timeblockData = {
|
||||||
this.starts_at_time = null;
|
id: null,
|
||||||
this.ends_at_time = null;
|
date: new Date(),
|
||||||
|
starts_at_time: null,
|
||||||
|
ends_at_time: null,
|
||||||
|
employee_id: null,
|
||||||
|
};
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.v$.$reset();
|
this.v$.$reset();
|
||||||
@@ -199,11 +180,18 @@ export default {
|
|||||||
`v1/blockers/${blocker.id}`,
|
`v1/blockers/${blocker.id}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.starts_at_time = moment(blocker.start).format('HH:mm');
|
const startMoment = moment(blocker.start);
|
||||||
this.ends_at_time = moment(blocker.end).format('HH:mm');
|
const endMoment = moment(blocker.end);
|
||||||
this.datepicker = new Date(blocker.start);
|
|
||||||
|
this.timeblockData = {
|
||||||
|
id: null,
|
||||||
|
date: startMoment.toDate(),
|
||||||
|
starts_at_time: startMoment.format('HH:mm'),
|
||||||
|
ends_at_time: endMoment.format('HH:mm'),
|
||||||
|
employee_id: blocker.employee.id,
|
||||||
|
};
|
||||||
|
|
||||||
blocker.employee_id = blocker.employee.id;
|
blocker.employee_id = blocker.employee.id;
|
||||||
//fixnut validacie employee_id
|
|
||||||
this.blocker = blocker;
|
this.blocker = blocker;
|
||||||
} else {
|
} else {
|
||||||
this.blocker = { start: null, employee_id: this.user.id };
|
this.blocker = { start: null, employee_id: this.user.id };
|
||||||
@@ -213,9 +201,16 @@ export default {
|
|||||||
blocker.datepicker &&
|
blocker.datepicker &&
|
||||||
blocker.employee_id
|
blocker.employee_id
|
||||||
) {
|
) {
|
||||||
this.datepicker = blocker.datepicker;
|
this.timeblockData = {
|
||||||
this.starts_at_time = blocker.starts_at_time;
|
id: null,
|
||||||
|
date: blocker.datepicker,
|
||||||
|
starts_at_time: blocker.starts_at_time,
|
||||||
|
ends_at_time: blocker.ends_at_time,
|
||||||
|
employee_id: blocker.employee_id,
|
||||||
|
};
|
||||||
this.blocker.employee_id = blocker.employee_id;
|
this.blocker.employee_id = blocker.employee_id;
|
||||||
|
} else {
|
||||||
|
this.timeblockData.employee_id = this.user.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -224,11 +219,13 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async save() {
|
async save() {
|
||||||
if (!(await this.v$.$validate())) return;
|
// Validate using the employee timeblock component's validation
|
||||||
|
const isTimeblockValid =
|
||||||
|
await this.$refs.employeeTimeblockRef?.validate();
|
||||||
|
|
||||||
|
if (!isTimeblockValid || !(await this.v$.$validate())) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// this.blocker.employee_id = this.blocker.employee?.id
|
|
||||||
|
|
||||||
if (this.blocker.id) {
|
if (this.blocker.id) {
|
||||||
const { blocker } = await this.$axios.put_auth(
|
const { blocker } = await this.$axios.put_auth(
|
||||||
`v1/blockers/${this.blocker.id}`,
|
`v1/blockers/${this.blocker.id}`,
|
||||||
@@ -253,29 +250,34 @@ export default {
|
|||||||
|
|
||||||
closeModal() {
|
closeModal() {
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
|
this.timeblockData = {
|
||||||
|
id: null,
|
||||||
|
date: new Date(),
|
||||||
|
starts_at_time: null,
|
||||||
|
ends_at_time: null,
|
||||||
|
employee_id: null,
|
||||||
|
};
|
||||||
this.$emit('close', this.blocker);
|
this.$emit('close', this.blocker);
|
||||||
},
|
},
|
||||||
|
|
||||||
onEmployeeSelected({ key }) {
|
|
||||||
this.blocker.employee = this.enrichedEmployees.find(
|
|
||||||
(employee) => employee.id == key,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
_syncDatesTimes() {
|
_syncDatesTimes() {
|
||||||
if (!this.starts_at_time || !this.ends_at_time || !this.datepicker)
|
if (
|
||||||
|
!this.timeblockData.starts_at_time ||
|
||||||
|
!this.timeblockData.ends_at_time ||
|
||||||
|
!this.timeblockData.date
|
||||||
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const splittedStart = this.starts_at_time.split(':');
|
const splittedStart = this.timeblockData.starts_at_time.split(':');
|
||||||
const splittedEnd = this.ends_at_time.split(':');
|
const splittedEnd = this.timeblockData.ends_at_time.split(':');
|
||||||
|
|
||||||
this.blocker.start = moment(this.datepicker)
|
this.blocker.start = moment(this.timeblockData.date)
|
||||||
.set({
|
.set({
|
||||||
hours: parseInt(splittedStart[0]),
|
hours: parseInt(splittedStart[0]),
|
||||||
minutes: parseInt(splittedStart[1]),
|
minutes: parseInt(splittedStart[1]),
|
||||||
})
|
})
|
||||||
.format('YYYY-MM-DD HH:mm');
|
.format('YYYY-MM-DD HH:mm');
|
||||||
this.blocker.end = moment(this.datepicker)
|
this.blocker.end = moment(this.timeblockData.date)
|
||||||
.set({
|
.set({
|
||||||
hours: parseInt(splittedEnd[0]),
|
hours: parseInt(splittedEnd[0]),
|
||||||
minutes: parseInt(splittedEnd[1]),
|
minutes: parseInt(splittedEnd[1]),
|
||||||
@@ -340,3 +342,13 @@ function oo_cm() {
|
|||||||
return v;
|
return v;
|
||||||
} /*eslint unicorn/no-abusive-eslint-disable:,eslint-comments/disable-enable-pair:,eslint-comments/no-unlimited-disable:,eslint-comments/no-aggregating-enable:,eslint-comments/no-duplicate-disable:,eslint-comments/no-unused-disable:,eslint-comments/no-unused-enable:,*/
|
} /*eslint unicorn/no-abusive-eslint-disable:,eslint-comments/disable-enable-pair:,eslint-comments/no-unlimited-disable:,eslint-comments/no-aggregating-enable:,eslint-comments/no-duplicate-disable:,eslint-comments/no-unused-disable:,eslint-comments/no-unused-enable:,*/
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass" scoped>
|
||||||
|
::v-deep
|
||||||
|
// Hide employee select and add/remove buttons in timeblock component
|
||||||
|
.timeblock__header__top
|
||||||
|
display: none
|
||||||
|
|
||||||
|
.actions
|
||||||
|
display: none
|
||||||
|
</style>
|
||||||
@@ -832,8 +832,16 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!data.deadline) {
|
if (!data.deadline) {
|
||||||
|
this.subtask = this._enrichTask(data);
|
||||||
this.editMode = editMode || !data.id;
|
this.editMode = editMode || !data.id;
|
||||||
return (this.subtask = this._enrichTask(data));
|
|
||||||
|
// Set Quill editor content after subtask is loaded and editMode is set
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs['description']) {
|
||||||
|
this.$refs['description'].setHTML(this.subtask.description || '');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const splittedDeadline = data.deadline.split(' ');
|
const splittedDeadline = data.deadline.split(' ');
|
||||||
@@ -963,6 +971,16 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.editMode = editMode || !this.subtask.id;
|
this.editMode = editMode || !this.subtask.id;
|
||||||
|
|
||||||
|
// Set Quill editor content after editMode is set
|
||||||
|
// This ensures the description is loaded when opening in edit mode
|
||||||
|
if (this.editMode) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs['description']) {
|
||||||
|
this.$refs['description'].setHTML(this.subtask?.description || '');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$toast.error(this.$parseError(error));
|
this.$toast.error(this.$parseError(error));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user