Files
nobat724_front/components/doctor/poster/index.js
T

277 lines
10 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useEffect, useState } from "react";
import DoctorAvatar from "@/app/component/DoctorAvatar";
import QrImg from "./QrImg";
import { getStateInfoClient } from "@/lib/getStateInfoClient";
import StarDI from "@/components/icons/StarDI";
import ClipBoard from "@/components/icons/ClipBoard";
import AddressPoster from "@/components/icons/AddressPoster";
import TelefonPoster from "@/components/icons/TelefonPoster";
import Instagram from "@/components/icons/Instagram";
import Telegram from "@/components/icons/Telegram";
import Whatsapp from "@/components/icons/Whatsapp";
const POSTER_BG =
"linear-gradient(160deg, #0B2A4A 0%, #16528C 52%, #2E77C4 100%)";
function SiteLogo({ city, className }) {
if (city?.logo_url) {
return (
<img
src={city.logo_url}
alt="logo"
crossOrigin="anonymous"
className={`object-contain ${className}`}
/>
);
}
return (
<svg
viewBox="0 0 100 100"
className={className}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M50 12 A38 38 0 1 0 88 50 A19 19 0 0 0 55.6 36.6"
fill="none"
stroke="#5559CE"
strokeWidth="7.5"
strokeLinecap="round"
/>
<rect x="46.5" y="40" width="7" height="20" rx="3.5" fill="#FF8848" />
<rect x="40" y="46.5" width="20" height="7" rx="3.5" fill="#FF8848" />
</svg>
);
}
function SectionTitle({ icon, children }) {
return (
<div className="mb-[20px] text-right">
<span className="inline-grid place-items-center align-middle w-[40px] h-[40px] rounded-[12px] bg-white/12 ml-[12px]">
{icon}
</span>
<span className="align-middle text-white text-[26px] font-bold leading-none">
{children}
</span>
</div>
);
}
function Poster({ data, onQrReady }) {
const [city, setCity] = useState(null);
useEffect(() => {
const { matchedCity } = getStateInfoClient();
setCity(matchedCity || null);
}, []);
const specialties = (data?.specialties ?? []).filter((s) => s?.name).slice(0, 4);
const services = (data?.expertise ?? []).filter((s) => s?.name);
const shownServices = services.slice(0, 8);
const moreServices = services.length - shownServices.length;
const address = data?.address?.[0]?.address;
const phones = (data?.address ?? [])
.map((a) => a?.phone)
.filter(Boolean)
.slice(0, 2);
const social = city?.social_media ?? {};
const socialItems = [
social.instagram && <Instagram key="ig" />,
social.telegram && <Telegram key="tg" />,
social.whatsapp && <Whatsapp key="wa" />,
].filter(Boolean);
const badges = [
Number(data?.experience) > 0 && {
icon: <span className="align-middle text-[#F6B93B] text-[20px] ml-[8px]"></span>,
label: `${data.experience} سال تجربه`,
},
(data?.point ?? 0) > 0 && {
icon: <span className="align-middle inline-block ml-[8px]"><StarDI /></span>,
label: `امتیاز ${data.point}`,
},
(data?.satisfaction ?? 0) > 0 && {
icon: <span className="align-middle text-[#4ADE80] text-[20px] ml-[8px]"></span>,
label: `${data.satisfaction}% رضایت`,
},
].filter(Boolean);
return (
<div
dir="rtl"
className="relative w-[1080px] h-[1350px] overflow-hidden flex flex-col p-[64px] text-right"
style={{ background: POSTER_BG, direction: "rtl" }}
>
<div className="pointer-events-none absolute -top-[180px] -left-[180px] w-[520px] h-[520px] rounded-full bg-[#57A6FF]/20 blur-[80px]" />
<div className="pointer-events-none absolute bottom-[120px] -right-[160px] w-[460px] h-[460px] rounded-full bg-[#0B2A4A]/40 blur-[80px]" />
{/* header — float layout so RTL survives html2canvas */}
<header className="relative overflow-hidden">
<div className="float-right">
<SiteLogo city={city} className="inline-block align-middle h-[64px] w-[64px] ml-[16px]" />
<div className="inline-block align-middle">
<div className="text-white text-[30px] font-extrabold leading-[36px]">
{city?.site_name || "نوبت ۷۲۴"}
</div>
<div className="text-[#9FC1E6] text-[18px] font-medium leading-[22px]" dir="ltr">
{city?.domain || "nobat724.com"}
</div>
</div>
</div>
<div className="float-left rounded-full bg-[#F59E0B] text-[#1A1200] text-[22px] font-bold px-[24px] h-[56px] leading-[56px] text-center">
نوبتدهی آنلاین
</div>
</header>
{city?.slogan && (
<p className="relative mt-[24px] text-[#C7DBF2] text-[22px] font-medium leading-[1.6]">
{city.slogan}
</p>
)}
{/* hero */}
<section className="relative mt-[40px] rounded-[32px] bg-white/8 border border-white/12 p-[40px] overflow-hidden">
<div className="float-right rounded-full p-[8px] ml-[36px] bg-gradient-to-br from-[#5AA6FF] to-[#F59E0B]">
<div className="rounded-full p-[6px] bg-[#0B2A4A]">
<DoctorAvatar
doctor={data}
size={220}
priority
className="rounded-full !object-cover w-[220px] h-[220px]"
/>
</div>
</div>
<div className="overflow-hidden">
<h1 className="text-white text-[46px] font-extrabold leading-[1.3]">
{data?.name}
</h1>
<div className="mt-[14px]">
{specialties.map((s, i) => (
<span
key={i}
className="inline-block rounded-full bg-[#F59E0B]/18 border border-[#F59E0B]/40 text-[#FCD9A0] text-[22px] font-semibold px-[18px] h-[46px] leading-[46px] ml-[10px] mb-[10px]"
>
{s.name}
</span>
))}
</div>
<div className="mt-[6px]">
{badges.map((b, i) => (
<span
key={i}
className="inline-block rounded-full bg-white/10 border border-white/15 px-[18px] h-[52px] leading-[52px] ml-[12px] mb-[12px]"
>
{b.icon}
<span className="align-middle text-[#EAF2FB] text-[22px] font-semibold">
{b.label}
</span>
</span>
))}
</div>
{data?.medical_system_code && (
<p className="mt-[8px] text-[#9FC1E6] text-[20px] leading-[1.5]">
کد نظام پزشکی:{" "}
<span dir="ltr" className="font-semibold text-[#E7EEF6]">
{data.medical_system_code}
</span>
</p>
)}
</div>
</section>
{/* body */}
<section className="relative mt-[36px] flex-1">
{shownServices.length > 0 && (
<div className="rounded-[28px] bg-white/6 border border-white/10 p-[32px] mb-[28px]">
<SectionTitle icon={<ClipBoard />}>خدمات</SectionTitle>
<div className="text-right">
{shownServices.map((s, i) => (
<span
key={i}
className="inline-block rounded-full bg-white/8 border border-white/10 px-[18px] h-[48px] leading-[48px] ml-[12px] mb-[14px]"
>
<span className="align-middle inline-block w-[10px] h-[10px] rounded-full bg-[#F59E0B] ml-[10px]" />
<span className="align-middle text-[#E7EEF6] text-[22px] font-normal">
{s.name}
</span>
</span>
))}
{moreServices > 0 && (
<span className="inline-block align-middle text-[#9FC1E6] text-[22px] h-[48px] leading-[48px]">
+ {moreServices} خدمت دیگر
</span>
)}
</div>
</div>
)}
{(address || phones.length > 0) && (
<div className="rounded-[28px] bg-white/6 border border-white/10 p-[32px]">
{address && (
<div className="mb-[24px]">
<SectionTitle icon={<AddressPoster />}>آدرس</SectionTitle>
<p className="text-[#E7EEF6] text-[23px] font-normal leading-[1.7] line-clamp-2 text-right">
{address}
</p>
</div>
)}
{phones.length > 0 && (
<div>
<SectionTitle icon={<TelefonPoster />}>تلفن</SectionTitle>
<div className="text-right">
{phones.map((p, i) => (
<span
key={i}
dir="ltr"
className="inline-block rounded-[14px] bg-white/10 text-[#E7EEF6] text-[24px] font-semibold px-[20px] h-[56px] leading-[56px] ml-[16px]"
>
{p}
</span>
))}
</div>
</div>
)}
</div>
)}
</section>
{/* footer */}
<footer className="relative mt-[36px] rounded-[28px] bg-white/8 border border-white/12 p-[32px] overflow-hidden">
<div className="float-right">
<div className="inline-block align-middle rounded-[20px] bg-white p-[16px] ml-[24px]">
<QrImg onReady={onQrReady} size={168} />
</div>
<div className="inline-block align-middle">
<div className="text-white text-[28px] font-bold leading-[34px]">
برای رزرو نوبت اسکن کنید
</div>
<div className="text-[#9FC1E6] text-[22px] leading-[28px] mt-[6px]" dir="ltr">
{city?.domain || "nobat724.com"}
</div>
</div>
</div>
<div className="float-left text-left">
<SiteLogo city={city} className="inline-block h-[48px] w-[48px]" />
{socialItems.length > 0 && (
<div className="mt-[14px]">
{socialItems.map((icon, i) => (
<span
key={i}
className="inline-grid place-items-center align-middle w-[44px] h-[44px] rounded-full bg-white ml-[10px]"
>
{icon}
</span>
))}
</div>
)}
</div>
</footer>
</div>
);
}
export default Poster;