fix(timesheet): minor fixes to UI and time regex

This commit is contained in:
Matthieu Haineault 2025-09-16 15:37:01 -04:00
parent 008b1363b5
commit 10a62219ef
4 changed files with 49 additions and 22 deletions

View File

@ -323,7 +323,7 @@ export default {
shift_types: { shift_types: {
EMERGENCY: 'Urgence', EMERGENCY: 'Urgence',
EVENING: 'Soir', EVENING: 'Soir',
HOLIDAY: 'Férier', HOLIDAY: 'Férié',
OVERTIME: 'Supplémentaire', OVERTIME: 'Supplémentaire',
SICK: 'Absence', SICK: 'Absence',
REGULAR: 'Régulier', REGULAR: 'Régulier',

View File

@ -37,11 +37,13 @@ import { computed } from 'vue';
const get_text_color = (type: string): string => { const get_text_color = (type: string): string => {
switch(type) { switch(type) {
case 'REGULAR': return 'grey-8'; case 'REGULAR': return 'grey-8';
case '': return 'transparent'; case '': return 'grey-5';
default: return 'white'; default: return 'white';
} }
} }
const on_click_edit = () => emit('request-edit', { shift: props.shift }); const on_click_edit = (type: string) => {
if(type !== '') { emit('request-edit', { shift: props.shift })};
}
const on_click_delete = () => emit('request-delete', { shift: props.shift }); const on_click_delete = () => emit('request-delete', { shift: props.shift });
</script> </script>
@ -49,9 +51,10 @@ const on_click_delete = () => emit('request-delete', { shift: props.shift });
<template> <template>
<q-card-section <q-card-section
horizontal horizontal
class="q-pa-none text-uppercase text-center items-center cursor-pointer rounded-10" class="q-pa-none text-uppercase text-center items-center rounded-10"
:class="props.shift.type === '' ? '': 'cursor-pointer'"
style="line-height: 1;" style="line-height: 1;"
@click.stop="on_click_edit" @click.stop="on_click_edit(props.shift.type)"
> >
<!-- punch-in timestamps --> <!-- punch-in timestamps -->
<q-card-section class="q-pa-none col"> <q-card-section class="q-pa-none col">

View File

@ -29,7 +29,7 @@ export interface UpsertShiftsResponse {
day: DayShift[]; day: DayShift[];
} }
export const TIME_FORMAT_PATTERN = /^([01]\d|2[0-3]):([0-5]\d)$/; export const TIME_FORMAT_PATTERN = /^\d{2}:\d{2}$/;
export const DATE_FORMAT_PATTERN = /^\d{4}-\d{2}-\d{2}$/; export const DATE_FORMAT_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
export const COMMENT_MAX_LENGTH = 512 as const; export const COMMENT_MAX_LENGTH = 512 as const;

View File

@ -2,8 +2,8 @@
import { useTimesheetStore } from 'src/stores/timesheet-store'; import { useTimesheetStore } from 'src/stores/timesheet-store';
import { useAuthStore } from 'src/stores/auth-store'; import { useAuthStore } from 'src/stores/auth-store';
import { useTimesheetApi } from '../composables/use-timesheet-api'; import { useTimesheetApi } from '../composables/use-timesheet-api';
import { computed, onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { computed, onMounted, ref } from 'vue';
import { date } from 'quasar'; import { date } from 'quasar';
import TimesheetNavigation from '../components/timesheet/timesheet-navigation.vue'; import TimesheetNavigation from '../components/timesheet/timesheet-navigation.vue';
import ShiftsLegend from '../components/shift/shifts-legend.vue'; import ShiftsLegend from '../components/shift/shifts-legend.vue';
@ -58,11 +58,6 @@ onMounted( async () => {
await loadByDate(date.formatDate(new Date(), 'YYYY-MM-DD' )); await loadByDate(date.formatDate(new Date(), 'YYYY-MM-DD' ));
}); });
const reload_current_period = async () => {
await timesheet_store.getPayPeriodByDate(date.formatDate(new Date(), 'YYYY-MM-DD'));
await timesheet_store.getTimesheetsByPayPeriodAndEmail(auth_store.user.email);
};
type FormMode = 'create' | 'edit' | 'delete'; type FormMode = 'create' | 'edit' | 'delete';
const is_dialog_open = ref<boolean>(false); const is_dialog_open = ref<boolean>(false);
@ -158,6 +153,7 @@ const submit_dialog = async () => {
await upsert_shifts_by_date(email, date_iso, body); await upsert_shifts_by_date(email, date_iso, body);
await timesheet_store.getTimesheetsByPayPeriodAndEmail(email); await timesheet_store.getTimesheetsByPayPeriodAndEmail(email);
close_dialog();
is_dialog_open.value = false; is_dialog_open.value = false;
} catch (e:any) { } catch (e:any) {
const status = e?.status_code ?? e?.response?.status ?? 500; const status = e?.status_code ?? e?.response?.status ?? 500;
@ -175,7 +171,10 @@ const submit_dialog = async () => {
} }
}; };
const close_dialog = () => { is_dialog_open.value = false; }; const close_dialog = () => {
error_banner.value = null;
is_dialog_open.value = false;
};
const on_request_add = ({ date }: { date: string }) => open_create_dialog(date); const on_request_add = ({ date }: { date: string }) => open_create_dialog(date);
const on_request_edit = ({ date, shift }: { date: string; shift: any }) => open_edit_dialog(date, shift); const on_request_edit = ({ date, shift }: { date: string; shift: any }) => open_edit_dialog(date, shift);
@ -262,10 +261,20 @@ const on_request_delete = async ({ date, shift }: { date: string; shift: any })
<div class="col"> <div class="col">
<q-input <q-input
v-model="start_time" v-model="start_time"
:label="$t('timesheet.fields.start')" filled dense inputmode="numeric" mask="##:##" /> :label="$t('timesheet.fields.start')"
filled dense
inputmode="numeric"
mask="##:##"
/>
</div> </div>
<div class="col"> <div class="col">
<q-input v-model="end_time" :label="$t('timesheet.fields.end')" filled dense inputmode="numeric" mask="##:##" /> <q-input
v-model="end_time"
:label="$t('timesheet.fields.end')"
filled dense
inputmode="numeric"
mask="##:##"
/>
</div> </div>
</div> </div>
<div class="row items-center"> <div class="row items-center">
@ -276,15 +285,22 @@ const on_request_delete = async ({ date, shift }: { date: string; shift: any })
:label="$t('timesheet.shift_types_label')" :label="$t('timesheet.shift_types_label')"
class="col" class="col"
color="primary" color="primary"
filled filled dense
dense
hide-dropdown-icon hide-dropdown-icon
emit-value emit-value
map-options map-options
/> />
<q-toggle v-model="is_remote" :label="$t('timesheet.shift_types.REMOTE')" class="col-auto" /> <q-toggle
v-model="is_remote"
:label="$t('timesheet.shift_types.REMOTE')"
class="col-auto" />
</div> </div>
<q-input v-model="comment" type="textarea" autogrow filled dense :label="$t('timesheet.fields.header_comment')" :counter="true" :maxlength="512" /> <q-input
v-model="comment"
type="textarea"
autogrow filled dense
:label="$t('timesheet.fields.header_comment')"
:counter="true" :maxlength="512" />
</div> </div>
<div v-else class="q-pa-md"> <div v-else class="q-pa-md">
@ -306,16 +322,24 @@ const on_request_delete = async ({ date, shift }: { date: string; shift: any })
<q-separator spaced /> <q-separator spaced />
<div class="row justify-end q-gutter-sm"> <div class="row justify-end q-gutter-sm">
<q-btn flat color="grey-8" :label="$t('timesheet.cancel_button')" @click="close_dialog" /> <q-btn
flat
color="grey-8"
:label="$t('timesheet.cancel_button')"
@click="close_dialog" />
<q-btn <q-btn
v-if="form_mode === 'delete'" v-if="form_mode === 'delete'"
outline color="negative" icon="cancel" :label="$t('timesheet.delete_button')" outline color="negative"
icon="cancel"
:label="$t('timesheet.delete_button')"
:loading="is_submitting" :loading="is_submitting"
@click="submit_dialog" @click="submit_dialog"
/> />
<q-btn <q-btn
v-else v-else
color="primary" icon="save_alt" :label="$t('timesheet.save_button')" color="primary"
icon="save_alt"
:label="$t('timesheet.save_button')"
:loading="is_submitting" :loading="is_submitting"
@click="submit_dialog" @click="submit_dialog"
/> />