targo-frontend/src/modules/timesheets/components/expenses/expense-form.vue

199 lines
6.2 KiB
Vue

<script setup lang="ts">
import { ref } from 'vue';
import type { QForm } from 'quasar';
import type { TimesheetExpense } from '../../types/expense.interfaces';
import type { ExpenseType } from '../../types/expense.types';
/* eslint-disable */
//---------------- v-models ------------------
const draft = defineModel<Partial<TimesheetExpense>>('draft');
const files = defineModel<File[] | null>('files');
const datePickerOpen = defineModel<boolean | null>('datePickerOpen', {default: false });
//------------------ Props ------------------
const {setType} = defineProps<{
type_options: { label: string; value: ExpenseType }[];
show_amount: boolean;
is_readonly: boolean;
rules: {
typeRequired: (val: unknown) => true | string;
amountRequired: (val: unknown) => true | string;
mileageRequired: (val: unknown) => true | string;
commentRequired: (val: unknown) => true | string;
commentTooLong: (val: unknown) => true | string;
};
comment_max_length: number;
setType: (val: ExpenseType) => void;
}>();
//------------------ Emits ------------------
defineEmits<{
'submit': [void];
}>();
//------------------ Exposes ------------------
const inner_form = ref<QForm | null>(null);
defineExpose({
validate: async ( force = true ) => (await inner_form.value?.validate(force)) === true,
});
//------------------ Handlers ------------------
const onTypeChange = (val: ExpenseType) => {
setType(val);
};
</script>
<template>
<q-form
ref="inner_form"
flat
v-if="!is_readonly"
@submit.prevent="$emit('submit')"
>
<div class="text-subtitle2 q-py-sm">
{{ $t('timesheet.expense.add_expense')}}
</div>
<div class="row justify-between">
<!-- date selection input -->
<q-input
v-model="draft!.date"
dense
filled
readonly
stack-label
class="col q-px-xs"
color="primary"
:label="$t('timesheet.expense.date')"
>
<template #before>
<q-btn
push
dense
icon="event"
color="primary"
@click="datePickerOpen = true"
/>
<q-dialog v-model="datePickerOpen">
<q-date
v-model="draft!.date"
@update:model-value="datePickerOpen = false"
mask="YYYY-MM-DD"
/>
</q-dialog>
</template>
</q-input>
<!-- expenses type selection -->
<q-select
v-model="draft!.type"
:options="type_options"
filled
dense
class="col q-px-xs"
color="primary"
emit-value
map-options
:label="$t('timesheet.expense.type')"
:rules="[ rules.typeRequired ]"
@update:model-value="val => setType(val as ExpenseType)"
/>
<!-- amount input -->
<template v-if="show_amount">
<q-input
key="amount"
v-model.number="draft!.amount"
filled
input-class="text-right"
dense
stack-label
clearable
color="primary"
class="col q-px-xs"
:label="$t('timesheet.expense.amount')"
suffix="$"
lazy-rules="ondemand"
:rules="[ rules.amountRequired ]"
/>
</template>
<!-- mileage input -->
<template v-else>
<q-input
key="mileage"
v-model.number="draft!.mileage"
filled
input-class="text-right"
dense
stack-label
clearable
color="primary"
class="col q-px-xs"
:label="$t('timesheet.expense.mileage')"
suffix="km"
lazy-rules="ondemand"
:rules="[ rules.mileageRequired ]"
/>
</template>
<!-- employee comment input -->
<q-input
v-model="draft!.comment"
filled
color="primary"
type="text"
class="col q-px-sm"
dense
stack-label
clearable
:counter="true"
:maxlength="comment_max_length"
lazy-rules="ondemand"
:rules="[ rules.commentRequired, rules.commentTooLong ]"
>
<template #label>
<span class="text-weight-bold ">
{{ $t('timesheet.expense.comment') }}
</span>
</template>
</q-input>
<!-- import attach file section -->
<q-file
v-model="files"
:label="$t('timesheet.expense.hints.attach_file')"
filled
use-chips
multiple
stack-label
class="col"
style="max-width: 300px;"
dense
>
<template #prepend>
<q-icon
name="attach_file"
size="sm"
color="primary"
/>
</template>
</q-file>
<!-- add btn section -->
<div>
<q-btn
push
dense
color="primary"
icon="add"
size="sm"
class="q-mt-sm q-ml-sm"
type="submit"
/>
</div>
</div>
</q-form>
</template>