613 lines
21 KiB
Vue

<template>
<div class="container-fluid py-4">
<!-- Header -->
<!-- Form -->
<div class="row">
<div class="col-12">
<div class="card mt-4">
<div class="card-header pb-0">
<div class="d-flex align-items-center">
<p class="font-weight-bold mb-0">Informations du Produit</p>
</div>
</div>
<div class="card-body">
<!-- Success Message -->
<div v-if="success" class="alert alert-success" role="alert">
<strong>Succès!</strong> Le produit a été créé avec succès.
Redirection en cours...
</div>
<!-- Loading State -->
<div v-if="loading" class="text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Création en cours...</span>
</div>
<p class="mt-2">Création du produit...</p>
</div>
<!-- Form -->
<form v-else novalidate @submit.prevent="handleSubmit">
<!-- Basic Information -->
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="nom" class="form-label">Nom du Produit *</label>
<soft-input
id="nom"
v-model="form.nom"
type="text"
:class="{ 'is-invalid': validationErrors.nom }"
required
placeholder="Entrez le nom du produit"
/>
<div v-if="validationErrors.nom" class="invalid-feedback">
{{ validationErrors.nom[0] }}
</div>
</div>
</div>
<div class="col-md-6">
<div v-if="!isIntervention" class="form-group">
<label for="reference" class="form-label"
>Référence *</label
>
<soft-input
id="reference"
v-model="form.reference"
type="text"
:class="{ 'is-invalid': validationErrors.reference }"
required
placeholder="Entrez la référence du produit"
/>
<div
v-if="validationErrors.reference"
class="invalid-feedback"
>
{{ validationErrors.reference[0] }}
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="categorie" class="form-label"
>Catégorie *</label
>
<select
id="categorie"
v-model="form.categorie_id"
class="form-control"
:class="{ 'is-invalid': validationErrors.categorie_id }"
required
>
<option value="">Sélectionnez une catégorie</option>
<option
v-for="category in categories"
:key="category.id"
:value="category.id"
>
{{ category.name }}
</option>
</select>
<div
v-if="validationErrors.categorie_id"
class="invalid-feedback"
>
{{ validationErrors.categorie_id[0] }}
</div>
</div>
</div>
<div class="col-md-6">
<div v-if="!isIntervention" class="form-group">
<label for="fabricant" class="form-label">Fabricant</label>
<soft-input
id="fabricant"
v-model="form.fabricant"
type="text"
:class="{ 'is-invalid': validationErrors.fabricant }"
placeholder="Entrez le nom du fabricant"
/>
<div
v-if="validationErrors.fabricant"
class="invalid-feedback"
>
{{ validationErrors.fabricant[0] }}
</div>
</div>
</div>
</div>
<!-- Stock Information -->
<div class="row">
<div class="col-md-4">
<div v-if="!isIntervention" class="form-group">
<label for="stock_actuel" class="form-label"
>Stock Actuel *</label
>
<soft-input
id="stock_actuel"
v-model.number="form.stock_actuel"
type="number"
step="0.01"
min="0"
:class="{ 'is-invalid': validationErrors.stock_actuel }"
required
placeholder="0.00"
/>
<div
v-if="validationErrors.stock_actuel"
class="invalid-feedback"
>
{{ validationErrors.stock_actuel[0] }}
</div>
</div>
</div>
<div class="col-md-4">
<div v-if="!isIntervention" class="form-group">
<label for="stock_minimum" class="form-label"
>Stock Minimum *</label
>
<soft-input
id="stock_minimum"
v-model.number="form.stock_minimum"
type="number"
step="0.01"
min="0"
:class="{ 'is-invalid': validationErrors.stock_minimum }"
required
placeholder="0.00"
/>
<div
v-if="validationErrors.stock_minimum"
class="invalid-feedback"
>
{{ validationErrors.stock_minimum[0] }}
</div>
</div>
</div>
<div v-if="!isIntervention" class="col-md-4">
<div class="form-group">
<label for="unite" class="form-label">Unité *</label>
<select
id="unite"
v-model="form.unite"
class="form-control"
:class="{ 'is-invalid': validationErrors.unite }"
required
>
<option value="">Sélectionnez une unité</option>
<option value="pièce">pièce(s)</option>
<option value="kg">kg</option>
<option value="g">g</option>
<option value="l">l</option>
<option value="ml">ml</option>
<option value="m">m</option>
<option value="cm">cm</option>
<option value="boîte">boîte(s)</option>
<option value="sachet">sachet(s)</option>
<option value="bouteille">bouteille(s)</option>
</select>
<div v-if="validationErrors.unite" class="invalid-feedback">
{{ validationErrors.unite[0] }}
</div>
</div>
</div>
</div>
<!-- Price and Dates -->
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="prix_unitaire" class="form-label"
>Prix Unitaire () *</label
>
<div class="soft-input-group">
<soft-input
id="prix_unitaire"
v-model.number="form.prix_unitaire"
type="number"
step="0.01"
min="0"
:class="{
'is-invalid': validationErrors.prix_unitaire,
}"
required
placeholder="0.00"
/>
<div
v-if="validationErrors.prix_unitaire"
class="invalid-feedback"
>
{{ validationErrors.prix_unitaire[0] }}
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div v-if="!isIntervention" class="form-group">
<label for="date_expiration" class="form-label"
>Date d'Expiration</label
>
<soft-input
id="date_expiration"
v-model="form.date_expiration"
type="date"
:class="{
'is-invalid': validationErrors.date_expiration,
}"
:min="new Date().toISOString().split('T')[0]"
/>
<div
v-if="validationErrors.date_expiration"
class="invalid-feedback"
>
{{ validationErrors.date_expiration[0] }}
</div>
</div>
</div>
</div>
<!-- Lot Number -->
<div class="row">
<div class="col-md-6">
<div v-if="!isIntervention" class="form-group">
<label for="numero_lot" class="form-label"
>Numéro de Lot</label
>
<soft-input
id="numero_lot"
v-model="form.numero_lot"
type="text"
:class="{ 'is-invalid': validationErrors.numero_lot }"
placeholder="Entrez le numéro de lot"
/>
<div
v-if="validationErrors.numero_lot"
class="invalid-feedback"
>
{{ validationErrors.numero_lot[0] }}
</div>
</div>
</div>
<div class="col-md-6">
<div v-if="!isIntervention" class="form-group">
<label for="fournisseur_id" class="form-label"
>Fournisseur</label
>
<select
id="fournisseur_id"
v-model="form.fournisseur_id"
class="form-control"
:class="{ 'is-invalid': validationErrors.fournisseur_id }"
>
<option value="">Sélectionnez un fournisseur</option>
<option
v-for="fournisseur in fournisseurs"
:key="fournisseur.id"
:value="fournisseur.id"
>
{{ fournisseur.name }}
</option>
</select>
<div
v-if="validationErrors.fournisseur_id"
class="invalid-feedback"
>
{{ validationErrors.fournisseur_id[0] }}
</div>
</div>
</div>
</div>
<!-- Packaging Information -->
<div v-if="!isIntervention" class="row">
<div class="col-md-4">
<div class="form-group">
<label for="conditionnement_nom" class="form-label"
>Nom Conditionnement</label
>
<soft-input
id="conditionnement_nom"
v-model="form.conditionnement_nom"
type="text"
:class="{
'is-invalid': validationErrors.conditionnement_nom,
}"
placeholder="Ex: Carton, Pack..."
/>
<div
v-if="validationErrors.conditionnement_nom"
class="invalid-feedback"
>
{{ validationErrors.conditionnement_nom[0] }}
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="conditionnement_quantite" class="form-label"
>Quantité Conditionnement</label
>
<soft-input
id="conditionnement_quantite"
v-model.number="form.conditionnement_quantite"
type="number"
step="0.01"
min="0"
:class="{
'is-invalid': validationErrors.conditionnement_quantite,
}"
placeholder="0.00"
/>
<div
v-if="validationErrors.conditionnement_quantite"
class="invalid-feedback"
>
{{ validationErrors.conditionnement_quantite[0] }}
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="conditionnement_unite" class="form-label"
>Unité Conditionnement</label
>
<soft-input
id="conditionnement_unite"
v-model="form.conditionnement_unite"
type="text"
:class="{
'is-invalid': validationErrors.conditionnement_unite,
}"
placeholder="Ex: pièce, kg..."
/>
<div
v-if="validationErrors.conditionnement_unite"
class="invalid-feedback"
>
{{ validationErrors.conditionnement_unite[0] }}
</div>
</div>
</div>
</div>
<!-- URLs -->
<div v-if="!isIntervention" class="row">
<div class="col-md-6">
<div class="form-group">
<label for="photo_url" class="form-label"
>URL de la Photo</label
>
<soft-input
id="photo_url"
v-model="form.photo_url"
type="url"
:class="{ 'is-invalid': validationErrors.photo_url }"
placeholder="https://exemple.com/photo.jpg"
/>
<div
v-if="validationErrors.photo_url"
class="invalid-feedback"
>
{{ validationErrors.photo_url[0] }}
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="fiche_technique_url" class="form-label"
>URL Fiche Technique</label
>
<soft-input
id="fiche_technique_url"
v-model="form.fiche_technique_url"
type="url"
:class="{
'is-invalid': validationErrors.fiche_technique_url,
}"
placeholder="https://exemple.com/fiche.pdf"
/>
<div
v-if="validationErrors.fiche_technique_url"
class="invalid-feedback"
>
{{ validationErrors.fiche_technique_url[0] }}
</div>
</div>
</div>
</div>
<!-- Form Actions -->
<div class="row mt-4">
<div class="col-12 d-flex justify-content-end">
<soft-button
type="soft-button"
class="btn btn-light me-3"
@click="$router.go(-1)"
>
Annuler
</soft-button>
<soft-button
type="submit"
class="btn bg-gradient-success"
:disabled="loading"
>
<span
v-if="loading"
class="spinner-border spinner-border-sm me-2"
role="status"
></span>
Créer le Produit
</soft-button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import SoftInput from "@/components/SoftInput.vue";
import SoftButton from "@/components/SoftButton.vue";
import { ref, reactive, defineProps, defineEmits } from "vue";
// Props
const props = defineProps({
fournisseurs: {
type: Array,
default: () => [],
},
loading: {
type: Boolean,
default: false,
},
validationErrors: {
type: Object,
default: () => ({}),
},
categories: {
type: Array,
default: () => [],
},
success: {
type: Boolean,
default: false,
},
});
// Emits
const emit = defineEmits(["create-product"]);
// Form data
const form = reactive({
nom: "",
reference: "",
categorie_id: "",
fabricant: "",
stock_actuel: 0,
stock_minimum: 0,
unite: "",
prix_unitaire: 0,
date_expiration: "",
numero_lot: "",
conditionnement_nom: "",
conditionnement_quantite: 0,
conditionnement_unite: "",
photo_url: "",
fiche_technique_url: "",
fournisseur_id: "",
});
// Computed property to check if selected category is an intervention
import { computed, watch } from "vue";
const isIntervention = computed(() => {
const selectedCategory = props.categories.find(
(c) => c.id === form.categorie_id
);
return selectedCategory ? selectedCategory.intervention : false;
});
// Watch logic for intervention categories
watch(
() => form.categorie_id,
(newVal) => {
if (isIntervention.value) {
form.stock_actuel = 1;
form.stock_minimum = 1;
form.unite = "pièce";
// Clear or set defaults for hidden fields if needed
form.fabricant = "";
form.date_expiration = "";
form.numero_lot = "";
form.conditionnement_nom = "";
form.conditionnement_quantite = 0;
form.conditionnement_unite = "";
form.photo_url = "";
form.fiche_technique_url = "";
form.fournisseur_id = "";
}
}
);
// Auto-generate reference for intervention products
watch(
() => form.nom,
(newVal) => {
if (isIntervention.value && newVal) {
form.reference = generateReference(newVal);
}
}
);
const generateReference = (name) => {
const prefix = name.substring(0, 3).toUpperCase();
const randomSuffix = Math.floor(Math.random() * 10000)
.toString()
.padStart(4, "0");
return `${prefix}-${randomSuffix}`;
};
// Methods
const handleSubmit = () => {
// Clean up the form data
const formData = { ...form };
// Convert empty strings to null for optional fields
Object.keys(formData).forEach((key) => {
if (formData[key] === "") {
formData[key] = null;
}
});
emit("create-product", formData);
};
</script>
<style scoped>
.form-label {
font-weight: 600;
color: #495057;
margin-bottom: 0.5rem;
}
.invalid-feedback {
display: block;
}
.soft-input-group-text {
background-color: #f8f9fa;
border: 1px solid #dee2e6;
}
.card {
border: none;
box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.075);
}
.form-control:focus {
border-color: #80bdff;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.alert {
border: none;
border-radius: 0.5rem;
}
</style>