539 lines
19 KiB
JavaScript

document.addEventListener("DOMContentLoaded", () => {
const form = document.getElementById("invoiceForm");
const invoiceItems = document.getElementById("invoiceItems");
const addItemButton = document.getElementById("addItemButton");
const clearFormButton = document.createElement("button");
const recipientNameInput = form.recipient_name;
const clientSuggestions = document.createElement("div");
// Configuration de la boîte de suggestions
clientSuggestions.className =
"client-suggestions absolute z-10 bg-white shadow-lg rounded-md w-full max-h-60 overflow-y-auto hidden";
recipientNameInput.parentNode.style.position = "relative";
recipientNameInput.parentNode.appendChild(clientSuggestions);
// Charger les clients précédents
let clientsData = JSON.parse(localStorage.getItem("clientsData") || "[]");
// Ajouter un bouton pour effacer le formulaire
clearFormButton.type = "button";
clearFormButton.className =
"bg-red-500 text-white px-4 py-2 rounded-md hover:bg-red-600 ml-4";
clearFormButton.textContent = "Effacer le formulaire";
clearFormButton.id = "clearFormButton";
// Ajouter le bouton après le bouton de soumission
const submitButton = form.querySelector('button[type="submit"]');
submitButton.parentNode.insertBefore(
clearFormButton,
submitButton.nextSibling
);
// Gestionnaire d'événement pour effacer le formulaire
clearFormButton.addEventListener("click", () => {
if (confirm("Êtes-vous sûr de vouloir effacer le formulaire ?")) {
localStorage.removeItem("invoiceData");
form.reset();
// Réinitialiser les lignes de facturation
invoiceItems.innerHTML = "";
addInvoiceItem();
showMessage("Formulaire effacé", "success");
}
});
// Restaurer les données du formulaire depuis localStorage si elles existent
restoreFormData();
// Initialiser avec une ligne de facturation par défaut ou restaurer les lignes sauvegardées
if (invoiceItems.children.length === 0) {
addInvoiceItem();
}
// Ajouter une ligne de facturation lorsqu'on clique sur le bouton
addItemButton.addEventListener("click", addInvoiceItem);
// Sauvegarder les données pendant la saisie (debounced)
let saveTimeout;
form.addEventListener("input", () => {
clearTimeout(saveTimeout);
saveTimeout = setTimeout(() => {
saveFormData();
}, 500); // Attendre 500ms après la dernière saisie
});
// Gérer l'auto-complétion des clients
recipientNameInput.addEventListener("input", function () {
const query = this.value.toLowerCase();
if (query.length < 2) {
clientSuggestions.classList.add("hidden");
return;
}
// Filtrer les clients qui correspondent à la recherche
const matches = clientsData.filter((client) =>
client.name.toLowerCase().includes(query)
);
if (matches.length === 0) {
clientSuggestions.classList.add("hidden");
return;
}
// Afficher les suggestions
clientSuggestions.innerHTML = matches
.map(
(client) => `
<div class="client-suggestion p-2 hover:bg-gray-100 cursor-pointer" data-client-id="${client.id}">
<div class="font-medium">${client.name}</div>
<div class="text-sm text-gray-600">${client.address}, ${client.postal_code} ${client.town}</div>
</div>
`
)
.join("");
clientSuggestions.classList.remove("hidden");
// Ajouter des gestionnaires d'événements pour les suggestions
document.querySelectorAll(".client-suggestion").forEach((suggestion) => {
suggestion.addEventListener("click", function () {
const clientId = this.getAttribute("data-client-id");
const client = clientsData.find((c) => c.id === clientId);
if (client) {
fillClientData(client);
clientSuggestions.classList.add("hidden");
}
});
});
});
// Masquer les suggestions lorsqu'on clique ailleurs
document.addEventListener("click", function (e) {
if (
!recipientNameInput.contains(e.target) &&
!clientSuggestions.contains(e.target)
) {
clientSuggestions.classList.add("hidden");
}
});
// Fonction pour remplir les données du client
function fillClientData(client) {
form.recipient_name.value = client.name;
form.recipient_address.value = client.address;
form.recipient_postal_code.value = client.postal_code;
form.recipient_town.value = client.town;
form.recipient_country.value = client.country;
if (client.vat_number) {
form.recipient_vat_number.value = client.vat_number;
}
}
// Fonction pour sauvegarder un nouveau client
function saveClient() {
// Ne sauvegarder que si les champs essentiels sont remplis
if (
!form.recipient_name.value ||
!form.recipient_address.value ||
!form.recipient_postal_code.value ||
!form.recipient_town.value
) {
return;
}
const clientData = {
id: Date.now().toString(), // ID unique
name: form.recipient_name.value,
address: form.recipient_address.value,
postal_code: form.recipient_postal_code.value,
town: form.recipient_town.value,
country: form.recipient_country.value,
vat_number: form.recipient_vat_number.value || null,
lastUsed: new Date().toISOString(),
};
// Vérifier si le client existe déjà (par nom)
const existingClientIndex = clientsData.findIndex(
(client) => client.name.toLowerCase() === clientData.name.toLowerCase()
);
if (existingClientIndex !== -1) {
// Mettre à jour le client existant
clientsData[existingClientIndex] = {
...clientsData[existingClientIndex],
...clientData,
id: clientsData[existingClientIndex].id, // Conserver l'ID d'origine
};
} else {
// Ajouter le nouveau client
clientsData.push(clientData);
}
// Trier par date d'utilisation (plus récent en premier)
clientsData.sort((a, b) => new Date(b.lastUsed) - new Date(a.lastUsed));
// Limiter à 50 clients
clientsData = clientsData.slice(0, 50);
// Sauvegarder dans localStorage
localStorage.setItem("clientsData", JSON.stringify(clientsData));
}
// Fonction pour sauvegarder les données du formulaire
function saveFormData() {
const formData = {
language: form.language.value,
invoice_number: form.invoice_number.value,
amount: form.amount.value,
currency: form.currency.value,
recipient_name: form.recipient_name.value,
recipient_address: form.recipient_address.value,
recipient_postal_code: form.recipient_postal_code.value,
recipient_town: form.recipient_town.value,
recipient_country: form.recipient_country.value,
recipient_vat_number: form.recipient_vat_number.value || null,
items: collectInvoiceItems(),
};
localStorage.setItem("invoiceData", JSON.stringify(formData));
// Sauvegarder aussi dans l'historique des factures récentes
saveToRecentInvoices(formData);
// Sauvegarder les informations du client si tous les champs sont remplis
saveClient();
}
// Fonction pour sauvegarder dans l'historique des factures récentes
function saveToRecentInvoices(formData) {
if (!formData.recipient_name) return; // Ne pas sauvegarder si pas de nom de destinataire
let recentInvoices = JSON.parse(
localStorage.getItem("recentInvoices") || "[]"
);
// Créer un identifiant unique basé sur le nom et la date
const now = new Date();
const id = `${formData.recipient_name}_${now.toISOString()}`;
// Ajouter la facture actuelle à l'historique avec un timestamp
const invoiceWithMeta = {
...formData,
id,
lastEdited: now.toISOString(),
};
// Vérifier si une facture similaire existe déjà (même destinataire)
const existingIndex = recentInvoices.findIndex(
(invoice) => invoice.recipient_name === formData.recipient_name
);
if (existingIndex !== -1) {
// Remplacer la facture existante
recentInvoices[existingIndex] = invoiceWithMeta;
} else {
// Ajouter la nouvelle facture
recentInvoices.unshift(invoiceWithMeta);
}
// Limiter à 10 factures récentes
recentInvoices = recentInvoices.slice(0, 10);
localStorage.setItem("recentInvoices", JSON.stringify(recentInvoices));
// Mettre à jour la liste des factures récentes dans l'interface
updateRecentInvoicesList();
}
// Fonction pour mettre à jour la liste des factures récentes dans l'interface
function updateRecentInvoicesList() {
const recentInvoicesContainer = document.getElementById("recentInvoices");
if (!recentInvoicesContainer) {
// Créer le conteneur s'il n'existe pas
const container = document.createElement("div");
container.id = "recentInvoices";
container.className = "mt-8 bg-white rounded-lg shadow p-4";
container.innerHTML = `
<h3 class="text-lg font-semibold mb-4">Factures récentes</h3>
<div id="recentInvoicesList" class="space-y-2"></div>
`;
form.parentNode.insertBefore(container, form.nextSibling);
}
const recentInvoicesList = document.getElementById("recentInvoicesList");
const recentInvoices = JSON.parse(
localStorage.getItem("recentInvoices") || "[]"
);
if (recentInvoices.length === 0) {
recentInvoicesList.innerHTML = `<p class="text-gray-500">Aucune facture récente</p>`;
return;
}
recentInvoicesList.innerHTML = recentInvoices
.map(
(invoice) => `
<div class="flex justify-between items-center p-2 border-b">
<div>
<span class="font-medium">${invoice.recipient_name}</span>
<span class="text-sm text-gray-500 ml-2">${invoice.amount} ${
invoice.currency
}</span>
<span class="text-xs text-gray-400 ml-2">${new Date(
invoice.lastEdited
).toLocaleDateString()}</span>
</div>
<button class="load-invoice bg-blue-500 text-white px-2 py-1 rounded text-sm" data-id="${
invoice.id
}">
Charger
</button>
</div>
`
)
.join("");
// Ajouter les gestionnaires d'événements pour charger les factures
document.querySelectorAll(".load-invoice").forEach((button) => {
button.addEventListener("click", (e) => {
const id = e.target.getAttribute("data-id");
const invoice = recentInvoices.find((inv) => inv.id === id);
if (invoice) {
if (
confirm(
"Charger cette facture ? Les données actuelles seront remplacées."
)
) {
loadInvoice(invoice);
}
}
});
});
}
// Fonction pour charger une facture depuis l'historique
function loadInvoice(invoice) {
// Remplir le formulaire avec les données de la facture
form.language.value = invoice.language || "";
form.invoice_number.value = invoice.invoice_number || "";
form.amount.value = invoice.amount || "";
form.currency.value = invoice.currency || "EUR";
form.recipient_name.value = invoice.recipient_name || "";
form.recipient_address.value = invoice.recipient_address || "";
form.recipient_postal_code.value = invoice.recipient_postal_code || "";
form.recipient_town.value = invoice.recipient_town || "";
form.recipient_country.value = invoice.recipient_country || "";
form.recipient_vat_number.value = invoice.recipient_vat_number || "";
// Restaurer les lignes de facturation
invoiceItems.innerHTML = "";
if (invoice.items && invoice.items.length > 0) {
invoice.items.forEach((item) => {
addInvoiceItem(item.description, item.amount);
});
} else {
addInvoiceItem();
}
// Sauvegarder dans le localStorage
localStorage.setItem("invoiceData", JSON.stringify(invoice));
showMessage("Facture chargée avec succès", "success");
}
// Fonction pour restaurer les données du formulaire depuis localStorage
function restoreFormData() {
const savedData = localStorage.getItem("invoiceData");
if (!savedData) {
// Mettre à jour la liste des factures récentes même s'il n'y a pas de données sauvegardées
updateRecentInvoicesList();
return;
}
try {
const formData = JSON.parse(savedData);
// Remplir les champs du formulaire
if (formData.language) form.language.value = formData.language;
if (formData.invoice_number)
form.invoice_number.value = formData.invoice_number;
if (formData.amount) form.amount.value = formData.amount;
if (formData.currency) form.currency.value = formData.currency;
if (formData.recipient_name)
form.recipient_name.value = formData.recipient_name;
if (formData.recipient_address)
form.recipient_address.value = formData.recipient_address;
if (formData.recipient_postal_code)
form.recipient_postal_code.value = formData.recipient_postal_code;
if (formData.recipient_town)
form.recipient_town.value = formData.recipient_town;
if (formData.recipient_country)
form.recipient_country.value = formData.recipient_country;
if (formData.recipient_vat_number)
form.recipient_vat_number.value = formData.recipient_vat_number;
// Restaurer les lignes de facturation
if (formData.items && formData.items.length > 0) {
// Vider les lignes existantes
invoiceItems.innerHTML = "";
// Ajouter chaque ligne sauvegardée
formData.items.forEach((item) => {
addInvoiceItem(item.description, item.amount);
});
}
// Mettre à jour la liste des factures récentes
updateRecentInvoicesList();
} catch (error) {
console.error("Erreur lors de la restauration des données:", error);
}
}
// Fonction pour créer une nouvelle ligne de facturation
function addInvoiceItem(description = "", amount = "") {
const itemId = Date.now(); // ID unique pour l'élément
const itemDiv = document.createElement("div");
itemDiv.className = "invoice-item grid grid-cols-5 gap-2";
itemDiv.dataset.id = itemId;
itemDiv.innerHTML = `
<div class="col-span-3">
<input type="text" name="item_description_${itemId}" placeholder="Description" value="${description}"
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div class="col-span-1">
<input type="number" step="0.01" name="item_amount_${itemId}" placeholder="Montant" value="${amount}"
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
</div>
<div class="col-span-1">
<button type="button" class="delete-item text-red-500 hover:text-red-700" data-id="${itemId}">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
`;
// Ajouter un gestionnaire d'événements pour supprimer la ligne
const deleteButton = itemDiv.querySelector(".delete-item");
deleteButton.addEventListener("click", function () {
const id = this.getAttribute("data-id");
deleteInvoiceItem(id);
});
invoiceItems.appendChild(itemDiv);
}
// Fonction pour supprimer une ligne de facturation
function deleteInvoiceItem(id) {
const item = document.querySelector(`.invoice-item[data-id="${id}"]`);
if (item) {
item.remove();
}
// S'assurer qu'il reste au moins une ligne
if (invoiceItems.children.length === 0) {
addInvoiceItem();
}
}
// Fonction pour collecter toutes les lignes de facturation
function collectInvoiceItems() {
const items = [];
document.querySelectorAll(".invoice-item").forEach((item) => {
const id = item.dataset.id;
const description = item.querySelector(
`[name="item_description_${id}"]`
).value;
const amount = item.querySelector(`[name="item_amount_${id}"]`).value;
if (description && amount) {
items.push({ description, amount });
}
});
return items;
}
// Fonction pour valider le formulaire
function validateForm() {
const requiredFields = [
form.invoice_number,
form.amount,
form.recipient_name,
form.recipient_address,
form.recipient_postal_code,
form.recipient_town,
form.recipient_country,
];
for (const field of requiredFields) {
if (!field.value) {
showMessage(`Le champ ${field.name} est requis`, "error");
field.focus();
return false;
}
}
const items = collectInvoiceItems();
if (items.length === 0) {
showMessage("Ajoutez au moins une ligne de facturation", "error");
return false;
}
return true;
}
// Fonction pour afficher les messages
function showMessage(message, type = "success") {
const messageDiv = document.createElement("div");
messageDiv.className = `${type}-message fixed top-4 right-4 p-4 rounded-md shadow-lg ${
type === "success" ? "bg-green-500" : "bg-red-500"
} text-white`;
messageDiv.textContent = message;
document.body.appendChild(messageDiv);
// Afficher le message
setTimeout(() => messageDiv.classList.add("opacity-100"), 100);
// Supprimer le message après 3 secondes
setTimeout(() => {
messageDiv.classList.remove("opacity-100");
setTimeout(() => messageDiv.remove(), 300);
}, 3000);
}
// Gestionnaire de soumission du formulaire
form.addEventListener("submit", function (e) {
e.preventDefault();
if (!validateForm()) {
return;
}
// Récupérer les données du formulaire
const formData = {
language: form.language.value,
invoice_number: form.invoice_number.value,
amount: form.amount.value, // Montant total
currency: form.currency.value,
recipient_name: form.recipient_name.value,
recipient_address: form.recipient_address.value,
recipient_postal_code: form.recipient_postal_code.value,
recipient_town: form.recipient_town.value,
recipient_country: form.recipient_country.value,
recipient_vat_number: form.recipient_vat_number.value || null,
items: collectInvoiceItems(), // Ajouter les lignes de facturation
};
// Sauvegarder les données du formulaire dans localStorage
localStorage.setItem("invoiceData", JSON.stringify(formData));
// Sauvegarder les informations du client
saveClient();
// Rediriger vers la page de prévisualisation avec les données
const queryString = encodeURIComponent(JSON.stringify(formData));
window.location.href = `/preview?data=${queryString}`;
});
});