81 lines
2.7 KiB
TypeScript
81 lines
2.7 KiB
TypeScript
import { useState, type RefObject } from 'react'
|
|
import html2canvas from 'html2canvas'
|
|
import { jsPDF } from 'jspdf'
|
|
|
|
type Props = {
|
|
targetRef: RefObject<HTMLElement | null>
|
|
}
|
|
|
|
export function ExportDashboardButton({ targetRef }: Props) {
|
|
const [busy, setBusy] = useState<'png' | 'pdf' | null>(null)
|
|
|
|
const runExport = async (mode: 'png' | 'pdf') => {
|
|
const el = targetRef.current
|
|
if (!el) return
|
|
setBusy(mode)
|
|
try {
|
|
const canvas = await html2canvas(el, {
|
|
scale: 2,
|
|
useCORS: true,
|
|
logging: false,
|
|
backgroundColor: '#020617',
|
|
})
|
|
const stamp = new Date().toISOString().slice(0, 19).replace(/[:T]/g, '-')
|
|
if (mode === 'png') {
|
|
canvas.toBlob((blob) => {
|
|
if (!blob) return
|
|
const url = URL.createObjectURL(blob)
|
|
const a = document.createElement('a')
|
|
a.href = url
|
|
a.download = `dashboard-copil-${stamp}.png`
|
|
a.click()
|
|
URL.revokeObjectURL(url)
|
|
}, 'image/png')
|
|
} else {
|
|
const imgData = canvas.toDataURL('image/png')
|
|
const pdf = new jsPDF({ orientation: 'landscape', unit: 'pt', format: 'a4' })
|
|
const pageW = pdf.internal.pageSize.getWidth()
|
|
const pageH = pdf.internal.pageSize.getHeight()
|
|
const img = new Image()
|
|
await new Promise<void>((resolve, reject) => {
|
|
img.onload = () => resolve()
|
|
img.onerror = () => reject(new Error('image'))
|
|
img.src = imgData
|
|
})
|
|
const ratio = Math.min(pageW / img.width, pageH / img.height)
|
|
const w = img.width * ratio
|
|
const h = img.height * ratio
|
|
const x = (pageW - w) / 2
|
|
const y = (pageH - h) / 2
|
|
pdf.addImage(imgData, 'PNG', x, y, w, h)
|
|
pdf.save(`dashboard-copil-${stamp}.pdf`)
|
|
}
|
|
} catch {
|
|
alert('Export impossible (vérifiez les bloqueurs ou réessayez).')
|
|
} finally {
|
|
setBusy(null)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="flex flex-wrap gap-2">
|
|
<button
|
|
type="button"
|
|
disabled={busy !== null}
|
|
onClick={() => void runExport('png')}
|
|
className="rounded-lg border border-violet-500/50 bg-violet-500/15 px-3 py-2 text-xs font-semibold text-violet-100 transition hover:bg-violet-500/25 disabled:opacity-50"
|
|
>
|
|
{busy === 'png' ? 'Export…' : 'Exporter PNG (Copil)'}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
disabled={busy !== null}
|
|
onClick={() => void runExport('pdf')}
|
|
className="rounded-lg border border-sky-500/50 bg-sky-500/15 px-3 py-2 text-xs font-semibold text-sky-100 transition hover:bg-sky-500/25 disabled:opacity-50"
|
|
>
|
|
{busy === 'pdf' ? 'Export…' : 'Exporter PDF (Copil)'}
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|