feat: enhance doctor and clinic components with doctorTitle helper and improve rendering logic
This commit is contained in:
@@ -7,6 +7,10 @@ import { imageUrl } from "@/helper";
|
||||
function Images({ data }) {
|
||||
const images_clinic = data?.images_clinic || [];
|
||||
|
||||
// کلینیک بدون عکس، بلوک تصویر ندارد — تصویر پیشفرض بهجای «عکسی ثبت نشده»
|
||||
// خوانده میشود و کاربر آن را عکس واقعی کلینیک فرض میکند.
|
||||
if (images_clinic.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className=" flex flex-col md:flex-row items-center mb-[8px] justify-center w-full gap-[12px] md:gap-[18px] lg:gap-[24px] overflow-hidden "
|
||||
|
||||
@@ -1,14 +1,32 @@
|
||||
import ContentDetail from "./ContentDetail";
|
||||
|
||||
function Detail({ data }) {
|
||||
// API برای فیلدهای پرنشده null میفرستد؛ درج مستقیم در template رشتهٔ «null»
|
||||
// را روی صفحه مینشاند. هر ردیف فقط وقتی مقدار واقعی دارد رندر میشود.
|
||||
const workingDays = data?.["24_7"]
|
||||
? "۲۴ ساعته، تمام روزهای هفته"
|
||||
: data?.field_working_days?.trim();
|
||||
const phone = (data?.phone_number || data?.phone || "").trim();
|
||||
const address = data?.location?.trim();
|
||||
|
||||
if (!workingDays && !phone && !address) return null;
|
||||
|
||||
return (
|
||||
<ul className="flex flex-col items-start justify-start gap-[16px]">
|
||||
<ContentDetail
|
||||
head="روزهای کاری: "
|
||||
detail={` ${data.field_working_days}`}
|
||||
/>
|
||||
<ContentDetail head="تلفن: " detail={`${data.phone_number}`} />
|
||||
<ContentDetail head="آدرس: " detail={data.location} />
|
||||
{workingDays && (
|
||||
<ContentDetail head="روزهای کاری: " detail={workingDays} />
|
||||
)}
|
||||
{phone && (
|
||||
<ContentDetail
|
||||
head="تلفن: "
|
||||
detail={
|
||||
<a href={`tel:${phone}`} dir="ltr" className="hover:text-[#5559CE]">
|
||||
{phone}
|
||||
</a>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{address && <ContentDetail head="آدرس: " detail={address} />}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,13 +12,22 @@ function Contact({ data }) {
|
||||
const handleOpen = () => setOpen(true);
|
||||
const handleClose = () => setOpen(false);
|
||||
|
||||
// بدون مختصات و بدون نشانی، کوئری نقشه خالی میماند و iframe نقطهٔ بیربط
|
||||
// نشان میدهد؛ در آن حالت نقشه و دکمهٔ مسیریابی اصلاً معنا ندارند.
|
||||
const hasCoords = Boolean(data?.map?.latitude && data?.map?.longitude);
|
||||
const mapQuery = hasCoords
|
||||
? `${data.map.latitude},${data.map.longitude}`
|
||||
: data?.location?.trim()
|
||||
? encodeURIComponent(data.location.trim())
|
||||
: "";
|
||||
|
||||
return (
|
||||
<div
|
||||
className=" opacity-page border border-[#EFEFEF] rounded-[16px] py-[12px] sm:py-[18px] md:py-[25px] lg:py-[32px] px-[12px] sm:px-[30px] md:px-[47px] lg:px-[64px] "
|
||||
>
|
||||
<div className="flex items-end justify-between">
|
||||
<Detail data={data} />
|
||||
<ModalOpenLocation
|
||||
{mapQuery && <ModalOpenLocation
|
||||
data={data}
|
||||
open={open}
|
||||
setOpen={setOpen}
|
||||
@@ -32,16 +41,13 @@ function Contact({ data }) {
|
||||
<RoutingC />
|
||||
مسیریابی
|
||||
</Button>
|
||||
</ModalOpenLocation>
|
||||
</ModalOpenLocation>}
|
||||
</div>
|
||||
<div className="w-full relative h-[460px] mt-[24px]">
|
||||
{mapQuery && <div className="w-full relative h-[460px] mt-[24px]">
|
||||
<CustomLoading width="full" height={400}>
|
||||
<iframe
|
||||
src={`https://maps.google.com/maps?q=${
|
||||
data?.map?.latitude && data?.map?.longitude
|
||||
? `${data.map.latitude},${data.map.longitude}`
|
||||
: encodeURIComponent(data?.location || data?.title || "")
|
||||
}&z=14&output=embed`}
|
||||
src={`https://maps.google.com/maps?q=${mapQuery}&z=14&output=embed`}
|
||||
title="موقعیت کلینیک روی نقشه"
|
||||
className="w-full h-full rounded-lg"
|
||||
loading="lazy"
|
||||
></iframe>
|
||||
@@ -60,7 +66,7 @@ function Contact({ data }) {
|
||||
</Button>
|
||||
</ModalOpenLocation>
|
||||
</CustomLoading>
|
||||
</div>
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { doctorTitle } from "@/helper";
|
||||
|
||||
// Icons
|
||||
import CopyBlueD from "@/components/icons/CopyBlueD";
|
||||
import DownloadBlue from "@/components/icons/DownloadBlue";
|
||||
@@ -121,7 +123,7 @@ function List({ hiddenRef, data, qrReady }) {
|
||||
typeof window !== "undefined" ? window.location.href : "";
|
||||
|
||||
const getShareText = () =>
|
||||
data?.name ? `معرفی ${data.name} در نوبت 724` : "معرفی پزشک در نوبت 724";
|
||||
data?.name ? `معرفی ${doctorTitle(data.name)} در نوبت 724` : "معرفی پزشک در نوبت 724";
|
||||
|
||||
const openShareWindow = (url) => {
|
||||
if (typeof window !== "undefined") {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { doctorTitle } from "@/helper";
|
||||
import CircularLoading from "@/app/component/loading/Circular";
|
||||
import CustomLoading from "@/app/component/loading/Custom";
|
||||
import TextLoading from "@/app/component/loading/Text";
|
||||
@@ -35,7 +36,7 @@ function Title({ doctor }) {
|
||||
<TextLoading width={90} height={20}>
|
||||
<div className="flex items-center gap-2">
|
||||
<h1 className="text-[#3B3B3B] text-[14px] sm:text-[16px] md:text-[18px] lg:text-[20px] font-bold">
|
||||
{doctor?.name}
|
||||
{doctorTitle(doctor?.name)}
|
||||
</h1>
|
||||
{isUnclaimed && (
|
||||
<span className="text-[#737373] bg-[#F5F5F5] border border-[#E5E5E5] rounded-full px-2 py-0.5 text-[10px] md:text-[12px] font-medium whitespace-nowrap">
|
||||
|
||||
@@ -6,6 +6,7 @@ import Share from "./detailDoctor/Share";
|
||||
import CustomLoading from "@/app/component/loading/Custom";
|
||||
import Faq from "@/components/specialties/detail/Faq";
|
||||
import specialtiesData from "@/data/specialties.json";
|
||||
import { doctorTitle } from "@/helper";
|
||||
|
||||
// مقصد تمیز صفحهٔ فرود تخصص؛ اگر تخصص slug نداشت، لیست پزشکان با کوئری قدیمی.
|
||||
const specialtyHref = (name) => {
|
||||
@@ -31,7 +32,7 @@ function DoctorPage({ doctor, comments, rateAggregate, addresses, bookableAddres
|
||||
</span>
|
||||
))}
|
||||
</h2>
|
||||
<p className="text-[#525252] text-nowrap mr-1">{doctor?.name}</p>
|
||||
<p className="text-[#525252] text-nowrap mr-1">{doctorTitle(doctor?.name)}</p>
|
||||
</div>
|
||||
</CustomLoading>
|
||||
<div className="flex lg:hidden">
|
||||
|
||||
@@ -4,6 +4,7 @@ import DoctorAvatar from "@/app/component/DoctorAvatar";
|
||||
import QrImg from "./QrImg";
|
||||
import SiteLogo from "./SiteLogo";
|
||||
import { getStateInfoClient } from "@/lib/getStateInfoClient";
|
||||
import { doctorTitle } from "@/helper";
|
||||
|
||||
import StarDI from "@/components/icons/StarDI";
|
||||
|
||||
@@ -83,7 +84,7 @@ function PosterLight({ data, onQrReady }) {
|
||||
</div>
|
||||
|
||||
<h1 className="mt-[28px] text-[#12365C] text-[48px] font-extrabold leading-tight">
|
||||
{data?.name}
|
||||
{doctorTitle(data?.name)}
|
||||
</h1>
|
||||
|
||||
<div className="w-full flex flex-wrap justify-center gap-[10px] mt-[16px]">
|
||||
|
||||
@@ -4,6 +4,7 @@ import DoctorAvatar from "@/app/component/DoctorAvatar";
|
||||
import QrImg from "./QrImg";
|
||||
import SiteLogoBase from "./SiteLogo";
|
||||
import { getStateInfoClient } from "@/lib/getStateInfoClient";
|
||||
import { doctorTitle } from "@/helper";
|
||||
|
||||
import StarDI from "@/components/icons/StarDI";
|
||||
import ClipBoard from "@/components/icons/ClipBoard";
|
||||
@@ -124,7 +125,7 @@ function Poster({ data, onQrReady }) {
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h1 className="text-white text-[46px] font-extrabold leading-tight">
|
||||
{data?.name}
|
||||
{doctorTitle(data?.name)}
|
||||
</h1>
|
||||
<div className="flex flex-wrap gap-[10px] mt-[16px]">
|
||||
{specialties.map((s, i) => (
|
||||
|
||||
Reference in New Issue
Block a user