2026-03-24 14:19:49 +03:00

540 lines
14 KiB
Vue

<template>
<div class="card p-3 border-radius-xl bg-white" data-animation="FadeIn">
<h5 class="font-weight-bolder mb-0">Informations de l'intervention</h5>
<p class="mb-0 text-sm">Créez une nouvelle intervention funéraire</p>
<div class="multisteps-form__content">
<!-- Client selection -->
<div class="row mt-3">
<div class="col-12">
<label class="form-label"
>Client <span class="text-danger">*</span></label
>
<search-input
v-model="selectedItem"
:search-action="props.searchClients"
:min-chars="0"
item-key="id"
item-label="name"
@search="handleSearch"
@select="handleSelect"
/>
<div v-if="selectedItem" class="selected-item">
Sélectionné: {{ selectedItem.name }} ({{
selectedItem.email || "Pas d'email"
}})
</div>
<div
v-if="fieldErrors.client_id"
class="invalid-feedback small-error"
>
{{ fieldErrors.client_id }}
</div>
</div>
</div>
<!-- Deceased selection -->
<div class="row mt-3">
<div class="col-12">
<label class="form-label">Personne décédée</label>
<search-input
v-model="selectedDeceased"
:search-action="props.searchDeceased"
:min-chars="0"
item-key="id"
:item-label="getDeceasedFullName"
@search="handleSearchDeceased"
@select="handleSelectDeceased"
/>
<div v-if="selectedDeceased" class="selected-item">
Sélectionné: {{ selectedDeceased.last_name }}
{{ selectedDeceased.first_name || "" }}
</div>
<div
v-if="fieldErrors.deceased_id"
class="invalid-feedback small-error"
>
{{ fieldErrors.deceased_id }}
</div>
</div>
</div>
<!-- Intervention type -->
<div class="row mt-3">
<div class="col-12">
<label class="form-label"
>Type d'intervention <span class="text-danger">*</span></label
>
<select
v-model="form.type"
class="form-select multisteps-form__select"
:class="{ 'is-invalid': fieldErrors.type }"
>
<option value="">Sélectionnez un type d'intervention</option>
<option value="thanatopraxie">Thanatopraxie</option>
<option value="toilette_mortuaire">Toilette mortuaire</option>
<option value="exhumation">Exhumation</option>
<option value="retrait_pacemaker">Retrait pacemaker</option>
<option value="retrait_bijoux">Retrait bijoux</option>
<option value="autre">Autre</option>
</select>
<div v-if="fieldErrors.type" class="invalid-feedback small-error">
{{ fieldErrors.type }}
</div>
</div>
</div>
<!-- Date et heure de l'intervention -->
<div class="row mt-3">
<div class="col-12 col-sm-6">
<label class="form-label">Date de l'intervention</label>
<soft-input
v-model="form.scheduled_date"
class="multisteps-form__input"
:class="{ 'is-invalid': fieldErrors.scheduled_at }"
type="date"
/>
<div
v-if="fieldErrors.scheduled_at"
class="invalid-feedback small-error"
>
{{ fieldErrors.scheduled_at }}
</div>
</div>
<div class="col-12 col-sm-6 mt-3 mt-sm-0">
<label class="form-label">Heure de l'intervention</label>
<soft-input
v-model="form.scheduled_time"
class="multisteps-form__input"
:class="{ 'is-invalid': fieldErrors.scheduled_at }"
type="time"
/>
<div
v-if="fieldErrors.scheduled_at"
class="invalid-feedback small-error"
>
{{ fieldErrors.scheduled_at }}
</div>
</div>
</div>
<!-- Duration and status -->
<div class="row mt-3">
<div class="col-12 col-sm-6">
<label class="form-label">Durée (minutes)</label>
<soft-input
v-model="form.duration_min"
class="multisteps-form__input"
:class="{ 'is-invalid': fieldErrors.duration_min }"
type="number"
min="1"
placeholder="ex. 90"
/>
<div
v-if="fieldErrors.duration_min"
class="invalid-feedback small-error"
>
{{ fieldErrors.duration_min }}
</div>
</div>
<div class="col-12 col-sm-6 mt-3 mt-sm-0">
<label class="form-label">Statut</label>
<select
v-model="form.status"
class="form-select multisteps-form__select"
:class="{ 'is-invalid': fieldErrors.status }"
>
<option value="">Sélectionnez un statut</option>
<option value="demande">Demande</option>
<option value="planifie">Planifié</option>
<option value="en_cours">En cours</option>
<option value="termine">Terminé</option>
<option value="annule">Annulé</option>
</select>
<div v-if="fieldErrors.status" class="invalid-feedback small-error">
{{ fieldErrors.status }}
</div>
</div>
</div>
<!-- Order giver and notes -->
<div class="row mt-3">
<div class="col-12">
<label class="form-label">Donneur d'ordre</label>
<soft-input
v-model="form.order_giver"
class="multisteps-form__input"
:class="{ 'is-invalid': fieldErrors.order_giver }"
type="text"
placeholder="Nom du donneur d'ordre"
/>
<div
v-if="fieldErrors.order_giver"
class="invalid-feedback small-error"
>
{{ fieldErrors.order_giver }}
</div>
</div>
</div>
<!-- Notes -->
<div class="row mt-3">
<div class="col-12">
<label class="form-label">Notes et observations</label>
<textarea
v-model="form.notes"
class="form-control multisteps-form__input"
:class="{ 'is-invalid': fieldErrors.notes }"
rows="4"
placeholder="Informations complémentaires, instructions spéciales..."
maxlength="2000"
></textarea>
<div v-if="fieldErrors.notes" class="invalid-feedback small-error">
{{ fieldErrors.notes }}
</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 ? "Enregistrement..." : "Enregistrer" }}
</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";
import SearchInput from "@/components/atoms/input/SearchInput.vue";
// Props
const props = defineProps({
loading: {
type: Boolean,
default: false,
},
validationErrors: {
type: Object,
default: () => ({}),
},
success: {
type: Boolean,
default: false,
},
deceasedList: {
type: Array,
default: () => [],
},
deceasedLoading: {
type: Boolean,
default: false,
},
clientList: {
type: Array,
default: () => [],
},
clientLoading: {
type: Boolean,
default: false,
},
searchClients: {
type: Function,
required: true,
},
onClientSelect: {
type: Function,
required: true,
},
searchDeceased: {
type: Function,
required: true,
},
onDeceasedSelect: {
type: Function,
required: true,
},
});
// Emits
const emit = defineEmits(["createIntervention"]);
// Reactive data
const errors = ref([]);
// Search input data
const selectedItem = ref(null);
const selectedDeceased = ref(null);
// Handle client search event
const handleSearch = (query) => {
console.log("Searching for client:", query);
};
// Handle client select event
const handleSelect = (item) => {
console.log("Selected client:", item);
// Call the parent callback for client selection if provided
if (props.onClientSelect) {
props.onClientSelect(item);
}
// Set the client_id in the form
if (item && item.id) {
form.value.client_id = item.id.toString();
}
};
// Handle deceased search event
const handleSearchDeceased = (query) => {
console.log("Searching for deceased:", query);
};
const getDeceasedFullName = (deceased) => {
const parts = [deceased.last_name, deceased.first_name].filter(Boolean);
return parts.join(" ").trim();
};
// Handle deceased select event
const handleSelectDeceased = (item) => {
console.log("Selected deceased:", item);
// Call the parent callback for deceased selection if provided
if (props.onDeceasedSelect) {
props.onDeceasedSelect(item);
}
// Set the deceased_id in the form
if (item && item.id) {
form.value.deceased_id = item.id.toString();
}
};
const fieldErrors = ref({});
const form = ref({
client_id: "",
deceased_id: "",
type: "",
scheduled_date: "",
scheduled_time: "",
duration_min: "",
status: "",
order_giver: "",
notes: "",
});
// 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();
}
}
);
// Watch for client_id changes to update selectedItem
watch(
() => form.value.client_id,
(newClientId) => {
if (newClientId && fieldErrors.value.client_id) {
delete fieldErrors.value.client_id;
}
if (!newClientId) {
selectedItem.value = null;
}
}
);
// Watch for deceased_id changes to update selectedDeceased
watch(
() => form.value.deceased_id,
(newDeceasedId) => {
if (newDeceasedId && fieldErrors.value.deceased_id) {
delete fieldErrors.value.deceased_id;
}
if (!newDeceasedId) {
selectedDeceased.value = null;
}
}
);
watch(
() => form.value.type,
(newType) => {
if (newType && fieldErrors.value.type) {
delete fieldErrors.value.type;
}
}
);
const submitForm = async () => {
// Clear errors before submitting
fieldErrors.value = {};
errors.value = [];
// Validate required fields
let hasErrors = false;
if (!form.value.client_id || form.value.client_id === "") {
fieldErrors.value.client_id = "Le client est obligatoire";
hasErrors = true;
}
if (!form.value.type || form.value.type === "") {
fieldErrors.value.type = "Le type d'intervention est obligatoire";
hasErrors = true;
}
if (hasErrors) {
return;
}
// 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;
}
}
// Combine date and time into scheduled_at (backend expects Y-m-d H:i:s format)
if (cleanedForm.scheduled_date && cleanedForm.scheduled_time) {
// Format: Y-m-d H:i:s (e.g., "2024-12-15 14:30:00")
const formattedDate = cleanedForm.scheduled_date;
const formattedTime = cleanedForm.scheduled_time;
cleanedForm.scheduled_at = `${formattedDate} ${formattedTime}:00`;
delete cleanedForm.scheduled_date;
delete cleanedForm.scheduled_time;
}
// Convert string numbers to integers
if (cleanedForm.client_id) {
cleanedForm.client_id = parseInt(cleanedForm.client_id);
}
if (cleanedForm.deceased_id) {
cleanedForm.deceased_id = parseInt(cleanedForm.deceased_id);
}
if (cleanedForm.duration_min) {
cleanedForm.duration_min = parseInt(cleanedForm.duration_min);
}
console.log("Intervention form data being emitted:", cleanedForm);
// Emit the cleaned form data to parent
emit("createIntervention", cleanedForm);
};
const resetForm = () => {
form.value = {
client_id: "",
deceased_id: "",
type: "",
scheduled_date: "",
scheduled_time: "",
duration_min: "",
status: "",
order_giver: "",
notes: "",
};
// Clear the selected items
selectedItem.value = null;
selectedDeceased.value = null;
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;
}
.small-error {
font-size: 0.75rem;
margin-top: 0.25rem;
}
.spinner-border-sm {
width: 1rem;
height: 1rem;
}
.alert {
border-radius: 0.75rem;
}
.alert-warning {
background-color: #fff3cd;
border: 1px solid #ffeaa7;
color: #856404;
}
.alert i {
font-size: 0.8rem;
}
.multisteps-form__select {
background-color: white;
border: 1px solid #d2d6da;
border-radius: 0.5rem;
color: #495057;
padding: 0.5rem 0.75rem;
font-size: 0.875rem;
transition: all 0.15s ease-in-out;
}
.multisteps-form__select:focus {
border-color: #5e72e4;
box-shadow: 0 0 0 0.2rem rgba(94, 114, 228, 0.25);
outline: 0;
}
</style>