206 lines
6.4 KiB
JavaScript
206 lines
6.4 KiB
JavaScript
import { doctorTitle } from "@/helper";
|
|
|
|
// Icons
|
|
import CopyBlueD from "@/components/icons/CopyBlueD";
|
|
import DownloadBlue from "@/components/icons/DownloadBlue";
|
|
import WhatsappBlueD from "@/components/icons/WhatsappBlueD";
|
|
import TelegramBlueD from "@/components/icons/TelegramBlueD";
|
|
import LinkedingBlueD from "@/components/icons/LinkedingBlueD";
|
|
|
|
// Packages
|
|
import { useState } from "react";
|
|
import { toPng } from "html-to-image";
|
|
import html2canvas from "html2canvas";
|
|
import jsPDF from "jspdf";
|
|
import { Button } from "@mui/material";
|
|
import { toast } from "react-toastify";
|
|
|
|
const VAZIR_WEIGHTS = [
|
|
[400, "Vazirmatn-RD-FD-Regular.ttf"],
|
|
[500, "Vazirmatn-RD-FD-Medium.ttf"],
|
|
[600, "Vazirmatn-RD-FD-SemiBold.ttf"],
|
|
[700, "Vazirmatn-RD-FD-Bold.ttf"],
|
|
[800, "Vazirmatn-RD-FD-ExtraBold.ttf"],
|
|
];
|
|
|
|
let vazirEmbedCssPromise;
|
|
const getVazirEmbedCss = () => {
|
|
vazirEmbedCssPromise ??= Promise.all(
|
|
VAZIR_WEIGHTS.map(async ([weight, file]) => {
|
|
const res = await fetch(`/fonts/vazir/${file}`);
|
|
const blob = await res.blob();
|
|
const dataUrl = await new Promise((resolve, reject) => {
|
|
const reader = new FileReader();
|
|
reader.onload = () => resolve(reader.result);
|
|
reader.onerror = reject;
|
|
reader.readAsDataURL(blob);
|
|
});
|
|
return `@font-face{font-family:vazir;src:url(${dataUrl});font-weight:${weight};}`;
|
|
})
|
|
).then((faces) => faces.join("\n"));
|
|
return vazirEmbedCssPromise;
|
|
};
|
|
|
|
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 || downloading) return;
|
|
|
|
if (!qrReady) {
|
|
toast.info("در حال آمادهسازی پوستر، لحظهای صبر کنید...");
|
|
return;
|
|
}
|
|
|
|
setDownloading(true);
|
|
try {
|
|
await waitForImages(element);
|
|
|
|
let imgData;
|
|
let pxWidth;
|
|
let pxHeight;
|
|
|
|
try {
|
|
const fontEmbedCSS = await getVazirEmbedCss();
|
|
const options = {
|
|
pixelRatio: 2,
|
|
backgroundColor: "#ffffff",
|
|
style: { opacity: "1" },
|
|
fontEmbedCSS,
|
|
};
|
|
imgData = await toPng(element, options);
|
|
pxWidth = element.offsetWidth * 2;
|
|
pxHeight = element.offsetHeight * 2;
|
|
} catch {
|
|
const canvas = await html2canvas(element, {
|
|
backgroundColor: "#ffffff",
|
|
useCORS: true,
|
|
scale: 2,
|
|
imageTimeout: 15000,
|
|
});
|
|
imgData = canvas.toDataURL("image/png");
|
|
pxWidth = canvas.width;
|
|
pxHeight = canvas.height;
|
|
}
|
|
|
|
const imgWidth = 210;
|
|
const pxPerMm = pxWidth / imgWidth;
|
|
const imgHeight = pxHeight / pxPerMm;
|
|
|
|
const pdf = new jsPDF({
|
|
orientation: "portrait",
|
|
unit: "mm",
|
|
format: [imgWidth, imgHeight],
|
|
});
|
|
|
|
pdf.addImage(imgData, "PNG", 0, 0, imgWidth, imgHeight);
|
|
const safeName = (data?.name ?? "doctor").replace(/[\\/:*?"<>|]+/g, "-");
|
|
pdf.save(`poster-${safeName}.pdf`);
|
|
} catch {
|
|
toast.error("ساخت پوستر ناموفق بود، دوباره تلاش کنید");
|
|
} finally {
|
|
setDownloading(false);
|
|
}
|
|
};
|
|
|
|
const getShareUrl = () =>
|
|
typeof window !== "undefined" ? window.location.href : "";
|
|
|
|
const getShareText = () =>
|
|
data?.name ? `معرفی ${doctorTitle(data.name)} در نوبت 724` : "معرفی پزشک در نوبت 724";
|
|
|
|
const openShareWindow = (url) => {
|
|
if (typeof window !== "undefined") {
|
|
window.open(url, "_blank", "noopener,noreferrer");
|
|
}
|
|
};
|
|
|
|
const handleWhatsapp = () => {
|
|
const text = encodeURIComponent(`${getShareText()}\n${getShareUrl()}`);
|
|
openShareWindow(`https://wa.me/?text=${text}`);
|
|
};
|
|
|
|
const handleTelegram = () => {
|
|
const url = encodeURIComponent(getShareUrl());
|
|
const text = encodeURIComponent(getShareText());
|
|
openShareWindow(`https://t.me/share/url?url=${url}&text=${text}`);
|
|
};
|
|
|
|
const handleLinkedin = () => {
|
|
const url = encodeURIComponent(getShareUrl());
|
|
openShareWindow(
|
|
`https://www.linkedin.com/sharing/share-offsite/?url=${url}`
|
|
);
|
|
};
|
|
|
|
const handleCopyLink = async () => {
|
|
try {
|
|
await navigator.clipboard.writeText(getShareUrl());
|
|
toast.success("لینک کپی شد");
|
|
} catch {
|
|
toast.error("کپی لینک ناموفق بود");
|
|
}
|
|
};
|
|
|
|
const listIcons = [
|
|
{ name: "واتساپ", icon: <WhatsappBlueD />, onClick: handleWhatsapp },
|
|
{ name: "تلگرام", icon: <TelegramBlueD />, onClick: handleTelegram },
|
|
{ name: "لینکدین", icon: <LinkedingBlueD />, onClick: handleLinkedin },
|
|
{ name: "کپی لینک", icon: <CopyBlueD />, onClick: handleCopyLink },
|
|
{
|
|
name: "دانلود",
|
|
icon: <DownloadBlue />,
|
|
onClick: handleDownloadPDF,
|
|
disabled: downloading,
|
|
},
|
|
];
|
|
|
|
return (
|
|
<>
|
|
<ul className="flex items-center mx-[60px] sm:mx-[86px] md:mx-[112px] lg:mx-[140px] justify-center mt-[8px] md:mt-[12px] lg:mt-[16px] gap-[24px] sm:gap-[26px] md:gap-[29px] lg:gap-[32px]">
|
|
{listIcons.map((item, idx) => (
|
|
<li
|
|
key={idx}
|
|
className="flex flex-col justify-center items-center w-fit gap-[2px]"
|
|
>
|
|
<Button
|
|
className=" !p-[0px] !bg-[#EAECFA] !rounded-full !min-w-0 grid place-items-center !w-[24px] sm:!w-[28px] md:!w-[32px] lg:!w-[36px] !h-[24px] sm:!h-[28px] md:!h-[32px] lg:!h-[36px] "
|
|
onClick={item.onClick}
|
|
aria-label={item.name}
|
|
variant="text"
|
|
disabled={item.disabled}
|
|
>
|
|
<div
|
|
className="grid place-items-center w-full-icon !w-[16px] md:!w-[17px] lg:!w-[18px] !h-[16px] md:!h-[17px] lg:!h-[18px]"
|
|
>
|
|
{item.icon}
|
|
</div>
|
|
</Button>
|
|
<span className="text-[#525252] text-[10px] md:text-[11px] lg:text-[12px]">
|
|
{item.name}
|
|
</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default List;
|