refactor(timesheet): add at least some updates to approved shift look, maybe more???
This commit is contained in:
parent
da93753515
commit
b307f33ab0
|
|
@ -105,7 +105,7 @@ export default defineConfig((ctx) => {
|
|||
notify: {
|
||||
color: 'primary',
|
||||
},
|
||||
dark: false,
|
||||
dark: 'auto',
|
||||
},
|
||||
|
||||
// iconSet: 'material-icons', // Quasar icon set
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
label-color="accent"
|
||||
class="rounded-5 inset-shadow bg-blue-grey-1"
|
||||
label-slot
|
||||
input-class="text-weight-medium text-h6"
|
||||
input-class="text-weight-medium text-h6 text-primary"
|
||||
>
|
||||
<template #label>
|
||||
<span class="text-weight-bolder text-uppercase text-overline"> {{ $t('login.email') }} </span>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
dense
|
||||
:stack-label="!isEditing"
|
||||
autogrow
|
||||
filled
|
||||
:standout="$q.dark.isActive ? 'bg-blue-grey-3' : 'bg-blue-grey-9'"
|
||||
debounce="500"
|
||||
label-color="accent"
|
||||
class="q-ma-xs text-uppercase"
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
v-model="model"
|
||||
dense
|
||||
:stack-label="!isEditing"
|
||||
filled
|
||||
:standout="$q.dark.isActive ? 'bg-blue-grey-3' : 'bg-blue-grey-9'"
|
||||
label-color="accent"
|
||||
class="q-ma-xs text-h6 text-uppercase"
|
||||
popup-content-class="text-weight-medium text-h6"
|
||||
|
|
|
|||
|
|
@ -11,13 +11,20 @@
|
|||
}>();
|
||||
|
||||
const date_format_options = { day: 'numeric', month: 'long', year: 'numeric', };
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="column q-mt-lg text-uppercase text-center text-weight-bolder text-h4">
|
||||
<span class="col">{{ $t(title) }}</span>
|
||||
|
||||
<transition
|
||||
enter-active-class="animated fadeInDown"
|
||||
leave-active-class="animated fadeOutDown"
|
||||
mode="out-in"
|
||||
>
|
||||
<div
|
||||
:key="startDate"
|
||||
v-if="startDate.length > 0"
|
||||
class="col row flex-center full-width q-py-none q-my-none"
|
||||
>
|
||||
|
|
@ -31,5 +38,6 @@
|
|||
{{ $d(date.extractDate(endDate, 'YYYY-MM-DD'), date_format_options) }}
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -2,15 +2,20 @@
|
|||
setup
|
||||
lang="ts"
|
||||
>
|
||||
import { date } from 'quasar';
|
||||
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 { useExpenseRules } from 'src/modules/timesheets/utils/expense.util';
|
||||
import { Expense, EXPENSE_TYPE, TYPES_WITH_AMOUNT_ONLY } from 'src/modules/timesheets/models/expense.models';
|
||||
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();
|
||||
|
||||
|
|
@ -28,25 +33,33 @@
|
|||
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: { label: string, value: ExpenseType, icon: string }[] = EXPENSE_TYPE.map(expense_type => {
|
||||
// return { label: t(`timesheet.expense.types.${expense_type}`), value: expense_type, icon: getExpenseIcon(expense_type) };
|
||||
// });
|
||||
|
||||
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;
|
||||
}
|
||||
console.log('current pay period start date: ', period_start_date.value);
|
||||
console.log('current pay period end date: ', period_end_date.value);
|
||||
};
|
||||
|
||||
const cancelUpdateMode = () => {
|
||||
expenses_store.current_expense = new Expense(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
||||
expenses_store.initial_expense = new Expense(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
||||
expenses_store.mode = 'create';
|
||||
};
|
||||
|
||||
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>
|
||||
|
|
@ -55,25 +68,30 @@
|
|||
:key="expenses_store.current_expense.id"
|
||||
flat
|
||||
@submit.prevent="requestExpenseCreationOrUpdate"
|
||||
class="full-width"
|
||||
>
|
||||
<div
|
||||
class="text-uppercase text-weight-medium q-pt-sm q-px-lg q-ma-sm"
|
||||
:class="expenses_store.mode === 'create' ? '' : 'invisible'"
|
||||
class="text-uppercase text-weight-medium q-pt-sm q-ma-sm"
|
||||
:class="expenses_store.mode === 'create' ? 'q-px-lg' : 'invisible'"
|
||||
>
|
||||
{{ $t('timesheet.expense.add_expense') }}
|
||||
</div>
|
||||
<div class="row justify-between items-start rounded-5 q-px-lg q-pb-sm">
|
||||
<div
|
||||
class="row justify-between items-start rounded-5 q-pb-sm"
|
||||
:class="expenses_store.mode === 'create' ? 'q-px-lg' : ''"
|
||||
>
|
||||
<!-- date selection input -->
|
||||
<q-input
|
||||
v-model="expenses_store.current_expense.date"
|
||||
dense
|
||||
type="date"
|
||||
outlined
|
||||
readonly
|
||||
stack-label
|
||||
color="primary"
|
||||
class="col q-px-xs"
|
||||
class="col-auto q-px-xs"
|
||||
input-class="text-weight-medium"
|
||||
input-style="font-size: 1.2em;"
|
||||
input-style="font-size: 1em;"
|
||||
:label="$t('timesheet.expense.date')"
|
||||
>
|
||||
<template #prepend>
|
||||
|
|
@ -110,12 +128,12 @@
|
|||
|
||||
<!-- expenses type selection -->
|
||||
<q-select
|
||||
v-model="expenses_store.current_expense.type"
|
||||
:options="EXPENSE_TYPE"
|
||||
v-model="expense_selected"
|
||||
standout="bg-blue-grey-9"
|
||||
dense
|
||||
emit-value
|
||||
:options="expense_options"
|
||||
hide-dropdown-icon
|
||||
stack-label
|
||||
label-slot
|
||||
class="col q-px-xs"
|
||||
color="primary"
|
||||
|
|
@ -126,7 +144,7 @@
|
|||
popup-content-class="text-uppercase text-weight-bold text-center rounded-5"
|
||||
popup-content-style="border: 2px solid var(--q-accent)"
|
||||
:rules="[rules.typeRequired]"
|
||||
:option-label="label => $t(`timesheet.expense.types.${label}`)"
|
||||
@update:model-value="option => expenses_store.current_expense.type = option.value"
|
||||
>
|
||||
<template #label>
|
||||
<span class="text-weight-bold text-accent text-uppercase text-caption">
|
||||
|
|
@ -136,13 +154,18 @@
|
|||
|
||||
<template #selected-item="scope">
|
||||
<div
|
||||
class="row flex-center text-weight-bold q-ma-none q-pa-none no-wrap ellipsis full-width"
|
||||
:class="ui_store.is_mobile_mode ? 'items-center full-height' : 'flex-center'"
|
||||
class="row items-center text-weight-bold q-ma-none q-pa-none no-wrap ellipsis full-width"
|
||||
:class="ui_store.is_mobile_mode ? 'full-height' : ''"
|
||||
:tabindex="scope.tabindex"
|
||||
>
|
||||
<q-icon
|
||||
:name="scope.opt.icon"
|
||||
size="xs"
|
||||
class="col-auto q-mx-xs"
|
||||
/>
|
||||
<span
|
||||
style="line-height: 0.9em;"
|
||||
class="col-auto ellipsis"
|
||||
style="line-height: 1em;"
|
||||
class="col-auto ellipsis text-uppercase"
|
||||
>{{ scope.opt.label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -153,16 +176,18 @@
|
|||
<q-input
|
||||
key="amount"
|
||||
v-model.number="expenses_store.current_expense.amount"
|
||||
filled
|
||||
input-class="text-right"
|
||||
standout="bg-blue-grey-9"
|
||||
dense
|
||||
stack-label
|
||||
color="primary"
|
||||
class="col q-px-xs"
|
||||
label-slot
|
||||
stack-label
|
||||
suffix="$"
|
||||
color="primary"
|
||||
class="col-auto q-px-xs"
|
||||
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">
|
||||
|
|
@ -177,7 +202,7 @@
|
|||
<q-input
|
||||
key="mileage"
|
||||
v-model.number="expenses_store.current_expense.mileage"
|
||||
filled
|
||||
standout="bg-blue-grey-9"
|
||||
input-class="text-right"
|
||||
dense
|
||||
stack-label
|
||||
|
|
@ -200,7 +225,7 @@
|
|||
<!-- employee comment input -->
|
||||
<q-input
|
||||
v-model="expenses_store.current_expense.comment"
|
||||
filled
|
||||
standout="bg-blue-grey-9"
|
||||
dense
|
||||
stack-label
|
||||
label-slot
|
||||
|
|
@ -222,8 +247,8 @@
|
|||
<!-- import attach file section -->
|
||||
<q-file
|
||||
v-model="files"
|
||||
standout="bg-blue-grey-9"
|
||||
dense
|
||||
filled
|
||||
use-chips
|
||||
multiple
|
||||
stack-label
|
||||
|
|
@ -257,7 +282,7 @@
|
|||
icon="clear"
|
||||
color="negative"
|
||||
:label="$q.screen.gt.sm ? $t('shared.label.cancel') : ''"
|
||||
@click="cancelUpdateMode"
|
||||
@click="$emit('onClickUpdateCancel')"
|
||||
/>
|
||||
|
||||
<q-btn
|
||||
|
|
@ -265,7 +290,8 @@
|
|||
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')) : ''"
|
||||
class="q-px-sm q-mb-sm q-mx-lg"
|
||||
class="q-px-sm "
|
||||
:class="expenses_store.mode === 'create' ? 'q-mr-lg q-mb-md' : 'q-mb-sm q-ml-lg'"
|
||||
type="submit"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
|
||||
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);
|
||||
|
|
@ -64,7 +63,6 @@
|
|||
: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">
|
||||
|
|
@ -72,21 +70,9 @@
|
|||
<q-item-section avatar>
|
||||
<q-icon
|
||||
:name="getExpenseIcon(expense.type)"
|
||||
:color="expense.is_approved ? 'white' : ($q.dark.isActive ? 'blue-grey-2' : 'primary')"
|
||||
:color="expense.is_approved ? 'white' : ($q.dark.isActive ? 'white' : '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 -->
|
||||
|
|
@ -110,7 +96,7 @@
|
|||
class="text-uppercase text-weight-light"
|
||||
:class="approved_class"
|
||||
>
|
||||
{{ $d(new Date(expense.date), { 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>
|
||||
|
||||
|
|
@ -185,13 +171,20 @@
|
|||
</q-item-section>
|
||||
|
||||
<q-item-section :side="$q.screen.gt.sm">
|
||||
<q-icon
|
||||
v-if="expense.is_approved"
|
||||
name="verified"
|
||||
color="white"
|
||||
size="lg"
|
||||
/>
|
||||
|
||||
<q-btn
|
||||
v-else
|
||||
flat
|
||||
size="lg"
|
||||
:icon="expense.is_approved ? 'verified' : 'close'"
|
||||
:color="expense.is_approved ? 'white' : 'negative'"
|
||||
icon="close"
|
||||
color="negative"
|
||||
class="q-pa-none z-top"
|
||||
:class="expense.is_approved ? 'no-pointer' : ''"
|
||||
@click.stop="requestExpenseDeletion"
|
||||
/>
|
||||
</q-item-section>
|
||||
|
|
@ -201,7 +194,7 @@
|
|||
@hide="expenses_store.is_hiding_create_form = false"
|
||||
:duration="200"
|
||||
>
|
||||
<ExpenseDialogForm v-if="is_showing_update_form && expenses_store.is_hiding_create_form" />
|
||||
<ExpenseDialogForm v-if="is_showing_update_form && expenses_store.is_hiding_create_form" @on-click-update-cancel="onUpdateClicked"/>
|
||||
</q-slide-transition>
|
||||
</q-item>
|
||||
</template>
|
||||
|
|
@ -3,8 +3,7 @@
|
|||
lang="ts"
|
||||
>
|
||||
/* eslint-disable*/
|
||||
import { onBeforeUnmount, onMounted, ref, toRaw, useTemplateRef } from 'vue';
|
||||
import { unwrapAndClone } from 'src/utils/unwrap-and-clone';
|
||||
import { onBeforeUnmount, onMounted, ref, useTemplateRef } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { QSelect } from 'quasar';
|
||||
import { Shift, ShiftType } from 'src/modules/timesheets/models/shift.models';
|
||||
|
|
@ -22,27 +21,26 @@
|
|||
|
||||
const COMMENT_LENGTH_MAX = 280;
|
||||
const SHIFT_OPTIONS: ShiftOption[] = [
|
||||
{ label: t('timesheet.shift.types.REGULAR'), value: 'REGULAR', icon: 'wb_sunny', icon_color: '' },
|
||||
{ label: t('timesheet.shift.types.REGULAR'), value: 'REGULAR', icon: 'wb_sunny', icon_color: 'blue-grey-3' },
|
||||
{ label: t('timesheet.shift.types.EVENING'), value: 'EVENING', icon: 'bedtime', icon_color: 'indigo-8' },
|
||||
{ label: t('timesheet.shift.types.EMERGENCY'), value: 'EMERGENCY', icon: 'ring_volume', icon_color: 'red-8' },
|
||||
{ label: t('timesheet.shift.types.VACATION'), value: 'VACATION', icon: 'beach_access', icon_color: 'yellow-8' },
|
||||
{ label: t('timesheet.shift.types.HOLIDAY'), value: 'HOLIDAY', icon: 'forest', icon_color: 'green-8' },
|
||||
{ label: t('timesheet.shift.types.SICK'), value: 'SICK', icon: 'medication_liquid', icon_color: 'cyan-8' },
|
||||
{ label: t('timesheet.shift.types.SICK'), value: 'SICK', icon: 'medication_liquid', icon_color: 'light-blue-6' },
|
||||
];
|
||||
|
||||
const shift = defineModel<Shift>('shift', { required: true });
|
||||
const { dense = false, outlined = false } = defineProps<{
|
||||
const { dense = false, hasShiftAfter = false } = defineProps<{
|
||||
dense?: boolean;
|
||||
outlined?: boolean;
|
||||
hasShiftAfter?: boolean;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
'saveComment': [comment: string, shift_id: number];
|
||||
'requestDelete': [void];
|
||||
}>();
|
||||
|
||||
const is_showing_time_picker = ref(false);
|
||||
const select_ref = useTemplateRef<QSelect>('select');
|
||||
const initial_shift = ref<Shift>(unwrapAndClone(toRaw(shift.value)))
|
||||
|
||||
let timer: NodeJS.Timeout;
|
||||
|
||||
const shift_type_selected = ref(SHIFT_OPTIONS.find(option => option.value == shift.value.type));
|
||||
|
|
@ -96,7 +94,10 @@
|
|||
<q-icon name="delete" />
|
||||
</template>
|
||||
<div :class="ui_store.is_mobile_mode ? 'column' : 'row'" >
|
||||
<div class="row items-center text-uppercase rounded-5 bg-transparent q-mb-xs" :class="ui_store.is_mobile_mode ? 'col' : 'col-4'">
|
||||
<div
|
||||
class="row items-center text-uppercase rounded-5 bg-transparent"
|
||||
:class="ui_store.is_mobile_mode ? 'col q-mb-xs' : 'col-4'"
|
||||
>
|
||||
<!-- mobile comment button -->
|
||||
<q-btn
|
||||
v-if="ui_store.is_mobile_mode && !dense"
|
||||
|
|
@ -154,8 +155,9 @@
|
|||
<q-select
|
||||
ref="select"
|
||||
v-model="shift_type_selected"
|
||||
standout="bg-blue-grey-9"
|
||||
:standout="$q.dark.isActive ? 'bg-blue-grey-3' : 'bg-blue-grey-9'"
|
||||
dense
|
||||
:borderless="shift.is_approved"
|
||||
:readonly="shift.is_approved"
|
||||
:options-dense="!ui_store.is_mobile_mode"
|
||||
hide-dropdown-icon
|
||||
|
|
@ -164,6 +166,8 @@
|
|||
menu-self="top middle"
|
||||
:options="SHIFT_OPTIONS"
|
||||
class="col rounded-5 q-mx-xs bg-dark"
|
||||
:class="shift.is_approved ? 'inset-shadow' : ''"
|
||||
:style="shift.is_approved ? 'background-color: #0002 !important;' : ''"
|
||||
popup-content-class="text-uppercase text-weight-bold text-center rounded-5"
|
||||
popup-content-style="border: 2px solid var(--q-accent)"
|
||||
@blur="onBlurShiftTypeSelect"
|
||||
|
|
@ -184,6 +188,7 @@
|
|||
<span
|
||||
style="line-height: 0.9em;"
|
||||
class="col-auto ellipsis"
|
||||
:class="shift.is_approved ? 'text-white' : ''"
|
||||
>{{ scope.opt.label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -195,15 +200,17 @@
|
|||
<q-input
|
||||
v-model="shift.start_time"
|
||||
dense
|
||||
:borderless="shift.is_approved"
|
||||
:readonly="shift.is_approved"
|
||||
type="time"
|
||||
:standout="$q.dark.isActive ? 'bg-blue-grey-9' : 'bg-blue-grey-1 text-white'"
|
||||
:standout="$q.dark.isActive ? 'bg-blue-grey-3' : 'bg-blue-grey-9'"
|
||||
label-slot
|
||||
label-color="accent"
|
||||
:input-class="'text-weight-medium ' + (shift.id === -2 ? 'text-white ' : ' ') + (shift.is_approved ? 'cursor-not-allowed' : '')"
|
||||
:label-color="shift.is_approved ? 'white' : 'accent'"
|
||||
:input-class="'text-weight-medium ' + (shift.id === -2 ? 'text-white ' : ' ') + (shift.is_approved ? 'cursor-not-allowed text-white' : '')"
|
||||
input-style="font-size: 1.2em;"
|
||||
class="col rounded-5 bg-dark"
|
||||
:class="(shift.id === -2 ? 'bg-negative ' : ' ') + (ui_store.is_mobile_mode ? 'q-mr-xs ' : 'q-mx-xs ') + (shift.is_approved ? 'cursor-not-allowed' : '')"
|
||||
:class="(shift.id === -2 ? 'bg-negative ' : ' ') + (ui_store.is_mobile_mode ? 'q-mr-xs ' : 'q-mx-xs ') + (shift.is_approved ? 'cursor-not-allowed q-px-xs transparent inset-shadow' : '')"
|
||||
:style="shift.is_approved ? 'background-color: #0002 !important;' : ''"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
|
|
@ -216,16 +223,18 @@
|
|||
<!-- punch out field -->
|
||||
<q-input
|
||||
v-model="shift.end_time"
|
||||
:standout="$q.dark.isActive ? 'bg-blue-grey-3' : 'bg-blue-grey-9'"
|
||||
dense
|
||||
:borderless="shift.is_approved"
|
||||
:readonly="shift.is_approved"
|
||||
type="time"
|
||||
standout="bg-blue-grey-9"
|
||||
label-slot
|
||||
label-color="accent"
|
||||
:input-class="'text-weight-medium ' + (shift.id === -2 ? 'text-white ' : ' ') + (shift.is_approved ? 'cursor-not-allowed' : '')"
|
||||
:label-color="shift.is_approved ? 'white' : 'accent'"
|
||||
:input-class="'text-weight-medium ' + (shift.id === -2 ? 'text-white ' : ' ') + (shift.is_approved ? 'cursor-not-allowed text-white' : '')"
|
||||
input-style="font-size: 1.2em;"
|
||||
class="col rounded-5 bg-dark"
|
||||
:class="(shift.id === -2 ? 'bg-negative ' : ' ') + (ui_store.is_mobile_mode ? 'q-ml-xs ' : 'q-mx-xs ') + (shift.is_approved ? 'cursor-not-allowed' : '')"
|
||||
:class="(shift.id === -2 ? 'bg-negative ' : ' ') + (ui_store.is_mobile_mode ? 'q-ml-xs ' : 'q-mx-xs ') + (shift.is_approved ? 'cursor-not-allowed q-px-xs transparent inset-shadow' : '')"
|
||||
:style="shift.is_approved ? 'background-color: #0002 !important;' : ''"
|
||||
>
|
||||
<template #label>
|
||||
<span
|
||||
|
|
@ -317,4 +326,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</q-slide-item>
|
||||
|
||||
<q-separator v-if="hasShiftAfter && ui_store.is_mobile_mode" spaced color="accent" class="q-mx-md"/>
|
||||
</template>
|
||||
|
|
@ -38,6 +38,7 @@
|
|||
v-model:shift="day.shifts[shift_index]!"
|
||||
:outlined="outlined"
|
||||
:dense="dense"
|
||||
:has-shift-after="shift_index < day.shifts.length - 1"
|
||||
@request-delete="deleteCurrentShift(shift)"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
setup
|
||||
lang="ts"
|
||||
>
|
||||
import { computed } from 'vue';
|
||||
import { date } from 'quasar';
|
||||
import { useUiStore } from 'src/stores/ui-store';
|
||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||
|
|
@ -15,6 +16,8 @@
|
|||
const ui_store = useUiStore();
|
||||
const timesheet_store = useTimesheetStore();
|
||||
|
||||
const animation_style = computed(() => ui_store.is_mobile_mode ? 'fadeInLeft' : 'fadeInDown' );
|
||||
|
||||
const addNewShift = (day_shifts: Shift[], date: string, timesheet_id: number) => {
|
||||
ui_store.focus_next_component = true;
|
||||
const new_shift = new Shift;
|
||||
|
|
@ -47,11 +50,16 @@
|
|||
v-for="timesheet, timesheet_index in timesheet_store.timesheets"
|
||||
:key="timesheet.timesheet_id"
|
||||
class="col column"
|
||||
>
|
||||
<transition-group
|
||||
appear
|
||||
:enter-active-class="`animated ${animation_style}`"
|
||||
>
|
||||
<div
|
||||
v-for="day, day_index in timesheet.days"
|
||||
:key="day.date"
|
||||
class="col-auto row rounded-10 q-ma-sm shadow-10"
|
||||
:style="`animation-delay: ${day_index / 15}s;`"
|
||||
>
|
||||
<div
|
||||
v-if="ui_store.is_mobile_mode"
|
||||
|
|
@ -59,7 +67,7 @@
|
|||
>
|
||||
<q-card
|
||||
class="rounded-10 bg-dark"
|
||||
:style="ui_store.is_mobile_mode ? (getDayApproval(day) ? 'border: 3px solid var(--q-accent)' : 'border: 1px solid var(--q-accent);') : ''"
|
||||
:style="ui_store.is_mobile_mode ? (getDayApproval(day) ? 'border: 6px inset var(--q-accent)' : 'border: 1px solid var(--q-accent);') : ''"
|
||||
>
|
||||
|
||||
<q-card-section
|
||||
|
|
@ -79,6 +87,7 @@
|
|||
>
|
||||
<ShiftListDay
|
||||
outlined
|
||||
:animation-delay-multiplier="day_index"
|
||||
:approved="getDayApproval(day)"
|
||||
:day="day"
|
||||
@delete-unsaved-shift="deleteUnsavedShift(timesheet_index, day_index)"
|
||||
|
|
@ -117,6 +126,8 @@
|
|||
class="col row full-width"
|
||||
:class="getDayApproval(day) ? 'rounded-10 bg-accent' : ''"
|
||||
>
|
||||
<!-- List of shifts -->
|
||||
|
||||
<div
|
||||
class="col row bg-dark"
|
||||
:class="getDayApproval(day) ? 'bg-transparent' : ''"
|
||||
|
|
@ -129,7 +140,7 @@
|
|||
class="col-auto"
|
||||
/>
|
||||
|
||||
<!-- List of shifts -->
|
||||
|
||||
<ShiftListDay
|
||||
:day="day"
|
||||
class="col"
|
||||
|
|
@ -137,6 +148,7 @@
|
|||
/>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-auto self-stretch">
|
||||
<q-icon
|
||||
v-if="getDayApproval(day)"
|
||||
|
|
@ -160,6 +172,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
>
|
||||
<q-card class="q-pa-xl rounded-200 bg-white frosted-glass">
|
||||
<q-spinner-radio
|
||||
color="primary"
|
||||
color="accent"
|
||||
size="20vh"
|
||||
/>
|
||||
</q-card>
|
||||
|
|
|
|||
|
|
@ -24,3 +24,20 @@ export const useExpenseRules = (t: (_key: string) => string) => {
|
|||
commentRequired,
|
||||
};
|
||||
};
|
||||
|
||||
export const convertToMonetaryAmount = (amount: number | string): number => {
|
||||
if (typeof amount === 'number') return Number(amount.toFixed(2));
|
||||
|
||||
if (typeof amount === 'string') {
|
||||
try {
|
||||
const single_decimal_amount = amount.replace(/\.(?=.*\.)/g, '');
|
||||
const numbers_only_decimal = single_decimal_amount.replace(/[^0-9.]/g, '');
|
||||
|
||||
return Number(numbers_only_decimal);
|
||||
} catch(error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
|
@ -25,6 +25,7 @@ export const useExpensesStore = defineStore('expenses', () => {
|
|||
|
||||
const close = () => {
|
||||
is_open.value = false;
|
||||
is_hiding_create_form.value = false;
|
||||
};
|
||||
|
||||
const upsertExpensesById = async (expense_id: number, expense: Expense): Promise<void> => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user