import React from "react"; import { Plus, Trash2, PenLine, Package, Lock, EyeOff } from "lucide-react"; import { cn } from "@/lib/utils"; import { Tooltip, TooltipTrigger, TooltipProvider } from "@/components/ui/tooltip"; import { Textarea } from "@/components/ui/FormModal"; import ArticleAutocomplete from "@/components/molecules/ArticleAutocomplete"; import StickyTotals from "@/components/document-entry/StickyTotals"; import { Facture } from "@/types/factureType"; export interface LigneForm { id: string; article_code: string; quantite: number; prix_unitaire_ht: number; total_taxes: number; taux_taxe1: number; montant_ligne_ht: number; remise_pourcentage: number; designation: string; articles: any | null; isManual: boolean; } export interface Note { publique: string; prive: string; } interface FactureContentProps { // Données facture: Facture; editLignes: LigneForm[]; note: Note; // États isEditing: boolean; isPdfPreviewVisible: boolean; activeLineId: string | null; description: string | null; error: string | null; // Totaux editTotalHT: number; editTotalTVA: number; editTotalTTC: number; // Handlers onToggleLineMode: (lineId: string) => void; onUpdateLigne: (lineId: string, field: keyof LigneForm, value: any) => void; onAjouterLigne: () => void; onSupprimerLigne: (lineId: string) => void; onSetActiveLineId: (lineId: string | null) => void; onSetDescription: (value: string | null) => void; onSetNote: (note: Note) => void; onOpenArticleModal: (lineId: string) => void; // Fonction de calcul calculerTotalLigne: (ligne: LigneForm) => number; } const FactureContent: React.FC = ({ facture, editLignes, note, isEditing, isPdfPreviewVisible, activeLineId, description, error, editTotalHT, editTotalTVA, editTotalTTC, onToggleLineMode, onUpdateLigne, onAjouterLigne, onSupprimerLigne, onSetActiveLineId, onSetDescription, onSetNote, onOpenArticleModal, calculerTotalLigne, }) => { const textSizeClass = isPdfPreviewVisible ? "text-xs" : "text-sm"; return (
{/* Zone scrollable - SEULEMENT ici le scroll s'active */}
{/* Tableau des lignes */}
{isEditing && } {isEditing && } {isEditing ? editLignes.map((item) => ( 1} /> )) : facture.lignes?.map((line, index) => ( ))}
ModeDésignation Description {!isEditing && "détaillée"} Qté P.U. HT Remise TVA Total HT
{/* Bouton ajouter ligne */} {isEditing && (
)} {/* Message d'erreur */} {error && isEditing && (
{error}
)}
{/* Section Notes */}
{/* Footer Totaux - Reste fixe naturellement en bas */}
); }; // ============================================ // SOUS-COMPOSANTS // ============================================ interface EditableLigneRowProps { item: LigneForm; isPdfPreviewVisible: boolean; activeLineId: string | null; description: string | null; canDelete: boolean; onToggleLineMode: (lineId: string) => void; onUpdateLigne: (lineId: string, field: keyof LigneForm, value: any) => void; onSupprimerLigne: (lineId: string) => void; onSetActiveLineId: (lineId: string | null) => void; onSetDescription: (value: string | null) => void; onOpenArticleModal: (lineId: string) => void; calculerTotalLigne: (ligne: LigneForm) => number; } const EditableLigneRow: React.FC = ({ item, isPdfPreviewVisible, activeLineId, description, canDelete, onToggleLineMode, onUpdateLigne, onSupprimerLigne, onSetActiveLineId, onSetDescription, onOpenArticleModal, calculerTotalLigne, }) => { const textSizeClass = isPdfPreviewVisible ? "text-xs" : "text-sm"; return ( {/* Mode Toggle */} {/* Article / Désignation */} {item.isManual ? (
onUpdateLigne(item.id, "designation", e.target.value)} onFocus={() => onSetActiveLineId(item.id)} onBlur={() => setTimeout(() => onSetActiveLineId(null), 150)} className={cn( `w-full border-0 ${textSizeClass} focus:outline-none bg-white text-gray-900` )} placeholder="Saisir une désignation..." /> {/* Menu dropdown */} {activeLineId === item.id && item.designation && ( onOpenArticleModal(item.id)} /> )}
) : (
onUpdateLigne(item.id, "articles", article)} required className={textSizeClass} />
)} {/* Description */} item.isManual ? onSetDescription(e.target.value) : onUpdateLigne(item.id, "designation", e.target.value) } placeholder="Description détaillée..." className={cn( `w-full border-0 ${textSizeClass} focus:outline-none bg-white text-gray-900 text-left` )} /> {/* Quantité */} onUpdateLigne(item.id, "quantite", parseFloat(e.target.value) || 0) } min={0} className={cn( `w-full border-0 ${textSizeClass} focus:outline-none bg-white text-gray-900 text-right` )} /> {/* Prix Unitaire */} onUpdateLigne(item.id, "prix_unitaire_ht", parseFloat(e.target.value) || 0) } min={0} step={0.01} className={cn( `w-full border-0 ${textSizeClass} focus:outline-none bg-white text-gray-900 text-right` )} /> {/* Remise */} onUpdateLigne(item.id, "remise_pourcentage", parseFloat(e.target.value) || 0) } min={0} step={1} className={cn( `w-full border-0 ${textSizeClass} focus:outline-none bg-white text-gray-900 text-right` )} /> {/* TVA */} {item.taux_taxe1}% {/* Total */} {calculerTotalLigne(item).toFixed(2)} € {/* Delete */} ); }; interface ReadOnlyLigneRowProps { line: any; textSizeClass: string; } const ReadOnlyLigneRow: React.FC = ({ line, textSizeClass }) => ( {line.article_code} {line.designation} {line.quantite} {line.prix_unitaire_ht?.toFixed(2)} € {line.remise_valeur1 || 0}% {line.taux_taxe1}% {line.montant_ligne_ht?.toFixed(2)} € ); interface ArticleCreationDropdownProps { designation: string; onCreateArticle: () => void; } const ArticleCreationDropdown: React.FC = ({ designation, onCreateArticle, }) => (
Texte libre accepté
); interface NotesSectionProps { note: Note; isEditing: boolean; onSetNote: (note: Note) => void; } const NotesSection: React.FC = ({ note, isEditing, onSetNote }) => (
{/* Notes publiques */}
Visible sur le PDF