refactor(timesheet): add buttons to apply weekly or daily presets, fix mobile UI/UX to please sup.
This commit is contained in:
parent
35d36873e4
commit
db821d1d13
|
|
@ -175,16 +175,14 @@ export default {
|
|||
|
||||
timesheet: {
|
||||
page_header: "Timesheet",
|
||||
apply_preset_day: "Apply schedule to day",
|
||||
apply_preset_week: "Apply schedule to week",
|
||||
nav_button: {
|
||||
calendar_date_picker: "Calendar",
|
||||
current_week: "This week",
|
||||
next_week: "Next period",
|
||||
previous_week: "Previous period",
|
||||
},
|
||||
save_button: "Save",
|
||||
cancel_button: "Cancel",
|
||||
remote_button: "Remote work",
|
||||
delete_button: "Delete",
|
||||
shift: {
|
||||
actions: {
|
||||
add: "Add Shift",
|
||||
|
|
|
|||
|
|
@ -176,16 +176,14 @@ export default {
|
|||
|
||||
timesheet: {
|
||||
page_header: "Carte de temps",
|
||||
apply_preset_day: "Appliquer horaire pour la journée",
|
||||
apply_preset_week: "Appliquer horaire pour la semaine",
|
||||
nav_button: {
|
||||
calendar_date_picker: "Calendrier",
|
||||
current_week: "Semaine actuelle",
|
||||
next_week: "Prochaine période",
|
||||
previous_week: "Période précédente",
|
||||
},
|
||||
save_button: "Enregistrer",
|
||||
cancel_button: "Annuler",
|
||||
remote_button: "Télétravail",
|
||||
delete_button: "Supprimer",
|
||||
shift: {
|
||||
actions: {
|
||||
add: "Ajouter un Quart",
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@
|
|||
|
||||
<q-input
|
||||
v-model="filters.search_bar_string"
|
||||
standout
|
||||
outlined
|
||||
dense
|
||||
rounded
|
||||
color="accent"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
setup
|
||||
lang="ts"
|
||||
>
|
||||
import { date } from 'quasar';
|
||||
import { date, useQuasar } from 'quasar';
|
||||
import { computed } from 'vue';
|
||||
|
||||
const { title, startDate = "", endDate = "" } = defineProps<{
|
||||
title: string;
|
||||
|
|
@ -10,13 +11,17 @@
|
|||
endDate?: string;
|
||||
}>();
|
||||
|
||||
const date_format_options = { day: 'numeric', month: 'long', year: 'numeric', };
|
||||
|
||||
const q = useQuasar();
|
||||
|
||||
const date_format_options = computed(() => q.platform.is.mobile ? { day: 'numeric', month: 'short', year: 'numeric' } : { 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>
|
||||
<div class="column text-uppercase text-center text-weight-bolder text-h4">
|
||||
<span
|
||||
v-if="!$q.platform.is.mobile"
|
||||
class="col q-mt-lg"
|
||||
>{{ $t(title) }}</span>
|
||||
|
||||
<transition
|
||||
enter-active-class="animated fadeInDown"
|
||||
|
|
@ -27,6 +32,7 @@
|
|||
:key="startDate"
|
||||
v-if="startDate.length > 0"
|
||||
class="col row flex-center full-width q-py-none q-my-none"
|
||||
:class="$q.platform.is.mobile ? 'q-mb-md' : ''"
|
||||
>
|
||||
<div class="text-accent text-weight-bold text-h6">
|
||||
{{ $d(date.extractDate(startDate, 'YYYY-MM-DD'), date_format_options) }}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@
|
|||
<template>
|
||||
<q-form
|
||||
v-if="!timesheet_store.timesheets?.every(timesheet => timesheet.is_approved)"
|
||||
:key="expenses_store.current_expense.id"
|
||||
flat
|
||||
@submit.prevent="requestExpenseCreationOrUpdate"
|
||||
class="full-width q-mt-md q-px-md"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@
|
|||
}
|
||||
|
||||
const onClickExpenseUpdate = () => {
|
||||
if (expense.value.is_approved) return;
|
||||
|
||||
expenses_store.mode = 'update';
|
||||
expenses_store.current_expense = expense.value;
|
||||
expenses_store.initial_expense = unwrapAndClone(expense.value);
|
||||
|
|
|
|||
|
|
@ -42,11 +42,8 @@
|
|||
:key="index"
|
||||
>
|
||||
<ExpenseDialogListItemMobile
|
||||
v-if="$q.screen.lt.md"
|
||||
v-if="$q.platform.is.mobile"
|
||||
v-model="expenses_list[index]!"
|
||||
:index="index"
|
||||
:expense="expense"
|
||||
:horizontal="horizontal"
|
||||
/>
|
||||
|
||||
<ExpenseDialogListItem
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@
|
|||
<q-dialog
|
||||
v-model="expense_store.is_open"
|
||||
persistent
|
||||
:full-width="$q.platform.is.mobile"
|
||||
transition-show="jump-down"
|
||||
transition-hide="jump-down"
|
||||
>
|
||||
<q-card
|
||||
class="q-pa-none rounded-10 shadow-10"
|
||||
:class="$q.screen.lt.md ? ' bg-primary' : 'bg-secondary'"
|
||||
class="q-pa-none rounded-10 shadow-24 bg-secondary"
|
||||
style=" min-width: 70vw;"
|
||||
:style="$q.dark.isActive ? 'border: solid 2px var(--q-accent);' : ''"
|
||||
>
|
||||
|
|
@ -45,22 +45,13 @@
|
|||
|
||||
<ExpenseDialogList />
|
||||
|
||||
<q-separator
|
||||
v-if="$q.screen.lt.md"
|
||||
spaced
|
||||
color="accent"
|
||||
size="2px"
|
||||
class="q-mx-md"
|
||||
/>
|
||||
|
||||
<q-expansion-item
|
||||
v-if="!isApproved"
|
||||
v-model="expense_store.is_showing_create_form"
|
||||
hide-expand-icon
|
||||
dense
|
||||
:dense="!$q.platform.is.mobile"
|
||||
group="expenses"
|
||||
@before-show="onClickExpenseCreate()"
|
||||
@hide="expense_store.mode = 'update'"
|
||||
@show="onClickExpenseCreate()"
|
||||
header-class="bg-accent text-white"
|
||||
>
|
||||
<template #header>
|
||||
|
|
@ -77,7 +68,7 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<ExpenseDialogFormMobile v-if="$q.screen.lt.md" />
|
||||
<ExpenseDialogFormMobile v-if="$q.platform.is.mobile" />
|
||||
|
||||
<ExpenseDialogForm v-else />
|
||||
</q-expansion-item>
|
||||
|
|
|
|||
|
|
@ -51,31 +51,18 @@
|
|||
const requestExpenseCreationOrUpdate = async () => {
|
||||
await expenses_api.upsertExpense(expenses_store.current_expense);
|
||||
};
|
||||
|
||||
defineEmits<{
|
||||
'onClickUpdateCancel': [void];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-form
|
||||
v-if="!timesheet_store.timesheets?.every(timesheet => timesheet.is_approved)"
|
||||
:key="expenses_store.current_expense.id"
|
||||
flat
|
||||
@submit.prevent="requestExpenseCreationOrUpdate"
|
||||
class="column full-width"
|
||||
>
|
||||
<!-- header -->
|
||||
<div
|
||||
class="col text-uppercase text-weight-medium text-h6 q-ma-xs"
|
||||
:class="expenses_store.mode === 'create' ? 'q-px-md' : 'invisible'"
|
||||
>
|
||||
{{ $t('timesheet.expense.add_expense') }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="col column items-start rounded-5 q-pb-sm"
|
||||
:class="expenses_store.mode === 'create' ? 'q-px-md' : ''"
|
||||
:class="expenses_store.is_showing_create_form ? 'q-px-md' : 'q-px-sm'"
|
||||
>
|
||||
<!-- date and type row -->
|
||||
<div class="col row q-my-xs full-width">
|
||||
|
|
@ -83,7 +70,6 @@
|
|||
<q-input
|
||||
v-model="expenses_store.current_expense.date"
|
||||
dense
|
||||
type="date"
|
||||
outlined
|
||||
readonly
|
||||
stack-label
|
||||
|
|
@ -286,27 +272,15 @@
|
|||
</template>
|
||||
</q-file>
|
||||
</div>
|
||||
<div class="col row full-width items-center">
|
||||
<q-space />
|
||||
|
||||
<q-btn
|
||||
v-if="expenses_store.mode === 'update'"
|
||||
flat
|
||||
dense
|
||||
class="col-auto"
|
||||
icon="clear"
|
||||
color="negative"
|
||||
:label="$q.screen.gt.sm ? $t('shared.label.cancel') : ''"
|
||||
@click="$emit('onClickUpdateCancel')"
|
||||
/>
|
||||
|
||||
<div class="col row full-width items-center" :class="expenses_store.mode === 'create' ? 'q-px-md q-py-xs' : ''">
|
||||
<q-btn
|
||||
push
|
||||
color="accent"
|
||||
:icon="expenses_store.mode === 'update' ? 'save' : 'upload'"
|
||||
:label="expenses_store.mode === 'update' ? $t('shared.label.update') : $t('shared.label.add')"
|
||||
class="q-px-sm"
|
||||
:class="expenses_store.mode === 'create' ? 'q-mr-md q-mb-md' : 'q-mb-sm q-ml-lg'"
|
||||
class="q-px-sm full-width"
|
||||
:class="expenses_store.mode === 'create' ? '' : 'q-mb-sm'"
|
||||
type="submit"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,70 +2,48 @@
|
|||
setup
|
||||
lang="ts"
|
||||
>
|
||||
/* eslint-disable */
|
||||
import { date } from 'quasar';
|
||||
import { computed, ref } from 'vue';
|
||||
import { unwrapAndClone } from 'src/utils/unwrap-and-clone';
|
||||
import { useExpensesApi } from 'src/modules/timesheets/composables/use-expense-api';
|
||||
import { useExpensesStore } from 'src/stores/expense-store';
|
||||
import { getExpenseIcon } from 'src/modules/timesheets/utils/expense.util';
|
||||
import { Expense } from 'src/modules/timesheets/models/expense.models';
|
||||
import type { Expense } from 'src/modules/timesheets/models/expense.models';
|
||||
import ExpenseDialogFormMobile from 'src/modules/timesheets/components/mobile/expense-dialog-form-mobile.vue';
|
||||
|
||||
const { expense, horizontal = false } = defineProps<{
|
||||
expense: Expense;
|
||||
index: number;
|
||||
horizontal?: boolean;
|
||||
}>();
|
||||
const expense = defineModel<Expense>({ required: true })
|
||||
|
||||
const expenses_store = useExpensesStore();
|
||||
const expenses_api = useExpensesApi();
|
||||
|
||||
const refresh_key = ref(1);
|
||||
const approved_class = computed(() => expense.is_approved ? ' bg-accent text-white' : '')
|
||||
const approved_class = computed(() => expense.value.is_approved ? ' bg-accent text-white' : '')
|
||||
const is_showing_update_form = ref(false);
|
||||
|
||||
const requestExpenseDeletion = async () => {
|
||||
await expenses_api.deleteExpenseById(expense.id);
|
||||
await expenses_api.deleteExpenseById(expense.value.id);
|
||||
}
|
||||
|
||||
const onUpdateClicked = () => {
|
||||
if (expense.is_approved) return;
|
||||
|
||||
if (JSON.stringify(expense) === JSON.stringify(expenses_store.current_expense)) {
|
||||
expenses_store.mode = 'create';
|
||||
expenses_store.current_expense = new Expense(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
||||
is_showing_update_form.value = false;
|
||||
return;
|
||||
}
|
||||
if (expense.value.is_approved) return;
|
||||
|
||||
expenses_store.mode = 'update';
|
||||
expenses_store.current_expense = expense;
|
||||
expenses_store.initial_expense = unwrapAndClone(expense);
|
||||
is_showing_update_form.value = true;
|
||||
expenses_store.current_expense = expense.value;
|
||||
expenses_store.initial_expense = unwrapAndClone(expense.value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="column bg-dark rounded-5 q-my-sm full-width">
|
||||
<q-slide-item
|
||||
right-color="negative"
|
||||
class="rounded-5 bg-dark full-width"
|
||||
@right="requestExpenseDeletion"
|
||||
<div class="column bg-dark shadow-5 rounded-5 q-my-sm full-width">
|
||||
<q-expansion-item
|
||||
v-model="is_showing_update_form"
|
||||
hide-expand-icon
|
||||
dense
|
||||
group="expenses"
|
||||
:class="expense.is_approved ? ' bg-accent text-white' : ''"
|
||||
@before-show="onUpdateClicked()"
|
||||
>
|
||||
<template
|
||||
#right
|
||||
v-if="$q.screen.lt.md && expenses_store.is_showing_create_form && !expense.is_approved"
|
||||
>
|
||||
<q-icon name="delete" />
|
||||
</template>
|
||||
|
||||
<q-item
|
||||
:key="refresh_key"
|
||||
clickable
|
||||
class="row q-py-none q-pa-xs rounded-5 full-width"
|
||||
:class="approved_class"
|
||||
@click="onUpdateClicked"
|
||||
>
|
||||
<template #header>
|
||||
<div class="column col">
|
||||
<!-- date label -->
|
||||
<div class="col-auto row items-center q-pl-xs">
|
||||
|
|
@ -92,22 +70,21 @@
|
|||
:name="getExpenseIcon(expense.type)"
|
||||
:color="expense.is_approved ? 'white' : ($q.dark.isActive ? 'white' : 'primary')"
|
||||
size="lg"
|
||||
class="col-auto"
|
||||
/>
|
||||
|
||||
<!-- amount or mileage section -->
|
||||
<q-item-section class="col text-weight-bold text-h6">
|
||||
<div class="col text-weight-bold text-h6">
|
||||
<q-item-label v-if="expense.type === 'MILEAGE'">
|
||||
{{ expense.mileage?.toFixed(1) }} km
|
||||
</q-item-label>
|
||||
<q-item-label v-else>
|
||||
$ {{ expense.amount.toFixed(2) }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
|
||||
<q-space v-if="horizontal" />
|
||||
</div>
|
||||
|
||||
<!-- attachment file icon -->
|
||||
<q-item-section avatar>
|
||||
<div class="col-auto q-px-xs">
|
||||
<q-btn
|
||||
push
|
||||
:color="expense.is_approved ? 'white' : 'accent'"
|
||||
|
|
@ -115,34 +92,24 @@
|
|||
class="col-auto q-mx-sm q-px-sm q-pb-sm"
|
||||
icon="attach_file"
|
||||
/>
|
||||
</q-item-section>
|
||||
</div>
|
||||
|
||||
<div class="col-auto">
|
||||
<q-icon
|
||||
v-if="expense.is_approved"
|
||||
name="verified"
|
||||
color="white"
|
||||
size="lg"
|
||||
class="full-height"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div
|
||||
class="col-auto q-px-sm"
|
||||
:class="expense.is_approved ? '' : 'invisible'"
|
||||
>
|
||||
<q-icon
|
||||
v-if="expense.is_approved"
|
||||
name="verified"
|
||||
color="white"
|
||||
size="lg"
|
||||
class="full-height"
|
||||
/>
|
||||
</div>
|
||||
</q-item>
|
||||
</q-slide-item>
|
||||
|
||||
<q-slide-transition
|
||||
@hide="expenses_store.is_showing_create_form = true"
|
||||
:duration="200"
|
||||
>
|
||||
<ExpenseDialogFormMobile
|
||||
v-if="is_showing_update_form && !expenses_store.is_showing_create_form"
|
||||
class="q-mt-sm q-pa-sm"
|
||||
@on-click-update-cancel="onUpdateClicked"
|
||||
/>
|
||||
</q-slide-transition>
|
||||
<div class="q-px-sm">
|
||||
<ExpenseDialogFormMobile />
|
||||
</div>
|
||||
</q-expansion-item>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -381,12 +381,6 @@
|
|||
:class="shift.is_approved ? 'invisible' : ''"
|
||||
@click="$emit('requestDelete')"
|
||||
>
|
||||
<q-badge
|
||||
v-if="!shift.is_approved"
|
||||
color="white"
|
||||
class="absolute"
|
||||
style="z-index: -1;"
|
||||
/>
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,18 +3,26 @@
|
|||
lang="ts"
|
||||
>
|
||||
import ShiftListDayRow from 'src/modules/timesheets/components/shift-list-day-row.vue';
|
||||
|
||||
import { ref } from 'vue';
|
||||
import { useShiftApi } from 'src/modules/timesheets/composables/use-shift-api';
|
||||
import { useTimesheetApi } from 'src/modules/timesheets/composables/use-timesheet-api';
|
||||
import type { Shift } from 'src/modules/timesheets/models/shift.models';
|
||||
import type { TimesheetDay } from 'src/modules/timesheets/models/timesheet.models';
|
||||
|
||||
const shift_api = useShiftApi();
|
||||
const timesheet_api = useTimesheetApi();
|
||||
|
||||
const { day, dense = false, approved = false } = defineProps<{
|
||||
timesheetId: number;
|
||||
weekDayIndex: number;
|
||||
day: TimesheetDay;
|
||||
dense?: boolean;
|
||||
approved?: boolean;
|
||||
}>();
|
||||
|
||||
const preset_mouseover = ref(false);
|
||||
|
||||
const emit = defineEmits<{
|
||||
'deleteUnsavedShift': [void];
|
||||
}>();
|
||||
|
|
@ -30,15 +38,45 @@
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="column justify-center q-py-xs" :class="approved ? '' : ''">
|
||||
<ShiftListDayRow
|
||||
v-for="shift, shift_index in day.shifts"
|
||||
:key="shift_index"
|
||||
v-model:shift="day.shifts[shift_index]!"
|
||||
:is-timesheet-approved="approved"
|
||||
:dense="dense"
|
||||
:has-shift-after="shift_index < day.shifts.length - 1"
|
||||
@request-delete="deleteCurrentShift(shift)"
|
||||
/>
|
||||
<div
|
||||
class="column justify-center q-py-xs"
|
||||
:class="approved ? '' : ''"
|
||||
@mouseenter="preset_mouseover = true"
|
||||
@mouseleave="preset_mouseover = false"
|
||||
>
|
||||
<!-- Button to apply preset to day -->
|
||||
<transition
|
||||
appear
|
||||
enter-active-class="animated zoomIn fast"
|
||||
leave-active-class="animated zoomOut fast"
|
||||
>
|
||||
<q-btn
|
||||
v-if="!$q.platform.is.mobile && day.shifts.length < 1 && preset_mouseover"
|
||||
:disable="day.shifts.length > 0"
|
||||
flat
|
||||
dense
|
||||
size="lg"
|
||||
:label="$t('timesheet.apply_preset_day')"
|
||||
class="text-uppercase text-weight-bold text-accent q-mx-lg q-py-none rounded-5"
|
||||
style="opacity: 0.6;"
|
||||
@click.stop="timesheet_api.applyPreset(timesheetId, weekDayIndex, day.date)"
|
||||
>
|
||||
<q-icon
|
||||
name="las la-calendar-day"
|
||||
color="accent"
|
||||
size="md"
|
||||
/>
|
||||
</q-btn>
|
||||
</transition>
|
||||
|
||||
<ShiftListDayRow
|
||||
v-for="shift, shift_index in day.shifts"
|
||||
:key="shift_index"
|
||||
v-model:shift="day.shifts[shift_index]!"
|
||||
:is-timesheet-approved="approved"
|
||||
:dense="dense"
|
||||
:has-shift-after="shift_index < day.shifts.length - 1"
|
||||
@request-delete="deleteCurrentShift(shift)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -2,21 +2,28 @@
|
|||
setup
|
||||
lang="ts"
|
||||
>
|
||||
import { computed } from 'vue';
|
||||
import ShiftListDay from 'src/modules/timesheets/components/shift-list-day.vue';
|
||||
import ShiftListDateWidget from 'src/modules/timesheets/components/shift-list-date-widget.vue';
|
||||
|
||||
import { date } from 'quasar';
|
||||
import { computed, ref } from 'vue';
|
||||
import { useUiStore } from 'src/stores/ui-store';
|
||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||
import { Shift } from 'src/modules/timesheets/models/shift.models';
|
||||
import ShiftListDay from 'src/modules/timesheets/components/shift-list-day.vue';
|
||||
import ShiftListDateWidget from 'src/modules/timesheets/components/shift-list-date-widget.vue';
|
||||
import { useTimesheetApi } from 'src/modules/timesheets/composables/use-timesheet-api';
|
||||
import type { QScrollArea } from 'quasar';
|
||||
import type { TimesheetDay } from 'src/modules/timesheets/models/timesheet.models';
|
||||
|
||||
const { extractDate } = date;
|
||||
|
||||
const ui_store = useUiStore();
|
||||
const timesheet_store = useTimesheetStore();
|
||||
const timesheet_api = useTimesheetApi();
|
||||
|
||||
const animation_style = computed(() => ui_store.is_mobile_mode ? 'fadeInLeft' : 'fadeInDown' );
|
||||
const animation_style = computed(() => ui_store.is_mobile_mode ? 'fadeInLeft' : 'fadeInDown');
|
||||
|
||||
const timesheet_page = ref<QScrollArea | null>(null);
|
||||
const scroll_y = computed(() => timesheet_page.value?.getScrollPosition().top ?? 0)
|
||||
|
||||
const addNewShift = (day_shifts: Shift[], date: string, timesheet_id: number) => {
|
||||
ui_store.focus_next_component = true;
|
||||
|
|
@ -41,138 +48,200 @@
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="$q.screen.lt.md ? 'column full-width' : 'row'"
|
||||
>
|
||||
<div
|
||||
v-for="timesheet, timesheet_index in timesheet_store.timesheets"
|
||||
:key="timesheet.timesheet_id"
|
||||
class="col column"
|
||||
<div class="col column fit">
|
||||
<q-scroll-area
|
||||
ref="timesheet_page"
|
||||
:horizontal-offset="[0, 3]"
|
||||
class="col hide-scrollbar q-mt-sm"
|
||||
:thumb-style="{ opacity: '0' }"
|
||||
:bar-style="{ opacity: '0' }"
|
||||
>
|
||||
<transition-group
|
||||
appear
|
||||
:enter-active-class="`animated ${animation_style}`"
|
||||
>
|
||||
<div :class="$q.platform.is.mobile ? 'column' : 'row'">
|
||||
|
||||
<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;`"
|
||||
v-for="timesheet, timesheet_index in timesheet_store.timesheets"
|
||||
:key="timesheet.timesheet_id"
|
||||
class="col"
|
||||
>
|
||||
<div
|
||||
v-if="ui_store.is_mobile_mode"
|
||||
class="col column full-width"
|
||||
<transition
|
||||
appear
|
||||
enter-active-class="animated fadeInDown"
|
||||
leave-active-class="animated fadeOutUp"
|
||||
>
|
||||
<q-card
|
||||
class="rounded-10"
|
||||
:class="(getDayApproval(day) || timesheet.is_approved) ? 'bg-accent' : 'bg-dark'"
|
||||
:style="ui_store.is_mobile_mode ? ((getDayApproval(day) || timesheet.is_approved) ? 'border: 6px inset var(--q-accent)' : 'border: 1px solid var(--q-accent);') : ''"
|
||||
<q-btn
|
||||
v-if="!$q.platform.is.mobile"
|
||||
:disable="!timesheet.days.every(day => day.shifts.length < 1)"
|
||||
flat
|
||||
dense
|
||||
:label="$t('timesheet.apply_preset_week')"
|
||||
class="text-uppercase text-weight-bold text-accent q-mx-lg q-py-none rounded-5"
|
||||
:class="timesheet.days.every(day => day.shifts.length < 1) ? '' : 'invisible'"
|
||||
@click="timesheet_api.applyPreset(timesheet.timesheet_id)"
|
||||
>
|
||||
|
||||
<q-card-section
|
||||
class="text-weight-bolder text-uppercase text-h6 q-py-xs"
|
||||
:class="(getDayApproval(day) || timesheet.is_approved) ? 'bg-accent text-white' : 'bg-primary text-white'"
|
||||
style="line-height: 1em;"
|
||||
>
|
||||
<span> {{ $d(extractDate(day.date, 'YYYY-MM-DD'), {
|
||||
weekday: 'long', day: 'numeric', month:
|
||||
'long'
|
||||
}) }}</span>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section
|
||||
v-if="day.shifts.filter(shift => shift.id !== 0).length > 0"
|
||||
class="q-pa-none transparent"
|
||||
>
|
||||
<ShiftListDay
|
||||
outlined
|
||||
:animation-delay-multiplier="day_index"
|
||||
:approved="(getDayApproval(day) || timesheet.is_approved)"
|
||||
:day="day"
|
||||
@delete-unsaved-shift="deleteUnsavedShift(timesheet_index, day_index)"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions class="q-pa-none">
|
||||
<q-btn
|
||||
v-if="!(getDayApproval(day) || timesheet.is_approved)"
|
||||
square
|
||||
color="accent"
|
||||
icon="more_time"
|
||||
class="full-width"
|
||||
style="border-radius: 0 0 5px 5px;"
|
||||
@click="addNewShift(day.shifts, day.date, timesheet.timesheet_id)"
|
||||
/>
|
||||
</q-card-actions>
|
||||
|
||||
<q-badge
|
||||
v-if="(getDayApproval(day) || timesheet.is_approved)"
|
||||
floating
|
||||
class="transparent q-pa-none rounded-50"
|
||||
style="transform: translate(15px, -5px);"
|
||||
>
|
||||
<q-icon
|
||||
name="verified"
|
||||
size="5em"
|
||||
color="white"
|
||||
/>
|
||||
</q-badge>
|
||||
</q-card>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="col row full-width"
|
||||
:class="(getDayApproval(day) || timesheet.is_approved) ? 'rounded-10 bg-accent' : ''"
|
||||
>
|
||||
<!-- List of shifts -->
|
||||
|
||||
<div
|
||||
class="col row bg-dark"
|
||||
:class="(getDayApproval(day) || timesheet.is_approved) ? 'bg-transparent' : ''"
|
||||
style="border-radius: 10px 0 0 10px;"
|
||||
>
|
||||
<!-- Date block -->
|
||||
<ShiftListDateWidget
|
||||
:display-date="day.date"
|
||||
:approved="(getDayApproval(day) || timesheet.is_approved)"
|
||||
class="col-auto"
|
||||
/>
|
||||
|
||||
|
||||
<ShiftListDay
|
||||
:day="day"
|
||||
:approved="getDayApproval(day) || timesheet.is_approved"
|
||||
class="col"
|
||||
@delete-unsaved-shift="deleteUnsavedShift(timesheet_index, day_index)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-auto self-stretch">
|
||||
<q-icon
|
||||
v-if="(getDayApproval(day) || timesheet.is_approved)"
|
||||
name="verified"
|
||||
color="white"
|
||||
size="xl"
|
||||
class="full-height"
|
||||
/>
|
||||
<q-btn
|
||||
v-else
|
||||
:dense="!ui_store.is_mobile_mode"
|
||||
icon="more_time"
|
||||
size="lg"
|
||||
name="las la-calendar-week"
|
||||
color="accent"
|
||||
text-color="white"
|
||||
class="full-height"
|
||||
:class="$q.screen.lt.md ? 'q-px-xs ' : ' '"
|
||||
style="border-radius: 0 10px 10px 0;"
|
||||
@click="addNewShift(day.shifts, day.date, timesheet.timesheet_id)"
|
||||
size="md"
|
||||
/>
|
||||
</q-btn>
|
||||
</transition>
|
||||
|
||||
<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="$q.platform.is.mobile && ($q.screen.width < $q.screen.height)"
|
||||
class="col column full-width"
|
||||
>
|
||||
<q-card
|
||||
class="rounded-10"
|
||||
:class="(getDayApproval(day) || timesheet.is_approved) ? 'bg-accent' : 'bg-dark'"
|
||||
:style="ui_store.is_mobile_mode ? ((getDayApproval(day) || timesheet.is_approved) ? 'border: 6px inset var(--q-accent)' : 'border: 1px solid var(--q-accent);') : ''"
|
||||
>
|
||||
|
||||
<q-card-section
|
||||
class="text-weight-bolder text-uppercase text-h6 q-py-xs"
|
||||
:class="(getDayApproval(day) || timesheet.is_approved) ? 'bg-accent text-white' : 'bg-primary text-white'"
|
||||
style="line-height: 1em;"
|
||||
>
|
||||
<span> {{ $d(extractDate(day.date, 'YYYY-MM-DD'), {
|
||||
weekday: 'long', day: 'numeric', month:
|
||||
'long'
|
||||
}) }}</span>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section
|
||||
v-if="day.shifts.filter(shift => shift.id !== 0).length > 0"
|
||||
class="q-pa-none transparent"
|
||||
>
|
||||
<ShiftListDay
|
||||
outlined
|
||||
:timesheet-id="timesheet.timesheet_id"
|
||||
:week-day-index="day_index"
|
||||
:animation-delay-multiplier="day_index"
|
||||
:approved="(getDayApproval(day) || timesheet.is_approved)"
|
||||
:day="day"
|
||||
@delete-unsaved-shift="deleteUnsavedShift(timesheet_index, day_index)"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions class="q-pa-none">
|
||||
<q-btn
|
||||
v-if="!(getDayApproval(day) || timesheet.is_approved)"
|
||||
square
|
||||
color="accent"
|
||||
icon="more_time"
|
||||
class="full-width"
|
||||
style="border-radius: 0 0 5px 5px;"
|
||||
@click="addNewShift(day.shifts, day.date, timesheet.timesheet_id)"
|
||||
/>
|
||||
</q-card-actions>
|
||||
|
||||
<q-badge
|
||||
v-if="(getDayApproval(day) || timesheet.is_approved)"
|
||||
floating
|
||||
class="transparent q-pa-none rounded-50"
|
||||
style="transform: translate(15px, -5px);"
|
||||
>
|
||||
<q-icon
|
||||
name="verified"
|
||||
size="5em"
|
||||
color="white"
|
||||
/>
|
||||
</q-badge>
|
||||
</q-card>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="col row full-width"
|
||||
:class="(getDayApproval(day) || timesheet.is_approved) ? 'rounded-10 bg-accent' : ''"
|
||||
>
|
||||
<transition
|
||||
appear
|
||||
enter-active-class="animated fadeInDown"
|
||||
leave-active-class="animated fadeOutUp"
|
||||
>
|
||||
</transition>
|
||||
<!-- List of shifts -->
|
||||
<div
|
||||
class="col row bg-dark"
|
||||
:class="(getDayApproval(day) || timesheet.is_approved) ? 'bg-transparent' : ''"
|
||||
style="border-radius: 10px 0 0 10px;"
|
||||
>
|
||||
<!-- Date block -->
|
||||
<ShiftListDateWidget
|
||||
:display-date="day.date"
|
||||
:approved="(getDayApproval(day) || timesheet.is_approved)"
|
||||
class="col-auto"
|
||||
/>
|
||||
|
||||
<ShiftListDay
|
||||
:timesheet-id="timesheet.timesheet_id"
|
||||
:week-day-index="day_index"
|
||||
:day="day"
|
||||
:approved="getDayApproval(day) || timesheet.is_approved"
|
||||
class="col"
|
||||
@delete-unsaved-shift="deleteUnsavedShift(timesheet_index, day_index)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-auto self-stretch">
|
||||
<q-icon
|
||||
v-if="(getDayApproval(day) || timesheet.is_approved)"
|
||||
name="verified"
|
||||
color="white"
|
||||
size="xl"
|
||||
class="full-height"
|
||||
/>
|
||||
<q-btn
|
||||
v-else
|
||||
:dense="!ui_store.is_mobile_mode"
|
||||
icon="more_time"
|
||||
size="lg"
|
||||
color="accent"
|
||||
text-color="white"
|
||||
class="full-height"
|
||||
:class="$q.screen.lt.md ? 'q-px-xs ' : ' '"
|
||||
style="border-radius: 0 10px 10px 0;"
|
||||
@click="addNewShift(day.shifts, day.date, timesheet.timesheet_id)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
</div>
|
||||
</q-scroll-area>
|
||||
</div>
|
||||
|
||||
<q-page-sticky
|
||||
position="bottom-right"
|
||||
:offset="[15, 15]"
|
||||
class="z-top"
|
||||
>
|
||||
<transition
|
||||
appear
|
||||
enter-active-class="animated zoomIn"
|
||||
leave-active-class="animated zoomOut"
|
||||
>
|
||||
<q-btn
|
||||
v-if="scroll_y > 400"
|
||||
fab
|
||||
icon="las la-chevron-up"
|
||||
color="white"
|
||||
text-color="accent"
|
||||
class="shadow-12"
|
||||
@click="timesheet_page!.setScrollPosition('vertical', 0, 300)"
|
||||
/>
|
||||
</transition>
|
||||
</q-page-sticky>
|
||||
</template>
|
||||
|
|
@ -9,11 +9,12 @@
|
|||
import TimesheetErrorWidget from 'src/modules/timesheets/components/timesheet-error-widget.vue';
|
||||
import LoadingOverlay from 'src/modules/shared/components/loading-overlay.vue';
|
||||
|
||||
import { computed } from '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();
|
||||
|
|
@ -28,89 +29,84 @@
|
|||
mode?: 'approval' | 'normal';
|
||||
}>();
|
||||
|
||||
onMounted(async () => {
|
||||
await timesheet_api.getTimesheetsByDate(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="column flex-center full-width">
|
||||
<div class="column items-center full-height">
|
||||
<LoadingOverlay v-model="timesheet_store.is_loading" />
|
||||
|
||||
<q-card
|
||||
flat
|
||||
class="transparent full-width"
|
||||
<div
|
||||
class="col-auto row items-center full-width"
|
||||
:class="$q.platform.is.mobile && ($q.screen.width < $q.screen.height) ? 'justify-between' : 'q-mt-md q-px-md'"
|
||||
>
|
||||
<q-card-section
|
||||
:horizontal="$q.screen.gt.sm"
|
||||
class="q-px-md items-center q-mb-md"
|
||||
:class="$q.screen.lt.md ? 'column' : ''"
|
||||
>
|
||||
<!-- navigation btn -->
|
||||
<PayPeriodNavigator
|
||||
v-if="mode === 'normal'"
|
||||
@date-selected="date_value => timesheet_api.getTimesheetsByDate(date_value)"
|
||||
@pressed-previous-button="timesheet_api.getTimesheetsByCurrentPayPeriod"
|
||||
@pressed-next-button="timesheet_api.getTimesheetsByCurrentPayPeriod"
|
||||
/>
|
||||
<!-- navigation btn -->
|
||||
<PayPeriodNavigator
|
||||
v-if="mode === 'normal'"
|
||||
class="col-auto"
|
||||
@date-selected="date_value => timesheet_api.getTimesheetsByDate(date_value)"
|
||||
@pressed-previous-button="timesheet_api.getTimesheetsByCurrentPayPeriod"
|
||||
@pressed-next-button="timesheet_api.getTimesheetsByCurrentPayPeriod"
|
||||
/>
|
||||
|
||||
<!-- mobile expenses button -->
|
||||
<q-btn
|
||||
v-if="$q.screen.lt.md && mode === 'normal'"
|
||||
push
|
||||
rounded
|
||||
color="accent"
|
||||
icon="receipt_long"
|
||||
:label="$t('timesheet.expense.open_btn')"
|
||||
class="q-mt-sm"
|
||||
@click="expenses_store.open"
|
||||
/>
|
||||
<!-- mobile expenses button -->
|
||||
<q-btn
|
||||
v-if="($q.platform.is.mobile && ($q.screen.width < $q.screen.height))"
|
||||
push
|
||||
rounded
|
||||
color="accent"
|
||||
icon="receipt_long"
|
||||
:label="$t('timesheet_approvals.table.expenses')"
|
||||
class="col-auto"
|
||||
@click="expenses_store.open"
|
||||
/>
|
||||
|
||||
<q-space />
|
||||
<q-space v-if="!$q.platform.is.mobile" />
|
||||
|
||||
<!-- save timesheet changes button -->
|
||||
<q-btn
|
||||
v-if="mode === 'normal' && !is_timesheets_approved"
|
||||
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-mr-md"
|
||||
@click="shift_api.saveShiftChanges"
|
||||
/>
|
||||
<!-- desktop save timesheet changes button -->
|
||||
<q-btn
|
||||
v-if="mode === 'normal' && !is_timesheets_approved && !$q.platform.is.mobile"
|
||||
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-mr-md'"
|
||||
@click="shift_api.saveShiftChanges"
|
||||
/>
|
||||
|
||||
<!-- desktop expenses button -->
|
||||
<q-btn
|
||||
v-if="mode === 'normal'"
|
||||
push
|
||||
rounded
|
||||
color="accent"
|
||||
icon="receipt_long"
|
||||
:label="$t('timesheet.expense.open_btn')"
|
||||
@click="expenses_store.open"
|
||||
/>
|
||||
<!-- 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"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</q-card-section>
|
||||
<TimesheetErrorWidget class="col-auto"/>
|
||||
|
||||
<ShiftList :mode="mode" />
|
||||
|
||||
<q-btn
|
||||
v-if="mode === 'approval' || $q.platform.is.mobile && $q.screen.width < $q.screen.height"
|
||||
push
|
||||
rounded
|
||||
:disable="timesheet_store.is_loading"
|
||||
color="accent"
|
||||
icon="upload"
|
||||
:label="$t('shared.label.save')"
|
||||
class="col-auto"
|
||||
:class="$q.platform.is.mobile && $q.screen.width < $q.screen.height ? 'full-width q-mt-sm' : 'q-mr-md'"
|
||||
@click="shift_api.saveShiftChanges"
|
||||
/>
|
||||
|
||||
<q-card-section class="q-pa-none">
|
||||
<TimesheetErrorWidget />
|
||||
</q-card-section>
|
||||
|
||||
<ShiftList :mode="mode" />
|
||||
|
||||
<q-card-actions align="right">
|
||||
<q-btn
|
||||
v-if="mode === 'approval'"
|
||||
push
|
||||
rounded
|
||||
:disable="timesheet_store.is_loading"
|
||||
color="accent"
|
||||
icon="upload"
|
||||
:label="$t('shared.label.save')"
|
||||
class="q-mr-md"
|
||||
@click="shift_api.saveShiftChanges"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
<ExpenseDialog :is-approved="is_timesheets_approved"/>
|
||||
<ExpenseDialog :is-approved="is_timesheets_approved" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import { useTimesheetStore } from "src/stores/timesheet-store"
|
||||
import { useTimesheetStore } from "src/stores/timesheet-store";
|
||||
import { timesheetService } from "src/modules/timesheets/services/timesheet-service";
|
||||
|
||||
export const useTimesheetApi = () => {
|
||||
const timesheet_store = useTimesheetStore();
|
||||
|
|
@ -17,7 +18,7 @@ export const useTimesheetApi = () => {
|
|||
|
||||
const getTimesheetsByCurrentPayPeriod = async (employee_email?: string) => {
|
||||
if (timesheet_store.pay_period === undefined) return false;
|
||||
|
||||
|
||||
timesheet_store.is_loading = true;
|
||||
const success = await timesheet_store.getPayPeriodByDateOrYearAndNumber();
|
||||
|
||||
|
|
@ -29,8 +30,30 @@ export const useTimesheetApi = () => {
|
|||
timesheet_store.is_loading = false;
|
||||
};
|
||||
|
||||
const applyPreset = async (timesheet_id: number, week_day_index?: number, date?: string) => {
|
||||
if (timesheet_store.timesheets.map(timesheet => timesheet.timesheet_id).includes(timesheet_id)) {
|
||||
timesheet_store.is_loading = true;
|
||||
try {
|
||||
let response;
|
||||
|
||||
if (week_day_index && date)
|
||||
response = await timesheetService.applyPresetToDay(timesheet_id, week_day_index, date);
|
||||
else
|
||||
response = await timesheetService.applyPresetToWeek(timesheet_id);
|
||||
|
||||
if (response.success)
|
||||
await timesheet_store.getTimesheetsByOptionalEmployeeEmail();
|
||||
} catch (error) {
|
||||
console.error('Error applying weekly timesheet: ', error);
|
||||
}
|
||||
|
||||
timesheet_store.is_loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
getTimesheetsByDate,
|
||||
getTimesheetsByCurrentPayPeriod,
|
||||
applyPreset,
|
||||
};
|
||||
};
|
||||
|
|
@ -2,30 +2,41 @@ import { api } from "src/boot/axios";
|
|||
import type { PayPeriod } from "src/modules/shared/models/pay-period.models";
|
||||
import type { TimesheetResponse } from "src/modules/timesheets/models/timesheet.models";
|
||||
import type { TimesheetOverview } from "src/modules/timesheet-approval/models/timesheet-overview.models";
|
||||
import type { BackendResponse } from "src/modules/shared/models/backend-response.models";
|
||||
|
||||
export const timesheetService = {
|
||||
getPayPeriodByDate: async (date_string: string): Promise<PayPeriod> => {
|
||||
const response = await api.get<{success: boolean, data: PayPeriod, error? : string}>(`pay-periods/date/${date_string}`);
|
||||
const response = await api.get<{ success: boolean, data: PayPeriod, error?: string }>(`pay-periods/date/${date_string}`);
|
||||
return response.data.data;
|
||||
},
|
||||
|
||||
getPayPeriodByYearAndPeriodNumber: async (year: number, period_number: number): Promise<PayPeriod> => {
|
||||
const response = await api.get<{success: boolean, data: PayPeriod, error? : string}>(`pay-periods/${year}/${period_number}`);
|
||||
const response = await api.get<{ success: boolean, data: PayPeriod, error?: string }>(`pay-periods/${year}/${period_number}`);
|
||||
return response.data.data;
|
||||
},
|
||||
|
||||
getTimesheetOverviewsByPayPeriodAndSupervisorEmail: async (year: number, period_number: number, supervisor_email: string): Promise<TimesheetOverview[]> => {
|
||||
const response = await api.get<{success: boolean, data: TimesheetOverview[], error? : string}>(`pay-periods/${year}/${period_number}/${supervisor_email}`);
|
||||
const response = await api.get<{ success: boolean, data: TimesheetOverview[], error?: string }>(`pay-periods/${year}/${period_number}/${supervisor_email}`);
|
||||
return response.data.data;
|
||||
},
|
||||
|
||||
getTimesheetsByPayPeriodAndOptionalEmail: async (year: number, period_number: number, employee_email?: string): Promise<TimesheetResponse> => {
|
||||
if (employee_email !== undefined) {
|
||||
const response = await api.get<{success: boolean, data: TimesheetResponse, error? : string}>(`timesheets/${year}/${period_number}?employee_email=${employee_email}`);
|
||||
const response = await api.get<{ success: boolean, data: TimesheetResponse, error?: string }>(`timesheets/${year}/${period_number}?employee_email=${employee_email}`);
|
||||
return response.data.data;
|
||||
} else {
|
||||
const response = await api.get<{success: boolean, data: TimesheetResponse, error? : string}>(`timesheets/${year}/${period_number}`);
|
||||
const response = await api.get<{ success: boolean, data: TimesheetResponse, error?: string }>(`timesheets/${year}/${period_number}`);
|
||||
return response.data.data;
|
||||
}
|
||||
},
|
||||
|
||||
applyPresetToWeek: async (timesheet_id: number): Promise<BackendResponse<boolean>> => {
|
||||
const response = await api.post<BackendResponse<boolean>>(`schedule-presets/apply-preset`, { timesheet_id });
|
||||
return response.data;
|
||||
},
|
||||
|
||||
applyPresetToDay: async (timesheet_id: number, week_day_index: number, date: string): Promise<BackendResponse<boolean>> => {
|
||||
const response = await api.post<BackendResponse<boolean>>('schedule-presets/apply-day-preset', { timesheet_id, week_day_index, date });
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
|
|
@ -2,21 +2,14 @@
|
|||
setup
|
||||
lang="ts"
|
||||
>
|
||||
import { date } from 'quasar';
|
||||
import { onMounted } from 'vue';
|
||||
import { useAuthStore } from 'src/stores/auth-store';
|
||||
import { useTimesheetApi } from 'src/modules/timesheets/composables/use-timesheet-api';
|
||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||
import PageHeaderTemplate from 'src/modules/shared/components/page-header-template.vue';
|
||||
import TimesheetWrapper from 'src/modules/timesheets/components/timesheet-wrapper.vue';
|
||||
|
||||
import { useAuthStore } from 'src/stores/auth-store';
|
||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||
|
||||
const { user } = useAuthStore();
|
||||
const timesheet_store = useTimesheetStore();
|
||||
const timesheet_api = useTimesheetApi();
|
||||
|
||||
onMounted(async () => {
|
||||
await timesheet_api.getTimesheetsByDate(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
|
@ -33,11 +26,10 @@
|
|||
/>
|
||||
|
||||
<div
|
||||
class="col"
|
||||
:style="$q.screen.gt.sm ? 'width: 90vw' : ''"
|
||||
class="col column fit"
|
||||
:style="$q.platform.is.mobile && ($q.screen.width < $q.screen.height) ? '' : 'width: 90vw'"
|
||||
>
|
||||
<TimesheetWrapper :employee-email="user?.email ?? ''" />
|
||||
<TimesheetWrapper :employee-email="user?.email ?? ''" class="col"/>
|
||||
</div>
|
||||
|
||||
</q-page>
|
||||
</template>
|
||||
Loading…
Reference in New Issue
Block a user