273 lines
12 KiB
Vue
273 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, useQuasar } from 'quasar';
|
|
import { ref, computed, watch, onMounted } 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 { TimesheetDay } from 'src/modules/timesheets/models/timesheet.models';
|
|
import { useI18n } from 'vue-i18n';
|
|
|
|
const CURRENT_DATE_STRING = new Date().toISOString().slice(0, 10);
|
|
|
|
const emit = defineEmits<{
|
|
'onCurrentDayComponentFound': [component: HTMLElement | undefined];
|
|
}>();
|
|
|
|
const { extractDate } = date;
|
|
const { locale } = useI18n();
|
|
const q = useQuasar();
|
|
|
|
const ui_store = useUiStore();
|
|
const timesheet_store = useTimesheetStore();
|
|
const timesheet_api = useTimesheetApi();
|
|
|
|
const mobile_animation_direction = ref('fadeInLeft');
|
|
const currentDayComponent = ref<HTMLElement[] | null>(null);
|
|
const currentDayComponentWatcher = ref(currentDayComponent);
|
|
|
|
const animation_style = computed(() => ui_store.is_mobile_mode ? mobile_animation_direction.value : 'fadeInDown');
|
|
|
|
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);
|
|
};
|
|
|
|
const getMobileDayRef = (iso_date_string: string): string => {
|
|
return iso_date_string === CURRENT_DATE_STRING ? 'currentDayComponent' : '';
|
|
};
|
|
|
|
const getHolidayName = (date: string) => {
|
|
const holiday = timesheet_store.federal_holidays.find(holiday => holiday.date === date);
|
|
if (!holiday) return;
|
|
|
|
if (locale.value === 'fr-FR')
|
|
return holiday.nameFr;
|
|
|
|
else if (locale.value === 'en-CA')
|
|
return holiday.nameEn;
|
|
};
|
|
|
|
onMounted(async () => {
|
|
await timesheet_store.getCurrentFederalHolidays();
|
|
});
|
|
|
|
watch(currentDayComponentWatcher, () => {
|
|
if (currentDayComponent.value && q.platform.is.mobile) {
|
|
emit('onCurrentDayComponentFound', currentDayComponent.value[0])
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
class="fit"
|
|
:class="$q.platform.is.mobile ? 'column' : 'row'"
|
|
>
|
|
<div
|
|
v-for="timesheet, timesheet_index of timesheet_store.timesheets"
|
|
:key="timesheet.timesheet_id"
|
|
class="col column fit items-center"
|
|
>
|
|
<transition
|
|
appear
|
|
enter-active-class="animated fadeInDown"
|
|
leave-active-class="animated fadeOutUp"
|
|
>
|
|
<q-btn
|
|
v-if="!$q.platform.is.mobile && timesheet.days.every(day => day.shifts.length < 1) && timesheet_store.has_timesheet_preset"
|
|
:disable="!timesheet.days.every(day => day.shifts.length < 1)"
|
|
flat
|
|
dense
|
|
:label="$t('timesheet.apply_preset_week')"
|
|
class="col-auto text-uppercase text-weight-bold text-accent q-mx-lg q-py-none rounded-5"
|
|
@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"
|
|
:ref="getMobileDayRef(day.date)"
|
|
class="col-auto row q-pa-sm full-width relative-position"
|
|
:style="`animation-delay: ${day_index / 15}s;`"
|
|
>
|
|
<!-- optional label indicating which holiday if today is a holiday -->
|
|
<span
|
|
v-if="timesheet_store.federal_holidays.some(holiday => holiday.date === day.date)"
|
|
class="absolute-top-left text-uppercase text-weight-bolder text-purple-5"
|
|
style="transform: translate(25px, -7px);"
|
|
>
|
|
{{ getHolidayName(day.date) }}
|
|
</span>
|
|
|
|
<!-- mobile version in portrait mode -->
|
|
<div
|
|
v-if="$q.platform.is.mobile && ($q.screen.width < $q.screen.height)"
|
|
class="col column full-width q-px-md q-py-sm"
|
|
>
|
|
<q-card
|
|
class="shadow-12"
|
|
:class="(getDayApproval(day) || timesheet.is_approved) ? 'bg-accent rounded-10' : 'bg-dark mobile-rounded-10'"
|
|
>
|
|
|
|
<q-card-section
|
|
class="text-weight-bolder text-uppercase text-h6 q-py-sm text-center relative-position"
|
|
: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-icon
|
|
v-if="(getDayApproval(day) || timesheet.is_approved)"
|
|
name="verified"
|
|
size="3em"
|
|
color="white"
|
|
class="absolute-top-left z-top"
|
|
style="top: -0.2em; left: 0px;"
|
|
/>
|
|
</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-section class="q-pa-none">
|
|
<q-btn
|
|
v-if="!(getDayApproval(day) || timesheet.is_approved)"
|
|
square
|
|
dense
|
|
size="xl"
|
|
color="accent"
|
|
icon="more_time"
|
|
class="full-width"
|
|
style="border-radius: 0 0 10px 10px;"
|
|
@click="addNewShift(day.shifts, day.date, timesheet.timesheet_id)"
|
|
/>
|
|
</q-card-section>
|
|
</q-card>
|
|
</div>
|
|
|
|
<!-- desktop version -->
|
|
<div
|
|
v-else
|
|
class="col row full-width rounded-10 ellipsis shadow-10"
|
|
:style="timesheet_store.federal_holidays.some(holiday => holiday.date === day.date) ? 'border: 2px solid #ab47bc' : ''"
|
|
>
|
|
<div
|
|
class="col row"
|
|
:class="(getDayApproval(day) || timesheet.is_approved) ? (timesheet_store.federal_holidays.some(holiday => holiday.date === day.date) ? 'bg-purple-5' : 'bg-accent') : 'bg-dark'"
|
|
>
|
|
<!-- 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"
|
|
:holiday="timesheet_store.federal_holidays.some(holiday => holiday.date === day.date)"
|
|
: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"
|
|
:class="(getDayApproval(day) || timesheet.is_approved) ? (timesheet_store.federal_holidays.some(holiday => holiday.date === day.date) ? 'bg-purple-5' : 'bg-accent') : ''"
|
|
/>
|
|
|
|
<q-btn
|
|
v-else
|
|
:dense="!$q.platform.is.mobile"
|
|
square
|
|
icon="more_time"
|
|
size="lg"
|
|
:color="timesheet_store.federal_holidays.some(holiday => holiday.date === day.date) ? 'purple-5' : 'accent'"
|
|
text-color="white"
|
|
class="full-height"
|
|
:class="$q.platform.is.mobile ? 'q-px-xs' : ''"
|
|
@click="addNewShift(day.shifts, day.date, timesheet.timesheet_id)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</transition-group>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style
|
|
scoped
|
|
lang="scss"
|
|
>
|
|
@each $size in (1, 2, 3, 4, 5, 10, 15, 20, 25, 50, 75, 100, 200) {
|
|
.mobile-rounded-#{$size} {
|
|
border-radius: #{$size}px !important;
|
|
}
|
|
|
|
.mobile-rounded-#{$size}>div:first-child {
|
|
border-radius: #{$size}px #{$size}px 0 0 !important;
|
|
}
|
|
|
|
.mobile-rounded-#{$size}>div:last-child {
|
|
border-radius: 0 0 #{$size}px #{$size}px !important;
|
|
}
|
|
}
|
|
</style> |