add first open time for appo item and change component data, remove work time in location, add loading on links in page doctor list, fix bug search city and state in clinics page
This commit is contained in:
@@ -11,10 +11,22 @@ import CustomLoading from "./loading/Custom";
|
||||
import TextLoading from "./loading/Text";
|
||||
import CircularLoading from "./loading/Circular";
|
||||
import moment from "moment-jalaali";
|
||||
import { useState } from "react";
|
||||
|
||||
moment.loadPersian({ dialect: "persian-modern" });
|
||||
|
||||
function ItemDoctor({ doctor }) {
|
||||
function ItemDoctor({ doctor, doctors, setDoctors }) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const handleLoading = () => {
|
||||
setDoctors((prevDoctors) =>
|
||||
prevDoctors.map((item) =>
|
||||
item.id === doctor.id
|
||||
? { ...item, loading: true }
|
||||
: { ...item, loading: false }
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<li className="p-4 relative rounded-lg bg-[#FFF] border border-[#EFEFEF]">
|
||||
{/* Detail Doctor */}
|
||||
@@ -93,9 +105,13 @@ function ItemDoctor({ doctor }) {
|
||||
<Link href={`/doctor/${doctor?.uuid}`}>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleLoading}
|
||||
loading={doctor?.loading}
|
||||
className="!p-[14px] !absolute !left-4 !bottom-4 !rounded-full !w-fit"
|
||||
>
|
||||
<ArrowLeftD />
|
||||
<div className={doctor && doctor.loading ? "opacity-0" : ""}>
|
||||
<ArrowLeftD />
|
||||
</div>
|
||||
</Button>
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
@@ -60,16 +60,16 @@ function Content({
|
||||
list={states}
|
||||
label="استان"
|
||||
disabled={matchedState}
|
||||
value={filter.state}
|
||||
value={filter?.state}
|
||||
updateData={updateData}
|
||||
/>
|
||||
<AddressSelector
|
||||
name="city"
|
||||
label="شهر"
|
||||
value={filter.city}
|
||||
value={filter?.city}
|
||||
list={filteredCities}
|
||||
updateData={updateData}
|
||||
disabled={!filter.state}
|
||||
disabled={!filter?.state}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full flex justify-end">
|
||||
@@ -79,7 +79,7 @@ function Content({
|
||||
onClick={handleClick}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={!filter.city || !filter.state}
|
||||
disabled={!filter?.city || !filter?.state}
|
||||
>
|
||||
تایید و ادامه
|
||||
<ArrowLeftM />
|
||||
|
||||
@@ -1,22 +1,44 @@
|
||||
import CloseModalD from "@/components/icons/CloseModalD";
|
||||
import Image from "next/image";
|
||||
|
||||
const maps = [
|
||||
{ src: "/assets/images/snapp.png", name: "snapp" },
|
||||
{ src: "/assets/images/tapsi.png", name: "tapsi" },
|
||||
{ src: "/assets/images/maps.png", name: "maps" },
|
||||
{ src: "/assets/images/balad.png", name: "balad" },
|
||||
{ src: "/assets/images/waze.png", name: "waze" },
|
||||
];
|
||||
function Content({ data, onClose }) {
|
||||
const { latitude, longitude } = data && data.map;
|
||||
|
||||
const maps = [
|
||||
{
|
||||
src: "/assets/images/snapp.png",
|
||||
name: "snapp",
|
||||
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}`,
|
||||
},
|
||||
{
|
||||
src: "/assets/images/maps.png",
|
||||
name: "maps",
|
||||
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}`,
|
||||
},
|
||||
{
|
||||
src: "/assets/images/waze.png",
|
||||
name: "waze",
|
||||
url: `https://waze.com/ul?ll=${latitude},${longitude}&navigate=yes`,
|
||||
},
|
||||
];
|
||||
|
||||
function Content({ handleClose }) {
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-[#3B3B3B] text-[14px] sm:text-[16px] md:text-[18px] lg:text-[20px] font-medium">
|
||||
باز شدن با
|
||||
</p>
|
||||
<div className="cursor-pointer" onClick={handleClose}>
|
||||
<div className="cursor-pointer" onClick={onClose}>
|
||||
<CloseModalD />
|
||||
</div>
|
||||
</div>
|
||||
@@ -27,20 +49,22 @@ function Content({ handleClose }) {
|
||||
key={idx}
|
||||
className="flex items-center flex-col justify-center gap-1"
|
||||
>
|
||||
<Image
|
||||
className="
|
||||
w-[32px] h-[32px] lg:w-[40px] lg:h-[40px]
|
||||
min-w-[32px] min-h-[32px] lg:min-w-[40px] lg:min-h-[40px]
|
||||
max-w-[32px] max-h-[32px] lg:max-w-[40px] lg:max-h-[40px]
|
||||
"
|
||||
src={item.src}
|
||||
alt="icon app"
|
||||
height={40}
|
||||
width={40}
|
||||
/>
|
||||
<p className="text-[#3B3B3B] font-normal text-[14px]">
|
||||
{item.name}
|
||||
</p>
|
||||
<a href={item.url} target="_blank" rel="noopener noreferrer">
|
||||
<Image
|
||||
className="
|
||||
w-[32px] h-[32px] lg:w-[40px] lg:h-[40px]
|
||||
min-w-[32px] min-h-[32px] lg:min-w-[40px] lg:min-h-[40px]
|
||||
max-w-[32px] max-h-[32px] lg:max-w-[40px] lg:max-h-[40px]
|
||||
"
|
||||
src={item.src}
|
||||
alt="icon app"
|
||||
height={40}
|
||||
width={40}
|
||||
/>
|
||||
<p className="text-[#3B3B3B] font-normal text-[14px]">
|
||||
{item.name}
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Drawer, Modal } from "@mui/material";
|
||||
import { styleDefault } from "@/mui";
|
||||
import Content from "./Content";
|
||||
|
||||
function ModalOpenLocation({ open, setOpen, handleClose, children }) {
|
||||
function ModalOpenLocation({ open, data, setOpen, handleClose, children }) {
|
||||
const toggleDrawer = (newOpen) => () => {
|
||||
setOpen(newOpen);
|
||||
};
|
||||
@@ -19,7 +19,7 @@ function ModalOpenLocation({ open, setOpen, handleClose, children }) {
|
||||
style={styleDefault}
|
||||
className="!pt-[12px] !pb-[28px] !px-[24px] !bg-[#FAFAFA] !rounded-[8px] !overflow-hidden"
|
||||
>
|
||||
<Content onClose={handleClose} />
|
||||
<Content data={data} onClose={handleClose} />
|
||||
</div>
|
||||
</Modal>
|
||||
<Drawer
|
||||
@@ -35,7 +35,7 @@ function ModalOpenLocation({ open, setOpen, handleClose, children }) {
|
||||
}}
|
||||
>
|
||||
<div className="!pt-[12px] !pb-[28px] !px-[24px] !bg-[#FAFAFA] !rounded-[8px] !overflow-hidden !shadow-[0px_1px_24.8px_0px_rgba(155,_155,_155,_0.27)]">
|
||||
<Content handleClose={handleClose} />
|
||||
<Content data={data} handleClose={handleClose} />
|
||||
</div>
|
||||
</Drawer>
|
||||
</>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Button, ButtonGroup, TextField } from "@mui/material";
|
||||
import SearchD from "@/components/icons/SearchD";
|
||||
import ModalSearchCity from "@/app/component/modalSearchCity";
|
||||
import { useState } from "react";
|
||||
import ButtonFilter from "@/app/component/modalSearchCity/ButtonFilter";
|
||||
import AutoCompleteSearch from "@/components/searchHead/smSearch/AutoCompleteSearch";
|
||||
import ModalSearchCity from "@/components/home/search/modal";
|
||||
|
||||
function SearchBar({
|
||||
selected,
|
||||
@@ -28,7 +28,7 @@ function SearchBar({
|
||||
setOpen={setOpen}
|
||||
selected={selected}
|
||||
setSelected={setSelected}
|
||||
handleSearch={handleSearch}
|
||||
// handleSearch={handleSearch}
|
||||
>
|
||||
<ButtonFilter setOpen={setOpen} selected={selected} />
|
||||
</ModalSearchCity>
|
||||
|
||||
@@ -32,8 +32,8 @@ function ClinicsPage({ clinics, matchedCity, matchedState }) {
|
||||
>
|
||||
<SearchBar
|
||||
selected={selected}
|
||||
state={matchedState}
|
||||
setSelected={setSelected}
|
||||
state={matchedState?.name}
|
||||
handleSearch={handleSearch}
|
||||
specialties={specialtiesData}
|
||||
/>
|
||||
|
||||
@@ -5,7 +5,9 @@ import GreenCalendarTurn from "@/components/icons/GreenCalendarTurn";
|
||||
import { Button } from "@mui/material";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import React from "react";
|
||||
import moment from "moment-jalaali";
|
||||
|
||||
moment.loadPersian({ dialect: "persian-modern" });
|
||||
|
||||
function ItemAppointment({ turn, loading }) {
|
||||
return (
|
||||
@@ -17,7 +19,7 @@ function ItemAppointment({ turn, loading }) {
|
||||
<span className="block w-full h-px bg-[#EFEFEF] my-4"></span>
|
||||
<div className="flex items-center justify-start gap-3">
|
||||
<CircularLoading width={56} height={56} loading={loading}>
|
||||
<Image src={turn?.img || ""} width={56} height={56} alt="doctor" />
|
||||
<Image width={56} height={56} alt="doctor" src={turn?.img[0]?.url} />
|
||||
</CircularLoading>
|
||||
<div className="flex flex-col items-start justify-center gap-2">
|
||||
<TextLoading width={60} height={15} loading={loading}>
|
||||
@@ -26,9 +28,9 @@ function ItemAppointment({ turn, loading }) {
|
||||
<TextLoading width={65} height={15} loading={loading}>
|
||||
<p className="text-[#525252] text-[14px] font-medium">
|
||||
تخصص:
|
||||
{turn?.expertise?.map(
|
||||
{turn?.specialties?.map(
|
||||
(item, idx) =>
|
||||
`${item.name} ${turn.expertise.length === idx + 1 ? "" : "|"} `
|
||||
`${item.name} ${turn.specialties.length === idx + 1 ? "" : "|"} `
|
||||
)}
|
||||
</p>
|
||||
</TextLoading>
|
||||
@@ -39,7 +41,11 @@ function ItemAppointment({ turn, loading }) {
|
||||
<GreenCalendarTurn />
|
||||
<TextLoading width={100} height={15} loading={loading}>
|
||||
<p className="text-[#05BA58] text-[12px] font-medium">
|
||||
اولین نوبت آزاد: {turn.first_free_turn || "یکشنبه 24 اردیبهشت"}
|
||||
{Number(turn?.active)
|
||||
? `اولین نوبت آزاد: ${moment(turn?.free_turn * 1000).format(
|
||||
"dddd jD jMMMM [ساعت] HH:mm"
|
||||
)}`
|
||||
: "نوبت ندارد"}
|
||||
</p>
|
||||
</TextLoading>
|
||||
</div>
|
||||
|
||||
@@ -22,9 +22,9 @@ function AppointmentList({ doctors, loading }) {
|
||||
border-solid bottom-0 right-0 w-full p-4 flex items-center justify-between"
|
||||
>
|
||||
<p className="text-[#05BA58] text-[11px] font-normal">
|
||||
اولین نوبت آزاد: {doctors[0]?.free_turn}
|
||||
اولین نوبت آزاد: {doctors && doctors[0]?.free_turn}
|
||||
</p>
|
||||
<Link href={`/appointment/${doctors[0]?.id}`}>
|
||||
<Link href={`/appointment/${doctors && doctors[0]?.id}`}>
|
||||
<Button
|
||||
variant="contained"
|
||||
className="!py-2 !px-4 gap-1 !text-[14px] !font-medium"
|
||||
|
||||
@@ -8,7 +8,7 @@ function ProgressAll({ doctor }) {
|
||||
<CircularLoading width={120} height={120}>
|
||||
<CircularProgress
|
||||
variant="determinate"
|
||||
value={doctor?.total_user_satisfaction}
|
||||
value={doctor?.satisfaction}
|
||||
sx={{
|
||||
"& .MuiCircularProgress-circle": {
|
||||
stroke: "#05BA58",
|
||||
@@ -28,7 +28,7 @@ function ProgressAll({ doctor }) {
|
||||
رضایت کاربران
|
||||
</p>
|
||||
<p className="text-[#3B3B3B]">
|
||||
{numberToArStyle(doctor?.total_user_satisfaction)}%
|
||||
{numberToArStyle(doctor?.satisfaction)}%
|
||||
</p>
|
||||
</div>
|
||||
</CircularLoading>
|
||||
|
||||
@@ -6,7 +6,10 @@ import ProgressDetail from "@/app/component/ProfressDetail";
|
||||
import TextLoading from "@/app/component/loading/Text";
|
||||
import CustomLoading from "@/app/component/loading/Custom";
|
||||
|
||||
function Chart({ doctor }) {
|
||||
function Chart({ comments, doctor }) {
|
||||
console.log(doctor);
|
||||
console.log(comments);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="
|
||||
@@ -17,10 +20,10 @@ function Chart({ doctor }) {
|
||||
<TextLoading width={130} height={20}>
|
||||
<div className="flex items-center justify-start gap-2.5">
|
||||
<p className="text-[#616161] text-[14px] font-medium">
|
||||
امتیاز کلی کاربران: {doctor?.overall_score} از 5
|
||||
امتیاز کلی کاربران: {doctor?.point} از 5
|
||||
</p>
|
||||
<p className="text-[#7E7E7E] text-[14px] font-normal">
|
||||
(از مجموع {doctor?.comments?.length} نظر)
|
||||
(از مجموع {comments?.length} نظر)
|
||||
</p>
|
||||
</div>
|
||||
</TextLoading>
|
||||
@@ -28,7 +31,7 @@ function Chart({ doctor }) {
|
||||
<TextLoading width={160} height={20}>
|
||||
<Rating
|
||||
readOnly
|
||||
value={4}
|
||||
value={3.5}
|
||||
size="small"
|
||||
name="read-only"
|
||||
className="!mt-4 !mb-6 !hidden lg:!flex"
|
||||
|
||||
@@ -18,7 +18,7 @@ function Comments({ doctor, comments }) {
|
||||
</p>
|
||||
<ModalAnswer doctor={doctor} />
|
||||
</div>
|
||||
<Chart doctor={doctor} />
|
||||
<Chart comments={comments} doctor={doctor} />
|
||||
<Comment data={doctor} comments={comments} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -7,7 +7,7 @@ import ModalOpenLocation from "@/app/component/openLocation";
|
||||
import RoutingWhiteC from "@/components/icons/RoutingWhiteC";
|
||||
import RoutingC from "@/components/icons/RoutingC";
|
||||
|
||||
function Item({ doctor, data }) {
|
||||
function Item({ data }) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
@@ -45,15 +45,13 @@ function Item({ doctor, data }) {
|
||||
<p className="text-[#525252] text-[16px] font-normal">
|
||||
آدرس: {data.address}
|
||||
</p>
|
||||
<p className="text-[#525252] text-[16px] font-normal">
|
||||
تلفن: {data.telephone}
|
||||
</p>
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<p className="text-[#525252] text-[16px] font-normal">
|
||||
روزهای کاری: {doctor.hours_of_work}
|
||||
تلفن: {data.telephone}
|
||||
</p>
|
||||
<ModalOpenLocation
|
||||
open={open}
|
||||
data={data}
|
||||
setOpen={setOpen}
|
||||
handleClose={handleClose}
|
||||
>
|
||||
@@ -79,6 +77,7 @@ function Item({ doctor, data }) {
|
||||
|
||||
<ModalOpenLocation
|
||||
open={open}
|
||||
data={data}
|
||||
setOpen={setOpen}
|
||||
handleClose={handleClose}
|
||||
>
|
||||
|
||||
@@ -11,7 +11,7 @@ function Locations({ doctor }) {
|
||||
{doctor?.address?.map((item, idx) => (
|
||||
<CustomLoading key={idx} width="full" height={40}>
|
||||
<li className="w-full">
|
||||
<Item doctor={doctor} data={item} />
|
||||
<Item data={item} />
|
||||
{doctor?.address.length > idx + 1 && (
|
||||
<span className="w-full h-px bg-[#EFEFEF] block my-[12px] md:my-[14px] lg:my-[16px]"></span>
|
||||
)}
|
||||
|
||||
@@ -4,8 +4,6 @@ import Share from "./detailDoctor/Share";
|
||||
import CustomLoading from "@/app/component/loading/Custom";
|
||||
|
||||
function DoctorPage({ doctor, doctors, comments }) {
|
||||
comments;
|
||||
|
||||
return (
|
||||
<div className="pt-[92px] sm:pt-[120px] mt:pt-[148px] lg:pt-[176px] mt-[px] padding-responsive">
|
||||
<div className="flex items-center justify-between">
|
||||
|
||||
@@ -67,7 +67,6 @@ function Head({ matchedCity, matchedState, setDoctors }) {
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
console.log(filter);
|
||||
|
||||
return (
|
||||
<div className="flex justify-center gap-[16px] sm:gap-[19px] md:gap-[22px] lg:gap-[24px] flex-col items-center mt-0 md:mt-[40px] lg:mt-[90px]">
|
||||
|
||||
@@ -16,7 +16,7 @@ function DoctorsPage({ matchedCity, matchedState, list }) {
|
||||
matchedCity={matchedCity}
|
||||
matchedState={matchedState}
|
||||
/>
|
||||
<ListDoctors list={doctors} />
|
||||
<ListDoctors doctors={doctors} setDoctors={setDoctors} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
import doctors from "@/data/doctors.json";
|
||||
import doctorList from "@/data/doctors.json";
|
||||
import Pagination from "@/app/component/Pagination";
|
||||
import ItemDoctor from "@/app/component/ItemDoctor";
|
||||
|
||||
function ListDoctors({ list }) {
|
||||
function ListDoctors({ doctors, setDoctors }) {
|
||||
return (
|
||||
<>
|
||||
<div className="mt-[24px] sm:mt-[37px] md:mt-[50px] lg:mt-[64px]">
|
||||
{list && list.length ? (
|
||||
{doctors && doctors.length ? (
|
||||
<ul className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-[24px]">
|
||||
{list?.map((doctor) => (
|
||||
<ItemDoctor key={doctor.id} doctor={doctor} />
|
||||
{doctors?.map((doctor) => (
|
||||
<ItemDoctor
|
||||
key={doctor.id}
|
||||
doctor={doctor}
|
||||
doctors={doctors}
|
||||
setDoctors={setDoctors}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
@@ -19,7 +24,7 @@ function ListDoctors({ list }) {
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-[56px] flex justify-center">
|
||||
<Pagination list={doctors} itemsPerPage={12} />
|
||||
<Pagination list={doctorList} itemsPerPage={12} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user