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/ProfressDetail.js b/app/component/ProfressDetail.js index 3df210b..705111e 100644 --- a/app/component/ProfressDetail.js +++ b/app/component/ProfressDetail.js @@ -1,11 +1,19 @@ import { numberToArStyle } from "@/helper"; import { LinearProgress } from "@mui/material"; -function ProgressDetail({ data }) { +const label = [ + "برخورد مناسب پزشک", + "تشخیص درست", + "زمان انتظار در مطب", + "مهارت پزشک", + "نظافت مطب", +]; + +function ProgressDetail({ data, idx }) { return (
  • - {data.label} + {label[idx]}

    - {selected.city || "شهر"} + {(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/clinics/head/AutoSearch.js b/components/clinics/head/AutoSearch.js new file mode 100644 index 0000000..a36cbc9 --- /dev/null +++ b/components/clinics/head/AutoSearch.js @@ -0,0 +1,105 @@ +import { Autocomplete, TextField } from "@mui/material"; +import { useEffect, useRef, useState } from "react"; + +function AutoSearch({ + data, + noneBg, + 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 ( + + typeof option === "string" ? option : option.name + } + disableClearable + inputValue={localInput} + className="!w-full" + onInputChange={onInputChange} + onChange={onChange} + renderOption={(props, option) => ( +
  • + {option.name} +
  • + )} + sx={{ + "& .MuiAutocomplete-input": { + background: noneBg ? "" : "#ffffff !important", + }, + }} + renderInput={(params) => ( + + )} + /> + ); +} + +export default AutoSearch; diff --git a/components/clinics/head/FilterButton.js b/components/clinics/head/FilterButton.js new file mode 100644 index 0000000..8029178 --- /dev/null +++ b/components/clinics/head/FilterButton.js @@ -0,0 +1,49 @@ +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({ selected, setFilteredClinics }) { + const [loading, setLoading] = useState(false); + + const filterData = () => { + 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 ( + + ); +} + +export default FilterButton; diff --git a/components/clinics/head/SearchBar.js b/components/clinics/head/SearchBar.js index 93d513a..db45427 100644 --- a/components/clinics/head/SearchBar.js +++ b/components/clinics/head/SearchBar.js @@ -1,18 +1,34 @@ -import { Button, ButtonGroup, TextField } from "@mui/material"; -import SearchD from "@/components/icons/SearchD"; +import { ButtonGroup } from "@mui/material"; 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"; +import AutoSearch from "./AutoSearch"; +import { useRouter } from "next/navigation"; +import FilterButton from "./FilterButton"; function SearchBar({ - selected, - setSelected, - specialties, state, - handleSearch, + selected, + specialties, + setSelected, + setFilteredClinics, }) { const [open, setOpen] = useState(false); + const router = useRouter(); + + const handleSearch = (e) => { + const specialty = specialties.find((item) => item.name === e); + const searchParams = new URLSearchParams(window.location.search); + + if (specialty) { + searchParams.set("specialty", specialty.name); + setSelected({ ...selected, specialty: specialty.name }); + } else { + e ? searchParams.set("specialty", e) : searchParams.delete("specialty"); + setSelected({ ...selected, specialty: e }); + } + router.push(`?${searchParams.toString()}`); + }; return ( - - + ); } diff --git a/components/clinics/index.js b/components/clinics/index.js index 7342e2d..b80b9b1 100644 --- a/components/clinics/index.js +++ b/components/clinics/index.js @@ -5,25 +5,31 @@ import { useState } from "react"; import List from "./list"; import SearchBar from "./head/SearchBar"; import HeadPageList from "@/app/component/head"; -import { useRouter } from "next/navigation"; 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 router = useRouter(); - 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 || "", + province: + selectedState && states.find((item) => item.name === selectedState), + city: selectedCity && cities.find((item) => item.name === selectedCity), + specialty: searchParams.get("specialty") || "", }); - const handleSearch = (value) => { - // const current = new URLSearchParams(window.location.search); - // current.set("search", value); - // const queryString = current.toString(); - // router.push(`/clinics?${queryString}`); - }; - return (
    - +
    ); } 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/doctor/detailDoctor/cards/comments/chart/index.js b/components/doctor/detailDoctor/cards/comments/chart/index.js index 8702ed1..2310a73 100644 --- a/components/doctor/detailDoctor/cards/comments/chart/index.js +++ b/components/doctor/detailDoctor/cards/comments/chart/index.js @@ -55,7 +55,7 @@ function Chart({ comments, doctor }) {
      {Object.values(doctor?.average_rate?.averages).map((item, idx) => ( - + ))}
    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/AutoComplete.js b/components/doctors/search/AutoComplete.js index 4127521..83c5eac 100644 --- a/components/doctors/search/AutoComplete.js +++ b/components/doctors/search/AutoComplete.js @@ -5,22 +5,20 @@ function AutoComplete({ data, noneBg, clearText, - inputValue, // مقدار کنترل‌شده از والد (اختیاری) + inputValue, placeholder, - handleSearch, // تابعی که باید با مقدار جستجو صدا زده بشه - setInputValue, // اختیاری: اگه والد دوست داره همون‌وقت مقدار رو بگیره + handleSearch, + setInputValue, setSelectedOption, - debounce = 500, // قابل تنظیم + debounce = 500, }) { const typingTimeoutRef = useRef(null); const [localInput, setLocalInput] = useState(inputValue || ""); - // همگام‌سازی وقتی والد مقدار کنترل‌شده رو تغییر میده (مثلاً بعد از انتخاب گزینه) useEffect(() => { setLocalInput(inputValue || ""); }, [inputValue]); - // پاک‌کردن تایمر هنگام unmount useEffect(() => { return () => { if (typingTimeoutRef.current) clearTimeout(typingTimeoutRef.current); @@ -28,13 +26,10 @@ function AutoComplete({ }, []); const onInputChange = (_, newInputValue) => { - // نمایش آنی تایپ کاربر setLocalInput(newInputValue); - // اختیاری: اگر والد خواست همون‌جا مقدار رو بگیره if (setInputValue) setInputValue(newInputValue); - // پاک کردن تایمر قبلی و ست کردن تایمر جدید برای debounce if (typingTimeoutRef.current) clearTimeout(typingTimeoutRef.current); typingTimeoutRef.current = setTimeout(() => { handleSearch(newInputValue); @@ -42,7 +37,6 @@ function AutoComplete({ }; const onChange = (_, newValue) => { - // انتخاب از لیست — مقدار رو فوراً پردازش کن if (typingTimeoutRef.current) { clearTimeout(typingTimeoutRef.current); typingTimeoutRef.current = null; @@ -55,7 +49,7 @@ function AutoComplete({ : ""; setLocalInput(val); setSelectedOption && setSelectedOption(newValue); - handleSearch(val); // اجرای فوری روی انتخاب + handleSearch(val); if (setInputValue) setInputValue(val); }; @@ -67,7 +61,7 @@ function AutoComplete({ typeof option === "string" ? option : option.name } disableClearable - inputValue={localInput} // ← نمایش آنی از local state + inputValue={localInput} className="!w-full" onInputChange={onInputChange} onChange={onChange} diff --git a/components/doctors/search/SearchField.js b/components/doctors/search/SearchField.js index a6f4fc7..65a90bd 100644 --- a/components/doctors/search/SearchField.js +++ b/components/doctors/search/SearchField.js @@ -3,7 +3,7 @@ import { useRouter } from "next/navigation"; import specialties from "@/data/specialties.json"; import AutoComplete from "./AutoComplete"; -function SearchField({ filter, setFilter, updateData, setDataInURL }) { +function SearchField({ filter, setFilter, setDataInURL }) { const router = useRouter(); const clearText = () => { @@ -17,7 +17,6 @@ function SearchField({ filter, setFilter, updateData, setDataInURL }) { }, }; setFilter(newFilter); - // setDataInURL(newFilter); }; const handleSearch = (e) => { @@ -34,7 +33,6 @@ function SearchField({ filter, setFilter, updateData, setDataInURL }) { dataUrl.specialty = findName.name; newFilter.category = itemParent; newFilter.specialty = findName; - // updateData("name", e); } else { dataUrl.specialty = findName.name; newFilter.category = findName; @@ -50,8 +48,6 @@ function SearchField({ filter, setFilter, updateData, setDataInURL }) { router.push(`?${searchParams.toString()}`); newFilter.name = e; setFilter(newFilter); - // const newFilter = { ...filter, [name]: e }; - // setFilter(newFilter); } else { let newFilter = filter; @@ -65,20 +61,18 @@ function SearchField({ filter, setFilter, updateData, setDataInURL }) { router.push(`?${searchParams.toString()}`); } newFilter.name = e; - // updateData("name", e); setFilter(newFilter); setDataInURL(newFilter); } }; return ( -
    +
    updateData("name", e)} placeholder="جستجوی نام پزشک، تخصص، بیماری ..." />
    diff --git a/components/doctors/search/index.js b/components/doctors/search/index.js index eef89cc..f414c0c 100644 --- a/components/doctors/search/index.js +++ b/components/doctors/search/index.js @@ -39,7 +39,6 @@ function SearchBar({ filter, sendReq, setFilter, updateData, setDataInURL }) { 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 80a62b8..fe1fffb 100644 --- a/components/home/search/modal/index.js +++ b/components/home/search/modal/index.js @@ -3,12 +3,12 @@ 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"; function ModalSearchCity({ open, @@ -16,13 +16,11 @@ function ModalSearchCity({ setOpen, children, selected, - handleSearch, setSelected, + handleSearch, }) { - const provinceSelected = selected.province; - - const states = addLabelToList(statesData); - const cities = addLabelToList(citiesData); + const provinceSelected = selected?.province?.name; + const router = useRouter(); const [filteredCities, setFilteredCities] = useState([]); const handleClose = () => setOpen(false); @@ -30,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; @@ -44,12 +42,19 @@ 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?.name); + searchParams.set("city", selected.city?.name); } else { setSelected({ ...selected, [name]: event }); + searchParams.set("city", event?.name); + searchParams.set("state", selected.province?.name); } + router.push(`?${searchParams.toString()}`); }; return ( diff --git a/data/city.json b/data/city.json index b84d9b2..fcaa394 100644 --- a/data/city.json +++ b/data/city.json @@ -1,6 +1,6 @@ [ { - "id": "32", + "id": "101", "email": "nobat724@gmail.com", "type": "2", "province_id": "1", @@ -21,7 +21,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به تبریز نوبت می‌باشد." }, { - "id": "33", + "id": "102", "email": "nobat724@gmail.com", "type": "2", "province_id": "2", @@ -42,7 +42,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به ارومیه نوبت می‌باشد." }, { - "id": "34", + "id": "103", "email": "nobat724@gmail.com", "type": "2", "province_id": "3", @@ -63,7 +63,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به اردبیل نوبت می‌باشد." }, { - "id": "35", + "id": "104", "email": "nobat724@gmail.com", "type": "2", "province_id": "4", @@ -84,7 +84,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به اصفهان نوبت می‌باشد." }, { - "id": "36", + "id": "105", "email": "nobat724@gmail.com", "type": "2", "province_id": "5", @@ -105,7 +105,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به کرج نوبت می‌باشد." }, { - "id": "37", + "id": "106", "email": "nobat724@gmail.com", "type": "2", "province_id": "6", @@ -126,7 +126,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به ایلام نوبت می‌باشد." }, { - "id": "38", + "id": "107", "email": "nobat724@gmail.com", "type": "2", "province_id": "7", @@ -147,7 +147,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به بوشهر نوبت می‌باشد." }, { - "id": "39", + "id": "108", "email": "nobat724@gmail.com", "type": "2", "province_id": "8", @@ -168,7 +168,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به تهران نوبت می‌باشد." }, { - "id": "40", + "id": "109", "email": "nobat724@gmail.com", "type": "2", "province_id": "9", @@ -189,7 +189,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به شهرکرد نوبت می‌باشد." }, { - "id": "41", + "id": "110", "email": "nobat724@gmail.com", "type": "2", "province_id": "10", @@ -210,7 +210,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به بیرجند نوبت می‌باشد." }, { - "id": "42", + "id": "111", "email": "nobat724@gmail.com", "type": "2", "province_id": "11", @@ -231,7 +231,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به مشهد نوبت می‌باشد." }, { - "id": "43", + "id": "112", "email": "nobat724@gmail.com", "type": "2", "province_id": "12", @@ -252,7 +252,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به بجنورد نوبت می‌باشد." }, { - "id": "44", + "id": "113", "email": "nobat724@gmail.com", "type": "2", "province_id": "13", @@ -273,7 +273,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به اهواز نوبت می‌باشد." }, { - "id": "45", + "id": "114", "email": "nobat724@gmail.com", "type": "2", "province_id": "14", @@ -294,7 +294,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به زنجان نوبت می‌باشد." }, { - "id": "46", + "id": "115", "email": "nobat724@gmail.com", "type": "2", "province_id": "15", @@ -315,7 +315,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به سمنان نوبت می‌باشد." }, { - "id": "47", + "id": "116", "email": "nobat724@gmail.com", "type": "2", "province_id": "16", @@ -336,7 +336,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به زاهدان نوبت می‌باشد." }, { - "id": "48", + "id": "117", "email": "nobat724@gmail.com", "type": "2", "province_id": "17", @@ -357,7 +357,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به شیراز نوبت می‌باشد." }, { - "id": "49", + "id": "118", "email": "nobat724@gmail.com", "type": "2", "province_id": "18", @@ -378,7 +378,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به قزوین نوبت می‌باشد." }, { - "id": "50", + "id": "119", "email": "nobat724@gmail.com", "type": "2", "province_id": "19", @@ -399,7 +399,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به قم نوبت می‌باشد." }, { - "id": "51", + "id": "120", "email": "nobat724@gmail.com", "type": "2", "province_id": "20", @@ -420,7 +420,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به سنندج نوبت می‌باشد." }, { - "id": "52", + "id": "121", "email": "nobat724@gmail.com", "type": "2", "province_id": "21", @@ -441,7 +441,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به کرمان نوبت می‌باشد." }, { - "id": "53", + "id": "122", "email": "nobat724@gmail.com", "type": "2", "province_id": "22", @@ -462,7 +462,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به کرمانشاه نوبت می‌باشد." }, { - "id": "54", + "id": "123", "email": "nobat724@gmail.com", "type": "2", "province_id": "23", @@ -483,7 +483,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به یاسوج نوبت می‌باشد." }, { - "id": "64", + "id": "124", "email": "nobat724@gmail.com", "type": "2", "province_id": "23", @@ -504,7 +504,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به یاسوج نوبت می‌باشد." }, { - "id": "55", + "id": "125", "email": "nobat724@gmail.com", "type": "2", "province_id": "24", @@ -525,7 +525,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به گرگان نوبت می‌باشد." }, { - "id": "56", + "id": "126", "email": "nobat724@gmail.com", "type": "2", "province_id": "25", @@ -546,7 +546,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به رشت نوبت می‌باشد." }, { - "id": "57", + "id": "127", "email": "nobat724@gmail.com", "type": "2", "province_id": "26", @@ -567,7 +567,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به خرم‌آباد نوبت می‌باشد." }, { - "id": "58", + "id": "128", "email": "nobat724@gmail.com", "type": "2", "province_id": "27", @@ -588,7 +588,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به ساری نوبت می‌باشد." }, { - "id": "59", + "id": "129", "email": "nobat724@gmail.com", "type": "2", "province_id": "28", @@ -609,7 +609,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به اراک نوبت می‌باشد." }, { - "id": "60", + "id": "130", "email": "nobat724@gmail.com", "type": "2", "province_id": "29", @@ -630,7 +630,7 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به بندرعباس نوبت می‌باشد." }, { - "id": "61", + "id": "131", "email": "nobat724@gmail.com", "type": "2", "province_id": "30", @@ -651,10 +651,10 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به همدان نوبت می‌باشد." }, { - "id": "62", + "id": "132", "email": "nobat724@gmail.com", "type": "2", - "province_id": "31", + "province_id": "100", "name": "یزد", "site_name": "یزد نوبت", "slogan": "نوبت‌گیری آنلاین پزشکان یزد، در هر ساعت از روز", @@ -672,10 +672,9 @@ "footerDisclaimer": "تمامی حقوق این سایت متعلق به یزد نوبت می‌باشد." }, { - "id": "63", + "id": "600", "email": "nobat724@gmail.com", "type": "2", - "province_id": "32", "name": "نوبت 724", "site_name": "نوبت 724", "slogan": "دیگه نوبت گرفتن کار سختی نیست !", @@ -692,4 +691,4 @@ "footerDescription": "نوبت 724، سامانه جامع نوبت‌دهی پزشکی برای تمامی شهرها. رزرو نوبت از پزشکان و مراکز درمانی معتبر بدون نیاز به مراجعه حضوری.", "footerDisclaimer": "تمامی حقوق این سایت متعلق به نوبت 724 می‌باشد." } -] \ No newline at end of file +] diff --git a/data/specialties.json b/data/specialties.json index 6720455..8b78b5a 100644 --- a/data/specialties.json +++ b/data/specialties.json @@ -1,346 +1,346 @@ [ { - "id": "500", + "id": "601", "name": "پزشکی عمومی", "parent": null }, { - "id": "501", + "id": "602", "name": "داخلی", "parent": null }, { - "id": "502", + "id": "603", "name": "داخلی عمومی", - "parent": "501" + "parent": "602" }, { - "id": "503", + "id": "604", "name": "قلب و عروق", - "parent": "501" + "parent": "602" }, { - "id": "504", + "id": "605", "name": "گوارش و کبد", - "parent": "501" + "parent": "602" }, { - "id": "505", + "id": "606", "name": "غدد و متابولیسم", - "parent": "501" + "parent": "602" }, { - "id": "506", + "id": "607", "name": "خون و انکولوژی", - "parent": "501" + "parent": "602" }, { - "id": "507", + "id": "608", "name": "ریه (پولمونولوژی)", - "parent": "501" + "parent": "602" }, { - "id": "508", + "id": "609", "name": "کلیه و مجاری ادراری (نفرولوژی)", - "parent": "501" + "parent": "602" }, { - "id": "509", + "id": "610", "name": "روماتولوژی (بیماری‌های مفاصل)", - "parent": "501" + "parent": "602" }, { - "id": "510", + "id": "611", "name": "نورولوژی (عصبی)", - "parent": "501" + "parent": "602" }, { - "id": "511", + "id": "612", "name": "جراحی", "parent": null }, { - "id": "512", + "id": "613", "name": "جراحی عمومی", - "parent": "511" + "parent": "612" }, { - "id": "513", + "id": "614", "name": "جراحی مغز و اعصاب", - "parent": "511" + "parent": "612" }, { - "id": "514", + "id": "615", "name": "جراحی قلب و عروق", - "parent": "511" + "parent": "612" }, { - "id": "515", + "id": "616", "name": "جراحی عروق", - "parent": "511" + "parent": "612" }, { - "id": "516", + "id": "617", "name": "جراحی ارتوپدی (استخوان و مفاصل)", - "parent": "511" + "parent": "612" }, { - "id": "517", + "id": "618", "name": "جراحی پلاستیک و ترمیمی", - "parent": "511" + "parent": "612" }, { - "id": "518", + "id": "619", "name": "جراحی چشم", - "parent": "511" + "parent": "612" }, { - "id": "519", + "id": "620", "name": "جراحی گوش، حلق و بینی (ENT)", - "parent": "511" + "parent": "612" }, { - "id": "520", + "id": "621", "name": "جراحی کودکان", - "parent": "511" + "parent": "612" }, { - "id": "521", + "id": "622", "name": "جراحی دستگاه گوارش", - "parent": "511" + "parent": "612" }, { - "id": "522", + "id": "623", "name": "جراحی توراکس (قفسه سینه)", - "parent": "511" + "parent": "612" }, { - "id": "523", + "id": "624", "name": "جراحی دست", - "parent": "511" + "parent": "612" }, { - "id": "524", + "id": "625", "name": "جراحی فک و صورت", - "parent": "511" + "parent": "612" }, { - "id": "525", + "id": "626", "name": "زنان و زایمان", "parent": null }, { - "id": "526", + "id": "627", "name": "اطفال (کودکان)", "parent": null }, { - "id": "527", + "id": "628", "name": "روانپزشکی", "parent": null }, { - "id": "528", + "id": "629", "name": "روانپزشکی عمومی", - "parent": "527" + "parent": "628" }, { - "id": "529", + "id": "630", "name": "روانپزشکی کودکان و نوجوانان", - "parent": "527" + "parent": "628" }, { - "id": "530", + "id": "631", "name": "روانپزشکی سالمندان", - "parent": "527" + "parent": "628" }, { - "id": "531", + "id": "632", "name": "پوست و مو (درماتولوژی)", "parent": null }, { - "id": "532", + "id": "633", "name": "چشم‌ پزشکی", "parent": null }, { - "id": "533", + "id": "634", "name": "گوش، حلق و بینی", "parent": null }, { - "id": "534", + "id": "635", "name": "اورولوژی (مجاری ادراری و تناسلی)", "parent": null }, { - "id": "535", + "id": "636", "name": "رادیولوژی", "parent": null }, { - "id": "536", + "id": "637", "name": "رادیولوژی تشخیصی", - "parent": "535" + "parent": "636" }, { - "id": "537", + "id": "638", "name": "رادیولوژی مداخله‌ای", - "parent": "535" + "parent": "636" }, { - "id": "538", + "id": "639", "name": "نوار قلب و الکتروفیزیولوژی", - "parent": "535" + "parent": "636" }, { - "id": "539", + "id": "640", "name": "پاتولوژی (آسیب‌شناسی)", "parent": null }, { - "id": "540", + "id": "641", "name": "انکولوژی (سرطان‌شناسی)", "parent": null }, { - "id": "541", + "id": "642", "name": "انکولوژی پزشکی", - "parent": "540" + "parent": "641" }, { - "id": "542", + "id": "643", "name": "انکولوژی رادیوتراپی", - "parent": "540" + "parent": "641" }, { - "id": "543", + "id": "644", "name": "طب فیزیکی و توانبخشی", "parent": null }, { - "id": "544", + "id": "645", "name": "دندانپزشکی", "parent": null }, { - "id": "545", + "id": "646", "name": "عمومی", - "parent": "544" + "parent": "645" }, { - "id": "546", + "id": "647", "name": "ارتودنسی", - "parent": "544" + "parent": "645" }, { - "id": "547", + "id": "648", "name": "جراحی فک و صورت", - "parent": "544" + "parent": "645" }, { - "id": "548", + "id": "649", "name": "پریودنتولوژی (بیماری‌های لثه)", - "parent": "544" + "parent": "645" }, { - "id": "549", + "id": "650", "name": "اندودنتولوژی (درمان ریشه)", - "parent": "544" + "parent": "645" }, { - "id": "550", + "id": "651", "name": "پروتز دندان", - "parent": "544" + "parent": "645" }, { - "id": "551", + "id": "652", "name": "دندانپزشکی کودکان", - "parent": "544" + "parent": "645" }, { - "id": "552", + "id": "653", "name": "طب اورژانس", "parent": null }, { - "id": "553", + "id": "654", "name": "پزشکی خانواده", "parent": null }, { - "id": "554", + "id": "655", "name": "طب ورزشی", "parent": null }, { - "id": "555", + "id": "656", "name": "پزشکی هسته‌ای", "parent": null }, { - "id": "556", + "id": "657", "name": "پزشکی قانونی", "parent": null }, { - "id": "557", + "id": "658", "name": "پزشکی اجتماعی", "parent": null }, { - "id": "558", + "id": "659", "name": "طب سالمندان", "parent": null }, { - "id": "559", + "id": "660", "name": "نوروسرجری (جراحی مغز و اعصاب)", "parent": null }, { - "id": "560", + "id": "661", "name": "پزشکی شغلی", "parent": null }, { - "id": "561", + "id": "662", "name": "اندوکرینولوژی (غدد درون‌ریز)", "parent": null }, { - "id": "562", + "id": "663", "name": "میکروبیولوژی و ویروس‌شناسی پزشکی", "parent": null }, { - "id": "563", + "id": "664", "name": "ایمونولوژی (سیستم ایمنی)", "parent": null }, { - "id": "564", + "id": "665", "name": "بیماری‌های عفونی", "parent": null }, { - "id": "565", + "id": "666", "name": "گوش، حلق و بینی", "parent": null }, { - "id": "566", + "id": "667", "name": "نورولوژی (عصبی)", "parent": null }, { - "id": "567", + "id": "668", "name": "پزشکی خواب", "parent": null }, { - "id": "568", + "id": "1500", "name": "سکته مغزی", "parent": null } diff --git a/data/state.json b/data/state.json index 3200021..97ada55 100644 --- a/data/state.json +++ b/data/state.json @@ -120,7 +120,7 @@ "name": "همدان" }, { - "id": "31", + "id": "100", "name": "یزد" } ] 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: "", + }, + }), };