feat(schedule-preset): Add update and create functionality to schedule preset with preview
This commit is contained in:
parent
f6e9415369
commit
fd2146567f
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -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 />
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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()"
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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');
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user