284 lines
9.5 KiB
TypeScript
284 lines
9.5 KiB
TypeScript
'use client'
|
|
|
|
import { useRef, useState, useEffect } from 'react'
|
|
import { useRouter } from 'next/navigation'
|
|
import { createClient } from '@/lib/supabase/client'
|
|
import SignatureEditor from '@/components/SignatureEditor'
|
|
import SignaturePreview from '@/components/SignaturePreview'
|
|
import StyleSelector from '@/components/StyleSelector'
|
|
import BannerGenerator from '@/components/BannerGenerator'
|
|
import { useSignatures, SavedSignature } from '@/hooks/useSignatures'
|
|
import { colorThemes, SignatureStyle } from '@/lib/types'
|
|
import { generateSignatureHTML, exportAsImage, copyHTMLToClipboard, downloadHTML } from '@/lib/export'
|
|
import '@/styles/dashboard.scss'
|
|
|
|
export default function DashboardPage() {
|
|
const router = useRouter()
|
|
const [user, setUser] = useState<{ email: string } | null>(null)
|
|
const [copySuccess, setCopySuccess] = useState(false)
|
|
const [exportLoading, setExportLoading] = useState(false)
|
|
const [activeTab, setActiveTab] = useState<'editor' | 'style' | 'banner'>('editor')
|
|
const signatureRef = useRef<HTMLDivElement>(null)
|
|
|
|
const {
|
|
signatures,
|
|
currentSignature,
|
|
currentId,
|
|
loading,
|
|
saving,
|
|
updateSignature,
|
|
createNewSignature,
|
|
selectSignature,
|
|
deleteSignature,
|
|
} = useSignatures()
|
|
|
|
useEffect(() => {
|
|
const supabase = createClient()
|
|
supabase.auth.getUser().then(({ data }) => {
|
|
if (data.user) {
|
|
setUser({ email: data.user.email || '' })
|
|
} else {
|
|
router.push('/login')
|
|
}
|
|
})
|
|
}, [router])
|
|
|
|
const handleLogout = async () => {
|
|
const supabase = createClient()
|
|
await supabase.auth.signOut()
|
|
router.push('/login')
|
|
router.refresh()
|
|
}
|
|
|
|
const handleNewSignature = async () => {
|
|
await createNewSignature()
|
|
setActiveTab('editor')
|
|
}
|
|
|
|
const handleStyleChange = (style: SignatureStyle) => {
|
|
updateSignature({ ...currentSignature, styleTemplate: style })
|
|
}
|
|
|
|
const handleThemeChange = (themeIndex: number) => {
|
|
const theme = colorThemes[themeIndex]
|
|
updateSignature({
|
|
...currentSignature,
|
|
primaryColor: theme.primary,
|
|
secondaryColor: theme.secondary,
|
|
accentColor: theme.accent,
|
|
})
|
|
}
|
|
|
|
const handleBannerChange = (url: string) => {
|
|
updateSignature({ ...currentSignature, bannerUrl: url })
|
|
}
|
|
|
|
const handleBannerLinkChange = (link: string) => {
|
|
updateSignature({ ...currentSignature, bannerLink: link })
|
|
}
|
|
|
|
const handleCopyHTML = async () => {
|
|
const html = generateSignatureHTML(currentSignature)
|
|
try {
|
|
await copyHTMLToClipboard(html)
|
|
setCopySuccess(true)
|
|
setTimeout(() => setCopySuccess(false), 2000)
|
|
} catch (error) {
|
|
console.error('Error copying HTML:', error)
|
|
}
|
|
}
|
|
|
|
const handleDownloadHTML = () => {
|
|
const html = generateSignatureHTML(currentSignature)
|
|
const filename = `signature-${currentSignature.firstName || 'email'}-${currentSignature.lastName || ''}.html`
|
|
downloadHTML(html, filename)
|
|
}
|
|
|
|
const handleExportImage = async () => {
|
|
if (!signatureRef.current) return
|
|
setExportLoading(true)
|
|
try {
|
|
await exportAsImage(signatureRef.current)
|
|
} catch (error) {
|
|
console.error('Error exporting image:', error)
|
|
} finally {
|
|
setExportLoading(false)
|
|
}
|
|
}
|
|
|
|
const handleDeleteSignature = async (sig: SavedSignature, e: React.MouseEvent) => {
|
|
e.stopPropagation()
|
|
if (confirm(`Supprimer la signature de ${sig.firstName} ${sig.lastName} ?`)) {
|
|
await deleteSignature(sig.id)
|
|
}
|
|
}
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="dashboard">
|
|
<div className="loading-screen">
|
|
<div className="loading-screen__spinner" />
|
|
<p>Chargement...</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="dashboard">
|
|
{/* Header */}
|
|
<header className="header">
|
|
<div className="header__inner">
|
|
<div className="header__brand">Navier Signatures</div>
|
|
<div className="header__actions">
|
|
{saving && <span className="auto-save">Sauvegarde...</span>}
|
|
{user && <span className="header__email">{user.email}</span>}
|
|
<button className="btn btn--ghost" onClick={handleLogout}>
|
|
Déconnexion
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<div className="app-layout">
|
|
{/* Sidebar */}
|
|
<aside className="sidebar">
|
|
<div className="sidebar__top">
|
|
<h2>Signatures</h2>
|
|
<button className="btn btn--primary btn--icon" onClick={handleNewSignature} title="Nouvelle signature">
|
|
+
|
|
</button>
|
|
</div>
|
|
|
|
<div className="signature-list">
|
|
{signatures.length === 0 ? (
|
|
<div className="signature-list__empty">
|
|
<p>Aucune signature</p>
|
|
<button className="btn btn--primary" onClick={handleNewSignature}>
|
|
Créer une signature
|
|
</button>
|
|
</div>
|
|
) : (
|
|
signatures.map((sig) => (
|
|
<div
|
|
key={sig.id}
|
|
className={`signature-card ${currentId === sig.id ? 'signature-card--active' : ''}`}
|
|
onClick={() => selectSignature(sig)}
|
|
>
|
|
<div className="signature-card__avatar">
|
|
{sig.firstName.charAt(0)}{sig.lastName.charAt(0)}
|
|
</div>
|
|
<div className="signature-card__info">
|
|
<span className="signature-card__name">{sig.firstName} {sig.lastName}</span>
|
|
<span className="signature-card__role">{sig.jobTitle || 'Sans titre'}</span>
|
|
</div>
|
|
<button
|
|
className="signature-card__delete"
|
|
onClick={(e) => handleDeleteSignature(sig, e)}
|
|
title="Supprimer"
|
|
>
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
|
<path d="M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
))
|
|
)}
|
|
</div>
|
|
</aside>
|
|
|
|
{/* Main content */}
|
|
<main className="main-content">
|
|
{/* Tabs */}
|
|
<nav className="tabs">
|
|
<button
|
|
className={`tabs__item ${activeTab === 'editor' ? 'tabs__item--active' : ''}`}
|
|
onClick={() => setActiveTab('editor')}
|
|
>
|
|
Informations
|
|
</button>
|
|
<button
|
|
className={`tabs__item ${activeTab === 'style' ? 'tabs__item--active' : ''}`}
|
|
onClick={() => setActiveTab('style')}
|
|
>
|
|
Style
|
|
</button>
|
|
<button
|
|
className={`tabs__item ${activeTab === 'banner' ? 'tabs__item--active' : ''}`}
|
|
onClick={() => setActiveTab('banner')}
|
|
>
|
|
Bannière
|
|
</button>
|
|
</nav>
|
|
|
|
<div className="content-grid">
|
|
{/* Editor Panel */}
|
|
<section className="panel">
|
|
{activeTab === 'editor' && (
|
|
<SignatureEditor data={currentSignature} onChange={updateSignature} />
|
|
)}
|
|
|
|
{activeTab === 'style' && (
|
|
<StyleSelector
|
|
currentStyle={currentSignature.styleTemplate}
|
|
currentThemeIndex={colorThemes.findIndex(t => t.primary === currentSignature.primaryColor)}
|
|
onStyleChange={handleStyleChange}
|
|
onThemeChange={handleThemeChange}
|
|
photoShape={currentSignature.photoShape}
|
|
onPhotoShapeChange={(shape) => updateSignature({ ...currentSignature, photoShape: shape })}
|
|
/>
|
|
)}
|
|
|
|
{activeTab === 'banner' && (
|
|
<BannerGenerator
|
|
bannerUrl={currentSignature.bannerUrl || ''}
|
|
bannerLink={currentSignature.bannerLink || ''}
|
|
onBannerChange={handleBannerChange}
|
|
onLinkChange={handleBannerLinkChange}
|
|
/>
|
|
)}
|
|
</section>
|
|
|
|
{/* Preview Panel */}
|
|
<section className="panel panel--preview">
|
|
<h3 className="panel__title">Aperçu</h3>
|
|
|
|
<div className="preview-box">
|
|
<SignaturePreview
|
|
ref={signatureRef}
|
|
data={currentSignature}
|
|
bannerUrl={currentSignature.bannerUrl}
|
|
bannerLink={currentSignature.bannerLink}
|
|
/>
|
|
</div>
|
|
|
|
<div className="export-actions">
|
|
<button
|
|
className={`btn ${copySuccess ? 'btn--success' : 'btn--primary'}`}
|
|
onClick={handleCopyHTML}
|
|
>
|
|
{copySuccess ? 'Copié !' : 'Copier HTML'}
|
|
</button>
|
|
<button className="btn btn--secondary" onClick={handleDownloadHTML}>
|
|
Télécharger
|
|
</button>
|
|
<button
|
|
className="btn btn--secondary"
|
|
onClick={handleExportImage}
|
|
disabled={exportLoading}
|
|
>
|
|
{exportLoading ? '...' : 'PNG'}
|
|
</button>
|
|
</div>
|
|
|
|
<p className="preview-hint">
|
|
Collez le HTML dans les paramètres de signature de votre client email.
|
|
</p>
|
|
</section>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|