Files
Lesstime/frontend/components/user/UserDrawer.vue
T
Matthieu 02ac151ac0
Auto Tag Develop / tag (push) Successful in 7s
feat(users) : ajout prénom et nom sur l'utilisateur
Deux colonnes nullable firstName/lastName sur User (groupes me:read,
user:list, user:write), éditables dans le drawer utilisateur (admin).
L'affichage reste basé sur le username pour l'instant. Migration +
valeurs de démo dans les fixtures.
2026-05-26 11:33:18 +02:00

165 lines
5.1 KiB
Vue

<template>
<MalioDrawer v-model="isOpen">
<template #header>
<h2 class="text-xl font-bold">{{ isEditing ? $t('users.editUser') : $t('users.addUser') }}</h2>
</template>
<form class="flex flex-col gap-2" @submit.prevent="handleSubmit">
<MalioInputText
v-model="form.username"
label="Nom d'utilisateur"
input-class="w-full"
:error="touched.username && !form.username.trim() ? 'Le nom est requis' : ''"
@blur="touched.username = true"
/>
<MalioInputText
v-model="form.firstName"
label="Prénom"
input-class="w-full"
/>
<MalioInputText
v-model="form.lastName"
label="Nom"
input-class="w-full"
/>
<MalioInputPassword
v-model="form.password"
label="Mot de passe"
input-class="w-full"
:hint="isEditing ? 'Laisser vide pour ne pas changer' : ''"
:error="touched.password && !isEditing && !form.password ? 'Le mot de passe est requis' : ''"
@blur="touched.password = true"
/>
<div class="mt-4">
<label class="text-sm font-semibold text-neutral-700">Rôles</label>
<div class="mt-2 flex flex-col gap-2">
<label
v-for="role in availableRoles"
:key="role"
class="flex items-center gap-2 text-sm text-neutral-700"
>
<input
v-model="form.roles"
type="checkbox"
:value="role"
class="rounded border-neutral-300"
/>
{{ role }}
</label>
</div>
</div>
<!-- RH / Absences -->
<div class="mt-6 border-t border-neutral-200 pt-4">
<MalioCheckbox v-model="form.isEmployee" label="Employé (soumis à la gestion des absences)" />
<p v-if="form.isEmployee" class="mt-2 text-xs text-neutral-500">
Les informations RH (contrat, dates, CP) se gèrent dans Absences équipe onglet Employés.
</p>
</div>
<div class="mt-6 flex justify-end">
<MalioButton
label="Enregistrer"
button-class="w-auto px-6"
:disabled="isSubmitting"
@click="handleSubmit"
/>
</div>
</form>
</MalioDrawer>
</template>
<script setup lang="ts">
import type { UserData, UserWrite } from '~/services/dto/user-data'
import { useUserService } from '~/services/users'
const props = defineProps<{
modelValue: boolean
item: UserData | null
}>()
const emit = defineEmits<{
(e: 'update:modelValue', value: boolean): void
(e: 'saved'): void
}>()
const isOpen = computed({
get: () => props.modelValue,
set: (v) => emit('update:modelValue', v),
})
const availableRoles = ['ROLE_ADMIN', 'ROLE_USER']
const isEditing = computed(() => !!props.item)
const isSubmitting = ref(false)
const form = reactive({
username: '',
firstName: '',
lastName: '',
password: '',
roles: [] as string[],
isEmployee: false,
})
const touched = reactive({
username: false,
password: false,
})
watch(() => props.modelValue, (open) => {
if (open) {
if (props.item) {
form.username = props.item.username ?? ''
form.firstName = props.item.firstName ?? ''
form.lastName = props.item.lastName ?? ''
form.password = ''
form.roles = [...props.item.roles]
form.isEmployee = props.item.isEmployee ?? false
} else {
form.username = ''
form.firstName = ''
form.lastName = ''
form.password = ''
form.roles = ['ROLE_USER']
form.isEmployee = false
}
touched.username = false
touched.password = false
}
})
const { create, update } = useUserService()
async function handleSubmit() {
touched.username = true
touched.password = true
if (!form.username.trim()) return
if (!isEditing.value && !form.password) return
isSubmitting.value = true
try {
const payload: UserWrite = {
username: form.username.trim(),
firstName: form.firstName.trim() || null,
lastName: form.lastName.trim() || null,
roles: form.roles,
isEmployee: form.isEmployee,
}
if (form.password) {
payload.plainPassword = form.password
}
if (isEditing.value && props.item) {
await update(props.item.id, payload)
} else {
await create(payload)
}
emit('saved')
isOpen.value = false
} finally {
isSubmitting.value = false
}
}
</script>