refactor(presets): set up work for schedule presets, minor cleanup of other modules
This commit is contained in:
parent
8852f5990b
commit
2affa8470b
|
|
@ -13,6 +13,10 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
employee_management: {
|
employee_management: {
|
||||||
|
add_employee: "Add employee",
|
||||||
|
modify_employee: "Modify employee",
|
||||||
|
access_label: "access",
|
||||||
|
details_label: "details",
|
||||||
module_access: {
|
module_access: {
|
||||||
dashboard: "Dashboard",
|
dashboard: "Dashboard",
|
||||||
employee_list: "employee list",
|
employee_list: "employee list",
|
||||||
|
|
@ -31,10 +35,10 @@ export default {
|
||||||
none_description: "Uncheck all modules",
|
none_description: "Uncheck all modules",
|
||||||
usage_description: "You can use roles to enable preset modules, add or remove modules individually, or both",
|
usage_description: "You can use roles to enable preset modules, add or remove modules individually, or both",
|
||||||
},
|
},
|
||||||
add_employee: "Add employee",
|
filter: {
|
||||||
modify_employee: "Modify employee",
|
show_terminated: "Show inactive employees",
|
||||||
access_label: "access",
|
sort_by_tags: "sort by tags",
|
||||||
details_label: "details",
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
login: {
|
login: {
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,10 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
employee_management: {
|
employee_management: {
|
||||||
|
add_employee: "Ajouter employé",
|
||||||
|
modify_employee: "Modifier employé",
|
||||||
|
access_label: "accès",
|
||||||
|
details_label: "détails",
|
||||||
module_access: {
|
module_access: {
|
||||||
dashboard: "Accueil",
|
dashboard: "Accueil",
|
||||||
employee_list: "Répertoire du personnel",
|
employee_list: "Répertoire du personnel",
|
||||||
|
|
@ -31,10 +35,10 @@ export default {
|
||||||
none_description: "Enlever tous les accès",
|
none_description: "Enlever tous les accès",
|
||||||
usage_description: "Vous pouvez utiliser les rôles pour sélectionner des modules prédéfinis, enlever ou ajouter des modules individuellement, ou les deux",
|
usage_description: "Vous pouvez utiliser les rôles pour sélectionner des modules prédéfinis, enlever ou ajouter des modules individuellement, ou les deux",
|
||||||
},
|
},
|
||||||
add_employee: "Ajouter employé",
|
filter: {
|
||||||
modify_employee: "Modifier employé",
|
show_terminated: "Afficher les employés inactifs",
|
||||||
access_label: "accès",
|
sort_by_tags: "filtrer par identifiants",
|
||||||
details_label: "détails",
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
login: {
|
login: {
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,13 @@
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { useUiStore } from 'src/stores/ui-store';
|
import { useUiStore } from 'src/stores/ui-store';
|
||||||
import { useEmployeeStore } from 'src/stores/employee-store';
|
import { useEmployeeStore } from 'src/stores/employee-store';
|
||||||
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||||
import { useEmployeeListApi } from 'src/modules/employee-list/composables/use-employee-api';
|
import { useEmployeeListApi } from 'src/modules/employee-list/composables/use-employee-api';
|
||||||
import { employee_list_columns } from 'src/modules/employee-list/models/employee-profile.models';
|
import { employee_list_columns } from 'src/modules/employee-list/models/employee-profile.models';
|
||||||
|
|
||||||
const employee_list_api = useEmployeeListApi();
|
const employee_list_api = useEmployeeListApi();
|
||||||
const employee_store = useEmployeeStore();
|
const employee_store = useEmployeeStore();
|
||||||
|
const timesheet_store = useTimesheetStore();
|
||||||
const ui_store = useUiStore();
|
const ui_store = useUiStore();
|
||||||
const is_loading_list = ref<boolean>(true);
|
const is_loading_list = ref<boolean>(true);
|
||||||
|
|
||||||
|
|
@ -48,34 +50,10 @@
|
||||||
:no-data-label="$t('shared.error.no_data_found')"
|
:no-data-label="$t('shared.error.no_data_found')"
|
||||||
:no-results-label="$t('shared.error.no_search_results')"
|
:no-results-label="$t('shared.error.no_search_results')"
|
||||||
:loading-label="$t('shared.label.loading')"
|
:loading-label="$t('shared.label.loading')"
|
||||||
|
:visible-columns="['first_name', 'email', 'company', 'supervisor_full_name', 'company_name', 'job_title']"
|
||||||
@row-click="() => console.log('click!')"
|
@row-click="() => console.log('click!')"
|
||||||
>
|
>
|
||||||
<template #header="props">
|
<template #top>
|
||||||
<q-tr
|
|
||||||
:props="props"
|
|
||||||
class="bg-accent"
|
|
||||||
>
|
|
||||||
<q-th
|
|
||||||
v-for="col in props.cols"
|
|
||||||
:key="col.name"
|
|
||||||
:props="props"
|
|
||||||
>
|
|
||||||
<span class="text-uppercase text-weight-bolder text-white">
|
|
||||||
{{ $t(col.label) }}
|
|
||||||
</span>
|
|
||||||
</q-th>
|
|
||||||
</q-tr>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-slot:item="props">
|
|
||||||
<EmployeeListTableItem
|
|
||||||
:row="props.row"
|
|
||||||
:index="props.rowIndex"
|
|
||||||
@on-profile-click="employee_store.openAddModifyDialog"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-slot:top>
|
|
||||||
<div class="row full-width q-mb-sm">
|
<div class="row full-width q-mb-sm">
|
||||||
<q-btn
|
<q-btn
|
||||||
push
|
push
|
||||||
|
|
@ -121,17 +99,57 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #body-cell="scope">
|
<template #header="props">
|
||||||
<q-td
|
<q-tr
|
||||||
:props="scope"
|
:props="props"
|
||||||
class="text-weight-medium"
|
class="bg-primary"
|
||||||
>
|
>
|
||||||
<span >{{ scope.value }}</span>
|
<q-th
|
||||||
|
v-for="col in props.cols"
|
||||||
|
:key="col.name"
|
||||||
|
:props="props"
|
||||||
|
>
|
||||||
|
<span class="text-uppercase text-weight-bolder text-white text-h6">
|
||||||
|
{{ $t(col.label) }}
|
||||||
|
</span>
|
||||||
|
</q-th>
|
||||||
|
</q-tr>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #item="props">
|
||||||
|
<EmployeeListTableItem
|
||||||
|
:row="props.row"
|
||||||
|
:index="props.rowIndex"
|
||||||
|
@on-profile-click="employee_store.openAddModifyDialog"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #body-cell="scope">
|
||||||
|
<q-td :props="scope">
|
||||||
|
<transition
|
||||||
|
appear
|
||||||
|
enter-active-class="animated fadeInUp slow"
|
||||||
|
leave-active-class="animated fadeOutDown"
|
||||||
|
mode="out-in"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
:key="scope.rowIndex + (timesheet_store.pay_period?.pay_period_no ?? 0)"
|
||||||
|
class="rounded-5"
|
||||||
|
style="font-size: 1.2em;"
|
||||||
|
:style="`animation-delay: ${scope.rowIndex / 30}s;`"
|
||||||
|
>
|
||||||
|
<div v-if="scope.col.name === 'first_name'">
|
||||||
|
<span class="text-h5 text-uppercase text-accent q-mr-xs">{{ scope.value }}</span>
|
||||||
|
<span class="text-uppercase text-weight-light">{{ scope.row.last_name }}</span>
|
||||||
|
</div>
|
||||||
|
<span v-else>{{ scope.value }}</span>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
</q-td>
|
</q-td>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Template for custome failed-to-load state -->
|
<!-- Template for custome failed-to-load state -->
|
||||||
<template v-slot:no-data="{ message, filter }">
|
<template #no-data="{ message, filter }">
|
||||||
<div class="full-width column items-center text-accent q-gutter-sm">
|
<div class="full-width column items-center text-accent q-gutter-sm">
|
||||||
<span class="text-h6 q-mt-xl">
|
<span class="text-h6 q-mt-xl">
|
||||||
{{ message }}
|
{{ message }}
|
||||||
|
|
@ -146,21 +164,26 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="sass">
|
<style scoped>
|
||||||
.sticky-header-table
|
.sticky-header-table thead tr:first-child th {
|
||||||
thead tr:first-child th
|
background-color: var(--q-primary);
|
||||||
background-color: var(--q-accent)
|
margin-top: none;
|
||||||
margin-top: none
|
}
|
||||||
|
|
||||||
thead tr th
|
thead tr th {
|
||||||
position: sticky
|
position: sticky;
|
||||||
z-index: 1
|
z-index: 1;
|
||||||
thead tr:first-child th
|
}
|
||||||
top: 0px
|
|
||||||
|
|
||||||
&.q-table--loading thead tr:last-child th
|
thead tr:first-child th {
|
||||||
top: 48px
|
top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
tbody
|
&.q-table--loading thead tr:last-child th {
|
||||||
scroll-margin-top: 48px
|
top: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody {
|
||||||
|
scroll-margin-top: 48px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -5,13 +5,15 @@
|
||||||
import AddModifyDialogForm from 'src/modules/employee-list/components/employee/add-modify-dialog-form.vue';
|
import AddModifyDialogForm from 'src/modules/employee-list/components/employee/add-modify-dialog-form.vue';
|
||||||
import AddModifyDialogAccess from 'src/modules/employee-list/components/employee/add-modify-dialog-access.vue';
|
import AddModifyDialogAccess from 'src/modules/employee-list/components/employee/add-modify-dialog-access.vue';
|
||||||
|
|
||||||
import { useEmployeeStore } from 'src/stores/employee-store';
|
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
import { useEmployeeStore } from 'src/stores/employee-store';
|
||||||
|
import { EmployeeProfile } from 'src/modules/employee-list/models/employee-profile.models';
|
||||||
|
|
||||||
const employee_store = useEmployeeStore();
|
const employee_store = useEmployeeStore();
|
||||||
const current_step = ref<'form' | 'access'>('form');
|
const current_step = ref<'form' | 'access'>('form');
|
||||||
const transition_in_animation = ref('fadeInRight');
|
const transition_in_animation = ref('fadeInRight');
|
||||||
const transition_out_animation = ref('fadeOutLeft');
|
const transition_out_animation = ref('fadeOutLeft');
|
||||||
|
const initial_employee_profile = ref(new EmployeeProfile)
|
||||||
|
|
||||||
const getNextMenu = (animation_in: string, animation_out: string, next_step: 'form' | 'access') => {
|
const getNextMenu = (animation_in: string, animation_out: string, next_step: 'form' | 'access') => {
|
||||||
transition_in_animation.value = animation_in;
|
transition_in_animation.value = animation_in;
|
||||||
|
|
@ -25,6 +27,7 @@
|
||||||
v-model="employee_store.is_add_modify_dialog_open"
|
v-model="employee_store.is_add_modify_dialog_open"
|
||||||
full-width
|
full-width
|
||||||
@beforeShow="current_step = 'form'"
|
@beforeShow="current_step = 'form'"
|
||||||
|
@show="Object.assign(initial_employee_profile, employee_store.employee)"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="column bg-secondary rounded-10"
|
class="column bg-secondary rounded-10"
|
||||||
|
|
@ -119,13 +122,13 @@
|
||||||
/>
|
/>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
square
|
square
|
||||||
color="accent"
|
color="accent"
|
||||||
:label="employee_store.management_mode === 'add_employee' ? $t('shared.label.save') : $t('shared.label.update')"
|
:label="employee_store.management_mode === 'add_employee' ? $t('shared.label.save') : $t('shared.label.update')"
|
||||||
class="col-auto q-py-sm shadow-up-5"
|
class="col-auto q-py-sm shadow-up-5"
|
||||||
@click="employee_store.createOrUpdateEmployee(employee_store.employee)"
|
@click="employee_store.createOrUpdateEmployee(employee_store.employee)"
|
||||||
/>
|
/>
|
||||||
<q-inner-loading :showing="employee_store.is_loading" />
|
<q-inner-loading :showing="employee_store.is_loading" />
|
||||||
</div>
|
</div>
|
||||||
</q-dialog>
|
</q-dialog>
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ export class EmployeeProfile {
|
||||||
export const employee_list_columns: QTableColumn<EmployeeProfile>[] = [
|
export const employee_list_columns: QTableColumn<EmployeeProfile>[] = [
|
||||||
{
|
{
|
||||||
name: 'first_name',
|
name: 'first_name',
|
||||||
label: 'employee_list.table.first_name',
|
label: 'timesheet_approvals.table.full_name',
|
||||||
field: 'first_name',
|
field: 'first_name',
|
||||||
align: 'left'
|
align: 'left'
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -39,4 +39,9 @@
|
||||||
:deep(.q-field__control-container) {
|
:deep(.q-field__control-container) {
|
||||||
padding-left: 16px;
|
padding-left: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(.q-field__control::before) {
|
||||||
|
border: 1px solid var(--q-accent) !important;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
export interface shiftColor {
|
|
||||||
type_label: string;
|
|
||||||
background_color: string;
|
|
||||||
font_color: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const shift_type_legend: shiftColor[] = [
|
|
||||||
{
|
|
||||||
type_label: 'shared.shift_type.regular',
|
|
||||||
background_color: 'blue-grey-4',
|
|
||||||
font_color: 'blue-grey-8',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type_label: 'shared.shift_type.evening',
|
|
||||||
background_color: 'warning',
|
|
||||||
font_color: 'blue-grey-2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type_label: 'shared.shift_type.emergency',
|
|
||||||
background_color: 'amber-10',
|
|
||||||
font_color: 'blue-grey-2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type_label: 'shared.shift_type.overtime',
|
|
||||||
background_color: 'negative',
|
|
||||||
font_color: 'blue-grey-2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type_label: 'shared.shift_type.vacation',
|
|
||||||
background_color: 'purple-10',
|
|
||||||
font_color: 'blue-grey-2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type_label: 'shared.shift_type.holiday',
|
|
||||||
background_color: 'purple-8',
|
|
||||||
font_color: 'blue-grey-2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type_label: 'shared.shift_type.sick',
|
|
||||||
background_color: 'grey-8',
|
|
||||||
font_color: 'blue-grey-2',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
<script
|
|
||||||
setup
|
|
||||||
lang="ts"
|
|
||||||
>
|
|
||||||
import { computed, ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import type { ShiftLegendItem } from 'src/modules/timesheets/models/shift.models';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
const is_showing_legend = ref(false);
|
|
||||||
|
|
||||||
const legend: ShiftLegendItem[] = [
|
|
||||||
{ type: 'REGULAR', color: 'secondary', label_type: 'timesheet.shift.types.REGULAR' },
|
|
||||||
{ type: 'EVENING', color: 'warning', label_type: 'timesheet.shift.types.EVENING' },
|
|
||||||
{ type: 'EMERGENCY', color: 'amber-10', label_type: 'timesheet.shift.types.EMERGENCY' },
|
|
||||||
{ type: 'VACATION', color: 'purple-10', label_type: 'timesheet.shift.types.VACATION' },
|
|
||||||
{ type: 'HOLIDAY', color: 'purple-5', label_type: 'timesheet.shift.types.HOLIDAY' },
|
|
||||||
{ type: 'SICK', color: 'grey-8', label_type: 'timesheet.shift.types.SICK' },
|
|
||||||
]
|
|
||||||
|
|
||||||
const shift_type_legend = computed(() =>
|
|
||||||
legend.map(item => ({ ...item, label: t(item.label_type) }))
|
|
||||||
);
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div
|
|
||||||
class="items-center"
|
|
||||||
:class="$q.screen.lt.md ? 'column' : 'row'"
|
|
||||||
>
|
|
||||||
<q-btn
|
|
||||||
flat
|
|
||||||
dense
|
|
||||||
rounded
|
|
||||||
color="primary"
|
|
||||||
class="col-auto q-my-sm"
|
|
||||||
@click="is_showing_legend = !is_showing_legend"
|
|
||||||
>
|
|
||||||
<template #default>
|
|
||||||
<q-icon
|
|
||||||
:name="is_showing_legend ? 'close' : 'info_outline'"
|
|
||||||
size="md"
|
|
||||||
class="col-auto"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</q-btn>
|
|
||||||
|
|
||||||
<transition
|
|
||||||
appear
|
|
||||||
enter-active-class="animated fadeIn"
|
|
||||||
leave-active-class="animated fadeOut"
|
|
||||||
class="col-auto"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="is_showing_legend"
|
|
||||||
class="q-py-xs bg-white rounded-5 shadow-2 text-center q-my-xs"
|
|
||||||
>
|
|
||||||
<q-badge
|
|
||||||
v-for="shift_type in shift_type_legend"
|
|
||||||
:key="shift_type.type"
|
|
||||||
:color="shift_type.color"
|
|
||||||
:label="shift_type.label"
|
|
||||||
:text-color="shift_type.text_color || 'white'"
|
|
||||||
class="q-pa-xs q-mx-xs q-my-none text-uppercase text-weight-bolder justify-center"
|
|
||||||
style="font-size: 0.8em;"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
@ -27,26 +27,8 @@
|
||||||
class="row items-center full-width bg-dark shadow-2 rounded-5 q-my-xs"
|
class="row items-center full-width bg-dark shadow-2 rounded-5 q-my-xs"
|
||||||
style="border: 2px solid var(--q-negative)"
|
style="border: 2px solid var(--q-negative)"
|
||||||
>
|
>
|
||||||
<q-item-section class="col-auto">
|
|
||||||
<q-badge
|
|
||||||
outline
|
|
||||||
color="negative"
|
|
||||||
class="bg-dark text-weight-bolder"
|
|
||||||
>{{ error.conflicts.date }}</q-badge>
|
|
||||||
</q-item-section>
|
|
||||||
|
|
||||||
<q-item-section class="col-auto">
|
|
||||||
<q-badge
|
|
||||||
outline
|
|
||||||
color="negative"
|
|
||||||
class="bg-dark text-weight-bolder"
|
|
||||||
>
|
|
||||||
{{ error.conflicts.start_time }} - {{ error.conflicts.end_time }}
|
|
||||||
</q-badge>
|
|
||||||
</q-item-section>
|
|
||||||
|
|
||||||
<q-item-label class="text-weight-medium text-caption q-ml-md">
|
<q-item-label class="text-weight-medium text-caption q-ml-md">
|
||||||
{{ $t('timesheet.shift.errors.' + error.error_code) }}
|
{{ $t('timesheet.shift.errors.' + error) }}
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,6 @@ export type ShiftType = 'REGULAR' | 'EVENING' | 'EMERGENCY' | 'HOLIDAY' | 'VACAT
|
||||||
|
|
||||||
export type ShiftErrorCode = 'SHIFT_OVERLAP' | 'MISSING_START_TIME' | 'MISSING_END_TIME' | 'COMMENT_LENGTH_EXCEEDED' | 'APPROVAL_LOCK' | 'INVALID_DATE' | 'INVALID TYPE' | 'INVALID_TIMESHEET';
|
export type ShiftErrorCode = 'SHIFT_OVERLAP' | 'MISSING_START_TIME' | 'MISSING_END_TIME' | 'COMMENT_LENGTH_EXCEEDED' | 'APPROVAL_LOCK' | 'INVALID_DATE' | 'INVALID TYPE' | 'INVALID_TIMESHEET';
|
||||||
|
|
||||||
export type ShiftLegendItem = {
|
|
||||||
type: ShiftType;
|
|
||||||
color: string;
|
|
||||||
label_type: string;
|
|
||||||
text_color?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class Shift {
|
export class Shift {
|
||||||
id: number;
|
id: number;
|
||||||
timesheet_id: number;
|
timesheet_id: number;
|
||||||
|
|
@ -49,23 +42,4 @@ export interface ShiftOption {
|
||||||
value: ShiftType;
|
value: ShiftType;
|
||||||
icon: string;
|
icon: string;
|
||||||
icon_color: string;
|
icon_color: string;
|
||||||
}
|
|
||||||
|
|
||||||
export interface ShiftAPIResponse {
|
|
||||||
ok: boolean;
|
|
||||||
data?: {
|
|
||||||
shift: Shift;
|
|
||||||
overtime: unknown;
|
|
||||||
}
|
|
||||||
error?: ShiftAPIError;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ShiftAPIError {
|
|
||||||
error_code: ShiftErrorCode;
|
|
||||||
conflicts:
|
|
||||||
{
|
|
||||||
date: string;
|
|
||||||
start_time: string;
|
|
||||||
end_time: string;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { api } from "src/boot/axios";
|
import { api } from "src/boot/axios";
|
||||||
import type { Shift, ShiftAPIResponse } from "src/modules/timesheets/models/shift.models";
|
import type { BackendResponse } from "src/modules/shared/models/backend-response.models";
|
||||||
|
import type { Shift } from "src/modules/timesheets/models/shift.models";
|
||||||
|
|
||||||
export const ShiftService = {
|
export const ShiftService = {
|
||||||
deleteShiftById: async (shift_id: number) => {
|
deleteShiftById: async (shift_id: number) => {
|
||||||
|
|
@ -7,14 +8,14 @@ export const ShiftService = {
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
createNewShifts: async (new_shifts: Shift[]):Promise<ShiftAPIResponse[]> => {
|
createNewShifts: async (new_shifts: Shift[]):Promise<BackendResponse<Shift>> => {
|
||||||
const response = await api.post(`/shift/create`, new_shifts);
|
const response = await api.post(`/shift/create`, new_shifts);
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
updateShifts: async (existing_shifts: Shift[]) => {
|
updateShifts: async (existing_shifts: Shift[]):Promise<BackendResponse<Shift>> => {
|
||||||
console.log('sent shifts: ', existing_shifts)
|
console.log('sent shifts: ', existing_shifts)
|
||||||
const response = await api.patch(`/shift/update`, existing_shifts);
|
const response = await api.patch(`/shift/update`, existing_shifts);
|
||||||
return response;
|
return response.data;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -27,11 +27,4 @@ import { onMounted } from 'vue';
|
||||||
class="col-sm-12 col-md-10 col-lg-7 col-xl-5"
|
class="col-sm-12 col-md-10 col-lg-7 col-xl-5"
|
||||||
/>
|
/>
|
||||||
</q-page>
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
:deep(.q-field--outlined.q-field--readonly .q-field__control:before) {
|
|
||||||
border: 1px solid var(--q-accent);
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -4,11 +4,10 @@ import { Notify } from "quasar";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { ShiftService } from "src/modules/timesheets/services/shift-service";
|
import { ShiftService } from "src/modules/timesheets/services/shift-service";
|
||||||
import { useTimesheetStore } from "src/stores/timesheet-store";
|
import { useTimesheetStore } from "src/stores/timesheet-store";
|
||||||
import type { ShiftAPIError } from "src/modules/timesheets/models/shift.models";
|
|
||||||
|
|
||||||
export const useShiftStore = defineStore('shift_store', () => {
|
export const useShiftStore = defineStore('shift_store', () => {
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheet_store = useTimesheetStore();
|
||||||
const shift_errors = ref<ShiftAPIError[]>([]);
|
const shift_errors = ref<string[]>([]);
|
||||||
|
|
||||||
const deleteShiftById = async (shift_id: number): Promise<boolean> => {
|
const deleteShiftById = async (shift_id: number): Promise<boolean> => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -22,7 +21,6 @@ export const useShiftStore = defineStore('shift_store', () => {
|
||||||
|
|
||||||
const createNewShifts = async (): Promise<boolean> => {
|
const createNewShifts = async (): Promise<boolean> => {
|
||||||
if (timesheet_store.timesheets === undefined) return false;
|
if (timesheet_store.timesheets === undefined) return false;
|
||||||
const has_errors = false;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const days = timesheet_store.timesheets.flatMap(week => week.days);
|
const days = timesheet_store.timesheets.flatMap(week => week.days);
|
||||||
|
|
@ -30,14 +28,10 @@ export const useShiftStore = defineStore('shift_store', () => {
|
||||||
|
|
||||||
if (new_shifts?.length > 0) {
|
if (new_shifts?.length > 0) {
|
||||||
const response = await ShiftService.createNewShifts(new_shifts);
|
const response = await ShiftService.createNewShifts(new_shifts);
|
||||||
if (response.every(res => res.ok)) {
|
if (response.success) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else { shift_errors.value.push(response.error!) }
|
||||||
response.forEach(res => {
|
|
||||||
shift_errors.value.push(res.error!);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -55,7 +49,7 @@ export const useShiftStore = defineStore('shift_store', () => {
|
||||||
if (existing_shifts?.length > 0) {
|
if (existing_shifts?.length > 0) {
|
||||||
const response = await ShiftService.updateShifts(existing_shifts);
|
const response = await ShiftService.updateShifts(existing_shifts);
|
||||||
|
|
||||||
if (response.status < 400) {
|
if (response.success) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user