/** * DashboardPage.tsx * * React component replacing dashboard-page.php. * Data is injected by PHP via wp_localize_script into window.pdfibDashboardData. */ import React, { useState } from 'react'; // ─── Types ──────────────────────────────────────────────────────────────────── interface DashboardStats { templates: number; documents: number; today: number; } export interface DashboardData { stats: DashboardStats; pluginVersion: string; isPremium: boolean; date: string; urls: { reactEditor: string; templates: string; settings: string; dashboard: string; purchase: string; }; i18n: { subtitle: string; version: string; lastUpdate: string; statTemplates: string; statDocuments: string; statToday: string; createPdf: string; createPdfDesc: string; manageTemplates: string; manageTemplatesDesc: string; viewTemplates: string; settingsConfig: string; settingsDesc: string; openSettings: string; premiumFeature: string; openEditor: string; premiumMsg: string; guideTitle: string; steps: Array<{ title: string; desc: string; hint: string; url: string }>; }; } declare global { interface Window { pdfibDashboardData?: DashboardData; showUpgradeModal?: (reason: string) => void; } } // ─── Sub-components ─────────────────────────────────────────────────────────── const StatCard: React.FC<{ value: number; label: string }> = ({ value, label }) => (
{value.toLocaleString()}
{label}
); interface ActionCardProps { isPremium: boolean; locked: boolean; title: string; desc: string; buttonLabel: string; href?: string; premiumMsg?: string; primary?: boolean; onPremiumClick?: () => void; } const ActionCard: React.FC = ({ locked, title, desc, buttonLabel, href, premiumMsg, primary, onPremiumClick, }) => { const cardClass = [ 'pdfb-action-card', primary ? 'pdfb-primary' : '', locked ? 'pdfb-premium-locked' : '', ] .filter(Boolean) .join(' '); return (

{title} {locked && PRO}

{desc}

{locked ? ( ) : ( {buttonLabel} )}
); }; interface GuideStepProps { number: number; title: string; desc: string; hint: string; url: string; } const GuideStep: React.FC = ({ number, title, desc, hint, url }) => ( {number}

{title}

{desc}

{hint}
); // ─── PRO Promo Section ─────────────────────────────────────────────────────── interface PromoCapabilityCardProps { icon: string; title: string; desc: string; items: string[]; tone: 'blue' | 'amber' | 'violet'; } interface PromoMetric { value: string; label: string; } interface PromoSection { title: string; rows: CompareRow[]; } interface SectionHeadingProps { eyebrow: string; title: string; desc: string; align?: 'left' | 'center'; } const SectionHeading: React.FC = ({ eyebrow, title, desc, align = 'left' }) => (
{eyebrow}

{title}

{desc}

); const PromoCapabilityCard: React.FC = ({ icon, title, desc, items, tone }) => (

{title}

{desc}

    {items.map((item) => (
  • {item}
  • ))}
); const PROMO_HERO_METRICS: PromoMetric[] = [ { value: 'PNG / JPG', label: 'exports image' }, { value: '300 / 600 DPI', label: 'qualité d’impression' }, { value: '57 modèles', label: 'textes + mentions' }, ]; const PROMO_CAPABILITIES: Array = [ { icon: '🖼️', title: 'Export et rendu', desc: 'Des sorties plus propres pour les documents publiés, archivés ou partagés.', items: ['PNG et JPG', '300 & 600 DPI', 'Formats de page étendus'], tone: 'blue', }, { icon: '🧲', title: 'Précision et confort', desc: 'Des outils pensés pour placer et ajuster les éléments plus rapidement.', items: ['Grille, guides et aimantation', 'Sélection multiple', 'Raccourcis clavier'], tone: 'violet', }, { icon: '📚', title: 'Contenus et modèles', desc: 'Plus de modèles prêts à l’emploi pour couvrir davantage de cas métier.', items: ['36 modèles de texte', '21 modèles de mentions', 'Types de document étendus'], tone: 'amber', }, ]; interface CompareRow { feature: string; free: string; pro: string; } const COMPARE_SECTIONS: PromoSection[] = [ { title: 'Création et export', rows: [ { feature: 'Éditeur visuel drag & drop', free: '✓', pro: '✓' }, { feature: 'Génération PDF', free: 'PDF', pro: 'PDF' }, { feature: 'Éléments standards', free: 'Texte, image, ligne, rectangle', pro: 'Texte, image, ligne, rectangle' }, { feature: 'Formats d’export', free: 'PDF', pro: 'PDF, PNG, JPG' }, { feature: 'Qualité d’export max', free: '150 DPI', pro: '300 & 600 DPI' }, ], }, { title: 'Modèles et contenus', rows: [ { feature: 'Types de document', free: 'Facture, devis', pro: 'Facture, devis, bon de commande, avoir, relevé, contrat' }, { feature: 'Modèles de texte dynamique', free: '3 modèles', pro: '36 modèles' }, { feature: 'Modèles de mentions', free: '3 modèles', pro: '21 modèles' }, { feature: 'Intégration WooCommerce', free: '✓', pro: '✓' }, { feature: 'Galerie de modèles avancés', free: '—', pro: '✓' }, ], }, { title: 'Précision et productivité', rows: [ { feature: 'Formats de page', free: 'A4 portrait', pro: 'A3, Letter, Legal + paysage' }, { feature: 'Navigation grille, snap & guides', free: '—', pro: '✓' }, { feature: 'Sélection multiple & mode groupe', free: '—', pro: '✓' }, { feature: 'Raccourcis clavier', free: '—', pro: '✓' }, { feature: 'Couleurs canvas avancées', free: '—', pro: '✓' }, { feature: 'Thèmes prédéfinis de l’éditeur', free: '—', pro: '✓' }, ], }, ]; function getCompareValueKind(value: string): 'check' | 'dash' | 'text' { const normalized = value.trim(); if (normalized === '✓' || normalized.startsWith('✓')) { return 'check'; } if (normalized === '—' || normalized === '-') { return 'dash'; } return 'text'; } function renderCompareValue(value: string, variant: 'free' | 'pro') { const kind = getCompareValueKind(value); const classNames = [ 'pdfb-promo-compare__value', `pdfb-promo-compare__value--${kind}`, `pdfb-promo-compare__value--${variant}`, ].join(' '); return {kind === 'check' ? '✓' : kind === 'dash' ? '—' : value}; } const PremiumPromoSection: React.FC<{ purchaseUrl: string }> = ({ purchaseUrl }) => { const [compareOpen, setCompareOpen] = useState(true); const compareRowsTotal = COMPARE_SECTIONS.reduce((total, section) => total + section.rows.length, 0); const includedInFree = COMPARE_SECTIONS.reduce( (total, section) => total + section.rows.filter((row) => row.free !== '—').length, 0, ); return (
Découvrir PRO

Une page plus structurée pour présenter la version Pro

La présentation est désormais découpée en blocs clairs: aperçu, points forts, comparatif détaillé, formules et appel à l’action.

Voir les formules PRO
PNG / JPG 300 & 600 DPI 57 modèles
{PROMO_CAPABILITIES.map((capability) => ( ))}
setCompareOpen((event.currentTarget as HTMLDetailsElement).open)} > Réduire le comparatif Voir le comparatif
{includedInFree} fonctionnalités déjà présentes dans le gratuit sur {compareRowsTotal}
{COMPARE_SECTIONS.map((section) => ( {section.rows.map((row) => ( ))} ))}
Fonctionnalité Gratuit PRO
{section.title}
{row.feature} {renderCompareValue(row.free, 'free')} {renderCompareValue(row.pro, 'pro')}
{/* CTA final */}
“Des options supplémentaires pour vos documents WooCommerce.”
Voir les formules PRO

✓ Achat séparé  ·  ✓ Activation par clé  ·  ✓ Support du vendeur

); }; // ─── Main component ─────────────────────────────────────────────────────────── const DashboardPage: React.FC = () => { const data = window.pdfibDashboardData; if (!data) { return
❌ ERREUR: window.pdfibDashboardData est undefined — le script PHP ne charge pas les données.
; } const { stats, pluginVersion, isPremium, date, urls, i18n } = data; const handlePremiumClick = () => { window.showUpgradeModal?.('template'); }; return (
{/* Header */}

Advanced PDF Invoice Builder

{i18n.subtitle}

{i18n.version.replace('%s', pluginVersion)} {i18n.lastUpdate.replace('%s', date)}
); }; export default DashboardPage;