save state selected in modal filter, filter list with location selected, save data sort, filter list with sort point, real all url from .env file, change name of value category and specialties to persian and change functional find data with field

This commit is contained in:
Ehsan
2025-09-08 08:08:35 +03:30
parent ded164fcb9
commit 9f53daa398
19 changed files with 186 additions and 141 deletions
+3 -3
View File
@@ -4,12 +4,12 @@ import axios from "axios";
async function Appointment({ params: { slug } }) {
const { matchedCity } = getStateInfo();
const API_URL = process.env.NEXT_PUBLIC_API_URL;
let apt = null;
try {
const response = await axios.get(
"https://back-dev.clinic-pro.ir/api/v1/appointment-slots"
);
const response = await axios.get(`${API_URL}/api/v1/appointment-slots`);
apt = response.data.data;
} catch (error) {
// console.error("problem with req:", error.message);
+4 -4
View File
@@ -3,10 +3,10 @@ import Layout from "@/components/layout/StLayout";
import { fetchReq } from "@/lib/req";
async function Blog({ params: { slug } }) {
const blog = await fetchReq(
`https://back-dev.clinic-pro.ir/api/v1/blog/${slug}`
);
const blogs = await fetchReq("https://back-dev.clinic-pro.ir/api/v1/blogs");
const API_URL = process.env.NEXT_PUBLIC_API_URL;
const blog = await fetchReq(`${API_URL}/api/v1/blog/${slug}`);
const blogs = await fetchReq(`${API_URL}/api/v1/blogs`);
return (
<Layout>
+3 -3
View File
@@ -3,9 +3,9 @@ import Layout from "@/components/layout/StLayout";
import { fetchReq } from "@/lib/req";
export default async function Blogs() {
const response = await fetchReq(
"https://back-dev.clinic-pro.ir/api/v1/blogs"
);
const API_URL = process.env.NEXT_PUBLIC_API_URL;
const response = await fetchReq(`${API_URL}/api/v1/blogs`);
const blogs = response.blogs;
return (
+4 -2
View File
@@ -3,12 +3,14 @@ import Layout from "@/components/layout/StLayout";
import { fetchReq } from "@/lib/req";
async function Clinic({ params: { slug } }) {
const API_URL = process.env.NEXT_PUBLIC_API_URL;
const reqClinics = await fetchReq(
`https://back-dev.clinic-pro.ir/api/v1/clinic/${slug}`
`${API_URL}/api/v1/clinic/${slug}`
);
const reqDoctors = await fetchReq(
"https://back-dev.clinic-pro.ir/api/v1/doctors"
`${API_URL}/api/v1/doctors`
);
const clinic = reqClinics;
+2 -3
View File
@@ -6,10 +6,9 @@ import { getStateInfo } from "@/lib/getStateInfo";
export default async function Clinics() {
const { matchedCity, matchedState } = getStateInfo();
const API_URL = process.env.NEXT_PUBLIC_API_URL;
const clinics = await fetchReq(
"https://back-dev.clinic-pro.ir/api/v1/clinics"
);
const clinics = await fetchReq(`${API_URL}/api/v1/clinics`);
return (
<Layout name="/clinics">
+5 -3
View File
@@ -6,19 +6,21 @@ async function Doctor({ params: { slug } }) {
let doctors = null;
let doctor = null;
let comments = null;
const API_URL = process.env.NEXT_PUBLIC_API_URL;
try {
const resDoctors = await axios.get(
"https://back-dev.clinic-pro.ir/api/v1/doctors?active=1"
`${API_URL}/api/v1/doctors?active=1`
);
const resDoctor = await axios.get(
`https://back-dev.clinic-pro.ir/api/v1/doctor/${slug}`
`${API_URL}/api/v1/doctor/${slug}`
);
doctor = resDoctor.data;
doctors = resDoctors.data.data;
if (doctor) {
const resComments = await axios.get(
`https://back-dev.clinic-pro.ir/api/v1/clinicpro/comments/${doctor.id}`
`${API_URL}/api/v1/clinicpro/comments/${doctor.id}`
);
comments = resComments?.data?.data;
}
+4 -6
View File
@@ -5,6 +5,7 @@ import axios from "axios";
async function Doctors({ searchParams }) {
const { matchedCity, matchedState } = getStateInfo();
const API_URL = process.env.NEXT_PUBLIC_API_URL;
let doctors = null;
try {
@@ -13,12 +14,9 @@ async function Doctors({ searchParams }) {
if (matchedCity) params.city = matchedCity?.id || null;
if (matchedState) params.state = matchedState?.id || null;
const response = await axios.get(
"https://back-dev.clinic-pro.ir/api/v1/doctors",
{
params,
}
);
const response = await axios.get(`${API_URL}/api/v1/doctors`, {
params,
});
doctors = response.data.data;
} catch (error) {}
+1 -1
View File
@@ -16,7 +16,7 @@ const defaultData = {
function AppointmentPage({ slug, matchedCity }) {
const doctor = doctors.find((item) => item.id === +slug);
const [step, setStep] = useState(1);
const [step, setStep] = useState(0);
const [isForAnother, setIsForAnother] = useState(false);
const [prevData, setPrevData] = useState(defaultData);
+17 -7
View File
@@ -12,23 +12,28 @@ import ModalSearchCity from "@/app/component/modalSearchCity";
import specialties from "@/data/specialties.json";
function DoctorsPage({ params, matchedCity, matchedState, list }) {
const fieldId = params.field;
const fieldName = params.field;
const [doctors, setDoctors] = useState(list);
const [open, setOpen] = useState(false);
const [fields, setFields] = useState({
search: "",
stars: null,
stars: "",
});
const [selected, setSelected] = useState({
province: matchedState?.name || params?.province,
city: matchedCity?.name || params?.city,
});
const findItem = (id) => specialties.find((item) => item.id === id);
const isParent = findItem(fieldId) && findItem(fieldId).parent;
const findItem = (key, name) =>
specialties.find((item) => item[key] === name);
const isParent =
findItem("name", fieldName) && findItem("name", fieldName).parent;
const dataParent =
findItem("name", fieldName) && isParent && findItem("id", isParent);
const defaultData = {
category: isParent ? findItem(isParent) : findItem(fieldId),
specialties: isParent && findItem(fieldId),
category: isParent ? findItem("id", isParent) : findItem("name", fieldName),
specialties: isParent && findItem("name", fieldName),
turn: params && params.hasOwnProperty("turn") ? JSON.parse(params.turn) : 1,
gender: params.gender || "هر دو",
degree: params.degree || "همه موارد",
@@ -72,7 +77,12 @@ function DoctorsPage({ params, matchedCity, matchedState, list }) {
confirmedData={confirmedData}
setConfirmedData={setConfirmedData}
/>
<SortList data={data} setData={setData} />
<SortList
fields={fields}
setFields={setFields}
data={data}
setData={setData}
/>
</div>
</div>
<ListDoctors list={doctors} />
+13 -19
View File
@@ -15,24 +15,9 @@ function ButtonApply({
const router = useRouter();
const [loading, setLoading] = useState(false);
const sendReq = () => {
const sendReq = (requestData) => {
setLoading(true);
const params = new URLSearchParams(window.location.search);
const specialty = params.get("specialty");
const gender = params.get("gender");
const degree = params.get("degree");
const turn = params.get("turn");
const requestData = {
specialty: specialty === "null" ? null : specialty,
gender,
degree,
turn,
city: matchedCity?.id || null,
state: matchedState?.id || null,
};
request
.getDoctors(requestData)
.then((res) => {
@@ -50,13 +35,16 @@ function ButtonApply({
const mappings = [
{
key: "specialty",
key: "field",
getValue: () => {
if (data.category) {
const children = specialties.filter(
(item) => item.parent === data.category.id
);
return children.length > 0 ? children[0].id : data.category.id;
return children.length > 0
? children.find((item) => item.name === data.specialties.name)
?.name
: data.category.name;
}
return null;
},
@@ -66,14 +54,20 @@ function ButtonApply({
{ key: "turn", getValue: () => data.turn },
];
let requestData = {
city: matchedCity?.id || null,
state: matchedState?.id || null,
};
mappings.forEach(({ key, getValue }) => {
const value = getValue();
current.set(key, value);
requestData[key] = value;
});
const queryString = current.toString();
setConfirmedData(data);
sendReq();
sendReq(requestData);
router.push(`/doctors?${queryString}`);
};
+6 -9
View File
@@ -29,13 +29,8 @@ function FilterModal({
};
const deleteData = () => {
clearFilterParams(router, [
"turn",
"specialty",
"degree",
"category",
"gender",
]);
clearFilterParams(router, ["turn", "field", "degree", "gender"]);
const defaultData = {
category: "",
specialties: "",
@@ -43,8 +38,10 @@ function FilterModal({
gender: "هر دو",
degree: "متخصص",
};
setData(defaultData);
setConfirmedData(defaultData);
setData({ ...defaultData });
setConfirmedData({ ...defaultData });
handleClose();
};
+1 -1
View File
@@ -5,7 +5,7 @@ function SearchField({ fields, setFields }) {
return (
<TextField
variant="standard"
value={fields}
value={fields.search}
onChange={(e) => setFields({ ...fields, search: e.target.value })}
InputProps={{
disableUnderline: true,
+20 -4
View File
@@ -3,6 +3,10 @@ import SearchD from "@/components/icons/SearchD";
import { useState } from "react";
import { request } from "@/services/response";
// Data
import cities from "@/data/city.json";
import states from "@/data/state.json";
function SendReq({ fields, setDoctors, matchedCity, matchedState }) {
const [loading, setLoading] = useState(false);
@@ -13,15 +17,27 @@ function SendReq({ fields, setDoctors, matchedCity, matchedState }) {
const specialty = params.get("specialty");
const gender = params.get("gender");
const degree = params.get("degree");
const turn = params.get("turn");
const active = params.get("turn");
const province = params.get("province");
const sort = fields.stars;
let city = matchedCity?.id || null;
let state = matchedState?.id || null;
if (province) {
const findCity = cities.find((item) => item.id === province);
const findState = states.find((item) => item.id === findCity.province_id);
if (findCity) city = findCity.id;
if (findState) state = findState.id;
}
const requestData = {
specialty: specialty === "null" ? null : specialty,
gender,
degree,
turn,
city: matchedCity?.id || null,
state: matchedState?.id || null,
active,
city,
state,
sort,
name: fields.search,
};
-1
View File
@@ -3,7 +3,6 @@ import SettingD from "@/components/icons/SettingD";
import ArrowBottomD from "@/components/icons/ArrowBottomD";
import FilterModal from "../modal/FilterModal";
import SendReq from "./SendReq";
import { useState } from "react";
import SearchField from "./SearchField";
function SearchBar({
+8 -9
View File
@@ -5,20 +5,19 @@ import SortD from "../../icons/SortD";
import StarDI from "@/components/icons/StarDI";
const listSort = [
{ label: 3, id: 30 },
{ label: 4, id: 40 },
{ label: 5, id: 50 },
{ label: 3, id: 3 },
{ label: 4, id: 4 },
{ label: 5, id: 5 },
];
function SelectSort() {
const [sort, setSort] = useState("");
const handleChange = (event) => setSort(event.target.value);
function SelectSort({ fields, setFields }) {
const handleChange = (event) =>
setFields({ ...fields, stars: Number(event.target.value) });
return (
<Select
displayEmpty
defaultValue={sort}
defaultValue={fields.stars}
onChange={handleChange}
className="!w-[198px] !max-w-[305px] lg:!w-full text-[14px] md:text-[16px] !bg-transparent lg:!bg-[#FFF] !h-[44px] sm:!h-[50px] md:!h-[57px] lg:!h-[64px]"
renderValue={(value) => {
@@ -29,7 +28,7 @@ function SelectSort() {
</SvgIcon>
{value ? (
<ul className="flex items-center justify-start gap-1">
{Array(sort)
{Array(fields.stars)
.fill({})
.map((_, idx) => (
<li key={idx}>
+2 -2
View File
@@ -4,13 +4,13 @@ import FilterModal from "../modal/FilterModal";
import FilterBtn from "./FilterBtn";
import SelectSort from "./SelectSort";
function SortList({ data, setData }) {
function SortList({ fields, data, setFields, setData }) {
return (
<div className="flex flex-wrap items-center lg:!w-[25%] gap-[20px] gap-y-[12px] lg:gap-0">
<FilterModal data={data} setData={setData}>
<FilterBtn />
</FilterModal>
<SelectSort />
<SelectSort fields={fields} setFields={setFields} />
</div>
);
}
+4 -64
View File
@@ -2,12 +2,10 @@
import { useState } from "react";
import { Button, TextField } from "@mui/material";
import ModalSearchCity from "@/app/component/modalSearchCity";
import Search from "@/components/icons/Search";
import ButtonFilter from "@/app/component/modalSearchCity/ButtonFilter";
import Link from "next/link";
import SearchD from "@/components/icons/SearchD";
import FilterText from "./FilterText";
import RedirectLink from "./RedirectLink";
function Fields({ city, state }) {
const [open, setOpen] = useState(false);
@@ -28,66 +26,8 @@ function Fields({ city, state }) {
<ButtonFilter setOpen={setOpen} selected={data} />
</ModalSearchCity>
<span className="black w-px bg-[#EFEFEF]"></span>
<TextField
variant="standard"
onChange={(e) => setData({ ...data, search: e.target.value })}
InputProps={{
disableUnderline: true,
}}
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
"& .MuiInput-root": {
padding: "0",
borderBottom: "none",
},
"& .MuiInputBase-input": {
color: "#6C757D",
},
"& .MuiInputBase-input": {
color: "#6C757D",
fontSize: {
xs: "10px !important",
sm: "12px !important",
md: "14px !important",
lg: "16px !important",
},
},
}}
placeholder="جستجوی نام پزشک، تخصص، بیماری ..."
dir="rtl"
className={`!shadow-none !w-full lg:!w-[524px] bg-[#FAFAFA] !text-[14px] md:!text-[16px] !rounded-0 !font-normal !text-[#6C757D]`}
/>
<Link
href={{
pathname: "/doctors",
query: {
province: data.province,
city: data.city,
search: data.search,
},
}}
>
<Button className="!hidden lg:!flex !rounded-[4px] !h-[40px] sm:!h-[42px] md:!h-[45px] lg:!h-[48px] !gap-2.5 !min-w-[114px]">
<div className="min-w-[20px] min-h-[20px]">
<Search />
</div>
<p>جستجو</p>
</Button>
<Button
className="!flex lg:!hidden !rounded-[4px]
!w-[40px] sm:!w-[42px] md:!w-[45px] lg:!w-[48px]
!h-[40px] sm:!h-[42px] md:!h-[45px] lg:!h-[48px]
!min-w-[40px] sm:!min-w-[42px] md:!min-w-[45px] lg:!min-w-[48px]
!min-h-[40px] sm:!min-h-[42px] md:!min-h-[45px] lg:!min-h-[48px]
!gap-2.5 !p-2.5"
>
<div className="w-[24px] h-[24px] min-w-[24px] min-h-[24px]">
<SearchD />
</div>
</Button>
</Link>
<FilterText data={data} setData={setData} />
<RedirectLink data={data} />
</>
);
}
+40
View File
@@ -0,0 +1,40 @@
import React from "react";
import { TextField } from "@mui/material";
function FilterText({ data, setData }) {
return (
<TextField
variant="standard"
onChange={(e) => setData({ ...data, search: e.target.value })}
InputProps={{
disableUnderline: true,
}}
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
"& .MuiInput-root": {
padding: "0",
borderBottom: "none",
},
"& .MuiInputBase-input": {
color: "#6C757D",
},
"& .MuiInputBase-input": {
color: "#6C757D",
fontSize: {
xs: "10px !important",
sm: "12px !important",
md: "14px !important",
lg: "16px !important",
},
},
}}
placeholder="جستجوی نام پزشک، تخصص، بیماری ..."
dir="rtl"
className={`!shadow-none !w-full lg:!w-[524px] bg-[#FAFAFA] !text-[14px] md:!text-[16px] !rounded-0 !font-normal !text-[#6C757D]`}
/>
);
}
export default FilterText;
+49
View File
@@ -0,0 +1,49 @@
"use client";
import SearchD from "@/components/icons/SearchD";
import { Search } from "@mui/icons-material";
import { Button } from "@mui/material";
import { useRouter } from "next/navigation";
function RedirectLink({ data }) {
const router = useRouter();
const handleRedirect = () => {
const queryParams = new URLSearchParams({
province: data.province || "",
city: data.city || "",
search: data.search || "",
}).toString();
router.push(`/doctors?${queryParams}`);
};
return (
<>
<Button
className="!hidden lg:!flex !rounded-[4px] !h-[40px] sm:!h-[42px] md:!h-[45px] lg:!h-[48px] !gap-2.5 !min-w-[114px]"
onClick={handleRedirect}
>
<div className="min-w-[20px] min-h-[20px]">
<Search />
</div>
<p>جستجو</p>
</Button>
<Button
onClick={handleRedirect}
className="!flex lg:!hidden !rounded-[4px]
!w-[40px] sm:!w-[42px] md:!w-[45px] lg:!w-[48px]
!h-[40px] sm:!h-[42px] md:!h-[45px] lg:!h-[48px]
!min-w-[40px] sm:!min-w-[42px] md:!min-w-[45px] lg:!min-w-[48px]
!min-h-[40px] sm:!min-h-[42px] md:!min-h-[45px] lg:!min-h-[48px]
!gap-2.5 !p-2.5"
>
<div className="w-[24px] h-[24px] min-w-[24px] min-h-[24px]">
<SearchD />
</div>
</Button>
</>
);
}
export default RedirectLink;