mirror of
https://bitbucket.org/studiotem/jandl-taskmanager-app.git
synced 2026-10-21 14:29:34 +00:00
refactor(timeline): updated modal for adding timeblock to correctly display other (draft) timeblocks when editing subtask draft
This commit is contained in:
1 parent
9f2db65481
commit
c5672c94f2
5 files changed
+110
-50
No files matched your search
@@ -25,7 +25,7 @@ export function useEmployeeTimeline(
|
|||||||
currentTimeblock: Ref<Timeblock | null>,
|
currentTimeblock: Ref<Timeblock | null>,
|
||||||
otherLocalTimeblocks?: Ref<Timeblock[]>,
|
otherLocalTimeblocks?: Ref<Timeblock[]>,
|
||||||
editingBlockerId?: Ref<number | null>,
|
editingBlockerId?: Ref<number | null>,
|
||||||
showDraftTasks?: Ref<boolean>,
|
draftTimeblocks?: Ref<Timeblock[]>,
|
||||||
) {
|
) {
|
||||||
// Fetch employee's tasks for the selected date
|
// Fetch employee's tasks for the selected date
|
||||||
const {
|
const {
|
||||||
@@ -64,61 +64,60 @@ export function useEmployeeTimeline(
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
// const {
|
||||||
data: conceptTasksData,
|
// data: conceptTasksData,
|
||||||
isLoading: conceptTasksLoading,
|
// isLoading: conceptTasksLoading,
|
||||||
error: conceptTasksError,
|
// error: conceptTasksError,
|
||||||
refetch: conceptTasksRefetch,
|
// refetch: conceptTasksRefetch,
|
||||||
} = useQuery({
|
// } = useQuery({
|
||||||
queryKey: computed(() => [
|
// queryKey: computed(() => [
|
||||||
'concept-employee-timeline',
|
// 'concept-employee-timeline',
|
||||||
unref(employee)?.id,
|
// unref(employee)?.id,
|
||||||
unref(date) ? moment(unref(date)).format('YYYY-MM-DD') : null,
|
// unref(date) ? moment(unref(date)).format('YYYY-MM-DD') : null,
|
||||||
]),
|
// ]),
|
||||||
queryFn: async () => {
|
// queryFn: async () => {
|
||||||
const emp = unref(employee);
|
// const emp = unref(employee);
|
||||||
const d = unref(date);
|
// const d = unref(date);
|
||||||
|
|
||||||
if (!emp?.id || !d) {
|
// if (!emp?.id || !d) {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const dateStr = moment(d).format('YYYY-MM-DD');
|
// const dateStr = moment(d).format('YYYY-MM-DD');
|
||||||
const queryParams = new URLSearchParams({
|
// const queryParams = new URLSearchParams({
|
||||||
start: dateStr,
|
// start: dateStr,
|
||||||
end: dateStr,
|
// end: dateStr,
|
||||||
employee_id: emp.id.toString(),
|
// employee_id: emp.id.toString(),
|
||||||
type: 'draft',
|
// type: 'draft',
|
||||||
}).toString();
|
// }).toString();
|
||||||
|
|
||||||
const response = await axios.get_auth(`v1/subtasks?${queryParams}`);
|
// const response = await axios.get_auth(`v1/subtasks?${queryParams}`);
|
||||||
return response;
|
// return response;
|
||||||
},
|
// },
|
||||||
enabled: computed(() => {
|
// enabled: computed(() => {
|
||||||
const emp = unref(employee);
|
// const emp = unref(employee);
|
||||||
const d = unref(date);
|
// const d = unref(date);
|
||||||
return !!(emp?.id && d);
|
// return !!(emp?.id && d);
|
||||||
}),
|
// }),
|
||||||
});
|
// });
|
||||||
|
|
||||||
// Generate timeline tasks from fetched data
|
// Generate timeline tasks from fetched data
|
||||||
const timelineTasks = computed(() => {
|
const timelineTasks = computed(() => {
|
||||||
const data = unref(tasksData);
|
const data = unref(tasksData);
|
||||||
const conceptData = unref(conceptTasksData);
|
// const conceptData = unref(conceptTasksData);
|
||||||
const emp = unref(employee);
|
const emp = unref(employee);
|
||||||
const d = unref(date);
|
const d = unref(date);
|
||||||
const excludeBlockerId = editingBlockerId ? unref(editingBlockerId) : null;
|
const excludeBlockerId = editingBlockerId ? unref(editingBlockerId) : null;
|
||||||
const includeDrafts = showDraftTasks ? unref(showDraftTasks) : false;
|
const draftTbs = draftTimeblocks ? unref(draftTimeblocks) : [];
|
||||||
|
|
||||||
if (!data || !conceptData || !emp || !d) {
|
if (!data || !emp || !d) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const subtasks = [
|
const subtasks = [
|
||||||
...(data.subtasks || []),
|
...(data.subtasks || []),
|
||||||
...(data.blockers || []),
|
...(data.blockers || []),
|
||||||
// Only include concept tasks if showDraftTasks is true
|
// ...(conceptData.subtasks || []),
|
||||||
...(includeDrafts ? (conceptData.subtasks || []) : []),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const selectedDateStr = moment(d).format('YYYY-MM-DD');
|
const selectedDateStr = moment(d).format('YYYY-MM-DD');
|
||||||
@@ -221,6 +220,39 @@ export function useEmployeeTimeline(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Process draft timeblocks from other employees in the same draft subtask
|
||||||
|
draftTbs.forEach((timeblock: any) => {
|
||||||
|
// Skip if timeblock doesn't have required fields
|
||||||
|
if (!timeblock.start || !timeblock.end) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeblockDateStr = moment(timeblock.start).format('YYYY-MM-DD');
|
||||||
|
|
||||||
|
// Only include timeblocks for the selected date
|
||||||
|
if (timeblockDateStr === selectedDateStr) {
|
||||||
|
const task = {
|
||||||
|
id: null, // Draft timeblock doesn't have a subtask ID
|
||||||
|
start: new Date(timeblock.start),
|
||||||
|
end: new Date(timeblock.end),
|
||||||
|
master_task: null,
|
||||||
|
date: new Date(timeblock.start),
|
||||||
|
project_code: null,
|
||||||
|
subtask: null,
|
||||||
|
is_draft: true,
|
||||||
|
blocker: undefined,
|
||||||
|
type: 'draft_timeblock',
|
||||||
|
_timeblock_id: timeblock.id || null,
|
||||||
|
_timeblock_is_finished: timeblock.is_finished || false,
|
||||||
|
_real_start: new Date(timeblock.start),
|
||||||
|
_real_end: new Date(timeblock.end),
|
||||||
|
_employee_id: timeblock.employee_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
tasks.push(task);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return tasks;
|
return tasks;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error generating timeline tasks:', error);
|
console.error('Error generating timeline tasks:', error);
|
||||||
@@ -328,9 +360,9 @@ export function useEmployeeTimeline(
|
|||||||
error,
|
error,
|
||||||
refetch,
|
refetch,
|
||||||
|
|
||||||
conceptTasksLoading,
|
// conceptTasksLoading,
|
||||||
conceptTasksError,
|
// conceptTasksError,
|
||||||
conceptTasksRefetch,
|
// conceptTasksRefetch,
|
||||||
|
|
||||||
// Timeline data
|
// Timeline data
|
||||||
timelineTasks,
|
timelineTasks,
|
||||||
|
|||||||
@@ -117,7 +117,7 @@
|
|||||||
:employee="employee"
|
:employee="employee"
|
||||||
:deletable="false"
|
:deletable="false"
|
||||||
:index="0"
|
:index="0"
|
||||||
:show-draft-tasks="!!subtask.is_draft"
|
:draft-timeblocks="draftTimeblocks"
|
||||||
/>
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
@@ -215,6 +215,11 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isDraft: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
emits: ['update-subtask'],
|
emits: ['update-subtask'],
|
||||||
|
|
||||||
@@ -261,6 +266,26 @@ export default {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Get draft timeblocks for the current employee in backend format for timeline
|
||||||
|
draftTimeblocks() {
|
||||||
|
if (!this.isDraft) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert timeblocks from internal format to backend format for timeline
|
||||||
|
return this.timeblocks
|
||||||
|
.filter((tb) => tb.date && tb.starts_at_time && tb.ends_at_time)
|
||||||
|
.map((tb) => {
|
||||||
|
const dateStr = moment(tb.date).format('YYYY-MM-DD');
|
||||||
|
return {
|
||||||
|
...tb,
|
||||||
|
start: `${dateStr} ${tb.starts_at_time}:00`,
|
||||||
|
end: `${dateStr} ${tb.ends_at_time}:00`,
|
||||||
|
employee_id: this.subtask.employee_id,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// Hour width based on screen size
|
// Hour width based on screen size
|
||||||
hourWidth() {
|
hourWidth() {
|
||||||
return window.innerWidth <= 768
|
return window.innerWidth <= 768
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ interface Props {
|
|||||||
currentIndex?: number;
|
currentIndex?: number;
|
||||||
deletable?: boolean;
|
deletable?: boolean;
|
||||||
index?: number;
|
index?: number;
|
||||||
showDraftTasks?: boolean; // Whether to show draft/concept tasks on timeline
|
draftTimeblocks?: TimeblockData[]; // Draft timeblocks from all employees in draft subtask
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
@@ -88,7 +88,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
currentIndex: 0,
|
currentIndex: 0,
|
||||||
deletable: false,
|
deletable: false,
|
||||||
index: 0,
|
index: 0,
|
||||||
showDraftTasks: false,
|
draftTimeblocks: () => [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@@ -240,7 +240,7 @@ const otherTimeblocksForSameDate = computed(() => {
|
|||||||
|
|
||||||
// Use timeline composable
|
// Use timeline composable
|
||||||
const editingBlockerIdRef = computed(() => props.editingBlockerId);
|
const editingBlockerIdRef = computed(() => props.editingBlockerId);
|
||||||
const showDraftTasksRef = computed(() => props.showDraftTasks);
|
const draftTimeblocksRef = computed(() => props.draftTimeblocks);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isLoading,
|
isLoading,
|
||||||
@@ -249,14 +249,13 @@ const {
|
|||||||
freeTime: _freeTime,
|
freeTime: _freeTime,
|
||||||
timeblockDuration,
|
timeblockDuration,
|
||||||
refetch,
|
refetch,
|
||||||
conceptTasksRefetch,
|
|
||||||
} = useEmployeeTimeline(
|
} = useEmployeeTimeline(
|
||||||
employeeRef,
|
employeeRef,
|
||||||
dateRef,
|
dateRef,
|
||||||
timeblockRef,
|
timeblockRef,
|
||||||
otherTimeblocksForSameDate,
|
otherTimeblocksForSameDate,
|
||||||
editingBlockerIdRef,
|
editingBlockerIdRef,
|
||||||
showDraftTasksRef,
|
draftTimeblocksRef,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Force refetch when date changes
|
// Force refetch when date changes
|
||||||
@@ -265,14 +264,14 @@ watch(
|
|||||||
() => {
|
() => {
|
||||||
if (props.modelValue.date && props.employee?.id) {
|
if (props.modelValue.date && props.employee?.id) {
|
||||||
refetch();
|
refetch();
|
||||||
conceptTasksRefetch();
|
// conceptTasksRefetch();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
refetch();
|
refetch();
|
||||||
conceptTasksRefetch();
|
// conceptTasksRefetch();
|
||||||
});
|
});
|
||||||
|
|
||||||
// All tasks from timelineTasks are already filtered for the selected date
|
// All tasks from timelineTasks are already filtered for the selected date
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
:all-employee-timeblocks="timeblocks"
|
:all-employee-timeblocks="timeblocks"
|
||||||
:all-timeblocks="allTimeblocksForCurrentEmployee"
|
:all-timeblocks="allTimeblocksForCurrentEmployee"
|
||||||
:deleted-timeblock-ids="deletedTimeblockIds"
|
:deleted-timeblock-ids="deletedTimeblockIds"
|
||||||
|
:draft-timeblocks="draftTimeblocks"
|
||||||
:current-index="index"
|
:current-index="index"
|
||||||
:deletable="timeblocks.length > 1"
|
:deletable="timeblocks.length > 1"
|
||||||
:index="index"
|
:index="index"
|
||||||
@@ -46,6 +47,7 @@ interface Props {
|
|||||||
timeblocks?: TimeblockData[];
|
timeblocks?: TimeblockData[];
|
||||||
allTimeblocks?: TimeblockData[]; // All timeblocks from all employees
|
allTimeblocks?: TimeblockData[]; // All timeblocks from all employees
|
||||||
deletedTimeblockIds?: number[]; // IDs of saved timeblocks that have been deleted
|
deletedTimeblockIds?: number[]; // IDs of saved timeblocks that have been deleted
|
||||||
|
draftTimeblocks?: TimeblockData[]; // Draft timeblocks from all employees in draft subtask
|
||||||
customFilter?: CustomFilterFunction;
|
customFilter?: CustomFilterFunction;
|
||||||
hasBackground?: boolean;
|
hasBackground?: boolean;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
@@ -55,6 +57,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
timeblocks: () => [],
|
timeblocks: () => [],
|
||||||
allTimeblocks: () => [],
|
allTimeblocks: () => [],
|
||||||
deletedTimeblockIds: () => [],
|
deletedTimeblockIds: () => [],
|
||||||
|
draftTimeblocks: () => [],
|
||||||
customFilter: undefined,
|
customFilter: undefined,
|
||||||
hasBackground: true,
|
hasBackground: true,
|
||||||
required: false,
|
required: false,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
<A-task-planned-time :hours="employeeData.duration" />
|
<A-task-planned-time :hours="employeeData.duration" />
|
||||||
<A-task-timeblocks
|
<A-task-timeblocks
|
||||||
:timeblocks="employeeData.timeblocks"
|
:timeblocks="employeeData.timeblocks"
|
||||||
|
:is-draft="!!subtask.is_draft"
|
||||||
:subtask="{
|
:subtask="{
|
||||||
...subtask,
|
...subtask,
|
||||||
employee_id: employeeData.id,
|
employee_id: employeeData.id,
|
||||||
|
|||||||
Reference in new issue
Block a user