mirror of
https://bitbucket.org/studiotem/jandl-taskmanager-app.git
synced 2026-10-21 14:29:34 +00:00
feat(z-task-modal): improve employee selection logic and add weekend overlay in timeblock components
This commit is contained in:
1 parent
1b666a63a3
commit
198f50dfc1
3 files changed
+81
-20
No files matched your search
@@ -47,6 +47,9 @@
|
||||
}"
|
||||
></div>
|
||||
|
||||
<!-- Weekend background overlay -->
|
||||
<div v-if="isWeekend" class="weekend-overlay"></div>
|
||||
|
||||
<!-- Existing scheduled blocks -->
|
||||
<div
|
||||
v-for="(task, index) in scheduledBlocks"
|
||||
@@ -257,6 +260,15 @@ const dragState = ref({
|
||||
});
|
||||
const resizedCurrentBlock = ref<{ start: Date; end: Date } | null>(null);
|
||||
|
||||
// Check if the current date is a weekend (Saturday or Sunday)
|
||||
const isWeekend = computed(() => {
|
||||
const date = props.currentTimeblockRange.start;
|
||||
if (!date) return false;
|
||||
|
||||
const dayOfWeek = moment(date).day(); // 0 = Sunday, 6 = Saturday
|
||||
return dayOfWeek === 0 || dayOfWeek === 6;
|
||||
});
|
||||
|
||||
// Convert other timeblocks to renderable format
|
||||
const otherTimeblocksRendered = computed(() => {
|
||||
return props.otherTimeblocks
|
||||
@@ -728,6 +740,17 @@ defineExpose({
|
||||
z-index: 1
|
||||
pointer-events: none
|
||||
|
||||
.weekend-overlay
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
width: 100%
|
||||
height: 100%
|
||||
background: rgba(255, 124, 124, 0.3) !important
|
||||
z-index: 1
|
||||
pointer-events: none
|
||||
border-radius: 4px
|
||||
|
||||
.scheduled-block
|
||||
position: absolute
|
||||
top: 5px
|
||||
|
||||
@@ -281,15 +281,39 @@ const scheduledBlocks = computed(() => {
|
||||
);
|
||||
});
|
||||
|
||||
// Recalculate collision using filtered scheduled blocks (not raw timeline tasks)
|
||||
// This prevents false collisions with timeblocks being edited
|
||||
const collision = computed(() => {
|
||||
return detectCollision(props.modelValue, scheduledBlocks.value);
|
||||
// Convert other unsaved timeblocks to task format for collision detection
|
||||
const otherTimeblocksAsTasks = computed(() => {
|
||||
return otherTimeblocksForSameDate.value
|
||||
.map((tb) => {
|
||||
const { start, end } = timeblockToDateRange(tb);
|
||||
if (!start || !end) return null;
|
||||
|
||||
return {
|
||||
_real_start: start,
|
||||
_real_end: end,
|
||||
_timeblock_id: tb.id || null,
|
||||
};
|
||||
})
|
||||
.filter((task) => task !== null);
|
||||
});
|
||||
|
||||
// Recalculate collision segments using filtered scheduled blocks
|
||||
// Combine scheduled blocks with other unsaved timeblocks for collision detection
|
||||
const allBlocksForCollisionCheck = computed(() => {
|
||||
return [...scheduledBlocks.value, ...otherTimeblocksAsTasks.value];
|
||||
});
|
||||
|
||||
// Recalculate collision using filtered scheduled blocks AND other unsaved timeblocks
|
||||
// This prevents false collisions with timeblocks being edited, but catches collisions with other unsaved timeblocks
|
||||
const collision = computed(() => {
|
||||
return detectCollision(props.modelValue, allBlocksForCollisionCheck.value);
|
||||
});
|
||||
|
||||
// Recalculate collision segments using filtered scheduled blocks AND other unsaved timeblocks
|
||||
const collisionSegments = computed(() => {
|
||||
return getCollisionSegmentsUtil(props.modelValue, scheduledBlocks.value);
|
||||
return getCollisionSegmentsUtil(
|
||||
props.modelValue,
|
||||
allBlocksForCollisionCheck.value,
|
||||
);
|
||||
});
|
||||
|
||||
// Get current timeblock range
|
||||
|
||||
@@ -531,19 +531,20 @@ export default {
|
||||
const employeeId = itemObject.value;
|
||||
|
||||
if (!this.subtask.id) {
|
||||
// New subtask with multiple employees support or edit of draft with multiple employees
|
||||
return (
|
||||
shouldShowItem &&
|
||||
!this.timeblocks.some((tb) => tb.employee_id === employeeId)
|
||||
// New subtask with multiple employees support
|
||||
// Hide employees that are already selected in any slot
|
||||
// The v-autocomplete will still display the currently selected employee
|
||||
const isAlreadySelected = this.subtask.employees.some(
|
||||
(emp) => emp.id && Number(emp.id) === employeeId,
|
||||
);
|
||||
return shouldShowItem && !isAlreadySelected;
|
||||
} else if (this.subtask.is_draft) {
|
||||
// Edit draft subtask with multiple employees support
|
||||
return (
|
||||
shouldShowItem &&
|
||||
!this.subtask.employees.some(
|
||||
(employee) => Number(employee.id) === employeeId,
|
||||
)
|
||||
// Hide employees that are already selected in any slot
|
||||
const isAlreadySelected = this.subtask.employees.some(
|
||||
(emp) => emp.id && Number(emp.id) === employeeId,
|
||||
);
|
||||
return shouldShowItem && !isAlreadySelected;
|
||||
} else {
|
||||
// Saved standard subtask, allow "re-select" for better UX
|
||||
return shouldShowItem;
|
||||
@@ -1046,8 +1047,9 @@ export default {
|
||||
|
||||
// For drafts with multiple employees, include employees array
|
||||
if (this.subtask.is_draft && this.isDraftWithMultipleEmployees) {
|
||||
const validEmployees = this.subtask.employees.filter(
|
||||
(employee) => employee.id && employee.duration,
|
||||
const validEmployees = this._filterValidEmployees(
|
||||
this.subtask.employees,
|
||||
concept,
|
||||
);
|
||||
|
||||
// Assign timeblocks to each employee
|
||||
@@ -1090,9 +1092,9 @@ export default {
|
||||
this.$store.commit('tm/update_subtask', subtask);
|
||||
this.$events.emit('on-subtask-edited', this.subtask);
|
||||
} else {
|
||||
// Filter out employees that don't have both id and duration
|
||||
const validEmployees = this.subtask.employees.filter(
|
||||
(employee) => employee.id && employee.duration,
|
||||
const validEmployees = this._filterValidEmployees(
|
||||
this.subtask.employees,
|
||||
concept,
|
||||
);
|
||||
|
||||
// Assign timeblocks to each employee based on employee_id
|
||||
@@ -1198,6 +1200,18 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
_filterValidEmployees(employees, isConcept) {
|
||||
// Filter employees based on whether it's a concept/draft or published task
|
||||
// For concepts: only require id (duration can be null/0)
|
||||
// For published tasks: require both id and duration
|
||||
return employees.filter((employee) => {
|
||||
if (isConcept) {
|
||||
return employee.id; // Only require ID for concepts/drafts
|
||||
}
|
||||
return employee.id && employee.duration; // Require both for published tasks
|
||||
});
|
||||
},
|
||||
|
||||
async _validateEmployees() {
|
||||
if (this.subtask.id && !this.subtask.is_draft) {
|
||||
// For existing subtasks, at least one employee is required
|
||||
|
||||
Reference in new issue
Block a user