diff --git a/app/clinics/page.js b/app/clinics/page.js index b4d8ce8..9bd8161 100644 --- a/app/clinics/page.js +++ b/app/clinics/page.js @@ -1,19 +1,52 @@ -// app/clinics/page.js +import { fetchReq } from "@/lib/req"; import ClinicsPage from "@/components/clinics"; import Layout from "@/components/layout/StLayout"; -import { fetchReq } from "@/lib/req"; import { getStateInfo } from "@/lib/getStateInfo"; +import { buildClinicParams } from "@/helper"; -export default async function Clinics() { +export default async function Clinics({ searchParams }) { const { matchedCity, matchedState } = getStateInfo(); const API_URL = process.env.NEXT_PUBLIC_API_URL; + const stateParams = searchParams.state; + const cityParams = searchParams.city; - const clinics = await fetchReq(`${API_URL}/api/v1/clinics`); + let clinics; + try { + // Params + let newSearchParams = searchParams; + + // Conditional State + if (stateParams) newSearchParams.state = stateParams; + else if (matchedState) newSearchParams.state = matchedState.name; + + // Conditional City + if (cityParams) newSearchParams.city = cityParams; + else if (matchedCity && matchedCity.id !== "600") + newSearchParams.city = matchedCity.name; + + console.log("newSearchParams"); + console.log(newSearchParams); + + const params = { + ...buildClinicParams(newSearchParams), + page: 1, + limit: 12, + }; + console.log("params"); + console.log(params); + + // Req + clinics = await fetchReq(`${API_URL}/api/v1/clinics`, { + params, + }); + } catch (err) { + console.log(`Error fetching doctors: ${err}`); + } return ( diff --git a/app/component/ItemDoctor.js b/app/component/ItemDoctor.js index 13be1fb..0fb4f66 100644 --- a/app/component/ItemDoctor.js +++ b/app/component/ItemDoctor.js @@ -37,7 +37,7 @@ function ItemDoctor({ doctor, doctors, setDoctors }) { height={72} alt="image-doctor" src={doctor?.img[0]?.url} - className="object-contain w-[64px] md:w-[68px] lg:w-[72px] h-[64px] md:h-[68px] lg:h-[72px]" + className="object-contain rounded-full w-[64px] md:w-[68px] lg:w-[72px] h-[64px] md:h-[68px] lg:h-[72px]" />
diff --git a/app/component/PaginationContent.js b/app/component/PaginationContent.js new file mode 100644 index 0000000..8a96300 --- /dev/null +++ b/app/component/PaginationContent.js @@ -0,0 +1,31 @@ +import { Pagination } from "@mui/material"; + +function PaginationContent({ page, pageDetail, changePage, limit = 12 }) { + const count = Math.ceil(pageDetail.totalRecords / limit); + + return ( + + ); +} + +export default PaginationContent; diff --git a/app/component/modalSearchCity/ButtonFilter.js b/app/component/modalSearchCity/ButtonFilter.js index 5180692..2ebe2e9 100644 --- a/app/component/modalSearchCity/ButtonFilter.js +++ b/app/component/modalSearchCity/ButtonFilter.js @@ -21,7 +21,8 @@ function ButtonFilter({ selected, setOpen }) { className="text-[#616161] text-[11px] md:text-[14px] leading-[17px] sm:leading-[19px] md:leading-[22px] lg:leading-[24px] font-medium ml-1 md:mx-1" > - {(selected.city !== "نوبت 724" ? selected.city : false) || "شهر"} + {(selected.city?.name !== "نوبت 724" ? selected.city?.name : false) || + "شهر"}

diff --git a/app/doctors/page.js b/app/doctors/page.js index 86737d8..d9f46ca 100644 --- a/app/doctors/page.js +++ b/app/doctors/page.js @@ -21,7 +21,7 @@ async function Doctors({ searchParams }) { // Conditional City if (cityParams) newSearchParams.city = cityParams; - else if (matchedCity && matchedCity.id !== "63") + else if (matchedCity && matchedCity.id !== "600") newSearchParams.city = matchedCity.name; const params = buildDoctorParams(newSearchParams); diff --git a/components/clinic/components/about/images/List.js b/components/clinic/components/about/images/List.js index eaec453..3cf12ab 100644 --- a/components/clinic/components/about/images/List.js +++ b/components/clinic/components/about/images/List.js @@ -4,8 +4,6 @@ import Img from "./Img"; function List({ data }) { const images_clinic = data.images_clinic; - console.log(data); - return (
diff --git a/components/clinics/head/FilterButton.js b/components/clinics/head/FilterButton.js index 3acbbda..8029178 100644 --- a/components/clinics/head/FilterButton.js +++ b/components/clinics/head/FilterButton.js @@ -1,11 +1,27 @@ import SearchD from "@/components/icons/SearchD"; +import { QueryForClinicsFilter } from "@/helper"; +import { request } from "@/services/response"; import { Button } from "@mui/material"; import { useState } from "react"; -function FilterButton({ setFilteredClinics }) { +function FilterButton({ selected, setFilteredClinics }) { const [loading, setLoading] = useState(false); + const filterData = () => { - setLoading(true) + setLoading(true); + const params = QueryForClinicsFilter(selected); + + request + .getClinicList(params) + .then((res) => { + if (res.data) setFilteredClinics(res.data); + }) + .catch((err) => { + console.log(err); + }) + .finally(() => { + setLoading(false); + }); }; return ( @@ -13,14 +29,14 @@ function FilterButton({ setFilteredClinics }) { onClick={filterData} loading={loading} className=" - !rounded-[4px] !gap-2.5 !p-2 md:!p-3 lg:!p-4 !grid !place-items-center - !w-[38px] sm:!w-[44px] md:!w-[50px] lg:!w-[56px] - !h-[38px] sm:!h-[44px] md:!h-[50px] lg:!h-[56px] - !min-w-[38px] sm:!min-w-[44px] md:!min-w-[50px] lg:!min-w-[56px] - !min-h-[38px] sm:!min-h-[44px] md:!min-h-[50px] lg:!min-h-[56px] - !max-w-[38px] sm:!max-w-[44px] md:!max-w-[50px] lg:!max-w-[56px] - !max-h-[38px] sm:!max-h-[44px] md:!max-h-[50px] lg:!max-h-[56px] - " + !rounded-[4px] !gap-2.5 !p-2 md:!p-3 lg:!p-4 !grid !place-items-center + !w-[38px] sm:!w-[44px] md:!w-[50px] lg:!w-[56px] + !h-[38px] sm:!h-[44px] md:!h-[50px] lg:!h-[56px] + !min-w-[38px] sm:!min-w-[44px] md:!min-w-[50px] lg:!min-w-[56px] + !min-h-[38px] sm:!min-h-[44px] md:!min-h-[50px] lg:!min-h-[56px] + !max-w-[38px] sm:!max-w-[44px] md:!max-w-[50px] lg:!max-w-[56px] + !max-h-[38px] sm:!max-h-[44px] md:!max-h-[50px] lg:!max-h-[56px] + " >
{!loading && } diff --git a/components/clinics/head/SearchBar.js b/components/clinics/head/SearchBar.js index c049da3..db45427 100644 --- a/components/clinics/head/SearchBar.js +++ b/components/clinics/head/SearchBar.js @@ -53,7 +53,10 @@ function SearchBar({ placeholder="جستجوی تخصص" handleSearch={handleSearch} /> - + ); } diff --git a/components/clinics/index.js b/components/clinics/index.js index 2e310b8..b80b9b1 100644 --- a/components/clinics/index.js +++ b/components/clinics/index.js @@ -6,14 +6,28 @@ import List from "./list"; import SearchBar from "./head/SearchBar"; import HeadPageList from "@/app/component/head"; import specialtiesData from "@/data/specialties.json"; +import { useSearchParams } from "next/navigation"; + +// Data +import states from "@/data/state.json"; +import cities from "@/data/city.json"; function ClinicsPage({ clinics, matchedCity, matchedState }) { - const [filteredClinics, setFilteredClinics] = useState(clinics); + const searchParams = useSearchParams(); + const [filteredClinics, setFilteredClinics] = useState(clinics.data); + + const selectedState = searchParams.get("state") || matchedState?.name; + const selectedCity = + searchParams.get("city") || + (matchedCity?.name && matchedCity?.id !== "600" + ? matchedCity?.name + : false); const [selected, setSelected] = useState({ - province: matchedState?.name || "", - city: matchedCity?.name || "", - specialty: "", + province: + selectedState && states.find((item) => item.name === selectedState), + city: selectedCity && cities.find((item) => item.name === selectedCity), + specialty: searchParams.get("specialty") || "", }); return ( @@ -30,7 +44,13 @@ function ClinicsPage({ clinics, matchedCity, matchedState }) { setFilteredClinics={setFilteredClinics} /> - +
); } diff --git a/components/clinics/list/ItemClinic.js b/components/clinics/list/ItemClinic.js index ac851d1..53a4e02 100644 --- a/components/clinics/list/ItemClinic.js +++ b/components/clinics/list/ItemClinic.js @@ -7,25 +7,26 @@ import { Button } from "@mui/material"; import Image from "next/image"; import Link from "next/link"; -function ItemClinic({ data }) { +function ItemClinic({ data, loading }) { return (
  • - + img clinic
    - +

    {data.title}

    - +

    {data.doctors} پزشک

    @@ -35,7 +36,7 @@ function ItemClinic({ data }) {
    - +

    {data.location}

    @@ -43,7 +44,7 @@ function ItemClinic({ data }) {
    - +

    ساعت کاری: {data.hours_of_work}

    diff --git a/components/clinics/list/index.js b/components/clinics/list/index.js index d73cf2b..4c84446 100644 --- a/components/clinics/list/index.js +++ b/components/clinics/list/index.js @@ -1,9 +1,35 @@ -import Pageguide from "@/app/component/Pageguide"; +import { useState } from "react"; import ItemClinic from "./ItemClinic"; -import Pagination from "@/app/component/Pagination"; +import { QueryForClinicsFilter } from "@/helper"; +import Pageguide from "@/app/component/Pageguide"; +import PaginationContent from "@/app/component/PaginationContent"; +import { request } from "@/services/response"; -function List({ selected, clinics }) { - const listPage = ["کلینیک ها", selected?.city || ""]; +function List({ limit, selected, clinics, pages, setFilteredClinics }) { + const listPage = ["کلینیک ها", selected?.city?.name || ""]; + const [page, setPage] = useState(pages?.currentPage); + const [loading, setLoading] = useState(false); + + const changePage = (_, num) => { + setLoading(true); + + setPage(num); + const params = { + ...QueryForClinicsFilter(selected), + page: num, + limit, + }; + + request + .getClinicList(params) + .then((res) => { + if (res.data) setFilteredClinics(res.data); + }) + .catch((err) => { + console.log(err); + }) + .finally(() => setLoading(false)); + }; return (
    @@ -14,7 +40,7 @@ function List({ selected, clinics }) { gap-y-[16px] sm:gap-y-[24px] md:gap-y-[32px] lg:gap-y-[40px] mt-6" > {clinics.map((item) => ( - + ))} ) : ( @@ -23,7 +49,15 @@ function List({ selected, clinics }) {
    )}
    - +
    ); diff --git a/components/doctors/head/index.js b/components/doctors/head/index.js index 33822a3..76957fd 100644 --- a/components/doctors/head/index.js +++ b/components/doctors/head/index.js @@ -25,7 +25,9 @@ function Head({ matchedCity, matchedState, setDoctors }) { const selectedState = searchParams.get("state") || matchedState?.name; const selectedCity = searchParams.get("city") || - (matchedCity?.name && matchedCity?.id !== "63" ? matchedCity?.name : false); + (matchedCity?.name && matchedCity?.id !== "600" + ? matchedCity?.name + : false); const valCategory = isParent ? findItem("id", isParent) diff --git a/components/doctors/search/SearchField.js b/components/doctors/search/SearchField.js index ee5b433..65a90bd 100644 --- a/components/doctors/search/SearchField.js +++ b/components/doctors/search/SearchField.js @@ -67,7 +67,7 @@ function SearchField({ filter, setFilter, setDataInURL }) { }; return ( -
    +
    option?.name || ""} + className="!w-full !rounded-lg auto-complete-selector" + onChange={(_, value) => updateData(name, value)} + 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) => ( + + )} + renderInput={(params) => ( + + +
    + ), + }} + placeholder={label} + sx={{ + borderRadius: "8px", + }} + /> + )} + /> + ); +} + +export default AutoComplete; diff --git a/components/home/search/modal/Content.js b/components/home/search/modal/Content.js index b9f3788..fc708c2 100644 --- a/components/home/search/modal/Content.js +++ b/components/home/search/modal/Content.js @@ -2,8 +2,8 @@ import { Button } from "@mui/material"; // Icon import CloseModalD from "@/components/icons/CloseModalD"; -import AutoCompleteSelect from "@/app/component/element/AutoCompleteSelect"; import ArrowLeftM from "@/components/icons/ArrowLeftM"; +import AutoComplete from "./AutoComplete"; function Content({ state, @@ -14,7 +14,6 @@ function Content({ filteredCities, handleSearch, }) { - const citySelected = selected.city; const listboxProps = { style: { maxHeight: 200, @@ -39,24 +38,19 @@ function Content({ شهر یا استان مورد نظر را انتخاب نمایید:

    - - item.name === citySelected) && - citySelected - } + value={selected.city} list={filteredCities} name="city" label="شهر" @@ -80,4 +74,4 @@ function Content({ ); } -export default Content; \ No newline at end of file +export default Content; diff --git a/components/home/search/modal/index.js b/components/home/search/modal/index.js index 72b8cab..fe1fffb 100644 --- a/components/home/search/modal/index.js +++ b/components/home/search/modal/index.js @@ -3,11 +3,10 @@ import { useState, useEffect } from "react"; import { Modal, Box } from "@mui/material"; import { styleDefault } from "@/mui"; -import { addLabelToList } from "@/helper"; // Data -import statesData from "@/data/state.json"; -import citiesData from "@/data/city.json"; +import states from "@/data/state.json"; +import cities from "@/data/city.json"; import Content from "./Content"; import { useRouter } from "next/navigation"; @@ -17,14 +16,11 @@ function ModalSearchCity({ setOpen, children, selected, - handleSearch, setSelected, + handleSearch, }) { - const provinceSelected = selected.province; + const provinceSelected = selected?.province?.name; const router = useRouter(); - - const states = addLabelToList(statesData); - const cities = addLabelToList(citiesData); const [filteredCities, setFilteredCities] = useState([]); const handleClose = () => setOpen(false); @@ -32,7 +28,7 @@ function ModalSearchCity({ useEffect(() => { if (provinceSelected) { const selectedState = states.find( - (state) => state.label === provinceSelected + (state) => state.name === provinceSelected ); if (selectedState) { const stateId = selectedState.id; @@ -46,15 +42,17 @@ function ModalSearchCity({ } }, [provinceSelected]); - const updateData = (event, name) => { + const updateData = (name, event) => { const searchParams = new URLSearchParams(window.location.search); if (name === "province") { setSelected({ ...selected, province: event, city: "" }); - searchParams.set("state", event); + searchParams.set("state", event?.name); + searchParams.set("city", selected.city?.name); } else { setSelected({ ...selected, [name]: event }); - searchParams.set("city", event); + searchParams.set("city", event?.name); + searchParams.set("state", selected.province?.name); } router.push(`?${searchParams.toString()}`); }; diff --git a/helper/index.js b/helper/index.js index f398a9a..886619d 100644 --- a/helper/index.js +++ b/helper/index.js @@ -104,14 +104,6 @@ export const alert = (type, text, prop) => { ); }; -export const addLabelToList = (list) => - list.map((item) => { - return { - ...item, - label: item.name, - }; - }); - export const formatPhoneNumber = (input) => { if (typeof input !== "string") input = String(input); @@ -363,6 +355,36 @@ export const QueryForDoctorsReq = (newFilter) => { return params; }; +export const QueryForClinicsFilter = (searchParams) => { + const params = {}; + + // 🔹 specialty (find by name in specialties.json) + if (searchParams.specialty) { + const spec = specialties.find((s) => s.name === searchParams.specialty); + if (spec) { + params.specialty = spec.id; + } + } + + // 🔹 city (find by name in city.json) + if (searchParams.city) { + const cityObj = cities.find((c) => c.name === searchParams.city.name); + if (cityObj) { + params.city = cityObj.id; + } + } + + // 🔹 state (find by name in state.json) + if (searchParams.province) { + const stateObj = states.find((s) => s.name === searchParams.province.name); + if (stateObj) { + params.state = stateObj.id; + } + } + + return params; +}; + export const buildDoctorParams = (searchParams) => { const params = {}; @@ -436,6 +458,36 @@ export const buildDoctorParams = (searchParams) => { return params; }; +export const buildClinicParams = (searchParams) => { + const params = {}; + + // 🔹 city (find by name in city.json) + if (searchParams.city) { + const cityObj = cities.find((c) => c.name === searchParams.city); + if (cityObj) { + params.city = cityObj.id; + } + } + + // 🔹 state (find by name in state.json) + if (searchParams.state) { + const stateObj = states.find((s) => s.name === searchParams.state); + if (stateObj) { + params.state = stateObj.id; + } + } + + // 🔹 specialty (find by name in specialties.json) + if (searchParams.specialty) { + const spec = specialties.find((s) => s.name === searchParams.specialty); + if (spec) { + params.specialty = spec.id; + } + } + + return params; +}; + export function timeAgo(timestamp) { const now = moment(); const then = moment.unix(timestamp); diff --git a/services/response.js b/services/response.js index d8e3331..2bac7da 100644 --- a/services/response.js +++ b/services/response.js @@ -86,4 +86,11 @@ export const request = { postDoctorComment: (data) => api.post("api/v1/clinicpro/comment", data), postDoctorRate: (data) => api.post("api/v1/clinicpro/rate", data), postCommentsLike: (data) => api.post("/api/v1/clinicpro/like", data), + getClinicList: (params) => + api.get("/api/v1/clinics", { + params, + headers: { + Authorization: "", + }, + }), };