247 lines
12 KiB
Vue
247 lines
12 KiB
Vue
<script
|
|
setup
|
|
lang="ts"
|
|
>
|
|
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 { 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 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;
|
|
const new_shift = new Shift;
|
|
new_shift.date = date;
|
|
new_shift.timesheet_id = timesheet_id;
|
|
day_shifts.push(new_shift);
|
|
};
|
|
|
|
const deleteUnsavedShift = (timesheet_index: number, day_index: number) => {
|
|
if (timesheet_store.timesheets !== undefined) {
|
|
const day = timesheet_store.timesheets[timesheet_index]!.days[day_index]!;
|
|
const shifts_without_deleted_shift = day.shifts.filter(shift => shift.id !== 0);
|
|
day.shifts = shifts_without_deleted_shift;
|
|
}
|
|
}
|
|
|
|
const getDayApproval = (day: TimesheetDay) => {
|
|
if (day.shifts.length < 1) return false;
|
|
return day.shifts.every(shift => shift.is_approved === true);
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<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' }"
|
|
>
|
|
<div :class="$q.platform.is.mobile ? 'column' : 'row'">
|
|
|
|
<div
|
|
v-for="timesheet, timesheet_index in timesheet_store.timesheets"
|
|
:key="timesheet.timesheet_id"
|
|
class="col"
|
|
>
|
|
<transition
|
|
appear
|
|
enter-active-class="animated fadeInDown"
|
|
leave-active-class="animated fadeOutUp"
|
|
>
|
|
<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-icon
|
|
name="las la-calendar-week"
|
|
color="accent"
|
|
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>
|
|
</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> |