With the backend now returning 200 (lazy-created profile) instead of 404, align the consumers: the profile lives at res.data.data (the endpoint double-nests), so the booking detail and dashboard read that instead of res.data / the raw envelope. Drop the obsolete 404 special handling (empty editable form now comes from the 200 payload), seed the dashboard empty state when the profile has no real data yet, and make the profile POST fall back to PATCH on 409 (already lazy-created). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
172 lines
5.5 KiB
JavaScript
172 lines
5.5 KiB
JavaScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { request } from "@/services/response";
|
|
import Cookies from "js-cookie";
|
|
import Container from "./Container";
|
|
import { safeJsonParse } from "@/lib/sanitize";
|
|
|
|
const defaultData = {
|
|
phone: { value: "", isEdit: false },
|
|
national_code: { value: "", isEdit: true },
|
|
name: { value: "", isEdit: true },
|
|
family: { value: "", isEdit: true },
|
|
gender: { value: "", isEdit: true },
|
|
insurance_id: { value: "", isEdit: true },
|
|
basic_insurance: { value: "", isEdit: true },
|
|
supplementary_insurance: { value: "", isEdit: true },
|
|
};
|
|
|
|
function buildProfileData(profile, phone) {
|
|
return {
|
|
uuid: profile.uuid,
|
|
phone: { value: phone, isEdit: false },
|
|
national_code: {
|
|
value: profile.national_code || "",
|
|
isEdit: profile.national_code ? false : true,
|
|
},
|
|
name: { value: profile.name || "", isEdit: true },
|
|
family: { value: profile.family || "", isEdit: true },
|
|
gender: {
|
|
value: profile.gender
|
|
? { id: profile.gender, title: profile.gender === "male" ? "مرد" : "زن" }
|
|
: "",
|
|
isEdit: true,
|
|
},
|
|
insurance_id: { value: profile.insurance_id || "", isEdit: true },
|
|
basic_insurance: { value: profile.basic_insurance, isEdit: true },
|
|
supplementary_insurance: { value: profile.supplementary_insurance, isEdit: true },
|
|
};
|
|
}
|
|
|
|
function AppointmentPage({ doctor, disabledDates, matchedCity }) {
|
|
const [step, setStep] = useState(0);
|
|
const [isForAnother, setIsForAnother] = useState(false);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
const [prevData, setPrevData] = useState(defaultData);
|
|
const [data, setData] = useState(defaultData);
|
|
|
|
// Login states
|
|
const [num, setNum] = useState("");
|
|
const [uuid, setUuid] = useState("");
|
|
const [isSendMsg, setIsSendMsg] = useState(false);
|
|
|
|
// Appointment slot states
|
|
const [selectedSlot, setSelectedSlot] = useState(null);
|
|
const [selectedDate, setSelectedDate] = useState(null);
|
|
const [appointmentId, setAppointmentId] = useState(null);
|
|
const [appointmentExpiresAt, setAppointmentExpiresAt] = useState(null);
|
|
|
|
useEffect(() => {
|
|
const fetchUserData = async () => {
|
|
setIsLoading(true);
|
|
|
|
const userInfo = Cookies.get("userInfo");
|
|
const parsedData = safeJsonParse(userInfo);
|
|
const usernameFromCookie = parsedData?.username || "";
|
|
|
|
// ابتدا شماره موبایل را از Cookie ست میکنیم
|
|
if (usernameFromCookie) {
|
|
setData(prev => ({
|
|
...prev,
|
|
phone: { value: usernameFromCookie, isEdit: false },
|
|
}));
|
|
}
|
|
|
|
// سپس اگر uuid داریم، بقیه اطلاعات را از API میگیریم
|
|
if (userInfo && parsedData) {
|
|
try {
|
|
const res = await request.getUserProfile(parsedData.uuid);
|
|
const profile = res?.data?.data;
|
|
|
|
if (profile) {
|
|
const newData = buildProfileData(profile, usernameFromCookie);
|
|
setData(newData);
|
|
setPrevData(newData);
|
|
}
|
|
} catch (error) {
|
|
// در صورت خطا، شماره موبایل حفظ میشود و بقیه فیلدها قابل ویرایش میمانند
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
} else {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchUserData();
|
|
}, []); // فقط یک بار در mount اولیه اجرا میشه
|
|
|
|
// useEffect جداگانه برای زمانی که step تغییر میکنه
|
|
useEffect(() => {
|
|
const refetchUserData = async () => {
|
|
if (step === 3) {
|
|
const userInfo = Cookies.get("userInfo");
|
|
const parsedData = safeJsonParse(userInfo);
|
|
const usernameFromCookie = parsedData?.username || "";
|
|
|
|
if (userInfo && parsedData && !data.uuid) {
|
|
try {
|
|
const res = await request.getUserProfile(parsedData.uuid);
|
|
const profile = res?.data?.data;
|
|
|
|
if (profile) {
|
|
const newData = buildProfileData(profile, usernameFromCookie);
|
|
setData(newData);
|
|
setPrevData(newData);
|
|
}
|
|
} catch (error) {
|
|
// در صورت خطا، فرم خالی قابل ویرایش باقی میماند
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
refetchUserData();
|
|
}, [step]);
|
|
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="flex items-center justify-center min-h-screen">
|
|
<div className="flex flex-col items-center gap-4">
|
|
<div className="w-12 h-12 border-4 border-[#5559CE] border-t-transparent rounded-full animate-spin"></div>
|
|
<p className="text-[#3B3B3B] text-[16px]">در حال بارگذاری...</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Container
|
|
step={step}
|
|
data={data}
|
|
doctor={doctor}
|
|
setData={setData}
|
|
setStep={setStep}
|
|
prevData={prevData}
|
|
matchedCity={matchedCity}
|
|
isForAnother={isForAnother}
|
|
setIsForAnother={setIsForAnother}
|
|
disabledDates={disabledDates}
|
|
num={num}
|
|
setNum={setNum}
|
|
uuid={uuid}
|
|
setUuid={setUuid}
|
|
isSendMsg={isSendMsg}
|
|
setIsSendMsg={setIsSendMsg}
|
|
selectedSlot={selectedSlot}
|
|
setSelectedSlot={setSelectedSlot}
|
|
selectedDate={selectedDate}
|
|
setSelectedDate={setSelectedDate}
|
|
appointmentId={appointmentId}
|
|
setAppointmentId={setAppointmentId}
|
|
appointmentExpiresAt={appointmentExpiresAt}
|
|
setAppointmentExpiresAt={setAppointmentExpiresAt}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export default AppointmentPage;
|