จัดการ Profile สมาชิก
try { await db.collection('repairs').add({ name, phone, model, issue, price, createdAt: firebase.firestore.FieldValue.serverTimestamp() }); alert('บันทึกสำเร็จ'); } catch (e) { alert('Error: ' + e.message); } }); function toast(message, type = 'info') { const el = $('toast'); el.textContent = message; el.className = 'toast fixed bottom-5 right-5 z-[60] max-w-sm rounded-xl px-4 py-3 text-sm text-white shadow-xl show'; if (type === 'error') el.classList.add('bg-rose-600'); else if (type === 'success') el.classList.add('bg-emerald-600'); else el.classList.add('bg-slate-900'); setTimeout(() => el.classList.remove('show'), 3200); } function friendlyAuthError(error) { const map = { 'auth/invalid-email': 'รูปแบบอีเมลไม่ถูกต้อง', 'auth/user-disabled': 'บัญชีนี้ถูกระงับ', 'auth/user-not-found': 'ไม่พบบัญชีผู้ใช้', 'auth/wrong-password': 'รหัสผ่านไม่ถูกต้อง', 'auth/invalid-credential': 'ข้อมูลเข้าสู่ระบบไม่ถูกต้อง', 'auth/email-already-in-use': 'อีเมลนี้ถูกใช้งานแล้ว', 'auth/weak-password': 'รหัสผ่านต้องมีความยาวอย่างน้อย 6 ตัวอักษร', 'auth/network-request-failed': 'ไม่สามารถเชื่อมต่อเครือข่ายได้' }; return map[error && error.code] || (error && error.message) || 'เกิดข้อผิดพลาด'; } try { const snapshot = await db.collection('repairs').where('phone', '==', phone).orderBy('createdAt', 'desc').get(); if (!snapshot.empty) { const latestDoc = snapshot.docs[0].data(); document.getElementById('lbl_name').textContent = latestDoc.name; document.getElementById('lbl_model').textContent = latestDoc.model; document.getElementById('lbl_issue').textContent = latestDoc.issue; document.getElementById('lbl_price').textContent = latestDoc.price; alert(`พบข้อมูลทั้งหมด ${snapshot.size} รายการ`); } else { alert('ไม่พบข้อมูล'); ['lbl_name', 'lbl_model', 'lbl_issue', 'lbl_price'].forEach(id => document.getElementById(id).textContent = '-'); } } catch (e) { alert('Error: ' + e.message); } }); function formatDate(value) { if (!value) return '-'; const d = value.toDate ? value.toDate() : new Date(value); if (Number.isNaN(d.getTime())) return '-'; const now = new Date(); const dKey = todayKey(d); const nowKey = todayKey(now); const time = d.toLocaleTimeString('th-TH', { timeZone: 'Asia/Bangkok', hour: '2-digit', minute: '2-digit' }) + ' น.'; if (dKey === nowKey) return 'วันนี้ ' + time; return d.toLocaleDateString('th-TH', { timeZone: 'Asia/Bangkok', year: 'numeric', month: '2-digit', day: '2-digit' }) + ' ' + time; } function todayKey(d = new Date()) { return new Intl.DateTimeFormat('en-CA', { timeZone: 'Asia/Bangkok', year: 'numeric', month: '2-digit', day: '2-digit' }).format(d); } function escapeHtml(value) { return String(value ?? '').replace(/[&<>"']/g, c => ({ '&':'&','<':'<','>':'>','"':'"',"'":''' }[c])); } function updateCurrentDateTime() { const now = new Date(); const dateText = now.toLocaleDateString('th-TH', { timeZone: 'Asia/Bangkok', year: 'numeric', month: 'long', day: 'numeric' }); const timeText = now.toLocaleTimeString('th-TH', { timeZone: 'Asia/Bangkok', hour: '2-digit', minute: '2-digit', second: '2-digit' }); const dayText = new Intl.DateTimeFormat('th-TH', { timeZone: 'Asia/Bangkok', weekday: 'long' }).format(now); if ($('current-date')) $('current-date').textContent = dateText; if ($('current-time')) $('current-time').textContent = timeText + ' น.'; if ($('current-day')) $('current-day').textContent = dayText; } updateCurrentDateTime(); setInterval(updateCurrentDateTime, 1000); function getUserRole(profile) { if (!profile) return null; return String(profile.role || '').toLowerCase(); } async function loadProfile(user) { /* * New member profile design: * members/{uid} * { username, email, role, active, ownerUid, groupId, createdAt } * * This is a new application schema; it is not claimed to exist in * the original project. */ try { const snap = await db.collection('members').doc(user.uid).get(); if (snap.exists) return { id: snap.id, ...snap.data() }; } catch (e) { console.warn('Profile lookup unavailable:', e); } return null; } async function resolveMemberUsername(username) { const normalized = username.trim().toLowerCase(); const snap = await db.collection('members') .where('username', '==', normalized) .limit(1) .get(); if (snap.empty) throw new Error('ไม่พบ Username ของสมาชิก'); const data = snap.docs[0].data(); if (data.active === false) throw new Error('สมาชิกนี้ถูกระงับการใช้งาน'); if (!data.email) throw new Error('สมาชิกนี้ไม่มี Email สำหรับ Firebase Authentication'); return data.email; } async function loginOwner(email, password) { await auth.signInWithEmailAndPassword(email.trim(), password); } $('login-form').addEventListener('submit', async e => { e.preventDefault(); const btn = $('btn-login'); const email = $('login-identifier').value.trim(); const password = $('login-password').value; btn.disabled = true; btn.textContent = 'กำลังเข้าสู่ระบบ...'; try { await auth.signInWithEmailAndPassword(email, password); } catch (error) { toast(friendlyAuthError(error), 'error'); } finally { btn.disabled = false; btn.textContent = 'เข้าสู่ระบบ'; } }); auth.onAuthStateChanged(async user => { currentUser = user; if (!user) { cleanupListeners(); showView('public'); return; } $('owner-email').textContent = user.email || '-'; showView('owner'); startOwnerListeners(); }); function cleanupListeners() { if (repairUnsubscribe) { repairUnsubscribe(); repairUnsubscribe = null; } } function ownerScopeQuery() { return db.collection('repairs') .where('ownerUid', '==', currentUser.uid) .orderBy('createdAt', 'desc') .limit(100); } function startOwnerListeners() { if (repairUnsubscribe) repairUnsubscribe(); $('owner-firestore-state').textContent = 'กำลังเชื่อมต่อ'; $('owner-listener-state').textContent = 'กำลังเชื่อมต่อ'; repairUnsubscribe = ownerScopeQuery().onSnapshot(snapshot => { cachedRepairs = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); $('owner-firestore-state').textContent = 'เชื่อมต่อแล้ว'; $('owner-listener-state').textContent = 'ทำงานอยู่'; renderOwnerStats(); renderRecentRepairs(); renderRepairTable(); }, error => { console.error(error); $('owner-firestore-state').textContent = 'อ่านข้อมูลไม่ได้'; $('owner-listener-state').textContent = 'หยุดทำงาน'; renderEmptyOwnerData('ไม่สามารถอ่านข้อมูล repairs ได้: ' + friendlyAuthError(error)); }); } function renderEmptyOwnerData(message) { $('owner-recent-repairs').innerHTML = `ยังไม่มีข้อมูลงานซ่อม
Firestore ปัจจุบันยังไม่มีข้อมูลตามที่ตรวจสอบไว้