change design poster and text head && design modal filter & data for filter and doctors & handle functionality filter, set in url, read from url and change state
This commit is contained in:
@@ -13,13 +13,13 @@ import PointD from "@/components/icons/PointD";
|
|||||||
|
|
||||||
function ItemDoctor({ doctor, loading, setDoctors }) {
|
function ItemDoctor({ doctor, loading, setDoctors }) {
|
||||||
const handleLoading = () => {
|
const handleLoading = () => {
|
||||||
setDoctors((prevDoctors) =>
|
// setDoctors((prevDoctors) =>
|
||||||
prevDoctors.map((item) =>
|
// prevDoctors.map((item) =>
|
||||||
item.id === doctor.id
|
// item.id === doctor.id
|
||||||
? { ...item, loading: true }
|
// ? { ...item, loading: true }
|
||||||
: { ...item, loading: false }
|
// : { ...item, loading: false }
|
||||||
)
|
// )
|
||||||
);
|
// );
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import ItemUser from "./ItemUser";
|
import ItemUser from "./ItemUser";
|
||||||
|
|
||||||
function Comment({ data, comments }) {
|
function Comment({ comments }) {
|
||||||
const [list, setList] = useState(data?.comments);
|
|
||||||
const [update, setUpdate] = useState(false);
|
const [update, setUpdate] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { TextField } from "@mui/material";
|
|||||||
function Field({
|
function Field({
|
||||||
type,
|
type,
|
||||||
name,
|
name,
|
||||||
|
error,
|
||||||
title,
|
title,
|
||||||
props,
|
props,
|
||||||
value,
|
value,
|
||||||
@@ -31,7 +32,9 @@ function Field({
|
|||||||
"& .MuiInputBase-input": { padding: "12.5px 14px" },
|
"& .MuiInputBase-input": { padding: "12.5px 14px" },
|
||||||
"& .MuiInputBase-root": { borderRadius: "6px !important" },
|
"& .MuiInputBase-root": { borderRadius: "6px !important" },
|
||||||
"& .MuiOutlinedInput-notchedOutline": {
|
"& .MuiOutlinedInput-notchedOutline": {
|
||||||
border: "1px solid #E9ECEF !important",
|
border: error
|
||||||
|
? "1px solid red !important"
|
||||||
|
: "1px solid #E9ECEF !important",
|
||||||
},
|
},
|
||||||
".Mui-focused": {
|
".Mui-focused": {
|
||||||
"& .MuiOutlinedInput-notchedOutline": {
|
"& .MuiOutlinedInput-notchedOutline": {
|
||||||
|
|||||||
@@ -2,33 +2,35 @@ import CloseModalD from "@/components/icons/CloseModalD";
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
||||||
function Content({ data, onClose }) {
|
function Content({ data, onClose }) {
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
const { latitude, longitude } = data && data.map;
|
const { latitude, longitude } = data && data.map;
|
||||||
|
|
||||||
const maps = [
|
const maps = [
|
||||||
{
|
{
|
||||||
src: "/assets/images/snapp.png",
|
src: "/assets/images/snapp.png",
|
||||||
name: "snapp",
|
name: "snapp",
|
||||||
url: `https://snapp.ir/route?lat=${latitude}&lng=${longitude}`,
|
url: `https://snapp.ir/route?lat=${"latitude"}&lng=${"longitude"}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: "/assets/images/tapsi.png",
|
src: "/assets/images/tapsi.png",
|
||||||
name: "tapsi",
|
name: "tapsi",
|
||||||
url: `https://tapsi.ir/route?lat=${latitude}&lng=${longitude}`,
|
url: `https://tapsi.ir/route?lat=${"latitude"}&lng=${"longitude"}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: "/assets/images/maps.png",
|
src: "/assets/images/maps.png",
|
||||||
name: "maps",
|
name: "maps",
|
||||||
url: `https://www.google.com/maps/dir/?api=1&destination=${latitude},${longitude}`,
|
url: `https://www.google.com/maps/dir/?api=1&destination=${"latitude"},${"longitude"}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: "/assets/images/balad.png",
|
src: "/assets/images/balad.png",
|
||||||
name: "balad",
|
name: "balad",
|
||||||
url: `https://balad.ir/map?lat=${latitude}&lng=${longitude}`,
|
url: `https://balad.ir/map?lat=${"latitude"}&lng=${"longitude"}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: "/assets/images/waze.png",
|
src: "/assets/images/waze.png",
|
||||||
name: "waze",
|
name: "waze",
|
||||||
url: `https://waze.com/ul?ll=${latitude},${longitude}&navigate=yes`,
|
url: `https://waze.com/ul?ll=${"latitude"},${"longitude"}&navigate=yes`,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -61,7 +63,7 @@ function Content({ data, onClose }) {
|
|||||||
height={40}
|
height={40}
|
||||||
width={40}
|
width={40}
|
||||||
/>
|
/>
|
||||||
<p className="text-[#3B3B3B] font-normal text-[14px]">
|
<p className="text-[#3B3B3B] text-center font-normal text-[14px]">
|
||||||
{item.name}
|
{item.name}
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { styleDefault } from "@/mui";
|
|||||||
import Content from "./Content";
|
import Content from "./Content";
|
||||||
|
|
||||||
function ModalOpenLocation({ open, data, setOpen, handleClose, children }) {
|
function ModalOpenLocation({ open, data, setOpen, handleClose, children }) {
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
const toggleDrawer = (newOpen) => () => {
|
const toggleDrawer = (newOpen) => () => {
|
||||||
setOpen(newOpen);
|
setOpen(newOpen);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,55 +1,95 @@
|
|||||||
|
"use client";
|
||||||
import CustomLoading from "@/app/component/loading/Custom";
|
import CustomLoading from "@/app/component/loading/Custom";
|
||||||
import ArrowLeftList from "@/components/icons/ArrowLeftList";
|
import ArrowLeftList from "@/components/icons/ArrowLeftList";
|
||||||
import { Button } from "@mui/material";
|
import { Button } from "@mui/material";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useRef } from "react";
|
import { useRef, useEffect, useState } from "react";
|
||||||
|
|
||||||
function ListBime({ data }) {
|
function ListBime({ data }) {
|
||||||
const list = useRef();
|
const list = useRef();
|
||||||
|
const [showArrows, setShowArrows] = useState(false);
|
||||||
|
const [itemWidth, setItemWidth] = useState(156);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data?.list_bime?.length > 4) {
|
||||||
|
setShowArrows(true);
|
||||||
|
} else {
|
||||||
|
setShowArrows(false);
|
||||||
|
}
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
if (window.innerWidth < 640) {
|
||||||
|
setItemWidth(window.innerWidth / 2.5);
|
||||||
|
} else if (window.innerWidth < 1024) {
|
||||||
|
setItemWidth(window.innerWidth / 3.5);
|
||||||
|
} else {
|
||||||
|
setItemWidth(156);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleResize();
|
||||||
|
window.addEventListener("resize", handleResize);
|
||||||
|
return () => window.removeEventListener("resize", handleResize);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleScroll = (type) => {
|
const handleScroll = (type) => {
|
||||||
|
if (!list.current) return;
|
||||||
list.current.scrollBy({
|
list.current.scrollBy({
|
||||||
left: type === "left" ? -200 : 200,
|
left: type === "left" ? -itemWidth : itemWidth,
|
||||||
behavior: "smooth",
|
behavior: "smooth",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full relative">
|
<div className="relative w-[calc(100%_-_48px)] mx-auto">
|
||||||
<Button
|
{showArrows && (
|
||||||
variant="outlined"
|
<Button
|
||||||
onClick={() => handleScroll("right")}
|
variant="outlined"
|
||||||
className="!border-[#EFEFEF] !hidden md:!flex !bg-[#FFF] !absolute !right-[-24px] !top-1/2 !-translate-y-1/2 !rounded-full !min-w-fit !p-0 !w-[48px] !h-[48px] !z-20 !rotate-180"
|
onClick={() => handleScroll("right")}
|
||||||
>
|
className="!border-[#EFEFEF] md:!flex !bg-[#FFF] !absolute !right-[-24px] !top-1/2 !-translate-y-1/2 !rounded-full !min-w-fit !p-0 !w-[48px] !h-[48px] !z-20 !rotate-180"
|
||||||
<ArrowLeftList />
|
>
|
||||||
</Button>
|
<ArrowLeftList />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
<ul
|
<ul
|
||||||
ref={list}
|
ref={list}
|
||||||
className="flex overflow-auto hidden-scroll mt-[8px] items-center justify-start xl:justify-center gap-[8px] sm:gap-[13px] md:gap-[19px] lg:gap-[24px]"
|
className={`flex mt-[8px] items-center justify-start xl:justify-center gap-[8px] sm:gap-[13px] md:gap-[19px] lg:gap-[24px] ${
|
||||||
|
showArrows ? "overflow-x-auto hidden-scroll" : "overflow-visible"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{data?.list_bime?.map((item, idx) => (
|
{data?.list_bime?.map((item, idx) => (
|
||||||
<CustomLoading key={idx} width={156} height={110}>
|
<CustomLoading key={idx} width={itemWidth} height={110}>
|
||||||
<li className="p-[16px] min-w-[156px] w-full border border-[#EFEFEF] flex flex-col items-center justify-center gap-[20px]">
|
<li
|
||||||
|
className="p-[16px] border border-[#EFEFEF] h-[175px] flex flex-col items-center justify-center gap-[20px]"
|
||||||
|
style={{ minWidth: itemWidth }}
|
||||||
|
>
|
||||||
<Image
|
<Image
|
||||||
src={item.logo && item.logo[0]?.url || ""}
|
src={item.logo?.[0]?.url || ""}
|
||||||
height={92}
|
height={92}
|
||||||
width={92}
|
width={92}
|
||||||
alt="bime"
|
alt="bime"
|
||||||
|
className="object-contain"
|
||||||
/>
|
/>
|
||||||
<h3 className="text-[#525252] text-[16px] font-medium">
|
<h3 className="text-[#525252] text-[16px] font-medium text-center">
|
||||||
{item.name}
|
{item.name}
|
||||||
</h3>
|
</h3>
|
||||||
</li>
|
</li>
|
||||||
</CustomLoading>
|
</CustomLoading>
|
||||||
))}
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{showArrows && (
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onClick={() => handleScroll("left")}
|
onClick={() => handleScroll("left")}
|
||||||
className="!border-[#EFEFEF] !hidden md:!flex !bg-[#FFF] !absolute !left-[-24px] !top-1/2 !-translate-y-1/2 !rounded-full !min-w-fit !p-0 !w-[48px] !h-[48px] !z-20"
|
className="!border-[#EFEFEF] md:!flex !bg-[#FFF] !absolute !left-[-24px] !top-1/2 !-translate-y-1/2 !rounded-full !min-w-fit !p-0 !w-[48px] !h-[48px] !z-20"
|
||||||
>
|
>
|
||||||
<ArrowLeftList />
|
<ArrowLeftList />
|
||||||
</Button>
|
</Button>
|
||||||
</ul>
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,7 @@ function Detail({ data }) {
|
|||||||
head="روزهای کاری: "
|
head="روزهای کاری: "
|
||||||
detail={`ساعت کاری: ${data.hours_of_work}`}
|
detail={`ساعت کاری: ${data.hours_of_work}`}
|
||||||
/>
|
/>
|
||||||
<ContentDetail
|
<ContentDetail head="تلفن: " detail={`${data.phone_number}`} />
|
||||||
head="تلفن: "
|
|
||||||
detail={`${data.phone_number_1} ${data.phone_number_2}`}
|
|
||||||
/>
|
|
||||||
<ContentDetail head="ایمیل:" detail={data.email} />
|
<ContentDetail head="ایمیل:" detail={data.email} />
|
||||||
<ContentDetail head="آدرس: " detail={data.location} />
|
<ContentDetail head="آدرس: " detail={data.location} />
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -15,14 +15,15 @@ function Contact({ data }) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="
|
className="
|
||||||
opacity-page border border-[#EFEFEF] rounded-[16px]
|
opacity-page border border-[#EFEFEF] rounded-[16px]
|
||||||
py-[12px] sm:py-[18px] md:py-[25px] lg:py-[32px]
|
py-[12px] sm:py-[18px] md:py-[25px] lg:py-[32px]
|
||||||
px-[12px] sm:px-[30px] md:px-[47px] lg:px-[64px]
|
px-[12px] sm:px-[30px] md:px-[47px] lg:px-[64px]
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div className="flex items-end justify-between">
|
<div className="flex items-end justify-between">
|
||||||
<Detail data={data} />
|
<Detail data={data} />
|
||||||
<ModalOpenLocation
|
<ModalOpenLocation
|
||||||
|
data={data}
|
||||||
open={open}
|
open={open}
|
||||||
setOpen={setOpen}
|
setOpen={setOpen}
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
@@ -40,11 +41,12 @@ function Contact({ data }) {
|
|||||||
<div className="w-full relative h-[460px] mt-[24px]">
|
<div className="w-full relative h-[460px] mt-[24px]">
|
||||||
<CustomLoading width="full" height={400}>
|
<CustomLoading width="full" height={400}>
|
||||||
<iframe
|
<iframe
|
||||||
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d83998.96777841153!2d2.264635095144491!3d48.85882549249809!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47e66e1f06e2b70f%3A0x40b82c3688c9460!2sParis%2C%20France!5e0!3m2!1sen!2snl!4v1723498499341!5m2!1sen!2snl"
|
src={`https://maps.google.com/maps?q=${data.map.latitude},${data.map.longitude}&z=14&output=embed`}
|
||||||
className="w-full h-full rounded-lg"
|
className="w-full h-full rounded-lg"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
></iframe>
|
></iframe>
|
||||||
<ModalOpenLocation
|
<ModalOpenLocation
|
||||||
|
data={data}
|
||||||
open={open}
|
open={open}
|
||||||
setOpen={setOpen}
|
setOpen={setOpen}
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import SearchBar from "./search";
|
||||||
|
import SortList from "./sortlist";
|
||||||
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
|
import specialties from "@/data/specialties.json";
|
||||||
|
import { QueryForDoctorsFilter } from "@/helper";
|
||||||
|
|
||||||
|
function Head() {
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
const [doctors, setDoctors] = useState();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const fieldName = searchParams.get("specialty");
|
||||||
|
|
||||||
|
const setDataInURL = (newFilter) => {
|
||||||
|
const query = QueryForDoctorsFilter(newFilter);
|
||||||
|
|
||||||
|
const searchParams = new URLSearchParams(query).toString();
|
||||||
|
router.push(`?${searchParams}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const findItem = (key, name) =>
|
||||||
|
specialties.find((item) => item[key] === name);
|
||||||
|
const isParent =
|
||||||
|
findItem("name", fieldName) && findItem("name", fieldName).parent;
|
||||||
|
|
||||||
|
const valCategory = isParent
|
||||||
|
? findItem("id", isParent)
|
||||||
|
: findItem("name", fieldName);
|
||||||
|
const valSpecialty = isParent && findItem("name", fieldName);
|
||||||
|
|
||||||
|
const defaultFilter = {
|
||||||
|
category: valCategory,
|
||||||
|
specialty: valSpecialty,
|
||||||
|
active: searchParams.get("active") || 0,
|
||||||
|
gender: searchParams.get("gender") || "هر دو",
|
||||||
|
degree: searchParams.get("degree") || "همه موارد",
|
||||||
|
sort: (searchParams.get("sort") && Number(searchParams.get("sort"))) || "",
|
||||||
|
name:
|
||||||
|
searchParams.get("name") || valSpecialty?.name || valCategory?.name || "",
|
||||||
|
};
|
||||||
|
const [filter, setFilter] = useState(defaultFilter);
|
||||||
|
|
||||||
|
const updateData = (name, value, isReq) => {
|
||||||
|
const newFilter = { ...filter, [name]: value };
|
||||||
|
setDataInURL(newFilter);
|
||||||
|
setFilter(newFilter);
|
||||||
|
isReq && sendReq(newFilter);
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendReq = (newFilter) => {
|
||||||
|
// const data = newFilter || filter;
|
||||||
|
// const params = QueryForDoctorsReq(data);
|
||||||
|
// let filteredName = params;
|
||||||
|
// if (
|
||||||
|
// data?.name === data.specialty?.name ||
|
||||||
|
// data?.name === data.category?.name
|
||||||
|
// ) {
|
||||||
|
// filteredName.name = "";
|
||||||
|
// delete filteredName.name;
|
||||||
|
// }
|
||||||
|
// filteredName.page = 1;
|
||||||
|
// filteredName.limit = 12;
|
||||||
|
// setPage(1);
|
||||||
|
// return request
|
||||||
|
// .getDoctors(filteredName)
|
||||||
|
// .then((res) => {
|
||||||
|
// setDoctors(res.data);
|
||||||
|
// return res;
|
||||||
|
// })
|
||||||
|
// .catch((err) => {
|
||||||
|
// throw err;
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col lg:flex-row items-start lg:items-center justify-center gap-[24px] lg:gap-[32px] w-full">
|
||||||
|
<SearchBar
|
||||||
|
filter={filter}
|
||||||
|
sendReq={sendReq}
|
||||||
|
setFilter={setFilter}
|
||||||
|
updateData={updateData}
|
||||||
|
setDataInURL={setDataInURL}
|
||||||
|
/>
|
||||||
|
<SortList
|
||||||
|
filter={filter}
|
||||||
|
sendReq={sendReq}
|
||||||
|
setFilter={setFilter}
|
||||||
|
updateData={updateData}
|
||||||
|
setDataInURL={setDataInURL}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Head;
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { Button } from "@mui/material";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
function ButtonApply({ sendReq, setOpen }) {
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
setLoading(false);
|
||||||
|
setOpen(false);
|
||||||
|
|
||||||
|
// setLoading(true);
|
||||||
|
|
||||||
|
// sendReq().finally(() => {
|
||||||
|
// setOpen(false);
|
||||||
|
// setLoading(false);
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex justify-end w-full">
|
||||||
|
<Button
|
||||||
|
loading={loading}
|
||||||
|
variant="contained"
|
||||||
|
onClick={handleClick}
|
||||||
|
className="!px-3 !py-2 !text-[16px] !font-medium"
|
||||||
|
>
|
||||||
|
اعمال تغییرات
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ButtonApply;
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import specialties from "@/data/specialties.json";
|
||||||
|
import Form from "./form";
|
||||||
|
|
||||||
|
function Content({ filter, setFilter, updateData, setDataInURL }) {
|
||||||
|
const changeSpecialty = (name, value) => {
|
||||||
|
const newFilter = { ...filter, [name]: value };
|
||||||
|
|
||||||
|
if (name === "category") {
|
||||||
|
const childrenList = specialties.filter((item) => item.parent);
|
||||||
|
const filteredChildrenList = childrenList.filter(
|
||||||
|
(item) => item.parent === value.id
|
||||||
|
);
|
||||||
|
const firstChildren = filteredChildrenList[0];
|
||||||
|
|
||||||
|
newFilter.specialty = firstChildren || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
setFilter(newFilter);
|
||||||
|
setDataInURL(newFilter);
|
||||||
|
return newFilter;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mt-[50px] px-[0px] md:px-[19px] lg:px-[38px] mb-[32px]">
|
||||||
|
<Form
|
||||||
|
filter={filter}
|
||||||
|
updateData={updateData}
|
||||||
|
changeSpecialty={changeSpecialty}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Content;
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import CloseOrangeModal from "@/components/icons/CloseOrangeModal";
|
||||||
|
import { Button, CircularProgress } from "@mui/material";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { clearFilterParams } from "@/helper";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
function DeleteAllButton({ filter, sendReq, setFilter, handleClose }) {
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const resetFilter = () => {
|
||||||
|
setLoading(true);
|
||||||
|
clearFilterParams(router, [
|
||||||
|
"category",
|
||||||
|
"specialty",
|
||||||
|
"active",
|
||||||
|
"gender",
|
||||||
|
"degree",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const newFilter = {
|
||||||
|
...filter,
|
||||||
|
...{
|
||||||
|
category: undefined,
|
||||||
|
specialty: undefined,
|
||||||
|
active: 0,
|
||||||
|
gender: "هر دو",
|
||||||
|
degree: "همه موارد",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
sendReq(newFilter).finally(() => {
|
||||||
|
setLoading(false);
|
||||||
|
handleClose();
|
||||||
|
setFilter(newFilter);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex justify-between w-full">
|
||||||
|
<p className="text-[#3B3B3B] text-[20px] font-bold">فیلترها</p>
|
||||||
|
<Button
|
||||||
|
variant="text"
|
||||||
|
disabled={loading}
|
||||||
|
onClick={resetFilter}
|
||||||
|
className="cursor-pointer !py-0 !px-2 flex items-center justify-center gap-1"
|
||||||
|
>
|
||||||
|
{loading ? (
|
||||||
|
<CircularProgress className="!max-w-[17px] !max-h-[17px] !w-[17px] !h-[17px] !text-[#F17732]" />
|
||||||
|
) : (
|
||||||
|
<CloseOrangeModal />
|
||||||
|
)}
|
||||||
|
<p className="text-[#F17732] text-[14px] font-normal">حذف همه</p>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DeleteAllButton;
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { styleDefault } from "@/mui";
|
||||||
|
import { Modal } from "@mui/material";
|
||||||
|
import { useState } from "react";
|
||||||
|
import Content from "./Content";
|
||||||
|
import ButtonApply from "./ButtonApply";
|
||||||
|
import DeleteAllButton from "./DeleteAllButton";
|
||||||
|
|
||||||
|
function FilterModal({
|
||||||
|
filter,
|
||||||
|
sendReq,
|
||||||
|
children,
|
||||||
|
setFilter,
|
||||||
|
updateData,
|
||||||
|
setDataInURL,
|
||||||
|
}) {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
const handleOpen = () => setOpen(true);
|
||||||
|
const handleClose = () => {
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Button Modal */}
|
||||||
|
<div onClick={handleOpen}>{children}</div>
|
||||||
|
|
||||||
|
{/* Content Modal */}
|
||||||
|
<Modal open={open} onClose={handleClose} className="w-full">
|
||||||
|
<div
|
||||||
|
style={styleDefault}
|
||||||
|
className="!px-[16px] !overflow-auto md:!min-w-[580px] md:!px-[24px] lg:!px-[32px] !py-[24px] !bg-[#FFF] !rounded-[8px] !shadow-[0px_1px_24.8px_0px_rgba(204,_204,_204,_0.18)]
|
||||||
|
!w-full md:!w-fit !h-full md:!h-fit !flex !flex-col !justify-between !max-h-screen md:!max-h-[calc(100%_-_32px)]"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<DeleteAllButton
|
||||||
|
filter={filter}
|
||||||
|
sendReq={sendReq}
|
||||||
|
setFilter={setFilter}
|
||||||
|
handleClose={handleClose}
|
||||||
|
/>
|
||||||
|
<Content
|
||||||
|
filter={filter}
|
||||||
|
setFilter={setFilter}
|
||||||
|
updateData={updateData}
|
||||||
|
setDataInURL={setDataInURL}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ButtonApply sendReq={sendReq} setOpen={setOpen} />
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FilterModal;
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import BottomSelect from "@/components/icons/BottomSelect";
|
||||||
|
import { Autocomplete, Button, TextField } from "@mui/material";
|
||||||
|
import { styleTextSelectRight } from "@/mui";
|
||||||
|
|
||||||
|
function CateSelector({ name, list, value, isError, updateData, label }) {
|
||||||
|
return (
|
||||||
|
<Autocomplete
|
||||||
|
disablePortal
|
||||||
|
value={value || null}
|
||||||
|
options={list}
|
||||||
|
getOptionLabel={(option) => option?.name}
|
||||||
|
className="!w-full !rounded-lg auto-complete-selector"
|
||||||
|
onChange={(_, newValue) => updateData(name, newValue)}
|
||||||
|
sx={{
|
||||||
|
...styleTextSelectRight,
|
||||||
|
// Hide Icon Number
|
||||||
|
"& input::-webkit-outer-spin-button, & input::-webkit-inner-spin-button":
|
||||||
|
{
|
||||||
|
display: "none",
|
||||||
|
},
|
||||||
|
"& input[type=number]": {
|
||||||
|
MozAppearance: "textfield",
|
||||||
|
},
|
||||||
|
"& .MuiInputBase-input": { padding: "12.5px 14px !important" },
|
||||||
|
"& .MuiInputBase-root": {
|
||||||
|
borderRadius: 2,
|
||||||
|
padding: "0 !important",
|
||||||
|
height: {
|
||||||
|
xs: "43px !important",
|
||||||
|
sm: "43px !important",
|
||||||
|
md: "46px !important",
|
||||||
|
lg: "48px !important",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"& .MuiOutlinedInput-notchedOutline": {
|
||||||
|
border: "1px solid #D7D7D7",
|
||||||
|
},
|
||||||
|
"& .MuiInput-underline:hover:not(.Mui-disabled):before, .MuiOutlinedInput-notchedOutline":
|
||||||
|
{
|
||||||
|
borderColor: "#D7D7D7 !important",
|
||||||
|
},
|
||||||
|
"& .muirtl-1kiro5a-MuiInputBase-root-MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline":
|
||||||
|
{
|
||||||
|
border: "1px solid #5559CE !important",
|
||||||
|
},
|
||||||
|
"& .MuiOutlinedInput-notchedOutline": {
|
||||||
|
border: isError ? "1px solid red !important" : "",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
renderOption={(props, option) => (
|
||||||
|
<Button
|
||||||
|
fullWidth
|
||||||
|
{...props}
|
||||||
|
key={option.id || props.id}
|
||||||
|
className="!flex !justify-start !p-[8px] !text-start !text-[#A1A1A1] hover:dark:!bg-[#35343D] !bg-[#FFF] dark:!bg-[#1F1D2B]"
|
||||||
|
>
|
||||||
|
{option.name}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
{...params}
|
||||||
|
InputProps={{
|
||||||
|
...params.InputProps,
|
||||||
|
endAdornment: (
|
||||||
|
<div className="absolute left-4">
|
||||||
|
<BottomSelect />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
placeholder={label}
|
||||||
|
sx={{
|
||||||
|
borderRadius: "8px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CateSelector;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import Radios from "./Radios";
|
||||||
|
|
||||||
|
function RadioContent({ group, text, value, updateData, name }) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p className="text-[16px] font-medium text-[#3B3B3B]">{text}</p>
|
||||||
|
<div className="mt-[16px]">
|
||||||
|
<Radios
|
||||||
|
updateData={updateData}
|
||||||
|
group={group}
|
||||||
|
value={value}
|
||||||
|
name={name}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RadioContent;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { FormControlLabel, Radio, RadioGroup } from "@mui/material";
|
||||||
|
|
||||||
|
function Radios({ group, value, updateData, name }) {
|
||||||
|
return (
|
||||||
|
<RadioGroup
|
||||||
|
value={value}
|
||||||
|
className="radio-mui"
|
||||||
|
onChange={(e) => updateData(name, e.target.value)}
|
||||||
|
sx={{
|
||||||
|
"& .MuiFormControlLabel-root": {
|
||||||
|
marginRight: "0 !important",
|
||||||
|
transform: "translateX(9px)",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{group.map((item, idx) => (
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Radio className="!ml-2" />}
|
||||||
|
className="!text-[#525252]"
|
||||||
|
label={item}
|
||||||
|
value={item}
|
||||||
|
key={idx}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</RadioGroup>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Radios;
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { FormControlLabel, Switch } from "@mui/material";
|
||||||
|
|
||||||
|
function SwitchContent({ filter, updateData }) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-start gap-[12px]">
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
checked={filter.active}
|
||||||
|
onChange={(event) =>
|
||||||
|
updateData("active", event.target.checked ? 1 : 0)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
sx={{
|
||||||
|
".MuiFormControlLabel-label": {
|
||||||
|
color: "#3B3B3B",
|
||||||
|
fontSize: "16px",
|
||||||
|
fontWeight: 500,
|
||||||
|
},
|
||||||
|
marginLeft: "0 !important",
|
||||||
|
}}
|
||||||
|
label="فقط پزشکان دارای نوبت"
|
||||||
|
labelPlacement="start"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SwitchContent;
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import SwitchContent from "./SwitchContent";
|
||||||
|
import RadioContent from "./RadioContent";
|
||||||
|
import { filterList } from "@/helper";
|
||||||
|
import CateSelector from "./CateSelector";
|
||||||
|
|
||||||
|
const gender = ["زن", "مرد", "هر دو"];
|
||||||
|
const degree = ["پزشک عمومی", "پزشک متخصص", "پزشک فوق تخصص", "همه موارد"];
|
||||||
|
|
||||||
|
function Form({ filter, changeSpecialty, updateData }) {
|
||||||
|
const { parentList, childrenList } = filterList(filter);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CateSelector
|
||||||
|
name="category"
|
||||||
|
list={parentList}
|
||||||
|
label="دسته بندی"
|
||||||
|
value={filter.category}
|
||||||
|
updateData={changeSpecialty}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className={`${!!childrenList.length ? "max-h-32 mt-[24px]" : "max-h-0 mt-0"} overflow-hidden transition-all duration-500`}
|
||||||
|
>
|
||||||
|
<CateSelector
|
||||||
|
name="specialty"
|
||||||
|
list={childrenList}
|
||||||
|
updateData={updateData}
|
||||||
|
value={filter.specialty}
|
||||||
|
label="تخصص"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mt-[40px] mb-[32px]">
|
||||||
|
<RadioContent
|
||||||
|
updateData={updateData}
|
||||||
|
value={filter.gender}
|
||||||
|
text="جنسیت پزشک"
|
||||||
|
group={gender}
|
||||||
|
name="gender"
|
||||||
|
/>
|
||||||
|
<span className="block mt-[16px] mb-[24px] w-full h-px bg-[#EFEFEF]"></span>
|
||||||
|
<RadioContent
|
||||||
|
updateData={updateData}
|
||||||
|
value={filter.degree}
|
||||||
|
text="درجه علمی"
|
||||||
|
group={degree}
|
||||||
|
name="degree"
|
||||||
|
/>
|
||||||
|
<span className="block mt-[16px] mb-[24px] w-full h-px bg-[#EFEFEF]"></span>
|
||||||
|
<SwitchContent filter={filter} updateData={updateData} />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Form;
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
import { Autocomplete, TextField } from "@mui/material";
|
||||||
|
import { useRef, useState, useEffect } from "react";
|
||||||
|
|
||||||
|
function AutoComplete({
|
||||||
|
data,
|
||||||
|
noneBg,
|
||||||
|
clearText,
|
||||||
|
inputValue,
|
||||||
|
placeholder,
|
||||||
|
handleSearch,
|
||||||
|
setInputValue,
|
||||||
|
setSelectedOption,
|
||||||
|
debounce = 500,
|
||||||
|
}) {
|
||||||
|
const typingTimeoutRef = useRef(null);
|
||||||
|
const [localInput, setLocalInput] = useState(inputValue || "");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLocalInput(inputValue || "");
|
||||||
|
}, [inputValue]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (typingTimeoutRef.current) clearTimeout(typingTimeoutRef.current);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onInputChange = (_, newInputValue) => {
|
||||||
|
setLocalInput(newInputValue);
|
||||||
|
|
||||||
|
if (setInputValue) setInputValue(newInputValue);
|
||||||
|
|
||||||
|
if (typingTimeoutRef.current) clearTimeout(typingTimeoutRef.current);
|
||||||
|
typingTimeoutRef.current = setTimeout(() => {
|
||||||
|
handleSearch(newInputValue);
|
||||||
|
}, debounce);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChange = (_, newValue) => {
|
||||||
|
if (typingTimeoutRef.current) {
|
||||||
|
clearTimeout(typingTimeoutRef.current);
|
||||||
|
typingTimeoutRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const val = newValue
|
||||||
|
? typeof newValue === "string"
|
||||||
|
? newValue
|
||||||
|
: newValue.name
|
||||||
|
: "";
|
||||||
|
setLocalInput(val);
|
||||||
|
setSelectedOption && setSelectedOption(newValue);
|
||||||
|
handleSearch(val);
|
||||||
|
if (setInputValue) setInputValue(val);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Autocomplete
|
||||||
|
freeSolo
|
||||||
|
options={data}
|
||||||
|
getOptionLabel={(option) =>
|
||||||
|
typeof option === "string" ? option : option.name
|
||||||
|
}
|
||||||
|
disableClearable
|
||||||
|
inputValue={localInput}
|
||||||
|
className="!w-full"
|
||||||
|
onInputChange={onInputChange}
|
||||||
|
onChange={onChange}
|
||||||
|
renderOption={(props, option) => (
|
||||||
|
<li {...props} key={option.id}>
|
||||||
|
{option.name}
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
sx={{
|
||||||
|
"& .MuiAutocomplete-input": {
|
||||||
|
background: noneBg ? "" : "#ffffff !important",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
variant="standard"
|
||||||
|
placeholder={placeholder}
|
||||||
|
dir="rtl"
|
||||||
|
InputProps={{
|
||||||
|
...params.InputProps,
|
||||||
|
disableUnderline: true,
|
||||||
|
style: { height: "100%" },
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
background: "transparent !important",
|
||||||
|
"& .MuiInputBase-input": {
|
||||||
|
background: "#FAFAFA",
|
||||||
|
color: "#6C757D",
|
||||||
|
padding: "0 16px",
|
||||||
|
fontSize: "14px",
|
||||||
|
fontFamily: "inherit",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
className="!shadow-none !w-full !px-5 !h-full !text-[14px] md:!text-[16px] !min-w-[50%] !rounded-0 !font-normal"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AutoComplete;
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import { clearFilterParams } from "@/helper";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import specialties from "@/data/specialties.json";
|
||||||
|
import AutoComplete from "./AutoComplete";
|
||||||
|
|
||||||
|
function SearchField({ filter, setFilter, setDataInURL }) {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const clearText = () => {
|
||||||
|
clearFilterParams(router, ["name", "category", "specialty"]);
|
||||||
|
const newFilter = {
|
||||||
|
...filter,
|
||||||
|
...{
|
||||||
|
name: "",
|
||||||
|
category: undefined,
|
||||||
|
specialty: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
setFilter(newFilter);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = (e) => {
|
||||||
|
const findName = specialties.find((item) => item.name === e);
|
||||||
|
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 = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="!min-w-[50%] !w-full">
|
||||||
|
<AutoComplete
|
||||||
|
data={specialties}
|
||||||
|
clearText={clearText}
|
||||||
|
inputValue={filter.name}
|
||||||
|
handleSearch={handleSearch}
|
||||||
|
placeholder="جستجوی نام پزشک، تخصص، بیماری ..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SearchField;
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { Button } from "@mui/material";
|
||||||
|
import SearchD from "@/components/icons/SearchD";
|
||||||
|
import { useState } from "react";
|
||||||
|
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 = () => {
|
||||||
|
setLoading(false);
|
||||||
|
|
||||||
|
// setLoading(true);
|
||||||
|
// // const newFilter = checkName();
|
||||||
|
// // setFilter(filter);
|
||||||
|
// // setDataInURL(filter);
|
||||||
|
|
||||||
|
// sendReq(filter).finally(() => {
|
||||||
|
// setLoading(false);
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
loading={loading}
|
||||||
|
onClick={filterData}
|
||||||
|
className="!flex !m-1 !rounded-[4px] !w-[36px] sm:!w-[42px] md:!w-[49px] lg:!w-[56px] !min-w-[36px] sm:!min-w-[42px] md:!min-w-[49px] lg:!min-w-[56px]
|
||||||
|
!gap-2.5 !p-2.5 md:!p-4 !h-[calc(100%_-_8px)]"
|
||||||
|
>
|
||||||
|
<div className="w-[24px] h-[24px] min-w-[24px] min-h-[24px]">
|
||||||
|
{!loading && <SearchD />}
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SendReq;
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { Button, ButtonGroup } from "@mui/material";
|
||||||
|
import SettingD from "@/components/icons/SettingD";
|
||||||
|
import ArrowBottomD from "@/components/icons/ArrowBottomD";
|
||||||
|
import SendReq from "./SendReq";
|
||||||
|
import SearchField from "./SearchField";
|
||||||
|
import FilterModal from "../modal/FilterModal";
|
||||||
|
|
||||||
|
function SearchBar({ filter, sendReq, setFilter, updateData, setDataInURL }) {
|
||||||
|
return (
|
||||||
|
<ButtonGroup
|
||||||
|
variant="contained"
|
||||||
|
className="!bg-[#FFF] !w-full lg:!w-[60%] lg:!max-w-[734px] !rounded-lg !overflow-hidden
|
||||||
|
flex items-center !shadow-[0px_1px_24.8px_0px_rgba(204,_204,_204,_0.18)]
|
||||||
|
!h-[44px] sm:!h-[50px] md:!h-[57px] lg:!h-[64px]"
|
||||||
|
>
|
||||||
|
<FilterModal
|
||||||
|
filter={filter}
|
||||||
|
sendReq={sendReq}
|
||||||
|
setFilter={setFilter}
|
||||||
|
updateData={updateData}
|
||||||
|
setDataInURL={setDataInURL}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
color="secondary"
|
||||||
|
variant="contained"
|
||||||
|
className="!border-none !hidden lg:!flex !max-h-full !min-w-fit !h-[64px] !px-2 !bg-[#F8F8FF] !rounded-l-none"
|
||||||
|
>
|
||||||
|
<div className="min-w-[20px] min-h-[20px]">
|
||||||
|
<SettingD />
|
||||||
|
</div>
|
||||||
|
<p className="text-[#616161] text-[14px] md:text-[16px] font-medium mx-2">
|
||||||
|
فیلترها
|
||||||
|
</p>
|
||||||
|
<div className="w-[20px] md:w-[22px] lg:w-[24px] h-[20px] md:h-[22px] lg:h-[24px]">
|
||||||
|
<ArrowBottomD />
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
</FilterModal>
|
||||||
|
<SearchField
|
||||||
|
filter={filter}
|
||||||
|
setFilter={setFilter}
|
||||||
|
setDataInURL={setDataInURL}
|
||||||
|
/>
|
||||||
|
<SendReq
|
||||||
|
filter={filter}
|
||||||
|
sendReq={sendReq}
|
||||||
|
setFilter={setFilter}
|
||||||
|
setDataInURL={setDataInURL}
|
||||||
|
/>
|
||||||
|
</ButtonGroup>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SearchBar;
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import ArrowBottomD from "@/components/icons/ArrowBottomD";
|
||||||
|
import SettingD from "@/components/icons/SettingD";
|
||||||
|
import { Button } from "@mui/material";
|
||||||
|
|
||||||
|
function FilterBtn() {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
className="!flex lg:!hidden !h-[44px] sm:!h-[50px] md:!h-[57px] lg:!h-[64px] !p-2.5 !bg-transparent !shadow-none !border !border-solid !border-[#EFEFEF]"
|
||||||
|
variant="contained"
|
||||||
|
color="secondary"
|
||||||
|
>
|
||||||
|
<div className="min-w-[20px] min-h-[20px]">
|
||||||
|
<SettingD />
|
||||||
|
</div>
|
||||||
|
<p className="text-[#616161] text-[14px] md:text-[16px] font-medium mx-2">
|
||||||
|
فیلترها
|
||||||
|
</p>
|
||||||
|
<div className="w-[20px] md:w-[22px] lg:w-[24px] h-[20px] md:h-[22px] lg:h-[24px]">
|
||||||
|
<ArrowBottomD />
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FilterBtn;
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import { MenuItem, Select, SvgIcon } from "@mui/material";
|
||||||
|
import SortD from "@/components/icons/SortD";
|
||||||
|
import StarDI from "@/components/icons/StarDI";
|
||||||
|
import ArrowBottomD from "@/components/icons/ArrowBottomD";
|
||||||
|
|
||||||
|
const listSort = [
|
||||||
|
{ label: 3, id: 3 },
|
||||||
|
{ label: 4, id: 4 },
|
||||||
|
{ label: 5, id: 5 },
|
||||||
|
];
|
||||||
|
|
||||||
|
function SelectSort({ filter, updateData }) {
|
||||||
|
const handleClick = (e) => {
|
||||||
|
updateData("sort", Number(e.target.value), true);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
displayEmpty
|
||||||
|
value={filter.sort}
|
||||||
|
onChange={handleClick}
|
||||||
|
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) => {
|
||||||
|
return (
|
||||||
|
<div className="w-[20px] flex gap-[4px] md:gap-[8px] md:w-[22px] lg:w-[24px] h-[20px] md:h-[22px] lg:h-[24px]">
|
||||||
|
<SvgIcon color="primary">
|
||||||
|
<SortD />
|
||||||
|
</SvgIcon>
|
||||||
|
{value ? (
|
||||||
|
<ul className="flex items-center justify-start gap-1">
|
||||||
|
{Array(filter.sort)
|
||||||
|
.fill({})
|
||||||
|
.map((_, idx) => (
|
||||||
|
<li key={idx}>
|
||||||
|
<StarDI />
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
) : (
|
||||||
|
"مرتب سازی"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
IconComponent={() => (
|
||||||
|
<div
|
||||||
|
className="mx-3
|
||||||
|
min-w-[20px] md:min-w-[22px] lg:min-w-[24px] min-h-[20px] md:min-h-[22px] lg:min-h-[24px]
|
||||||
|
max-w-[20px] md:max-w-[22px] lg:max-w-[24px] max-h-[20px] md:max-h-[22px] lg:max-h-[24px]
|
||||||
|
w-[20px] md:w-[22px] lg:w-[24px] h-[20px] md:h-[22px] lg:h-[24px]
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<ArrowBottomD />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
sx={{
|
||||||
|
"& .MuiSelect-select ": {
|
||||||
|
paddingRight: "12px !important",
|
||||||
|
},
|
||||||
|
"& .MuiOutlinedInput-notchedOutline ": {
|
||||||
|
borderColor: "#EFEFEF !important",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{listSort.map((item, idx) => (
|
||||||
|
<MenuItem
|
||||||
|
key={idx}
|
||||||
|
value={item.label}
|
||||||
|
name={item.label}
|
||||||
|
className="!flex !flex-col !items-start !w-full hover:!bg-transparent"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
value={item.id}
|
||||||
|
className="!p-2 !mr-2 !w-[calc(100%_-_16px)] flex items-center justify-start"
|
||||||
|
>
|
||||||
|
{Array(item.label)
|
||||||
|
.fill({})
|
||||||
|
.map((_, idx) => (
|
||||||
|
<StarDI key={idx} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SelectSort;
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import FilterModal from "../modal/FilterModal";
|
||||||
|
import FilterBtn from "./FilterBtn";
|
||||||
|
import SelectSort from "./SelectSort";
|
||||||
|
|
||||||
|
function SortList({ filter, sendReq, setFilter, updateData, setDataInURL }) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-wrap items-center lg:!w-[25%] gap-[20px] gap-y-[12px] lg:gap-0">
|
||||||
|
<FilterModal
|
||||||
|
filter={filter}
|
||||||
|
sendReq={sendReq}
|
||||||
|
setFilter={setFilter}
|
||||||
|
updateData={updateData}
|
||||||
|
setDataInURL={setDataInURL}
|
||||||
|
>
|
||||||
|
<FilterBtn />
|
||||||
|
</FilterModal>
|
||||||
|
<SelectSort filter={filter} updateData={updateData} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SortList;
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import SmSearch from "@/components/searchHead/smSearch";
|
|
||||||
import List from "./List";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { searchOnList } from "@/helper";
|
import { searchOnList } from "@/helper";
|
||||||
|
import { useState } from "react";
|
||||||
|
import List from "./List";
|
||||||
|
import Head from "./head";
|
||||||
|
|
||||||
function Doctors({ doctors }) {
|
function Doctors({ doctors }) {
|
||||||
const [filteredSpecialties, setFilteredSpecialties] = useState(doctors);
|
const [filteredSpecialties, setFilteredSpecialties] = useState(doctors);
|
||||||
@@ -13,13 +13,15 @@ function Doctors({ doctors }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="opacity-page">
|
<div className="opacity-page">
|
||||||
<div className="flex justify-center">
|
{/* <div className="flex justify-center">
|
||||||
<SmSearch
|
<SmSearch
|
||||||
data={doctors}
|
data={doctors}
|
||||||
handleSearch={handleSearch}
|
handleSearch={handleSearch}
|
||||||
placeholder="جستجوی پزشک یا تخصص"
|
placeholder="جستجوی پزشک یا تخصص"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
|
<Head />
|
||||||
<List doctors={filteredSpecialties} />
|
<List doctors={filteredSpecialties} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import Tabs from "@/app/component/Tabs";
|
|||||||
const listTab = ["درباره کلینیک", "اطلاعات تماس", "پزشک ها"];
|
const listTab = ["درباره کلینیک", "اطلاعات تماس", "پزشک ها"];
|
||||||
|
|
||||||
function ClinicPage({ data, doctors }) {
|
function ClinicPage({ data, doctors }) {
|
||||||
const [value, setValue] = useState(0);
|
const [value, setValue] = useState(2);
|
||||||
const handleChange = (event, newValue) => setValue(newValue);
|
const handleChange = (_, newValue) => setValue(newValue);
|
||||||
|
|
||||||
const Components = [
|
const Components = [
|
||||||
<About data={data} />,
|
<About data={data} />,
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ function Share({ data }) {
|
|||||||
<Box
|
<Box
|
||||||
sx={styleDefault}
|
sx={styleDefault}
|
||||||
className="!pt-[12px] md:!pt-[14px] lg:!py-[16px] !overflow-hidden
|
className="!pt-[12px] md:!pt-[14px] lg:!py-[16px] !overflow-hidden
|
||||||
!px-[12px] sm:!px-[16px] md:!px-[20px] lg:!px-[24px]
|
!px-[12px] sm:!px-[16px] md:!px-[20px] lg:!px-[24px]
|
||||||
!pb-[12px] sm:!pb-[16px] lg:!pb-[20px] !rounded-[8px]"
|
!pb-[12px] sm:!pb-[16px] lg:!pb-[20px] !rounded-[8px]"
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between w-full">
|
<div className="flex items-center justify-between w-full">
|
||||||
<p className="text-[#3B3B3B] text-[14px] sm:text-[16px] md:text-[18px] lg:text-[20px] font-medium">
|
<p className="text-[#3B3B3B] text-[14px] sm:text-[16px] md:text-[18px] lg:text-[20px] font-medium">
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ function Comments({ doctor, comments }) {
|
|||||||
<ModalAnswer doctor={doctor} />
|
<ModalAnswer doctor={doctor} />
|
||||||
</div>
|
</div>
|
||||||
<Chart comments={comments} doctor={doctor} />
|
<Chart comments={comments} doctor={doctor} />
|
||||||
<Comment data={doctor} comments={comments} />
|
<Comment comments={comments} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,12 +41,9 @@ function ModalAnswer({ doctor }) {
|
|||||||
rate: newRate,
|
rate: newRate,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const data = res.response?.data;
|
|
||||||
// setComment();
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch(() => {
|
||||||
const data = err.response?.data;
|
//
|
||||||
// setComment();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
@@ -1,45 +1,70 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import Field from "@/app/component/fields/Field";
|
import Field from "@/app/component/fields/Field";
|
||||||
import { Button } from "@mui/material";
|
import { Button } from "@mui/material";
|
||||||
import { request } from "@/services/response";
|
import { request } from "@/services/response";
|
||||||
import ArrowLeftD from "@/components/icons/ArrowLeftD";
|
import ArrowLeftD from "@/components/icons/ArrowLeftD";
|
||||||
|
|
||||||
function Form({ doctor, changeData, setOpen, comment, loading, setLoading }) {
|
function Form({
|
||||||
console.log(comment.rate);
|
doctor,
|
||||||
|
setOpen,
|
||||||
|
comment,
|
||||||
|
loading,
|
||||||
|
changeData,
|
||||||
|
setComment,
|
||||||
|
setLoading,
|
||||||
|
}) {
|
||||||
|
const [isError, setIsError] = useState(false);
|
||||||
|
|
||||||
const sendReq = () => {
|
const sendReq = () => {
|
||||||
setLoading(true);
|
if (comment?.detail?.comment) {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
request
|
request
|
||||||
.postDoctorComment(comment.detail)
|
.postDoctorComment(comment.detail)
|
||||||
.then((res) => {
|
.then(() => {
|
||||||
let newComment = comment.rate;
|
let newComment = comment.rate;
|
||||||
newComment = {
|
newComment = {
|
||||||
doctor_id: doctor?.id,
|
doctor_id: doctor?.id,
|
||||||
accuracy_of_diagnosis: newComment[1].progress,
|
accuracy_of_diagnosis: newComment[1].progress,
|
||||||
doctor_expertise: newComment[4].progress,
|
doctor_expertise: newComment[4].progress,
|
||||||
doctor_behavior: newComment[2].progress,
|
doctor_behavior: newComment[2].progress,
|
||||||
clinic_cleanliness: newComment[3].progress,
|
clinic_cleanliness: newComment[3].progress,
|
||||||
waiting_time_at_clinic: newComment[0].progress,
|
waiting_time_at_clinic: newComment[0].progress,
|
||||||
};
|
};
|
||||||
|
setComment({
|
||||||
request[comment.defaultRate ? "patchDoctorRate" : "postDoctorRate"](
|
...comment,
|
||||||
newComment,
|
detail: {
|
||||||
comment.uuid
|
...comment.detail,
|
||||||
)
|
comment: "",
|
||||||
.then((res) => {
|
},
|
||||||
setLoading(false);
|
|
||||||
setOpen(false);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
setLoading(false);
|
|
||||||
setOpen(false);
|
|
||||||
});
|
});
|
||||||
})
|
|
||||||
.catch((err) => {
|
request[comment.defaultRate ? "patchDoctorRate" : "postDoctorRate"](
|
||||||
setLoading(false);
|
newComment,
|
||||||
setOpen(false);
|
comment.uuid
|
||||||
});
|
)
|
||||||
|
.then(() => {
|
||||||
|
setLoading(false);
|
||||||
|
setOpen(false);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLoading(false);
|
||||||
|
setOpen(false);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLoading(false);
|
||||||
|
setOpen(false);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setIsError(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (_, val) => {
|
||||||
|
if (val && isError) setIsError(false);
|
||||||
|
else if (!val && !isError) setIsError(true);
|
||||||
|
changeData("detail", "comment", val);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -47,8 +72,9 @@ function Form({ doctor, changeData, setOpen, comment, loading, setLoading }) {
|
|||||||
<p className="text-[#495057] text-[16px] font-bold">متن نظر</p>
|
<p className="text-[#495057] text-[16px] font-bold">متن نظر</p>
|
||||||
<Field
|
<Field
|
||||||
type="number"
|
type="number"
|
||||||
|
error={isError}
|
||||||
multiline={true}
|
multiline={true}
|
||||||
handleChange={(_, val) => changeData("detail", "comment", val)}
|
handleChange={handleChange}
|
||||||
title="نظر خود را بنویسید..."
|
title="نظر خود را بنویسید..."
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ function Content({
|
|||||||
comment={comment}
|
comment={comment}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
setOpen={setOpen}
|
setOpen={setOpen}
|
||||||
|
setComment={setComment}
|
||||||
changeData={changeData}
|
changeData={changeData}
|
||||||
setLoading={setLoading}
|
setLoading={setLoading}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ function Poster({ data }) {
|
|||||||
<div>
|
<div>
|
||||||
<div className="flex items-center justify-start gap-[5px]">
|
<div className="flex items-center justify-start gap-[5px]">
|
||||||
<Image src={Logo} width={30} height={30} alt="logo" />
|
<Image src={Logo} width={30} height={30} alt="logo" />
|
||||||
<p className="text-[#E7EEF6] text-[16px] font-bold">nobat724.com</p>
|
<p className="text-[#E7EEF6] text-[16px] font-bold !-translate-y-1">
|
||||||
|
nobat724.com
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-[40px] text-[#E7EEF6] text-[20px] font-bold text-right">
|
<p className="mt-[40px] text-[#E7EEF6] text-[20px] font-bold text-right">
|
||||||
{data?.name}
|
{data?.name}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name": "clinic_cleanliness",
|
"name": "waiting_time_at_clinic",
|
||||||
"label": "زمان انتظار در مطب",
|
"label": "زمان انتظار در مطب",
|
||||||
"progress": 70
|
"progress": 70
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export function getStateInfoClient() {
|
|||||||
if (typeof window === "undefined")
|
if (typeof window === "undefined")
|
||||||
return { matchedCity: null, matchedState: null, fullUrl: "" };
|
return { matchedCity: null, matchedState: null, fullUrl: "" };
|
||||||
|
|
||||||
const fullUrl = window.location.href; // کل URL
|
const fullUrl = window.location.href;
|
||||||
const host = window.location.host || "";
|
const host = window.location.host || "";
|
||||||
const subdomain = host.split(".")[0];
|
const subdomain = host.split(".")[0];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user