feat: enhance poster download functionality by ensuring images load before PDF generation and adding QR readiness check

This commit is contained in:
hamed
2026-07-04 21:50:57 +03:30
parent 3344a2f77a
commit 199c843b08
6 changed files with 255 additions and 38 deletions
+58 -20
View File
@@ -6,37 +6,69 @@ import TelegramBlueD from "@/components/icons/TelegramBlueD";
import LinkedingBlueD from "@/components/icons/LinkedingBlueD";
// Packages
import { useState } from "react";
import html2canvas from "html2canvas";
import jsPDF from "jspdf";
import { Button } from "@mui/material";
import { toast } from "react-toastify";
function List({ hiddenRef, data }) {
const waitForImages = async (element) => {
const imgs = Array.from(element.querySelectorAll("img"));
await Promise.all(
imgs.map((img) => {
if (img.complete && img.naturalWidth !== 0) {
return img.decode?.().catch(() => {}) ?? Promise.resolve();
}
return new Promise((resolve) => {
img.onload = () => resolve();
img.onerror = () => resolve();
});
})
);
};
function List({ hiddenRef, data, qrReady }) {
const [downloading, setDownloading] = useState(false);
const handleDownloadPDF = async () => {
const element = hiddenRef.current;
if (!element) return;
if (!element || downloading) return;
const canvas = await html2canvas(element, {
backgroundColor: "#ffffff",
useCORS: true,
scale: 2,
});
if (!qrReady) {
toast.info("در حال آماده‌سازی پوستر، لحظه‌ای صبر کنید...");
return;
}
const imgData = canvas.toDataURL("image/png");
setDownloading(true);
try {
await waitForImages(element);
const imgWidth = 210;
const imgProps = canvas;
const pxPerMm = imgProps.width / imgWidth;
const imgHeight = canvas.height / pxPerMm;
const canvas = await html2canvas(element, {
backgroundColor: "#ffffff",
useCORS: true,
scale: 2,
imageTimeout: 15000,
});
const pdf = new jsPDF({
orientation: "portrait",
unit: "mm",
format: [imgWidth, imgHeight],
});
const imgData = canvas.toDataURL("image/png");
pdf.addImage(imgData, "PNG", 0, 0, imgWidth, imgHeight);
pdf.save("poster.pdf");
const imgWidth = 210;
const pxPerMm = canvas.width / imgWidth;
const imgHeight = canvas.height / pxPerMm;
const pdf = new jsPDF({
orientation: "portrait",
unit: "mm",
format: [imgWidth, imgHeight],
});
pdf.addImage(imgData, "PNG", 0, 0, imgWidth, imgHeight);
pdf.save("poster.pdf");
} catch {
toast.error("ساخت پوستر ناموفق بود، دوباره تلاش کنید");
} finally {
setDownloading(false);
}
};
const getShareUrl = () =>
@@ -83,7 +115,12 @@ function List({ hiddenRef, data }) {
{ name: "تلگرام", icon: <TelegramBlueD />, onClick: handleTelegram },
{ name: "لینکدین", icon: <LinkedingBlueD />, onClick: handleLinkedin },
{ name: "کپی لینک", icon: <CopyBlueD />, onClick: handleCopyLink },
{ name: "دانلود", icon: <DownloadBlue />, onClick: handleDownloadPDF },
{
name: "دانلود",
icon: <DownloadBlue />,
onClick: handleDownloadPDF,
disabled: downloading,
},
];
return (
@@ -103,6 +140,7 @@ function List({ hiddenRef, data }) {
onClick={item.onClick}
aria-label={item.name}
variant="text"
disabled={item.disabled}
>
<div
className="grid place-items-center w-full-icon