import { MentionsElement } from "../../types/elements"; import { NumericPropertyInput } from "../ui/NumericPropertyInput"; import { ColorPropertyInput } from "../ui/ColorPropertyInput"; import { getEditorFeatureFlags, getPdfBuilderData } from "../../utils/editorFeatures"; type MentionTemplateOption = { key: string; label: string; text: string; }; type MentionThemeOption = { id: string; name: string; preview: any; styles: { backgroundColor: string; borderColor: string; textColor: string; separatorColor: string; borderWidth: number; borderStyle: string; showBackground?: boolean; }; }; // Composant Toggle personnalisé const Toggle = ({ checked, onChange, label, description, }: { checked: boolean; onChange: (checked: boolean) => void; label: string; description: string; }) => (
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}
); interface MentionsPropertiesProps { element: MentionsElement; onChange: (elementId: string, property: string, value: unknown) => void; activeTab: { [key: string]: "fonctionnalites" | "personnalisation" | "positionnement"; }; setActiveTab: (tabs: { [key: string]: "fonctionnalites" | "personnalisation" | "positionnement"; }) => void; } export function MentionsProperties({ element, onChange, activeTab, setActiveTab, }: MentionsPropertiesProps) { const mentionsCurrentTab = activeTab[element.id] || "fonctionnalites"; const setMentionsCurrentTab = ( tab: "fonctionnalites" | "personnalisation" | "positionnement", ) => { setActiveTab({ ...activeTab, [element.id]: tab }); }; const { canUseEditorThemes } = getEditorFeatureFlags(); const customMention: MentionTemplateOption = { key: "custom", label: "Personnalisé", text: "", }; const medleyMention: MentionTemplateOption = { key: "medley", label: "Médley (Combinaison)", text: "", }; const freeMentionOptions: MentionTemplateOption[] = [ { key: "legal", label: "Mentions légales", text: "Document établi sous la responsabilité de l'entreprise. Toutes les informations sont confidentielles.", }, { key: "payment", label: "Conditions de paiement", text: "Paiement dû dans les délais convenus. Tout retard peut entraîner des pénalités.", }, { key: "tva", label: "TVA et mentions fiscales", text: "TVA non applicable, art. 293 B du CGI. Mention : auto-entrepreneur soumise à l'impôt sur le revenu.", }, ]; const pdfBuilderData = getPdfBuilderData(); const premiumMentionOptions = ((pdfBuilderData.mentionsTemplatesPremium ?? []) as MentionTemplateOption[]); const allMentionOptions = [customMention, medleyMention, ...freeMentionOptions, ...premiumMentionOptions]; const allMentionKeys = new Set(allMentionOptions.map((mention) => mention.key)); const mentionsThemes: MentionThemeOption[] = [ { id: "clean", name: "Propre", preview: (
), styles: { backgroundColor: "#ffffff", borderColor: "#e5e7eb", textColor: "#374151", separatorColor: "#e5e7eb", borderWidth: 1, borderStyle: "solid", showBackground: true, }, }, { id: "subtle", name: "Discret", preview: (
), styles: { backgroundColor: "#f9fafb", borderColor: "#e5e7eb", textColor: "#6b7280", separatorColor: "#cbd5e1", borderWidth: 1, borderStyle: "solid", showBackground: true, }, }, { id: "highlighted", name: "Surligné", preview: (
), styles: { backgroundColor: "#eff6ff", borderColor: "#bfdbfe", textColor: "#1d4ed8", separatorColor: "#60a5fa", borderWidth: 1, borderStyle: "solid", showBackground: true, }, }, { id: "elegant", name: "Élégant", preview: (
), styles: { backgroundColor: "#ffffff", borderColor: "#ddd6fe", textColor: "#6d28d9", separatorColor: "#8b5cf6", borderWidth: 1, borderStyle: "solid", showBackground: true, }, }, ]; const getMedleySeparator = (separatorKey?: string) => { const separatorMap = { double_newline: "\n\n", single_newline: "\n", dash: " - ", bullet: " • ", pipe: " | ", }; return ( separatorMap[ (separatorKey || "double_newline") as keyof typeof separatorMap ] || "\n\n" ); }; // Fonction pour générer le contenu des mentions depuis les propriétés d'entreprise const generateMentionsContent = (props?: any) => { const config = props || element; const mentionParts: string[] = []; const pluginCompany = pdfBuilderData.company || {}; const NOT_SET = "Non indiqué"; const pick = (elementVal: string | undefined, companyVal: string): string => { const v = (elementVal && elementVal.trim()) ? elementVal.trim() : companyVal; return v === NOT_SET ? "" : v; }; // Email if (config.showEmail !== false) { const v = pick(config.email, pluginCompany.email || ""); if (v) mentionParts.push(v); } // Téléphone if (config.showPhone !== false) { const v = pick(config.phone, pluginCompany.phone || ""); if (v) mentionParts.push(v); } // Adresse (opt-in : doit être explicitement activé) if (config.showAddress === true) { const v = pick(config.address, pluginCompany.address || ""); if (v) mentionParts.push(v); } // SIRET if (config.showSiret !== false) { const v = pick(config.siret, pluginCompany.siret || ""); if (v) mentionParts.push(`SIRET: ${v}`); } // TVA if (config.showVat !== false) { const v = pick(config.tva, pluginCompany.vat || ""); if (v) mentionParts.push(`TVA: ${v}`); } // RCS (opt-in) if (config.showRcs === true) { const v = pick(config.rcs, pluginCompany.rcs || ""); if (v) mentionParts.push(`RCS: ${v}`); } // Capital (opt-in) if (config.showCapital === true) { const v = pick(config.capital, pluginCompany.capital || ""); if (v) mentionParts.push(`Capital: ${v}`); } const separator = config.separator || " • "; const companyText = mentionParts.join(separator); const currentMentionType = config.mentionType || element.mentionType || "custom"; const selectedText = currentMentionType === "medley" ? buildSelectedMentionsContent(config) : currentMentionType !== "custom" ? predefinedMentions.find((mention) => mention.key === currentMentionType)?.text || "" : ""; const blockSeparator = currentMentionType === "medley" ? getMedleySeparator(config.medleySeparator) : "\n\n"; return [companyText, selectedText].filter(Boolean).join(blockSeparator); }; const buildSelectedMentionsContent = (config?: any) => { const source = config || element; const selectedMentions = source.selectedMentions || []; if (selectedMentions.length === 0) { return ""; } return selectedMentions .map( (key: string) => predefinedMentions.find((m) => m.key === key)?.text, ) .filter(Boolean) .join(getMedleySeparator(source.medleySeparator)); }; // Met à jour une propriété ET régénère le texte (pour le mode infos entreprise) const handlePropertyChangeWithContentUpdate = (property: string, value: unknown) => { onChange(element.id, property, value); const generatedProperties = new Set([ "showEmail", "showPhone", "showAddress", "showSiret", "showVat", "showRcs", "showCapital", "separator", "email", "phone", "address", "siret", "tva", "rcs", "capital", ]); // Les champs d'entreprise doivent toujours régénérer le texte stocké // pour garder le bloc société + mention sélectionnée synchronisé. if (generatedProperties.has(property)) { const updatedConfig = { ...element, [property]: value }; const newText = generateMentionsContent(updatedConfig); onChange(element.id, "text", newText); } }; const predefinedMentions = allMentionOptions; // Détecter automatiquement le type de mention basé sur le texte actuel const detectMentionType = () => { const currentText = element.text || ""; const currentMentionType = element.mentionType || "custom"; // Si un type connu est déjà défini et que ce n'est pas custom, le garder if ( currentMentionType && currentMentionType !== "custom" && allMentionKeys.has(currentMentionType) ) { return currentMentionType; } // Pour le medley, vérifier s'il y a des mentions sélectionnées if (element.selectedMentions && element.selectedMentions.length > 0) { return "medley"; } // Sinon, essayer de détecter automatiquement const matchingMention = predefinedMentions.find( (mention) => mention.key !== "medley" && mention.key !== "custom" && mention.text === currentText, ); return matchingMention ? matchingMention.key : "custom"; }; const currentMentionType = detectMentionType(); const currentMentionTheme = mentionsThemes.find((theme) => theme.id === element.theme) ?? mentionsThemes[0]; const applyMentionTheme = (themeId: string) => { const theme = mentionsThemes.find((item) => item.id === themeId); if (!theme) { return; } onChange(element.id, "theme", theme.id); onChange(element.id, "backgroundColor", theme.styles.backgroundColor); onChange(element.id, "borderColor", theme.styles.borderColor); onChange(element.id, "borderWidth", theme.styles.borderWidth); onChange(element.id, "borderStyle", theme.styles.borderStyle); onChange(element.id, "textColor", theme.styles.textColor); onChange(element.id, "separatorColor", theme.styles.separatorColor); onChange(element.id, "showBackground", theme.styles.showBackground !== false); }; return ( <> {/* Système d'onglets pour Mentions */}
{/* Onglet Fonctionnalités */} {mentionsCurrentTab === "fonctionnalites" && ( <>
{/* Section Propriétés de mentions - Affichage des informations d'entreprise */}
{( [ { prop: "showEmail", label: "Email", companyKey: "email", optIn: false }, { prop: "showPhone", label: "Téléphone", companyKey: "phone", optIn: false }, { prop: "showAddress", label: "Adresse", companyKey: "address", optIn: true }, { prop: "showSiret", label: "SIRET", companyKey: "siret", optIn: false }, { prop: "showVat", label: "TVA", companyKey: "vat", optIn: false }, { prop: "showRcs", label: "RCS", companyKey: "rcs", optIn: true }, { prop: "showCapital", label: "Capital", companyKey: "capital", optIn: true }, ] as const ).map(({ prop, label, companyKey, optIn }) => { const companyVal = (pdfBuilderData.company || {})[companyKey] || ""; const hint = companyVal && companyVal !== "Non indiqué" ? companyVal.length > 32 ? companyVal.substring(0, 32) + "…" : companyVal : null; const isChecked = optIn ? (element as any)[prop] === true : (element as any)[prop] !== false; return (
); })}
{/* Aperçu en temps réel du contenu généré */} {(() => { const preview = generateMentionsContent(); return preview ? (
Aperçu {currentMentionTheme.name}
{preview}
) : (
Aucune donnée d'entreprise disponible — configurez vos informations dans les Paramètres du plugin.
); })()}
{/* Section Médley - Sélection des mentions à combiner */} {currentMentionType === "medley" && (
{predefinedMentions .filter((m) => m.key !== "medley" && m.key !== "custom") .map((mention) => { const selectedMentions = element.selectedMentions || []; const isSelected = selectedMentions.includes(mention.key); return ( ); })}
{element.selectedMentions?.length ?? 0} mention(s) sélectionnée(s) {(element.selectedMentions?.length ?? 0) > 0 && ( • Dimensions ajustables manuellement (avec clipping) )}
{(element.selectedMentions?.length ?? 0) > 0 && (
)}
)}