🏸 BadCount — แอปบันทึกเกมแบดมินตัน
Web App (PWA) ธีม Sporty Neon-Lime & Sleek Graphite-Black สำหรับจดสมาชิก นับลูก คำนวณค่าใช้จ่าย และจัดคิวเกมแบดมินตัน
Real-time sync ทุกคนเห็นพร้อมกัน — ใช้ฟรี 100%
เวอร์ชันปัจจุบัน: 3.19.0 (cache badcount-v55)
🌐 Live: badcount.vercel.app
📦 GitHub: leezen441/Badcount
✨ คุณสมบัติหลัก
🎨 ธีมพรีเมียม Sporty Neon-Lime & Sleek Graphite-Black (CI 100%)
- ✅ บังคับธีมดาร์กโหมดถาวร (Forced Dark Mode): ดีไซน์สปอร์ตด้วยเขียวสะท้อนแสงนีออน (
#b5f714) และดำกราไฟต์ (#0d0e12) — initTheme() ใส่คลาส dark ตลอด ไม่มีโหมดสว่าง
- ✅ เน้นการอ่านออกได้ง่ายและชัดเจน (High Legibility): คอนทราสต์อักษรสีดำเข้ม (
#121315) บนปุ่มเขียวนีออน อ่านง่ายภายใต้แสงสนาม
- ✅ ดีไซน์ Opaque Card เรียบหรู: หลีกเลี่ยงเลเยอร์โปร่งแสงที่ทับซ้อน ทำให้อ่านประวัติ ยอดเงิน และตารางเกมได้ชัด
- ✅ สปอร์ตไอคอนเฉพาะตัว (Abstract Brand Identity): โลโก้ PWA และ Favicon เป็นเวกเตอร์ไม้แบด + ลูกขนไก่
- ✅ ปุ่มหลักพร้อม Micro-Animations: ปุ่มในหน้ารายละเอียดกลุ่ม (Invite, Temp Manager, Export, QR Payment) เรืองแสงนีออน พร้อมคลิกย่อตัวและ hover glow
- ✅ ตัวเลือกปฏิทิน/เวลาความคมชัดสูง: ในดาร์กโหมด ไอคอน date/time picker เป็นสีขาวคมชัด
👥 จัดการกลุ่ม (Session Management)
- ✅ สร้างกลุ่ม/ก๊วนของแต่ละวัน: จัดการรายชื่อสมาชิก จำนวนสนาม และค่าใช้จ่าย
- ✅ ปุ่ม "สร้างกลุ่มอาทิตย์หน้า" (Recurring Session): คัดลอกจากก๊วนล่าสุดเฉพาะ สถานที่ / ค่าคอร์ต / ค่าลูก / ค่าอื่นๆ / สนาม / QR ธนาคาร แล้วตั้งวันที่เป็นวันอาทิตย์ที่ใกล้ที่สุด — ไม่คัดลอกสมาชิกและแมตช์ ก๊วนใหม่เริ่มว่าง สถานะเปิด เปิดรับสมาชิก
- ✅ การจัดการสมาชิกแบบยืดหยุ่น: เพิ่ม/ลบได้ตลอด พร้อม suggestion จากชื่อที่เคยลงเล่นในเครื่องนั้น (สูงสุด 30 ชื่อ)
- ✅ พักคิวสมาชิกชั่วคราว (Pause Members): หยุดไม่ให้เข้า Auto Draft โดยไม่ต้องลบชื่อ — คนที่ลงชื่อผ่านลิงก์ join จะถูกพักคิวอัตโนมัติจนกว่าแอดมินจะปลด
- ✅ ปิดรับสมาชิก: ล็อกไม่ให้ลงชื่อเพิ่มได้ แม้ Court ยังเปิดอยู่ (ปิด Court = ปิดรับอัตโนมัติ)
- ✅ ประวัติย้อนหลัง (History): แสดงรายการกลุ่มย้อนหลังสูงสุด 50 รายการล่าสุด
- ✅ Highlight สถานะกลุ่ม: กลุ่มที่ปิดยอดแล้วเด่นด้วยกรอบเขียวนีออน กลุ่มที่กำลังเปิดอยู่แยกชัด
🏟️ จัดการสนาม (Court Management)
- ✅ ระบุเลขสนาม + ช่วงเวลา: เปิด-ปิดแต่ละสนามไม่พร้อมกันได้
- ✅ Time Picker: นาฬิกา 24 ชั่วโมง
- ✅ Suggestion จากกลุ่มก่อน: ดึงสนามล่าสุดจาก
settings/defaults (lastUsedCourts)
💰 คำนวณค่าใช้จ่าย (Expense Calculation)
- ✅ ค่าคอร์ตแบบยืดหยุ่น: toggle "รวม (หารเท่ากัน)" หรือ "ต่อคน"
- ✅ ค่าลูกแบดตามใช้จริง: โหมดเบอร์ลูก (เช่น
1-5, 8) หรือโหมดนับจำนวนอย่างง่าย (simpleShuttleCount) — ลูกจากแมตช์หารให้ผู้เล่นในเกมนั้น (ยกเว้นคนที่ถูก exempt)
- ✅ ค่าใช้จ่ายอื่นๆ (ค่าน้ำ/อาหาร): หารเท่ากันทุกคน หรือคิดรายคน
- ✅ ยกเว้น / กำหนดยอดเอง: ฟรีค่าลูกทั้งก๊วน, เว้นจำนวนลูก, หรือ
manualFee ให้แอดมินใส่ยอดคงที่รายคน
- ✅ ติดตามสถานะการชำระเงิน: ติ๊ก "จ่ายแล้ว" รายคนแบบ realtime พร้อมขีดฆ่าชื่อ
🎮 จัดเกม + สถิติ (Matchmaking & Stats)
- ✅ Auto Draft: จัด 4 คนจากผู้ที่ลงน้อย, คู่ซ้ำน้อย, บาลานซ์มือ, buddy อยู่ฝั่งเดียวกัน (คนพักคิว / จ่ายแล้วไม่ถูกสุ่ม)
- ✅ Auto Split: แบ่งฝั่ง Team A vs Team B จากระดับมือ (A / B / C / P / S)
- ✅ Buddy (คู่หู): ในโหมด advance สมาชิกเลือก buddy ได้ตอนลงชื่อ เพื่อให้อยู่ฝั่งเดียวกัน
- ✅ Co-play Badges: badge 3 ระดับว่าใครเคยเล่นด้วยกันกี่ครั้ง
- ✅ บันทึกแมตช์นับลูก: เก็บผู้เล่น 4 คน, เบอร์/จำนวนลูก, และผู้เล่นที่ยกเว้นค่าลูกในเกมนั้น — ไม่มีฟิลด์คะแนน rally
📲 หน้าต่างโต้ตอบบนมือถือ (Mobile Modals & Layout)
- ✅ Centered Modals: หน้าต่างเกมใหม่, PromptPay, และอื่นๆ กึ่งกลางจอ มุมโค้ง
rounded-2xl
- ✅ ปุ่มล่างไม่ถูกบัง: ความสูง modal สูงสุด ~90% ของจอ มีสกรอลล์ภายใน
- ✅ ปุ่มย้อนกลับบนมือถือ: History API + LIFO modal stack — กด Back ปิด modal ล่าสุดก่อน ไม่ออกจากหน้า
- ✅ PWA Install: ติดตั้งแบบ standalone เต็มจอ
⚡ Cache-Busting & PWA Resilient Updates
- ✅ Service Worker: namespace
badcount-v33 ใน sw.js — เคลียร์แคชเก่าเมื่ออัปเดต
- ✅ Cache-busting query:
premium.css?v=3.16.0 และ app.js?v=3.16.0 ใน index.html
- ⚠️ กฎสำคัญ: ทุกครั้งที่แก้
app.js / premium.css ต้อง bump ?v= ใน index.html และ CACHE_NAME ใน sw.js ไม่งั้นผู้ใช้ไม่เห็นของใหม่
- ✅ Resilient Realtime Sync: แจ้ง online/offline และ resubscribe Firestore เมื่อกลับมาจาก background
📤 Export & Sharing
- ✅ Bill JPG: สรุปยอดก๊วนพร้อม QR รับเงิน
- ✅ ภาพทวงค่า: ส่งต่อทางแชต (LINE / Messenger) แจ้งยอดค้างรายคน
- ✅ PromptPay QR Cloud Sync: สร้าง QR ไดนามิกจากเบอร์/ID ใน
settings/defaults (canonical EMV + quiet zone) — fallback เป็น session.bankQR ถ้ายังไม่มี PromptPay ID
- ✅ สลิปโอนเงิน: อัปโหลดเก็บใน
sessions/{id}/receipts/{memberId} เป็น base64 ใน Firestore (ไม่ใช้ Firebase Storage) พร้อม metadata ลบอัตโนมัติ ~30 วัน
🔔 Notification System
- ✅ Toast + เสียง: แจ้งเมื่อมีคนลงชื่อใหม่
- ✅ Dynamic Tab Title: กระพริบชื่อแท็บพร้อมจำนวนผู้เล่น
- ✅ Native OS Notifications: แจ้งแอดมิน/ผู้จัดการเมื่อย่อหน้าต่าง
🔒 Authentication & Access Level
- ✅ Admin passcode: เทียบ SHA-256 กับ
PASSCODE_HASH ใน app.js — จำใน localStorage 30 วัน
- ✅ Manager passcode: รหัสผู้ช่วยแยกต่างหากใน
app.js (ข้อความตรง ไม่ได้ hash) — จำจนกว่าจะออกจากระบบ
- ✅ Temp Manager PIN: PIN 4 หลักต่อก๊วน + วันหมดอายุ ใช้เข้า
/#/m/{id}
- ✅ 3-Tier Permission: Admin / Manager / Member (ลิงก์ join สาธารณะ ไม่มีล็อกอิน)
This is the beginning of the README. Read the rest at the original. Read the full README ↗