fix(timesheet): fix issue with expense not updating properly in approval module
Also rework expense item appearance in list to better divide space between components for visual clarity.
This commit is contained in:
parent
c6187305d9
commit
1271d1eb61
|
|
@ -66,10 +66,13 @@ export default defineConfig((ctx) => {
|
||||||
// polyfillModulePreload: true,
|
// polyfillModulePreload: true,
|
||||||
// distDir
|
// distDir
|
||||||
|
|
||||||
extendViteConf: (_config) => ({
|
extendViteConf: (config) => ({
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
exclude: ['tesseract.js']
|
exclude: ['tesseract.js']
|
||||||
}
|
},
|
||||||
|
define: {
|
||||||
|
__VUE_PROD_DEVTOOLS__: config.mode !== 'production'
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
// viteVuePluginOptions: {},
|
// viteVuePluginOptions: {},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,21 @@
|
||||||
setup
|
setup
|
||||||
lang="ts"
|
lang="ts"
|
||||||
>
|
>
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import { computed, ref } from 'vue';
|
|
||||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
|
||||||
import DetailsDialogChartHoursWorked from 'src/modules/timesheet-approval/components/details-dialog-chart-hours-worked.vue';
|
import DetailsDialogChartHoursWorked from 'src/modules/timesheet-approval/components/details-dialog-chart-hours-worked.vue';
|
||||||
import DetailsDialogChartShiftTypes from 'src/modules/timesheet-approval/components/details-dialog-chart-shift-types.vue';
|
import DetailsDialogChartShiftTypes from 'src/modules/timesheet-approval/components/details-dialog-chart-shift-types.vue';
|
||||||
import DetailsDialogChartExpenses from 'src/modules/timesheet-approval/components/details-dialog-chart-expenses.vue';
|
import DetailsDialogChartExpenses from 'src/modules/timesheet-approval/components/details-dialog-chart-expenses.vue';
|
||||||
import TimesheetWrapper from 'src/modules/timesheets/components/timesheet-wrapper.vue';
|
import TimesheetWrapper from 'src/modules/timesheets/components/timesheet-wrapper.vue';
|
||||||
import ExpenseDialogList from 'src/modules/timesheets/components/expense-dialog-list.vue';
|
import ExpenseDialogList from 'src/modules/timesheets/components/expense-dialog-list.vue';
|
||||||
import ExpenseDialogForm from 'src/modules/timesheets/components/expense-dialog-form.vue';
|
import ExpenseDialogForm from 'src/modules/timesheets/components/expense-dialog-form.vue';
|
||||||
|
|
||||||
|
import { date } from 'quasar';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||||
import { useTimesheetApprovalApi } from '../composables/use-timesheet-approval-api';
|
import { useTimesheetApprovalApi } from '../composables/use-timesheet-approval-api';
|
||||||
import { useShiftApi } from 'src/modules/timesheets/composables/use-shift-api';
|
import { useShiftApi } from 'src/modules/timesheets/composables/use-shift-api';
|
||||||
import { useExpensesStore } from 'src/stores/expense-store';
|
import { useExpensesStore } from 'src/stores/expense-store';
|
||||||
import { Expense } from 'src/modules/timesheets/models/expense.models';
|
import { Expense } from 'src/modules/timesheets/models/expense.models';
|
||||||
import { date } from 'quasar';
|
|
||||||
|
|
||||||
// ========== state ========================================
|
// ========== state ========================================
|
||||||
|
|
||||||
|
|
@ -25,6 +26,7 @@
|
||||||
const timesheetApprovalApi = useTimesheetApprovalApi();
|
const timesheetApprovalApi = useTimesheetApprovalApi();
|
||||||
const shiftApi = useShiftApi();
|
const shiftApi = useShiftApi();
|
||||||
const isDialogOpen = ref(false);
|
const isDialogOpen = ref(false);
|
||||||
|
const refreshKey = ref(0);
|
||||||
|
|
||||||
// ========== computed ========================================
|
// ========== computed ========================================
|
||||||
|
|
||||||
|
|
@ -60,13 +62,22 @@
|
||||||
expenseStore.is_showing_create_form = false;
|
expenseStore.is_showing_create_form = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const onClickExpenseCreate = () => {
|
const onClickNewExpense = () => {
|
||||||
expenseStore.mode = 'create';
|
expenseStore.mode = 'create';
|
||||||
if (timesheetStore.pay_period)
|
if (timesheetStore.pay_period)
|
||||||
expenseStore.current_expense = new Expense(timesheetStore.pay_period.period_start);
|
expenseStore.current_expense = new Expense(timesheetStore.pay_period.period_start);
|
||||||
else
|
else
|
||||||
expenseStore.current_expense = new Expense(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
expenseStore.current_expense = new Expense(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onClickSaveNewExpense = () => {
|
||||||
|
expenseStore.is_showing_create_form = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onShowDetailsDialog = () => {
|
||||||
|
isDialogOpen.value = true;
|
||||||
|
expenseStore.is_showing_create_form = false;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -77,7 +88,7 @@
|
||||||
transition-show="jump-down"
|
transition-show="jump-down"
|
||||||
transition-hide="jump-down"
|
transition-hide="jump-down"
|
||||||
backdrop-filter="blur(6px)"
|
backdrop-filter="blur(6px)"
|
||||||
@show="isDialogOpen = true"
|
@show="onShowDetailsDialog"
|
||||||
@hide="isDialogOpen = false"
|
@hide="isDialogOpen = false"
|
||||||
@before-hide="timesheetStore.getTimesheetOverviews"
|
@before-hide="timesheetStore.getTimesheetOverviews"
|
||||||
>
|
>
|
||||||
|
|
@ -154,7 +165,10 @@
|
||||||
class="q-mx-md"
|
class="q-mx-md"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ExpenseDialogList mode="approval" />
|
<ExpenseDialogList
|
||||||
|
mode="approval"
|
||||||
|
:key="refreshKey + 1"
|
||||||
|
/>
|
||||||
|
|
||||||
<q-expansion-item
|
<q-expansion-item
|
||||||
v-if="!isApproved"
|
v-if="!isApproved"
|
||||||
|
|
@ -162,7 +176,7 @@
|
||||||
hide-expand-icon
|
hide-expand-icon
|
||||||
:dense="!$q.platform.is.mobile"
|
:dense="!$q.platform.is.mobile"
|
||||||
group="expenses"
|
group="expenses"
|
||||||
@show="onClickExpenseCreate()"
|
@show="onClickNewExpense()"
|
||||||
header-class="bg-accent text-white q-mx-md rounded-5"
|
header-class="bg-accent text-white q-mx-md rounded-5"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
|
|
@ -180,7 +194,11 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<ExpenseDialogForm :email="timesheetStore.current_pay_period_overview?.email"/>
|
<ExpenseDialogForm
|
||||||
|
:email="timesheetStore.current_pay_period_overview?.email"
|
||||||
|
:key="refreshKey"
|
||||||
|
@click-save="onClickSaveNewExpense"
|
||||||
|
/>
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
|
|
||||||
<q-separator
|
<q-separator
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ watch(selected_company, (company) => {
|
||||||
left-label
|
left-label
|
||||||
color="white"
|
color="white"
|
||||||
dense
|
dense
|
||||||
:label="$t(company.label)"
|
:label="company.label"
|
||||||
:val="company.value"
|
:val="company.value"
|
||||||
checked-icon="radio_button_checked"
|
checked-icon="radio_button_checked"
|
||||||
unchecked-icon="radio_button_unchecked"
|
unchecked-icon="radio_button_unchecked"
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,14 @@
|
||||||
setup
|
setup
|
||||||
lang="ts"
|
lang="ts"
|
||||||
>
|
>
|
||||||
import { date } from 'quasar';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { computed, inject, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
import { useUiStore } from 'src/stores/ui-store';
|
import { useUiStore } from 'src/stores/ui-store';
|
||||||
import { useExpensesStore } from 'src/stores/expense-store';
|
import { useExpensesStore } from 'src/stores/expense-store';
|
||||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||||
import { useExpensesApi } from 'src/modules/timesheets/composables/use-expense-api';
|
import { useExpensesApi } from 'src/modules/timesheets/composables/use-expense-api';
|
||||||
import { getExpenseIcon, useExpenseRules } from 'src/modules/timesheets/utils/expense.util';
|
import { getExpenseIcon, useExpenseRules } from 'src/modules/timesheets/utils/expense.util';
|
||||||
import { Expense, type ExpenseOption, TYPES_WITH_AMOUNT_ONLY } from 'src/modules/timesheets/models/expense.models';
|
import { Expense, type ExpenseOption, TYPES_WITH_AMOUNT_ONLY } from 'src/modules/timesheets/models/expense.models';
|
||||||
import { useAuthStore } from 'src/stores/auth-store';
|
|
||||||
|
|
||||||
// ================= state ======================
|
// ================= state ======================
|
||||||
|
|
||||||
|
|
@ -19,90 +17,86 @@
|
||||||
|
|
||||||
const expense = defineModel<Expense>({ default: new Expense(new Date().toISOString().slice(0, 10)) })
|
const expense = defineModel<Expense>({ default: new Expense(new Date().toISOString().slice(0, 10)) })
|
||||||
const file = defineModel<File>('file');
|
const file = defineModel<File>('file');
|
||||||
|
|
||||||
const { email } = defineProps<{
|
const { email } = defineProps<{
|
||||||
email?: string | undefined;
|
email?: string | undefined;
|
||||||
}>();
|
}>();
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'clickSave': [void];
|
||||||
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const ui_store = useUiStore();
|
const ui_store = useUiStore();
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheetStore = useTimesheetStore();
|
||||||
const expenses_store = useExpensesStore();
|
const expenseStore = useExpensesStore();
|
||||||
const auth_store = useAuthStore();
|
const expensesApi = useExpensesApi();
|
||||||
const expenses_api = useExpensesApi();
|
const isNavigatorOpen = ref(false);
|
||||||
const is_navigator_open = ref(false);
|
|
||||||
const rules = useExpenseRules(t);
|
const rules = useExpenseRules(t);
|
||||||
|
|
||||||
|
|
||||||
const expense_options: ExpenseOption[] = [
|
const expenseOptions: 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.EXPENSES'), value: 'EXPENSES', icon: getExpenseIcon('EXPENSES') },
|
||||||
|
{ label: t('timesheet.expense.types.PER_DIEM'), value: 'PER_DIEM', icon: getExpenseIcon('PER_DIEM') },
|
||||||
{ label: t('timesheet.expense.types.MILEAGE'), value: 'MILEAGE', icon: getExpenseIcon('MILEAGE') },
|
{ 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') },
|
{ label: t('timesheet.expense.types.ON_CALL'), value: 'ON_CALL', icon: getExpenseIcon('ON_CALL') },
|
||||||
]
|
]
|
||||||
const expense_selected = ref<ExpenseOption | undefined>();
|
const expenseSelected = ref<ExpenseOption | undefined>();
|
||||||
const employeeEmail = inject<string>('employeeEmail');
|
|
||||||
|
|
||||||
// ================== computed ===================
|
// ================== computed ===================
|
||||||
|
|
||||||
const period_start_date = computed(() => timesheet_store.pay_period?.period_start.replaceAll('-', '/') ?? '');
|
const period_start_date = computed(() => timesheetStore.pay_period?.period_start.replaceAll('-', '/') ?? '');
|
||||||
const period_end_date = computed(() => timesheet_store.pay_period?.period_end.replaceAll('-', '/') ?? '');
|
const period_end_date = computed(() => timesheetStore.pay_period?.period_end.replaceAll('-', '/') ?? '');
|
||||||
|
const isSaveDisabled = computed(() =>
|
||||||
|
JSON.stringify(expenseStore.current_expense) === JSON.stringify(expenseStore.initial_expense)
|
||||||
|
);
|
||||||
|
|
||||||
// ==================== method =======================
|
// ==================== method =======================
|
||||||
|
|
||||||
const openDatePicker = () => {
|
const openDatePicker = () => {
|
||||||
is_navigator_open.value = true;
|
isNavigatorOpen.value = true;
|
||||||
if (expenses_store.current_expense.date === undefined) {
|
if (expenseStore.current_expense.date === undefined) {
|
||||||
expenses_store.current_expense.date = timesheet_store.pay_period?.period_start ?? '';
|
expenseStore.current_expense.date = timesheetStore.pay_period?.period_start ?? '';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeDatePicker = (date: string) => {
|
const closeDatePicker = (date: string) => {
|
||||||
is_navigator_open.value = false;
|
isNavigatorOpen.value = false;
|
||||||
expenses_store.current_expense.date = date;
|
expenseStore.current_expense.date = date;
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestExpenseCreationOrUpdate = async () => {
|
const requestExpenseCreationOrUpdate = async () => {
|
||||||
if (file.value)
|
const success = await expensesApi.upsertExpense(expenseStore.current_expense, email, file.value);
|
||||||
await expenses_api.upsertExpense(
|
|
||||||
expenses_store.current_expense,
|
|
||||||
email ?? employeeEmail ?? auth_store.user?.email ?? 'MISSING_EMAIL',
|
|
||||||
file.value
|
|
||||||
);
|
|
||||||
else
|
|
||||||
await expenses_api.upsertExpense(
|
|
||||||
expenses_store.current_expense,
|
|
||||||
email ?? employeeEmail ?? auth_store.user?.email ?? 'MISSING_EMAIL'
|
|
||||||
);
|
|
||||||
|
|
||||||
expenses_store.is_showing_create_form = true;
|
if (success) {
|
||||||
expenses_store.mode = 'create';
|
expenseStore.is_showing_create_form = false;
|
||||||
expenses_store.current_expense = new Expense(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
emit('clickSave');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (expense.value)
|
if (expense.value)
|
||||||
expense_selected.value = expense_options.find(expense_option => expense_option.value === expense.value.type);
|
expenseSelected.value = expenseOptions.find(expense_option => expense_option.value === expense.value.type);
|
||||||
else
|
else
|
||||||
expense_selected.value = expense_options[1];
|
expenseSelected.value = expenseOptions[0];
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<div
|
||||||
|
v-if="!expenseStore.current_expense.is_approved"
|
||||||
|
class="full-width q-mt-md q-px-md"
|
||||||
|
>
|
||||||
<q-form
|
<q-form
|
||||||
v-if="!expenses_store.current_expense.is_approved"
|
|
||||||
flat
|
flat
|
||||||
@submit.prevent="requestExpenseCreationOrUpdate"
|
@submit.prevent="requestExpenseCreationOrUpdate"
|
||||||
class="full-width q-mt-md q-px-md"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="row justify-between items-start rounded-5 q-pb-sm"
|
class="row justify-between items-start rounded-5 q-pb-sm"
|
||||||
:class="expenses_store.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="col q-px-xs">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="expenses_store.current_expense.date"
|
v-model="expenseStore.current_expense.date"
|
||||||
dense
|
dense
|
||||||
standout
|
standout
|
||||||
readonly
|
readonly
|
||||||
|
|
@ -123,13 +117,13 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-dialog
|
<q-dialog
|
||||||
v-model="is_navigator_open"
|
v-model="isNavigatorOpen"
|
||||||
transition-show="jump-right"
|
transition-show="jump-right"
|
||||||
transition-hide="jump-right"
|
transition-hide="jump-right"
|
||||||
class="z-top"
|
class="z-top"
|
||||||
>
|
>
|
||||||
<q-date
|
<q-date
|
||||||
v-model="expenses_store.current_expense.date"
|
v-model="expenseStore.current_expense.date"
|
||||||
mask="YYYY-MM-DD"
|
mask="YYYY-MM-DD"
|
||||||
event-color="accent"
|
event-color="accent"
|
||||||
:options="date => date >= period_start_date && date <= period_end_date"
|
:options="date => date >= period_start_date && date <= period_end_date"
|
||||||
|
|
@ -149,10 +143,10 @@
|
||||||
<!-- expenses type selection -->
|
<!-- expenses type selection -->
|
||||||
<div class="col q-px-xs">
|
<div class="col q-px-xs">
|
||||||
<q-select
|
<q-select
|
||||||
v-model="expense_selected"
|
v-model="expenseSelected"
|
||||||
standout
|
standout
|
||||||
dense
|
dense
|
||||||
:options="expense_options"
|
:options="expenseOptions"
|
||||||
hide-dropdown-icon
|
hide-dropdown-icon
|
||||||
stack-label
|
stack-label
|
||||||
label-slot
|
label-slot
|
||||||
|
|
@ -165,7 +159,7 @@
|
||||||
options-selected-class="text-weight-bolder text-white bg-accent"
|
options-selected-class="text-weight-bolder text-white bg-accent"
|
||||||
popup-content-style="border: 2px solid var(--q-accent)"
|
popup-content-style="border: 2px solid var(--q-accent)"
|
||||||
:rules="[rules.typeRequired]"
|
:rules="[rules.typeRequired]"
|
||||||
@update:model-value="option => expenses_store.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-bold text-accent text-uppercase text-caption">
|
||||||
|
|
@ -196,8 +190,8 @@
|
||||||
<!-- amount input -->
|
<!-- amount input -->
|
||||||
<div class="col q-px-xs">
|
<div class="col q-px-xs">
|
||||||
<q-input
|
<q-input
|
||||||
v-if="TYPES_WITH_AMOUNT_ONLY.includes(expenses_store.current_expense?.type ?? 'EXPENSES')"
|
v-if="TYPES_WITH_AMOUNT_ONLY.includes(expenseStore.current_expense?.type ?? 'EXPENSES')"
|
||||||
v-model="expenses_store.current_expense.amount"
|
v-model.number="expenseStore.current_expense.amount"
|
||||||
standout
|
standout
|
||||||
dense
|
dense
|
||||||
label-slot
|
label-slot
|
||||||
|
|
@ -219,7 +213,7 @@
|
||||||
|
|
||||||
<q-input
|
<q-input
|
||||||
v-else
|
v-else
|
||||||
v-model="expenses_store.current_expense.mileage"
|
v-model="expenseStore.current_expense.mileage"
|
||||||
standout
|
standout
|
||||||
dense
|
dense
|
||||||
label-slot
|
label-slot
|
||||||
|
|
@ -243,7 +237,7 @@
|
||||||
<!-- employee comment input -->
|
<!-- employee comment input -->
|
||||||
<div class="col q-px-xs">
|
<div class="col q-px-xs">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="expenses_store.current_expense.comment"
|
v-model="expenseStore.current_expense.comment"
|
||||||
standout
|
standout
|
||||||
dense
|
dense
|
||||||
stack-label
|
stack-label
|
||||||
|
|
@ -296,16 +290,17 @@
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
push
|
push
|
||||||
:disable="expenses_store.is_save_disabled"
|
:disable="isSaveDisabled"
|
||||||
:color="expenses_store.is_save_disabled ? 'grey-5' : 'accent'"
|
:color="isSaveDisabled ? 'grey-5' : 'accent'"
|
||||||
:icon="expenses_store.mode === 'update' ? 'save' : 'upload'"
|
:icon="expenseStore.mode === 'update' ? 'save' : 'upload'"
|
||||||
:label="expenses_store.mode === 'update' ? $t('shared.label.update') : $t('shared.label.add')"
|
:label="expenseStore.mode === 'update' ? $t('shared.label.update') : $t('shared.label.add')"
|
||||||
class="q-px-sm "
|
class="q-px-sm "
|
||||||
:class="expenses_store.mode === 'create' ? 'q-mr-lg q-mb-md' : 'q-mb-sm q-ml-lg'"
|
:class="expenseStore.mode === 'create' ? 'q-mr-lg q-mb-md' : 'q-mb-sm q-ml-lg'"
|
||||||
type="submit"
|
type="submit"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</q-form>
|
</q-form>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,9 @@
|
||||||
>
|
>
|
||||||
import ExpenseDialogForm from 'src/modules/timesheets/components/expense-dialog-form.vue';
|
import ExpenseDialogForm from 'src/modules/timesheets/components/expense-dialog-form.vue';
|
||||||
|
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref, toRaw } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { date, Notify } from 'quasar';
|
import { date, Notify } from 'quasar';
|
||||||
import { unwrapAndClone } from 'src/utils/unwrap-and-clone';
|
|
||||||
import { useExpensesStore } from 'src/stores/expense-store';
|
import { useExpensesStore } from 'src/stores/expense-store';
|
||||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||||
import { useExpensesApi } from 'src/modules/timesheets/composables/use-expense-api';
|
import { useExpensesApi } from 'src/modules/timesheets/composables/use-expense-api';
|
||||||
|
|
@ -23,10 +22,10 @@
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const expenses_api = useExpensesApi();
|
const expensesApi = useExpensesApi();
|
||||||
const expenses_store = useExpensesStore();
|
const expenseStore = useExpensesStore();
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheetStore = useTimesheetStore();
|
||||||
const is_showing_update_form = ref(false);
|
const isShowingUpdateForm = ref(false);
|
||||||
|
|
||||||
// ========== computed ===================================
|
// ========== computed ===================================
|
||||||
|
|
||||||
|
|
@ -37,30 +36,30 @@
|
||||||
// ===================== methods =========================
|
// ===================== methods =========================
|
||||||
|
|
||||||
const requestExpenseDeletion = async () => {
|
const requestExpenseDeletion = async () => {
|
||||||
await expenses_api.deleteExpenseById(expense.value.id);
|
await expensesApi.deleteExpenseById(expense.value.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onClickExpenseUpdate = () => {
|
const onClickExpenseUpdate = () => {
|
||||||
if (expense.value.is_approved) return;
|
if (expense.value.is_approved) return;
|
||||||
|
|
||||||
expenses_store.mode = 'update';
|
expenseStore.mode = 'update';
|
||||||
expenses_store.current_expense = expense.value;
|
expenseStore.current_expense = structuredClone(toRaw(expense.value));
|
||||||
expenses_store.initial_expense = unwrapAndClone(expense.value);
|
expenseStore.initial_expense = structuredClone(toRaw(expense.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
const onClickApproval = async () => {
|
const onClickApproval = async () => {
|
||||||
expenses_store.current_expense = unwrapAndClone(expense.value);
|
expenseStore.current_expense = structuredClone(toRaw(expense.value));
|
||||||
expenses_store.current_expense.is_approved = !expenses_store.current_expense.is_approved;
|
expenseStore.current_expense.is_approved = !expenseStore.current_expense.is_approved;
|
||||||
|
|
||||||
const success = await expenses_store.upsertExpense(
|
const success = await expenseStore.upsertExpense(
|
||||||
expenses_store.current_expense,
|
expenseStore.current_expense,
|
||||||
timesheet_store.current_pay_period_overview?.email
|
timesheetStore.current_pay_period_overview?.email
|
||||||
);
|
);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
expense.value.is_approved = !expense.value.is_approved;
|
expense.value.is_approved = !expense.value.is_approved;
|
||||||
} else {
|
} else {
|
||||||
expenses_store.current_expense.is_approved = !expenses_store.current_expense.is_approved;
|
expenseStore.current_expense.is_approved = !expenseStore.current_expense.is_approved;
|
||||||
Notify.create({
|
Notify.create({
|
||||||
message: t('timesheet.errors.UPDATE_ERROR'),
|
message: t('timesheet.errors.UPDATE_ERROR'),
|
||||||
color: "negative"
|
color: "negative"
|
||||||
|
|
@ -68,16 +67,25 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getEmployeeEmail = () => {
|
||||||
|
if (mode === 'approval')
|
||||||
|
return timesheetStore.current_pay_period_overview?.email;
|
||||||
|
}
|
||||||
|
|
||||||
const onClickAttachment = async () => {
|
const onClickAttachment = async () => {
|
||||||
expenses_store.isShowingAttachmentDialog = true;
|
expenseStore.isShowingAttachmentDialog = true;
|
||||||
await expenses_store.getAttachmentURL(expense.value.attachment_key);
|
await expenseStore.getAttachmentURL(expense.value.attachment_key);
|
||||||
console.log('image url: ', expenses_store.attachmentURL);
|
console.log('image url: ', expenseStore.attachmentURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hideUpdateForm = () => {
|
||||||
|
isShowingUpdateForm.value = false;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-expansion-item
|
<q-expansion-item
|
||||||
v-model="is_showing_update_form"
|
v-model="isShowingUpdateForm"
|
||||||
hide-expand-icon
|
hide-expand-icon
|
||||||
dense
|
dense
|
||||||
group="expenses"
|
group="expenses"
|
||||||
|
|
@ -106,7 +114,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- amount or mileage section -->
|
<!-- amount or mileage section -->
|
||||||
<div class="col column">
|
<div class="col-auto column q-pr-md">
|
||||||
<span
|
<span
|
||||||
class="text-weight-bolder"
|
class="text-weight-bolder"
|
||||||
:class="expense.is_approved ? ' bg-accent text-white' : ''"
|
:class="expense.is_approved ? ' bg-accent text-white' : ''"
|
||||||
|
|
@ -122,81 +130,74 @@
|
||||||
:class="expense.is_approved ? ' bg-accent text-white' : ''"
|
:class="expense.is_approved ? ' bg-accent text-white' : ''"
|
||||||
>
|
>
|
||||||
{{ $d(date.extractDate(expense.date, 'YYYY-MM-DD'), {
|
{{ $d(date.extractDate(expense.date, 'YYYY-MM-DD'), {
|
||||||
month: 'short', day: 'numeric', weekday:
|
month: 'long', day: 'numeric', weekday: 'long'
|
||||||
'long'
|
|
||||||
}) }}
|
}) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- attachment file icon -->
|
<q-separator vertical spaced class="q-my-xs"/>
|
||||||
<div class="col row items-center justify-start">
|
|
||||||
<q-btn
|
|
||||||
push
|
|
||||||
:disable="expense.attachment_name === undefined"
|
|
||||||
:color="attachmentButtonColor"
|
|
||||||
:text-color="expense.is_approved ? 'accent' : 'white'"
|
|
||||||
class="col-auto q-px-sm q-mr-sm"
|
|
||||||
icon="attach_file"
|
|
||||||
@click.stop="onClickAttachment"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<q-item-label class="col">
|
|
||||||
<span v-if="expense.attachment_name">
|
|
||||||
{{ expense.attachment_name }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
|
<!-- comments section -->
|
||||||
|
<div class="col column">
|
||||||
|
<div class="col row items-center">
|
||||||
<span
|
<span
|
||||||
v-else
|
class="col-auto text-weight-medium text-accent text-uppercase q-pr-md"
|
||||||
class="text-italic text-blue-grey-5 text-uppercase"
|
style="font-size: 1.2em;"
|
||||||
>
|
>
|
||||||
{{ $t('timesheet.expense.no_attachment') }}
|
{{ $t('timesheet.expense.employee_comment') }} :
|
||||||
</span>
|
|
||||||
</q-item-label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- comment section -->
|
|
||||||
<div class="col column no-wrap">
|
|
||||||
<span class="col-auto text-weight-bold text-accent text-uppercase text-caption">
|
|
||||||
{{ $t('timesheet.expense.employee_comment') }}
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
class="col ellipsis"
|
class="col"
|
||||||
:class="expense.is_approved ? ' bg-accent text-white' : ''"
|
:class="expense.is_approved ? ' bg-accent text-white' : ''"
|
||||||
style="font-size: 1em;"
|
|
||||||
>
|
>
|
||||||
{{ expense.comment }}
|
{{ expense.comment }}
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<q-separator class="q-mr-md"/>
|
||||||
|
|
||||||
|
<div class="col row items-center">
|
||||||
|
<span
|
||||||
|
class="col-auto text-weight-medium text-accent text-uppercase q-pr-md"
|
||||||
|
style="font-size: 1.2em; "
|
||||||
|
:style="expense.supervisor_comment ? '' : 'filter: grayscale(1);'"
|
||||||
|
>
|
||||||
|
{{ $t('timesheet.expense.supervisor_comment') }} :
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
class="col"
|
||||||
|
:class="expense.is_approved ? ' bg-accent text-white' : ''"
|
||||||
|
>
|
||||||
|
{{ expense.supervisor_comment }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- attachment -->
|
||||||
|
<div class="col-auto">
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
size="lg"
|
||||||
|
:disable="expense.attachment_name === undefined"
|
||||||
|
:color="attachmentButtonColor"
|
||||||
|
class="col-auto q-px-sm q-mr-sm"
|
||||||
|
:icon="expense.attachment_key ? 'image' : 'hide_image'"
|
||||||
|
@click.stop="onClickAttachment"
|
||||||
|
>
|
||||||
<q-tooltip
|
<q-tooltip
|
||||||
anchor="top middle"
|
anchor="top middle"
|
||||||
self="center middle"
|
self="center middle"
|
||||||
:offset="[0, 20]"
|
:offset="[0, 20]"
|
||||||
class="bg-accent text-uppercase text-weight-bold"
|
class="bg-accent text-uppercase text-weight-bold"
|
||||||
>
|
>
|
||||||
{{ expense.comment }}
|
{{ expense.attachment_name ?? $t('timesheet.expense.no_attachment') }}
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- supervisor comment section -->
|
<!-- buttons -->
|
||||||
<div
|
|
||||||
v-if="expense.supervisor_comment"
|
|
||||||
class="col column"
|
|
||||||
>
|
|
||||||
<span class="col-auto text-weight-bold text-accent text-uppercase text-caption">
|
|
||||||
{{ $t('timesheet.expense.supervisor_comment') }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span
|
|
||||||
class="col"
|
|
||||||
:class="expense.is_approved ? ' bg-accent text-white' : ''"
|
|
||||||
style="font-size: 1.3em;"
|
|
||||||
>
|
|
||||||
{{ expense.supervisor_comment }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="mode === 'approval'"
|
v-if="mode === 'approval'"
|
||||||
|
|
@ -240,6 +241,10 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<ExpenseDialogForm v-model="expense" />
|
<ExpenseDialogForm
|
||||||
|
v-model="expense"
|
||||||
|
:email="getEmployeeEmail()"
|
||||||
|
@click-save="hideUpdateForm"
|
||||||
|
/>
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
setup
|
setup
|
||||||
lang="ts"
|
lang="ts"
|
||||||
>
|
>
|
||||||
import { computed, inject } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||||
import ExpenseDialogListItem from 'src/modules/timesheets/components/expense-dialog-list-item.vue';
|
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';
|
import ExpenseDialogListItemMobile from 'src/modules/timesheets/components/mobile/expense-dialog-list-item-mobile.vue';
|
||||||
|
|
@ -23,10 +23,6 @@
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
})
|
})
|
||||||
|
|
||||||
// ==================== methods ========================
|
|
||||||
|
|
||||||
inject( 'employeeEmail', mode === 'approval' ? timesheet_store.current_pay_period_overview?.email : undefined);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -45,7 +41,7 @@
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-for="(expense, index) in expenses_list"
|
v-for="(_expense, index) in expenses_list"
|
||||||
:key="index"
|
:key="index"
|
||||||
>
|
>
|
||||||
<ExpenseDialogListItemMobile
|
<ExpenseDialogListItemMobile
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,10 @@
|
||||||
import { date } from 'quasar';
|
import { date } from 'quasar';
|
||||||
import { useExpensesStore } from 'src/stores/expense-store';
|
import { useExpensesStore } from 'src/stores/expense-store';
|
||||||
import { Expense } from 'src/modules/timesheets/models/expense.models';
|
import { Expense } from 'src/modules/timesheets/models/expense.models';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
const expense_store = useExpensesStore();
|
const expense_store = useExpensesStore();
|
||||||
|
const refreshKey = ref(0);
|
||||||
|
|
||||||
const { isApproved = false } = defineProps<{
|
const { isApproved = false } = defineProps<{
|
||||||
isApproved?: boolean;
|
isApproved?: boolean;
|
||||||
|
|
@ -47,7 +49,7 @@
|
||||||
<q-card-section class="q-pa-none">
|
<q-card-section class="q-pa-none">
|
||||||
<ExpenseDialogHeader />
|
<ExpenseDialogHeader />
|
||||||
|
|
||||||
<ExpenseDialogList />
|
<ExpenseDialogList :key="refreshKey + 1" />
|
||||||
|
|
||||||
<q-expansion-item
|
<q-expansion-item
|
||||||
v-if="!isApproved"
|
v-if="!isApproved"
|
||||||
|
|
@ -56,6 +58,7 @@
|
||||||
:dense="!$q.platform.is.mobile"
|
:dense="!$q.platform.is.mobile"
|
||||||
group="expenses"
|
group="expenses"
|
||||||
@show="onClickExpenseCreate()"
|
@show="onClickExpenseCreate()"
|
||||||
|
@after-hide="refreshKey += 1"
|
||||||
header-class="bg-accent text-white"
|
header-class="bg-accent text-white"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
|
|
@ -74,8 +77,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<ExpenseDialogFormMobile v-if="$q.platform.is.mobile" />
|
<ExpenseDialogFormMobile v-if="$q.platform.is.mobile" />
|
||||||
|
<ExpenseDialogForm
|
||||||
<ExpenseDialogForm v-else />
|
v-else
|
||||||
|
:key="refreshKey"
|
||||||
|
/>
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@
|
||||||
import { useExpensesStore } from "src/stores/expense-store";
|
import { useExpensesStore } from "src/stores/expense-store";
|
||||||
import { useTimesheetStore } from "src/stores/timesheet-store";
|
import { useTimesheetStore } from "src/stores/timesheet-store";
|
||||||
import { Expense } from "src/modules/timesheets/models/expense.models";
|
import { Expense } from "src/modules/timesheets/models/expense.models";
|
||||||
import { date } from "quasar";
|
import { date, Notify } from "quasar";
|
||||||
|
|
||||||
export const useExpensesApi = () => {
|
export const useExpensesApi = () => {
|
||||||
const expenses_store = useExpensesStore();
|
const expenses_store = useExpensesStore();
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheet_store = useTimesheetStore();
|
||||||
|
|
||||||
const upsertExpense = async (expense: Expense, employee_email: string, file?: File): Promise<string> => {
|
const upsertExpense = async (expense: Expense, employee_email?: string, file?: File): Promise<boolean> => {
|
||||||
if (file) {
|
if (file) {
|
||||||
const attachmentKey = await expenses_store.uploadAttachment(file);
|
const attachmentKey = await expenses_store.uploadAttachment(file);
|
||||||
|
|
||||||
|
|
@ -19,23 +19,24 @@ export const useExpensesApi = () => {
|
||||||
expense.attachment_name = file.name;
|
expense.attachment_name = file.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log('employee email provided for expense: ', employee_email)
|
|
||||||
const success = await expenses_store.upsertExpense(expense, employee_email);
|
const success = await expenses_store.upsertExpense(expense, employee_email);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
expenses_store.current_expense = new Expense(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
expenses_store.current_expense = new Expense(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
||||||
timesheet_store.getTimesheetsByOptionalEmployeeEmail(employee_email);
|
await timesheet_store.getTimesheetsByOptionalEmployeeEmail(employee_email);
|
||||||
return 'SUCCESS';
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'INVALID_EXPENSE';
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteExpenseById = async (expense_id: number, employee_email?: string): Promise<void> => {
|
const deleteExpenseById = async (expense_id: number, employee_email?: string): Promise<void> => {
|
||||||
const success = await expenses_store.deleteExpenseById(expense_id);
|
const success = await expenses_store.deleteExpenseById(expense_id);
|
||||||
if (success) {
|
|
||||||
timesheet_store.getTimesheetsByOptionalEmployeeEmail(employee_email);
|
if (success)
|
||||||
}
|
await timesheet_store.getTimesheetsByOptionalEmployeeEmail(employee_email);
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { date } from "quasar";
|
import { date } from "quasar";
|
||||||
import { computed, ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { useTimesheetStore } from "src/stores/timesheet-store";
|
import { useTimesheetStore } from "src/stores/timesheet-store";
|
||||||
import { Expense } from "src/modules/timesheets/models/expense.models";
|
import { Expense } from "src/modules/timesheets/models/expense.models";
|
||||||
|
|
@ -16,7 +16,6 @@ export const useExpensesStore = defineStore('expenses', () => {
|
||||||
const current_expense = ref<Expense>(new Expense(date.formatDate(new Date(), 'YYYY-MM-DD')));
|
const current_expense = ref<Expense>(new Expense(date.formatDate(new Date(), 'YYYY-MM-DD')));
|
||||||
const initial_expense = ref<Expense>(new Expense(date.formatDate(new Date(), 'YYYY-MM-DD')));
|
const initial_expense = ref<Expense>(new Expense(date.formatDate(new Date(), 'YYYY-MM-DD')));
|
||||||
const isShowingAttachmentDialog = ref(false);
|
const isShowingAttachmentDialog = ref(false);
|
||||||
const is_save_disabled = computed(() => JSON.stringify(current_expense.value) === JSON.stringify(initial_expense.value))
|
|
||||||
|
|
||||||
const open = (): void => {
|
const open = (): void => {
|
||||||
is_open.value = true;
|
is_open.value = true;
|
||||||
|
|
@ -103,7 +102,6 @@ export const useExpensesStore = defineStore('expenses', () => {
|
||||||
current_expense,
|
current_expense,
|
||||||
initial_expense,
|
initial_expense,
|
||||||
isShowingAttachmentDialog,
|
isShowingAttachmentDialog,
|
||||||
is_save_disabled,
|
|
||||||
attachmentURL,
|
attachmentURL,
|
||||||
open,
|
open,
|
||||||
upsertExpense,
|
upsertExpense,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Notify, date } from 'quasar';
|
import { Notify } from 'quasar';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
|
|
@ -14,6 +14,7 @@ import type { TimesheetApprovalCSVReportFilters } from 'src/modules/timesheet-ap
|
||||||
import { type FederalHoliday, TARGO_HOLIDAY_NAMES_FR } from 'src/modules/timesheets/models/federal-holidays.models';
|
import { type FederalHoliday, TARGO_HOLIDAY_NAMES_FR } from 'src/modules/timesheets/models/federal-holidays.models';
|
||||||
import type { RouteNames } from 'src/router/router-constants';
|
import type { RouteNames } from 'src/router/router-constants';
|
||||||
import type { RouteRecordNameGeneric } from 'vue-router';
|
import type { RouteRecordNameGeneric } from 'vue-router';
|
||||||
|
import { isBetweenDateStrings } from 'src/utils/date-and-time-utils';
|
||||||
|
|
||||||
export const useTimesheetStore = defineStore('timesheet', () => {
|
export const useTimesheetStore = defineStore('timesheet', () => {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
@ -223,11 +224,7 @@ export const useTimesheetStore = defineStore('timesheet', () => {
|
||||||
const pay_period_event: PayPeriodEvent = JSON.parse(event.data);
|
const pay_period_event: PayPeriodEvent = JSON.parse(event.data);
|
||||||
|
|
||||||
// abort notification if event date is not within pay period being currently viewed
|
// abort notification if event date is not within pay period being currently viewed
|
||||||
const eventDate = date.extractDate(pay_period_event.date, 'YYYY-MM-DD');
|
if (!isBetweenDateStrings(pay_period_event.date, pay_period.value!.period_start, pay_period.value!.period_end))
|
||||||
const startDate = date.extractDate(pay_period.value!.period_start, 'YYYY-MM-DD');
|
|
||||||
const endDate = date.extractDate(pay_period.value!.period_end, 'YYYY-MM-DD');
|
|
||||||
|
|
||||||
if (!date.isBetweenDates(eventDate, startDate, endDate, { inclusiveFrom: true, inclusiveTo: true, onlyDate: true }))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const overview = pay_period_overviews.value.find(overview => overview.email === pay_period_event.employee_email);
|
const overview = pay_period_overviews.value.find(overview => overview.email === pay_period_event.employee_email);
|
||||||
|
|
|
||||||
|
|
@ -44,3 +44,19 @@ export const getHoursMinutesBetweenTwoHHmm = (startTime: string, endTime: string
|
||||||
minutes: Number(endMinutes) - Number(startMinutes),
|
minutes: Number(endMinutes) - Number(startMinutes),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const isBetweenDateStrings = (evDate: string, start: string, end: string, inclusive: boolean = true) => {
|
||||||
|
const eventDate = date.extractDate(evDate, 'YYYY-MM-DD');
|
||||||
|
const startDate = date.extractDate(start, 'YYYY-MM-DD');
|
||||||
|
const endDate = date.extractDate(end, 'YYYY-MM-DD');
|
||||||
|
|
||||||
|
return date.isBetweenDates(
|
||||||
|
eventDate,
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
{
|
||||||
|
inclusiveFrom: inclusive,
|
||||||
|
inclusiveTo: inclusive,
|
||||||
|
onlyDate: true
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user