Files
jira/src/components/ExportDashboardButton.tsx
Bastien COIGNOUX ca4c64bbb0 init
2026-04-24 11:50:39 +02:00

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>
)
}