feat(employee-list): add check for overlap when creating or editing schedule presets
module complete for staging
This commit is contained in:
parent
6606ebb992
commit
c5cf6becda
|
|
@ -28,7 +28,6 @@
|
||||||
|
|
||||||
const onClickSchedulePresetManager = (mode: PresetManagerMode, preset_id?: number) => {
|
const onClickSchedulePresetManager = (mode: PresetManagerMode, preset_id?: number) => {
|
||||||
schedule_preset_store.schedule_preset_dialog_mode = mode;
|
schedule_preset_store.schedule_preset_dialog_mode = mode;
|
||||||
console.log('preset id: ', preset_id);
|
|
||||||
schedule_preset_store.openSchedulePresetManager(preset_id ?? current_preset.value.value);
|
schedule_preset_store.openSchedulePresetManager(preset_id ?? current_preset.value.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,27 +82,28 @@
|
||||||
</q-select>
|
</q-select>
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
push
|
|
||||||
dense
|
|
||||||
rounded
|
|
||||||
icon="add"
|
icon="add"
|
||||||
color="accent"
|
color="accent"
|
||||||
class="col-auto q-px-sm q-ml-sm"
|
class="col-auto q-px-sm q-ml-sm rounded-50"
|
||||||
@click="onClickSchedulePresetManager('create', -1)"
|
@click="onClickSchedulePresetManager('create', -1)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<HorizontalSlideTransition :show="current_preset !== undefined && current_preset?.value !== -1">
|
<HorizontalSlideTransition :show="current_preset !== undefined && current_preset?.value !== -1">
|
||||||
<div class="col-auto row no-wrap full-height">
|
<div class="col-auto row no-wrap full-height">
|
||||||
<q-btn
|
<q-btn
|
||||||
push
|
|
||||||
dense
|
|
||||||
rounded
|
|
||||||
icon="edit"
|
icon="edit"
|
||||||
color="accent"
|
color="accent"
|
||||||
class="col-auto q-px-sm q-mx-sm full-height"
|
class="col-auto q-px-sm q-ml-sm rounded-50"
|
||||||
@click="onClickSchedulePresetManager('update')"
|
@click="onClickSchedulePresetManager('update')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
icon="content_copy"
|
||||||
|
color="accent"
|
||||||
|
class="col-auto q-px-sm q-mx-sm rounded-50"
|
||||||
|
@click="onClickSchedulePresetManager('copy')"
|
||||||
|
/>
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
flat
|
flat
|
||||||
dense
|
dense
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
<q-dialog
|
<q-dialog
|
||||||
v-model="employee_store.is_add_modify_dialog_open"
|
v-model="employee_store.is_add_modify_dialog_open"
|
||||||
full-width
|
full-width
|
||||||
|
full-height
|
||||||
@beforeShow="current_step = 'form'"
|
@beforeShow="current_step = 'form'"
|
||||||
@show="Object.assign(initial_employee_profile, employee_store.employee)"
|
@show="Object.assign(initial_employee_profile, employee_store.employee)"
|
||||||
class="shadow-24"
|
class="shadow-24"
|
||||||
|
|
@ -26,7 +27,7 @@
|
||||||
<div
|
<div
|
||||||
class="column bg-secondary rounded-10 no-wrap"
|
class="column bg-secondary rounded-10 no-wrap"
|
||||||
:class="$q.dark.isActive ? 'shadow-24' : 'shadow-10'"
|
:class="$q.dark.isActive ? 'shadow-24' : 'shadow-10'"
|
||||||
:style="($q.screen.lt.md ? ' ' : 'max-width: 60vw !important; height: 60vh') +
|
:style="($q.screen.lt.md ? ' ' : 'max-width: 60vw !important; max-height: 80vh !important;') +
|
||||||
($q.dark.isActive ? 'border: 2px solid var(--q-accent)' : '')"
|
($q.dark.isActive ? 'border: 2px solid var(--q-accent)' : '')"
|
||||||
>
|
>
|
||||||
<div class="row col-auto text-white bg-primary flex-center shadow-5">
|
<div class="row col-auto text-white bg-primary flex-center shadow-5">
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
import { useEmployeeStore } from 'src/stores/employee-store';
|
import { useEmployeeStore } from 'src/stores/employee-store';
|
||||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||||
import { employee_list_columns, type EmployeeProfile, type EmployeeListFilters } from 'src/modules/employee-list/models/employee-profile.models';
|
import { employee_list_columns, type EmployeeProfile, type EmployeeListFilters } from 'src/modules/employee-list/models/employee-profile.models';
|
||||||
import { animateFlip } from 'src/utils/table-grid-FLIP';
|
|
||||||
|
|
||||||
const employee_store = useEmployeeStore();
|
const employee_store = useEmployeeStore();
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheet_store = useTimesheetStore();
|
||||||
|
|
@ -50,8 +49,6 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
animateFlip(table_grid_container);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -114,9 +111,10 @@
|
||||||
{ icon: 'view_list', value: false },
|
{ icon: 'view_list', value: false },
|
||||||
]"
|
]"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-input
|
<q-input
|
||||||
v-model="filters.search_bar_string"
|
v-model="filters.search_bar_string"
|
||||||
outlined
|
standout
|
||||||
dense
|
dense
|
||||||
rounded
|
rounded
|
||||||
color="accent"
|
color="accent"
|
||||||
|
|
@ -133,6 +131,7 @@
|
||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<q-space />
|
<q-space />
|
||||||
<q-checkbox
|
<q-checkbox
|
||||||
|
|
@ -191,7 +190,7 @@
|
||||||
:key="scope.rowIndex + (timesheet_store.pay_period?.pay_period_no ?? 0)"
|
:key="scope.rowIndex + (timesheet_store.pay_period?.pay_period_no ?? 0)"
|
||||||
class="rounded-5 cursor-pointer"
|
class="rounded-5 cursor-pointer"
|
||||||
style="font-size: 1.2em;"
|
style="font-size: 1.2em;"
|
||||||
:style="`animation-delay: ${scope.pageIndex + scope.rowIndex * 5}ms; ` + (scope.row.last_work_day === null ? '' : 'opacity: 0.5;')"
|
:style="scope.row.last_work_day === null ? '' : 'opacity: 0.5;'"
|
||||||
>
|
>
|
||||||
<div v-if="scope.col.name === 'first_name'">
|
<div v-if="scope.col.name === 'first_name'">
|
||||||
<span
|
<span
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,14 @@
|
||||||
|
|
||||||
const shift = defineModel<SchedulePresetShift>('shift', { required: true });
|
const shift = defineModel<SchedulePresetShift>('shift', { required: true });
|
||||||
const shift_type_selected = ref(SHIFT_OPTIONS[0]);
|
const shift_type_selected = ref(SHIFT_OPTIONS[0]);
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
error: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
'click-delete': [void];
|
'clickDelete': [void];
|
||||||
|
'blurTimeField': [void];
|
||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -72,6 +77,8 @@
|
||||||
hide-bottom-space
|
hide-bottom-space
|
||||||
type="time"
|
type="time"
|
||||||
class="text-uppercase weekday-field"
|
class="text-uppercase weekday-field"
|
||||||
|
:error="error"
|
||||||
|
@blur="$emit('blurTimeField')"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<div
|
<div
|
||||||
|
|
@ -92,6 +99,8 @@
|
||||||
hide-bottom-space
|
hide-bottom-space
|
||||||
type="time"
|
type="time"
|
||||||
class="text-uppercase weekday-field"
|
class="text-uppercase weekday-field"
|
||||||
|
:error="error"
|
||||||
|
@blur="$emit('blurTimeField')"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<div
|
<div
|
||||||
|
|
@ -112,7 +121,7 @@
|
||||||
icon="clear"
|
icon="clear"
|
||||||
size="sm"
|
size="sm"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
@click="$emit('click-delete')"
|
@click="$emit('clickDelete')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -128,6 +137,11 @@
|
||||||
min-height: 25px;
|
min-height: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.weekday-field :deep(.q-field__marginal) {
|
||||||
|
height: 25px;
|
||||||
|
min-height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.q-field--auto-height.q-field--dense .q-field__native) {
|
:deep(.q-field--auto-height.q-field--dense .q-field__native) {
|
||||||
min-height: 25px;
|
min-height: 25px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
import { useEmployeeListApi } from '../composables/use-employee-api';
|
import { useEmployeeListApi } from '../composables/use-employee-api';
|
||||||
import { SchedulePresetShift } from '../models/schedule-presets.models';
|
import { SchedulePresetShift } from '../models/schedule-presets.models';
|
||||||
import { useSchedulePresetsStore } from 'src/stores/schedule-presets.store';
|
import { useSchedulePresetsStore } from 'src/stores/schedule-presets.store';
|
||||||
|
import { isShiftOverlap } from 'src/modules/timesheets/utils/shift.util';
|
||||||
|
|
||||||
const schedule_preset_store = useSchedulePresetsStore();
|
const schedule_preset_store = useSchedulePresetsStore();
|
||||||
const employee_list_api = useEmployeeListApi();
|
const employee_list_api = useEmployeeListApi();
|
||||||
|
|
@ -18,14 +19,14 @@
|
||||||
v-model="schedule_preset_store.is_manager_open"
|
v-model="schedule_preset_store.is_manager_open"
|
||||||
full-width
|
full-width
|
||||||
>
|
>
|
||||||
<SchedulePresetsDialogDelete
|
<SchedulePresetsDialogDelete
|
||||||
v-if="schedule_preset_store.schedule_preset_dialog_mode === 'delete'"
|
v-if="schedule_preset_store.schedule_preset_dialog_mode === 'delete'"
|
||||||
:preset-id="schedule_preset_store.current_schedule_preset.id"
|
:preset-id="schedule_preset_store.current_schedule_preset.id"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
class="column flex-center bg-secondary rounded-10 shadow-24"
|
class="column flex-center bg-secondary rounded-10 shadow-24 no-wrap"
|
||||||
style="border: 2px solid var(--q-accent); width: 50vw !important;"
|
style="border: 2px solid var(--q-accent); width: 50vw !important;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
@ -61,7 +62,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="column col full-width q-py-sm q-px-lg">
|
<div
|
||||||
|
v-if="schedule_preset_store.schedule_preset_dialog_mode !== 'copy'"
|
||||||
|
class="column col full-width q-py-sm q-px-lg no-wrap scroll"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="weekday of schedule_preset_store.current_schedule_preset.weekdays"
|
v-for="weekday of schedule_preset_store.current_schedule_preset.weekdays"
|
||||||
:key="weekday.day"
|
:key="weekday.day"
|
||||||
|
|
@ -79,7 +83,9 @@
|
||||||
>
|
>
|
||||||
<SchedulePresetsDialogRow
|
<SchedulePresetsDialogRow
|
||||||
v-model:shift="weekday.shifts[index]!"
|
v-model:shift="weekday.shifts[index]!"
|
||||||
|
:error="weekday.is_error"
|
||||||
@click-delete="weekday.shifts.splice(index, 1)"
|
@click-delete="weekday.shifts.splice(index, 1)"
|
||||||
|
@blur-time-field="weekday.is_error = isShiftOverlap(weekday.shifts)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -97,7 +103,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-auto row self-end q-px-lg full-width">
|
<div class="col-auto row self-end q-px-lg q-mt-sm full-width">
|
||||||
<q-space />
|
<q-space />
|
||||||
<q-btn
|
<q-btn
|
||||||
:disable="schedule_preset_store.current_schedule_preset.name === ''"
|
:disable="schedule_preset_store.current_schedule_preset.name === ''"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { useEmployeeStore } from "src/stores/employee-store";
|
import { useEmployeeStore } from "src/stores/employee-store";
|
||||||
import { useSchedulePresetsStore } from "src/stores/schedule-presets.store";
|
import { useSchedulePresetsStore } from "src/stores/schedule-presets.store";
|
||||||
import { SchedulePreset } from "../models/schedule-presets.models";
|
import { SchedulePreset } from "../models/schedule-presets.models";
|
||||||
|
import { isShiftOverlap } from "src/modules/timesheets/utils/shift.util";
|
||||||
|
|
||||||
export const useEmployeeListApi = () => {
|
export const useEmployeeListApi = () => {
|
||||||
const employee_store = useEmployeeStore();
|
const employee_store = useEmployeeStore();
|
||||||
|
|
@ -15,34 +16,63 @@ export const useEmployeeListApi = () => {
|
||||||
employee_store.is_loading = false;
|
employee_store.is_loading = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getEmployeeDetails = async(email: string): Promise<void> => {
|
const getEmployeeDetails = async (email: string): Promise<void> => {
|
||||||
const success = await employee_store.getEmployeeDetails(email);
|
const success = await employee_store.getEmployeeDetails(email);
|
||||||
if (success && employee_store.employee.preset_id !== null) {
|
if (success && employee_store.employee.preset_id !== null) {
|
||||||
schedule_preset_store.setCurrentSchedulePreset(employee_store.employee.preset_id ?? -1);
|
schedule_preset_store.setCurrentSchedulePreset(employee_store.employee.preset_id ?? -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const setSchedulePreset = (preset_id: number) => {
|
const setSchedulePreset = (preset_id: number) => {
|
||||||
schedule_preset_store.setCurrentSchedulePreset(preset_id);
|
schedule_preset_store.setCurrentSchedulePreset(preset_id);
|
||||||
employee_store.employee.preset_id = preset_id < 0 ? null : preset_id;
|
employee_store.employee.preset_id = preset_id < 0 ? null : preset_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveSchedulePreset = async() => {
|
const saveSchedulePreset = async () => {
|
||||||
|
// Get the currently edited schedule preset from the store (frontend model)
|
||||||
const preset = schedule_preset_store.current_schedule_preset;
|
const preset = schedule_preset_store.current_schedule_preset;
|
||||||
|
|
||||||
|
// Check if there's any overlap between shifts. If there is, is_error property
|
||||||
|
// will be toggled to true and save process will stop
|
||||||
|
for (const weekday of preset.weekdays) {
|
||||||
|
weekday.is_error = isShiftOverlap(weekday.shifts);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('current preset: ', preset);
|
||||||
|
|
||||||
|
if (preset.weekdays.some(weekday => weekday.is_error)) {
|
||||||
|
console.log('overlap!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flatten all weekday shifts into a single array
|
||||||
const preset_shifts = preset.weekdays.flatMap(weekday => weekday.shifts);
|
const preset_shifts = preset.weekdays.flatMap(weekday => weekday.shifts);
|
||||||
const backend_preset = new SchedulePreset(preset.id, preset.name, preset.is_default, preset_shifts);
|
|
||||||
|
// Build a backend-compatible SchedulePreset instance
|
||||||
|
const backend_preset = new SchedulePreset(
|
||||||
|
preset.id,
|
||||||
|
preset.name,
|
||||||
|
preset.is_default,
|
||||||
|
preset_shifts
|
||||||
|
);
|
||||||
|
|
||||||
|
// Track whether the create/update operation succeeds
|
||||||
let success = false;
|
let success = false;
|
||||||
|
|
||||||
if (preset.id === -1) success = await schedule_preset_store.createSchedulePreset(backend_preset);
|
// Create a new preset if it has no backend ID, otherwise update the existing one
|
||||||
else success = await schedule_preset_store.updateSchedulePreset(backend_preset);
|
if (preset.id === -1)
|
||||||
|
success = await schedule_preset_store.createSchedulePreset(backend_preset);
|
||||||
|
else
|
||||||
|
success = await schedule_preset_store.updateSchedulePreset(backend_preset);
|
||||||
|
|
||||||
|
// On success, refresh the preset list and close the preset manager UI
|
||||||
if (success) {
|
if (success) {
|
||||||
await schedule_preset_store.findSchedulePresetList();
|
await schedule_preset_store.findSchedulePresetList();
|
||||||
schedule_preset_store.is_manager_open = false;
|
schedule_preset_store.is_manager_open = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteSchedulePreset = async(preset_id: number) => {
|
const deleteSchedulePreset = async (preset_id: number) => {
|
||||||
const success = await schedule_preset_store.deleteSchedulePreset(preset_id);
|
const success = await schedule_preset_store.deleteSchedulePreset(preset_id);
|
||||||
if (success) {
|
if (success) {
|
||||||
await schedule_preset_store.findSchedulePresetList();
|
await schedule_preset_store.findSchedulePresetList();
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ export class SchedulePresetFrontend {
|
||||||
this.is_default = schedule_preset?.is_default ?? false;
|
this.is_default = schedule_preset?.is_default ?? false;
|
||||||
this.weekdays = WEEKDAYS.map(day => ({
|
this.weekdays = WEEKDAYS.map(day => ({
|
||||||
day,
|
day,
|
||||||
|
is_error: false,
|
||||||
shifts: schedule_preset !== undefined ? schedule_preset?.shifts.filter(shift => shift.week_day === day) : [],
|
shifts: schedule_preset !== undefined ? schedule_preset?.shifts.filter(shift => shift.week_day === day) : [],
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
@ -57,5 +58,6 @@ export class SchedulePresetFrontend {
|
||||||
|
|
||||||
export interface WeekdayPresetShifts {
|
export interface WeekdayPresetShifts {
|
||||||
day: Weekday;
|
day: Weekday;
|
||||||
|
is_error: boolean;
|
||||||
shifts: SchedulePresetShift[];
|
shifts: SchedulePresetShift[];
|
||||||
}
|
}
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
import { date, patterns, type ValidationRule } from "quasar";
|
import { date, patterns, type ValidationRule } from "quasar";
|
||||||
|
import type { SchedulePresetShift } from "src/modules/employee-list/models/schedule-presets.models";
|
||||||
import type { Shift } from "src/modules/timesheets/models/shift.models";
|
import type { Shift } from "src/modules/timesheets/models/shift.models";
|
||||||
|
|
||||||
export const isShiftOverlap = (shifts: Shift[]): boolean => {
|
export const isShiftOverlap = (shifts: Shift[] | SchedulePresetShift[]): boolean => {
|
||||||
if (shifts.length < 2) return false;
|
if (shifts.length < 2) return false;
|
||||||
|
|
||||||
const parsed_shifts = shifts.map(shift => ({
|
const parsed_shifts = shifts.map(shift => ({
|
||||||
start: date.extractDate(`${shift.date} ${shift.start_time}`, 'YYYY-MM-DD HH:mm').getTime(),
|
start: date.extractDate(`2000-01-01 ${shift.start_time}`, 'YYYY-MM-DD HH:mm').getTime(),
|
||||||
end: date.extractDate(`${shift.date} ${shift.end_time}`, 'YYYY-MM-DD HH:mm').getTime(),
|
end: date.extractDate(`2000-01-01 ${shift.end_time}`, 'YYYY-MM-DD HH:mm').getTime(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
console.log('parsed_shifts: ', parsed_shifts);
|
||||||
|
|
||||||
for (let i = 0; i < parsed_shifts.length; i++) {
|
for (let i = 0; i < parsed_shifts.length; i++) {
|
||||||
for (let j = i + 1; j < parsed_shifts.length; j++) {
|
for (let j = i + 1; j < parsed_shifts.length; j++) {
|
||||||
|
|
@ -15,6 +18,8 @@ export const isShiftOverlap = (shifts: Shift[]): boolean => {
|
||||||
const parsed_shift_b = parsed_shifts[j];
|
const parsed_shift_b = parsed_shifts[j];
|
||||||
|
|
||||||
if (parsed_shift_a === undefined || parsed_shift_b === undefined) continue;
|
if (parsed_shift_a === undefined || parsed_shift_b === undefined) continue;
|
||||||
|
console.log('times(a start, b start, a end, b end): ', parsed_shift_a.start, parsed_shift_b.start, parsed_shift_a.end, parsed_shift_b.end);
|
||||||
|
console.log('result: ', Math.max(parsed_shift_a.start, parsed_shift_b.start) < Math.min(parsed_shift_a.end, parsed_shift_b.end))
|
||||||
|
|
||||||
if (Math.max(parsed_shift_a.start, parsed_shift_b.start) < Math.min(parsed_shift_a.end, parsed_shift_b.end)) {
|
if (Math.max(parsed_shift_a.start, parsed_shift_b.start) < Math.min(parsed_shift_a.end, parsed_shift_b.end)) {
|
||||||
return true; // overlap found
|
return true; // overlap found
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
/* eslint-disable */
|
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { SchedulePresetsService } from "src/modules/employee-list/services/schedule-presets-service";
|
import { SchedulePresetsService } from "src/modules/employee-list/services/schedule-presets-service";
|
||||||
|
|
@ -12,11 +11,17 @@ export const useSchedulePresetsStore = defineStore('schedule_presets_store', ()
|
||||||
const is_manager_open = ref(false);
|
const is_manager_open = ref(false);
|
||||||
|
|
||||||
const openSchedulePresetManager = (preset_id: number) => {
|
const openSchedulePresetManager = (preset_id: number) => {
|
||||||
if (preset_id === -1) {
|
if (preset_id === -1)
|
||||||
current_schedule_preset.value = new SchedulePresetFrontend;
|
current_schedule_preset.value = new SchedulePresetFrontend;
|
||||||
} else {
|
else if (schedule_preset_dialog_mode.value === 'copy') {
|
||||||
setCurrentSchedulePreset(preset_id);
|
const preset = schedule_presets.value.find(preset => preset.id === preset_id)!;
|
||||||
|
const copied_preset = new SchedulePresetFrontend(preset);
|
||||||
|
copied_preset.id = -1;
|
||||||
|
copied_preset.name = "";
|
||||||
|
current_schedule_preset.value = copied_preset;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
setCurrentSchedulePreset(preset_id);
|
||||||
|
|
||||||
is_manager_open.value = true;
|
is_manager_open.value = true;
|
||||||
};
|
};
|
||||||
|
|
@ -26,7 +31,7 @@ export const useSchedulePresetsStore = defineStore('schedule_presets_store', ()
|
||||||
current_schedule_preset.value = new SchedulePresetFrontend;
|
current_schedule_preset.value = new SchedulePresetFrontend;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
current_schedule_preset.value = new SchedulePresetFrontend(schedule_presets.value.find(preset => preset.id === preset_id)!)
|
current_schedule_preset.value = new SchedulePresetFrontend(schedule_presets.value.find(preset => preset.id === preset_id))
|
||||||
};
|
};
|
||||||
|
|
||||||
const createSchedulePreset = async (preset: SchedulePreset): Promise<boolean> => {
|
const createSchedulePreset = async (preset: SchedulePreset): Promise<boolean> => {
|
||||||
|
|
@ -73,15 +78,6 @@ export const useSchedulePresetsStore = defineStore('schedule_presets_store', ()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const applySchedulePreset = async (): Promise<boolean> => {
|
|
||||||
try {
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('DEV ERROR || error while building schedule: ', error);
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
schedule_presets,
|
schedule_presets,
|
||||||
current_schedule_preset,
|
current_schedule_preset,
|
||||||
|
|
@ -93,6 +89,5 @@ export const useSchedulePresetsStore = defineStore('schedule_presets_store', ()
|
||||||
updateSchedulePreset,
|
updateSchedulePreset,
|
||||||
deleteSchedulePreset,
|
deleteSchedulePreset,
|
||||||
findSchedulePresetList,
|
findSchedulePresetList,
|
||||||
applySchedulePreset,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
import { type Ref, nextTick } from 'vue';
|
|
||||||
|
|
||||||
export const animateFlip = (container: Ref<HTMLElement | null>) => {
|
|
||||||
const el = container.value;
|
|
||||||
if (!el) return;
|
|
||||||
|
|
||||||
const children = Array.from(el.children) as HTMLElement[];
|
|
||||||
|
|
||||||
// FIRST: record initial positions
|
|
||||||
const firstRects = children.map(c => c.getBoundingClientRect());
|
|
||||||
|
|
||||||
// Do LAST → INVERT → PLAY after DOM update
|
|
||||||
void nextTick(() => {
|
|
||||||
const lastRects = children.map(c => c.getBoundingClientRect());
|
|
||||||
|
|
||||||
children.forEach((child, i) => {
|
|
||||||
const dx = firstRects[i]!.left - lastRects[i]!.left;
|
|
||||||
const dy = firstRects[i]!.top - lastRects[i]!.top;
|
|
||||||
|
|
||||||
if (!dx && !dy) return;
|
|
||||||
|
|
||||||
child.style.transition = 'none';
|
|
||||||
child.style.transform = `translate(${dx}px, ${dy}px)`;
|
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
child.style.transition = 'transform 250ms ease';
|
|
||||||
child.style.transform = '';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user