import React, { useState } from "react";
import { CompanyInfoElement } from "../../types/elements";
import { NumericPropertyInput } from "../ui/NumericPropertyInput";
import { ColorPropertyInput } from "../ui/ColorPropertyInput";
import { getEditorFeatureFlags, getPdfBuilderData } from "../../utils/editorFeatures";
interface CompanyInfoPropertiesProps {
element: CompanyInfoElement;
onChange: (elementId: string, property: string, value: unknown) => void;
activeTab: {
[key: string]: "fonctionnalites" | "personnalisation" | "positionnement";
};
setActiveTab: (tabs: {
[key: string]: "fonctionnalites" | "personnalisation" | "positionnement";
}) => void;
}
// Composant Toggle personnalisé
const Toggle = ({
checked,
onChange,
label,
description,
}: {
checked: boolean;
onChange: (checked: boolean) => void;
label: string;
description: string;
}) => (
{label}
onChange(!checked)}
style={{
position: "relative",
width: "44px",
height: "24px",
backgroundColor: checked ? "#007bff" : "#ccc",
borderRadius: "12px",
cursor: "pointer",
transition: "background-color 0.2s ease",
border: "none",
}}
>
{description}
);
export function CompanyInfoProperties({
element,
onChange,
activeTab,
setActiveTab,
}: CompanyInfoPropertiesProps) {
const companyCurrentTab = activeTab[element.id] || "fonctionnalites";
const setCompanyCurrentTab = (
tab: "fonctionnalites" | "personnalisation" | "positionnement",
) => {
setActiveTab({ ...activeTab, [element.id]: tab });
};
const pdfBuilderData = getPdfBuilderData();
const { canUseEditorThemes } = getEditorFeatureFlags();
// Helper pour normaliser le padding en nombre (gère les objets padding complexes)
const _normalizePadding = (
value:
| number
| { top?: number; right?: number; bottom?: number; left?: number }
| undefined,
defaultValue: number = 12,
): number => {
if (typeof value === "number") return value;
if (typeof value === "object" && value !== null) {
// Si c'est un objet, on prend la moyenne ou la première valeur disponible
return (
value.top ?? value.left ?? value.right ?? value.bottom ?? defaultValue
);
}
return defaultValue;
};
// Fonction pour générer le contenu des infos entreprise depuis les propriétés
const generateCompanyContent = (props?: any) => {
const config = props || element;
const companyParts: string[] = [];
// Récupérer les données d'entreprise depuis window
const pluginCompany = pdfBuilderData.company || {};
// Helper pour valider une valeur
const isValidValue = (value: any): boolean => {
return value && value.toString().trim() !== "" && value !== "Non indiqué";
};
// Nom de l'entreprise (header)
if (config.showCompanyName !== false) {
const companyName = config.companyName || pluginCompany.name || "";
if (isValidValue(companyName)) {
const _headerFontSize = config.headerFontSize || config.fontSize || 14;
const _headerFontWeight = config.headerFontWeight || "bold";
const _headerColor =
config.headerTextColor || config.textColor || "#000000";
companyParts.push(`Entreprise: ${companyName}`);
}
}
// Adresse
if (config.showAddress !== false) {
const address = config.companyAddress || pluginCompany.address || "";
const city = config.companyCity || pluginCompany.city || "";
if (isValidValue(address)) {
let fullAddress = address;
if (isValidValue(city)) fullAddress += `, ${city}`;
companyParts.push(fullAddress);
}
}
// Téléphone
if (config.showPhone !== false) {
const phone = config.companyPhone || pluginCompany.phone || "";
if (isValidValue(phone)) {
companyParts.push(`Tél: ${phone}`);
}
}
// Email
if (config.showEmail !== false) {
const email = config.companyEmail || pluginCompany.email || "";
if (isValidValue(email)) {
companyParts.push(`Email: ${email}`);
}
}
// SIRET
if (config.showSiret !== false) {
const siret = config.companySiret || pluginCompany.siret || "";
if (isValidValue(siret)) {
companyParts.push(`SIRET: ${siret}`);
}
}
// TVA
if (config.showVat !== false) {
const tva = config.companyTva || pluginCompany.vat || "";
if (isValidValue(tva)) {
companyParts.push(`TVA: ${tva}`);
}
}
// RCS
if (config.showRcs !== false) {
const rcs = config.companyRcs || pluginCompany.rcs || "";
if (isValidValue(rcs)) {
companyParts.push(`RCS: ${rcs}`);
}
}
// Capital
if (config.showCapital !== false) {
const capital = config.companyCapital || pluginCompany.capital || "";
if (isValidValue(capital)) {
companyParts.push(`Capital: ${capital} €`);
}
}
// Assembler avec séparateur (newline pour vertical)
return companyParts.join("\n");
};
// Helper pour toggler et régénérer le contenu
const handlePropertyChangeWithContentUpdate = (
property: string,
value: any,
) => {
onChange(element.id, property, value);
// Si c'est une propriété qui affecte le contenu, régénérer et sauvegarder
if (
[
"showCompanyName",
"showAddress",
"showPhone",
"showEmail",
"showSiret",
"showVat",
"showRcs",
"showCapital",
].includes(property)
) {
const newConfig = { ...element, [property]: value };
const generatedContent = generateCompanyContent(newConfig);
if (generatedContent && generatedContent.trim()) {
onChange(element.id, "content", generatedContent);
}
}
};
// État pour les accordéons de police
const [fontAccordions, setFontAccordions] = useState({
headerFont: false, // Accordéon du nom de l'entreprise fermé par défaut
bodyFont: false, // Accordéon des informations fermé par défaut
layout: true, // Accordéon disposition ouvert par défaut
themes: false, // Accordéon thèmes fermé par défaut
colors: false, // Accordéon couleurs fermé par défaut
});
const toggleAccordion = (accordion: "headerFont" | "bodyFont") => {
setFontAccordions((prev) => ({
...prev,
[accordion]: !prev[accordion],
}));
};
const companyThemes = [
{
id: "corporate",
name: "Corporate",
preview: (
),
styles: {
backgroundColor: "#ffffff",
borderColor: "#1f2937",
textColor: "#374151",
headerTextColor: "#111827",
},
},
{
id: "modern",
name: "Moderne",
preview: (
),
styles: {
backgroundColor: "#ffffff",
borderColor: "#3b82f6",
textColor: "#1e40af",
headerTextColor: "#1e3a8a",
},
},
{
id: "elegant",
name: "Élégant",
preview: (
),
styles: {
backgroundColor: "#ffffff",
borderColor: "#8b5cf6",
textColor: "#6d28d9",
headerTextColor: "#581c87",
},
},
{
id: "minimal",
name: "Minimal",
preview: (
),
styles: {
backgroundColor: "#ffffff",
borderColor: "#e5e7eb",
textColor: "#374151",
headerTextColor: "#111827",
},
},
{
id: "professional",
name: "Professionnel",
preview: (
),
styles: {
backgroundColor: "#ffffff",
borderColor: "#059669",
textColor: "#065f46",
headerTextColor: "#064e3b",
},
},
{
id: "classic",
name: "Classique",
preview: (
),
styles: {
backgroundColor: "#ffffff",
borderColor: "#92400e",
textColor: "#78350f",
headerTextColor: "#451a03",
},
},
];
return (
<>
{/* Système d'onglets pour Company Info */}
setCompanyCurrentTab("fonctionnalites")}
style={{
flex: "1 1 30%",
padding: "8px 6px",
backgroundColor:
companyCurrentTab === "fonctionnalites" ? "#007bff" : "#f0f0f0",
color: companyCurrentTab === "fonctionnalites" ? "#fff" : "#333",
border: "none",
cursor: "pointer",
fontSize: "11px",
fontWeight: "bold",
borderRadius: "3px 3px 0 0",
minWidth: "0",
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
title="Fonctionnalités"
>
Fonctionnalités
setCompanyCurrentTab("personnalisation")}
style={{
flex: "1 1 30%",
padding: "8px 6px",
backgroundColor:
companyCurrentTab === "personnalisation" ? "#007bff" : "#f0f0f0",
color: companyCurrentTab === "personnalisation" ? "#fff" : "#333",
border: "none",
cursor: "pointer",
fontSize: "11px",
fontWeight: "bold",
borderRadius: "3px 3px 0 0",
minWidth: "0",
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
title="Personnalisation"
>
Personnalisation
setCompanyCurrentTab("positionnement")}
style={{
flex: "1 1 30%",
padding: "8px 6px",
backgroundColor:
companyCurrentTab === "positionnement" ? "#007bff" : "#f0f0f0",
color: companyCurrentTab === "positionnement" ? "#fff" : "#333",
border: "none",
cursor: "pointer",
fontSize: "11px",
fontWeight: "bold",
borderRadius: "3px 3px 0 0",
minWidth: "0",
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
title="Positionnement"
>
Positionnement
{/* Onglet Fonctionnalités */}
{companyCurrentTab === "fonctionnalites" && (
<>
{/* Section Structure des informations */}
Structure des informations
onChange(element.id, "showBackground", checked)
}
label="Afficher le fond"
description="Affiche un fond coloré derrière les informations"
/>
onChange(element.id, "showBorders", checked)
}
label="Afficher les bordures"
description="Affiche les bordures autour des sections"
/>
{/* Section Informations générales */}
Informations générales
handlePropertyChangeWithContentUpdate(
"showCompanyName",
checked,
)
}
label="Afficher le nom de l'entreprise"
description="Nom de l'entreprise"
/>
{/* Section Coordonnées */}
Coordonnées
handlePropertyChangeWithContentUpdate("showAddress", checked)
}
label="Afficher l'adresse"
description="Adresse complète de l'entreprise"
/>
handlePropertyChangeWithContentUpdate("showPhone", checked)
}
label="Afficher le téléphone"
description="Numéro de téléphone"
/>
handlePropertyChangeWithContentUpdate("showEmail", checked)
}
label="Afficher l'email"
description="Adresse email de l'entreprise"
/>
{/* Section Informations légales */}
Informations légales
onChange(element.id, "showSiret", checked)
}
label="Afficher le numéro SIRET"
description="Numéro SIRET de l'entreprise"
/>
onChange(element.id, "showVat", checked)}
label="Afficher le numéro TVA"
description="Numéro TVA de l'entreprise"
/>
onChange(element.id, "showRcs", checked)}
label="Afficher le RCS"
description="Registre du Commerce et des Sociétés"
/>
onChange(element.id, "showCapital", checked)
}
label="Afficher le capital social"
description="Montant du capital social de l'entreprise"
/>
>
)}
{/* Onglet Personnalisation */}
{companyCurrentTab === "personnalisation" && (
<>
{/* Accordéon Disposition */}
setFontAccordions((prev) => ({ ...prev, layout: !prev.layout }))
}
style={{
padding: "12px",
backgroundColor: "#f8f9fa",
cursor: "pointer",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
borderBottom: fontAccordions.layout
? "1px solid #e9ecef"
: "none",
}}
>
Disposition
▼
{fontAccordions.layout && (
Type de disposition
onChange(element.id, "layout", e.target.value)
}
style={{
width: "100%",
padding: "4px 8px",
border: "1px solid #ccc",
borderRadius: "3px",
fontSize: "12px",
}}
>
Verticale
Horizontale
Compacte
Alignement du texte
onChange(element.id, "textAlign", e.target.value)
}
style={{
width: "100%",
padding: "4px 8px",
border: "1px solid #ccc",
borderRadius: "3px",
fontSize: "12px",
}}
>
Gauche
Centre
Droite
{/* Alignement vertical */}
Alignement vertical
onChange(element.id, "verticalAlign", e.target.value)
}
style={{
width: "100%",
padding: "4px 8px",
border: "1px solid #ccc",
borderRadius: "3px",
fontSize: "12px",
}}
>
Haut
Milieu
Bas
{/* Padding top */}
Marge supérieure (px)
onChange(
element.id,
"paddingTop",
parseInt(e.target.value) || 0,
)
}
min="0"
max="50"
style={{
width: "100%",
padding: "4px 8px",
border: "1px solid #ccc",
borderRadius: "3px",
fontSize: "12px",
}}
/>
{/* Padding horizontal */}
Marge latérale (px)
onChange(
element.id,
"paddingHorizontal",
parseInt(e.target.value) || 0,
)
}
min="0"
max="50"
style={{
width: "100%",
padding: "4px 8px",
border: "1px solid #ccc",
borderRadius: "3px",
fontSize: "12px",
}}
/>
{/* Padding bottom */}
Marge inférieure (px)
onChange(
element.id,
"paddingBottom",
parseInt(e.target.value) || 0,
)
}
min="0"
max="50"
style={{
width: "100%",
padding: "4px 8px",
border: "1px solid #ccc",
borderRadius: "3px",
fontSize: "12px",
}}
/>
{/* Line spacing */}
Espacement entre lignes (px)
onChange(
element.id,
"lineSpacing",
parseInt(e.target.value) || 0,
)
}
min="0"
max="20"
style={{
width: "100%",
padding: "4px 8px",
border: "1px solid #ccc",
borderRadius: "3px",
fontSize: "12px",
}}
/>
{/* Line-height (CSS) */}
)}
{canUseEditorThemes && (
<>
{/* Accordéon Thèmes prédéfinis */}
setFontAccordions((prev) => ({ ...prev, themes: !prev.themes }))
}
style={{
padding: "12px",
backgroundColor: "#f8f9fa",
cursor: "pointer",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
borderBottom: fontAccordions.themes
? "1px solid #e9ecef"
: "none",
}}
>
Thèmes prédéfinis
▼
{fontAccordions.themes && (
{companyThemes.map((theme) => (
{
// Appliquer le thème et toutes ses couleurs
onChange(element.id, "theme", theme.id);
onChange(
element.id,
"backgroundColor",
theme.styles.backgroundColor,
);
onChange(
element.id,
"borderColor",
theme.styles.borderColor,
);
onChange(
element.id,
"textColor",
theme.styles.textColor,
);
onChange(
element.id,
"headerTextColor",
theme.styles.headerTextColor,
);
}}
style={{
cursor: "pointer",
border:
element.theme === theme.id
? "2px solid #007bff"
: "2px solid transparent",
borderRadius: "6px",
padding: "6px",
backgroundColor: "#ffffff",
transition: "all 0.2s ease",
}}
title={theme.name}
>
{theme.name}
{theme.preview}
))}
)}
>
)}
{/* Police du nom de l'entreprise - Accordéon */}
{element.showCompanyName !== false && (
toggleAccordion("headerFont")}
style={{
padding: "12px",
backgroundColor: "#f8f9fa",
cursor: "pointer",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
borderBottom: fontAccordions.headerFont
? "1px solid #e9ecef"
: "none",
}}
>
Police du nom de l'entreprise
▼
{fontAccordions.headerFont && (
onChange(element.id, "headerFontSize", value)
}
/>
Famille de police
onChange(element.id, "headerFontFamily", e.target.value)
}
style={{
width: "100%",
padding: "4px 8px",
border: "1px solid #ccc",
borderRadius: "3px",
fontSize: "12px",
}}
>
Arial
Helvetica
Times New Roman
Georgia
Verdana
Tahoma
Trebuchet MS
Calibri
Cambria
Segoe UI
Épaisseur de police
onChange(element.id, "headerFontWeight", e.target.value)
}
style={{
width: "100%",
padding: "4px 8px",
border: "1px solid #ccc",
borderRadius: "3px",
fontSize: "12px",
}}
>
Normal (400)
Gras (700)
Fin (300)
Très gras (900)
Style de police
onChange(element.id, "headerFontStyle", e.target.value)
}
style={{
width: "100%",
padding: "4px 8px",
border: "1px solid #ccc",
borderRadius: "3px",
fontSize: "12px",
}}
>
Normal
Italique
Oblique
)}
)}
{/* Police du corps du texte - Accordéon */}
toggleAccordion("bodyFont")}
style={{
padding: "12px",
backgroundColor: "#f8f9fa",
cursor: "pointer",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
borderBottom: fontAccordions.bodyFont
? "1px solid #e9ecef"
: "none",
}}
>
Police des informations
▼
{fontAccordions.bodyFont && (
onChange(element.id, "bodyFontSize", value)
}
/>
Famille de police
onChange(element.id, "bodyFontFamily", e.target.value)
}
style={{
width: "100%",
padding: "4px 8px",
border: "1px solid #ccc",
borderRadius: "3px",
fontSize: "12px",
}}
>
Arial
Helvetica
Times New Roman
Georgia
Verdana
Tahoma
Trebuchet MS
Calibri
Cambria
Segoe UI
Épaisseur de police
onChange(element.id, "bodyFontWeight", e.target.value)
}
style={{
width: "100%",
padding: "4px 8px",
border: "1px solid #ccc",
borderRadius: "3px",
fontSize: "12px",
}}
>
Normal (400)
Gras (700)
Fin (300)
Très gras (900)
Style de police
onChange(element.id, "bodyFontStyle", e.target.value)
}
style={{
width: "100%",
padding: "4px 8px",
border: "1px solid #ccc",
borderRadius: "3px",
fontSize: "12px",
}}
>
Normal
Italique
Oblique
)}
{/* Accordéon Couleurs */}
setFontAccordions((prev) => ({ ...prev, colors: !prev.colors }))
}
style={{
padding: "12px",
backgroundColor: "#f8f9fa",
cursor: "pointer",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
borderBottom: fontAccordions.colors
? "1px solid #e9ecef"
: "none",
}}
>
Couleurs
▼
{fontAccordions.colors && (
{element.showBackground !== false && (
onChange(element.id, "backgroundColor", value)
}
/>
)}
{element.showBorders !== false && (
onChange(element.id, "borderColor", value)
}
/>
)}
{element.showBorders !== false && (
onChange(element.id, "borderWidth", value)
}
description="Épaisseur de la bordure en pixels"
/>
)}
onChange(element.id, "headerTextColor", value)
}
/>
onChange(element.id, "textColor", value)
}
/>
onChange(element.id, "textColor", value)
}
/>
)}
>
)}
{/* Onglet Positionnement */}
{companyCurrentTab === "positionnement" && (
<>
Position X: {element.x}px
onChange(element.id, "x", parseInt(e.target.value))
}
style={{
width: "100%",
height: "6px",
borderRadius: "3px",
background: "#ddd",
outline: "none",
cursor: "pointer",
}}
/>
Position Y: {element.y}px
onChange(element.id, "y", parseInt(e.target.value))
}
style={{
width: "100%",
height: "6px",
borderRadius: "3px",
background: "#ddd",
outline: "none",
cursor: "pointer",
}}
/>
Largeur: {element.width}px
onChange(element.id, "width", parseInt(e.target.value))
}
style={{
width: "100%",
height: "6px",
borderRadius: "3px",
background: "#ddd",
outline: "none",
cursor: "pointer",
}}
/>
Hauteur: {element.height}px
onChange(element.id, "height", parseInt(e.target.value))
}
style={{
width: "100%",
height: "6px",
borderRadius: "3px",
background: "#ddd",
outline: "none",
cursor: "pointer",
}}
/>
>
)}
>
);
}