feat(timesheet): i18n for timesheet page

This commit is contained in:
Matthieu Haineault 2025-09-05 16:07:29 -04:00
parent 29f5760c62
commit d0b0f2df6c
5 changed files with 92 additions and 30 deletions

View File

@ -249,7 +249,31 @@ export default {
timeSheets: 'Time sheet', timeSheets: 'Time sheet',
timeSheetValidations: 'Time sheet', timeSheetValidations: 'Time sheet',
}, },
timeSheet: { timesheet: {
//employee's timesheet page
days: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
nav_button: {
calendar_date_picker:'Calendar',
current_week:'This week',
next_week:'Next week',
previous_week:'Previous week',
},
save_button:'Save',
shift_types: 'Shift`s Type',
shiftTypes: {
EMERGENCY: 'Emergency',
EVENING: 'Evening',
HOLIDAY: 'Holiday',
REGULAR: 'Regular',
SICK: 'Sick Leave',
VACATION: 'Vacation',
WORK_FROM_HOME: 'Work from home',
},
fields: {
start:'Start',
end:'End',
},
//rest
timeSheetTab_1: 'Shifts', timeSheetTab_1: 'Shifts',
timeSheetTab_2: 'Expenses', timeSheetTab_2: 'Expenses',
templateButton: 'Apply Templates', templateButton: 'Apply Templates',

View File

@ -299,7 +299,31 @@ export default {
noResultsLabel: 'Le filtre na révélé aucun résultat', noResultsLabel: 'Le filtre na révélé aucun résultat',
noDataLabel: 'Je nai rien trouvé pour toi', noDataLabel: 'Je nai rien trouvé pour toi',
}, },
timeSheet: { timesheet: {
//employee's timesheet page
days: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'],
nav_button: {
calendar_date_picker:'Calendrier',
current_week:'Semaine actuelle',
next_week:'Prochaine semaine',
previous_week:'Semaine précédente',
},
save_button:'Enregistrer',
shift_types: 'Type de quart',
shiftTypes: {
EMERGENCY: 'Urgence',
EVENING: 'Soir',
HOLIDAY: 'Férier',
SICK: 'Absence',
REGULAR: 'Régulier',
VACATION: 'Vacance',
WORK_FROM_HOME: 'Télétravail',
},
fields: {
start:'Entrée',
end:'Sortie',
},
//rest
timeSheetTab_1: 'Quarts de travail', timeSheetTab_1: 'Quarts de travail',
timeSheetTab_2: 'Dépenses', timeSheetTab_2: 'Dépenses',
templateButton: 'Appliquer le modèle', templateButton: 'Appliquer le modèle',

View File

@ -27,7 +27,7 @@
</script> </script>
<template> <template>
<div class="row q-mb-lg q-mt-lg col-12" > <div class="row q-mb-lg q-mt-lg" >
<q-btn <q-btn
push rounded push rounded
icon="keyboard_arrow_left" icon="keyboard_arrow_left"
@ -40,7 +40,7 @@
anchor="top middle" anchor="top middle"
self="center middle" self="center middle"
class="bg-primary text-uppercase text-weight-bold" class="bg-primary text-uppercase text-weight-bold"
> Semaine précédante > {{ $t( 'timesheet.nav_button.previous_week' )}}
</q-tooltip> </q-tooltip>
</q-btn> </q-btn>
<q-btn <q-btn
@ -55,7 +55,7 @@
anchor="top middle" anchor="top middle"
self="center middle" self="center middle"
class="bg-primary text-uppercase text-weight-bold" class="bg-primary text-uppercase text-weight-bold"
>Cette Semaine >{{ $t('timesheet.nav_button.current_week') }}
</q-tooltip> </q-tooltip>
</q-btn> </q-btn>
<q-btn <q-btn
@ -70,7 +70,7 @@
anchor="top middle" anchor="top middle"
self="center middle" self="center middle"
class="bg-primary text-uppercase text-weight-bold" class="bg-primary text-uppercase text-weight-bold"
> calendrier >{{ $t('timesheet.nav_button.calendar_date_picker') }}
</q-tooltip> </q-tooltip>
</q-btn> </q-btn>
<q-btn <q-btn
@ -85,7 +85,7 @@
anchor="top middle" anchor="top middle"
self="center middle" self="center middle"
class="bg-primary text-uppercase text-weight-bold" class="bg-primary text-uppercase text-weight-bold"
> Semaine suivante > {{ $t('timesheet.nav_button.next_week') }}
</q-tooltip> </q-tooltip>
</q-btn> </q-btn>
</div> </div>

View File

@ -9,6 +9,7 @@ import TimesheetNavigation from './timesheet-navigation.vue';
import type { CreateShiftPayload } from '../../types/timesheet-shift-interface'; import type { CreateShiftPayload } from '../../types/timesheet-shift-interface';
import { useTimesheetApi } from '../../composables/use-timesheet-api'; import { useTimesheetApi } from '../../composables/use-timesheet-api';
import { date as qdate } from 'quasar'; import { date as qdate } from 'quasar';
import { useI18n } from 'vue-i18n';
type ShiftRow = { type ShiftRow = {
type: string; type: string;
@ -18,6 +19,8 @@ type ShiftRow = {
is_approved: boolean; is_approved: boolean;
} }
const { t, tm } = useI18n();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'save', payload: CreateShiftPayload[]): void; (e: 'save', payload: CreateShiftPayload[]): void;
}>(); }>();
@ -25,10 +28,15 @@ const emit = defineEmits<{
const timesheet_store = useTimesheetStore(); const timesheet_store = useTimesheetStore();
const timesheet_api = useTimesheetApi(); const timesheet_api = useTimesheetApi();
const shift_type = ref<string[]> (['Régulier','Télétravail', 'Soir', 'Urgence', 'Férier', 'Vacance', 'Maladie']); const SHIFT_KEY = ['REGULAR','WORK_FROM_HOME', 'EVENING', 'EMERGENCY', 'HOLIDAY', 'VACATION', 'SICK'] as const;
const days = ['Dimanche', 'Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi']; const days = computed(()=> (tm('timesheet.days') as string[]) ?? []);
const empty_row = { type: '', start_time: '', end_time: '', comment: '', is_approved: false };
const shift_options = computed(()=> SHIFT_KEY.map(key => ({ value: key, label: t(`timeSheet.shiftType.${key}`)})));
const shift_type = computed(() => SHIFT_KEY.map(key => (`timesheet.shiftTypes.${key}`)));
const empty_row = { type: '', start_time: '', end_time: '', comment: '', is_approved: false };
//Week dates //Week dates
const week_dates = computed(() => { const week_dates = computed(() => {
const start_date = timesheet_store.current_timesheet.start_day; const start_date = timesheet_store.current_timesheet.start_day;
@ -49,7 +57,7 @@ const week_dates = computed(() => {
//filling timesheet with shifts //filling timesheet with shifts
const rows = ref<ShiftRow[]>( const rows = ref<ShiftRow[]>(
days.map((_,index) => { days.value.map((_,index) => {
const date_ISO = week_dates.value[index]; const date_ISO = week_dates.value[index];
const shift = timesheet_store.current_timesheet.shifts.find(sh => sh.date === date_ISO); const shift = timesheet_store.current_timesheet.shifts.find(sh => sh.date === date_ISO);
return shift ? { return shift ? {
@ -124,7 +132,7 @@ watch(
() => [timesheet_store.current_timesheet.start_day, timesheet_store.current_timesheet.shifts], () => [timesheet_store.current_timesheet.start_day, timesheet_store.current_timesheet.shifts],
() => { () => {
const dates = week_dates.value; const dates = week_dates.value;
rows.value = days.map((_, idx)=> { rows.value = days.value.map((_, idx)=> {
const shift = timesheet_store.current_timesheet.shifts.find(sh => sh.date === dates[idx]); const shift = timesheet_store.current_timesheet.shifts.find(sh => sh.date === dates[idx]);
return shift return shift
? { type: shift.bank_type || '', start_time: shift.start_time || '', end_time: shift.end_time || '', comment: shift.description || '', is_approved: shift.is_approved} ? { type: shift.bank_type || '', start_time: shift.start_time || '', end_time: shift.end_time || '', comment: shift.description || '', is_approved: shift.is_approved}
@ -144,13 +152,15 @@ watch(
transition-hide="fade" transition-hide="fade"
persistent persistent
> >
<!-- comment popup -->
<TimesheetShiftComment <TimesheetShiftComment
:comment-string="selected_row?.comment ?? ''" :comment-string="selected_row?.comment ?? ''"
@click-save="setComment" @click-save="setComment"
@click-close="show_comment = false" @click-close="show_comment = false"
/> />
</q-dialog> </q-dialog>
<q-form autofocus class="q-ml-xl"> <q-form autofocus>
<!-- navigation buttons -->
<TimesheetNavigation <TimesheetNavigation
:is-disabled="timesheet_store.is_loading" :is-disabled="timesheet_store.is_loading"
:is-previous-limit="is_calendar_limit" :is-previous-limit="is_calendar_limit"
@ -160,13 +170,15 @@ watch(
@pressed-next-button="timesheet_api.next_week()" @pressed-next-button="timesheet_api.next_week()"
/> />
<div v-for="row, index in rows" :key="index" class="row q-gutter-sm q-mb-sm"> <div v-for="row, index in rows" :key="index" class="row q-gutter-sm q-mb-sm">
<!--Week days-->
<span class="text-weight-bold text-primary col-1">{{ days[index] }}</span> <span class="text-weight-bold text-primary col-1">{{ days[index] }}</span>
<!-- type selection -->
<q-select <q-select
v-model="row.type" v-model="row.type"
:options="shift_type" :options="shift_type"
:readonly="row.is_approved" :readonly="row.is_approved"
class="col-2" class="col-1"
label="Type de Quart" :label="$t('timesheet.shift_types')"
dense dense
filled filled
color="primary" color="primary"
@ -175,11 +187,12 @@ watch(
map-options map-options
hide-dropdown-icon hide-dropdown-icon
/> />
<!-- start time input -->
<q-input <q-input
v-model="row.start_time" v-model="row.start_time"
:readonly="row.is_approved" :readonly="row.is_approved"
class="col-2" class="col-auto"
label="Entrée" :label="$t('timesheet.fields.start')"
dense dense
filled filled
color="primary" color="primary"
@ -187,38 +200,39 @@ watch(
step="300" step="300"
standout="bg-primary text-white" standout="bg-primary text-white"
/> />
<!-- end time input -->
<q-input <q-input
v-model="row.end_time" v-model="row.end_time"
:readonly="row.is_approved" :readonly="row.is_approved"
class="col-2" class="col-auto"
label="Sortie" :label="$t('timesheet.fields.end')"
dense dense
filled filled
clearable
color="primary" color="primary"
type="time" type="time"
step="300" step="300"
standout="bg-primary text-white" standout="bg-primary text-white"
/> />
<!-- comment icon -->
<q-btn <q-btn
:icon="row.comment.length > 0 ? 'announcement':'chat_bubble_outline'" :icon="row.comment.length > 0 ? 'announcement':'chat_bubble_outline'"
:color="row.comment.length > 0 ? 'primary' : 'grey-8'" :color="row.comment.length > 0 ? 'primary' : 'grey-8'"
:disable="row.is_approved" :disable="row.is_approved"
flat flat
class="col-1" class="col-auto"
@click="onClickComment(index)" @click="onClickComment(index)"
/> />
<!-- reset entries icon -->
<q-btn <q-btn
icon="cleaning_services" icon="cleaning_services"
flat flat
dense dense
class="q-pa-none q-ma-none justify-right" class="q-pa-none q-ma-none justify-right col-1"
:color="row.type.length || row.start_time.length || row.end_time.length || row.comment.length > 0 ? 'primary' : 'accent'" :color="row.type.length || row.start_time.length || row.end_time.length || row.comment.length > 0 ? 'primary' : 'accent'"
@click="clearRow(index)" @click="clearRow(index)"
/> />
</div> </div>
</q-form> <!-- save button -->
<q-card-actions align="right">
<q-btn <q-btn
color="primary" color="primary"
icon="save_alt" icon="save_alt"
@ -231,9 +245,9 @@ watch(
anchor="top middle" anchor="top middle"
self="center middle" self="center middle"
class="bg-primary text-uppercase text-weight-bold" class="bg-primary text-uppercase text-weight-bold"
>Sauvegarder >{{ $t('timesheet.save_button') }}
</q-tooltip> </q-tooltip>
</q-btn> </q-btn>
</q-card-actions> </q-form>
</q-card> </q-card>
</template> </template>

View File

@ -55,7 +55,7 @@ import type { CreateShiftPayload } from '../types/timesheet-shift-interface';
{{ timesheet_label.start_date }} {{ timesheet_label.start_date }}
</div> </div>
<div class="text-grey-8 text-weight-bold text-uppercase q-mx-md"> <div class="text-grey-8 text-weight-bold text-uppercase q-mx-md">
{{ $t('timeSheet.dateRangesTo') }} {{ $t('timesheet.dateRangesTo') }}
</div> </div>
<div class="text-primary text-h6 text-uppercase"> <div class="text-primary text-h6 text-uppercase">
{{ timesheet_label.end_date }} {{ timesheet_label.end_date }}