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:
ehsan
2025-10-06 01:13:55 +03:30
parent 0b90e1abc4
commit e6893846bd
35 changed files with 1097 additions and 95 deletions
+7 -7
View File
@@ -13,13 +13,13 @@ import PointD from "@/components/icons/PointD";
function ItemDoctor({ doctor, loading, setDoctors }) {
const handleLoading = () => {
setDoctors((prevDoctors) =>
prevDoctors.map((item) =>
item.id === doctor.id
? { ...item, loading: true }
: { ...item, loading: false }
)
);
// setDoctors((prevDoctors) =>
// prevDoctors.map((item) =>
// item.id === doctor.id
// ? { ...item, loading: true }
// : { ...item, loading: false }
// )
// );
};
return (
+1 -2
View File
@@ -2,8 +2,7 @@
import { useState } from "react";
import ItemUser from "./ItemUser";
function Comment({ data, comments }) {
const [list, setList] = useState(data?.comments);
function Comment({ comments }) {
const [update, setUpdate] = useState(false);
return (
+4 -1
View File
@@ -3,6 +3,7 @@ import { TextField } from "@mui/material";
function Field({
type,
name,
error,
title,
props,
value,
@@ -31,7 +32,9 @@ function Field({
"& .MuiInputBase-input": { padding: "12.5px 14px" },
"& .MuiInputBase-root": { borderRadius: "6px !important" },
"& .MuiOutlinedInput-notchedOutline": {
border: "1px solid #E9ECEF !important",
border: error
? "1px solid red !important"
: "1px solid #E9ECEF !important",
},
".Mui-focused": {
"& .MuiOutlinedInput-notchedOutline": {
+8 -6
View File
@@ -2,33 +2,35 @@ import CloseModalD from "@/components/icons/CloseModalD";
import Image from "next/image";
function Content({ data, onClose }) {
console.log(data);
const { latitude, longitude } = data && data.map;
const maps = [
{
src: "/assets/images/snapp.png",
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",
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",
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",
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",
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}
width={40}
/>
<p className="text-[#3B3B3B] font-normal text-[14px]">
<p className="text-[#3B3B3B] text-center font-normal text-[14px]">
{item.name}
</p>
</a>
+2
View File
@@ -5,6 +5,8 @@ import { styleDefault } from "@/mui";
import Content from "./Content";
function ModalOpenLocation({ open, data, setOpen, handleClose, children }) {
console.log(data);
const toggleDrawer = (newOpen) => () => {
setOpen(newOpen);
};
+57 -17
View File
@@ -1,55 +1,95 @@
"use client";
import CustomLoading from "@/app/component/loading/Custom";
import ArrowLeftList from "@/components/icons/ArrowLeftList";
import { Button } from "@mui/material";
import Image from "next/image";
import { useRef } from "react";
import { useRef, useEffect, useState } from "react";
function ListBime({ data }) {
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) => {
if (!list.current) return;
list.current.scrollBy({
left: type === "left" ? -200 : 200,
left: type === "left" ? -itemWidth : itemWidth,
behavior: "smooth",
});
};
return (
<div className="w-full relative">
<Button
variant="outlined"
onClick={() => handleScroll("right")}
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"
>
<ArrowLeftList />
</Button>
<div className="relative w-[calc(100%_-_48px)] mx-auto">
{showArrows && (
<Button
variant="outlined"
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>
)}
<ul
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) => (
<CustomLoading key={idx} width={156} height={110}>
<li className="p-[16px] min-w-[156px] w-full border border-[#EFEFEF] flex flex-col items-center justify-center gap-[20px]">
<CustomLoading key={idx} width={itemWidth} height={110}>
<li
className="p-[16px] border border-[#EFEFEF] h-[175px] flex flex-col items-center justify-center gap-[20px]"
style={{ minWidth: itemWidth }}
>
<Image
src={item.logo && item.logo[0]?.url || ""}
src={item.logo?.[0]?.url || ""}
height={92}
width={92}
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}
</h3>
</li>
</CustomLoading>
))}
</ul>
{showArrows && (
<Button
variant="outlined"
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 />
</Button>
</ul>
)}
</div>
);
}
@@ -7,10 +7,7 @@ function Detail({ data }) {
head="روزهای کاری: "
detail={`ساعت کاری: ${data.hours_of_work}`}
/>
<ContentDetail
head="تلفن: "
detail={`${data.phone_number_1} ${data.phone_number_2}`}
/>
<ContentDetail head="تلفن: " detail={`${data.phone_number}`} />
<ContentDetail head="ایمیل:" detail={data.email} />
<ContentDetail head="آدرس: " detail={data.location} />
</ul>
@@ -15,14 +15,15 @@ function Contact({ data }) {
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]
"
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
data={data}
open={open}
setOpen={setOpen}
handleClose={handleClose}
@@ -40,11 +41,12 @@ function Contact({ data }) {
<div className="w-full relative h-[460px] mt-[24px]">
<CustomLoading width="full" height={400}>
<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"
loading="lazy"
></iframe>
<ModalOpenLocation
data={data}
open={open}
setOpen={setOpen}
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";
import SmSearch from "@/components/searchHead/smSearch";
import List from "./List";
import { useState } from "react";
import { searchOnList } from "@/helper";
import { useState } from "react";
import List from "./List";
import Head from "./head";
function Doctors({ doctors }) {
const [filteredSpecialties, setFilteredSpecialties] = useState(doctors);
@@ -13,13 +13,15 @@ function Doctors({ doctors }) {
return (
<div className="opacity-page">
<div className="flex justify-center">
{/* <div className="flex justify-center">
<SmSearch
data={doctors}
handleSearch={handleSearch}
placeholder="جستجوی پزشک یا تخصص"
/>
</div>
</div> */}
<Head />
<List doctors={filteredSpecialties} />
</div>
);
+2 -2
View File
@@ -10,8 +10,8 @@ import Tabs from "@/app/component/Tabs";
const listTab = ["درباره کلینیک", "اطلاعات تماس", "پزشک ها"];
function ClinicPage({ data, doctors }) {
const [value, setValue] = useState(0);
const handleChange = (event, newValue) => setValue(newValue);
const [value, setValue] = useState(2);
const handleChange = (_, newValue) => setValue(newValue);
const Components = [
<About data={data} />,
+2 -2
View File
@@ -34,8 +34,8 @@ function Share({ data }) {
<Box
sx={styleDefault}
className="!pt-[12px] md:!pt-[14px] lg:!py-[16px] !overflow-hidden
!px-[12px] sm:!px-[16px] md:!px-[20px] lg:!px-[24px]
!pb-[12px] sm:!pb-[16px] lg:!pb-[20px] !rounded-[8px]"
!px-[12px] sm:!px-[16px] md:!px-[20px] lg:!px-[24px]
!pb-[12px] sm:!pb-[16px] lg:!pb-[20px] !rounded-[8px]"
>
<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">
@@ -21,7 +21,7 @@ function Comments({ doctor, comments }) {
<ModalAnswer doctor={doctor} />
</div>
<Chart comments={comments} doctor={doctor} />
<Comment data={doctor} comments={comments} />
<Comment comments={comments} />
</div>
);
}
@@ -41,12 +41,9 @@ function ModalAnswer({ doctor }) {
rate: newRate,
});
}
const data = res.response?.data;
// setComment();
})
.catch((err) => {
const data = err.response?.data;
// setComment();
.catch(() => {
//
});
}
}, []);
@@ -1,45 +1,70 @@
import React from "react";
import React, { useState } from "react";
import Field from "@/app/component/fields/Field";
import { Button } from "@mui/material";
import { request } from "@/services/response";
import ArrowLeftD from "@/components/icons/ArrowLeftD";
function Form({ doctor, changeData, setOpen, comment, loading, setLoading }) {
console.log(comment.rate);
function Form({
doctor,
setOpen,
comment,
loading,
changeData,
setComment,
setLoading,
}) {
const [isError, setIsError] = useState(false);
const sendReq = () => {
setLoading(true);
if (comment?.detail?.comment) {
setLoading(true);
request
.postDoctorComment(comment.detail)
.then((res) => {
let newComment = comment.rate;
newComment = {
doctor_id: doctor?.id,
accuracy_of_diagnosis: newComment[1].progress,
doctor_expertise: newComment[4].progress,
doctor_behavior: newComment[2].progress,
clinic_cleanliness: newComment[3].progress,
waiting_time_at_clinic: newComment[0].progress,
};
request[comment.defaultRate ? "patchDoctorRate" : "postDoctorRate"](
newComment,
comment.uuid
)
.then((res) => {
setLoading(false);
setOpen(false);
})
.catch((err) => {
setLoading(false);
setOpen(false);
request
.postDoctorComment(comment.detail)
.then(() => {
let newComment = comment.rate;
newComment = {
doctor_id: doctor?.id,
accuracy_of_diagnosis: newComment[1].progress,
doctor_expertise: newComment[4].progress,
doctor_behavior: newComment[2].progress,
clinic_cleanliness: newComment[3].progress,
waiting_time_at_clinic: newComment[0].progress,
};
setComment({
...comment,
detail: {
...comment.detail,
comment: "",
},
});
})
.catch((err) => {
setLoading(false);
setOpen(false);
});
request[comment.defaultRate ? "patchDoctorRate" : "postDoctorRate"](
newComment,
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 (
@@ -47,8 +72,9 @@ function Form({ doctor, changeData, setOpen, comment, loading, setLoading }) {
<p className="text-[#495057] text-[16px] font-bold">متن نظر</p>
<Field
type="number"
error={isError}
multiline={true}
handleChange={(_, val) => changeData("detail", "comment", val)}
handleChange={handleChange}
title="نظر خود را بنویسید..."
/>
<Button
@@ -63,6 +63,7 @@ function Content({
comment={comment}
loading={loading}
setOpen={setOpen}
setComment={setComment}
changeData={changeData}
setLoading={setLoading}
/>
+3 -1
View File
@@ -12,7 +12,9 @@ function Poster({ data }) {
<div>
<div className="flex items-center justify-start gap-[5px]">
<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>
<p className="mt-[40px] text-[#E7EEF6] text-[20px] font-bold text-right">
{data?.name}
+1 -1
View File
@@ -1,6 +1,6 @@
[
{
"name": "clinic_cleanliness",
"name": "waiting_time_at_clinic",
"label": "زمان انتظار در مطب",
"progress": 70
},
+1 -1
View File
@@ -6,7 +6,7 @@ export function getStateInfoClient() {
if (typeof window === "undefined")
return { matchedCity: null, matchedState: null, fullUrl: "" };
const fullUrl = window.location.href; // کل URL
const fullUrl = window.location.href;
const host = window.location.host || "";
const subdomain = host.split(".")[0];