Spaces:
Sleeping
Sleeping
Update App.tsx
Browse files
App.tsx
CHANGED
|
@@ -37,6 +37,25 @@ const INTRO_SLIDES = [
|
|
| 37 |
}
|
| 38 |
];
|
| 39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
interface WelcomeScreenProps {
|
| 41 |
onStart: () => void;
|
| 42 |
}
|
|
@@ -170,7 +189,7 @@ export default function App() {
|
|
| 170 |
const [searchResults, setSearchResults] = useState<any[]>([]);
|
| 171 |
const [activeTabSchool, setActiveTabSchool] = useState("portfolio"); // 'portfolio', 'B2B', 'sponsorship'
|
| 172 |
|
| 173 |
-
//
|
| 174 |
useEffect(() => {
|
| 175 |
const storedToken = localStorage.getItem("token");
|
| 176 |
const storedRole = localStorage.getItem("userRole");
|
|
@@ -184,6 +203,7 @@ export default function App() {
|
|
| 184 |
setUserProfile(res.data);
|
| 185 |
setUserBalance(res.data.balance);
|
| 186 |
|
|
|
|
| 187 |
if (res.data.role === "student") {
|
| 188 |
setCurrentScreen("student_dashboard");
|
| 189 |
} else if (res.data.role === "counselor") {
|
|
@@ -266,8 +286,8 @@ export default function App() {
|
|
| 266 |
}
|
| 267 |
else if (role === "school_representative") setCurrentScreen("school_dashboard");
|
| 268 |
} catch (err: any) {
|
| 269 |
-
// استفاده دا
|
| 270 |
-
setErrorMessage(err
|
| 271 |
}
|
| 272 |
};
|
| 273 |
|
|
@@ -279,9 +299,9 @@ export default function App() {
|
|
| 279 |
email, password, role, name, specialty, resume, hourly_rate: Number(hourlyRate), phone_number: phone, city
|
| 280 |
});
|
| 281 |
setCurrentScreen("login");
|
| 282 |
-
alert("ثبتنام با موفقیت انجام شد. اکنون وارد
|
| 283 |
} catch (err: any) {
|
| 284 |
-
setErrorMessage(err
|
| 285 |
}
|
| 286 |
};
|
| 287 |
|
|
@@ -297,9 +317,9 @@ export default function App() {
|
|
| 297 |
try {
|
| 298 |
const res = await axios.post(`${API_BASE_URL}/api/student/topup`, { amount: 150000 });
|
| 299 |
setUserBalance(res.data.new_balance);
|
| 300 |
-
alert("حساب با موفقیت شارژ گردید.");
|
| 301 |
} catch (err: any) {
|
| 302 |
-
alert(err
|
| 303 |
}
|
| 304 |
};
|
| 305 |
|
|
@@ -309,7 +329,7 @@ export default function App() {
|
|
| 309 |
const res = await axios.get(`${API_BASE_URL}/api/counselors/${counselor.counselor_id}/slots`);
|
| 310 |
setCounselorSlots(res.data);
|
| 311 |
} catch (err: any) {
|
| 312 |
-
alert(err
|
| 313 |
}
|
| 314 |
};
|
| 315 |
|
|
@@ -320,12 +340,12 @@ export default function App() {
|
|
| 320 |
selectCounselorForBooking(selectedCounselor);
|
| 321 |
fetchPayloads();
|
| 322 |
} catch (err: any) {
|
| 323 |
-
alert(err
|
| 324 |
}
|
| 325 |
};
|
| 326 |
|
| 327 |
const handleSubmitTest = async () => {
|
| 328 |
-
if (!selectedCounselor) return alert("یک مشاور را
|
| 329 |
try {
|
| 330 |
const res = await axios.post(`${API_BASE_URL}/api/student/test/submit`, {
|
| 331 |
counselor_id: selectedCounselor.counselor_id,
|
|
@@ -334,12 +354,12 @@ export default function App() {
|
|
| 334 |
alert(res.data.message);
|
| 335 |
setCurrentScreen("student_dashboard");
|
| 336 |
} catch (err: any) {
|
| 337 |
-
alert(err
|
| 338 |
}
|
| 339 |
};
|
| 340 |
|
| 341 |
const handleKonkurSubmit = async () => {
|
| 342 |
-
if (!selectedCounselor) return alert("ا
|
| 343 |
try {
|
| 344 |
const res = await axios.post(`${API_BASE_URL}/api/selection/select`, {
|
| 345 |
rank: Number(rank),
|
|
@@ -348,9 +368,9 @@ export default function App() {
|
|
| 348 |
counselor_id: selectedCounselor.counselor_id
|
| 349 |
});
|
| 350 |
setAiChoices(res.data.selections);
|
| 351 |
-
alert(
|
| 352 |
} catch (err: any) {
|
| 353 |
-
alert(err
|
| 354 |
}
|
| 355 |
};
|
| 356 |
|
|
@@ -360,7 +380,7 @@ export default function App() {
|
|
| 360 |
setMajorSelection(res.data);
|
| 361 |
setCurrentScreen("selection_view");
|
| 362 |
} catch (err: any) {
|
| 363 |
-
alert(err
|
| 364 |
}
|
| 365 |
};
|
| 366 |
|
|
@@ -378,11 +398,11 @@ export default function App() {
|
|
| 378 |
start_time: newSlotStart,
|
| 379 |
end_time: newSlotEnd
|
| 380 |
}]);
|
| 381 |
-
alert("
|
| 382 |
setNewSlotStart("");
|
| 383 |
setNewSlotEnd("");
|
| 384 |
} catch (err: any) {
|
| 385 |
-
alert(err
|
| 386 |
}
|
| 387 |
};
|
| 388 |
|
|
@@ -391,25 +411,23 @@ export default function App() {
|
|
| 391 |
await axios.put(`${API_BASE_URL}/api/selection/${selectionId}/approve`, {
|
| 392 |
finalized_list_json: JSON.stringify(updatedList)
|
| 393 |
});
|
| 394 |
-
alert("
|
| 395 |
fetchCounselorDashboard();
|
| 396 |
} catch (err: any) {
|
| 397 |
-
alert(err
|
| 398 |
}
|
| 399 |
};
|
| 400 |
|
| 401 |
-
// --- ارتقای هوش مصنوعی رزومه مشاور ---
|
| 402 |
const handleExtractBio = async () => {
|
| 403 |
try {
|
| 404 |
const res = await axios.post(`${API_BASE_URL}/api/counselor/extract-bio`, { resume_text: resume });
|
| 405 |
setAiChoicesExtracted(res.data.extracted_bio);
|
| 406 |
alert("بیوگرافی با موفقیت استخراج شد؛ در صورت نیاز آن را ویرایش نمایید.");
|
| 407 |
} catch (err: any) {
|
| 408 |
-
alert(err
|
| 409 |
}
|
| 410 |
};
|
| 411 |
|
| 412 |
-
// --- نوبتدهی دستی با صورتحساب ۲۴ ساعته توسط مشاور ---
|
| 413 |
const handleManualBooking = async () => {
|
| 414 |
if (!selectedStudentForManual || !manualTime) return alert("تمام فیلدها الزامی است.");
|
| 415 |
try {
|
|
@@ -424,11 +442,10 @@ export default function App() {
|
|
| 424 |
alert("نوبت با موفقیت رزرو و صورتحساب ۲۴ ساعته برای داوطلب صادر گردید.");
|
| 425 |
fetchCounselorDashboard();
|
| 426 |
} catch (err: any) {
|
| 427 |
-
alert(err
|
| 428 |
}
|
| 429 |
};
|
| 430 |
|
| 431 |
-
// --- طراحی آزمون گزینهای در مشاور ---
|
| 432 |
const handleAddQuestionField = () => {
|
| 433 |
setQuestions([...questions, { question: "", option1: "", option2: "", option3: "", option4: "", correct: "1" }]);
|
| 434 |
};
|
|
@@ -449,11 +466,10 @@ export default function App() {
|
|
| 449 |
setQuizTitle("");
|
| 450 |
setQuestions([{ question: "", option1: "", option2: "", option3: "", option4: "", correct: "1" }]);
|
| 451 |
} catch (err: any) {
|
| 452 |
-
alert(err
|
| 453 |
}
|
| 454 |
};
|
| 455 |
|
| 456 |
-
// --- عملیات آموزشگاه مجهز به متدهای داینامیک ---
|
| 457 |
const handleAddCourseField = () => {
|
| 458 |
setCourses([...courses, { course_name: "", teacher_name: "", teaching_style: "" }]);
|
| 459 |
};
|
|
@@ -476,7 +492,7 @@ export default function App() {
|
|
| 476 |
});
|
| 477 |
alert("پروفایل آموزشگاه با موفقیت به روزرسانی شد.");
|
| 478 |
} catch (err: any) {
|
| 479 |
-
alert(err
|
| 480 |
}
|
| 481 |
};
|
| 482 |
|
|
@@ -485,7 +501,7 @@ export default function App() {
|
|
| 485 |
const res = await axios.get(`${API_BASE_URL}/api/schools?name=${searchCourse}&city=${searchSchoolCity}`);
|
| 486 |
setSearchResults(res.data);
|
| 487 |
} catch (err: any) {
|
| 488 |
-
alert(err
|
| 489 |
}
|
| 490 |
};
|
| 491 |
|
|
@@ -494,7 +510,7 @@ export default function App() {
|
|
| 494 |
await axios.post(`${API_BASE_URL}/api/schools/purchase-ad`);
|
| 495 |
alert("با موفقیت به آموزشگاه ویژه ارتقا یافتید و به صدر جدول فرستاده شدید.");
|
| 496 |
} catch (err: any) {
|
| 497 |
-
alert(err
|
| 498 |
}
|
| 499 |
};
|
| 500 |
|
|
@@ -815,7 +831,7 @@ export default function App() {
|
|
| 815 |
{s.is_sponsored && (
|
| 816 |
<span className="absolute top-3 left-3 bg-amberGold-500 text-white text-[8px] font-black py-0.5 px-2 rounded-full shadow-sm">ویژه اسپانسر</span>
|
| 817 |
)}
|
| 818 |
-
<h4 className="text-xs font-black text-
|
| 819 |
<p className="text-[10px] text-slate-500">{s.bio || "آموزشگاه برتر فعال"}</p>
|
| 820 |
<p className="text-[10px] text-slate-400">سال تاسیس: {s.founding_year || "۱۳۹۸"} | آدرس: {s.address || "بخش مرکزی"}</p>
|
| 821 |
<div className="space-y-1">
|
|
@@ -1027,10 +1043,10 @@ export default function App() {
|
|
| 1027 |
<span className="font-bold text-turquoise-700">سوال شماره {idx + 1}:</span>
|
| 1028 |
<input type="text" placeholder="متن سوال چند گزینهای" value={q.question} onChange={(e) => handleQuestionChange(idx, "question", e.target.value)} className="w-full p-2 border border-slate-200 rounded bg-white text-slate-800" />
|
| 1029 |
<div className="grid grid-cols-2 gap-2">
|
| 1030 |
-
<input type="text" placeholder="گزینه ۱" value={q.option1} onChange={(e) => handleQuestionChange(idx, "option1", e.target.value)} className="p-1 border border-slate-200 rounded bg-white text-slate-
|
| 1031 |
-
<input type="text" placeholder="گزینه ۲" value={q.option2} onChange={(e) => handleQuestionChange(idx, "option2", e.target.value)} className="p-1 border border-slate-200 rounded bg-white text-slate-
|
| 1032 |
-
<input type="text" placeholder="گزینه ۳" value={q.option3} onChange={(e) => handleQuestionChange(idx, "option3", e.target.value)} className="p-1 border border-slate-200 rounded bg-white text-slate-
|
| 1033 |
-
<input type="text" placeholder="گزینه ۴" value={q.option4} onChange={(e) => handleQuestionChange(idx, "option4", e.target.value)} className="p-1 border border-slate-200 rounded bg-white text-slate-
|
| 1034 |
</div>
|
| 1035 |
</div>
|
| 1036 |
))}
|
|
@@ -1068,9 +1084,9 @@ export default function App() {
|
|
| 1068 |
{currentScreen === "school_dashboard" && (
|
| 1069 |
<div className="space-y-6 animate-screen">
|
| 1070 |
<div className="flex justify-between border-b border-slate-200 pb-2">
|
| 1071 |
-
<button onClick={() => setActiveTabSchool("portfolio")} className={`text-xs font-bold pb-2 ${activeTabSchool === "portfolio" ? "border-b-2 border-turquoise-700 text-turquoise-
|
| 1072 |
-
<button onClick={() => setActiveTabSchool("B2B")} className={`text-xs font-bold pb-2 ${activeTabSchool === "B2B" ? "border-b-2 border-turquoise-700 text-turquoise-
|
| 1073 |
-
<button onClick={() => setActiveTabSchool("sponsorship")} className={`text-xs font-bold pb-2 ${activeTabSchool === "sponsorship" ? "border-b-2 border-turquoise-700 text-turquoise-
|
| 1074 |
</div>
|
| 1075 |
|
| 1076 |
{activeTabSchool === "portfolio" && (
|
|
@@ -1148,7 +1164,7 @@ export default function App() {
|
|
| 1148 |
|
| 1149 |
</main>
|
| 1150 |
|
| 1151 |
-
{/* منوی شناور پایینی
|
| 1152 |
{showBottomNav && (
|
| 1153 |
<div className="fixed bottom-4 left-4 right-4 max-w-md mx-auto bg-white/95 backdrop-blur-md rounded-2xl py-2 px-3 shadow-2xl border border-slate-200/80 flex justify-around items-center z-50 animate-screen">
|
| 1154 |
|
|
@@ -1208,7 +1224,7 @@ export default function App() {
|
|
| 1208 |
</button>
|
| 1209 |
|
| 1210 |
<button
|
| 1211 |
-
onClick={() => { setCurrentScreen("counselor_dashboard");
|
| 1212 |
className={`flex flex-col items-center gap-1 p-2 rounded-xl transition-all ${currentScreen === "counselor_dashboard" && activeTabCounselor === "quizzes" ? "bg-slate-100 text-turquoise-700" : "text-slate-500 hover:text-slate-800"}`}
|
| 1213 |
>
|
| 1214 |
<FileText size={18} />
|
|
|
|
| 37 |
}
|
| 38 |
];
|
| 39 |
|
| 40 |
+
// متد کمکی و هوشمند استخراج و تحلیل جزییات دقیق خطاهای سرور
|
| 41 |
+
const getErrorMessage = (err: any, defaultMsg: string): string => {
|
| 42 |
+
console.error("API Error Captured:", err);
|
| 43 |
+
if (err.response) {
|
| 44 |
+
const data = err.response.data;
|
| 45 |
+
if (data) {
|
| 46 |
+
if (typeof data.detail === 'string') {
|
| 47 |
+
return data.detail; // بازگرداندن خطای مستقیم صادر شده (مانند کلمه عبور اشتباه است)
|
| 48 |
+
} else if (Array.isArray(data.detail)) {
|
| 49 |
+
// بازگرداندن و چسباندن خطاهای ولیدیشن ورودیها به صورت تفکیک شده
|
| 50 |
+
return data.detail.map((d: any) => d.msg).join(" - ");
|
| 51 |
+
} else if (data.message) {
|
| 52 |
+
return data.message;
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
return err.message || defaultMsg;
|
| 57 |
+
};
|
| 58 |
+
|
| 59 |
interface WelcomeScreenProps {
|
| 60 |
onStart: () => void;
|
| 61 |
}
|
|
|
|
| 189 |
const [searchResults, setSearchResults] = useState<any[]>([]);
|
| 190 |
const [activeTabSchool, setActiveTabSchool] = useState("portfolio"); // 'portfolio', 'B2B', 'sponsorship'
|
| 191 |
|
| 192 |
+
// بررسی احراز هویت خودکار (Auto-Login Check) در بدو ورود به اپلیکیشن
|
| 193 |
useEffect(() => {
|
| 194 |
const storedToken = localStorage.getItem("token");
|
| 195 |
const storedRole = localStorage.getItem("userRole");
|
|
|
|
| 203 |
setUserProfile(res.data);
|
| 204 |
setUserBalance(res.data.balance);
|
| 205 |
|
| 206 |
+
// هدایت مستقیم به داشبورد مربوطه بدون نمایش صفحه لاگین
|
| 207 |
if (res.data.role === "student") {
|
| 208 |
setCurrentScreen("student_dashboard");
|
| 209 |
} else if (res.data.role === "counselor") {
|
|
|
|
| 286 |
}
|
| 287 |
else if (role === "school_representative") setCurrentScreen("school_dashboard");
|
| 288 |
} catch (err: any) {
|
| 289 |
+
// استفاده هوشمند از متد کمکی استخراج جزییات دقیق خطای ورودی
|
| 290 |
+
setErrorMessage(getErrorMessage(err, "سرور موقتاً شلوغ است. لطفاً چند لحظه دیگر دوباره تلاش کنید."));
|
| 291 |
}
|
| 292 |
};
|
| 293 |
|
|
|
|
| 299 |
email, password, role, name, specialty, resume, hourly_rate: Number(hourlyRate), phone_number: phone, city
|
| 300 |
});
|
| 301 |
setCurrentScreen("login");
|
| 302 |
+
alert("ثبتنام با موفقیت انجام شد. اکنون وارد شوید.");
|
| 303 |
} catch (err: any) {
|
| 304 |
+
setErrorMessage(getErrorMessage(err, "ثبتنام با خطا مواجه شد؛ مجدداً تلاش نمایید."));
|
| 305 |
}
|
| 306 |
};
|
| 307 |
|
|
|
|
| 317 |
try {
|
| 318 |
const res = await axios.post(`${API_BASE_URL}/api/student/topup`, { amount: 150000 });
|
| 319 |
setUserBalance(res.data.new_balance);
|
| 320 |
+
alert("تراز حساب مالی شما با موفقیت شارژ گردید.");
|
| 321 |
} catch (err: any) {
|
| 322 |
+
alert(getErrorMessage(err, "سرور موقتاً شلوغ است."));
|
| 323 |
}
|
| 324 |
};
|
| 325 |
|
|
|
|
| 329 |
const res = await axios.get(`${API_BASE_URL}/api/counselors/${counselor.counselor_id}/slots`);
|
| 330 |
setCounselorSlots(res.data);
|
| 331 |
} catch (err: any) {
|
| 332 |
+
alert(getErrorMessage(err, "لود اطلاعات تقویم امکانپذیر نیست."));
|
| 333 |
}
|
| 334 |
};
|
| 335 |
|
|
|
|
| 340 |
selectCounselorForBooking(selectedCounselor);
|
| 341 |
fetchPayloads();
|
| 342 |
} catch (err: any) {
|
| 343 |
+
alert(getErrorMessage(err, "موجودی کیف پول شما کافی نیست. لطفا ابتدا اقدام به شارژ نمایید."));
|
| 344 |
}
|
| 345 |
};
|
| 346 |
|
| 347 |
const handleSubmitTest = async () => {
|
| 348 |
+
if (!selectedCounselor) return alert("ابتدا یک مشاور فعال را گزینش کنید.");
|
| 349 |
try {
|
| 350 |
const res = await axios.post(`${API_BASE_URL}/api/student/test/submit`, {
|
| 351 |
counselor_id: selectedCounselor.counselor_id,
|
|
|
|
| 354 |
alert(res.data.message);
|
| 355 |
setCurrentScreen("student_dashboard");
|
| 356 |
} catch (err: any) {
|
| 357 |
+
alert(getErrorMessage(err, "سرور موقتاً شلوغ است. بعداً تلاش کنید."));
|
| 358 |
}
|
| 359 |
};
|
| 360 |
|
| 361 |
const handleKonkurSubmit = async () => {
|
| 362 |
+
if (!selectedCounselor) return alert("انتخاب مشاور برای رهگیری نهایی الزامی است.");
|
| 363 |
try {
|
| 364 |
const res = await axios.post(`${API_BASE_URL}/api/selection/select`, {
|
| 365 |
rank: Number(rank),
|
|
|
|
| 368 |
counselor_id: selectedCounselor.counselor_id
|
| 369 |
});
|
| 370 |
setAiChoices(res.data.selections);
|
| 371 |
+
alert("پردازش اطلاعات با موفقیت انجام شد.");
|
| 372 |
} catch (err: any) {
|
| 373 |
+
alert(getErrorMessage(err, "سرور موقتاً شلوغ است. بعداً تلاش کنید."));
|
| 374 |
}
|
| 375 |
};
|
| 376 |
|
|
|
|
| 380 |
setMajorSelection(res.data);
|
| 381 |
setCurrentScreen("selection_view");
|
| 382 |
} catch (err: any) {
|
| 383 |
+
alert(getErrorMessage(err, "پرونده ثبتی برای شما یافت نگردید."));
|
| 384 |
}
|
| 385 |
};
|
| 386 |
|
|
|
|
| 398 |
start_time: newSlotStart,
|
| 399 |
end_time: newSlotEnd
|
| 400 |
}]);
|
| 401 |
+
alert("زمان جدید با موفقیت در تقویم ذخیره شد.");
|
| 402 |
setNewSlotStart("");
|
| 403 |
setNewSlotEnd("");
|
| 404 |
} catch (err: any) {
|
| 405 |
+
alert(getErrorMessage(err, "سرور موقتاً شلوغ است. بعداً تلاش کنید."));
|
| 406 |
}
|
| 407 |
};
|
| 408 |
|
|
|
|
| 411 |
await axios.put(`${API_BASE_URL}/api/selection/${selectionId}/approve`, {
|
| 412 |
finalized_list_json: JSON.stringify(updatedList)
|
| 413 |
});
|
| 414 |
+
alert("پرونده داوطلب با موفقیت ثبت و نهایی شد.");
|
| 415 |
fetchCounselorDashboard();
|
| 416 |
} catch (err: any) {
|
| 417 |
+
alert(getErrorMessage(err, "خطا در نهاییسازی لیست تاییدیه."));
|
| 418 |
}
|
| 419 |
};
|
| 420 |
|
|
|
|
| 421 |
const handleExtractBio = async () => {
|
| 422 |
try {
|
| 423 |
const res = await axios.post(`${API_BASE_URL}/api/counselor/extract-bio`, { resume_text: resume });
|
| 424 |
setAiChoicesExtracted(res.data.extracted_bio);
|
| 425 |
alert("بیوگرافی با موفقیت استخراج شد؛ در صورت نیاز آن را ویرایش نمایید.");
|
| 426 |
} catch (err: any) {
|
| 427 |
+
alert(getErrorMessage(err, "سرور موقتاً شلوغ است."));
|
| 428 |
}
|
| 429 |
};
|
| 430 |
|
|
|
|
| 431 |
const handleManualBooking = async () => {
|
| 432 |
if (!selectedStudentForManual || !manualTime) return alert("تمام فیلدها الزامی است.");
|
| 433 |
try {
|
|
|
|
| 442 |
alert("نوبت با موفقیت رزرو و صورتحساب ۲۴ ساعته برای داوطلب صادر گردید.");
|
| 443 |
fetchCounselorDashboard();
|
| 444 |
} catch (err: any) {
|
| 445 |
+
alert(getErrorMessage(err, "خطا در ایجاد نوبت دستی."));
|
| 446 |
}
|
| 447 |
};
|
| 448 |
|
|
|
|
| 449 |
const handleAddQuestionField = () => {
|
| 450 |
setQuestions([...questions, { question: "", option1: "", option2: "", option3: "", option4: "", correct: "1" }]);
|
| 451 |
};
|
|
|
|
| 466 |
setQuizTitle("");
|
| 467 |
setQuestions([{ question: "", option1: "", option2: "", option3: "", option4: "", correct: "1" }]);
|
| 468 |
} catch (err: any) {
|
| 469 |
+
alert(getErrorMessage(err, "خطا در ثبت آزمون"));
|
| 470 |
}
|
| 471 |
};
|
| 472 |
|
|
|
|
| 473 |
const handleAddCourseField = () => {
|
| 474 |
setCourses([...courses, { course_name: "", teacher_name: "", teaching_style: "" }]);
|
| 475 |
};
|
|
|
|
| 492 |
});
|
| 493 |
alert("پروفایل آموزشگاه با موفقیت به روزرسانی شد.");
|
| 494 |
} catch (err: any) {
|
| 495 |
+
alert(getErrorMessage(err, "سرور موقتاً شلوغ است."));
|
| 496 |
}
|
| 497 |
};
|
| 498 |
|
|
|
|
| 501 |
const res = await axios.get(`${API_BASE_URL}/api/schools?name=${searchCourse}&city=${searchSchoolCity}`);
|
| 502 |
setSearchResults(res.data);
|
| 503 |
} catch (err: any) {
|
| 504 |
+
alert(getErrorMessage(err, "سرور موقتاً شلوغ است."));
|
| 505 |
}
|
| 506 |
};
|
| 507 |
|
|
|
|
| 510 |
await axios.post(`${API_BASE_URL}/api/schools/purchase-ad`);
|
| 511 |
alert("با موفقیت به آموزشگاه ویژه ارتقا یافتید و به صدر جدول فرستاده شدید.");
|
| 512 |
} catch (err: any) {
|
| 513 |
+
alert(getErrorMessage(err, "سرور موقتاً شلوغ است."));
|
| 514 |
}
|
| 515 |
};
|
| 516 |
|
|
|
|
| 831 |
{s.is_sponsored && (
|
| 832 |
<span className="absolute top-3 left-3 bg-amberGold-500 text-white text-[8px] font-black py-0.5 px-2 rounded-full shadow-sm">ویژه اسپانسر</span>
|
| 833 |
)}
|
| 834 |
+
<h4 className="text-xs font-black text-white">{s.school_name}</h4>
|
| 835 |
<p className="text-[10px] text-slate-500">{s.bio || "آموزشگاه برتر فعال"}</p>
|
| 836 |
<p className="text-[10px] text-slate-400">سال تاسیس: {s.founding_year || "۱۳۹۸"} | آدرس: {s.address || "بخش مرکزی"}</p>
|
| 837 |
<div className="space-y-1">
|
|
|
|
| 1043 |
<span className="font-bold text-turquoise-700">سوال شماره {idx + 1}:</span>
|
| 1044 |
<input type="text" placeholder="متن سوال چند گزینهای" value={q.question} onChange={(e) => handleQuestionChange(idx, "question", e.target.value)} className="w-full p-2 border border-slate-200 rounded bg-white text-slate-800" />
|
| 1045 |
<div className="grid grid-cols-2 gap-2">
|
| 1046 |
+
<input type="text" placeholder="گزینه ۱" value={q.option1} onChange={(e) => handleQuestionChange(idx, "option1", e.target.value)} className="p-1 border border-slate-200 rounded bg-white text-slate-855" />
|
| 1047 |
+
<input type="text" placeholder="گزینه ۲" value={q.option2} onChange={(e) => handleQuestionChange(idx, "option2", e.target.value)} className="p-1 border border-slate-200 rounded bg-white text-slate-855" />
|
| 1048 |
+
<input type="text" placeholder="گزینه ۳" value={q.option3} onChange={(e) => handleQuestionChange(idx, "option3", e.target.value)} className="p-1 border border-slate-200 rounded bg-white text-slate-855" />
|
| 1049 |
+
<input type="text" placeholder="گزینه ۴" value={q.option4} onChange={(e) => handleQuestionChange(idx, "option4", e.target.value)} className="p-1 border border-slate-200 rounded bg-white text-slate-855" />
|
| 1050 |
</div>
|
| 1051 |
</div>
|
| 1052 |
))}
|
|
|
|
| 1084 |
{currentScreen === "school_dashboard" && (
|
| 1085 |
<div className="space-y-6 animate-screen">
|
| 1086 |
<div className="flex justify-between border-b border-slate-200 pb-2">
|
| 1087 |
+
<button onClick={() => setActiveTabSchool("portfolio")} className={`text-xs font-bold pb-2 ${activeTabSchool === "portfolio" ? "border-b-2 border-turquoise-700 text-turquoise-750" : "text-slate-500"}`}>ویرایش اطلاعات</button>
|
| 1088 |
+
<button onClick={() => setActiveTabSchool("B2B")} className={`text-xs font-bold pb-2 ${activeTabSchool === "B2B" ? "border-b-2 border-turquoise-700 text-turquoise-750" : "text-slate-500"}`}>اتصال همکاران (B2B)</button>
|
| 1089 |
+
<button onClick={() => setActiveTabSchool("sponsorship")} className={`text-xs font-bold pb-2 ${activeTabSchool === "sponsorship" ? "border-b-2 border-turquoise-700 text-turquoise-750" : "text-slate-500"}`}>اشتراک و تبلیغات</button>
|
| 1090 |
</div>
|
| 1091 |
|
| 1092 |
{activeTabSchool === "portfolio" && (
|
|
|
|
| 1164 |
|
| 1165 |
</main>
|
| 1166 |
|
| 1167 |
+
{/* منوی شناور پایینی لوکس مجهز به نشانگر نوتیفیکیشن عددی */}
|
| 1168 |
{showBottomNav && (
|
| 1169 |
<div className="fixed bottom-4 left-4 right-4 max-w-md mx-auto bg-white/95 backdrop-blur-md rounded-2xl py-2 px-3 shadow-2xl border border-slate-200/80 flex justify-around items-center z-50 animate-screen">
|
| 1170 |
|
|
|
|
| 1224 |
</button>
|
| 1225 |
|
| 1226 |
<button
|
| 1227 |
+
onClick={() => { setCurrentScreen("counselor_dashboard"); setActiveTabCounselor("quizzes"); }}
|
| 1228 |
className={`flex flex-col items-center gap-1 p-2 rounded-xl transition-all ${currentScreen === "counselor_dashboard" && activeTabCounselor === "quizzes" ? "bg-slate-100 text-turquoise-700" : "text-slate-500 hover:text-slate-800"}`}
|
| 1229 |
>
|
| 1230 |
<FileText size={18} />
|