fix(images): resolve relative backend image URLs to absolute
API مسیرهای تصویر را نسبی برمیگرداند (/uploads/...) که next/image روی دامنه localhost میجست و 404 میداد. helper جدید imageUrl مسیرهای نسبی uploads را با NEXT_PUBLIC_API_URL کامل میکند (absolute و asset محلی دستنخورده). اعمال روی لیست/جزئیات پزشک، نوبت، گالری کلینیک، آواتارها. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import Link from "next/link";
|
||||
import CustomLoading from "./loading/Custom";
|
||||
import TextLoading from "./loading/Text";
|
||||
import CircularLoading from "./loading/Circular";
|
||||
import { imageUrl } from "@/helper";
|
||||
|
||||
// Icons
|
||||
import ArrowLeftD from "@/components/icons/ArrowLeftD";
|
||||
@@ -32,7 +33,7 @@ function ItemDoctor({ doctor, loading, setDoctors, priority = false }) {
|
||||
width={72}
|
||||
height={72}
|
||||
alt="image-doctor"
|
||||
src={doctor?.img?.[0]?.url || "/assets/images/user.png"}
|
||||
src={imageUrl(doctor?.img?.[0]?.url)}
|
||||
className="object-contain rounded-full w-[64px] md:w-[68px] lg:w-[72px] h-[64px] md:h-[68px] lg:h-[72px]"
|
||||
priority={priority}
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Image from "next/image";
|
||||
import { imageUrl } from "@/helper";
|
||||
import { Button, CircularProgress } from "@mui/material";
|
||||
|
||||
// Icons
|
||||
@@ -75,7 +76,7 @@ function ItemUser({ update, setUpdate, data }) {
|
||||
<div className="flex items-center justify-start gap-2">
|
||||
<Image
|
||||
className="!w-[32px] !h-[32px]"
|
||||
src={data.author?.picture[0]?.url}
|
||||
src={imageUrl(data.author?.picture?.[0]?.url)}
|
||||
width={40}
|
||||
height={40}
|
||||
alt="profile"
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import Image from "next/image";
|
||||
import { imageUrl } from "@/helper";
|
||||
|
||||
function Head({ doctor }) {
|
||||
// تبدیل img array به string
|
||||
const doctorImage = doctor?.img?.[0]?.url || "/default-doctor.jpg";
|
||||
const doctorImage = imageUrl(doctor?.img?.[0]?.url, "/default-doctor.jpg");
|
||||
|
||||
// تبدیل specialties array به string
|
||||
const expertiseText = doctor?.specialties
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import Image from "next/image";
|
||||
import { imageUrl } from "@/helper";
|
||||
|
||||
function Head({ doctor }) {
|
||||
// تبدیل img array به string
|
||||
const doctorImage = doctor?.img?.[0]?.url || "/default-doctor.jpg";
|
||||
const doctorImage = imageUrl(doctor?.img?.[0]?.url, "/default-doctor.jpg");
|
||||
|
||||
// تبدیل specialties array به string
|
||||
const expertiseText = doctor?.specialties
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import CustomLoading from "@/app/component/loading/Custom";
|
||||
import Image from "next/image";
|
||||
import { imageUrl } from "@/helper";
|
||||
|
||||
function Slider({ data }) {
|
||||
return (
|
||||
@@ -11,7 +12,7 @@ function Slider({ data }) {
|
||||
idx !== 0 ? (
|
||||
<CustomLoading key={idx} width={90} height={90}>
|
||||
<Image
|
||||
src={item.url}
|
||||
src={imageUrl(item.url)}
|
||||
width={90}
|
||||
height={90}
|
||||
alt="image clinic"
|
||||
|
||||
@@ -5,6 +5,7 @@ import GreenCalendarTurn from "@/components/icons/GreenCalendarTurn";
|
||||
import { Button } from "@mui/material";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { imageUrl } from "@/helper";
|
||||
|
||||
function ItemAppointment({ turn, loading, doctorSlug }) {
|
||||
return (
|
||||
@@ -21,7 +22,7 @@ function ItemAppointment({ turn, loading, doctorSlug }) {
|
||||
width={56}
|
||||
height={56}
|
||||
alt="doctor"
|
||||
src={turn?.img[0]?.url}
|
||||
src={imageUrl(turn?.img?.[0]?.url)}
|
||||
/>
|
||||
</CircularLoading>
|
||||
<div className="flex flex-col items-start justify-center gap-2">
|
||||
|
||||
@@ -5,6 +5,7 @@ import LikeDI from "@/components/icons/LikeDI";
|
||||
import StarDI from "@/components/icons/StarDI";
|
||||
import TickCircle from "@/components/icons/TickCircle";
|
||||
import Image from "next/image";
|
||||
import { imageUrl } from "@/helper";
|
||||
|
||||
function Title({ doctor }) {
|
||||
return (
|
||||
@@ -16,7 +17,7 @@ function Title({ doctor }) {
|
||||
w-[40px] sm:w-[81px] md:w-[123px] lg:w-[164px]
|
||||
h-[40px] sm:h-[81px] md:h-[123px] lg:h-[164px]
|
||||
"
|
||||
src={doctor?.img?.[0]?.url || "/assets/images/user.png"}
|
||||
src={imageUrl(doctor?.img?.[0]?.url)}
|
||||
alt="img-doctor"
|
||||
height={164}
|
||||
width={164}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
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={data?.img[0]?.url}
|
||||
src={imageUrl(data?.img?.[0]?.url)}
|
||||
width={173}
|
||||
height={173}
|
||||
alt="profile-user"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { getParsedUserInfo } from "@/helper";
|
||||
import Image from "next/image";
|
||||
import { imageUrl } from "@/helper";
|
||||
|
||||
function Head({ user }) {
|
||||
const userInfo = getParsedUserInfo();
|
||||
@@ -8,7 +9,7 @@ function Head({ user }) {
|
||||
<div className="w-full flex flex-row md:flex-col items-center justify-center md:justify-start gap-[12px] md:gap-[4px]">
|
||||
<Image
|
||||
className="rounded-full border-[3px] border-solid border-[#F8F8FF] shadow-[0px_1px_25.6px_0px_rgba(85,_89,_205,_0.20)]"
|
||||
src={userInfo?.picture[0]?.url}
|
||||
src={imageUrl(userInfo?.picture?.[0]?.url)}
|
||||
alt="profile"
|
||||
height={73}
|
||||
width={73}
|
||||
|
||||
@@ -12,6 +12,18 @@ export const numberToArStyle = (num) => num?.toLocaleString("ar-AE") || "";
|
||||
|
||||
export const isActiveURL = (link, name) => link === name;
|
||||
|
||||
// تبدیل مسیر نسبی تصویر (/uploads/...) به URL کامل backend.
|
||||
// مسیرهای absolute (http...) و asset های محلی (/assets، /default) دستنخورده میمانند.
|
||||
export const imageUrl = (url, fallback = "/assets/images/user.png") => {
|
||||
if (!url) return fallback;
|
||||
if (/^https?:\/\//.test(url)) return url;
|
||||
if (url.startsWith("/uploads")) {
|
||||
const base = process.env.NEXT_PUBLIC_API_URL || "";
|
||||
return `${base}${url}`;
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
export const convertToJalali = (date) => {
|
||||
const currentDate = date;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user