targo-frontend/src/modules/timesheets/components/timesheet-wrapper.vue

215 lines
8.3 KiB
Vue

<script
setup
lang="ts"
>
/* eslint-disable */
import ShiftList from 'src/modules/timesheets/components/shift-list.vue';
import ShiftListScrollable from 'src/modules/timesheets/components/shift-list-scrollable.vue';
import LoadingOverlay from 'src/modules/shared/components/loading-overlay.vue';
import ExpenseDialog from 'src/modules/timesheets/components/expense-dialog.vue';
import PageHeaderTemplate from 'src/modules/shared/components/page-header-template.vue';
import PayPeriodNavigator from 'src/modules/shared/components/pay-period-navigator.vue';
import TimesheetErrorWidget from 'src/modules/timesheets/components/timesheet-error-widget.vue';
import ShiftListWeeklyOverview from 'src/modules/timesheets/components/shift-list-weekly-overview.vue';
import ShiftListWeeklyOverviewMobile from 'src/modules/timesheets/components/mobile/shift-list-weekly-overview-mobile.vue';
import { computed, onMounted } from 'vue';
import { useShiftApi } from 'src/modules/timesheets/composables/use-shift-api';
import { useTimesheetApi } from 'src/modules/timesheets/composables/use-timesheet-api';
import { useExpensesStore } from 'src/stores/expense-store';
import { useTimesheetStore } from 'src/stores/timesheet-store';
import { date } from 'quasar';
const expenses_store = useExpensesStore();
const timesheet_store = useTimesheetStore();
const timesheet_api = useTimesheetApi();
const shift_api = useShiftApi();
const has_shift_errors = computed(() => timesheet_store.all_current_shifts.filter(shift => shift.has_error === true).length > 0);
const is_timesheets_approved = computed(() => timesheet_store.timesheets.every(timesheet => timesheet.is_approved))
const total_hours = computed(() => timesheet_store.timesheets.reduce((sum, timesheet) =>
sum += timesheet.weekly_hours.regular
+ timesheet.weekly_hours.evening
+ timesheet.weekly_hours.emergency
+ timesheet.weekly_hours.overtime,
0) //initial value
);
const total_expenses = computed(() => timesheet_store.timesheets.reduce((sum, timesheet) =>
sum + timesheet.weekly_expenses.expenses
+ timesheet.weekly_expenses.on_call
+ timesheet.weekly_expenses.per_diem,
0) //initial value
);
const { mode = 'normal' } = defineProps<{
mode?: 'approval' | 'normal';
}>();
onMounted(async () => {
if (mode === 'normal')
await timesheet_api.getTimesheetsByDate(date.formatDate(new Date(), 'YYYY-MM-DD'));
});
</script>
<template>
<div class="column items-center full-height relative-position no-wrap">
<LoadingOverlay v-model="timesheet_store.is_loading" />
<!-- label for approval mode to delimit that this is the timesheet -->
<span
v-if="mode === 'approval'"
class="col-auto text-uppercase text-bold text-h5"
>
{{ $t('timesheet.page_header') }}
</span>
<!-- weekly overview -->
<div class="col-auto row q-px-lg full-width">
<!-- supervisor weekly overview -->
<div
v-if="!$q.platform.is.mobile"
class="col-xs-6 col-md-4 col-xl-3 q-pa-md"
>
<ShiftListWeeklyOverview
mode="total-hours"
:timesheet-mode="mode"
:total-hours="total_hours"
:total-expenses="total_expenses"
/>
</div>
<PageHeaderTemplate
v-if="mode === 'normal'"
:title="'timesheet.page_header'"
:start-date="timesheet_store.pay_period?.period_start ?? ''"
:end-date="timesheet_store.pay_period?.period_end ?? ''"
class="col"
/>
<q-space v-if="!$q.platform.is.mobile && mode === 'approval'" />
<!-- employee weekly overview -->
<div
v-if="!$q.platform.is.mobile"
class="col-xs-6 col-md-4 col-xl-3 q-pa-md"
>
<ShiftListWeeklyOverview mode="off-hours" :timesheet-mode="mode" />
</div>
</div>
<!-- top menu -->
<div
class="col-auto row items-center full-width"
:class="$q.platform.is.mobile && ($q.screen.width < $q.screen.height) ? 'justify-between q-px-md' : 'q-pb-sm q-px-xl'"
>
<!-- navigation btn -->
<PayPeriodNavigator
v-if="mode === 'normal'"
class="col-auto"
@date-selected="timesheet_api.getTimesheetsByDate"
@pressed-previous-button="timesheet_api.getTimesheetsByCurrentPayPeriod"
@pressed-next-button="timesheet_api.getTimesheetsByCurrentPayPeriod"
/>
<!-- mobile expenses button -->
<div v-if="($q.platform.is.mobile && ($q.screen.width < $q.screen.height))" class="col q-pl-lg">
<q-btn
push
rounded
color="accent"
icon="receipt_long"
class="full-width"
@click="expenses_store.open"
/>
</div>
<q-space v-if="$q.screen.width > $q.screen.height" />
<!-- desktop expenses button -->
<q-btn
v-if="mode === 'normal' && $q.screen.width > $q.screen.height"
push
rounded
color="accent"
icon="receipt_long"
:label="$t('timesheet.expense.open_btn')"
@click="expenses_store.open"
/>
<!-- desktop save timesheet changes button -->
<q-btn
v-if="!is_timesheets_approved && $q.screen.width > $q.screen.height"
push
rounded
:disable="timesheet_store.is_loading || has_shift_errors"
:color="timesheet_store.is_loading || has_shift_errors ? 'grey-5' : 'accent'"
icon="upload"
:label="$t('shared.label.save')"
:class="$q.platform.is.mobile && ($q.screen.width < $q.screen.height) ? 'full-width' : 'q-ml-md'"
@click="shift_api.saveShiftChanges"
/>
</div>
<!-- error message widget for potential backend-provided errors -->
<TimesheetErrorWidget class="col-auto" />
<!-- mobile weekly overview widget -->
<ShiftListWeeklyOverviewMobile class="col-auto" />
<!-- standard scrollable shift list for user input -->
<ShiftListScrollable
v-if="mode === 'normal'"
:mode="mode"
:class="mode === 'normal' ? 'col' : 'col-auto'"
/>
<!-- full shift list for timesheet approval details dialog -->
<div
v-else
class="col-auto column full-width"
:style="$q.platform.is.mobile && $q.screen.width < $q.screen.height ? 'margin-bottom: 40px' : ''"
>
<!-- Show if no timesheets found (further than one month from present) -->
<div
v-if="timesheet_store.timesheets.length < 1 && !timesheet_store.is_loading"
class="col-auto column flex-center fit q-py-lg"
style="min-height: 20vh;"
>
<span class="text-uppercase text-weight-bolder text-center">{{ $t('shared.error.no_data_found')
}}</span>
<q-icon
name="las la-calendar"
color="accent"
size="10em"
class="absolute"
style="opacity: 0.2;"
/>
</div>
<!-- Else show timesheets if found -->
<ShiftList class="col" />
</div>
<q-btn
v-if="$q.platform.is.mobile && $q.screen.width < $q.screen.height"
square
:disable="timesheet_store.is_loading"
size="lg"
color="accent"
icon="upload"
:label="$t('shared.label.save')"
class="col-auto absolute-bottom shadow-up-10"
style="height: 50px;"
@click="shift_api.saveShiftChanges"
/>
<ExpenseDialog
:is-approved="is_timesheets_approved"
class="z-top"
/>
</div>
</template>