// Types simplifiés pour éviter les erreurs TypeScript complexes export type VerticalAlign = "top" | "middle" | "bottom"; export type LabelPosition = "top" | "left" | "bottom" | "right"; export type CustomerInfoLayout = "vertical" | "horizontal" | "compact"; export type TextAlign = "left" | "center" | "right"; export interface Point { x: number; y: number; } export interface Size { width: number; height: number; } export interface Bounds extends Point, Size {} // ✅ NEW: Structure pour les produits du tableau export interface ProductTableProduct { name: string; sku?: string; quantity: number; price: number; total: number; description?: string; image?: string; // URL de l'image produit } // ✅ NEW: Structure pour les frais du tableau export interface ProductTableFee { name: string; total: number; } // ✅ NEW: Structure pour les totaux du tableau export interface ProductTableTotals { subtotal: number; shippingCost: number; taxCost: number; taxRate: number; discount: number; total: number; } // ✅ NEW: Structure complète pour les données product_table // Les frais sont au même niveau que les produits, pas imbriqués dans les totaux export interface ProductTableData { products: ProductTableProduct[]; fees: ProductTableFee[]; // ✅ REFACTOR: Frais au même niveau que produits totals: ProductTableTotals; } export interface TemplateState { id?: string; name?: string; description?: string; tags?: string[]; canvasWidth?: number; canvasHeight?: number; marginTop?: number; marginBottom?: number; marginLeft?: number; marginRight?: number; showGuides?: boolean; snapToGrid?: boolean; isNew: boolean; isModified: boolean; isSaving: boolean; isLoading: boolean; // ✅ NEW: Template is loading from AJAX lastSaved?: Date; } export interface BaseElement { id: string; type: string; x: number; y: number; width: number; height: number; rotation?: number; opacity?: number; visible: boolean; locked: boolean; createdAt: Date; updatedAt: Date; // ✅ NEW: Support pour données réelles vs fictives /** Indique si cet élément utilise des données réelles (WooCommerce) */ isRealDataElement?: boolean; /** Valeur fictive/par défaut affichée en édition */ defaultTestValue?: unknown; /** Identifiant de la propriété réelle à récupérer depuis WooCommerce */ realDataKey?: string; // ✅ NEW: Propriétés optionnelles pour les images et logos borderRadius?: number; objectFit?: string; } export interface BaseElementProperties { backgroundColor?: string; borderColor?: string; borderWidth?: number; borderRadius?: number; padding?: number; showBackground?: boolean; fillColor?: string; strokeColor?: string; strokeWidth?: number; } export interface WoocommerceOrderDateElement extends BaseElement { type: "woocommerce_order_date"; verticalAlign?: VerticalAlign; dateFormat?: string; showTime?: boolean; fontFamily?: string; fontSize?: number; textColor?: string; color?: string; // Alias pour textColor pour compatibilité fontWeight?: string; fontStyle?: string; textAlign?: string; padding?: { top?: number; right?: number; bottom?: number; left?: number }; border?: { width?: number; style?: string; color?: string }; backgroundColor?: string; showBackground?: boolean; // Propriétés du label showLabel?: boolean; labelText?: string; labelPosition?: LabelPosition; labelFontFamily?: string; labelFontSize?: number; labelFontWeight?: string; labelFontStyle?: string; labelColor?: string; labelSpacing?: number; // Espacement entre le label et la date } export interface WoocommerceInvoiceNumberElement extends BaseElement { type: "woocommerce_invoice_number"; prefix?: string; suffix?: string; fontFamily?: string; fontSize?: number; textColor?: string; color?: string; // Alias pour textColor pour compatibilité fontWeight?: string; fontStyle?: string; textAlign?: string; verticalAlign?: VerticalAlign; padding?: { top?: number; right?: number; bottom?: number; left?: number }; border?: { width?: number; style?: string; color?: string }; backgroundColor?: string; showBackground?: boolean; // Propriétés du label showLabel?: boolean; labelText?: string; labelPosition?: LabelPosition; labelFontFamily?: string; labelFontSize?: number; labelFontWeight?: string; labelFontStyle?: string; labelColor?: string; labelSpacing?: number; // Espacement entre le label et le numéro } export interface DynamicTextElement extends BaseElement { type: "dynamic_text"; text?: string; content?: string; textTemplate?: string; theme?: string; textDecoration?: string; fontSize?: number; textColor?: string; color?: string; // Alias pour textColor pour compatibilité fontFamily?: string; fontWeight?: string; fontStyle?: string; textAlign?: TextAlign; autoWrap?: boolean; bold?: boolean; italic?: boolean; underline?: boolean; showBackground?: boolean; backgroundColor?: string; padding?: number; } export interface ProductTableElement extends BaseElement { type: "product_table"; // Propriétés d'affichage showHeaders?: boolean; showBorders?: boolean; showAlternatingRows?: boolean; showSku?: boolean; showDescription?: boolean; showQuantity?: boolean; showPrice?: boolean; showTotal?: boolean; showImage?: boolean; // ✅ NEW: Afficher les images des produits showShipping?: boolean; showTax?: boolean; showGlobalDiscount?: boolean; // Propriétés de police globale globalFontSize?: number; globalFontFamily?: string; globalFontWeight?: string; globalFontStyle?: string; globalFontEnabled?: boolean; // Propriétés de police fontSize?: number; fontFamily?: string; fontWeight?: string; fontStyle?: string; headerFontSize?: number; headerFontFamily?: string; headerFontWeight?: string; headerFontStyle?: string; bodyFontSize?: number; bodyFontFamily?: string; bodyFontWeight?: string; bodyFontStyle?: string; rowFontSize?: number; rowFontFamily?: string; rowFontWeight?: string; rowFontStyle?: string; totalFontSize?: number; totalFontFamily?: string; totalFontWeight?: string; totalFontStyle?: string; // Propriétés d'alignement textAlign?: TextAlign; headerBackgroundColor?: string; headerTextColor?: string; bodyBackgroundColor?: string; bodyTextColor?: string; alternateRowColor?: string; rowTextColor?: string; totalTextColor?: string; // Propriétés de thème et style theme?: string; textColor?: string; backgroundColor?: string; borderColor?: string; borderWidth?: number; borderRadius?: number; currency?: string; // Propriétés de données shippingCost?: number; taxRate?: number; globalDiscount?: number; orderFees?: number; verticalAlign?: VerticalAlign; // Propriétés de colonnes columns?: Array<{ id: string; label: string; [key: string]: any }>; // ✅ NEW: Données produits, frais et totaux /** Produits affichés dans le tableau (fictifs en édition, réels en aperçu) */ products?: ProductTableProduct[]; /** Frais (port, paiement, emballage, etc.) affichés au même niveau que produits */ fees?: ProductTableFee[]; /** Totaux du tableau (subtotaux, taxes, remise, total final) */ totals?: ProductTableTotals; } export interface MentionsElement extends BaseElement { type: "mentions"; mentionType?: string; selectedMentions?: string[]; medleySeparator?: string; separator?: string; separatorStyle?: string; separatorColor?: string; separatorWidth?: number; showEmail?: boolean; showPhone?: boolean; showAddress?: boolean; showSiret?: boolean; showVat?: boolean; showRcs?: boolean; showCapital?: boolean; theme?: string; content?: string; lineHeight?: number; margin?: number; padding?: number; text?: string; textColor?: string; fontFamily?: string; fontSize?: number; fontWeight?: string; fontStyle?: string; textAlign?: string; textDecoration?: string; textTransform?: string; wordSpacing?: string; backgroundColor?: string; borderColor?: string; borderWidth?: number; borderStyle?: string; borderRadius?: number; showSeparator?: boolean; showBackground?: boolean; } export interface CustomerInfoElement extends BaseElement { type: "customer_info"; showName?: boolean; showEmail?: boolean; showPhone?: boolean; showAddress?: boolean; showCompany?: boolean; showPaymentMethod?: boolean; showTransactionId?: boolean; labelColor?: string; valueColor?: string; separator?: string; // Propriétés de police pour l'en-tête headerFontSize?: number; headerFontFamily?: string; headerFontWeight?: string; headerFontStyle?: string; // Propriétés de police pour le corps du texte bodyFontSize?: number; bodyFontFamily?: string; bodyFontWeight?: string; bodyFontStyle?: string; bodyTextColor?: string; // Propriétés de mise en page layout?: CustomerInfoLayout; showLabels?: boolean; labelPosition?: "before" | "above"; // Propriétés de style générales fontFamily?: string; fontSize?: number; fontWeight?: string; fontStyle?: string; textColor?: string; color?: string; // Alias pour textColor pour compatibilité textAlign?: TextAlign; backgroundColor?: string; showBackground?: boolean; border?: { width?: number; style?: string; color?: string }; padding?: number | { top?: number; right?: number; bottom?: number; left?: number }; } export interface CompanyInfoElement extends BaseElement { type: "company_info"; template?: string; fields?: string[]; layout?: CustomerInfoLayout; separator?: string; // Informations de l'entreprise name?: string; address?: string; phone?: string; email?: string; website?: string; taxId?: string; registrationNumber?: string; companyName?: string; companyAddress?: string; companyCity?: string; companySiret?: string; companyTva?: string; companyRcs?: string; companyCapital?: string; companyEmail?: string; companyPhone?: string; // Propriétés de style fontFamily?: string; fontSize?: number; fontWeight?: string; fontStyle?: string; textColor?: string; color?: string; // Alias pour textColor pour compatibilité textAlign?: TextAlign; backgroundColor?: string; showBackground?: boolean; border?: { width?: number; style?: string; color?: string }; padding?: | number | { top?: number; right?: number; bottom?: number; left?: number }; borderColor?: string; borderWidth?: number; showIcons?: boolean; iconsPosition?: "left" | "right"; iconsSize?: number; iconsColor?: string; headerFontSize?: number; headerFontFamily?: string; headerFontWeight?: string; headerFontStyle?: string; bodyFontSize?: number; bodyFontFamily?: string; bodyFontWeight?: string; bodyFontStyle?: string; headerTextColor?: string; showCompanyName?: boolean; showAddress?: boolean; showEmail?: boolean; showPhone?: boolean; showSiret?: boolean; showVat?: boolean; showRcs?: boolean; showCapital?: boolean; lineHeight?: number; verticalAlign?: VerticalAlign; } export interface ElementProperties { [key: string]: unknown; } export interface CanvasState { zoom: number; pan: Point; showGrid: boolean; gridSize: number; snapToGrid: boolean; backgroundColor: string; } export interface SelectionState { selectedElements: string[]; selectionBounds?: Bounds; isSelecting: boolean; selectionStart?: Point; selectionEnd?: Point; } export interface DragState { isDragging: boolean; dragStart?: Point; dragOffset?: Point; draggedElements: string[]; } export interface BuilderState { elements: Element[]; canvas: CanvasState; selection: SelectionState; drag: DragState; mode: BuilderMode; history: HistoryState; // Propriétés du template template: TemplateState; // Mode de prévisualisation (éditeur vs commande) previewMode: "editor" | "command"; orderId?: string; // Modal de prévisualisation showPreviewModal: boolean; // Contenu HTML de l'aperçu htmlPreviewContent: string; } export type BuilderMode = | "select" | "rectangle" | "circle" | "text" | "image" | "line" | "pan" | "zoom"; export interface HistoryState { past: BuilderState[]; present: BuilderState; future: BuilderState[]; canUndo: boolean; canRedo: boolean; } export interface BuilderConfig { containerId: string; initialState?: Partial; enableHistory?: boolean; maxHistorySize?: number; enableKeyboard?: boolean; enableContextMenu?: boolean; theme?: "light" | "dark"; } // Événements export interface BuilderEvents { onElementAdded: (element: Element) => void; onElementUpdated: (element: Element) => void; onElementRemoved: (elementId: string) => void; onSelectionChanged: (selectedIds: string[]) => void; onCanvasChanged: (canvas: CanvasState) => void; onModeChanged: (mode: BuilderMode) => void; onHistoryChanged: (history: HistoryState) => void; } // Actions pour le reducer export type BuilderAction = | { type: "ADD_ELEMENT"; payload: Element } | { type: "UPDATE_ELEMENT"; payload: { id: string; updates: Partial }; } | { type: "REMOVE_ELEMENT"; payload: string } | { type: "SET_ELEMENTS"; payload: Element[] } | { type: "SET_SELECTION"; payload: string[] } | { type: "CLEAR_SELECTION" } | { type: "SET_CANVAS"; payload: Partial } | { type: "SET_MODE"; payload: BuilderMode } | { type: "SET_DRAG_STATE"; payload: Partial } | { type: "SET_PREVIEW_MODE"; payload: "editor" | "command" } | { type: "SET_SHOW_PREVIEW_MODAL"; payload: boolean } | { type: "SET_HTML_PREVIEW_CONTENT"; payload: string } | { type: "SET_ORDER_ID"; payload: string | undefined } | { type: "UNDO" } | { type: "REDO" } | { type: "RESET" } | { type: "SAVE_TEMPLATE"; payload?: { id?: string; name?: string; lastSaved?: Date }; } | { type: "SET_TEMPLATE_MODIFIED"; payload: boolean } | { type: "SET_TEMPLATE_SAVING"; payload: boolean } | { type: "SET_TEMPLATE_LOADING"; payload: boolean } | { type: "UPDATE_TEMPLATE_SETTINGS"; payload: Partial } | { type: "TOGGLE_GUIDES" } | { type: "LOAD_TEMPLATE"; payload: LoadTemplatePayload; } | { type: "NEW_TEMPLATE" }; // Props des composants export interface CanvasProps { width: number; height: number; state: BuilderState; onStateChange: (action: BuilderAction) => void; className?: string; } export interface ToolbarProps { mode: BuilderMode; onModeChange: (mode: BuilderMode) => void; onAction: (action: string) => void; disabled?: boolean; } export interface PropertiesPanelProps { selectedElements: Element[]; onUpdateElement: (id: string, updates: Partial) => void; onDeleteElements: (ids: string[]) => void; } export interface LoadTemplatePayload { id?: string; name?: string; description?: string; elements?: Element[]; canvas?: Partial; lastSaved?: Date; showGuides?: boolean; snapToGrid?: boolean; marginTop?: number; marginBottom?: number; marginLeft?: number; marginRight?: number; } // Propriétés spécifiques pour les éléments export interface RectangleElement extends BaseElement { type: "rectangle"; backgroundColor?: string; borderColor?: string; borderWidth?: number; borderRadius?: number; fillColor?: string; strokeColor?: string; strokeWidth?: number; padding?: number; } export interface CircleElement extends BaseElement { type: "circle"; backgroundColor?: string; borderColor?: string; borderWidth?: number; fillColor?: string; strokeColor?: string; strokeWidth?: number; padding?: number; } export interface TextElement extends BaseElement { type: "text"; text?: string; padding?: number; fontSize?: number; textColor?: string; color?: string; // Alias pour textColor pour compatibilité fontFamily?: string; fontWeight?: string; fontStyle?: string; textAlign?: TextAlign; align?: TextAlign; // Alias pour textAlign pour compatibilité textDecoration?: string; autoWrap?: boolean; bold?: boolean; italic?: boolean; underline?: boolean; backgroundColor?: string; borderColor?: string; borderWidth?: number; verticalAlign?: VerticalAlign; lineHeight?: number; } export interface LineElement extends BaseElement { type: "line"; backgroundColor?: string; borderColor?: string; borderWidth?: number; strokeColor?: string; strokeWidth?: number; } export interface DynamicTextElementProperties extends BaseElementProperties { textTemplate?: string; theme?: string; textDecoration?: string; } export interface DocumentTypeElementProperties extends BaseElementProperties { documentType?: string; verticalAlign?: VerticalAlign; } export interface CustomerInfoElementProperties extends BaseElementProperties { showName?: boolean; showEmail?: boolean; showPhone?: boolean; showAddress?: boolean; showCompany?: boolean; showPaymentMethod?: boolean; showTransactionId?: boolean; labelColor?: string; valueColor?: string; separator?: string; // Propriétés de police pour l'en-tête headerFontSize?: number; headerFontFamily?: string; headerFontWeight?: string; headerFontStyle?: string; // Propriétés de police pour le corps du texte bodyFontSize?: number; bodyFontFamily?: string; bodyFontWeight?: string; bodyFontStyle?: string; // Propriétés de mise en page layout?: CustomerInfoLayout; showHeaders?: boolean; showBorders?: boolean; showFullName?: boolean; // ✅ NEW: Padding interne padding?: number; // Propriétés de style headerTextColor?: string; verticalAlign?: VerticalAlign; // Propriétés d'icônes showIcons?: boolean; iconsPosition?: "left" | "right"; iconsSize?: number; iconsColor?: string; } export interface CompanyInfoElementProperties extends BaseElementProperties { showCompanyName?: boolean; showAddress?: boolean; showPhone?: boolean; showEmail?: boolean; showWebsite?: boolean; showTaxId?: boolean; logoUrl?: string; logoWidth?: number; logoHeight?: number; separator?: string; // Propriétés de padding spécifiques paddingTop?: number; paddingHorizontal?: number; paddingBottom?: number; // Propriétés d'espacement lineSpacing?: number; letterSpacing?: number; // Propriétés de police pour l'en-tête (nom de l'entreprise) headerFontSize?: number; headerFontFamily?: string; headerFontWeight?: string; headerFontStyle?: string; // Propriétés de police pour le corps du texte bodyFontSize?: number; bodyFontFamily?: string; bodyFontWeight?: string; bodyFontStyle?: string; // Propriétés de thème et style theme?: string; showHeaders?: boolean; showBorders?: boolean; showSiret?: boolean; showVat?: boolean; showRcs?: boolean; showCapital?: boolean; headerTextColor?: string; // Propriétés de données d'entreprise companyName?: string; companyAddress?: string; companyCity?: string; companySiret?: string; companyTva?: string; companyRcs?: string; companyCapital?: string; companyEmail?: string; companyPhone?: string; // Propriétés d'icônes showIcons?: boolean; iconsPosition?: "left" | "right"; iconsSize?: number; iconsColor?: string; verticalAlign?: VerticalAlign; } export interface ImageElement extends BaseElement { type: "image"; src?: string; logoUrl?: string; alt?: string; fit?: "contain" | "cover" | "fill" | "none" | "scale-down"; position?: | "center" | "top" | "bottom" | "left" | "right" | "top-left" | "top-right" | "bottom-left" | "bottom-right"; opacity?: number; alignment?: TextAlign; maintainAspectRatio?: boolean; } // Interface spécifique pour les éléments CompanyInfo export interface CompanyInfoElement extends BaseElement { type: "company_info"; // Propriétés d'affichage showCompanyName?: boolean; showAddress?: boolean; showPhone?: boolean; showEmail?: boolean; showWebsite?: boolean; showTaxId?: boolean; // Propriétés de logo logoUrl?: string; logoWidth?: number; logoHeight?: number; separator?: string; // Propriétés de police pour l'en-tête (nom de l'entreprise) headerFontSize?: number; headerFontFamily?: string; headerFontWeight?: string; headerFontStyle?: string; // Propriétés de police pour le corps du texte bodyFontSize?: number; bodyFontFamily?: string; bodyFontWeight?: string; bodyFontStyle?: string; // Propriétés de thème et style theme?: string; showHeaders?: boolean; showBorders?: boolean; showSiret?: boolean; showVat?: boolean; showRcs?: boolean; showCapital?: boolean; headerTextColor?: string; // Propriétés de données d'entreprise companyName?: string; companyAddress?: string; companyCity?: string; companySiret?: string; companyTva?: string; companyRcs?: string; companyCapital?: string; companyEmail?: string; companyPhone?: string; // Propriétés de padding padding?: number | { top?: number; right?: number; bottom?: number; left?: number }; // Backward compatibility paddingTop?: number; paddingHorizontal?: number; paddingBottom?: number; // Propriétés de border borderColor?: string; borderWidth?: number; backgroundColor?: string; // Propriétés d'icônes showIcons?: boolean; iconsPosition?: "left" | "right"; iconsSize?: number; iconsColor?: string; // Propriétés d'espacement lineHeight?: number; lineSpacing?: number; } // Interface spécifique pour les éléments CompanyLogo // Interface spécifique pour les éléments CustomerInfo export interface CustomerInfoElement extends BaseElement { type: "customer_info"; // Propriétés d'affichage showName?: boolean; showEmail?: boolean; showPhone?: boolean; showAddress?: boolean; showCompany?: boolean; showPaymentMethod?: boolean; showTransactionId?: boolean; // Propriétés de couleur labelColor?: string; valueColor?: string; separator?: string; // Propriétés de police pour l'en-tête headerFontSize?: number; headerFontFamily?: string; headerFontWeight?: string; headerFontStyle?: string; // Propriétés de police pour le corps du texte bodyFontSize?: number; bodyFontFamily?: string; bodyFontWeight?: string; bodyFontStyle?: string; // Propriétés de mise en page layout?: CustomerInfoLayout; showHeaders?: boolean; showBorders?: boolean; showFullName?: boolean; // ✅ NEW: Padding interne padding?: number | { top?: number; right?: number; bottom?: number; left?: number }; // Backward compatibility // Propriétés de style headerTextColor?: string; verticalAlign?: VerticalAlign; borderColor?: string; borderWidth?: number; backgroundColor?: string; // Propriétés d'espacement lineHeight?: number; lineSpacing?: number; letterSpacing?: number; } export interface DocumentTypeElement extends BaseElement { type: "document_type"; documentType?: string; verticalAlign?: VerticalAlign; fontSize?: number; fontFamily?: string; fontWeight?: string; fontStyle?: string; textColor?: string; backgroundColor?: string; showBackground?: boolean; textAlign?: TextAlign; padding?: number; borderColor?: string; borderWidth?: number; } // Interface spécifique pour CompanyLogoElement export interface CompanyLogoElement extends BaseElement { type: "company_logo"; logoUrl?: string; src?: string; alt?: string; altText?: string; fit?: "contain" | "cover" | "fill" | "none" | "scale-down"; position?: | "center" | "top" | "bottom" | "left" | "right" | "top-left" | "top-right" | "bottom-left" | "bottom-right"; opacity?: number; alignment?: TextAlign; maintainAspectRatio?: boolean; borderRadius?: number; objectFit?: string; backgroundColor?: string; } // Type union pour tous les éléments supportés export type Element = | WoocommerceOrderDateElement | WoocommerceInvoiceNumberElement | DynamicTextElement | ProductTableElement | MentionsElement | CustomerInfoElement | CompanyInfoElement | RectangleElement | CircleElement | TextElement | LineElement | ImageElement | CompanyLogoElement | DocumentTypeElement;