feat(schedule-preset): Add update and create functionality to schedule preset with preview

This commit is contained in:
Nic D. 2025-12-10 16:59:41 -05:00
parent f6e9415369
commit fd2146567f
18 changed files with 334 additions and 75 deletions

View File

@ -29,11 +29,12 @@ export default defineConfig((ctx) => {
// 'fontawesome-v6', // 'fontawesome-v6',
// 'eva-icons', // 'eva-icons',
// 'themify', // 'themify',
// 'line-awesome', 'line-awesome',
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both! 'material-icons',
'material-icons-outlined',
'roboto-font', // optional, you are not bound to it 'roboto-font',
'material-icons', // optional, you are not bound to it // 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
], ],
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#build // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#build

View File

@ -20,7 +20,7 @@ export default {
modify_employee: "Modify employee", modify_employee: "Modify employee",
access_label: "access", access_label: "access",
details_label: "details", details_label: "details",
schedule_label: "schedules", schedule_label: "schedule",
schedule_presets: { schedule_presets: {
preset_list_placeholder: "Select a schedule", preset_list_placeholder: "Select a schedule",
preset_name_placeholder: "schedule preset name", preset_name_placeholder: "schedule preset name",

View File

@ -20,7 +20,7 @@ export default {
modify_employee: "Modifier employé", modify_employee: "Modifier employé",
access_label: "accès", access_label: "accès",
details_label: "détails", details_label: "détails",
schedule_label: "horaires", schedule_label: "horaire",
schedule_presets: { schedule_presets: {
preset_list_placeholder: "Sélectionner un horaire", preset_list_placeholder: "Sélectionner un horaire",
preset_name_placeholder: "nom de l'horaire", preset_name_placeholder: "nom de l'horaire",

View File

@ -93,7 +93,7 @@
> >
<q-item-section avatar> <q-item-section avatar>
<q-icon <q-icon
name="view_list" name="groups"
color="accent" color="accent"
size="lg" size="lg"
/> />

View File

@ -5,7 +5,7 @@
import { ref } from 'vue'; import { ref } from 'vue';
import { unwrapAndClone } from 'src/utils/unwrap-and-clone'; import { unwrapAndClone } from 'src/utils/unwrap-and-clone';
import { useEmployeeStore } from 'src/stores/employee-store'; import { useEmployeeStore } from 'src/stores/employee-store';
import { employee_access_options, type ModuleAccessPreset, type ModuleAccessName, employee_access_presets } from 'src/modules/employee-list/models/employee-profile.models'; import { employee_access_options, type ModuleAccessPreset, type ModuleAccessName, employee_access_presets, getEmployeeAccessOptionIcon } from 'src/modules/employee-list/models/employee-profile.models';
const employee_store = useEmployeeStore(); const employee_store = useEmployeeStore();
const preset_preview = ref<ModuleAccessPreset>(); const preset_preview = ref<ModuleAccessPreset>();
@ -20,6 +20,7 @@
employee_store.employee.user_module_access = unwrapAndClone(employee_access_presets[preset]); employee_store.employee.user_module_access = unwrapAndClone(employee_access_presets[preset]);
} }
const getPreviewBackgroundColor = (name: ModuleAccessName) => { const getPreviewBackgroundColor = (name: ModuleAccessName) => {
if (employee_access_presets[preset_preview.value!].includes(name)) { if (employee_access_presets[preset_preview.value!].includes(name)) {
if (!employee_store.employee.user_module_access.includes(name)) return 'bg-info text-white'; if (!employee_store.employee.user_module_access.includes(name)) return 'bg-info text-white';
@ -142,7 +143,8 @@
:class="preset_preview !== undefined ? getPreviewBackgroundColor(option.value) : getBackgroundColor(option.value)" :class="preset_preview !== undefined ? getPreviewBackgroundColor(option.value) : getBackgroundColor(option.value)"
@click="toggleInSelected(option.value)" @click="toggleInSelected(option.value)"
> >
<span class="text-uppercase text-weight-bold"> <q-icon :name="getEmployeeAccessOptionIcon(option.value)" size="sm" class="q-mr-sm"/>
<span class="text-uppercase text-weight-bold non-selectable">
{{ $t('employee_management.module_access.' + option.value) }} {{ $t('employee_management.module_access.' + option.value) }}
</span> </span>
<q-space /> <q-space />

View File

@ -0,0 +1,59 @@
<script
setup
lang="ts"
>
import { date } from 'quasar';
import { useSchedulePresetsStore } from 'src/stores/schedule-presets.store';
const schedule_preset_store = useSchedulePresetsStore();
defineProps<{
currentPresetId: number;
}>();
</script>
<template>
<div class="row flex-center fit">
<div
v-if="currentPresetId > 0"
class="col column fit flex-center q-pa-md"
>
<div
v-for="weekday in schedule_preset_store.current_schedule_preset.weekdays"
:key="weekday.day"
class="col row justify-center q-py-xs full-width"
>
<div class="col-10 row items-center bg-dark q-px-md shadow-10 rounded-10">
<span class="col-2 text-weight-bolder text-accent text-uppercase text-overline" style="font-size: 1.3em;">{{
$t(`shared.weekday.${weekday.day.toLowerCase()}`) }}</span>
<div
v-for="shift, index in weekday.shifts.sort((a, b) => date.extractDate(a.start_time, 'HH:mm').getTime() - date.extractDate(b.start_time, 'HH:mm').getTime())"
:key="index"
class="col q-px-md q-py-xs"
>
<div class="row flex-center rounded-5" style="border: 1px solid var(--q-accent);">
<div class="col bg-accent text-white text-uppercase text-weight-bolder text-center">
{{ $t(`shared.shift_type.${shift.type.toLowerCase()}`) }}
</div>
<div class="col text-center text-bold">{{ shift.start_time }}</div>
<q-icon name="las la-chevron-right" color="accent" class="col-auto"></q-icon>
<div class="col text-center text-bold">{{ shift.end_time }}</div>
</div>
</div>
</div>
</div>
</div>
<div
v-else
class="col row justify-center"
>
<q-icon
name="las la-calendar-week"
size="20em"
color="accent"
style="opacity: 0.3;"
/>
</div>
</div>
</template>

View File

@ -4,19 +4,24 @@
> >
import HorizontalSlideTransition from 'src/modules/shared/components/horizontal-slide-transition.vue'; import HorizontalSlideTransition from 'src/modules/shared/components/horizontal-slide-transition.vue';
import SchedulePresetsDialog from 'src/modules/employee-list/components/schedule_presets_dialog.vue'; import SchedulePresetsDialog from 'src/modules/employee-list/components/schedule_presets_dialog.vue';
import AddModifyDialogSchedulePreview from './add-modify-dialog-schedule-preview.vue';
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import { useSchedulePresetsStore } from 'src/stores/schedule-presets.store'; import { useSchedulePresetsStore } from 'src/stores/schedule-presets.store';
import { useEmployeeStore } from 'src/stores/employee-store'; import { useEmployeeStore } from 'src/stores/employee-store';
import { useEmployeeListApi } from '../composables/use-employee-api';
const schedule_preset_store = useSchedulePresetsStore(); const schedule_preset_store = useSchedulePresetsStore();
const employee_store = useEmployeeStore(); const employee_store = useEmployeeStore();
const employee_list_api = useEmployeeListApi();
const preset_options = ref<{ label: string, value: number }[]>([]); const preset_options = ref<{ label: string, value: number }[]>([]);
const current_preset = ref<{ label: string | undefined, value: number }>({ label: undefined, value: -1 }); const current_preset = ref<{ label: string | undefined, value: number }>({ label: undefined, value: -1 });
const getPresetOptions = (): { label: string, value: number }[] => { const getPresetOptions = (): { label: string, value: number }[] => {
return schedule_preset_store.schedule_presets.map(preset => { return { label: preset.name, value: preset.id } }); const options = schedule_preset_store.schedule_presets.map(preset => { return { label: preset.name, value: preset.id } });
options.push({ label: '', value: -1 });
return options;
}; };
onMounted(() => { onMounted(() => {
@ -35,6 +40,7 @@
v-model="current_preset" v-model="current_preset"
standout="bg-accent" standout="bg-accent"
dense dense
options-dense
rounded rounded
color="accent" color="accent"
:options="getPresetOptions()" :options="getPresetOptions()"
@ -44,11 +50,16 @@
menu-anchor="bottom middle" menu-anchor="bottom middle"
menu-self="top middle" menu-self="top middle"
:menu-offset="[0, 10]" :menu-offset="[0, 10]"
@update:modelValue="option => schedule_preset_store.setCurrentSchedulePreset(option.value)" @update:modelValue="option => employee_list_api.setSchedulePreset(option.value)"
> >
<template #selected> <template #selected>
<span class="text-uppercase" :style="current_preset.label === undefined ? 'opacity: 0.5;' : ''"> <span
{{ current_preset.label === undefined ? $t('employee_management.schedule_presets.preset_list_placeholder') : current_preset.label }} class="text-uppercase text-center text-weight-bold full-width"
:style="current_preset.label === undefined ? 'opacity: 0.5;' : ''"
>
{{ current_preset.label === undefined ?
$t('employee_management.schedule_presets.preset_list_placeholder') :
current_preset.label }}
</span> </span>
</template> </template>
</q-select> </q-select>
@ -81,6 +92,8 @@
/> />
</transition> </transition>
</HorizontalSlideTransition> </HorizontalSlideTransition>
</div> </div>
<AddModifyDialogSchedulePreview :current-preset-id="current_preset.value" />
</div> </div>
</template> </template>

View File

@ -55,14 +55,14 @@
> >
<q-tab <q-tab
name="form" name="form"
icon="badge" icon="las la-id-card"
:label="$q.screen.lt.sm ? '' : $t('employee_management.details_label')" :label="$q.screen.lt.sm ? '' : $t('employee_management.details_label')"
class="rounded-25 q-ma-xs" class="rounded-25 q-ma-xs"
style="border: 2px solid var(--q-accent);" style="border: 2px solid var(--q-accent);"
/> />
<q-tab <q-tab
name="access" name="access"
icon="key" icon="las la-key"
:label="$q.screen.lt.sm ? '' : $t('employee_management.access_label')" :label="$q.screen.lt.sm ? '' : $t('employee_management.access_label')"
class="rounded-25 q-ma-xs" class="rounded-25 q-ma-xs"
style="border: 2px solid var(--q-accent);" style="border: 2px solid var(--q-accent);"
@ -81,7 +81,7 @@
animated animated
:transition-prev="$q.screen.lt.sm ? 'jump-down' : 'jump-left'" :transition-prev="$q.screen.lt.sm ? 'jump-down' : 'jump-left'"
:transition-next="$q.screen.lt.sm ? 'jump-up' : 'jump-right'" :transition-next="$q.screen.lt.sm ? 'jump-up' : 'jump-right'"
class="bg-transparent" class="bg-transparent full-height"
> >
<q-tab-panel <q-tab-panel
name="form" name="form"

View File

@ -93,7 +93,7 @@
<q-btn <q-btn
push push
color="accent" color="accent"
icon="person_add" icon="las la-user-edit"
:label="$t('shared.label.add')" :label="$t('shared.label.add')"
class="text-uppercase" class="text-uppercase"
@click.stop="_evt => employee_store.openAddModifyDialog()" @click.stop="_evt => employee_store.openAddModifyDialog()"

View File

@ -0,0 +1,134 @@
<script
setup
lang="ts"
>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import type { ShiftOption } from 'src/modules/timesheets/models/shift.models';
import type { SchedulePresetShift } from '../models/schedule-presets.models';
const { t } = useI18n();
const SHIFT_OPTIONS: ShiftOption[] = [
{ label: t('timesheet.shift.types.REGULAR'), value: 'REGULAR', icon: 'wb_sunny', icon_color: 'blue-grey-3' },
{ label: t('timesheet.shift.types.EVENING'), value: 'EVENING', icon: 'bedtime', icon_color: 'indigo-8' },
{ label: t('timesheet.shift.types.EMERGENCY'), value: 'EMERGENCY', icon: 'ring_volume', icon_color: 'red-8' },
{ label: t('timesheet.shift.types.VACATION'), value: 'VACATION', icon: 'beach_access', icon_color: 'yellow-8' },
{ label: t('timesheet.shift.types.HOLIDAY'), value: 'HOLIDAY', icon: 'forest', icon_color: 'green-8' },
{ label: t('timesheet.shift.types.SICK'), value: 'SICK', icon: 'medication_liquid', icon_color: 'light-blue-6' },
];
const shift = defineModel<SchedulePresetShift>('shift', { required: true });
const shift_type_selected = ref(SHIFT_OPTIONS[0]);
defineEmits<{
'click-delete': [void];
}>();
</script>
<template>
<div class="row col-auto flex-center">
<div class="col q-pa-xs">
<q-select
ref="select"
v-model="shift_type_selected"
:standout="$q.dark.isActive ? 'bg-blue-grey-3' : 'bg-blue-grey-9'"
dense
options-dense
hide-dropdown-icon
:menu-offset="[0, 10]"
menu-anchor="bottom middle"
menu-self="top middle"
:options="SHIFT_OPTIONS"
class="col rounded-5 bg-dark weekday-field"
popup-content-class="text-uppercase text-weight-bold text-center rounded-5"
popup-content-style="border: 2px solid var(--q-accent)"
@update:model-value="option => shift.type = option.value"
>
<template #selected-item="scope">
<div
class="row flex-center text-uppercase q-ma-none q-pa-none no-wrap ellipsis full-width"
:tabindex="scope.tabindex"
>
<q-icon
:name="scope.opt.icon"
:color="scope.opt.icon_color"
class="col-auto q-mx-xs"
/>
<span
style="line-height: 0.9em;"
class="col-auto ellipsis"
>{{ scope.opt.label }}</span>
</div>
</template>
</q-select>
</div>
<div class="col q-px-xs">
<q-input
v-model="shift.start_time"
standout
dense
hide-bottom-space
type="time"
class="text-uppercase weekday-field"
>
<template #prepend>
<div
class="column text-uppercase text-accent text-weight-bold full-height"
style="font-size: 0.5em; transform: translateY(4px);"
>
{{ $t('shared.misc.in') }} :
</div>
</template>
</q-input>
</div>
<div class="col q-px-xs">
<q-input
v-model="shift.end_time"
standout
dense
hide-bottom-space
type="time"
class="text-uppercase weekday-field"
>
<template #prepend>
<div
class="column text-uppercase text-accent text-weight-bold full-height"
style="font-size: 0.5em; transform: translateY(4px);"
>
{{ $t('shared.misc.out') }} :
</div>
</template>
</q-input>
</div>
<div class="col-auto q-px-xs">
<q-btn
dense
push
color="negative"
icon="clear"
size="sm"
tabindex="-1"
@click="$emit('click-delete')"
/>
</div>
</div>
</template>
<style scoped>
:deep(.q-field__native) {
padding: 0 !important;
}
.weekday-field :deep(.q-field__control) {
height: 25px;
min-height: 25px;
}
:deep(.q-field--auto-height.q-field--dense .q-field__native) {
min-height: 25px;
}
</style>

View File

@ -2,18 +2,29 @@
setup setup
lang="ts" lang="ts"
> >
import SchedulePresetsDialogRow from './schedule-presets-dialog-row.vue';
import { useEmployeeListApi } from '../composables/use-employee-api';
import { SchedulePresetShift } from '../models/schedule-presets.models';
import { useSchedulePresetsStore } from 'src/stores/schedule-presets.store'; import { useSchedulePresetsStore } from 'src/stores/schedule-presets.store';
const schedule_preset_store = useSchedulePresetsStore(); const schedule_preset_store = useSchedulePresetsStore();
const employee_list_api = useEmployeeListApi();
</script> </script>
<template> <template>
<q-dialog v-model="schedule_preset_store.is_manager_open"> <q-dialog
v-model="schedule_preset_store.is_manager_open"
full-width
>
<div <div
class="column flex-center bg-secondary rounded-10 shadow-24 full-width" class="column flex-center bg-secondary rounded-10 shadow-24"
style="border: 2px solid var(--q-accent);" style="border: 2px solid var(--q-accent); width: 50vw !important;"
> >
<div class="row col-auto flex-center bg-primary full-width"> <div
class="row col-auto flex-center bg-primary full-width"
style="border-radius: 8px 8px 0 0;"
>
<span class="row col-auto text-uppercase text-weight-bold text-white q-py-sm">{{ <span class="row col-auto text-uppercase text-weight-bold text-white q-py-sm">{{
schedule_preset_store.current_schedule_preset.id === -1 ? schedule_preset_store.current_schedule_preset.id === -1 ?
$t('shared.label.add') : $t('shared.label.add') :
@ -31,7 +42,15 @@
:placeholder="$t('employee_management.schedule_presets.preset_name_placeholder')" :placeholder="$t('employee_management.schedule_presets.preset_name_placeholder')"
class="text-uppercase" class="text-uppercase"
input-class="text-weight-bold text-center" input-class="text-weight-bold text-center"
/> >
<template #before>
<q-icon
name="edit"
color="accent"
class="q-ml-sm"
/>
</template>
</q-input>
</div> </div>
</div> </div>
@ -39,35 +58,34 @@
<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"
class="row col-auto items-center q-my-xs full-width shadow-2 q-px-sm bg-dark rounded-10" class="row col-auto items-center q-my-xs shadow-2 bg-dark rounded-10 ellipsis"
style="min-height: 50px;" style="min-height: 50px;"
> >
<span class="col-2 text-uppercase text-weight-bold ellipsis">{{ <span class="col-2 text-uppercase text-weight-bold q-ml-sm ellipsis">{{
$t(`shared.weekday.${weekday.day.toLowerCase()}`) }} $t(`shared.weekday.${weekday.day.toLowerCase()}`) }}
</span> </span>
<div class="col column"> <div class="col column">
<div <div
v-for="shift in weekday.shifts" v-for="_shift, index in weekday.shifts"
:key="shift.week_day" :key="index"
class="row col-auto"
> >
<q-input <SchedulePresetsDialogRow
v-model="shift.end_time" v-model:shift="weekday.shifts[index]!"
standout @click-delete="weekday.shifts.splice(index, 1)"
dense />
hide-bottom-space
class="text-uppercase weekday-field"
input-class="text-weight-bold"
>
<template #prepend>
<div class="column text-uppercase text-accent text-weight-bold full-height" style="font-size: 0.5em; transform: translateY(4px);">
{{ $t('shared.misc.out') }}
</div>
</template>
</q-input>
</div> </div>
</div>
<div class="col-auto self-stretch">
<q-btn
square
icon="more_time"
color="accent"
class="full-height q-ma-none q-px-sm"
tabindex="-1"
@click="weekday.shifts.push(new SchedulePresetShift(weekday.day))"
/>
</div> </div>
</div> </div>
</div> </div>
@ -79,21 +97,12 @@
push push
dense dense
:color="schedule_preset_store.current_schedule_preset.name === '' ? 'grey-7' : 'accent'" :color="schedule_preset_store.current_schedule_preset.name === '' ? 'grey-7' : 'accent'"
icon="save" icon="download"
label="save" :label="$t('shared.label.save')"
class="col-3 q-px-sm q-mb-md" class="col-auto q-px-md q-mb-sm"
@click="employee_list_api.saveSchedulePreset"
/> />
</div> </div>
</div> </div>
</q-dialog> </q-dialog>
</template> </template>
<style scoped>
:deep(.q-field__native) {
padding: 0 !important;
}
.weekday-field :deep(.q-field__control) {
height: 25px;
}
</style>

View File

@ -1,25 +1,46 @@
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";
export const useEmployeeListApi = () => { export const useEmployeeListApi = () => {
const employee_list_store = useEmployeeStore(); const employee_store = useEmployeeStore();
const schedule_preset_store = useSchedulePresetsStore(); const schedule_preset_store = useSchedulePresetsStore();
const getEmployeeList = async (): Promise<void> => { const getEmployeeList = async (): Promise<void> => {
employee_list_store.is_loading = true; employee_store.is_loading = true;
const success = await employee_list_store.getEmployeeList(); const success = await employee_store.getEmployeeList();
if (success) await schedule_preset_store.findSchedulePresetList(); if (success) await schedule_preset_store.findSchedulePresetList();
employee_list_store.is_loading = false; employee_store.is_loading = false;
}; };
const getEmployeeDetails = (email: string): Promise<void> => { const getEmployeeDetails = (email: string): Promise<void> => {
return employee_list_store.getEmployeeDetails(email); return employee_store.getEmployeeDetails(email);
}
const setSchedulePreset = (preset_id: number) => {
schedule_preset_store.setCurrentSchedulePreset(preset_id);
employee_store.employee.preset_id = preset_id < 0 ? null : preset_id;
}
const saveSchedulePreset = async() => {
const preset = schedule_preset_store.current_schedule_preset;
const preset_shifts = preset.weekdays.flatMap(weekday => weekday.shifts);
const backend_preset = new SchedulePreset(preset.id, preset.name, preset.is_default, preset_shifts);
const success = await schedule_preset_store.updateSchedulePreset(backend_preset);
if (success) {
schedule_preset_store.is_manager_open = false;
await schedule_preset_store.findSchedulePresetList();
}
} }
return { return {
getEmployeeList, getEmployeeList,
getEmployeeDetails, getEmployeeDetails,
setSchedulePreset,
saveSchedulePreset,
}; };
}; };

View File

@ -19,7 +19,7 @@ export class EmployeeProfile {
birth_date: string; birth_date: string;
is_supervisor: boolean; is_supervisor: boolean;
user_module_access: ModuleAccessName[]; user_module_access: ModuleAccessName[];
preset_id?: number; preset_id?: number | null;
constructor() { constructor() {
this.first_name = ''; this.first_name = '';
@ -116,3 +116,14 @@ export const employee_access_presets: Record<ModuleAccessPreset, ModuleAccessNam
'employee' : ['dashboard', 'timesheets', 'personal_profile', 'employee_list'], 'employee' : ['dashboard', 'timesheets', 'personal_profile', 'employee_list'],
'none' : [], 'none' : [],
} }
export const getEmployeeAccessOptionIcon = (module: ModuleAccessName): string => {
switch (module) {
case 'dashboard': return 'home';
case 'employee_list' : return 'groups';
case 'employee_management': return 'las la-user-edit';
case 'personal_profile': return 'las la-id-card';
case 'timesheets': return 'punch_clock';
case 'timesheets_approval': return 'event_available';
}
}

View File

@ -1,3 +1,5 @@
import type { ShiftType } from "src/modules/timesheets/models/shift.models";
export type Weekday = 'SUN' | 'MON' | 'TUE' | 'WED' | 'THU' | 'FRI' | 'SAT'; export type Weekday = 'SUN' | 'MON' | 'TUE' | 'WED' | 'THU' | 'FRI' | 'SAT';
export const WEEKDAYS: Weekday[] = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'] export const WEEKDAYS: Weekday[] = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT']
@ -8,18 +10,18 @@ export class SchedulePreset {
is_default: boolean; is_default: boolean;
shifts: SchedulePresetShift[]; shifts: SchedulePresetShift[];
constructor() { constructor(id?: number, name?: string, is_default?: boolean, shifts?: SchedulePresetShift[]) {
this.id = -1; this.id = id ?? -1;
this.name = 'default'; this.name = name ?? 'default';
this.is_default = true; this.is_default = is_default ?? false;
this.shifts = []; this.shifts = shifts ?? [];
} }
} }
class SchedulePresetShift { export class SchedulePresetShift {
preset_id: number; preset_id: number;
week_day: Weekday; week_day: Weekday;
type: string; type: ShiftType;
start_time: string; start_time: string;
end_time: string; end_time: string;
is_remote: boolean; is_remote: boolean;
@ -27,7 +29,7 @@ class SchedulePresetShift {
constructor(weekday: Weekday) { constructor(weekday: Weekday) {
this.preset_id = -1; this.preset_id = -1;
this.week_day = weekday; this.week_day = weekday;
this.type = ''; this.type = 'REGULAR';
this.start_time = '00:00'; this.start_time = '00:00';
this.end_time = '00:00'; this.end_time = '00:00';
this.is_remote = false; this.is_remote = false;

View File

@ -3,13 +3,13 @@ import type { SchedulePreset } from "src/modules/employee-list/models/schedule-p
import type { BackendResponse } from "src/modules/shared/models/backend-response.models"; import type { BackendResponse } from "src/modules/shared/models/backend-response.models";
export const SchedulePresetsService = { export const SchedulePresetsService = {
createSchedulePresets: async (new_schedule: SchedulePreset) => { createSchedulePresets: async (preset: SchedulePreset) => {
const response = await api.post(`/schedule-presets/create/`, new_schedule); const response = await api.post(`/schedule-presets/create/`, preset);
return response.data; return response.data;
}, },
updateSchedulePresets: async (preset_id: number, dto: Partial<SchedulePreset>) => { updateSchedulePresets: async (preset: SchedulePreset): Promise<BackendResponse<boolean>> => {
const response = await api.patch(`/schedule-presets/update/${preset_id}`, dto); const response = await api.patch(`/schedule-presets/update`, preset);
return response.data; return response.data;
}, },

View File

@ -16,6 +16,7 @@
const shift_rules = useShiftRules(t('timesheet.errors.SHIFT_TIME_REQUIRED'),); const shift_rules = useShiftRules(t('timesheet.errors.SHIFT_TIME_REQUIRED'),);
const COMMENT_LENGTH_MAX = 280; const COMMENT_LENGTH_MAX = 280;
const SHIFT_OPTIONS: ShiftOption[] = [ const SHIFT_OPTIONS: ShiftOption[] = [
{ label: t('timesheet.shift.types.REGULAR'), value: 'REGULAR', icon: 'wb_sunny', icon_color: 'blue-grey-3' }, { label: t('timesheet.shift.types.REGULAR'), value: 'REGULAR', icon: 'wb_sunny', icon_color: 'blue-grey-3' },
{ label: t('timesheet.shift.types.EVENING'), value: 'EVENING', icon: 'bedtime', icon_color: 'indigo-8' }, { label: t('timesheet.shift.types.EVENING'), value: 'EVENING', icon: 'bedtime', icon_color: 'indigo-8' },
@ -24,6 +25,7 @@
{ label: t('timesheet.shift.types.HOLIDAY'), value: 'HOLIDAY', icon: 'forest', icon_color: 'green-8' }, { label: t('timesheet.shift.types.HOLIDAY'), value: 'HOLIDAY', icon: 'forest', icon_color: 'green-8' },
{ label: t('timesheet.shift.types.SICK'), value: 'SICK', icon: 'medication_liquid', icon_color: 'light-blue-6' }, { label: t('timesheet.shift.types.SICK'), value: 'SICK', icon: 'medication_liquid', icon_color: 'light-blue-6' },
]; ];
const shift = defineModel<Shift>('shift', { required: true }); const shift = defineModel<Shift>('shift', { required: true });
const shift_type_selected = ref(SHIFT_OPTIONS.find(option => option.value == shift.value.type)); const shift_type_selected = ref(SHIFT_OPTIONS.find(option => option.value == shift.value.type));
const select_ref = useTemplateRef<QSelect>('select'); const select_ref = useTemplateRef<QSelect>('select');

View File

@ -11,6 +11,10 @@ export const useSchedulePresetsStore = defineStore('schedule_presets_store', ()
const is_manager_open = ref(false); const is_manager_open = ref(false);
const setCurrentSchedulePreset = (preset_id: number) => { const setCurrentSchedulePreset = (preset_id: number) => {
if (preset_id === -1) {
current_schedule_preset.value = new SchedulePresetFrontend;
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)!)
}; };
@ -34,9 +38,10 @@ export const useSchedulePresetsStore = defineStore('schedule_presets_store', ()
} }
}; };
const updateSchedulePreset = async (): Promise<boolean> => { const updateSchedulePreset = async (preset: SchedulePreset): Promise<boolean> => {
try { try {
return true; const response = await SchedulePresetsService.updateSchedulePresets(preset);
return response.success;
} catch (error) { } catch (error) {
console.error('DEV ERROR || error while updating schedule preset: ', error); console.error('DEV ERROR || error while updating schedule preset: ', error);
return false; return false;