targo-frontend/src/modules/timesheets/components/mobile/expense-dialog-list-item-mobile.vue
Nicolas Drolet 88cdb9e5ff feat(timesheet mobile): add interfaces for expense dialog in mobile format
Added mobile versions for expense form as well as expense items.
2025-11-17 12:06:30 -05:00

150 lines
5.9 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 { Expense } from 'src/modules/timesheets/models/expense.models';
import ExpenseDialogFormMobile from 'src/modules/timesheets/components/mobile/expense-dialog-form-mobile.vue';
const { expense, horizontal = false } = defineProps<{
expense: Expense;
index: number;
horizontal?: boolean;
}>();
const expenses_store = useExpensesStore();
const expenses_api = useExpensesApi();
const refresh_key = ref(1);
const background_class = computed(() => deepEqual(expense, expenses_store.current_expense) ? '' : '');
const approved_class = computed(() => expense.is_approved ? ' bg-accent text-white' : '')
const is_showing_update_form = ref(false);
const requestExpenseDeletion = async () => {
await expenses_api.deleteExpenseById(expense.id);
}
const onUpdateClicked = () => {
if (expense.is_approved) return;
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>
<div class="column bg-dark rounded-5 q-my-sm full-width">
<q-slide-item
right-color="negative"
class="rounded-5 bg-dark full-width"
@right="requestExpenseDeletion"
>
<template
#right
v-if="$q.screen.lt.md && !expenses_store.is_hiding_create_form && !expense.is_approved"
>
<q-icon name="delete" />
</template>
<q-item
:key="refresh_key"
clickable
class="row q-py-none q-pa-xs rounded-5 full-width"
:class="background_class + approved_class"
@click="onUpdateClicked"
>
<div class="column col">
<!-- date label -->
<div class="col-auto row items-center q-pl-xs">
<q-icon
name="calendar_month"
size="sm"
class="col-auto"
/>
<span
class="col text-uppercase text-weight-light full-width q-pl-sm text-h6"
:class="approved_class"
>
{{ $d(
date.extractDate(expense.date, 'YYYY-MM-DD'),
{ month: 'long', day: 'numeric' }
) }}
</span>
</div>
<div class="col row full-width items-center">
<!-- avatar type icon section -->
<q-icon
:name="getExpenseIcon(expense.type)"
:color="expense.is_approved ? 'white' : ($q.dark.isActive ? 'white' : 'primary')"
size="lg"
/>
<!-- amount or mileage section -->
<q-item-section class="col text-weight-bold text-h6">
<q-item-label v-if="expense.type === 'MILEAGE'">
{{ expense.mileage?.toFixed(1) }} km
</q-item-label>
<q-item-label v-else>
$ {{ expense.amount.toFixed(2) }}
</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>
</div>
</div>
<div
class="col-auto q-px-sm"
:class="expense.is_approved ? '' : 'invisible'"
>
<q-icon
v-if="expense.is_approved"
name="verified"
color="white"
size="lg"
class="full-height"
/>
</div>
</q-item>
</q-slide-item>
<q-slide-transition
@hide="expenses_store.is_hiding_create_form = false"
:duration="200"
>
<ExpenseDialogFormMobile
v-if="is_showing_update_form && expenses_store.is_hiding_create_form"
class="q-mt-sm q-pa-sm"
@on-click-update-cancel="onUpdateClicked"
/>
</q-slide-transition>
</div>
</template>