targo-frontend/src/modules/timesheets/components/expense-dialog-list-item.vue

207 lines
8.0 KiB
Vue

<script
setup
lang="ts"
>
import { date } from 'quasar';
import { computed, ref } from 'vue';
import { unwrapAndClone } from 'src/utils/unwrap-and-clone';
import { deepEqual } from 'src/utils/deep-equal';
import { useExpensesApi } from 'src/modules/timesheets/composables/use-expense-api';
import { useExpensesStore } from 'src/stores/expense-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 { Expense } from 'src/modules/timesheets/models/expense.models';
import ExpenseDialogForm from 'src/modules/timesheets/components/expense-dialog-form.vue';
const { expense, horizontal = false } = defineProps<{
expense: Expense;
index: number;
horizontal?: boolean;
}>();
const is_approved = defineModel<boolean>({ required: true });
const expenses_store = useExpensesStore();
const auth_store = useAuthStore();
const expenses_api = useExpensesApi();
const refresh_key = ref(1);
const background_class = computed(() => deepEqual(expense, expenses_store.current_expense) ? '' : '');
const background_style = computed(() => deepEqual(expense, expenses_store.current_expense) ? 'border: 3px solid var(--q-accent);' : '');
const approved_class = computed(() => expense.is_approved ? ' bg-accent text-white' : '')
const is_authorized_to_approve = computed(() => CAN_APPROVE_PAY_PERIODS.includes(auth_store.user?.role ?? 'GUEST'))
const is_showing_update_form = ref(false);
const requestExpenseDeletion = async () => {
await expenses_api.deleteExpenseById(expense.id);
}
const onExpenseClicked = () => {
if (is_authorized_to_approve.value) {
is_approved.value = !is_approved.value;
refresh_key.value += 1;
}
}
const onUpdateClicked = () => {
if (deepEqual(expense, expenses_store.current_expense)) {
expenses_store.mode = 'create';
expenses_store.current_expense = new Expense(date.formatDate(new Date(), 'YYYY-MM-DD'));
is_showing_update_form.value = false;
return;
}
expenses_store.mode = 'update';
expenses_store.current_expense = expense;
expenses_store.initial_expense = unwrapAndClone(expense);
is_showing_update_form.value = true;
}
</script>
<template>
<q-item
:key="refresh_key"
:clickable="horizontal"
class="column col-4 items-center q-my-sm q-py-none shadow-3 rounded-5 bg-dark"
:class="background_class + approved_class"
:style="background_style"
@click="onExpenseClicked"
>
<div class="row full-width items-center">
<!-- avatar type icon section -->
<q-item-section avatar>
<q-icon
:name="getExpenseIcon(expense.type)"
:color="expense.is_approved ? 'white' : ($q.dark.isActive ? 'blue-grey-2' : 'primary')"
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 ? 'white' : ($q.dark.isActive ? 'blue-grey-2' : 'primary')"
/>
</q-badge>
</q-icon>
</q-item-section>
<!-- amount or mileage section -->
<q-item-section class="col col-md-2 text-weight-bold">
<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"
class="text-uppercase text-weight-light"
:class="approved_class"
>
{{ $d(new Date(expense.date), { month: 'short', day: 'numeric', weekday: 'long' }) }}
</q-item-label>
</q-item-section>
<q-space v-if="horizontal" />
<!-- attachment file icon -->
<q-item-section avatar>
<q-btn
push
:color="expense.is_approved ? 'white' : 'accent'"
:text-color="expense.is_approved ? 'accent' : 'white'"
class="col-auto q-mx-sm q-px-sm q-pb-sm"
icon="attach_file"
/>
</q-item-section>
<q-item-label class="col text-weight-light text-caption">
<span>attachment_goes_here.jpg</span>
</q-item-label>
<!-- comment section -->
<q-item-section
v-if="!horizontal"
top
>
<q-item-label
lines="1"
class="text-weight-medium text-uppercase"
>
{{ $t('timesheet.expense.employee_comment') }}
</q-item-label>
<q-item-label
caption
lines="1"
:class="approved_class"
>
{{ expense.comment }}
</q-item-label>
</q-item-section>
<!-- supervisor comment section -->
<q-item-section
v-if="is_authorized_to_approve"
top
>
<q-item-label
lines="1"
class="text-weight-medium text-uppercase"
>
{{ $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="$q.screen.gt.sm">
<q-btn
flat
size="lg"
icon="edit"
color="accent"
:disable="expense.is_approved"
class="q-pa-none z-top"
:class="expense.is_approved ? 'invisible no-pointer' : ''"
@click.stop="onUpdateClicked"
/>
</q-item-section>
<q-item-section :side="$q.screen.gt.sm">
<q-btn
flat
size="lg"
:icon="expense.is_approved ? 'verified' : 'close'"
:color="expense.is_approved ? 'white' : 'negative'"
class="q-pa-none z-top"
:class="expense.is_approved ? 'no-pointer' : ''"
@click.stop="requestExpenseDeletion"
/>
</q-item-section>
</div>
<q-slide-transition
@hide="expenses_store.is_hiding_create_form = false"
:duration="200"
>
<ExpenseDialogForm v-if="is_showing_update_form && expenses_store.is_hiding_create_form" />
</q-slide-transition>
</q-item>
</template>