| <!DOCTYPE html> |
| <html lang="ro"> |
| <head> |
| <link rel="icon" type="image/svg+xml" href="favicon.svg"> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> |
| <title>IDEA | Resetare Parolă</title> |
| <link rel="stylesheet" href="style.css"> |
| <script src="errors.js"></script> |
| <style> |
| body { display:flex; flex-direction:column; align-items:center; justify-content:center; min-height:100dvh; padding:20px 14px; } |
| .wrap { width:100%; max-width:360px; } |
| .phone-wrap { display:flex; border:1px solid rgba(255,255,255,0.12); } |
| .phone-prefix { background:rgba(255,255,255,0.06); border:none; border-right:1px solid rgba(255,255,255,0.1); color:var(--white); padding:10px 12px; font-family:'DM Mono',monospace; font-size:12px; flex-shrink:0; display:flex; align-items:center; } |
| .phone-input { flex:1; background:transparent; border:none; color:var(--white); padding:10px 12px; font-family:'DM Mono',monospace; font-size:13px; letter-spacing:2px; outline:none; } |
| .phone-input::placeholder { color:var(--white-faint); font-size:11px; } |
| .phase { display:none; animation:fadeSlideIn 0.3s ease forwards; } |
| .phase.active { display:block; } |
| @keyframes fadeSlideIn { from{opacity:0;transform:translateY(6px);}to{opacity:1;transform:translateY(0);} } |
| .sms-box { text-align:center; padding:20px 16px; background:var(--glass); border:1px solid var(--glass-border); margin-bottom:14px; } |
| .sms-box .sb-title { font-family:'Cormorant Garamond',serif; font-size:17px; letter-spacing:2px; margin-bottom:6px; } |
| .sms-box .sb-num { font-family:'DM Mono',monospace; font-size:14px; letter-spacing:2px; margin-top:8px; } |
| .waiting-indicator { display:flex; align-items:center; gap:10px; padding:12px 14px; background:var(--glass); border:1px solid var(--glass-border); margin-bottom:14px; } |
| .pulse-dot { width:8px; height:8px; border-radius:50%; background:rgba(255,255,255,0.4); animation:pulse 2s ease-in-out infinite; flex-shrink:0; } |
| @keyframes pulse { 0%,100%{opacity:0.3;transform:scale(0.8);}50%{opacity:1;transform:scale(1.2);} } |
| </style> |
| <script>if(localStorage.getItem('idea_maintenance')==='1'){window.location.replace('503.html');}</script> |
| </head> |
| <body> |
|
|
| <div class="wrap"> |
| <div style="text-align:center;margin-bottom:22px;" class="fade-in"> |
| <img src="logo.svg" style="width:34px;height:34px;margin:0 auto 10px;display:block;"> |
| <div style="font-family:'Cormorant Garamond',serif;font-size:22px;letter-spacing:3px;">IDEA</div> |
| <div style="font-size:9px;letter-spacing:2px;color:var(--white-dim);margin-top:3px;">RESETARE PAROLĂ</div> |
| </div> |
|
|
| |
| <div class="steps fade-in-2"> |
| <div class="step"><div class="step-dot active" id="s1-dot">1</div><div class="step-label active">IDENTIFICARE</div></div> |
| <div class="step-line"></div> |
| <div class="step"><div class="step-dot" id="s2-dot">2</div><div class="step-label" id="s2-lbl">SMS</div></div> |
| <div class="step-line"></div> |
| <div class="step"><div class="step-dot" id="s3-dot">3</div><div class="step-label" id="s3-lbl">PAROLĂ NOUĂ</div></div> |
| </div> |
|
|
| |
| <div class="phase active fade-in-3" id="phase-1"> |
| <div class="card" style="padding:18px 16px;"> |
| <div class="card-title" style="font-size:15px;">Identificare cont</div> |
| <p style="font-size:11px;color:var(--white-dim);margin-bottom:16px;line-height:1.9;"> |
| Selectează contul tău și introdu numărul de telefon pentru a primi un cod de resetare. |
| </p> |
| <div class="field"> |
| <label>Contul tău</label> |
| <select id="elev-sel"><option value="">— selectează —</option></select> |
| </div> |
| <div class="field"> |
| <label>Număr de telefon</label> |
| <div class="phone-wrap"> |
| <div class="phone-prefix">+373</div> |
| <input class="phone-input" type="tel" id="phone-in" maxlength="9" placeholder="(69) 048 176" inputmode="tel" oninput="fmtPhone(this)"> |
| </div> |
| <div style="font-size:9px;color:var(--white-faint);margin-top:5px;letter-spacing:1px;">Ex: +373 (69) 048 176</div> |
| </div> |
| <button class="btn-primary" onclick="requestReset()" id="btn-reset" style="width:100%;letter-spacing:2px;margin-top:4px;">SOLICITĂ RESETARE →</button> |
| <div class="alert error" id="err-1" style="margin-top:10px;"></div> |
| </div> |
| <div style="text-align:center;margin-top:12px;"> |
| <a href="index.html" style="font-size:10px;color:var(--white-dim);letter-spacing:1px;text-decoration:none;">← înapoi la login</a> |
| </div> |
| </div> |
|
|
| |
| <div class="phase" id="phase-2"> |
| <div class="sms-box"> |
| <div class="sb-title">Cod trimis prin SMS</div> |
| <div style="font-size:10px;color:var(--white-dim);letter-spacing:1px;line-height:1.9;">Administratorul ți-a transmis un cod de resetare pe numărul:</div> |
| <div class="sb-num" id="phone-display">—</div> |
| </div> |
| <div class="waiting-indicator"> |
| <div class="pulse-dot"></div> |
| <div> |
| <div class="wi-text">Așteptăm confirmarea adminului...</div> |
| <div class="wi-code" id="wait-timer">—</div> |
| </div> |
| </div> |
| <div class="card" style="padding:18px 16px;"> |
| <div class="card-title" style="font-size:15px;">Introdu codul din SMS</div> |
| <div class="field"> |
| <input type="text" id="code-in" maxlength="4" placeholder="• • • •" |
| inputmode="numeric" autocomplete="one-time-code" |
| style="font-size:28px;letter-spacing:12px;text-align:center;padding:14px;"> |
| </div> |
| <button class="btn-primary" onclick="verifyReset()" style="width:100%;letter-spacing:2px;margin-top:4px;">VERIFICĂ COD →</button> |
| <div class="alert error" id="err-2" style="margin-top:10px;"></div> |
| <div style="text-align:center;margin-top:12px;"> |
| <button class="btn-ghost" onclick="backToStep1()" style="font-size:9px;">Nu am primit SMS — Înapoi</button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="phase" id="phase-3"> |
| <div class="card" style="padding:18px 16px;"> |
| <div class="card-title" style="font-size:15px;">Parolă nouă</div> |
| <p style="font-size:11px;color:var(--white-dim);margin-bottom:14px;line-height:1.9;"> |
| Alege o parolă nouă de minimum 6 cifre. |
| </p> |
| <div class="field"> |
| <label>Parolă nouă (min. 6 cifre)</label> |
| <input type="password" id="new-pin1" maxlength="6" placeholder="••••••" inputmode="numeric" autocomplete="new-password"> |
| </div> |
| <div class="field"> |
| <label>Confirmă parola</label> |
| <input type="password" id="new-pin2" maxlength="6" placeholder="••••••" inputmode="numeric" autocomplete="new-password"> |
| </div> |
| <button class="btn-primary" onclick="saveNewPin()" style="width:100%;letter-spacing:2px;margin-top:4px;">SALVEAZĂ PAROLA →</button> |
| <div class="alert error" id="err-3" style="margin-top:10px;"></div> |
| </div> |
| </div> |
|
|
| |
| <div class="phase" id="phase-4"> |
| <div class="card" style="padding:28px 20px;"> |
| <div class="success-anim"> |
| <svg viewBox="0 0 24 24" fill="none" stroke="#5a9a5a" stroke-width="1.5" stroke-linecap="round"> |
| <path d="M22 11.08V12a10 10 0 11-5.93-9.14"/> |
| <polyline points="22 4 12 14.01 9 11.01"/> |
| </svg> |
| <div class="sa-title">Parolă resetată</div> |
| <div style="font-size:11px;color:var(--white-dim);letter-spacing:1px;" id="done-name">—</div> |
| </div> |
| <div style="margin-top:20px;"> |
| <button class="btn-primary" onclick="window.location.href='index.html'" style="width:100%;letter-spacing:2px;">MERGI LA LOGIN →</button> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="footer-mini">IDEA v2.3 ©2026 — Victor Roșca</div> |
| </div> |
|
|
| <script type="module"> |
| import { initializeApp } from "https://www.gstatic.com/firebasejs/10.12.0/firebase-app.js"; |
| import { getFirestore, collection, getDocs, addDoc, updateDoc, doc, query, where, serverTimestamp } |
| from "https://www.gstatic.com/firebasejs/10.12.0/firebase-firestore.js"; |
| |
| const cfg = { |
| apiKey:"AIzaSyB9--Onx3-_YjD-YzblhZjaWSVVqTQJ1lU", authDomain:"vservers1.firebaseapp.com", |
| projectId:"vservers1", storageBucket:"vservers1.firebasestorage.app", |
| messagingSenderId:"42433037358", appId:"1:42433037358:web:fde70fec79542428b60bbf" |
| }; |
| const app = initializeApp(cfg); |
| const db = getFirestore(app); |
| |
| let selectedElevId = null, selectedVpass = null, selectedNume = null; |
| let resetCode = null, resetDocId = null, codeExpiry = null; |
| |
| |
| try { |
| const snap = await getDocs(collection(db,'elevi')); |
| const sel = document.getElementById('elev-sel'); |
| const elevi = []; |
| snap.forEach(d => elevi.push({id:d.id,...d.data()})); |
| elevi.sort((a,b)=>(a.pozitie||0)-(b.pozitie||0)); |
| elevi.forEach(e => { |
| if (!e.pin) return; |
| const o = document.createElement('option'); |
| o.value = e.id; |
| o.textContent = `${String(e.pozitie||'').padStart(2,'0')}. ${e.nume}`; |
| sel.appendChild(o); |
| }); |
| } catch(e) {} |
| |
| function setPhase(n) { |
| document.querySelectorAll('.phase').forEach(p => p.classList.remove('active')); |
| document.getElementById('phase-'+n).classList.add('active'); |
| window.scrollTo({top:0,behavior:'smooth'}); |
| for (let i=1;i<=3;i++) { |
| const d = document.getElementById(`s${i}-dot`); |
| if (i < n) { d.classList.add('done'); d.innerHTML='✓'; } |
| else if (i===n) { d.classList.add('active'); } |
| else { d.classList.remove('active','done'); } |
| } |
| } |
| |
| window.fmtPhone = function(input) { |
| let v = input.value.replace(/\D/g,''); |
| if(v.length>8)v=v.slice(0,8); |
| let out=''; |
| if(v.length>=2)out='('+v.slice(0,2)+') '; else out=v; |
| if(v.length>2)out+=v.slice(2,5); |
| if(v.length>5)out+=' '+v.slice(5,8); |
| input.value=out; |
| }; |
| |
| window.requestReset = async function() { |
| hideError('err-1'); |
| const id = document.getElementById('elev-sel').value; |
| const rawPh = document.getElementById('phone-in').value.replace(/\D/g,''); |
| if (!id) { showError('err-1','err-021','Selectează contul.'); return; } |
| if (rawPh.length<8){ showError('err-1','err-021','Număr de telefon incomplet.'); return; } |
| |
| document.getElementById('btn-reset').disabled=true; |
| const phone = '+373 ('+rawPh.slice(0,2)+') '+rawPh.slice(2,5)+' '+rawPh.slice(5,8); |
| |
| try { |
| const snap = await getDocs(query(collection(db,'elevi'))); |
| const elevDoc = snap.docs.find(d=>d.id===id); |
| if (!elevDoc) { showError('err-1','err-002'); document.getElementById('btn-reset').disabled=false; return; } |
| selectedElevId = id; |
| selectedVpass = elevDoc.data().vpassId; |
| selectedNume = elevDoc.data().nume; |
| |
| resetCode = String(Math.floor(1000+Math.random()*9000)); |
| |
| const ref = await addDoc(collection(db,'notificari'),{ |
| tip:'reset_request', elevId:id, elevVpass:selectedVpass, elevNume:selectedNume, |
| telefon:phone, confirmCode:resetCode, |
| status:'pending', citita:false, timestamp:serverTimestamp() |
| }); |
| resetDocId = ref.id; |
| |
| document.getElementById('phone-display').textContent = phone; |
| codeExpiry = Date.now() + 10*60*1000; |
| const tv = document.getElementById('wait-timer'); |
| const iv = setInterval(()=>{ |
| const l=Math.max(0,codeExpiry-Date.now()); |
| const m=Math.floor(l/60000), s=Math.floor((l%60000)/1000); |
| tv.textContent=`Expiră în ${m}:${String(s).padStart(2,'0')}`; |
| if(l<=0){clearInterval(iv);tv.textContent='Cod expirat';} |
| },1000); |
| setPhase(2); |
| } catch(e){ showError('err-1','err-025'); document.getElementById('btn-reset').disabled=false; } |
| }; |
| |
| window.verifyReset = function() { |
| hideError('err-2'); |
| const input = document.getElementById('code-in').value.replace(/\s/g,''); |
| if(!/^\d{4}$/.test(input)){ showError('err-2','err-029'); return; } |
| if(codeExpiry && Date.now()>codeExpiry){ showError('err-2','err-006'); return; } |
| if(input !== resetCode){ showError('err-2','err-007'); return; } |
| setPhase(3); |
| }; |
| |
| window.backToStep1 = function() { |
| document.getElementById('btn-reset').disabled=false; |
| setPhase(1); |
| }; |
| |
| window.saveNewPin = async function() { |
| hideError('err-3'); |
| const p1 = document.getElementById('new-pin1').value; |
| const p2 = document.getElementById('new-pin2').value; |
| if(p1.length<6){ showError('err-3','err-008'); return; } |
| if(p1!==p2){ showError('err-3','err-008','Parolele nu coincid.'); return; } |
| try { |
| await updateDoc(doc(db,'elevi',selectedElevId),{pin:p1}); |
| if(resetDocId) await updateDoc(doc(db,'notificari',resetDocId),{status:'completed',citita:true}); |
| document.getElementById('done-name').textContent=selectedNume; |
| |
| sessionStorage.removeItem('vs_role'); |
| setPhase(4); |
| } catch(e){ showError('err-3','err-025'); } |
| }; |
| </script> |
| <a href="vhelp.html" class="vhelp-fab" title="VHelp"> |
| <svg viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,0.9)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"> |
| <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/> |
| <circle cx="9" cy="10" r="0.5" fill="rgba(255,255,255,0.9)"/> |
| <circle cx="12" cy="10" r="0.5" fill="rgba(255,255,255,0.9)"/> |
| <circle cx="15" cy="10" r="0.5" fill="rgba(255,255,255,0.9)"/> |
| </svg> |
| </a> |
| </body> |
| </html> |
|
|