import React, { useEffect, useState } from 'react'; export interface SeatingTemplate { id: string; name: string; rows: number; cols: number; boardPosition: 'top' | 'bottom' | 'left' | 'right'; lockedSeats: string[]; // e.g. ["0,0", "1,2"] } const DEFAULT_TEMPLATES: SeatingTemplate[] = [ { id: 'tpl-standard-30', name: 'Phòng Lab Standard (30 máy)', rows: 5, cols: 6, boardPosition: 'top', lockedSeats: [], }, { id: 'tpl-aisle-large', name: 'Phòng Máy A1 (Có lối đi giữa)', rows: 6, cols: 8, boardPosition: 'top', lockedSeats: ['0,3', '1,3', '2,3', '3,3', '4,3', '5,3'], }, ]; export const SeatingTemplatesSection: React.FC = () => { const [templates, setTemplates] = useState([]); const [editing, setEditing] = useState(null); const [creating, setCreating] = useState(false); // Form states const [name, setName] = useState(''); const [rows, setRows] = useState(5); const [cols, setCols] = useState(6); const [boardPosition, setBoardPosition] = useState<'top' | 'bottom' | 'left' | 'right'>('top'); const [lockedSeats, setLockedSeats] = useState([]); const [error, setError] = useState(''); useEffect(() => { const stored = localStorage.getItem('sc_seating_templates'); if (stored) { try { setTemplates(JSON.parse(stored)); } catch { setTemplates(DEFAULT_TEMPLATES); } } else { localStorage.setItem('sc_seating_templates', JSON.stringify(DEFAULT_TEMPLATES)); setTemplates(DEFAULT_TEMPLATES); } }, []); const saveTemplates = (newTemplates: SeatingTemplate[]) => { localStorage.setItem('sc_seating_templates', JSON.stringify(newTemplates)); setTemplates(newTemplates); }; const handleOpenCreate = () => { setCreating(true); setEditing(null); setName(''); setRows(5); setCols(6); setBoardPosition('top'); setLockedSeats([]); setError(''); }; const handleOpenEdit = (tpl: SeatingTemplate) => { setEditing(tpl); setCreating(false); setName(tpl.name); setRows(tpl.rows); setCols(tpl.cols); setBoardPosition(tpl.boardPosition); setLockedSeats(tpl.lockedSeats || []); setError(''); }; const handleCloseForm = () => { setCreating(false); setEditing(null); setError(''); }; const handleToggleLock = (r: number, c: number) => { const key = `${r},${c}`; if (lockedSeats.includes(key)) { setLockedSeats(lockedSeats.filter((k) => k !== key)); } else { setLockedSeats([...lockedSeats, key]); } }; const handleSave = () => { if (!name.trim()) { setError('Vui lòng nhập tên template.'); return; } // Clean up locked seats that fall outside the current rows/cols boundary const validLockedSeats = lockedSeats.filter((key) => { const [r, c] = key.split(',').map(Number); return r < rows && c < cols; }); const newTemplate: SeatingTemplate = { id: editing ? editing.id : `tpl-${Date.now()}`, name: name.trim(), rows, cols, boardPosition, lockedSeats: validLockedSeats, }; let updatedList: SeatingTemplate[]; if (editing) { updatedList = templates.map((t) => (t.id === editing.id ? newTemplate : t)); } else { updatedList = [...templates, newTemplate]; } saveTemplates(updatedList); handleCloseForm(); }; const handleDelete = (tpl: SeatingTemplate) => { if (confirm(`Bạn có chắc chắn muốn xóa template "${tpl.name}"?`)) { const updatedList = templates.filter((t) => t.id !== tpl.id); saveTemplates(updatedList); if (editing?.id === tpl.id) { handleCloseForm(); } } }; // Helper to render preview grid in edit/create form const renderDesignerGrid = () => { const gridItems = []; for (let r = 0; r < rows; r++) { for (let c = 0; c < cols; c++) { const key = `${r},${c}`; const isLocked = lockedSeats.includes(key); gridItems.push(
handleToggleLock(r, c)} className={`seating-designer-cell ${isLocked ? 'locked' : 'available'}`} style={{ padding: '0.5rem', border: '1px solid var(--border-color)', borderRadius: '6px', textAlign: 'center', cursor: 'pointer', fontSize: '0.78rem', fontWeight: 600, userSelect: 'none', backgroundColor: isLocked ? '#e5e7eb' : '#eff6ff', color: isLocked ? '#9ca3af' : '#1e40af', borderColor: isLocked ? '#d1d5db' : '#bfdbfe', transition: 'var(--transition)', }} > {isLocked ? '🔒 Khóa' : `H${r + 1}-C${c + 1}`}
); } } return (
{boardPosition === 'top' && (
📢 BẢNG / GIẢNG ĐƯỜNG (TOP)
)}
{boardPosition === 'left' && (
📢 BẢNG (LEFT)
)}
{gridItems}
{boardPosition === 'right' && (
📢 BẢNG (RIGHT)
)}
{boardPosition === 'bottom' && (
📢 BẢNG / GIẢNG ĐƯỜNG (BOTTOM)
)}
); }; return (

Danh sách mẫu sơ đồ chỗ ngồi

Thiết lập sẵn cấu trúc hàng, cột, bảng và các vị trí máy hỏng hoặc lối đi để áp dụng nhanh cho lớp hoặc phòng thi.

{!creating && !editing && ( )}
{(creating || editing) ? (

{creating ? 'Thêm sơ đồ mẫu mới' : 'Chỉnh sửa sơ đồ mẫu'}

{error &&
{error}
}

Thiết kế vị trí khóa

Click chuột vào các ô bên dưới để chuyển đổi trạng thái giữa Chỗ trống khả dụngVị trí khóa (Không thể xếp sinh viên).

{renderDesignerGrid()}
) : (
{templates.map((tpl) => (

{tpl.name}

Kích thước: {tpl.rows} hàng × {tpl.cols} cột ({tpl.rows * tpl.cols} vị trí)
Bảng ở: {tpl.boardPosition.toUpperCase()}
Vị trí khóa: {tpl.lockedSeats ? tpl.lockedSeats.length : 0} ô
))}
)}
); };