Update Saqel Platform: 2026-08-28 18:21:58
This commit is contained in:
@@ -585,10 +585,54 @@ class StudentPortal
|
||||
<input type="text" id="student_otp" maxlength="6" placeholder="• • • • • •" class="input-text" style="font-size: 24px; text-align: center; letter-spacing: 8px;" onkeypress="if(event.key==='Enter') verifyStudentOtp()">
|
||||
</div>
|
||||
<button type="button" id="btn_verify_otp" onclick="verifyStudentOtp()" class="btn-primary" style="margin-bottom: 12px;">
|
||||
<span>تأكيد الرمز والدخول 🚀</span>
|
||||
<span>تأكيد الرمز 💬</span>
|
||||
</button>
|
||||
<button type="button" onclick="switchToPhoneStep()" style="width: 100%; background: transparent; border: none; color: var(--text-muted); font-size: 12px; cursor: pointer; font-weight: 600;">← تغيير رقم الهاتف</button>
|
||||
</div>
|
||||
|
||||
<!-- Step 3: Student Onboarding Form (For New Students) -->
|
||||
<div id="step_onboarding_container" style="display: none;">
|
||||
<div style="text-align: center; margin-bottom: 16px;">
|
||||
<span style="font-size: 32px;">📝</span>
|
||||
<h3 style="font-size: 16px; font-weight: 800; color: #FFF; margin-top: 6px;">استكمال بيانات الطالب 🎓</h3>
|
||||
<p style="font-size: 12px; color: var(--text-muted);">يرجى تزويدنا ببياناتك الدراسية لنخصص لك المنهاج والنتاجات التعليمية بدقة.</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">الاسم الرباعي للطالب *</label>
|
||||
<input type="text" id="onboard_student_name" placeholder="مثال: أحمد محمد علي الغويري" class="input-text">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">الصف الدراسي *</label>
|
||||
<select id="onboard_student_grade" class="input-text" style="background: var(--bg-card); color: #FFF; cursor: pointer;">
|
||||
<option value="grade_10" selected>الصف العاشر الأساسي (Grade 10)</option>
|
||||
<option value="grade_11">الأول ثانوي (Grade 11)</option>
|
||||
<option value="tawjihi_2008">توجيهي 2008 (الثانوية العامة)</option>
|
||||
<option value="grade_9">الصف التاسع الأساسي</option>
|
||||
<option value="grade_8">الصف الثامن الأساسي</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">الفرع الأكاديمي</label>
|
||||
<select id="onboard_student_stream" class="input-text" style="background: var(--bg-card); color: #FFF; cursor: pointer;">
|
||||
<option value="scientific" selected>الفرع العلمي (Scientific)</option>
|
||||
<option value="literary">الفرع الأدبي (Literary)</option>
|
||||
<option value="general">التعليم العام / الأساسي</option>
|
||||
<option value="vocational">التعليم المهني والتقني (BTEC)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">الرقم الوطني / أو رقم الجلوس (اختياري)</label>
|
||||
<input type="text" id="onboard_student_national_id" placeholder="الرقم الوطني المكون من 10 خانات" class="input-text">
|
||||
</div>
|
||||
|
||||
<button type="button" id="btn_complete_onboarding" onclick="completeStudentOnboarding()" class="btn-primary" style="margin-top: 10px;">
|
||||
<span>إتمام التسجيل وبدء التعلم 🚀</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1939,7 +1983,7 @@ class StudentPortal
|
||||
}
|
||||
}
|
||||
|
||||
async function verifyStudentOtp() {
|
||||
async function verifyStudentOtp() {
|
||||
const phone = document.getElementById('student_phone').value.trim();
|
||||
const otp = document.getElementById('student_otp').value.trim();
|
||||
if (!otp || otp.length < 4) {
|
||||
@@ -1954,11 +1998,19 @@ class StudentPortal
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok && data.status === 'success') {
|
||||
localStorage.setItem('saqel_student_jwt', data.data.token);
|
||||
localStorage.setItem('saqel_student_user', JSON.stringify(data.data.user));
|
||||
renderDashboard(data.data.user);
|
||||
initWebSocket(data.data.token);
|
||||
showLuxuryToast('أهلاً بك يا بطل! 🚀', 'تم تسجيل الدخول بنجاح.');
|
||||
const token = data.data.token;
|
||||
localStorage.setItem('saqel_student_jwt', token);
|
||||
|
||||
// Check if student needs onboarding
|
||||
const isNew = data.data.user.is_new || data.data.user.name === 'طالب جديد' || data.data.user.name === 'الطالب المتميز';
|
||||
if (isNew) {
|
||||
switchToStudentOnboarding();
|
||||
} else {
|
||||
localStorage.setItem('saqel_student_user', JSON.stringify(data.data.user));
|
||||
renderDashboard(data.data.user);
|
||||
initWebSocket(token);
|
||||
showLuxuryToast('أهلاً بك يا بطل! 🚀', 'تم تسجيل الدخول بنجاح.');
|
||||
}
|
||||
} else {
|
||||
showError(data.message || 'رمز التحقق غير صحيح أو منتهي الصلاحية');
|
||||
}
|
||||
@@ -1967,11 +2019,67 @@ class StudentPortal
|
||||
}
|
||||
}
|
||||
|
||||
function switchToStudentOnboarding() {
|
||||
document.getElementById('step_phone_container').style.display = 'none';
|
||||
document.getElementById('step_otp_container').style.display = 'none';
|
||||
document.getElementById('step_onboarding_container').style.display = 'block';
|
||||
document.getElementById('alert_box_error').style.display = 'none';
|
||||
document.getElementById('alert_box_success').style.display = 'none';
|
||||
}
|
||||
|
||||
async function completeStudentOnboarding() {
|
||||
const token = localStorage.getItem('saqel_student_jwt');
|
||||
const fullName = document.getElementById('onboard_student_name').value.trim();
|
||||
const grade = document.getElementById('onboard_student_grade').value;
|
||||
const stream = document.getElementById('onboard_student_stream').value;
|
||||
const nationalId = document.getElementById('onboard_student_national_id').value.trim();
|
||||
|
||||
if (!fullName || fullName.length < 3) {
|
||||
showError('يرجى إدخال اسم الطالب الكامل (الرباعي)');
|
||||
return;
|
||||
}
|
||||
|
||||
const btn = document.getElementById('btn_complete_onboarding');
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<span>⏳ جاري حفظ البيانات...</span>';
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/student/profile/setup', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + token
|
||||
},
|
||||
body: JSON.stringify({
|
||||
full_name: fullName,
|
||||
grade_level: grade,
|
||||
stream: stream,
|
||||
national_id: nationalId
|
||||
})
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok && data.status === 'success') {
|
||||
const u = data.user;
|
||||
localStorage.setItem('saqel_student_user', JSON.stringify(u));
|
||||
renderDashboard(u);
|
||||
initWebSocket(token);
|
||||
showLuxuryToast('تم استكمال الحساب بنجاح! 🚀', `مرحباً بك يا ${fullName}`);
|
||||
} else {
|
||||
showError(data.message || 'فشل حفظ الملف الشخصي');
|
||||
}
|
||||
} catch (e) {
|
||||
showError('تعذر الاتصال بالسيرفر أثناء حفظ البيانات');
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = '<span>إتمام التسجيل وبدء التعلم 🚀</span>';
|
||||
}
|
||||
}
|
||||
|
||||
function renderDashboard(user) {
|
||||
document.getElementById('auth_box_view').style.display = 'none';
|
||||
document.getElementById('dashboard_container').style.display = 'block';
|
||||
document.getElementById('auth_user_badge').style.display = 'flex';
|
||||
const name = user.full_name || 'طالب صَقِل';
|
||||
const name = user.full_name || user.name || 'طالب صَقِل';
|
||||
document.getElementById('header_student_name').textContent = `أهلاً، ${name}`;
|
||||
document.getElementById('dashboard_welcome_title').textContent = `أهلاً بك يا ${name} 🚀`;
|
||||
}
|
||||
@@ -1983,37 +2091,31 @@ class StudentPortal
|
||||
}
|
||||
|
||||
function switchToPhoneStep() {
|
||||
document.getElementById('step_onboarding_container').style.display = 'none';
|
||||
document.getElementById('step_otp_container').style.display = 'none';
|
||||
document.getElementById('step_phone_container').style.display = 'block';
|
||||
document.getElementById('alert_box_error').style.display = 'none';
|
||||
document.getElementById('alert_box_success').style.display = 'none';
|
||||
}
|
||||
|
||||
function showError(msg) {
|
||||
document.getElementById('alert_box_success').style.display = 'none';
|
||||
const errBox = document.getElementById('alert_box_error');
|
||||
document.getElementById('alert_error_msg').textContent = msg;
|
||||
errBox.style.display = 'block';
|
||||
}
|
||||
|
||||
function showSuccess(msg) {
|
||||
document.getElementById('alert_box_error').style.display = 'none';
|
||||
const okBox = document.getElementById('alert_box_success');
|
||||
document.getElementById('alert_success_msg').textContent = msg;
|
||||
okBox.style.display = 'block';
|
||||
}
|
||||
|
||||
async function checkStudentSession(token) {
|
||||
try {
|
||||
const res = await fetch('/api/auth/me', {
|
||||
headers: { 'Authorization': 'Bearer ' + token }
|
||||
});
|
||||
if (res.status === 401) {
|
||||
handleLogout();
|
||||
return;
|
||||
}
|
||||
const data = await res.json();
|
||||
if (res.ok && data.data) {
|
||||
renderDashboard(data.data.user || data.data);
|
||||
} else {
|
||||
// Token invalid or database was reset: clear cached session
|
||||
handleLogout();
|
||||
const user = data.data;
|
||||
if (!user.is_completed) {
|
||||
switchToStudentOnboarding();
|
||||
} else {
|
||||
localStorage.setItem('saqel_student_user', JSON.stringify(user));
|
||||
renderDashboard(user);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Student session check error:', e);
|
||||
|
||||
Reference in New Issue
Block a user