humanvprojectceo commited on
Commit
8e847f1
·
verified ·
1 Parent(s): b380bf7

Update App.tsx

Browse files
Files changed (1) hide show
  1. App.tsx +55 -39
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.response?.data?.detail || "سرور موقتاً شلوغ است. لطفاً چند لحظه دیگر دوباره تلاش کنید.");
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.response?.data?.detail || "ثبت‌نام با خطا مواجه شد؛ مجدداً تلاش نمایید.");
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.response?.data?.detail || "خطا در شارژ مجدد کیف پول مالی.");
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.response?.data?.detail || "خطا در دریافت اطلاعات تقویم کاری.");
313
  }
314
  };
315
 
@@ -320,12 +340,12 @@ export default function App() {
320
  selectCounselorForBooking(selectedCounselor);
321
  fetchPayloads();
322
  } catch (err: any) {
323
- alert(err.response?.data?.detail || "موجودی کیف پول برای رزرو کافی نیست.");
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.response?.data?.detail || "خطا در ثبت پاسخنامه داوطلب.");
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(res.data.message);
352
  } catch (err: any) {
353
- alert(err.response?.data?.detail || "سرور موقتاً شلوغ است.");
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.response?.data?.detail || "هیچ پیش‌نویسی در پرونده یافت نگردید.");
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.response?.data?.detail || "سرور موقتاً شلوغ است.");
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.response?.data?.detail || "خطا در نهایی‌سازی لیست تاییدیه.");
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.response?.data?.detail || "سرور موقتاً شلوغ است.");
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.response?.data?.detail || "خطا در ایجاد نوبت دستی.");
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.response?.data?.detail || "خطا در ثبت آزمون");
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.response?.data?.detail || "سرور موقتاً شلوغ است.");
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.response?.data?.detail || "سرور موقتاً شلوغ است.");
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.response?.data?.detail || "سرور موقتاً شلوغ است.");
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-slate-800">{s.school_name}</h4>
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-850" />
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-850" />
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-850" />
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-850" />
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-700" : "text-slate-500"}`}>ویرایش اطلاعات</button>
1072
- <button onClick={() => setActiveTabSchool("B2B")} className={`text-xs font-bold pb-2 ${activeTabSchool === "B2B" ? "border-b-2 border-turquoise-700 text-turquoise-700" : "text-slate-500"}`}>اتصال همکاران (B2B)</button>
1073
- <button onClick={() => setActiveTabSchool("sponsorship")} className={`text-xs font-bold pb-2 ${activeTabSchool === "sponsorship" ? "border-b-2 border-turquoise-700 text-turquoise-700" : "text-slate-500"}`}>اشتراک و تبلیغات</button>
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"); setActiveTabSchool("B2B"); }}
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} />