import { useEffect, useState } from 'react'; import { apiAppTemplates, type AppTemplateItem } from '../api'; import { AppPoolModal } from './AppPoolModal'; import { countKeywords, mergeKeywordCSV } from '../utils/appKeywords'; export function AppTemplatesSection() { const [items, setItems] = useState([]); const [loading, setLoading] = useState(true); const [editing, setEditing] = useState(null); const [creating, setCreating] = useState(false); const [name, setName] = useState(''); const [description, setDescription] = useState(''); const [keywords, setKeywords] = useState(''); const [busy, setBusy] = useState(false); const [poolOpen, setPoolOpen] = useState(false); const [error, setError] = useState(''); const load = async () => { setLoading(true); try { const res = await apiAppTemplates.list(); setItems(res.data || []); } catch (e) { console.error(e); } finally { setLoading(false); } }; useEffect(() => { load(); }, []); const openCreate = () => { setCreating(true); setEditing(null); setName(''); setDescription(''); setKeywords(''); setError(''); }; const openEdit = (tpl: AppTemplateItem) => { setEditing(tpl); setCreating(false); setName(tpl.name); setDescription(tpl.description || ''); setKeywords(tpl.keywords); setError(''); }; const closeForm = () => { setCreating(false); setEditing(null); setError(''); }; const save = async () => { if (!name.trim()) { setError('Nhập tên khung.'); return; } if (!keywords.trim()) { setError('Thêm ít nhất một keyword.'); return; } setBusy(true); setError(''); try { if (editing) { await apiAppTemplates.update(editing.id, { name: name.trim(), description: description.trim(), keywords, }); } else { await apiAppTemplates.create({ name: name.trim(), description: description.trim(), keywords, }); } closeForm(); await load(); } catch (e: any) { setError(e?.message || 'Lỗi lưu khung'); } finally { setBusy(false); } }; const remove = async (tpl: AppTemplateItem) => { if (!confirm(`Xóa khung "${tpl.name}"?`)) return; try { await apiAppTemplates.delete(tpl.id); if (editing?.id === tpl.id) closeForm(); await load(); } catch (e: any) { alert(e?.message || 'Không xóa được'); } }; const addPoolKeyword = (kw: string) => { setKeywords((prev) => mergeKeywordCSV(prev, kw)); }; const showForm = creating || editing; return (

Khung ứng dụng

Tạo bộ keyword whitelist dùng chung — ghép từ kho app hoặc tự nhập. Lớp học và phòng thi có thể áp dụng nhanh thay vì chỉ chọn từng app trong kho.

{showForm && (

{editing ? 'Sửa khung' : 'Khung mới'}