refactor(timesheet): complete overhaul of expense UI, fix functionality in approval module.
This commit is contained in:
parent
4ab271e66f
commit
9213a42d6b
|
|
@ -3,7 +3,7 @@
|
|||
lang="ts"
|
||||
>
|
||||
const model = defineModel<string | number | null | undefined>({ required: true });
|
||||
const is_date_picker_open = defineModel<boolean>('isDatePickerOpen', {default: false});
|
||||
const is_date_picker_open = defineModel<boolean>('isDatePickerOpen', { default: false });
|
||||
|
||||
defineProps<{
|
||||
label?: string | undefined;
|
||||
|
|
@ -11,16 +11,22 @@
|
|||
maxLength?: number;
|
||||
noTopPadding?: boolean;
|
||||
backgroundColor?: 'bg-secondary' | 'bg-dark';
|
||||
appendContent?: string | number;
|
||||
}>();
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
<div
|
||||
class="col q-px-sm"
|
||||
:class="noTopPadding ? '' : 'q-pt-md'"
|
||||
>
|
||||
<q-input
|
||||
v-model="model"
|
||||
v-bind="$attrs"
|
||||
dense
|
||||
borderless
|
||||
color="accent"
|
||||
|
|
@ -42,28 +48,41 @@
|
|||
{{ 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"
|
||||
|
||||
<template
|
||||
#append
|
||||
v-if="requiresDatePicker || !!appendContent"
|
||||
>
|
||||
<div v-if="requiresDatePicker">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="lg"
|
||||
icon="calendar_month"
|
||||
color="accent"
|
||||
@click="is_date_picker_open = true"
|
||||
>
|
||||
<q-date
|
||||
v-model="model"
|
||||
mask="YYYY-MM-DD"
|
||||
color="accent"
|
||||
@update:model-value="is_date_picker_open = false"
|
||||
/>
|
||||
</q-dialog>
|
||||
</q-btn>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="!!appendContent"
|
||||
class="self-end text-uppercase text-bold text-accent"
|
||||
style="font-size: 0.8em;"
|
||||
>
|
||||
{{ appendContent }}
|
||||
</div>
|
||||
</template>
|
||||
</q-input>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@
|
|||
<ExpenseDialogForm
|
||||
:email="timesheetStore.current_pay_period_overview?.email"
|
||||
:key="refreshKey"
|
||||
mode="approval"
|
||||
@click-save="onClickSaveNewExpense"
|
||||
/>
|
||||
</q-expansion-item>
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@
|
|||
<template>
|
||||
<div class="full-width">
|
||||
<LoadingOverlay v-model="timesheetStore.is_loading" />
|
||||
|
||||
<q-table
|
||||
dense
|
||||
row-key="email"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
const file = defineModel<File>('file');
|
||||
const { email } = defineProps<{
|
||||
email?: string | undefined;
|
||||
mode?: 'normal' | 'approval';
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
'clickSave': [void];
|
||||
|
|
@ -91,156 +92,184 @@
|
|||
flat
|
||||
@submit.prevent="requestExpenseCreationOrUpdate"
|
||||
>
|
||||
<div
|
||||
class="row justify-between rounded-5 q-pb-sm"
|
||||
:class="expenseStore.mode === 'create' ? 'q-px-lg' : ''"
|
||||
>
|
||||
<!-- date selection input -->
|
||||
<div class="row col items-center">
|
||||
<q-btn
|
||||
push
|
||||
dense
|
||||
icon="event"
|
||||
color="accent"
|
||||
class="col-auto"
|
||||
@click="openDatePicker"
|
||||
/>
|
||||
|
||||
<q-dialog
|
||||
v-model="isNavigatorOpen"
|
||||
transition-show="jump-right"
|
||||
transition-hide="jump-right"
|
||||
class="z-top"
|
||||
>
|
||||
<q-date
|
||||
v-model="expenseStore.current_expense.date"
|
||||
mask="YYYY-MM-DD"
|
||||
event-color="accent"
|
||||
:options="date => date >= period_start_date && date <= period_end_date"
|
||||
@update:model-value="closeDatePicker"
|
||||
<div class="column rounded-5 q-pb-sm">
|
||||
<div class="row">
|
||||
<!-- date selection input -->
|
||||
<div class="row col items-center q-pl-sm">
|
||||
<q-btn
|
||||
push
|
||||
dense
|
||||
icon="event"
|
||||
color="accent"
|
||||
class="col-auto"
|
||||
@click="openDatePicker"
|
||||
/>
|
||||
</q-dialog>
|
||||
|
||||
<TargoInput
|
||||
v-model="expenseStore.current_expense.date"
|
||||
no-top-padding
|
||||
:label="$t('timesheet.expense.date')"
|
||||
background-color="bg-dark"
|
||||
class="col"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- expenses type selection -->
|
||||
<div class="col">
|
||||
<q-select
|
||||
v-model="expenseSelected"
|
||||
dense
|
||||
borderless
|
||||
color="accent"
|
||||
label-color="white"
|
||||
stack-label
|
||||
label-slot
|
||||
:options="expenseOptions"
|
||||
hide-dropdown-icon
|
||||
lazy-rules
|
||||
no-error-icon
|
||||
hide-bottom-space
|
||||
options-selected-class="text-white text-bold bg-accent"
|
||||
class="q-px-md rounded-5 inset-shadow"
|
||||
:class="$q.dark.isActive ? 'bg-primary' : 'bg-dark'"
|
||||
popup-content-class="text-uppercase text-weight-medium rounded-5 shadow-12 z-top"
|
||||
popup-content-style="border: 1px solid var(--q-primary);"
|
||||
menu-anchor="bottom middle"
|
||||
menu-self="top middle"
|
||||
:menu-offset="[0, 5]"
|
||||
:style="`border: 1px solid var(${$q.dark.isActive ? '--q-secondary' : '--q-primary'});`"
|
||||
:rules="[rules.typeRequired]"
|
||||
@update:model-value="option => expenseStore.current_expense.type = option.value"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-medium text-uppercase q-px-sm no-pointer-events"
|
||||
:class="$q.dark.isActive ? 'bg-secondary' : 'bg-primary'"
|
||||
>
|
||||
{{ $t('timesheet.expense.type') }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #selected-item="scope">
|
||||
<div
|
||||
class="row items-center text-weight-bold q-ma-none q-pa-none no-wrap ellipsis full-width"
|
||||
:class="ui_store.is_mobile_mode ? 'full-height' : ''"
|
||||
:tabindex="scope.tabindex"
|
||||
>
|
||||
<q-icon
|
||||
:name="scope.opt.icon"
|
||||
size="xs"
|
||||
class="col-auto q-mx-xs"
|
||||
/>
|
||||
<span
|
||||
style="line-height: 1em;"
|
||||
class="col-auto ellipsis text-uppercase"
|
||||
>{{ scope.opt.label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</q-select>
|
||||
</div>
|
||||
|
||||
<!-- amount input -->
|
||||
<div class="col q-px-xs">
|
||||
<TargoInput
|
||||
v-if="TYPES_WITH_AMOUNT_ONLY.includes(expenseStore.current_expense?.type ?? 'EXPENSES')"
|
||||
v-model.number="expenseStore.current_expense.amount"
|
||||
no-top-padding
|
||||
background-color="bg-dark"
|
||||
:label="$t('timesheet.expense.amount')"
|
||||
/>
|
||||
|
||||
<TargoInput
|
||||
v-else
|
||||
v-model="expenseStore.current_expense.mileage"
|
||||
no-top-padding
|
||||
background-color="bg-dark"
|
||||
:label="$t('timesheet.expense.mileage')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- employee comment input -->
|
||||
<div class="col q-px-xs">
|
||||
<TargoInput
|
||||
v-model="expenseStore.current_expense.comment"
|
||||
no-top-padding
|
||||
background-color="bg-dark"
|
||||
:max-length="COMMENT_MAX_LENGTH"
|
||||
:label="$t('timesheet.expense.employee_comment')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- import attach file section -->
|
||||
<div class="col q-px-xs">
|
||||
<q-file
|
||||
v-model="file"
|
||||
standout
|
||||
dense
|
||||
stack-label
|
||||
label-slot
|
||||
type="file"
|
||||
accept="image/*"
|
||||
>
|
||||
<template #prepend>
|
||||
<q-icon
|
||||
name="attach_file"
|
||||
size="sm"
|
||||
color="accent"
|
||||
<q-dialog
|
||||
v-model="isNavigatorOpen"
|
||||
transition-show="jump-right"
|
||||
transition-hide="jump-right"
|
||||
class="z-top"
|
||||
>
|
||||
<q-date
|
||||
v-model="expenseStore.current_expense.date"
|
||||
mask="YYYY-MM-DD"
|
||||
event-color="accent"
|
||||
:options="date => date >= period_start_date && date <= period_end_date"
|
||||
@update:model-value="closeDatePicker"
|
||||
/>
|
||||
</template>
|
||||
</q-dialog>
|
||||
|
||||
<template #label>
|
||||
<span class="text-weight-bold text-accent text-uppercase text-caption">
|
||||
{{ $t('timesheet.expense.hints.attach_file') }}
|
||||
</span>
|
||||
</template>
|
||||
</q-file>
|
||||
<TargoInput
|
||||
v-model="expenseStore.current_expense.date"
|
||||
no-top-padding
|
||||
:label="$t('timesheet.expense.date')"
|
||||
background-color="bg-dark"
|
||||
class="col"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- expenses type selection -->
|
||||
<div class="col">
|
||||
<q-select
|
||||
v-model="expenseSelected"
|
||||
dense
|
||||
borderless
|
||||
color="accent"
|
||||
label-color="white"
|
||||
stack-label
|
||||
label-slot
|
||||
:options="expenseOptions"
|
||||
hide-dropdown-icon
|
||||
lazy-rules
|
||||
no-error-icon
|
||||
hide-bottom-space
|
||||
options-selected-class="text-white text-bold bg-accent"
|
||||
class="q-px-md rounded-5 inset-shadow"
|
||||
:class="$q.dark.isActive ? 'bg-primary' : 'bg-dark'"
|
||||
popup-content-class="text-uppercase text-weight-medium rounded-5 shadow-12 z-top"
|
||||
popup-content-style="border: 1px solid var(--q-primary);"
|
||||
menu-anchor="bottom middle"
|
||||
menu-self="top middle"
|
||||
:menu-offset="[0, 5]"
|
||||
:style="`border: 1px solid var(${$q.dark.isActive ? '--q-secondary' : '--q-primary'});`"
|
||||
:rules="[rules.typeRequired]"
|
||||
@update:model-value="option => expenseStore.current_expense.type = option.value"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-medium text-uppercase q-px-sm no-pointer-events"
|
||||
:class="$q.dark.isActive ? 'bg-secondary' : 'bg-primary'"
|
||||
>
|
||||
{{ $t('timesheet.expense.type') }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #selected-item="scope">
|
||||
<div
|
||||
class="row items-center text-weight-bold q-ma-none q-pa-none no-wrap ellipsis full-width"
|
||||
:class="ui_store.is_mobile_mode ? 'full-height' : ''"
|
||||
:tabindex="scope.tabindex"
|
||||
>
|
||||
<q-icon
|
||||
:name="scope.opt.icon"
|
||||
size="xs"
|
||||
class="col-auto q-mx-xs"
|
||||
/>
|
||||
<span
|
||||
style="line-height: 1em;"
|
||||
class="col-auto ellipsis text-uppercase"
|
||||
>{{ scope.opt.label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</q-select>
|
||||
</div>
|
||||
|
||||
<!-- amount input -->
|
||||
<div class="col">
|
||||
<TargoInput
|
||||
v-if="TYPES_WITH_AMOUNT_ONLY.includes(expenseStore.current_expense?.type ?? 'EXPENSES')"
|
||||
v-model.number="expenseStore.current_expense.amount"
|
||||
no-top-padding
|
||||
background-color="bg-dark"
|
||||
type="number"
|
||||
input-class="text-right"
|
||||
append-content=" $"
|
||||
:label="$t('timesheet.expense.amount')"
|
||||
/>
|
||||
|
||||
<TargoInput
|
||||
v-else
|
||||
v-model.number="expenseStore.current_expense.mileage"
|
||||
no-top-padding
|
||||
background-color="bg-dark"
|
||||
type="number"
|
||||
input-class="text-right"
|
||||
append-content=" km"
|
||||
:label="$t('timesheet.expense.mileage')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row q-pt-md">
|
||||
<!-- employee comment input -->
|
||||
<div class="col">
|
||||
<TargoInput
|
||||
v-model="expenseStore.current_expense.comment"
|
||||
no-top-padding
|
||||
background-color="bg-dark"
|
||||
:max-length="COMMENT_MAX_LENGTH"
|
||||
:label="$t('timesheet.expense.employee_comment')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="mode === 'approval'"
|
||||
class="col"
|
||||
>
|
||||
<TargoInput
|
||||
v-model="expenseStore.current_expense.supervisor_comment"
|
||||
no-top-padding
|
||||
background-color="bg-dark"
|
||||
:max-length="COMMENT_MAX_LENGTH"
|
||||
:label="$t('timesheet.expense.supervisor_comment')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- import attach file section -->
|
||||
<div class="col-3 q-px-sm">
|
||||
<q-file
|
||||
v-model="file"
|
||||
dense
|
||||
borderless
|
||||
color="accent"
|
||||
label-color="white"
|
||||
stack-label
|
||||
label-slot
|
||||
type="file"
|
||||
accept="image/*"
|
||||
class="q-px-md rounded-5 inset-shadow"
|
||||
:class="$q.dark.isActive ? 'bg-primary' : 'bg-dark'"
|
||||
:style="`border: 1px solid var(${$q.dark.isActive ? '--q-secondary' : '--q-primary'});`"
|
||||
>
|
||||
<template #append>
|
||||
<q-icon
|
||||
name="attach_file"
|
||||
size="sm"
|
||||
color="accent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #label>
|
||||
<span
|
||||
class="text-weight-medium text-uppercase q-px-sm no-pointer-events"
|
||||
:class="$q.dark.isActive ? 'bg-secondary' : 'bg-primary'"
|
||||
>
|
||||
{{ $t('timesheet.expense.hints.attach_file') }}
|
||||
</span>
|
||||
</template>
|
||||
</q-file>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -266,8 +295,8 @@
|
|||
scoped
|
||||
lang="css"
|
||||
>
|
||||
:deep(.q-field--dense.q-field--float .q-field__label) {
|
||||
transform: translate(-17px, -60%) scale(0.75) !important;
|
||||
border-radius: 10px 10px 10px 0px;
|
||||
}
|
||||
:deep(.q-field--dense.q-field--float .q-field__label) {
|
||||
transform: translate(-17px, -60%) scale(0.75) !important;
|
||||
border-radius: 10px 10px 10px 0px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -244,6 +244,7 @@
|
|||
<ExpenseDialogForm
|
||||
v-model="expense"
|
||||
:email="getEmployeeEmail()"
|
||||
:mode="mode"
|
||||
@click-save="hideUpdateForm"
|
||||
/>
|
||||
</q-expansion-item>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user