203 lines
7.3 KiB
Vue
203 lines
7.3 KiB
Vue
<script
|
|
setup
|
|
lang="ts"
|
|
>
|
|
/* eslint-disable */
|
|
import { computed, inject, ref } from 'vue';
|
|
import { unwrapAndClone } from 'src/utils/unwrap-and-clone';
|
|
import { useExpensesApi } from 'src/modules/timesheets/composables/use-expense-api';
|
|
import { useExpensesStore } from 'src/stores/expense-store';
|
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
|
import { getExpenseIcon } from 'src/modules/timesheets/utils/expense.util';
|
|
import { useAuthStore } from 'src/stores/auth-store';
|
|
import { CAN_APPROVE_PAY_PERIODS } from 'src/modules/shared/models/user.models';
|
|
import { empty_expense, type Expense } from 'src/modules/timesheets/models/expense.models';
|
|
|
|
const { expense, horizontal = false } = defineProps<{
|
|
expense: Expense;
|
|
index: number;
|
|
horizontal?: boolean;
|
|
}>();
|
|
|
|
const timesheet_store = useTimesheetStore();
|
|
const expenses_store = useExpensesStore();
|
|
const auth_store = useAuthStore();
|
|
const expenses_api = useExpensesApi();
|
|
|
|
const is_approved = defineModel<boolean>({ required: true });
|
|
const is_selected = ref(false);
|
|
const refresh_key = ref(1);
|
|
const is_authorized_to_approve = computed(() => CAN_APPROVE_PAY_PERIODS.includes(auth_store.user?.role ?? 'GUEST'))
|
|
|
|
const expenseItemStyle = computed(() => is_approved.value ? 'border: solid 2px var(--q-primary);' : 'border: solid 2px grey;');
|
|
// const highlightClass = computed(() => (expenses_store.mode === 'update' && is_selected) ? 'bg-accent' : '');
|
|
const approvedClass = computed(() => horizontal ? ' q-mx-xs q-pa-xs cursor-pointer' : '')
|
|
|
|
|
|
const employeeEmail = inject<string>('employeeEmail') ?? '';
|
|
|
|
|
|
const setExpenseToModify = () => {
|
|
// expenses_store.mode = 'update';
|
|
expenses_store.current_expense = expense;
|
|
expenses_store.initial_expense = unwrapAndClone(expense);
|
|
};
|
|
|
|
const requestExpenseDeletion = async () => {
|
|
// expenses_store.mode = 'delete';
|
|
expenses_store.initial_expense = expense;
|
|
expenses_store.current_expense = empty_expense;
|
|
await expenses_api.deleteExpenseByEmployeeEmail(employeeEmail, expenses_store.initial_expense.date);
|
|
}
|
|
|
|
function onExpenseClicked() {
|
|
if (is_authorized_to_approve.value) {
|
|
is_approved.value = !is_approved.value;
|
|
refresh_key.value += 1;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<transition
|
|
enter-active-class="animated pulse"
|
|
mode="out-in"
|
|
>
|
|
<q-item
|
|
:key="refresh_key"
|
|
:clickable="horizontal"
|
|
class="row col-4 q-ma-xs shadow-2"
|
|
:style="expenseItemStyle + approvedClass"
|
|
@click="onExpenseClicked"
|
|
>
|
|
<q-badge
|
|
v-if="expense.is_approved"
|
|
class="absolute z-top rounded-20 bg-dark q-pa-none"
|
|
style="transform: translate(-15px, -15px);"
|
|
>
|
|
<q-icon
|
|
name="verified"
|
|
color="primary"
|
|
size="md"
|
|
/>
|
|
</q-badge>
|
|
|
|
<!-- avatar type icon section -->
|
|
<q-item-section avatar>
|
|
<q-icon
|
|
:name="getExpenseIcon(expense.type)"
|
|
:color="expense.is_approved ? 'primary' : ($q.dark.isActive ? 'blue-grey-2' : 'grey-8')"
|
|
size="lg"
|
|
>
|
|
<q-badge
|
|
v-if="expense.type === 'ON_CALL'"
|
|
floating
|
|
class="q-pa-none rounded-50 bg-white z-top"
|
|
>
|
|
<q-icon
|
|
name="shield"
|
|
size="xs"
|
|
:color="expense.is_approved ? 'primary' : ($q.dark.isActive ? 'blue-grey-2' : 'grey-8')"
|
|
/>
|
|
</q-badge>
|
|
</q-icon>
|
|
</q-item-section>
|
|
|
|
<!-- amount or mileage section -->
|
|
<q-item-section class="col-auto">
|
|
<q-item-label v-if="String(expense.type).trim().toUpperCase() === 'MILEAGE'">
|
|
<template v-if="typeof expense.mileage === 'number'">
|
|
{{ expense.mileage?.toFixed(1) }} km
|
|
</template>
|
|
<template v-else>
|
|
${{ expense.amount.toFixed(2) }}
|
|
</template>
|
|
</q-item-label>
|
|
<q-item-label v-else>
|
|
${{ expense.amount.toFixed(2) }}
|
|
</q-item-label>
|
|
|
|
<!-- date label -->
|
|
<q-item-label
|
|
caption
|
|
lines="1"
|
|
>
|
|
<!-- {{ $d(new Date(expense.date), { year: 'numeric', month: 'short', day: 'numeric', weekday: 'short' }) }} -->
|
|
{{ expense.date }}
|
|
</q-item-label>
|
|
</q-item-section>
|
|
|
|
<q-space v-if="horizontal" />
|
|
|
|
<!-- attachment file icon -->
|
|
<q-item-section side>
|
|
<q-btn
|
|
push
|
|
dense
|
|
size="md"
|
|
color="primary"
|
|
class="q-mx-lg"
|
|
icon="attach_file"
|
|
/>
|
|
</q-item-section>
|
|
|
|
<!-- comment section -->
|
|
<q-item-section
|
|
v-if="!horizontal"
|
|
top
|
|
>
|
|
<q-item-label lines="1">
|
|
{{ $t('timesheet.expense.employee_comment') }}
|
|
</q-item-label>
|
|
<q-item-label
|
|
caption
|
|
lines="1"
|
|
>
|
|
{{ expense.comment }}
|
|
</q-item-label>
|
|
</q-item-section>
|
|
|
|
<!-- supervisor comment section -->
|
|
<q-item-section
|
|
v-if="expense.supervisor_comment && !horizontal"
|
|
top
|
|
>
|
|
<q-item-label lines="1">
|
|
{{ $t('timesheet.expense.supervisor_comment') }}
|
|
</q-item-label>
|
|
<q-item-label
|
|
v-if="expense.supervisor_comment"
|
|
caption
|
|
lines="2"
|
|
>
|
|
{{ expense.supervisor_comment }}
|
|
</q-item-label>
|
|
</q-item-section>
|
|
|
|
<q-item-section
|
|
side
|
|
class="q-pa-none"
|
|
>
|
|
<q-btn
|
|
push
|
|
dense
|
|
size="xs"
|
|
color="primary"
|
|
icon="edit"
|
|
class="q-mb-xs z-top"
|
|
@click.stop="setExpenseToModify"
|
|
/>
|
|
|
|
<q-btn
|
|
push
|
|
dense
|
|
size="xs"
|
|
color="negative"
|
|
icon="close"
|
|
class="z-top"
|
|
@click.stop="requestExpenseDeletion"
|
|
/>
|
|
</q-item-section>
|
|
</q-item>
|
|
</transition>
|
|
</template> |