feat : Ajout d'un onglet Observation sur la page employé + fonctionnalité de verrouillage utilisateur
This commit is contained in:
187
frontend/components/employees/ObservationTab.vue
Normal file
187
frontend/components/employees/ObservationTab.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<section class="mt-8">
|
||||
<div class="overflow-hidden bg-white">
|
||||
<div
|
||||
class="grid grid-cols-2 border border-black bg-tertiary-500 px-6 py-3 text-[20px] font-semibold text-black rounded-t-md">
|
||||
<p>Mois</p>
|
||||
<p>Observation</p>
|
||||
</div>
|
||||
<div v-if="observations.length === 0" class="px-6 py-4 text-[20px] font-bold text-primary-500 border-x border-b border-primary-500 rounded-b-md">
|
||||
Aucune observation.
|
||||
</div>
|
||||
<div v-else class="border-x border-b border-primary-500 rounded-b-md">
|
||||
<div
|
||||
v-for="item in observations"
|
||||
:key="item.id"
|
||||
class="grid grid-cols-2 border-b border-primary-500 px-6 py-3 text-md font-bold text-primary-500 last:border-b-0 cursor-pointer hover:bg-tertiary-500"
|
||||
@click="onOpenEditDrawer(item)"
|
||||
>
|
||||
<p>{{ formatMonth(item.month) }}</p>
|
||||
<p class="truncate">{{ item.content }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center mb-4 mt-8">
|
||||
<button
|
||||
type="button"
|
||||
class="flex w-[200px] items-center justify-center gap-2 rounded-md bg-primary-500 px-4 py-2 text-md text-white disabled:cursor-not-allowed disabled:opacity-50"
|
||||
@click="onOpenCreateDrawer"
|
||||
>
|
||||
+ Ajouter
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<AppDrawer v-model="isDrawerOpen" :title="isEditing ? 'Modification observation' : 'Nouvelle observation'">
|
||||
<form class="space-y-4" @submit.prevent="onSubmit">
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="observation-month">
|
||||
Mois <span class="text-red-600">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="observation-month"
|
||||
v-model="form.month"
|
||||
type="month"
|
||||
class="capitalize mt-2 w-full rounded-md border border-neutral-300 px-3 py-2 text-base text-neutral-900 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-secondary-500/20"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="observation-content">
|
||||
Observation <span class="text-red-600">*</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="observation-content"
|
||||
v-model="form.content"
|
||||
rows="5"
|
||||
class="mt-2 w-full rounded-md border border-neutral-300 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="Observation..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="isEditing" class="grid grid-cols-2 gap-3 pt-2">
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center justify-center rounded-md bg-red-500 px-4 py-2 text-md font-semibold text-white hover:bg-red-600"
|
||||
@click="onDelete"
|
||||
>
|
||||
Supprimer
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="flex items-center justify-center rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
:disabled="!isFormValid"
|
||||
>
|
||||
Modifier
|
||||
</button>
|
||||
</div>
|
||||
<div v-else class="flex justify-center pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
class="flex w-[200px] items-center justify-center gap-2 rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
:disabled="!isFormValid"
|
||||
>
|
||||
+ Ajouter
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Observation } from '~/services/dto/observation'
|
||||
import AppDrawer from '~/components/AppDrawer.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
observations: Observation[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'create', data: { month: string; content: string }): void
|
||||
(event: 'update', id: number, data: { month: string; content: string }): void
|
||||
(event: 'delete', id: number): void
|
||||
}>()
|
||||
|
||||
const isDrawerOpen = ref(false)
|
||||
const isEditing = ref(false)
|
||||
const editingItem = ref<Observation | null>(null)
|
||||
|
||||
const currentYearMonth = () => {
|
||||
const now = new Date()
|
||||
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
const form = reactive({
|
||||
month: currentYearMonth(),
|
||||
content: ''
|
||||
})
|
||||
|
||||
const isFormValid = computed(() => {
|
||||
return form.month && form.content.trim().length > 0
|
||||
})
|
||||
|
||||
const monthLabels: Record<number, string> = {
|
||||
1: 'Janvier',
|
||||
2: 'Février',
|
||||
3: 'Mars',
|
||||
4: 'Avril',
|
||||
5: 'Mai',
|
||||
6: 'Juin',
|
||||
7: 'Juillet',
|
||||
8: 'Août',
|
||||
9: 'Septembre',
|
||||
10: 'Octobre',
|
||||
11: 'Novembre',
|
||||
12: 'Décembre'
|
||||
}
|
||||
|
||||
const formatMonth = (dateStr: string): string => {
|
||||
const date = new Date(dateStr)
|
||||
if (Number.isNaN(date.getTime())) return dateStr
|
||||
const month = date.getMonth() + 1
|
||||
const year = date.getFullYear()
|
||||
return `${monthLabels[month]} ${year}`
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
form.month = currentYearMonth()
|
||||
form.content = ''
|
||||
}
|
||||
|
||||
const onOpenCreateDrawer = () => {
|
||||
isEditing.value = false
|
||||
editingItem.value = null
|
||||
resetForm()
|
||||
isDrawerOpen.value = true
|
||||
}
|
||||
|
||||
const onOpenEditDrawer = (item: Observation) => {
|
||||
isEditing.value = true
|
||||
editingItem.value = item
|
||||
form.month = item.month.substring(0, 7)
|
||||
form.content = item.content
|
||||
isDrawerOpen.value = true
|
||||
}
|
||||
|
||||
const onSubmit = () => {
|
||||
const data = {
|
||||
month: `${form.month}-01`,
|
||||
content: form.content
|
||||
}
|
||||
|
||||
if (isEditing.value && editingItem.value) {
|
||||
emit('update', editingItem.value.id, data)
|
||||
} else {
|
||||
emit('create', data)
|
||||
}
|
||||
isDrawerOpen.value = false
|
||||
}
|
||||
|
||||
const onDelete = () => {
|
||||
if (!editingItem.value) return
|
||||
const ok = window.confirm('Supprimer cette observation ?')
|
||||
if (!ok) return
|
||||
emit('delete', editingItem.value.id)
|
||||
isDrawerOpen.value = false
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user