# رفع مشکل عکس نادرست در پوستر دانلودی صفحه پزشک (اشتراک‌گذاری)

## پروژه

`nobat724_front`

## زمینه

در صفحه‌ی عمومی پزشک (`/doctor/[slug]`) یک دکمه‌ی «اشتراک گذاری» هست که یک Modal باز می‌کند. داخل Modal گزینه‌ی «دانلود» یک پوستر PDF می‌سازد. پوستر شامل عکس پروفایل پزشک، QR کد، لوگو و اطلاعات پزشک است.

مسیر تست:
`http://localhost:3000/doctor/f58d3dba-6ce0-4bd4-85d9-9d787a0b9324` → «اشتراک گذاری» → «دانلود»

## مشکل / هدف

وقتی روی «دانلود» کلیک می‌شود، پوستر PDF دانلود می‌شود ولی **عکس آن درست نیست** — عکس پروفایل پزشک و/یا QR کد در فایل خروجی خالی/خراب/ناقص است.

**علت ریشه‌ای:** `handleDownloadPDF` بلافاصله `html2canvas` را صدا می‌زند بدون اینکه منتظر بارگذاری کامل تصاویر بماند:

1. عکس پروفایل با `next/image` (`<Image>`) رندر می‌شود که از دامنه‌ی remote (`api.clinic-pro.ir`) از طریق optimizer آدرس `/_next/image?url=...` می‌آید و lazy load دارد؛ ممکن است هنگام capture هنوز paint نشده باشد.
2. QR کد به‌صورت async در `useEffect` تولید می‌شود (`QRCode.toDataURL(...).then(setQrCodeData)`)؛ اگر کاربر سریع دانلود بزند، به‌جای QR متن «در حال بارگذاری...» در پوستر می‌افتد.
3. هیچ await برای اتمام لود شدن `<img>`ها قبل از snapshot وجود ندارد.

## فایل‌های مرتبط

| فایل | نقش |
|------|-----|
| `components/doctor/detailDoctor/Share.js` | Modal اشتراک‌گذاری؛ Poster را در یک div مخفی (`hiddenRef`) رندر می‌کند |
| `components/doctor/detailDoctor/List.js` | آیکون‌های اشتراک + `handleDownloadPDF` (منطق html2canvas + jsPDF) — **هسته‌ی باگ** |
| `components/doctor/poster/index.js` | چیدمان پوستر |
| `components/doctor/poster/ImageProfile.js` | عکس پروفایل با `next/image` |
| `components/doctor/poster/QrImg.js` | تولید async QR کد |
| `helper/index.js` | `imageUrl(url, fallback)` |

## وضعیت فعلی

### `components/doctor/detailDoctor/List.js` (بخش دانلود)

```jsx
const handleDownloadPDF = async () => {
  const element = hiddenRef.current;
  if (!element) return;

  const canvas = await html2canvas(element, {
    backgroundColor: "#ffffff",
    useCORS: true,
    scale: 2,
  });

  const imgData = canvas.toDataURL("image/png");
  // ... jsPDF ...
  pdf.save("poster.pdf");
};
```

### `components/doctor/poster/ImageProfile.js`

```jsx
import Image from "next/image";
import { imageUrl } from "@/helper";

function ImageProfile({ data }) {
  return (
    <div className="bg-stroke-circle ml-[10px] mt-[57px] p-[9px] rounded-full overflow-hidden">
      <Image
        src={imageUrl(data?.img?.[0]?.url)}
        width={173}
        height={173}
        alt="profile-user"
        className="rounded-full"
      />
    </div>
  );
}
```

### `components/doctor/poster/QrImg.js` (خلاصه)

```jsx
useEffect(() => {
  const info = getStateInfoClient();
  setHost(info.host);
  if (info.fullUrl) QRCode.toDataURL(info.fullUrl).then(setQrCodeData);
}, []);
// ...
{qrCodeData ? <img src={qrCodeData} .../> : <p>در حال بارگذاری...</p>}
```

## وظایف

### ۱. منتظر بارگذاری کامل همه‌ی `<img>`ها بمان قبل از `html2canvas`

در `List.js` یک helper اضافه کن که همه‌ی `<img>`های داخل `element` را پیدا کند و تا `complete` شدن (و در صورت امکان `decode()`) منتظر بماند. سپس در `handleDownloadPDF` قبل از `html2canvas` آن را await کن.

```jsx
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(); // خراب بودن یک عکس نباید کل دانلود را بلاک کند
      });
    })
  );
};
```

در `handleDownloadPDF`:

```jsx
const element = hiddenRef.current;
if (!element) return;

await waitForImages(element);

const canvas = await html2canvas(element, {
  backgroundColor: "#ffffff",
  useCORS: true,
  scale: 2,
  imageTimeout: 15000,
});
```

### ۲. اطمینان از آماده بودن QR قبل از دانلود

اگر QR هنوز تولید نشده باشد، پوستر متن «در حال بارگذاری...» را نشان می‌دهد. راه‌حل ساده و مطمئن: دکمه‌ی دانلود تا آماده شدن QR غیرفعال/در حالت لودینگ باشد.

- در `QrImg.js` یک callback مثل `onReady` بپذیر و بعد از `setQrCodeData` صدا بزن؛ این وضعیت را تا `Share.js` بالا ببر و به `List.js` بده، یا
- ساده‌تر: در `handleDownloadPDF` بعد از `waitForImages`، اگر داخل `element` عنصری با متن «در حال بارگذاری...» بود، چند صد میلی‌ثانیه polling کوتاه انجام بده تا `img` مربوط به QR ظاهر شود (سقف زمانی بگذار).

رویکرد اول (state واقعی) تمیزتر است؛ آن را ترجیح بده.

### ۳. سازگاری عکس پروفایل با html2canvas

عکس پروفایل با `next/image` از طریق `/_next/image` (same-origin) سرو می‌شود، پس مشکل CORS نباید داشته باشد و **نیازی به تبدیل به `<img>` خام نیست**. اگر بعد از وظیفه‌ی ۱ باز هم عکس پروفایل در خروجی خالی بود:

- fallback `imageUrl` مقدار `/assets/images/user.png` (local) را برمی‌گرداند که همیشه قابل رندر است — این را نگه‌دار.
- در صورت نیاز `priority` یا `unoptimized` به `<Image>` اضافه کن تا lazy load حذف شود و از همان ابتدا لود شود:

```jsx
<Image
  src={imageUrl(data?.img?.[0]?.url)}
  width={173}
  height={173}
  alt="profile-user"
  className="rounded-full"
  priority
  unoptimized
/>
```

> `unoptimized` باعث می‌شود آدرس مستقیم عکس (بدون `/_next/image`) رندر شود؛ اگر دامنه‌ی remote هدر CORS نفرستد ممکن است canvas آلوده شود. اگر این حالت را انتخاب کردی حتماً خروجی را تست کن؛ در غیر این صورت فقط `priority` کافی است.

### ۴. UX دکمه‌ی دانلود

- هنگام تولید پوستر، دکمه‌ی «دانلود» را در حالت loading/disabled بگذار تا کلیک دوباره منجر به دانلودهای موازی نشود.
- در صورت throw شدن `html2canvas`، با `toast.error(...)` (فارسی) خطا بده و state را ریست کن. `react-toastify` از قبل import شده.

## نکات مهم

- Poster در `Share.js` داخل یک div با `opacity-0 pointer-events-none -z-10` ولی با ابعاد ثابت `600x700` و در `top-0 left-0` رندر می‌شود (یعنی داخل viewport است و لود می‌شود). این ساختار را نگه‌دار — html2canvas به عنصر رندرشده‌ی واقعی نیاز دارد؛ `display:none` نکن.
- نسخه‌ها: `html2canvas@^1.4.1`، `jspdf@^3.0.4`. Tailwind نسخه‌ی ۳ است (رنگ‌ها rgb هستند، مشکل oklch نداریم).
- کلاس‌های `bg-poster` و `bg-stroke-circle` در `globals.css` از تصاویر local (`public/assets/images/...`) به‌عنوان `background-image` استفاده می‌کنند؛ html2canvas background-image را رندر می‌کند و چون local هستند مشکلی ندارند.
- همه‌ی رشته‌های جدید فارسی باشند.
- بعد از تغییر، سناریو را واقعی تست کن: باز کردن Modal، کلیک روی دانلود، و باز کردن PDF خروجی برای تأیید حضور عکس پروفایل + QR + لوگو.
