diff --git a/app/clinic/[slug]/page.js b/app/clinic/[slug]/page.js
index b7c485a..b434599 100644
--- a/app/clinic/[slug]/page.js
+++ b/app/clinic/[slug]/page.js
@@ -2,15 +2,16 @@ import ClinicPage from "@/components/clinic";
import Layout from "@/components/layout/StLayout";
import { fetchReq } from "@/lib/req";
-async function Clinic({ params: { slug } }) {
+async function Clinic({ params: { slug },searchParams }) {
const API_URL = process.env.NEXT_PUBLIC_API_URL;
-
+ const page = Number(searchParams?.page) || 1;
const reqClinics = await fetchReq(
`${API_URL}/api/v1/clinic/${slug}`
);
const limit=50
+
const reqDoctors = await fetchReq(
- `${API_URL}/api/v1/clinic/doctor-list/${slug}?page=1&limit=${limit}`
+ `${API_URL}/api/v1/clinic/doctor-list/${slug}?page=${page}&limit=${limit}`
);
diff --git a/components/clinic/components/doctors/List.js b/components/clinic/components/doctors/List.js
index 660a137..82f54a0 100644
--- a/components/clinic/components/doctors/List.js
+++ b/components/clinic/components/doctors/List.js
@@ -20,34 +20,50 @@ function List({
const router = useRouter();
const changePage = async (_, num) => {
setLoading(true);
+
+ window.scrollTo({ top: 0, behavior: "smooth" });
+
const searchParams = new URLSearchParams(window.location.search);
searchParams.set("page", num);
router.push(`/clinic/${slug}?${searchParams.toString()}`);
setPage(num);
-
- let params = {
- ...QueryForDoctorsClinicReq(filter),
- current: num,
- limit,
- };
try {
- const doctors = await getClinicDoctors(slug, params);
- setDoctors(doctors.data);
- setTotalPage(doctors?.page?.total_pages || 1);
+ let params = {
+ ...QueryForDoctorsClinicReq(filter),
+ page: num,
+ limit,
+ };
+
+ const res = await getClinicDoctors(slug, params);
+ console.log("📦 پاسخ API:", res);
+
+ // اگر سرور داده را در data برمیگرداند
+ if (res?.data) {
+ setDoctors([...res.data]);
+ setTotalPage(res?.page?.total_pages || 1);
+ }
+ // اگر فقط آرایه برمیگرداند
+ else if (Array.isArray(res)) {
+ setDoctors([...res]);
+ setTotalPage(1);
+ }
+
setPage(num);
+ } catch (error) {
+ console.error("❌ خطا در دریافت داده:", error);
} finally {
setLoading(false);
}
};
- const doctorList = Array.isArray(doctors?.data) ? doctors.data : doctors;
+ const doctorList = Array.isArray(doctors)
+ ? doctors
+ : Array.isArray(doctors?.data)
+ ? doctors.data
+ : [];
return (
<>
- {loading ? (
-
- ) : doctorList?.length === 0 ? (
+ { doctorList?.length === 0 ? (
دکتری مطابق فیلتر شما یافت نشد
@@ -55,7 +71,12 @@ function List({
<>
{doctorList?.map((doctor) => (
-
+
))}
diff --git a/components/clinic/components/doctors/head/index.js b/components/clinic/components/doctors/head/index.js
index 8b91230..6f43c37 100644
--- a/components/clinic/components/doctors/head/index.js
+++ b/components/clinic/components/doctors/head/index.js
@@ -57,9 +57,10 @@ function Head({ setDoctors, slug, filter, setFilter,setPage,setTotalPage }) {
let params = QueryForDoctorsClinicReq(data);
- if (
- data?.name === data.specialty?.name ||
- data?.name === data.category?.name
+ if (
+ data?.specialty &&
+ (data?.name === data.specialty?.name ||
+ data?.name === data.category?.name)
) {
delete params.name;
}
@@ -71,7 +72,7 @@ function Head({ setDoctors, slug, filter, setFilter,setPage,setTotalPage }) {
const doctors = await getClinicDoctors(slug, params);
// تنظیم دادهها در state
- setDoctors(doctors);
+ setDoctors(doctors.data);
// ✅ حالا که جواب API اومده، مقدار صفحات مشخصه
if (doctors?.page) {
diff --git a/components/clinic/components/doctors/head/search/AutoComplete.js b/components/clinic/components/doctors/head/search/AutoComplete.js
index 83c5eac..d21d5df 100644
--- a/components/clinic/components/doctors/head/search/AutoComplete.js
+++ b/components/clinic/components/doctors/head/search/AutoComplete.js
@@ -2,71 +2,61 @@ import { Autocomplete, TextField } from "@mui/material";
import { useRef, useState, useEffect } from "react";
function AutoComplete({
- data,
- noneBg,
+ data = [], // همیشه آرایه ایمن
+ noneBg = false,
clearText,
- inputValue,
- placeholder,
+ inputValue = "",
+ placeholder = "",
handleSearch,
- setInputValue,
- setSelectedOption,
- debounce = 500,
+ debounce = 400,
}) {
const typingTimeoutRef = useRef(null);
- const [localInput, setLocalInput] = useState(inputValue || "");
+ const [localInput, setLocalInput] = useState(inputValue);
+ // sync بین inputValue بیرونی و مقدار محلی
useEffect(() => {
- setLocalInput(inputValue || "");
+ if (inputValue !== localInput) setLocalInput(inputValue || "");
}, [inputValue]);
+ // پاکسازی تایمر هنگام خروج
useEffect(() => {
return () => {
if (typingTimeoutRef.current) clearTimeout(typingTimeoutRef.current);
};
}, []);
- const onInputChange = (_, newInputValue) => {
- setLocalInput(newInputValue);
-
- if (setInputValue) setInputValue(newInputValue);
-
+ // تایپ در input
+ const onInputChange = (_, newValue) => {
+ setLocalInput(newValue);
if (typingTimeoutRef.current) clearTimeout(typingTimeoutRef.current);
typingTimeoutRef.current = setTimeout(() => {
- handleSearch(newInputValue);
+ handleSearch(newValue);
}, debounce);
};
+ // انتخاب از بین گزینهها
const onChange = (_, newValue) => {
- if (typingTimeoutRef.current) {
- clearTimeout(typingTimeoutRef.current);
- typingTimeoutRef.current = null;
- }
-
- const val = newValue
- ? typeof newValue === "string"
- ? newValue
- : newValue.name
- : "";
+ if (typingTimeoutRef.current) clearTimeout(typingTimeoutRef.current);
+ const val = typeof newValue === "string" ? newValue : newValue?.name || "";
setLocalInput(val);
- setSelectedOption && setSelectedOption(newValue);
handleSearch(val);
- if (setInputValue) setInputValue(val);
};
return (
- typeof option === "string" ? option : option.name
- }
disableClearable
+ options={Array.isArray(data) ? data : []}
+ getOptionLabel={(option) =>
+ typeof option === "string" ? option : option.name || ""
+ }
inputValue={localInput}
- className="!w-full"
onInputChange={onInputChange}
onChange={onChange}
+ noOptionsText="پزشکی یافت نشد"
+ className="!w-full"
renderOption={(props, option) => (
-
+
{option.name}
)}
diff --git a/components/clinic/components/doctors/head/search/SearchField.js b/components/clinic/components/doctors/head/search/SearchField.js
index 65a90bd..9229da1 100644
--- a/components/clinic/components/doctors/head/search/SearchField.js
+++ b/components/clinic/components/doctors/head/search/SearchField.js
@@ -1,79 +1,59 @@
+"use client";
+
import { clearFilterParams } from "@/helper";
import { useRouter } from "next/navigation";
-import specialties from "@/data/specialties.json";
+import { useRef } from "react";
import AutoComplete from "./AutoComplete";
-function SearchField({ filter, setFilter, setDataInURL }) {
+function SearchField({ filter, setFilter, setDataInURL, sendReq }) {
const router = useRouter();
+ const typingTimeoutRef = useRef(null);
+ // ✅ پاک کردن فیلد سرچ
const clearText = () => {
- clearFilterParams(router, ["name", "category", "specialty"]);
- const newFilter = {
- ...filter,
- ...{
- name: "",
- category: undefined,
- specialty: undefined,
- },
- };
+ clearFilterParams(router, ["name"]);
+ const newFilter = { ...filter, name: "" };
setFilter(newFilter);
+ setDataInURL(newFilter);
+ sendReq(newFilter); // جستجو مجدد بدون نام پزشک
};
- const handleSearch = (e) => {
- const findName = specialties.find((item) => item.name === e);
+ // ✅ فقط جستجوی پزشک بر اساس name
+ const handleSearch = (value) => {
+ const newFilter = { ...filter, name: value };
const searchParams = new URLSearchParams(window.location.search);
- let dataUrl = {};
-
- if (findName) {
- let newFilter = { ...filter };
- if (findName.parent) {
- const itemParent = specialties.find(
- (item) => item.id === findName.parent
- );
- dataUrl.specialty = findName.name;
- newFilter.category = itemParent;
- newFilter.specialty = findName;
- } else {
- dataUrl.specialty = findName.name;
- newFilter.category = findName;
- newFilter.specialty = "";
- }
+ // اگر کاربر پاک کرد
+ if (!value.trim()) {
searchParams.delete("name");
- Object.entries(dataUrl).forEach(([key, value]) => {
- if (value) {
- searchParams.set(key, value);
- }
- });
router.push(`?${searchParams.toString()}`);
- newFilter.name = e;
- setFilter(newFilter);
- } else {
- let newFilter = filter;
-
- if (
- filter.name === filter.specialty?.name ||
- filter.name === filter.category?.name
- ) {
- searchParams.delete("specialty");
- newFilter.specialty = "";
- newFilter.category = "";
- router.push(`?${searchParams.toString()}`);
- }
- newFilter.name = e;
setFilter(newFilter);
setDataInURL(newFilter);
+ sendReq(newFilter);
+ return;
}
+
+ // مقدار name در URL قرار میگیرد
+ searchParams.set("name", value);
+ router.push(`?${searchParams.toString()}`);
+ setFilter(newFilter);
+ setDataInURL(newFilter);
+
+ // جلوگیری از درخواست زیاد
+ if (typingTimeoutRef.current) clearTimeout(typingTimeoutRef.current);
+ typingTimeoutRef.current = setTimeout(() => {
+ sendReq(newFilter); // ارسال درخواست به بکاند
+ }, 400);
};
return (
);
diff --git a/components/clinic/components/doctors/head/search/SendReq.js b/components/clinic/components/doctors/head/search/SendReq.js
index b2245a0..17bb9e3 100644
--- a/components/clinic/components/doctors/head/search/SendReq.js
+++ b/components/clinic/components/doctors/head/search/SendReq.js
@@ -5,39 +5,28 @@ import specialties from "@/data/specialties.json";
function SendReq({ filter, setFilter, setDataInURL, sendReq }) {
const [loading, setLoading] = useState(false);
- // const checkName = () => {
- // let newFilter = filter;
- // const specialtyItem =
- // filter.name &&
- // specialties.find((item) => item.name.includes(filter.name));
-
- // if (specialtyItem) {
- // if (specialtyItem.parent) {
- // newFilter.specialty = specialtyItem;
- // newFilter.category = specialties.find(
- // (item) => item.id === specialtyItem.parent
- // );
- // } else {
- // newFilter.specialty = specialtyItem;
- // }
- // }
-
- // return newFilter;
- // };
-
const filterData = () => {
+ if (!filter?.name?.trim()) {
+ // اگر کاربر چیزی ننوشته، فقط کل لیست رو بگیر
+ setDataInURL(filter);
+ sendReq(filter);
+ return;
+ }
+
setLoading(true);
-
- // setLoading(true);
- // // const newFilter = checkName();
- // // setFilter(filter);
- // // setDataInURL(filter);
- sendReq(filter).finally(() => {
- setLoading(false);
- });
+ // ✅ 1. مقدار در URL ست بشه
+ if (setDataInURL) {
+ setDataInURL(filter);
+ }
+
+ // ✅ 2. درخواست به بکاند بره
+ sendReq(filter)
+ .catch((err) => console.error("❌ خطا در جستجو:", err))
+ .finally(() => {
+ setLoading(false); // ✅ 3. بعد از پاسخ، loading خاموش
+ });
};
-
return (
{
+ const changePage =async (_, num) => {
setLoading(true);
+ // 👇 اسکرول به بالا با انیمیشن
+ window.scrollTo({ top: 0, behavior: "smooth" });
+
+ // 👇 کمی تاخیر برای نمایش نرمتر
+ await new Promise((res) => setTimeout(res, 300));
+
const searchParams = new URLSearchParams(window.location.search);
searchParams.set("page", num);
router.push(`?${searchParams.toString()}`);
diff --git a/services/clinicApi.js b/services/clinicApi.js
index f52058f..6c4d9a5 100644
--- a/services/clinicApi.js
+++ b/services/clinicApi.js
@@ -16,12 +16,19 @@ export async function getClinicDoctors(slug, params = {}) {
}
const json = await response.json();
- return {
+
+ // ✅ خروجی همیشه ساختار ثابت دارد
+ return {
data: json?.data || [],
page: json?.page || json?.pages || { total_pages: 1, current: 1 },
};
} catch (error) {
- console.error("خطا در دریافت دکترهای کلینیک:", error);
- return [];
+ console.error("❌ خطا در دریافت دکترهای کلینیک:", error);
+
+ // ✅ ساختار خروجی در حالت خطا هم مثل حالت عادی
+ return {
+ data: [],
+ page: { total_pages: 1, current: 1 },
+ };
}
}