Merge pull request 'dev/nicolas/staging-prep' (#44) from dev/nicolas/staging-prep into main
Reviewed-on: Targo/targo_frontend#44
This commit is contained in:
commit
68973501c6
|
|
@ -70,6 +70,7 @@ export default {
|
|||
supervisor: "Supervisor",
|
||||
company: "Company",
|
||||
is_supervisor: "is a supervisor",
|
||||
expected_daily_hours: "Expected Daily Hours",
|
||||
active: "active",
|
||||
inactive: "inactive",
|
||||
},
|
||||
|
|
@ -81,7 +82,11 @@ export default {
|
|||
access_label: "access",
|
||||
details_label: "details",
|
||||
schedule_label: "schedule",
|
||||
can_be_entered_later: "OPTIONAL: can be entered later",
|
||||
enter_delete_input: "type 'DELETE' to remove",
|
||||
banked_hours: "available banked hours",
|
||||
sick_hours: "available PTO hours",
|
||||
vacation_hours: "available vacation hours",
|
||||
schedule_presets: {
|
||||
preset_list_placeholder: "Select a schedule",
|
||||
preset_name_placeholder: "schedule preset name",
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ export default {
|
|||
supervisor: "superviseur",
|
||||
company: "Compagnie",
|
||||
is_supervisor: "est un superviseur",
|
||||
expected_daily_hours: "Heures quotidiennes attendues",
|
||||
active: "actif",
|
||||
inactive: "inactif",
|
||||
},
|
||||
|
|
@ -81,7 +82,11 @@ export default {
|
|||
access_label: "accès",
|
||||
details_label: "détails",
|
||||
schedule_label: "horaire",
|
||||
can_be_entered_later: "FACULTATIF: peut être entré plus tard",
|
||||
enter_delete_input: "tappez 'SUPPRIMER' pour confirmer",
|
||||
banked_hours: "heures en banque disponibles",
|
||||
sick_hours: "heures d'absence payées disponibles",
|
||||
vacation_hours: "heures de vacances disponibles",
|
||||
schedule_presets: {
|
||||
preset_list_placeholder: "Sélectionner un horaire",
|
||||
preset_name_placeholder: "nom de l'horaire",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
<script
|
||||
setup
|
||||
lang="ts"
|
||||
>
|
||||
const model = defineModel<string | number | null | undefined>({ required: true });
|
||||
const is_date_picker_open = defineModel<boolean>('isDatePickerOpen', {default: false});
|
||||
|
||||
defineProps<{
|
||||
label?: string | undefined;
|
||||
requiresDatePicker?: boolean | undefined;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-input
|
||||
v-model="model"
|
||||
dense
|
||||
outlined
|
||||
color="accent"
|
||||
stack-label
|
||||
label-slot
|
||||
class="col q-px-sm q-py-xs"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-bolder text-uppercase"
|
||||
style="font-size: 0.85em;"
|
||||
>
|
||||
{{ label }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #append v-if="requiresDatePicker">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="lg"
|
||||
icon="calendar_month"
|
||||
color="accent"
|
||||
@click="is_date_picker_open = true"
|
||||
>
|
||||
<q-dialog
|
||||
v-model="is_date_picker_open"
|
||||
backdrop-filter="none"
|
||||
>
|
||||
<q-date
|
||||
v-model="model"
|
||||
mask="YYYY-MM-DD"
|
||||
color="accent"
|
||||
@update:model-value="is_date_picker_open = false"
|
||||
/>
|
||||
</q-dialog>
|
||||
</q-btn>
|
||||
</template>
|
||||
</q-input>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<script
|
||||
setup
|
||||
lang="ts"
|
||||
>
|
||||
const model = defineModel<string>({ required: true });
|
||||
|
||||
defineProps<{
|
||||
label?: string | undefined;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-select
|
||||
v-model="model"
|
||||
dense
|
||||
outlined
|
||||
color="accent"
|
||||
stack-label
|
||||
label-slot
|
||||
options-selected-class="text-white text-bold bg-accent"
|
||||
class="col q-px-sm q-py-xs"
|
||||
popup-content-class="text-uppercase text-weight-medium rounded-5"
|
||||
popup-content-style="border: 2px solid var(--q-accent)"
|
||||
menu-anchor="bottom middle"
|
||||
menu-self="top middle"
|
||||
:menu-offset="[0, 5]"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-bolder text-uppercase"
|
||||
style="font-size: 0.85em;"
|
||||
>
|
||||
{{ label }}
|
||||
</span>
|
||||
</template>
|
||||
</q-select>
|
||||
</template>
|
||||
|
|
@ -2,6 +2,9 @@
|
|||
setup
|
||||
lang="ts"
|
||||
>
|
||||
import AddModifyDialogFormInput from 'src/modules/employee-list/components/add-modify-dialog-form-input.vue';
|
||||
import AddModifyDialogFormSelect from 'src/modules/employee-list/components/add-modify-dialog-form-select.vue';
|
||||
|
||||
import { ref, computed } from 'vue';
|
||||
import { useEmployeeStore } from 'src/stores/employee-store';
|
||||
|
||||
|
|
@ -20,7 +23,7 @@
|
|||
return supervisors.map(supervisor => supervisor.first_name + ' ' + supervisor.last_name);
|
||||
})
|
||||
|
||||
const setLastWorkDay = (date: string | number | null) => {
|
||||
const setLastWorkDay = (date: string | number | null | undefined) => {
|
||||
if (typeof date === 'string' && date.length > 0) {
|
||||
employee_store.employee.last_work_day = date;
|
||||
}
|
||||
|
|
@ -54,260 +57,124 @@
|
|||
class="q-ma-xs"
|
||||
:class="$q.screen.lt.sm ? 'column' : 'row'"
|
||||
>
|
||||
<q-input
|
||||
<AddModifyDialogFormInput
|
||||
v-model="employee_store.employee.first_name"
|
||||
color="accent"
|
||||
stack-label
|
||||
label-slot
|
||||
class="col q-mx-md"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-bolder text-uppercase"
|
||||
style="font-size: 0.85em;"
|
||||
>
|
||||
{{ $t('profile.personal.first_name') }}
|
||||
</span>
|
||||
</template>
|
||||
</q-input>
|
||||
:label="$t('profile.personal.first_name')"
|
||||
/>
|
||||
|
||||
<q-input
|
||||
<AddModifyDialogFormInput
|
||||
v-model="employee_store.employee.last_name"
|
||||
color="accent"
|
||||
stack-label
|
||||
label-slot
|
||||
class="col q-mx-md"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-bolder text-uppercase"
|
||||
style="font-size: 0.85em;"
|
||||
>
|
||||
{{ $t('profile.personal.last_name') }}
|
||||
</span>
|
||||
</template>
|
||||
</q-input>
|
||||
:label="$t('profile.personal.last_name')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="q-ma-xs"
|
||||
:class="$q.screen.lt.sm ? 'column' : 'row'"
|
||||
>
|
||||
<q-input
|
||||
<AddModifyDialogFormInput
|
||||
v-model="employee_store.employee.email"
|
||||
color="accent"
|
||||
stack-label
|
||||
label-slot
|
||||
class="col q-mx-md"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-bolder text-uppercase"
|
||||
style="font-size: 0.85em;"
|
||||
>
|
||||
{{ $t('profile.employee.email') }}
|
||||
</span>
|
||||
</template>
|
||||
</q-input>
|
||||
:label="$t('profile.employee.email')"
|
||||
/>
|
||||
|
||||
<q-input
|
||||
<AddModifyDialogFormInput
|
||||
v-model="employee_store.employee.phone_number"
|
||||
color="accent"
|
||||
stack-label
|
||||
label-slot
|
||||
mask="(###) ### - ####"
|
||||
class="col q-mx-md"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-bolder text-uppercase"
|
||||
style="font-size: 0.85em;"
|
||||
>
|
||||
{{ $t('profile.personal.phone_number') }}
|
||||
</span>
|
||||
</template>
|
||||
</q-input>
|
||||
:label="$t('profile.personal.phone_number')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="q-ma-xs"
|
||||
:class="$q.screen.lt.sm ? 'column' : 'row'"
|
||||
>
|
||||
<q-input
|
||||
<AddModifyDialogFormInput
|
||||
v-model="employee_store.employee.job_title"
|
||||
color="accent"
|
||||
stack-label
|
||||
label-slot
|
||||
class="col q-mx-md"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-bolder text-uppercase"
|
||||
style="font-size: 0.85em;"
|
||||
>
|
||||
{{ $t('profile.employee.job_title') }}
|
||||
</span>
|
||||
</template>
|
||||
</q-input>
|
||||
:label="$t('profile.employee.job_title')"
|
||||
/>
|
||||
|
||||
<q-select
|
||||
<AddModifyDialogFormSelect
|
||||
v-model="employee_store.employee.company_name"
|
||||
color="accent"
|
||||
:options="company_options"
|
||||
stack-label
|
||||
emit-value
|
||||
label-slot
|
||||
class="col q-mx-md"
|
||||
popup-content-class="text-uppercase text-weight-medium rounded-20"
|
||||
popup-content-style="border: 2px solid var(--q-accent)"
|
||||
menu-anchor="bottom middle"
|
||||
menu-self="top middle"
|
||||
:menu-offset="[0, 10]"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-bolder text-uppercase"
|
||||
style="font-size: 0.85em;"
|
||||
>
|
||||
{{ $t('profile.employee.company') }}
|
||||
</span>
|
||||
</template>
|
||||
</q-select>
|
||||
:label="$t('profile.employee.company')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="q-ma-xs"
|
||||
:class="$q.screen.lt.sm ? 'column' : 'row'"
|
||||
>
|
||||
<q-select
|
||||
<AddModifyDialogFormSelect
|
||||
v-model="employee_store.employee.supervisor_full_name"
|
||||
color="accent"
|
||||
stack-label
|
||||
label-slot
|
||||
:options="supervisor_options"
|
||||
options-selected-class="text-white text-bold bg-accent"
|
||||
class="col q-mx-md"
|
||||
popup-content-class="text-uppercase text-weight-medium rounded-20"
|
||||
popup-content-style="border: 2px solid var(--q-accent)"
|
||||
menu-anchor="bottom middle"
|
||||
menu-self="top middle"
|
||||
:menu-offset="[0, 10]"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-bolder text-uppercase"
|
||||
style="font-size: 0.85em;"
|
||||
>
|
||||
{{ $t('profile.employee.supervisor') }}
|
||||
</span>
|
||||
</template>
|
||||
</q-select>
|
||||
:label="$t('profile.employee.supervisor')"
|
||||
/>
|
||||
|
||||
<q-input
|
||||
v-if="employee_store.management_mode === 'modify_employee'"
|
||||
<AddModifyDialogFormInput
|
||||
v-model="employee_store.employee.external_payroll_id"
|
||||
color="accent"
|
||||
stack-label
|
||||
label-slot
|
||||
class="col q-mx-md"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-bolder text-uppercase"
|
||||
style="font-size: 0.85em;"
|
||||
>
|
||||
{{ $t('profile.employee.bankroll_id') }}
|
||||
</span>
|
||||
</template>
|
||||
</q-input>
|
||||
:label="$t('profile.employee.bankroll_id')"
|
||||
:placeholder="$t('employee_management.can_be_entered_later')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="q-ma-xs"
|
||||
:class="$q.screen.lt.sm ? 'column' : 'row'"
|
||||
>
|
||||
<AddModifyDialogFormInput
|
||||
v-model="employee_store.employee.daily_expected_hours"
|
||||
:label="$t('employee_list.table.expected_daily_hours')"
|
||||
type="number"
|
||||
/>
|
||||
|
||||
<AddModifyDialogFormInput
|
||||
v-if="employee_store.employee.paid_time_off"
|
||||
v-model="employee_store.employee.paid_time_off.banked_hours"
|
||||
:label="$t('employee_management.banked_hours')"
|
||||
type="number"
|
||||
/>
|
||||
|
||||
<div v-else class="col q-px-sm"></div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="q-ma-xs"
|
||||
:class="$q.screen.lt.sm ? 'column' : 'row'"
|
||||
>
|
||||
<AddModifyDialogFormInput
|
||||
v-if="employee_store.employee.paid_time_off"
|
||||
v-model="employee_store.employee.paid_time_off.sick_hours"
|
||||
:label="$t('employee_management.sick_hours')"
|
||||
type="number"
|
||||
/>
|
||||
|
||||
<AddModifyDialogFormInput
|
||||
v-if="employee_store.employee.paid_time_off"
|
||||
v-model="employee_store.employee.paid_time_off.vacation_hours"
|
||||
:label="$t('employee_management.vacation_hours')"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="q-ma-xs"
|
||||
:class="$q.screen.lt.md ? 'column' : 'row'"
|
||||
>
|
||||
<q-input
|
||||
<AddModifyDialogFormInput
|
||||
v-model="employee_store.employee.first_work_day"
|
||||
color="accent"
|
||||
stack-label
|
||||
label-slot
|
||||
v-model:is-date-picker-open="is_first_day_picker_open"
|
||||
reqires-date-picker
|
||||
:label="$t('profile.employee.hired_date')"
|
||||
mask="####-##-##"
|
||||
class="col q-mx-md"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-bolder text-uppercase"
|
||||
style="font-size: 0.85em;"
|
||||
>
|
||||
{{ $t('profile.employee.hired_date') }}
|
||||
</span>
|
||||
</template>
|
||||
/>
|
||||
|
||||
<template #append>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="lg"
|
||||
icon="calendar_month"
|
||||
color="accent"
|
||||
@click="is_first_day_picker_open = true"
|
||||
>
|
||||
<q-dialog
|
||||
v-model="is_first_day_picker_open"
|
||||
backdrop-filter="none"
|
||||
>
|
||||
<q-date
|
||||
v-model="employee_store.employee.first_work_day"
|
||||
mask="YYYY-MM-DD"
|
||||
color="accent"
|
||||
@update:model-value="is_first_day_picker_open = false"
|
||||
/>
|
||||
</q-dialog>
|
||||
</q-btn>
|
||||
</template>
|
||||
</q-input>
|
||||
|
||||
<q-input
|
||||
<AddModifyDialogFormInput
|
||||
v-model="last_work_day"
|
||||
color="accent"
|
||||
stack-label
|
||||
label-slot
|
||||
v-model:is-date-picker-open="is_last_day_picker_open"
|
||||
reqires-date-picker
|
||||
:label="$t('profile.employee.fired_date')"
|
||||
mask="####-##-##"
|
||||
class="col q-mx-md"
|
||||
@update:model-value="setLastWorkDay"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-bolder text-uppercase"
|
||||
style="font-size: 0.85em;"
|
||||
>
|
||||
{{ $t('profile.employee.fired_date') }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #append>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="lg"
|
||||
icon="calendar_month"
|
||||
color="accent"
|
||||
@click="is_last_day_picker_open = true"
|
||||
>
|
||||
<q-dialog
|
||||
v-model="is_last_day_picker_open"
|
||||
backdrop-filter="none"
|
||||
>
|
||||
<q-date
|
||||
v-model="employee_store.employee.last_work_day"
|
||||
mask="YYYY-MM-DD"
|
||||
color="accent"
|
||||
@update:model-value="is_last_day_picker_open = false"
|
||||
/>
|
||||
</q-dialog>
|
||||
</q-btn>
|
||||
</template>
|
||||
</q-input>
|
||||
/>
|
||||
</div>
|
||||
</q-form>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
>
|
||||
import { useQuasar } from 'quasar';
|
||||
import type { EmployeeProfile } from 'src/modules/employee-list/models/employee-profile.models';
|
||||
import { ref } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const q = useQuasar();
|
||||
const is_mouseover = ref(false);
|
||||
|
|
@ -22,7 +22,7 @@ import { ref } from 'vue';
|
|||
const getItemStyle = (): string => {
|
||||
const active_style = row.last_work_day === null ? '' : 'opacity: 0.6;';
|
||||
const dark_style = q.dark.isActive ? 'border: 2px solid var(--q-accent);' : '';
|
||||
const hover_style = isManagement ? (is_mouseover.value ? `transform: scale(1.1); z-index: 2;` :'transform: scale(1) skew(0)') : '';
|
||||
const hover_style = isManagement ? (is_mouseover.value ? `transform: scale(1.1); z-index: 2;` : 'transform: scale(1) skew(0)') : '';
|
||||
|
||||
return `${active_style} ${dark_style} ${hover_style}`;
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ import { ref } from 'vue';
|
|||
<div
|
||||
class="column col no-wrap bg-dark rounded-15 shadow-12"
|
||||
:class="isManagement ? 'cursor-pointer item-mouse-hover' : ''"
|
||||
style="max-width: 230px; height: 275px;"
|
||||
style="height: 275px;"
|
||||
:style="getItemStyle()"
|
||||
@click="$emit('onProfileClick', row.email)"
|
||||
@mouseenter="is_mouseover = true"
|
||||
|
|
@ -57,7 +57,7 @@ import { ref } from 'vue';
|
|||
</div>
|
||||
|
||||
<div
|
||||
class="col column items-center justify-start text-center text-weight-medium text-uppercase q-pa-sm no-wrap"
|
||||
class="col column items-center justify-start text-center text-weight-medium text-uppercase q-px-sm q-pt-sm no-wrap"
|
||||
style="line-height: 1.2em; font-size: 1.3em;"
|
||||
>
|
||||
<div
|
||||
|
|
@ -68,21 +68,40 @@ import { ref } from 'vue';
|
|||
|
||||
<q-separator class="q-mb-xs q-mx-md" />
|
||||
</div>
|
||||
<div class=" ellipsis-2-lines text-caption no-wrap">{{ row.job_title }}</div>
|
||||
|
||||
<div class="col-auto ellipsis-2-lines text-caption no-wrap">{{ row.job_title }}</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="col-auto bg-primary text-white text-caption text-center text-weight-medium q-py-sm"
|
||||
class="col-auto column items-center bg-primary text-white text-caption text-center q-py-xs"
|
||||
style="border-radius: 0 0 15px 15px;"
|
||||
>
|
||||
{{ row.email }}
|
||||
<div
|
||||
class="col-auto row flex-center text-weight-light text-italic"
|
||||
style="font-size: 1em;"
|
||||
>
|
||||
<q-icon
|
||||
name="las la-phone"
|
||||
size="xs"
|
||||
color="accent"
|
||||
class="col-auto"
|
||||
/>
|
||||
<span class="col-auto">{{ row.phone_number }}</span>
|
||||
</div>
|
||||
|
||||
<span class="col-auto text-italic">extension: </span>
|
||||
|
||||
<span class="col-auto text-weight-medium">{{ row.email }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.item-mouse-hover {
|
||||
transition: all 0.2s ease-out;
|
||||
}
|
||||
<style
|
||||
lang="css"
|
||||
scoped
|
||||
>
|
||||
.item-mouse-hover {
|
||||
transition: all 0.2s ease-out;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
const is_management = auth_store.user?.user_module_access.includes('employee_management') ?? false;
|
||||
|
||||
const visible_columns = ref<(keyof EmployeeProfile)[]>(['first_name', 'email', 'job_title', 'last_work_day']);
|
||||
const visible_columns = ref<(keyof EmployeeProfile)[]>(['first_name', 'email', 'job_title', 'phone_number', 'last_work_day']);
|
||||
|
||||
const table_grid_container = ref<HTMLElement | null>(null);
|
||||
|
||||
|
|
@ -28,6 +28,10 @@
|
|||
hide_inactive_users: true,
|
||||
});
|
||||
|
||||
const { maxHeight } = defineProps<{
|
||||
maxHeight: number;
|
||||
}>();
|
||||
|
||||
const filterEmployeeRows = (rows: readonly EmployeeProfile[], terms: EmployeeListFilters, _cols: readonly QTableColumn<EmployeeProfile>[]): EmployeeProfile[] => {
|
||||
let result = [...rows];
|
||||
|
||||
|
|
@ -63,7 +67,7 @@
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="q-pa-lg">
|
||||
<div class="full-width">
|
||||
<q-table
|
||||
:key="filters.hide_inactive_users ? '1' : '0'"
|
||||
dense
|
||||
|
|
@ -77,10 +81,11 @@
|
|||
:pagination="{ sortBy: 'first_name' }"
|
||||
:filter="filters"
|
||||
:filter-method="filterEmployeeRows"
|
||||
class="bg-transparent no-shadow sticky-header-table"
|
||||
:style="$q.screen.lt.md ? '' : 'width: 80vw;'"
|
||||
class="bg-transparent no-shadow sticky-header-table full-width q-pt-lg"
|
||||
:style="employee_store.employee_list.length > 0 ? `max-height: ${maxHeight - (ui_store.user_preferences.is_employee_list_grid ? 0 : 20)}px;` : ''"
|
||||
:table-class="$q.dark.isActive ? 'q-py-none q-mx-md rounded-10 bg-dark shadow-10 hide-scrollbar' : 'q-py-none q-mx-md rounded-10 bg-white shadow-10 hide-scrollbar'"
|
||||
color="accent"
|
||||
separator="none"
|
||||
table-header-class="text-accent text-uppercase"
|
||||
card-container-class="justify-center"
|
||||
:grid="ui_store.user_preferences.is_employee_list_grid"
|
||||
|
|
@ -193,6 +198,7 @@
|
|||
<q-td
|
||||
:props="scope"
|
||||
@click="is_management ? employee_store.openAddModifyDialog(scope.row.email) : ''"
|
||||
:class="scope.rowIndex % 2 === 0 ? ($q.dark.isActive ? 'bg-primary' : 'bg-secondary') : ''"
|
||||
>
|
||||
<transition
|
||||
appear
|
||||
|
|
@ -287,4 +293,8 @@ tbody {
|
|||
:deep(.q-table) {
|
||||
transition: height 0.25s ease;
|
||||
}
|
||||
|
||||
:deep(.q-table__grid-content) {
|
||||
overflow: auto
|
||||
}
|
||||
</style>
|
||||
|
|
@ -4,6 +4,13 @@ import type { UserModuleAccess } from "src/modules/shared/models/user.models";
|
|||
export type ModuleAccessPreset = 'admin' | 'supervisor' | 'employee' | 'none';
|
||||
export type CompanyNames = 'Targo' | 'Solucom';
|
||||
|
||||
export interface PaidTimeOff {
|
||||
sick_hours: number;
|
||||
vacation_hours: number;
|
||||
banked_hours: number;
|
||||
last_updated: string;
|
||||
}
|
||||
|
||||
export class EmployeeProfile {
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
|
|
@ -14,7 +21,9 @@ export class EmployeeProfile {
|
|||
phone_number: string;
|
||||
first_work_day: string;
|
||||
last_work_day?: string | null;
|
||||
external_payroll_id: number;
|
||||
external_payroll_id?: number;
|
||||
daily_expected_hours?: number;
|
||||
paid_time_off?: PaidTimeOff;
|
||||
residence: string;
|
||||
birth_date: string;
|
||||
is_supervisor: boolean;
|
||||
|
|
@ -34,7 +43,6 @@ export class EmployeeProfile {
|
|||
this.residence = '';
|
||||
this.birth_date = '';
|
||||
this.is_supervisor = false;
|
||||
this.external_payroll_id = 999;
|
||||
this.user_module_access = ['dashboard',];
|
||||
}
|
||||
}
|
||||
|
|
@ -80,11 +88,24 @@ export const employee_list_columns: QTableColumn<EmployeeProfile>[] = [
|
|||
align: 'left',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'phone_number',
|
||||
label: 'employee_list.table.phone_number',
|
||||
field: 'phone_number',
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'job_title',
|
||||
label: 'employee_list.table.role',
|
||||
field: 'job_title',
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'expected_daily_hours',
|
||||
label: 'employee_list.table.expected_daily_hours',
|
||||
field: 'daily_expected_hours',
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'last_work_day',
|
||||
|
|
|
|||
|
|
@ -7,9 +7,8 @@
|
|||
|
||||
const modelApproval = defineModel<boolean>();
|
||||
|
||||
const { row, index = 0 } = defineProps<{
|
||||
const { row } = defineProps<{
|
||||
row: TimesheetApprovalOverview;
|
||||
index?: number;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
|
@ -26,7 +25,7 @@
|
|||
>
|
||||
<q-card
|
||||
class="rounded-10 shadow-5"
|
||||
:style="`animation-delay: ${index / 15}s; opacity: ${row.is_active ? '1' : '0.75'}; transform: scale(${row.is_active ? '1' : '0.9'})`"
|
||||
:style="`opacity: ${row.is_active ? '1' : '0.75'}; transform: scale(${row.is_active ? '1' : '0.9'})`"
|
||||
>
|
||||
<!-- Card header with employee name and details button-->
|
||||
<q-card-section
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@
|
|||
import { useTimesheetApprovalApi } from 'src/modules/timesheet-approval/composables/use-timesheet-approval-api';
|
||||
import { type OverviewColumns, pay_period_overview_columns, PayPeriodOverviewFilters, type TimesheetApprovalOverview } from 'src/modules/timesheet-approval/models/timesheet-overview.models';
|
||||
import { getHoursMinutesStringFromHoursFloat } from 'src/utils/date-and-time-utils';
|
||||
import { useUiStore } from 'src/stores/ui-store';
|
||||
import { useUiStore } from 'src/stores/ui-store';
|
||||
|
||||
const WARNING_COLUMNS: OverviewColumns[] = ['EMERGENCY', 'EVENING', 'HOLIDAY', 'VACATION', 'SICK']
|
||||
const NEGATIVE_COLUMNS: OverviewColumns[] = ['OVERTIME',]
|
||||
const WARNING_COLUMNS: OverviewColumns[] = ['EVENING', 'HOLIDAY', 'VACATION', 'SICK']
|
||||
const NEGATIVE_COLUMNS: OverviewColumns[] = ['OVERTIME', 'EMERGENCY']
|
||||
|
||||
const ui_store = useUiStore();
|
||||
const auth_store = useAuthStore();
|
||||
|
|
@ -51,7 +51,7 @@ import { useUiStore } from 'src/stores/ui-store';
|
|||
const overview_rows = computed(() => timesheet_store.pay_period_overviews.filter(overview => overview));
|
||||
const overview_filters = ref<PayPeriodOverviewFilters>({
|
||||
is_showing_inactive: false,
|
||||
is_showing_team_only: false,
|
||||
is_showing_team_only: true,
|
||||
supervisors: [],
|
||||
name_search_string: '',
|
||||
});
|
||||
|
|
@ -88,12 +88,14 @@ import { useUiStore } from 'src/stores/ui-store';
|
|||
return result;
|
||||
};
|
||||
|
||||
const getListViewTimeClass = (column_name: OverviewColumns, value: number) => {
|
||||
if(WARNING_COLUMNS.includes(column_name) && value > 0)
|
||||
return 'bg-warning text-white rounded-5';
|
||||
const getListViewTimeCss = (column_name: OverviewColumns, value: number): { classes: string, style: string } => {
|
||||
if (WARNING_COLUMNS.includes(column_name) && value > 0)
|
||||
return { classes: 'bg-warning text-white rounded-5', style: '' };
|
||||
|
||||
if(NEGATIVE_COLUMNS.includes(column_name) && value > 0)
|
||||
return 'bg-negative text-white text-bold rounded-5';
|
||||
if (NEGATIVE_COLUMNS.includes(column_name) && value > 0)
|
||||
return { classes: 'bg-negative text-white text-bold rounded-5', style: '' };
|
||||
|
||||
return { classes: '', style: '' }
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
@ -104,6 +106,7 @@ import { useUiStore } from 'src/stores/ui-store';
|
|||
dense
|
||||
row-key="email"
|
||||
color="accent"
|
||||
separator="none"
|
||||
hide-pagination
|
||||
:rows="overview_rows"
|
||||
:columns="pay_period_overview_columns"
|
||||
|
|
@ -123,7 +126,7 @@ import { useUiStore } from 'src/stores/ui-store';
|
|||
:loading-label="$t('shared.label.loading')"
|
||||
table-header-style="min-width: 80xp; max-width: 80px;"
|
||||
:style="overview_rows.length > 0 ? `max-height: ${maxHeight - (ui_store.user_preferences.is_timesheet_approval_grid ? 0 : 20)}px;` : ''"
|
||||
:table-style="{ tableLayout: 'fixed'}"
|
||||
:table-style="{ tableLayout: 'fixed' }"
|
||||
@row-click="(_evt, row: TimesheetApprovalOverview) => onClickedDetails(row)"
|
||||
>
|
||||
<template #top>
|
||||
|
|
@ -278,17 +281,16 @@ import { useUiStore } from 'src/stores/ui-store';
|
|||
{{ props.row.employee_last_name }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- display weekly total hours (regular, vacation, holiday, emergency, evening) -->
|
||||
<div
|
||||
v-else-if="props.col.name.includes('weekly_hours')"
|
||||
class="q-px-xs"
|
||||
:class="props.value[Number(props.col.name.slice(-1,)) - 1] > 40 ? 'bg-negative text-white rounded-5' : ''"
|
||||
>
|
||||
<span>
|
||||
{{
|
||||
getHoursMinutesStringFromHoursFloat((props.value[Number(props.col.name.slice(-1,)) -
|
||||
1]) ?? 0) }}
|
||||
1]) ?? 0) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -296,7 +298,6 @@ import { useUiStore } from 'src/stores/ui-store';
|
|||
<div
|
||||
v-else-if="props.col.name === 'total_hours'"
|
||||
class="q-px-xs"
|
||||
:class="props.value > 80 ? 'bg-negative rounded-5 text-white' : ''"
|
||||
>
|
||||
<span>{{ getHoursMinutesStringFromHoursFloat(props.value) }}</span>
|
||||
</div>
|
||||
|
|
@ -305,7 +306,7 @@ import { useUiStore } from 'src/stores/ui-store';
|
|||
<div
|
||||
v-else
|
||||
class="q-px-xs"
|
||||
:class="getListViewTimeClass(props.col.name, props.value)"
|
||||
:class="getListViewTimeCss(props.col.name, props.value).classes"
|
||||
>
|
||||
{{ TIME_COLUMNS.includes(props.col.name) ?
|
||||
getHoursMinutesStringFromHoursFloat(props.value) : props.value }}
|
||||
|
|
@ -320,7 +321,6 @@ import { useUiStore } from 'src/stores/ui-store';
|
|||
<OverviewListItem
|
||||
v-model="props.row.is_approved"
|
||||
:key="props.row.email + timesheet_store.pay_period?.pay_period_no"
|
||||
:index="props.rowIndex"
|
||||
:row="props.row"
|
||||
@click-details="onClickedDetails"
|
||||
@click-approval-all="is_approved => onClickApproveAll(props.row.email, is_approved)"
|
||||
|
|
@ -347,7 +347,10 @@ import { useUiStore } from 'src/stores/ui-store';
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="sass" scoped>
|
||||
<style
|
||||
lang="sass"
|
||||
scoped
|
||||
>
|
||||
.sticky-header-table
|
||||
thead tr:first-child th
|
||||
background-color: var(--q-accent)
|
||||
|
|
|
|||
|
|
@ -4,24 +4,33 @@
|
|||
>
|
||||
import EmployeeListTable from 'src/modules/employee-list/components/employee-list-table.vue';
|
||||
import AddModifyDialog from 'src/modules/employee-list/components/add-modify-dialog.vue';
|
||||
import PageHeaderTemplate from 'src/modules/shared/components/page-header-template.vue';
|
||||
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
import { onMounted, ref, computed } from 'vue';
|
||||
import { useEmployeeListApi } from 'src/modules/employee-list/composables/use-employee-api';
|
||||
|
||||
const employee_list_api = useEmployeeListApi();
|
||||
|
||||
const page_height = ref(0);
|
||||
const table_max_height = computed(() => page_height.value);
|
||||
|
||||
const tableStyleFunction = (offset: number, height: number) => {
|
||||
page_height.value = height - offset;
|
||||
|
||||
return { minHeight: height - offset + 'px' };
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await employee_list_api.getEmployeeList();
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-page class="column items-center bg-secondary">
|
||||
<q-page
|
||||
class="column items-center bg-secondary"
|
||||
:style-fn="tableStyleFunction"
|
||||
>
|
||||
<AddModifyDialog />
|
||||
|
||||
<PageHeaderTemplate title="employee_list.page_header" />
|
||||
|
||||
<EmployeeListTable />
|
||||
<EmployeeListTable :max-height="table_max_height" />
|
||||
</q-page>
|
||||
</template>
|
||||
|
|
@ -48,10 +48,7 @@
|
|||
class="column items-center scroll q-px-sm full-width"
|
||||
style="min-height: inherit;"
|
||||
>
|
||||
<div
|
||||
ref="headerComponent"
|
||||
class="col-auto"
|
||||
>
|
||||
<div class="col-auto">
|
||||
<PageHeaderTemplate
|
||||
title="timesheet_approvals.page_title"
|
||||
:start-date="timesheet_store.pay_period?.period_start ?? ''"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user