2025-11-05 17:08:08 +03:00

312 lines
8.0 KiB
Vue

<template>
<div class="card p-3 border-radius-xl bg-white" data-animation="FadeIn">
<h5 class="font-weight-bolder mb-0">Nouvel Employé</h5>
<p class="mb-0 text-sm">Informations de l'employé</p>
<div class="multisteps-form__content">
<!-- Nom & Prénom -->
<div class="row mt-3">
<div class="col-12 col-sm-6">
<label class="form-label"
>Prénom <span class="text-danger">*</span></label
>
<soft-input
:value="form.first_name"
class="multisteps-form__input"
:class="{ 'is-invalid': fieldErrors.first_name }"
type="text"
placeholder="ex. Jean"
maxlength="191"
@input="form.first_name = $event.target.value"
/>
<div v-if="fieldErrors.first_name" class="invalid-feedback">
{{ fieldErrors.first_name }}
</div>
</div>
<div class="col-12 col-sm-6 mt-3 mt-sm-0">
<label class="form-label"
>Nom de famille <span class="text-danger">*</span></label
>
<soft-input
:value="form.last_name"
class="multisteps-form__input"
:class="{ 'is-invalid': fieldErrors.last_name }"
type="text"
placeholder="ex. Dupont"
maxlength="191"
@input="form.last_name = $event.target.value"
/>
<div v-if="fieldErrors.last_name" class="invalid-feedback">
{{ fieldErrors.last_name }}
</div>
</div>
</div>
<!-- Email & Téléphone -->
<div class="row mt-3">
<div class="col-12 col-sm-6">
<label class="form-label">Email</label>
<soft-input
:value="form.email"
class="multisteps-form__input"
:class="{ 'is-invalid': fieldErrors.email }"
type="email"
placeholder="ex. jean.dupont@entreprise.com"
maxlength="191"
@input="form.email = $event.target.value"
/>
<div v-if="fieldErrors.email" class="invalid-feedback">
{{ fieldErrors.email }}
</div>
</div>
<div class="col-12 col-sm-6 mt-3 mt-sm-0">
<label class="form-label">Téléphone</label>
<soft-input
:value="form.phone"
class="multisteps-form__input"
:class="{ 'is-invalid': fieldErrors.phone }"
type="text"
placeholder="ex. +261341234567"
maxlength="50"
@input="form.phone = $event.target.value"
/>
<div v-if="fieldErrors.phone" class="invalid-feedback">
{{ fieldErrors.phone }}
</div>
</div>
</div>
<!-- Intitulé du poste -->
<div class="row mt-3">
<div class="col-12">
<label class="form-label">Intitulé du poste</label>
<soft-input
:value="form.job_title"
class="multisteps-form__input"
:class="{ 'is-invalid': fieldErrors.job_title }"
type="text"
placeholder="ex. Développeur Full-Stack"
maxlength="191"
@input="form.job_title = $event.target.value"
/>
<div v-if="fieldErrors.job_title" class="invalid-feedback">
{{ fieldErrors.job_title }}
</div>
</div>
</div>
<!-- Date d'embauche -->
<div class="row mt-3">
<div class="col-12 col-sm-6">
<label class="form-label">Date d'embauche</label>
<soft-input
:value="form.hire_date"
class="multisteps-form__input"
:class="{ 'is-invalid': fieldErrors.hire_date }"
type="date"
@input="form.hire_date = $event.target.value"
/>
<div v-if="fieldErrors.hire_date" class="invalid-feedback">
{{ fieldErrors.hire_date }}
</div>
</div>
<div class="col-12 col-sm-6 mt-3 mt-sm-0">
<label class="form-label">Salaire</label>
<soft-input
:value="form.salary"
class="multisteps-form__input"
:class="{ 'is-invalid': fieldErrors.salary }"
type="number"
placeholder="ex. 45000"
step="0.01"
min="0"
@input="form.salary = $event.target.value"
/>
<div v-if="fieldErrors.salary" class="invalid-feedback">
{{ fieldErrors.salary }}
</div>
</div>
</div>
<!-- Statut actif -->
<div class="row mt-3">
<div class="col-12">
<div class="form-check form-switch">
<input
id="isActive"
class="form-check-input"
type="checkbox"
:checked="form.active"
@change="form.active = $event.target.checked"
/>
<label class="form-check-label" for="isActive">
Employé actif
</label>
</div>
</div>
</div>
<!-- Boutons -->
<div class="button-row d-flex mt-4">
<soft-button
type="button"
color="secondary"
variant="outline"
class="me-2 mb-0"
@click="resetForm"
>
Réinitialiser
</soft-button>
<soft-button
type="button"
color="dark"
variant="gradient"
class="ms-auto mb-0"
:disabled="props.loading"
@click="submitForm"
>
<span
v-if="props.loading"
class="spinner-border spinner-border-sm me-2"
role="status"
></span>
{{ props.loading ? "Création..." : "Créer l'employé" }}
</soft-button>
</div>
</div>
</div>
</template>
<script setup>
import { ref, defineProps, defineEmits, watch } from "vue";
import SoftInput from "@/components/SoftInput.vue";
import SoftButton from "@/components/SoftButton.vue";
// Props
const props = defineProps({
loading: {
type: Boolean,
default: false,
},
validationErrors: {
type: Object,
default: () => ({}),
},
success: {
type: Boolean,
default: false,
},
});
// Emits
const emit = defineEmits(["createEmployee"]);
// Reactive data
const errors = ref([]);
const fieldErrors = ref({});
const form = ref({
first_name: "",
last_name: "",
email: "",
phone: "",
job_title: "",
hire_date: "",
salary: null,
active: true,
});
// Watch for validation errors from parent
watch(
() => props.validationErrors,
(newErrors) => {
fieldErrors.value = { ...newErrors };
},
{ deep: true }
);
// Watch for success from parent
watch(
() => props.success,
(newSuccess) => {
if (newSuccess) {
resetForm();
}
}
);
const submitForm = async () => {
// Clear errors before submitting
fieldErrors.value = {};
errors.value = [];
// Clean up form data: convert empty strings to null
const cleanedForm = {};
const formData = form.value;
for (const [key, value] of Object.entries(formData)) {
if (value === "" || value === null || value === undefined) {
cleanedForm[key] = null;
} else {
cleanedForm[key] = value;
}
}
// Ensure active is boolean
cleanedForm.active = Boolean(formData.active);
// Convert salary to number if provided
if (cleanedForm.salary !== null) {
cleanedForm.salary = parseFloat(cleanedForm.salary);
}
console.log("Form data being emitted:", cleanedForm);
// Emit the cleaned form data to parent
emit("createEmployee", cleanedForm);
};
const resetForm = () => {
form.value = {
first_name: "",
last_name: "",
email: "",
phone: "",
job_title: "",
hire_date: "",
salary: null,
active: true,
};
clearErrors();
};
const clearErrors = () => {
errors.value = [];
fieldErrors.value = {};
};
</script>
<style scoped>
.form-label {
font-weight: 600;
margin-bottom: 0.5rem;
}
.text-danger {
color: #f5365c;
}
.invalid-feedback {
display: block;
}
.spinner-border-sm {
width: 1rem;
height: 1rem;
}
.alert {
border-radius: 0.75rem;
}
</style>