266 lines
9.5 KiB
Vue
266 lines
9.5 KiB
Vue
<script setup lang="ts">
|
|
/* eslint-disable */
|
|
import { computed, ref, watch } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
|
import TimesheetShiftComment from '../shift/timesheet-shift-comment.vue';
|
|
import TimesheetSavePayload from './timesheet-save-payload.vue';
|
|
import { Shift } from '../../types/timesheet-shift-interface';
|
|
import type { CreateShiftPayload } from '../../types/timesheet-shift-interface';
|
|
|
|
const timesheet_store = useTimesheetStore();
|
|
|
|
const { t, tm, locale } = useI18n();
|
|
|
|
const SHIFT_KEY = ['REGULAR', 'EVENING', 'EMERGENCY', 'HOLIDAY', 'VACATION', 'SICK'] as const;
|
|
const days = computed(()=> {
|
|
void locale.value;
|
|
return (tm('timesheet.days') as string[]) ?? [];
|
|
});
|
|
|
|
const shift_options = computed(()=> {
|
|
void locale.value;
|
|
return SHIFT_KEY.map(key => ({ value: key, label: t(`timesheet.shift_types.${key}`)}))
|
|
});
|
|
|
|
const empty_row = { date:'', type: '', start_time: '', end_time: '', comment: '', is_approved: false, is_remote: false };
|
|
//Week dates
|
|
const week_dates = computed(() => {
|
|
const start_date = timesheet_store.current_timesheet.start_day;
|
|
if(!start_date) return [];
|
|
|
|
const mm = /^(\d{4})-(\d{2})-(\d{2})$/.exec(start_date);
|
|
if(!mm) return [];
|
|
const year = Number(mm[1]), month = Number(mm[2]), day = Number(mm[3])
|
|
|
|
const base = new Date(Date.UTC(year, month - 1, day));
|
|
const yyyymmdd = (date: Date) => {
|
|
const yyyy = date.getFullYear();
|
|
const mm = String(date.getUTCMonth() + 1).padStart(2,'0');
|
|
const dd = String(date.getUTCDate()).padStart(2,'0');
|
|
return `${yyyy}-${mm}-${dd}`};
|
|
|
|
return Array.from({length:7 }, (_, i) => {
|
|
const date = new Date(base);
|
|
date.setUTCDate(base.getDate() + i);
|
|
return yyyymmdd(date);
|
|
});
|
|
});
|
|
|
|
//filling timesheet with shifts
|
|
const rows = ref<Shift[]>(
|
|
days.value.map((_,index) => {
|
|
const date_ISO = week_dates.value[index];
|
|
const shift = timesheet_store.current_timesheet.shifts.find(sh => sh.date === date_ISO);
|
|
return shift ? {
|
|
date:shift.date || '',
|
|
type: shift.bank_type || '',
|
|
start_time: shift.start_time || '',
|
|
end_time: shift.end_time || '',
|
|
comment: shift.description || '',
|
|
is_approved: !!shift.is_approved,
|
|
is_remote: !!shift.is_remote,
|
|
}
|
|
: { ...empty_row };
|
|
})
|
|
);
|
|
const hasData = (row: Shift) => !!(row.type || row.start_time || row.end_time || row.comment);
|
|
|
|
const show_comment = ref(false);
|
|
const selected_index = ref<number | null>(null);
|
|
const selected_row = computed<Shift | undefined>(()=>
|
|
selected_index.value != null ? rows.value[selected_index.value] : undefined
|
|
);
|
|
|
|
const setComment = (comment: string) => {
|
|
if(selected_row.value) selected_row.value.comment = comment;
|
|
show_comment.value = false;
|
|
}
|
|
|
|
const onClickComment = (index: number)=> {
|
|
selected_index.value = index;
|
|
show_comment.value = true;
|
|
};
|
|
|
|
const clearRow = (index: number) => {
|
|
rows.value[index] = { ...empty_row };
|
|
}
|
|
|
|
|
|
const emit = defineEmits<{ (e: 'save', payload: CreateShiftPayload[]): void }>();
|
|
|
|
//onMounted?
|
|
watch(
|
|
() => [timesheet_store.current_timesheet.start_day, timesheet_store.current_timesheet.shifts],
|
|
() => {
|
|
const dates = week_dates.value;
|
|
rows.value = days.value.map((_, idx)=> {
|
|
const shift = timesheet_store.current_timesheet.shifts.find(sh => sh.date === dates[idx]);
|
|
return shift
|
|
? { date: shift.date || '',
|
|
type: shift.bank_type || '',
|
|
start_time: shift.start_time || '',
|
|
end_time: shift.end_time || '',
|
|
comment: shift.description || '',
|
|
is_approved: shift.is_approved,
|
|
is_remote: shift.is_remote,
|
|
}
|
|
: { date: '',
|
|
type: '',
|
|
start_time: '',
|
|
end_time: '',
|
|
comment: '',
|
|
is_approved: false,
|
|
is_remote: false
|
|
};
|
|
});
|
|
},
|
|
{ deep: true, immediate: true }
|
|
);
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<q-card class="bg-transparent q-pa-md q-ma-md">
|
|
<q-dialog
|
|
v-model="show_comment"
|
|
transition-show="fade"
|
|
transition-hide="fade"
|
|
persistent
|
|
>
|
|
<!-- comment popup -->
|
|
<TimesheetShiftComment
|
|
:comment-string="selected_row?.comment ?? ''"
|
|
@click-save="setComment"
|
|
@click-close="show_comment = false"
|
|
/>
|
|
</q-dialog>
|
|
|
|
<q-form
|
|
autofocus
|
|
class="bg-white q-pa-sm q-pt-lg rounded-10">
|
|
|
|
<div
|
|
v-for="(row, index) in rows"
|
|
:key="week_dates[index] ?? index"
|
|
class="q-gutter-sm q-mb-sm"
|
|
:class="$q.screen.lt.md ? 'column' : 'row'" >
|
|
<!--Week days-->
|
|
<span class="text-weight-bold text-primary col-1">{{ days[index] }}</span>
|
|
<!-- remote work toggle -->
|
|
<q-toggle
|
|
v-model="row.is_remote"
|
|
:disable="row.is_approved"
|
|
color="primary"
|
|
checked-icon="home_work"
|
|
unchecked-icon="business"
|
|
icon="home_work"
|
|
class="col-auto q-ml-sm"
|
|
>
|
|
<q-tooltip
|
|
anchor="top middle"
|
|
self="center middle"
|
|
class="bg-primary text-uppercase text-weight-bold"
|
|
>{{ $t('timesheet.remote_button') }}
|
|
</q-tooltip>
|
|
</q-toggle>
|
|
<!-- type selection -->
|
|
<q-select
|
|
v-model="row.type"
|
|
:options="shift_options"
|
|
:readonly="row.is_approved"
|
|
class="col-3"
|
|
:label="$t('timesheet.shift_types_label')"
|
|
dense
|
|
filled
|
|
color="primary"
|
|
standout="bg-primary text-white"
|
|
options-dense
|
|
emit-value
|
|
map-options
|
|
option-value="value"
|
|
option-label="label"
|
|
hide-dropdown-icon
|
|
/>
|
|
<!-- start time input -->
|
|
<q-input
|
|
v-model="row.start_time"
|
|
:readonly="row.is_approved"
|
|
class="col-auto"
|
|
:label="$t('timesheet.fields.start')"
|
|
dense
|
|
filled
|
|
color="primary"
|
|
type="time"
|
|
step="300"
|
|
standout="bg-primary text-white"
|
|
/>
|
|
<!-- end time input -->
|
|
<q-input
|
|
v-model="row.end_time"
|
|
:readonly="row.is_approved"
|
|
class="col-auto"
|
|
:label="$t('timesheet.fields.end')"
|
|
dense
|
|
filled
|
|
color="primary"
|
|
type="time"
|
|
step="300"
|
|
standout="bg-primary text-white"
|
|
/>
|
|
<div class="col-3">
|
|
<!-- comment button -->
|
|
<q-btn
|
|
:icon="row.comment.length > 0 ? 'announcement':'chat_bubble_outline'"
|
|
:color="row.comment.length > 0 ? 'primary' : 'grey-8'"
|
|
:disable="row.is_approved"
|
|
flat
|
|
class="col-auto"
|
|
@click="onClickComment(index)"
|
|
/>
|
|
<!-- expense button -->
|
|
<q-btn
|
|
:icon="row.comment.length > 0 ? 'receipt_long':'attach_money'"
|
|
flat
|
|
dense
|
|
class="q-pa-none q-ma-sm col-1"
|
|
:color="hasData(row) ? 'primary' : 'grey-8'"
|
|
@click="clearRow(index)"
|
|
/>
|
|
|
|
</div>
|
|
<!-- reset entries button -->
|
|
<q-btn
|
|
icon="cleaning_services"
|
|
flat
|
|
dense
|
|
class="q-pa-none q-ma-sm col-auto"
|
|
:color="hasData(row) ? 'primary' : 'grey-4'"
|
|
@click="clearRow(index)"
|
|
/>
|
|
<!-- add one more shift buttons -->
|
|
<q-btn
|
|
icon="more_time"
|
|
flat
|
|
dense
|
|
class="q-pa-none q-ma-sm col-auto"
|
|
color="primary"
|
|
>
|
|
<q-tooltip
|
|
anchor="top middle"
|
|
self="center middle"
|
|
class="bg-primary text-uppercase text-weight-bold"
|
|
>{{ $t('timesheet.add_shift') }}
|
|
</q-tooltip>
|
|
</q-btn>
|
|
</div>
|
|
<TimesheetSavePayload
|
|
:week_dates="week_dates"
|
|
:rows="rows"
|
|
@save="(payload) => emit('save', payload)"
|
|
/>
|
|
</q-form>
|
|
|
|
</q-card>
|
|
|
|
</template> |