feat(timesheet mobile): add interfaces for expense dialog in mobile format
Added mobile versions for expense form as well as expense items.
This commit is contained in:
parent
b307f33ab0
commit
88cdb9e5ff
Binary file not shown.
|
Before Width: | Height: | Size: 2.9 MiB After Width: | Height: | Size: 242 KiB |
|
|
@ -232,7 +232,6 @@
|
|||
color="primary"
|
||||
type="text"
|
||||
class="col q-px-sm"
|
||||
:counter="true"
|
||||
:maxlength="COMMENT_MAX_LENGTH"
|
||||
lazy-rules="ondemand"
|
||||
:rules="[rules.commentRequired]"
|
||||
|
|
@ -289,7 +288,7 @@
|
|||
push
|
||||
color="accent"
|
||||
:icon="expenses_store.mode === 'update' ? 'save' : 'upload'"
|
||||
:label="$q.screen.gt.sm ? (expenses_store.mode === 'update' ? $t('shared.label.update') : $t('shared.label.add')) : ''"
|
||||
:label="expenses_store.mode === 'update' ? $t('shared.label.update') : $t('shared.label.add')"
|
||||
class="q-px-sm "
|
||||
:class="expenses_store.mode === 'create' ? 'q-mr-lg q-mb-md' : 'q-mb-sm q-ml-lg'"
|
||||
type="submit"
|
||||
|
|
|
|||
|
|
@ -48,20 +48,20 @@
|
|||
{{ $t('timesheet.expense.total_amount') }} :
|
||||
</span>
|
||||
|
||||
<q-icon
|
||||
v-else
|
||||
name="payments"
|
||||
size="sm"
|
||||
color="accent"
|
||||
class="col"
|
||||
/>
|
||||
|
||||
<span
|
||||
class="col-auto text-weight-light"
|
||||
style="font-size: 2.5em; line-height: 1em;"
|
||||
>
|
||||
{{ weekly_totals.expenses.toFixed(2) }}
|
||||
</span>
|
||||
|
||||
<q-icon
|
||||
v-if="$q.screen.lt.md"
|
||||
name="attach_money"
|
||||
size="md"
|
||||
color="accent"
|
||||
class="col q-ml-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-auto row items-center q-px-sm">
|
||||
|
|
@ -72,20 +72,20 @@
|
|||
{{ $t('timesheet.expense.total_mileage') }} :
|
||||
</span>
|
||||
|
||||
<q-icon
|
||||
v-else
|
||||
name="drive_eta"
|
||||
size="sm"
|
||||
color="accent"
|
||||
class="col"
|
||||
/>
|
||||
|
||||
<span
|
||||
class="col-auto text-weight-light"
|
||||
style="font-size: 2.5em; line-height: 1em;"
|
||||
>
|
||||
{{ weekly_totals.mileage.toFixed(1) }}
|
||||
</span>
|
||||
|
||||
<q-icon
|
||||
v-if="$q.screen.lt.md"
|
||||
name="commute"
|
||||
size="md"
|
||||
color="accent"
|
||||
class="col q-ml-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -96,7 +96,9 @@
|
|||
class="text-uppercase text-weight-light"
|
||||
:class="approved_class"
|
||||
>
|
||||
{{ $d(date.extractDate(expense.date, 'YYYY-MM-DD'), { month: 'short', day: 'numeric', weekday: 'long' }) }}
|
||||
{{ $d(date.extractDate(expense.date, 'YYYY-MM-DD'), {
|
||||
month: 'short', day: 'numeric', weekday:
|
||||
'long' }) }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
|
||||
|
|
@ -194,7 +196,10 @@
|
|||
@hide="expenses_store.is_hiding_create_form = false"
|
||||
:duration="200"
|
||||
>
|
||||
<ExpenseDialogForm v-if="is_showing_update_form && expenses_store.is_hiding_create_form" @on-click-update-cancel="onUpdateClicked"/>
|
||||
<ExpenseDialogForm
|
||||
v-if="is_showing_update_form && expenses_store.is_hiding_create_form"
|
||||
@on-click-update-cancel="onUpdateClicked"
|
||||
/>
|
||||
</q-slide-transition>
|
||||
</q-item>
|
||||
</template>
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
import { computed } from 'vue';
|
||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||
import ExpenseDialogListItem from 'src/modules/timesheets/components/expense-dialog-list-item.vue';
|
||||
import ExpenseDialogListItemMobile from 'src/modules/timesheets/components/mobile/expense-dialog-list-item-mobile.vue';
|
||||
|
||||
const timesheet_store = useTimesheetStore();
|
||||
|
||||
|
|
@ -38,14 +39,25 @@
|
|||
<q-separator spaced />
|
||||
</q-item-label>
|
||||
|
||||
<ExpenseDialogListItem
|
||||
<div
|
||||
v-for="(expense, index) in expenses_list"
|
||||
:key="index"
|
||||
v-model="expense.is_approved"
|
||||
:index="index"
|
||||
:expense="expense"
|
||||
:horizontal="horizontal"
|
||||
/>
|
||||
</q-list>
|
||||
>
|
||||
<ExpenseDialogListItemMobile
|
||||
v-if="$q.screen.lt.md"
|
||||
v-model="expense.is_approved"
|
||||
:index="index"
|
||||
:expense="expense"
|
||||
:horizontal="horizontal"
|
||||
/>
|
||||
|
||||
<ExpenseDialogListItem
|
||||
v-else
|
||||
v-model="expense.is_approved"
|
||||
:index="index"
|
||||
:expense="expense"
|
||||
:horizontal="horizontal"
|
||||
/>
|
||||
</div>
|
||||
</q-list>
|
||||
</template>
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
import { useExpensesStore } from 'src/stores/expense-store';
|
||||
import ExpenseDialogList from 'src/modules/timesheets/components/expense-dialog-list.vue';
|
||||
import ExpenseDialogForm from 'src/modules/timesheets/components/expense-dialog-form.vue';
|
||||
import ExpenseDialogFormMobile from 'src/modules/timesheets/components/mobile/expense-dialog-form-mobile.vue';
|
||||
import ExpenseDialogHeader from 'src/modules/timesheets/components/expense-dialog-header.vue';
|
||||
|
||||
const expense_store = useExpensesStore();
|
||||
|
|
@ -18,8 +19,10 @@
|
|||
transition-hide="jump-down"
|
||||
>
|
||||
<q-card
|
||||
class="q-pa-none rounded-10 shadow-10 bg-secondary"
|
||||
class="q-pa-none rounded-10 shadow-10"
|
||||
:class="$q.screen.lt.md ? ' bg-primary' : 'bg-secondary'"
|
||||
style=" min-width: 70vw;"
|
||||
:style="$q.screen.lt.md ? 'border: solid 2px var(--q-accent);' : ''"
|
||||
>
|
||||
<q-inner-loading :showing="expense_store.is_loading">
|
||||
<q-spinner size="32px" />
|
||||
|
|
@ -38,8 +41,13 @@
|
|||
|
||||
<ExpenseDialogList />
|
||||
|
||||
<q-separator v-if="$q.screen.lt.md" spaced color="accent" size="2px" class="q-mx-md" />
|
||||
|
||||
<q-slide-transition @hide="expense_store.is_hiding_create_form = true" :duration="200">
|
||||
<ExpenseDialogForm v-if="!expense_store.current_expense.is_approved && expense_store.mode !== 'update' && expense_store.is_hiding_create_form === false" />
|
||||
<div v-if="!expense_store.current_expense.is_approved && expense_store.mode !== 'update' && expense_store.is_hiding_create_form === false">
|
||||
<ExpenseDialogFormMobile v-if="$q.screen.lt.md" />
|
||||
<ExpenseDialogForm v-else/>
|
||||
</div>
|
||||
</q-slide-transition>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,317 @@
|
|||
<script
|
||||
setup
|
||||
lang="ts"
|
||||
>
|
||||
import { computed, inject, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useUiStore } from 'src/stores/ui-store';
|
||||
import { useExpensesStore } from 'src/stores/expense-store';
|
||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||
import { useExpensesApi } from 'src/modules/timesheets/composables/use-expense-api';
|
||||
import { convertToMonetaryAmount, getExpenseIcon, useExpenseRules } from 'src/modules/timesheets/utils/expense.util';
|
||||
import { type ExpenseType, TYPES_WITH_AMOUNT_ONLY } from 'src/modules/timesheets/models/expense.models';
|
||||
|
||||
interface ExpenseOption {
|
||||
label: string;
|
||||
value: ExpenseType;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const ui_store = useUiStore();
|
||||
const timesheet_store = useTimesheetStore();
|
||||
const expenses_store = useExpensesStore();
|
||||
const expenses_api = useExpensesApi();
|
||||
const files = defineModel<File[] | null>('files');
|
||||
const is_navigator_open = ref(false);
|
||||
const is_showing_comment_dialog_mobile = ref(false);
|
||||
|
||||
const COMMENT_MAX_LENGTH = 280;
|
||||
const employee_email = inject<string>('employeeEmail');
|
||||
const rules = useExpenseRules(t);
|
||||
|
||||
const period_start_date = computed(() => timesheet_store.pay_period?.period_start.replaceAll('-', '/') ?? '');
|
||||
const period_end_date = computed(() => timesheet_store.pay_period?.period_end.replaceAll('-', '/') ?? '');
|
||||
|
||||
const expense_options: ExpenseOption[] = [
|
||||
{ label: t('timesheet.expense.types.PER_DIEM'), value: 'PER_DIEM', icon: getExpenseIcon('PER_DIEM') },
|
||||
{ label: t('timesheet.expense.types.EXPENSES'), value: 'EXPENSES', icon: getExpenseIcon('EXPENSES') },
|
||||
{ label: t('timesheet.expense.types.MILEAGE'), value: 'MILEAGE', icon: getExpenseIcon('MILEAGE') },
|
||||
{ label: t('timesheet.expense.types.ON_CALL'), value: 'ON_CALL', icon: getExpenseIcon('ON_CALL') },
|
||||
]
|
||||
const expense_selected = ref(expense_options.find(expense => expense.value == expenses_store.current_expense.type));
|
||||
|
||||
const openDatePicker = () => {
|
||||
is_navigator_open.value = true;
|
||||
if (timesheet_store.pay_period !== undefined) {
|
||||
expenses_store.current_expense.date = timesheet_store.pay_period.period_start;
|
||||
}
|
||||
};
|
||||
|
||||
const requestExpenseCreationOrUpdate = async () => {
|
||||
if (expenses_store.mode === 'create') await expenses_api.createExpenseByEmployeeEmail(employee_email ?? '', expenses_store.current_expense?.date ?? '');
|
||||
else await expenses_api.updateExpenseByEmployeeEmail(employee_email ?? '', expenses_store.current_expense?.date ?? '');
|
||||
};
|
||||
|
||||
defineEmits<{
|
||||
'onClickUpdateCancel': [void];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-form
|
||||
v-if="!timesheet_store.timesheets?.every(timesheet => timesheet.is_approved)"
|
||||
:key="expenses_store.current_expense.id"
|
||||
flat
|
||||
@submit.prevent="requestExpenseCreationOrUpdate"
|
||||
class="column full-width"
|
||||
>
|
||||
<!-- header -->
|
||||
<div
|
||||
class="col text-uppercase text-weight-medium text-h6 q-ma-xs"
|
||||
:class="expenses_store.mode === 'create' ? 'q-px-md' : 'invisible'"
|
||||
>
|
||||
{{ $t('timesheet.expense.add_expense') }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="col column items-start rounded-5 q-pb-sm"
|
||||
:class="expenses_store.mode === 'create' ? 'q-px-md' : ''"
|
||||
>
|
||||
<!-- date and type row -->
|
||||
<div class="col row q-my-xs full-width">
|
||||
<!-- date selection input -->
|
||||
<q-input
|
||||
v-model="expenses_store.current_expense.date"
|
||||
dense
|
||||
type="date"
|
||||
outlined
|
||||
readonly
|
||||
stack-label
|
||||
hide-bottom-space
|
||||
color="primary"
|
||||
class="col-auto q-mr-sm"
|
||||
input-class="text-weight-medium"
|
||||
input-style="font-size: 1em;"
|
||||
:label="$t('timesheet.expense.date')"
|
||||
>
|
||||
<template #prepend>
|
||||
<q-btn
|
||||
push
|
||||
dense
|
||||
icon="event"
|
||||
color="accent"
|
||||
class="q-mr-sm"
|
||||
@click="openDatePicker"
|
||||
/>
|
||||
|
||||
<q-dialog
|
||||
v-model="is_navigator_open"
|
||||
transition-show="jump-right"
|
||||
transition-hide="jump-right"
|
||||
>
|
||||
<q-date
|
||||
v-model="expenses_store.current_expense.date"
|
||||
mask="YYYY-MM-DD"
|
||||
event-color="accent"
|
||||
:options="date => date >= period_start_date && date <= period_end_date"
|
||||
@update:model-value="is_navigator_open = false"
|
||||
/>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<template #label>
|
||||
<span class="text-weight-bold text-accent text-uppercase text-caption">
|
||||
{{ $t('timesheet.expense.date') }}
|
||||
</span>
|
||||
</template>
|
||||
</q-input>
|
||||
|
||||
<!-- expenses type selection -->
|
||||
<q-select
|
||||
v-model="expense_selected"
|
||||
standout="bg-blue-grey-9 text-white"
|
||||
dense
|
||||
:options="expense_options"
|
||||
hide-dropdown-icon
|
||||
stack-label
|
||||
label-slot
|
||||
hide-bottom-space
|
||||
class="col"
|
||||
color="primary"
|
||||
:label="$t('timesheet.expense.type')"
|
||||
:menu-offset="[0, 10]"
|
||||
menu-anchor="bottom middle"
|
||||
menu-self="top middle"
|
||||
popup-content-class="text-uppercase text-weight-bold text-center rounded-5"
|
||||
popup-content-style="border: 2px solid var(--q-accent)"
|
||||
:rules="[rules.typeRequired]"
|
||||
@update:model-value="option => expenses_store.current_expense.type = option.value"
|
||||
>
|
||||
<template #label>
|
||||
<span class="text-weight-bold text-accent text-uppercase text-caption">
|
||||
{{ $t('timesheet.expense.type') }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #selected-item="scope">
|
||||
<div
|
||||
class="row items-center text-weight-bold q-ma-none q-pa-none full-width"
|
||||
:class="ui_store.is_mobile_mode ? 'full-height' : ''"
|
||||
:tabindex="scope.tabindex"
|
||||
>
|
||||
<q-icon
|
||||
:name="scope.opt.icon"
|
||||
size="sm"
|
||||
class="col-auto q-mx-xs"
|
||||
/>
|
||||
<span class="col text-uppercase ellipsis">{{ scope.opt.label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</q-select>
|
||||
</div>
|
||||
|
||||
<!-- amount and comment row -->
|
||||
<div class="col row q-my-xs full-width">
|
||||
<!-- amount input -->
|
||||
<div class="col q-mr-sm">
|
||||
<q-input
|
||||
v-if="TYPES_WITH_AMOUNT_ONLY.includes(expenses_store.current_expense?.type ?? 'EXPENSES')"
|
||||
v-model.number="expenses_store.current_expense.amount"
|
||||
key="amount"
|
||||
standout="bg-blue-grey-9"
|
||||
dense
|
||||
label-slot
|
||||
stack-label
|
||||
hide-bottom-space
|
||||
suffix="$"
|
||||
color="primary"
|
||||
input-class="text-right text-weight-bold"
|
||||
:input-style="'font-size: 1.2em;'"
|
||||
lazy-rules="ondemand"
|
||||
:rules="[rules.amountRequired]"
|
||||
@blur="expenses_store.current_expense.amount = convertToMonetaryAmount(expenses_store.current_expense.amount)"
|
||||
>
|
||||
<template #label>
|
||||
<span class="text-weight-bold text-accent text-uppercase text-caption">
|
||||
{{ $t('timesheet.expense.amount') }}
|
||||
</span>
|
||||
</template>
|
||||
</q-input>
|
||||
|
||||
<!-- mileage input -->
|
||||
<q-input
|
||||
v-else
|
||||
v-model.number="expenses_store.current_expense.mileage"
|
||||
key="mileage"
|
||||
standout="bg-blue-grey-9"
|
||||
input-class="text-right"
|
||||
dense
|
||||
stack-label
|
||||
clearable
|
||||
hide-bottom-space
|
||||
color="primary"
|
||||
label-slot
|
||||
suffix="km"
|
||||
lazy-rules="ondemand"
|
||||
:rules="[rules.mileageRequired]"
|
||||
>
|
||||
<template #label>
|
||||
<span class="text-weight-bold text-accent text-uppercase text-caption">
|
||||
{{ $t('timesheet.expense.mileage') }}
|
||||
</span>
|
||||
</template>
|
||||
</q-input>
|
||||
</div>
|
||||
|
||||
<!-- employee comment input -->
|
||||
<q-btn
|
||||
push
|
||||
color="accent"
|
||||
:icon="expenses_store.current_expense.comment ? 'chat' : 'chat_bubble_outline'"
|
||||
@click="is_showing_comment_dialog_mobile = true"
|
||||
class="col-auto"
|
||||
/>
|
||||
|
||||
<q-dialog v-model="is_showing_comment_dialog_mobile">
|
||||
<q-card class="full-width bg-secondary rounded-10">
|
||||
<q-card-section class="q-pa-none">
|
||||
<span
|
||||
class="text-weight-bold text-accent text-uppercase text-caption"
|
||||
style="font-size: 1.5em;"
|
||||
>
|
||||
{{ $t('timesheet.expense.employee_comment') }}
|
||||
</span>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="q-pa-none bg-primary rounded-10">
|
||||
<q-input
|
||||
v-model="expenses_store.current_expense.comment"
|
||||
standout="bg-blue-grey-9"
|
||||
dense
|
||||
hide-bottom-space
|
||||
color="primary"
|
||||
type="textarea"
|
||||
:maxlength="COMMENT_MAX_LENGTH"
|
||||
lazy-rules="ondemand"
|
||||
:rules="[rules.commentRequired]"
|
||||
>
|
||||
</q-input>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</div>
|
||||
|
||||
<!-- import attach file section -->
|
||||
<q-file
|
||||
v-model="files"
|
||||
standout="bg-blue-grey-9"
|
||||
dense
|
||||
use-chips
|
||||
multiple
|
||||
stack-label
|
||||
:label="$t('timesheet.expense.hints.attach_file')"
|
||||
class="col full-width q-my-xs"
|
||||
>
|
||||
<template #prepend>
|
||||
<q-icon
|
||||
name="attach_file"
|
||||
size="sm"
|
||||
color="accent"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #label>
|
||||
<span class="text-weight-bold text-accent text-uppercase text-caption">
|
||||
{{ $t('timesheet.expense.hints.attach_file') }}
|
||||
</span>
|
||||
</template>
|
||||
</q-file>
|
||||
</div>
|
||||
<div class="col row full-width items-center">
|
||||
<q-space />
|
||||
|
||||
<q-btn
|
||||
v-if="expenses_store.mode === 'update'"
|
||||
flat
|
||||
dense
|
||||
class="col-auto"
|
||||
icon="clear"
|
||||
color="negative"
|
||||
:label="$q.screen.gt.sm ? $t('shared.label.cancel') : ''"
|
||||
@click="$emit('onClickUpdateCancel')"
|
||||
/>
|
||||
|
||||
<q-btn
|
||||
push
|
||||
color="accent"
|
||||
:icon="expenses_store.mode === 'update' ? 'save' : 'upload'"
|
||||
:label="expenses_store.mode === 'update' ? $t('shared.label.update') : $t('shared.label.add')"
|
||||
class="q-px-sm"
|
||||
:class="expenses_store.mode === 'create' ? 'q-mr-md q-mb-md' : 'q-mb-sm q-ml-lg'"
|
||||
type="submit"
|
||||
/>
|
||||
</div>
|
||||
</q-form>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
<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>
|
||||
|
|
@ -4,10 +4,10 @@
|
|||
|
||||
<template>
|
||||
<q-layout view="hHh lpR fFf">
|
||||
<q-page-container class="bg-dark">
|
||||
<q-img src="src/assets/village.png" fit="cover" position="50% 100%" class="absolute-full" />
|
||||
<q-page class="flex flex-center">
|
||||
<transition appear slow enter-active-class="animated zoomIn" leave-active-class="animated zoomOut">
|
||||
<q-page-container class="bg-secondary">
|
||||
<q-page class="column">
|
||||
<q-img src="src/assets/village.png" fit="contain" class="col absolute-bottom-right" style="opacity: 50%;" />
|
||||
<transition appear slow enter-active-class="animated zoomIn" leave-active-class="animated zoomOut" class="col absolute-center">
|
||||
<LoginConnectionPanel />
|
||||
</transition>
|
||||
</q-page>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user