This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
apiExam,
|
||||
apiSeatingLayout,
|
||||
staffFetch,
|
||||
type ExamPaper,
|
||||
type ExamRoomStudent,
|
||||
@@ -327,12 +328,12 @@ export const ExamRoomWorkspace: React.FC<Props> = ({ examId, onBack }) => {
|
||||
const assignRandomPackages = async () => {
|
||||
if (papers.length === 0) return;
|
||||
|
||||
// Đọc sơ đồ chỗ ngồi từ localStorage (exam rooms vẫn lưu local)
|
||||
// Đọc sơ đồ chỗ ngồi từ server
|
||||
let seatingSeats: Record<string, number> | null = null;
|
||||
try {
|
||||
const raw = localStorage.getItem(`sc_seating_layout_exam-${examId}`);
|
||||
if (raw) {
|
||||
const parsed = JSON.parse(raw) as { seats?: Record<string, number> };
|
||||
const json = await apiSeatingLayout.getExam(examId);
|
||||
if (json) {
|
||||
const parsed = JSON.parse(json) as { seats?: Record<string, number> };
|
||||
if (parsed.seats && Object.keys(parsed.seats).length > 0) {
|
||||
seatingSeats = parsed.seats;
|
||||
}
|
||||
|
||||
@@ -53,11 +53,15 @@ export const WorkspaceSeatingChart: React.FC<WorkspaceSeatingChartProps> = ({
|
||||
const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');
|
||||
const [listSearchQuery, setListSearchQuery] = useState('');
|
||||
|
||||
// Detect if this is a class workspace (vs exam) to use API storage
|
||||
const classRkId = useMemo(() => {
|
||||
// Parse workspace type and ID for API storage
|
||||
const workspaceInfo = useMemo(() => {
|
||||
if (workspaceId.startsWith('class-')) {
|
||||
const n = Number(workspaceId.replace('class-', ''));
|
||||
return isNaN(n) ? null : n;
|
||||
return isNaN(n) ? null : { kind: 'class' as const, id: n };
|
||||
}
|
||||
if (workspaceId.startsWith('exam-')) {
|
||||
const n = Number(workspaceId.replace('exam-', ''));
|
||||
return isNaN(n) ? null : { kind: 'exam' as const, id: n };
|
||||
}
|
||||
return null;
|
||||
}, [workspaceId]);
|
||||
@@ -103,58 +107,44 @@ export const WorkspaceSeatingChart: React.FC<WorkspaceSeatingChartProps> = ({
|
||||
}
|
||||
}
|
||||
|
||||
if (classRkId !== null) {
|
||||
// Load layout từ server theo lớp
|
||||
apiSeatingLayout.get(classRkId).then((json) => {
|
||||
if (workspaceInfo !== null) {
|
||||
const getter = workspaceInfo.kind === 'class'
|
||||
? apiSeatingLayout.getClass(workspaceInfo.id)
|
||||
: apiSeatingLayout.getExam(workspaceInfo.id);
|
||||
getter.then((json) => {
|
||||
if (json) {
|
||||
try {
|
||||
setLayout(JSON.parse(json));
|
||||
} catch {
|
||||
setLayout(null);
|
||||
}
|
||||
try { setLayout(JSON.parse(json)); } catch { setLayout(null); }
|
||||
} else {
|
||||
setLayout(null);
|
||||
}
|
||||
}).catch(() => setLayout(null));
|
||||
} else {
|
||||
// Exam rooms — vẫn dùng localStorage
|
||||
const storedLayout = localStorage.getItem(`sc_seating_layout_${workspaceId}`);
|
||||
if (storedLayout) {
|
||||
try {
|
||||
setLayout(JSON.parse(storedLayout));
|
||||
} catch {
|
||||
setLayout(null);
|
||||
}
|
||||
}
|
||||
setLayout(null);
|
||||
}
|
||||
}, [workspaceId, classRkId]);
|
||||
}, [workspaceId, workspaceInfo]);
|
||||
|
||||
// Save layout — debounce API calls, fallback to localStorage for exam rooms
|
||||
// Save layout — debounce để tránh gọi API quá nhiều khi kéo thả nhanh
|
||||
const saveLayout = (newLayout: SeatingLayout | null) => {
|
||||
setLayout(newLayout);
|
||||
if (!workspaceInfo) return;
|
||||
|
||||
if (classRkId !== null) {
|
||||
// Debounce để tránh gọi API quá nhiều khi kéo thả nhanh
|
||||
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
|
||||
saveTimerRef.current = setTimeout(() => {
|
||||
if (newLayout) {
|
||||
apiSeatingLayout.save(classRkId, JSON.stringify(newLayout)).catch(() => {});
|
||||
setSaveNotice('Đã lưu sơ đồ chỗ ngồi!');
|
||||
} else {
|
||||
apiSeatingLayout.delete(classRkId).catch(() => {});
|
||||
setSaveNotice('Đã xóa sơ đồ chỗ ngồi!');
|
||||
}
|
||||
}, 600);
|
||||
} else {
|
||||
// Exam rooms — localStorage
|
||||
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
|
||||
saveTimerRef.current = setTimeout(() => {
|
||||
if (newLayout) {
|
||||
localStorage.setItem(`sc_seating_layout_${workspaceId}`, JSON.stringify(newLayout));
|
||||
setSaveNotice('Đã lưu thay đổi sơ đồ chỗ ngồi!');
|
||||
const json = JSON.stringify(newLayout);
|
||||
const saver = workspaceInfo.kind === 'class'
|
||||
? apiSeatingLayout.saveClass(workspaceInfo.id, json)
|
||||
: apiSeatingLayout.saveExam(workspaceInfo.id, json);
|
||||
saver.catch(() => {});
|
||||
setSaveNotice('Đã lưu sơ đồ chỗ ngồi!');
|
||||
} else {
|
||||
localStorage.removeItem(`sc_seating_layout_${workspaceId}`);
|
||||
const deleter = workspaceInfo.kind === 'class'
|
||||
? apiSeatingLayout.deleteClass(workspaceInfo.id)
|
||||
: apiSeatingLayout.deleteExam(workspaceInfo.id);
|
||||
deleter.catch(() => {});
|
||||
setSaveNotice('Đã xóa sơ đồ chỗ ngồi!');
|
||||
}
|
||||
}
|
||||
}, 600);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user