refactor(timesheet): Implement refactor of select and input fields from freeswitch-ui branch

This commit is contained in:
Nic D 2026-03-10 16:42:31 -04:00
parent 1271d1eb61
commit 4ab271e66f
3 changed files with 206 additions and 112 deletions

View File

@ -0,0 +1,77 @@
<script
setup
lang="ts"
>
const model = defineModel<string | number | null | undefined>({ required: true });
const is_date_picker_open = defineModel<boolean>('isDatePickerOpen', {default: false});
defineProps<{
label?: string | undefined;
requiresDatePicker?: boolean | undefined;
maxLength?: number;
noTopPadding?: boolean;
backgroundColor?: 'bg-secondary' | 'bg-dark';
}>();
</script>
<template>
<div
class="col q-px-sm"
:class="noTopPadding ? '' : 'q-pt-md'"
>
<q-input
v-model="model"
dense
borderless
color="accent"
label-color="white"
stack-label
label-slot
no-error-icon
hide-bottom-space
:maxlength="maxLength"
class="q-px-md rounded-5 inset-shadow"
:class="$q.dark.isActive ? 'bg-primary' : (backgroundColor ?? 'bg-secondary')"
:style="`border: 1px solid var(${$q.dark.isActive ? '--q-secondary' : '--q-primary'});`"
>
<template #label>
<span
class="text-weight-bold text-uppercase q-px-md"
:class="$q.dark.isActive ? 'bg-secondary' : 'bg-primary'"
>
{{ label }}
</span>
</template>
<template #append v-if="requiresDatePicker">
<q-btn
flat
dense
size="lg"
icon="calendar_month"
color="accent"
@click="is_date_picker_open = true"
>
<q-dialog
v-model="is_date_picker_open"
backdrop-filter="none"
>
<q-date
v-model="model"
mask="YYYY-MM-DD"
color="accent"
@update:model-value="is_date_picker_open = false"
/>
</q-dialog>
</q-btn>
</template>
</q-input>
</div>
</template>
<style scoped>
:deep(.q-field--dense.q-field--float .q-field__label) {
transform: translate(-17px, -60%) scale(0.75);
border-radius: 10px 10px 10px 0px;
}
</style>

View File

@ -0,0 +1,54 @@
<script
setup
lang="ts"
>
const model = defineModel<string>({ required: true });
defineProps<{
label?: string | undefined;
options: string[];
}>();
</script>
<template>
<div class="col q-px-sm q-pt-md">
<q-select
v-model="model"
dense
borderless
color="accent"
label-color="white"
stack-label
label-slot
:options="options"
lazy-rules
no-error-icon
hide-bottom-space
options-selected-class="text-white text-bold bg-accent"
class="q-px-md rounded-5 inset-shadow"
:class="$q.dark.isActive ? 'bg-primary' : 'bg-secondary'"
popup-content-class="text-uppercase text-weight-medium rounded-5 shadow-12 z-top"
popup-content-style="border: 1px solid var(--q-primary)"
menu-anchor="bottom middle"
menu-self="top middle"
:menu-offset="[0, 5]"
:style="`border: 1px solid var(${$q.dark.isActive ? '--q-secondary' : '--q-primary'});`"
>
<template #label>
<span
class="text-weight-medium text-uppercase q-px-sm no-pointer-events"
:class="$q.dark.isActive ? 'bg-secondary' : 'bg-primary'"
>
{{ label }}
</span>
</template>
</q-select>
</div>
</template>
<style scoped>
:deep(.q-field--dense.q-field--float .q-field__label) {
transform: translate(-17px, -60%) scale(0.75) !important;
border-radius: 10px 10px 10px 0px;
}
</style>

View File

@ -2,6 +2,8 @@
setup setup
lang="ts" lang="ts"
> >
import TargoInput from 'src/modules/shared/components/targo-input.vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, ref } from 'vue';
import { useUiStore } from 'src/stores/ui-store'; import { useUiStore } from 'src/stores/ui-store';
@ -90,29 +92,17 @@
@submit.prevent="requestExpenseCreationOrUpdate" @submit.prevent="requestExpenseCreationOrUpdate"
> >
<div <div
class="row justify-between items-start rounded-5 q-pb-sm" class="row justify-between rounded-5 q-pb-sm"
:class="expenseStore.mode === 'create' ? 'q-px-lg' : ''" :class="expenseStore.mode === 'create' ? 'q-px-lg' : ''"
> >
<!-- date selection input --> <!-- date selection input -->
<div class="col q-px-xs"> <div class="row col items-center">
<q-input
v-model="expenseStore.current_expense.date"
dense
standout
readonly
stack-label
color="primary"
input-class="text-weight-medium"
input-style="font-size: 1em;"
:label="$t('timesheet.expense.date')"
>
<template #prepend>
<q-btn <q-btn
push push
dense dense
icon="event" icon="event"
color="accent" color="accent"
class="q-mr-sm" class="col-auto"
@click="openDatePicker" @click="openDatePicker"
/> />
@ -130,39 +120,48 @@
@update:model-value="closeDatePicker" @update:model-value="closeDatePicker"
/> />
</q-dialog> </q-dialog>
</template>
<template #label> <TargoInput
<span class="text-weight-bold text-accent text-uppercase text-caption"> v-model="expenseStore.current_expense.date"
{{ $t('timesheet.expense.date') }} no-top-padding
</span> :label="$t('timesheet.expense.date')"
</template> background-color="bg-dark"
</q-input> class="col"
/>
</div> </div>
<!-- expenses type selection --> <!-- expenses type selection -->
<div class="col q-px-xs"> <div class="col">
<q-select <q-select
v-model="expenseSelected" v-model="expenseSelected"
standout
dense dense
:options="expenseOptions" borderless
hide-dropdown-icon color="accent"
label-color="white"
stack-label stack-label
label-slot label-slot
color="primary" :options="expenseOptions"
:label="$t('timesheet.expense.type')" hide-dropdown-icon
:menu-offset="[0, 10]" lazy-rules
no-error-icon
hide-bottom-space
options-selected-class="text-white text-bold bg-accent"
class="q-px-md rounded-5 inset-shadow"
:class="$q.dark.isActive ? 'bg-primary' : 'bg-dark'"
popup-content-class="text-uppercase text-weight-medium rounded-5 shadow-12 z-top"
popup-content-style="border: 1px solid var(--q-primary);"
menu-anchor="bottom middle" menu-anchor="bottom middle"
menu-self="top middle" menu-self="top middle"
popup-content-class="text-uppercase text-weight-bold text-center rounded-5 z-top" :menu-offset="[0, 5]"
options-selected-class="text-weight-bolder text-white bg-accent" :style="`border: 1px solid var(${$q.dark.isActive ? '--q-secondary' : '--q-primary'});`"
popup-content-style="border: 2px solid var(--q-accent)"
:rules="[rules.typeRequired]" :rules="[rules.typeRequired]"
@update:model-value="option => expenseStore.current_expense.type = option.value" @update:model-value="option => expenseStore.current_expense.type = option.value"
> >
<template #label> <template #label>
<span class="text-weight-bold text-accent text-uppercase text-caption"> <span
class="text-weight-medium text-uppercase q-px-sm no-pointer-events"
:class="$q.dark.isActive ? 'bg-secondary' : 'bg-primary'"
>
{{ $t('timesheet.expense.type') }} {{ $t('timesheet.expense.type') }}
</span> </span>
</template> </template>
@ -189,72 +188,32 @@
<!-- amount input --> <!-- amount input -->
<div class="col q-px-xs"> <div class="col q-px-xs">
<q-input <TargoInput
v-if="TYPES_WITH_AMOUNT_ONLY.includes(expenseStore.current_expense?.type ?? 'EXPENSES')" v-if="TYPES_WITH_AMOUNT_ONLY.includes(expenseStore.current_expense?.type ?? 'EXPENSES')"
v-model.number="expenseStore.current_expense.amount" v-model.number="expenseStore.current_expense.amount"
standout no-top-padding
dense background-color="bg-dark"
label-slot :label="$t('timesheet.expense.amount')"
stack-label />
suffix="$"
type="number"
color="primary"
input-class="text-right text-weight-medium"
input-style="font-size: 1.3em;"
lazy-rules="ondemand"
:rules="[rules.amountRequired]"
>
<template #label>
<span class="text-weight-bold text-accent text-uppercase text-caption">
{{ $t('timesheet.expense.amount') }}
</span>
</template>
</q-input>
<q-input <TargoInput
v-else v-else
v-model="expenseStore.current_expense.mileage" v-model="expenseStore.current_expense.mileage"
standout no-top-padding
dense background-color="bg-dark"
label-slot :label="$t('timesheet.expense.mileage')"
stack-label />
suffix="km"
type="number"
input-class="text-right text-weight-medium"
input-style="font-size: 1.3em;"
color="primary"
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> </div>
<!-- employee comment input --> <!-- employee comment input -->
<div class="col q-px-xs"> <div class="col q-px-xs">
<q-input <TargoInput
v-model="expenseStore.current_expense.comment" v-model="expenseStore.current_expense.comment"
standout no-top-padding
dense background-color="bg-dark"
stack-label :max-length="COMMENT_MAX_LENGTH"
label-slot :label="$t('timesheet.expense.employee_comment')"
color="primary" />
input-class="text-weight-medium"
input-style="font-size: 1.3em;"
:maxlength="COMMENT_MAX_LENGTH"
lazy-rules="ondemand"
:rules="[rules.commentRequired]"
>
<template #label>
<span class="text-weight-bold text-accent text-uppercase text-caption">
{{ $t('timesheet.expense.employee_comment') }}
</span>
</template>
</q-input>
</div> </div>
<!-- import attach file section --> <!-- import attach file section -->
@ -303,8 +262,12 @@
</div> </div>
</template> </template>
<style scoped> <style
:deep(.q-field--standout.q-field--readonly .q-field__control::before) { scoped
border: transparent; lang="css"
>
:deep(.q-field--dense.q-field--float .q-field__label) {
transform: translate(-17px, -60%) scale(0.75) !important;
border-radius: 10px 10px 10px 0px;
} }
</style> </style>