in page add doctor change data state & component & save data & request to send data & change component folder

This commit is contained in:
Ehsan
2025-07-14 04:30:50 +03:30
parent 97802a9fdf
commit 88f25cdd2e
16 changed files with 393 additions and 156 deletions
-1
View File
@@ -17,7 +17,6 @@ function SendAppo({ hour }) {
slot: hour,
})
.then((res) => {
console.log(res);
setLoading(false);
})
.catch((err) => {
-3
View File
@@ -23,7 +23,6 @@ function DateTime({ date, doctor, setStep, setIsError, locateVisit }) {
setHour();
setValue(newValue);
};
console.log(hour);
useEffect(() => {
if (date) {
@@ -32,11 +31,9 @@ function DateTime({ date, doctor, setStep, setIsError, locateVisit }) {
request
.getAppointment(doctorId, date)
.then((res) => {
console.log(res);
setAppo(res);
})
.catch((err) => {
console.log(err);
setAppo("در حال حاضر، نوبتی برای ساعت‌های صبح موجود نمی‌باشد.");
});
}
@@ -3,13 +3,8 @@ import Content from "./Content";
import DateBirthday from "./DateBirthday";
import AutoSelector from "../component/AutoSelector";
import Field from "../component/Field";
import {
gender,
blood_group,
marital_status,
education,
job,
} from "./listSelector";
import { gender, blood_group, marital_status, job } from "./listSelector";
import education from "@/data/education.json";
function Form({ insurance, errors, changeData, information }) {
const findVal = (list, name) =>
@@ -19,14 +19,6 @@ export const marital_status = [
{ label: "مجرد", id: "single" },
];
export const education = [
{ label: "دیپلم", id: "diploma" },
{ label: "دیپلم تحصیلات تکمیلی", id: "postgraduate_diploma" },
{ label: "لیسانس", id: "bachelor_s_degree" },
{ label: "کارشناسی ارشد", id: "master_s_degree" },
{ label: "دکترا", id: "doctorate" },
];
export const job = [
{ label: "آزاد", id: "azad" },
{ label: "دولتی", id: "dolati" },
-5
View File
@@ -29,15 +29,12 @@ function ModalSearchCity() {
second: "",
});
// Load states and cities from JSON files
useEffect(() => {
// Format states data to match the structure expected by AutoCompleteSelect
const formattedStates = statesData.map((state) => ({
label: state.name,
id: state.id,
}));
// Format cities data
const formattedCities = citiesData.map((city) => ({
label: city.name,
id: city.id,
@@ -48,7 +45,6 @@ function ModalSearchCity() {
setCities(formattedCities);
}, []);
// Filter cities when state is selected
useEffect(() => {
if (selected.first) {
const selectedState = states.find(
@@ -69,7 +65,6 @@ function ModalSearchCity() {
const updateData = (event, name) => {
if (name === "first" && event !== selected.first) {
// If state changes, reset city selection
setSelected({ first: event, second: "" });
} else {
setSelected({ ...selected, [name]: event });
@@ -0,0 +1,72 @@
export const defaultState = {
general: {
name: { value: "", placeholder: "", isEdit: true },
medical_system_number: {
value: "",
placeholder: 1741025645,
isEdit: true,
},
expertise: { value: "", placeholder: "دندان پزشکی", isEdit: true },
description: { value: "", isEdit: true },
skills: { value: "", isEdit: true },
time_work: { value: "", isEdit: true },
degree: { value: "", isEdit: true },
},
office: {
address: { value: "مپ", isEdit: true },
phone: { value: "", placeholder: 1741025645, isEdit: true },
office_number1: { value: "", isEdit: true },
state: { value: "", isEdit: true },
city: { value: "", isEdit: true },
},
work_day: [
{
name: "شنبه",
number_turns: { value: 1, isEdit: true },
turn_time: "",
workplace: "",
morning_time: ["", ""],
evening_time: ["", ""],
},
{
name: "یکشنبه",
number_turns: { value: 1, isEdit: true },
turn_time: "",
workplace: "",
morning_time: ["", ""],
evening_time: ["", ""],
},
{
name: "دوشنبه",
number_turns: { value: 1, isEdit: true },
turn_time: "",
workplace: "",
morning_time: ["", ""],
evening_time: ["", ""],
},
{
name: "سه شنبه",
number_turns: { value: 1, isEdit: true },
turn_time: "",
workplace: "",
morning_time: ["", ""],
evening_time: ["", ""],
},
{
name: "چهار شنبه",
number_turns: { value: 1, isEdit: true },
turn_time: "",
workplace: "",
morning_time: ["", ""],
evening_time: ["", ""],
},
{
name: "پنج شنبه",
number_turns: { value: 1, isEdit: true },
turn_time: "",
workplace: "",
morning_time: ["", ""],
evening_time: ["", ""],
},
],
};
+14 -75
View File
@@ -7,82 +7,16 @@ import WorkingDays from "./listMenu/workingDays";
import OfficeInformation from "./listMenu/officeInformation";
import GeneralInformation from "./listMenu/generalInformation";
import Step from "./Step";
import { defaultState } from "./defaultState";
function AddDoctorPage() {
const [value, setValue] = useState(0);
const [data, setData] = useState({
general: {
name: { value: "", placeholder: "", isEdit: true },
medical_system_number: {
value: "",
placeholder: 1741025645,
isEdit: true,
},
expertise: { value: "", placeholder: "دندان پزشکی", isEdit: true },
description: { value: "", isEdit: true },
skills: { value: "", isEdit: true },
time_work: { value: "", isEdit: true },
degree: { value: "", isEdit: true },
},
office: {
address: { value: "مپ", isEdit: true },
phone: { value: "", placeholder: 1741025645, isEdit: true },
office_number1: { value: "", isEdit: true },
office_number2: { value: "", isEdit: true },
state: { value: "", isEdit: true },
city: { value: "", isEdit: true },
},
work_day: [
{
name: "شنبه",
number_turns: { value: 1, isEdit: true },
turn_time: "",
workplace: "",
morning_time: ["", ""],
evening_time: ["", ""],
},
{
name: "یکشنبه",
number_turns: { value: 1, isEdit: true },
turn_time: "",
workplace: "",
morning_time: ["", ""],
evening_time: ["", ""],
},
{
name: "دوشنبه",
number_turns: { value: 1, isEdit: true },
turn_time: "",
workplace: "",
morning_time: ["", ""],
evening_time: ["", ""],
},
{
name: "سه شنبه",
number_turns: { value: 1, isEdit: true },
turn_time: "",
workplace: "",
morning_time: ["", ""],
evening_time: ["", ""],
},
{
name: "چهار شنبه",
number_turns: { value: 1, isEdit: true },
turn_time: "",
workplace: "",
morning_time: ["", ""],
evening_time: ["", ""],
},
{
name: "پنج شنبه",
number_turns: { value: 1, isEdit: true },
turn_time: "",
workplace: "",
morning_time: ["", ""],
evening_time: ["", ""],
},
],
});
const [value, setValue] = useState(2);
const [data, setData] = useState(defaultState);
const resetData = () => {
setData(defaultState);
setValue(0);
};
const components = [
<GeneralInformation
@@ -97,7 +31,12 @@ function AddDoctorPage() {
setData={setData}
setValue={setValue}
/>,
<WorkingDays data={data} parent="work_day" setData={setData} />,
<WorkingDays
data={data}
parent="work_day"
setData={setData}
resetData={resetData}
/>,
];
return (
@@ -0,0 +1,83 @@
import BottomSelect from "@/components/icons/BottomSelect";
import { Autocomplete, Button, TextField } from "@mui/material";
import { styleTextSelectRight } from "@/mui";
function Selector({ updateData, nameKey, label, name, list }) {
return (
<Autocomplete
disablePortal
options={list}
getOptionLabel={(option) => option[nameKey] || ""}
isOptionEqualToValue={(option, value) => option.id === value.id}
className="!w-full !rounded-lg auto-complete-selector "
onChange={(e, newValue) => {
if (newValue) {
updateData && updateData(newValue.id, "value", name);
}
}}
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",
},
}}
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 || option.label}
</Button>
)}
renderInput={(params) => (
<TextField
fullWidth
{...params}
InputProps={{
...params.InputProps,
endAdornment: (
<div className="absolute left-4">
<BottomSelect />
</div>
),
}}
placeholder={label}
sx={{
borderRadius: "8px",
}}
/>
)}
/>
);
}
export default Selector;
@@ -0,0 +1,23 @@
import ArrowLeftPA from "@/components/icons/ArrowLeftPA";
import { checkAllValues } from "@/helper";
import { Button } from "@mui/material";
function SendReq({ setValue, data }) {
return (
<div className="mt-[40px] w-full flex justify-end">
<Button
className="!w-full md:!w-fit !shadow-none !rounded-[4px] !gap-[4px] !text-[#EFEFEF] !text-[14px] md:!text-[16px] !font-medium"
onClick={() => setValue((prev) => prev + 1)}
disabled={!checkAllValues(data)}
variant="contained"
>
ثبت اطلاعات
<div className={!checkAllValues(data) ? "opacity-40" : "opacity-100"}>
<ArrowLeftPA />
</div>
</Button>
</div>
);
}
export default SendReq;
@@ -1,14 +1,15 @@
import { Button } from "@mui/material";
import FieldDate from "./FieldDate";
import { degree, expertise } from "./listSelector";
import RadioGender from "./RadioGender";
import SendReq from "./SendReq";
import Selector from "./Selector";
// Components
import EditField from "@/app/component/EditField";
import ContentText from "@/app/component/ContentText";
import ArrowLeftPA from "@/components/icons/ArrowLeftPA";
import AutoCompleteSelect from "@/app/component/element/AutoCompleteSelect";
import { checkAllValues } from "@/helper";
// Data
import specialties from "@/data/specialties.json";
import education from "@/data/education.json";
const validate_medical_number = {
min: 1,
@@ -16,20 +17,22 @@ const validate_medical_number = {
};
function Form({ setValue, parent, data, setData }) {
const changeData = (value, type, name) =>
const changeData = (value, type, name) => {
type !== "isEdit" &&
setData((prev) => {
return {
...prev,
[parent]: {
...prev[parent],
[name]: {
...prev[parent][name],
[type]: value,
setData((prev) => {
return {
...prev,
[parent]: {
...prev[parent],
[name]: {
...prev[parent][name],
[type]: value,
},
},
},
};
});
};
});
};
const updateNum = (value, type, name) => {
const parseValue = +value;
@@ -37,6 +40,7 @@ function Form({ setValue, parent, data, setData }) {
const validateValue = parseValue > max ? data[name].value : value;
changeData(validateValue, type, name);
};
const filteredSpe = specialties.filter((item) => item.parent);
return (
<>
@@ -67,20 +71,22 @@ function Form({ setValue, parent, data, setData }) {
/>
</ContentText>
<ContentText text="تخصص">
<AutoCompleteSelect
<Selector
updateData={changeData}
label="انتخاب کنید..."
name="expertise"
list={expertise}
list={filteredSpe}
nameKey="name"
/>
</ContentText>
<ContentText text="مدرک">
<AutoCompleteSelect
<Selector
updateData={changeData}
type="number"
// type="number"
label="انتخاب کنید..."
name="degree"
list={degree}
list={education}
nameKey="label"
/>
</ContentText>
<ContentText text="توضیحات">
@@ -110,19 +116,7 @@ function Form({ setValue, parent, data, setData }) {
</ContentText>
<FieldDate changeListData={changeData} data={data?.time_work} />
</div>
<div className="mt-[40px] w-full flex justify-end">
<Button
className="!w-full md:!w-fit !shadow-none !rounded-[4px] !gap-[4px] !text-[#EFEFEF] !text-[14px] md:!text-[16px] !font-medium"
onClick={() => setValue((prev) => prev + 1)}
disabled={!checkAllValues(data)}
variant="contained"
>
ثبت اطلاعات
<div className={!checkAllValues(data) ? "opacity-40" : "opacity-100"}>
<ArrowLeftPA />
</div>
</Button>
</div>
<SendReq setValue={setValue} data={data} />
</>
);
}
@@ -8,6 +8,11 @@ import AutoCompleteSelect from "@/app/component/element/AutoCompleteSelect";
import { useState } from "react";
import ModalMap from "./modal";
// Data
import statesData from "@/data/state.json";
import citiesData from "@/data/city.json";
import Selector from "./Selector";
const validate_phone_number = {
min: 1,
max: 9999999999,
@@ -45,19 +50,19 @@ function Form({ parent, data, setData }) {
<>
<div className="mt-[24px] grid grid-cols-1 md:grid-cols-2 gap-x-[48px] gap-y-[24px]">
<ContentText text="استان">
<AutoCompleteSelect
<Selector
updateData={changeData}
label="انتخاب کنید..."
name="state"
list={state}
list={statesData}
/>
</ContentText>
<ContentText text="شهر">
<AutoCompleteSelect
<Selector
updateData={changeData}
label="انتخاب کنید..."
name="city"
list={city}
list={citiesData}
/>
</ContentText>
<ContentText text="آدرس">
@@ -107,7 +112,7 @@ function Form({ parent, data, setData }) {
}}
/>
</ContentText>
<ContentText text="شماره مطب">
{/* <ContentText text="شماره مطب">
<EditField
isTransparent={true}
iconGray={true}
@@ -121,7 +126,7 @@ function Form({ parent, data, setData }) {
inputProps: validate_phone_number,
}}
/>
</ContentText>
</ContentText> */}
</div>
<ModalMap open={open} handleClose={handleClose} />
</>
@@ -0,0 +1,83 @@
import BottomSelect from "@/components/icons/BottomSelect";
import { Autocomplete, Button, TextField } from "@mui/material";
import { styleTextSelectRight } from "@/mui";
function Selector({ updateData, label, name, list }) {
return (
<Autocomplete
disablePortal
options={list}
getOptionLabel={(option) => option.name || ""}
// isOptionEqualToValue={(option, value) => option.id === value.id}
className="!w-full !rounded-lg auto-complete-selector "
onChange={(e, newValue) => {
if (newValue) {
updateData && updateData(newValue.id, "value", name);
}
}}
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",
},
}}
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 || option.label}
</Button>
)}
renderInput={(params) => (
<TextField
fullWidth
{...params}
InputProps={{
...params.InputProps,
endAdornment: (
<div className="absolute left-4">
<BottomSelect />
</div>
),
}}
placeholder={label}
sx={{
borderRadius: "8px",
}}
/>
)}
/>
);
}
export default Selector;
@@ -0,0 +1,64 @@
import { Button } from "@mui/material";
import ArrowLeftWhiteD from "@/components/icons/ArrowLeftWhiteD";
import { request } from "@/services/response";
import { useState } from "react";
import moment from "jalali-moment";
import { defaultState } from "../../defaultState";
const dateToTimestamp = (date) => {
const gregorianMoment = moment(date, "jYYYY/jM/jD").locale("fa");
const unixTimestamp = gregorianMoment.valueOf();
return unixTimestamp / 1000;
};
const transformData = (data) => {
return {
name: data.general.name.value,
activity_time: dateToTimestamp(data.general.time_work.value),
doctor_mobile_number: data.office.phone.value,
state: [Number(data.office.state.value)],
city: [Number(data.office.city.value)],
degree: data.general.degree.value,
specialty: [Number(data.general.expertise.value)],
info: data.general.description.value,
};
};
function SendReq({ data, isDisable, resetData }) {
const [loading, setLoading] = useState(false);
const saveData = () => {
setLoading(true);
const transformed = transformData(data);
request
.postDoctor(transformed)
.then(() => {
resetData();
setLoading(false);
})
.catch(() => {
setLoading(false);
});
};
return (
<Button
className="!gap-[4px] !w-full md:!w-fit !mr-auto !text-nowrap !flex !flex-nowrap !py-[8px]
!rounded-[4px] !text-[#EFEFEF] !text-[14px] md:!text-[16px] !font-medium
!mt-[48px] md:!mt-[44px] lg:!mt-[40px] !px-[16px] sm:!px-[19px] md:!px-[22px] lg:!px-[24px]"
disabled={isDisable}
variant="contained"
onClick={saveData}
loading={loading}
>
<p className={loading ? "opacity-0" : ""}>ثبت اطلاعات</p>
<div className={isDisable ? "opacity-40" : "opacity-100"}>
<ArrowLeftWhiteD />
</div>
</Button>
);
}
export default SendReq;
@@ -1,11 +1,10 @@
import { Button } from "@mui/material";
import List from "./List";
import ArrowLeftWhiteD from "@/components/icons/ArrowLeftWhiteD";
import { useState } from "react";
import ScrollToTop from "@/app/component/ScrollToTop";
import SendReq from "./SendReq";
function WorkingDays({ parent, data, setData }) {
const [isDisable, setIsDisable] = useState(true);
function WorkingDays({ parent, data, setData, resetData }) {
const [isDisable, setIsDisable] = useState(false);
return (
<div className="opacity-page pb-[24px]">
@@ -19,18 +18,7 @@ function WorkingDays({ parent, data, setData }) {
setData={setData}
setIsDisable={setIsDisable}
/>
<Button
className="!gap-[4px] !w-full md:!w-fit !mr-auto !text-nowrap !flex !flex-nowrap !py-[8px]
!rounded-[4px] !text-[#EFEFEF] !text-[14px] md:!text-[16px] !font-medium
!mt-[48px] md:!mt-[44px] lg:!mt-[40px] !px-[16px] sm:!px-[19px] md:!px-[22px] lg:!px-[24px]"
disabled={isDisable}
variant="contained"
>
ثبت اطلاعات
<div className={isDisable ? "opacity-40" : "opacity-100"}>
<ArrowLeftWhiteD />
</div>
</Button>
<SendReq resetData={resetData} isDisable={isDisable} data={data} />
</div>
);
}
+7
View File
@@ -0,0 +1,7 @@
[
{ "label": "دیپلم", "id": "diploma" },
{ "label": "دیپلم تحصیلات تکمیلی", "id": "postgraduate_diploma" },
{ "label": "لیسانس", "id": "bachelor_s_degree" },
{ "label": "کارشناسی ارشد", "id": "master_s_degree" },
{ "label": "دکترا", "id": "doctorate" }
]
+1
View File
@@ -59,4 +59,5 @@ export const request = {
removeTokenHead
),
postAppointment: (data) => api.post(`api/v1/appointment`, data),
postDoctor: (data) => api.post("api/v1/doctor", data),
};