fix : drawer commentaire de semaine — toasts, titre et UI Malio

- Ajoute les clés i18n manquantes (success/errors weekComment.save/delete) qui faisaient afficher la clé brute dans le toast.
- Titre du drawer simplifié à "Commentaire" ; semaine (S{n}) et plage de dates affichées sous le nom de l'employé.
- Drawer, textarea et boutons migrés vers les composants Malio UI ; bouton Annuler supprimé.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-29 17:43:42 +02:00
parent 0f6577aedc
commit d595d323b3
4 changed files with 40 additions and 18 deletions

View File

@@ -96,7 +96,7 @@
</p> </p>
<p class="text-[11px] text-neutral-500 truncate inline-flex items-center gap-2"> <p class="text-[11px] text-neutral-500 truncate inline-flex items-center gap-2">
<span>{{ row.siteName ?? 'Sans site' }}<span v-if="row.contractNature"> {{ contractNatureLabel(row.contractNature) }}</span></span> <span>{{ row.siteName ?? 'Sans site' }}<span v-if="row.contractNature"> {{ contractNatureLabel(row.contractNature) }}</span></span>
<button v-if="isAdmin" type="button" class="inline-flex items-center justify-center rounded-md p-1 text-white transition-colors" :class="row.comment ? 'bg-red-500 hover:bg-red-600' : 'bg-primary-500 hover:bg-secondary-500'" :title="row.comment ?? 'Ajouter un commentaire'" @click="$emit('open-comment', row)"> <button v-if="isAdmin" type="button" class="flex items-center text-white p-1" :class="row.comment ? 'bg-red-500 hover:bg-red-600' : 'bg-primary-500 hover:bg-secondary-500'" :title="row.comment ?? 'Ajouter un commentaire'" @click="$emit('open-comment', row)">
<Icon name="mdi:comment-text-outline" size="12"/> <Icon name="mdi:comment-text-outline" size="12"/>
</button> </button>
</p> </p>

View File

@@ -1,27 +1,39 @@
<template> <template>
<AppDrawer v-model="drawerOpen" :title="`Commentaire — ${formatWeekRange}`"> <MalioDrawer v-model="drawerOpen" title="Commentaire">
<form class="space-y-4" @submit.prevent="onSave"> <form class="space-y-4" @submit.prevent="onSave">
<div v-if="employeeLabel" class="text-md font-semibold text-neutral-700">{{ employeeLabel }}</div> <div v-if="employeeLabel" class="text-md font-semibold text-neutral-700">{{ employeeLabel }}</div>
<div> <div class="text-md font-semibold text-neutral-700">{{ formatWeekRange }}</div>
<label class="text-md font-semibold text-neutral-700" for="week-comment-content">Commentaire</label> <MalioInputTextArea
<textarea id="week-comment-content" v-model="content" rows="8" maxlength="5000" class="mt-2 w-full rounded-md border border-neutral-300 bg-white px-3 py-2 text-base text-neutral-900 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-secondary-500/20" placeholder="Ex. Arrêt maladie lundi, reprise jeudi..." /> v-model="content"
<p class="mt-1 text-xs text-neutral-400">{{ content.length }} / 5000</p> label="Commentaire"
</div> :size="8"
:max-length="5000"
:show-counter="true"
resize="vertical"
/>
<div class="sticky bottom-0 -mx-[20px] bg-white px-[20px] py-3 flex justify-between gap-3"> <div class="sticky bottom-0 -mx-[20px] bg-white px-[20px] py-3 flex justify-between gap-3">
<button v-if="commentId" type="button" class="rounded-lg bg-red-500 px-4 py-2 text-md font-semibold text-white hover:bg-red-600 disabled:opacity-50" :disabled="isSubmitting" @click="onDelete">Supprimer</button> <MalioButton
<div class="flex gap-3 ml-auto"> v-if="commentId"
<button type="button" class="rounded-lg border border-neutral-200 px-4 py-2 text-md font-semibold text-neutral-700 hover:bg-neutral-100" @click="drawerOpen = false">Annuler</button> label="Supprimer"
<button type="submit" class="rounded-lg bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:opacity-50" :disabled="isSubmitting || !canSubmit">Enregistrer</button> variant="danger"
</div> :disabled="isSubmitting"
@click="onDelete"
/>
<MalioButton
label="Enregistrer"
button-class="ml-auto"
:disabled="isSubmitting || !canSubmit"
@click="onSave"
/>
</div> </div>
</form> </form>
</AppDrawer> </MalioDrawer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, watch } from 'vue' import { computed, ref, watch } from 'vue'
import AppDrawer from '~/components/AppDrawer.vue'
import { createWeekComment, deleteWeekComment, updateWeekComment } from '~/services/employee-week-comments' import { createWeekComment, deleteWeekComment, updateWeekComment } from '~/services/employee-week-comments'
import { getIsoWeekNumber, parseYmd } from '~/utils/date'
const props = defineProps<{ const props = defineProps<{
modelValue: boolean modelValue: boolean
@@ -42,7 +54,9 @@ watch(() => [props.modelValue, props.initialContent] as const, ([open, init]) =>
const formatWeekRange = computed(() => { const formatWeekRange = computed(() => {
const fmt = (ymd: string) => { const p = ymd.split('-'); return p.length === 3 ? `${p[2]}/${p[1]}/${p[0]}` : ymd } const fmt = (ymd: string) => { const p = ymd.split('-'); return p.length === 3 ? `${p[2]}/${p[1]}/${p[0]}` : ymd }
return `${fmt(props.weekStart)}${fmt(props.weekEnd)}` const start = parseYmd(props.weekStart)
const weekLabel = start ? `S${getIsoWeekNumber(start)}` : ''
return weekLabel ? `${weekLabel} du ${fmt(props.weekStart)} au ${fmt(props.weekEnd)}` : `${fmt(props.weekStart)}${fmt(props.weekEnd)}`
}) })
const canSubmit = computed(() => content.value.trim().length > 0 || props.commentId !== null) const canSubmit = computed(() => content.value.trim().length > 0 || props.commentId !== null)

View File

@@ -59,6 +59,10 @@
}, },
"leaveRecap": { "leaveRecap": {
"load": "Impossible de charger le récap des congés." "load": "Impossible de charger le récap des congés."
},
"weekComment": {
"save": "Impossible d'enregistrer le commentaire de semaine.",
"delete": "Impossible de supprimer le commentaire de semaine."
} }
}, },
"success": { "success": {
@@ -110,6 +114,10 @@
"create": "Observation créée.", "create": "Observation créée.",
"update": "Observation mise à jour.", "update": "Observation mise à jour.",
"delete": "Observation supprimée." "delete": "Observation supprimée."
},
"weekComment": {
"save": "Commentaire enregistré.",
"delete": "Commentaire supprimé."
} }
} }
} }

View File

@@ -10,15 +10,15 @@ export const createWeekComment = async (payload: { employeeId: number; weekStart
employee: `/api/employees/${payload.employeeId}`, employee: `/api/employees/${payload.employeeId}`,
weekStartDate: payload.weekStartDate, weekStartDate: payload.weekStartDate,
content: payload.content content: payload.content
}, { toastSuccessKey: 'success.week-comment.save', toastErrorKey: 'errors.week-comment.save' }) }, { toastSuccessKey: 'success.weekComment.save', toastErrorKey: 'errors.weekComment.save' })
} }
export const updateWeekComment = async (id: number, content: string) => { export const updateWeekComment = async (id: number, content: string) => {
const api = useApi() const api = useApi()
return api.patch<EmployeeWeekComment>(`/employee_week_comments/${id}`, { content }, { toastSuccessKey: 'success.week-comment.save', toastErrorKey: 'errors.week-comment.save' }) return api.patch<EmployeeWeekComment>(`/employee_week_comments/${id}`, { content }, { toastSuccessKey: 'success.weekComment.save', toastErrorKey: 'errors.weekComment.save' })
} }
export const deleteWeekComment = async (id: number) => { export const deleteWeekComment = async (id: number) => {
const api = useApi() const api = useApi()
await api.delete(`/employee_week_comments/${id}`, {}, { toastSuccessKey: 'success.week-comment.delete', toastErrorKey: 'errors.week-comment.delete' }) await api.delete(`/employee_week_comments/${id}`, {}, { toastSuccessKey: 'success.weekComment.delete', toastErrorKey: 'errors.weekComment.delete' })
} }