fix ui
All checks were successful
Deploy on Master Change / deploy (push) Successful in 44s

This commit is contained in:
2026-07-01 15:08:31 +07:00
parent 7a9c7a93ff
commit 7e84ddeaf9
8 changed files with 443 additions and 20 deletions

View File

@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { api, type AppDownloadItem, type GuideLinkItem } from '../api';
import { api, type AppDownloadItem, type AppGuideItem } from '../api';
import { useAuth } from '../auth/AuthContext';
// Icons
@@ -54,7 +54,7 @@ export const ApplicationsTab: React.FC = () => {
const [appsLoading, setAppsLoading] = useState(true);
// Guides state
const [guides, setGuides] = useState<GuideLinkItem[]>([]);
const [guides, setGuides] = useState<AppGuideItem[]>([]);
const [guidesLoading, setGuidesLoading] = useState(true);
// App Modal states
@@ -68,7 +68,7 @@ export const ApplicationsTab: React.FC = () => {
// Guide Modal states
const [showGuideModal, setShowGuideModal] = useState(false);
const [editingGuide, setEditingGuide] = useState<GuideLinkItem | null>(null);
const [editingGuide, setEditingGuide] = useState<AppGuideItem | null>(null);
const [guideTitle, setGuideTitle] = useState('');
const [guideUrl, setGuideUrl] = useState('');
const [guideSaving, setGuideSaving] = useState(false);
@@ -88,10 +88,10 @@ export const ApplicationsTab: React.FC = () => {
const fetchGuides = async () => {
try {
setGuidesLoading(true);
const res = await api.listGuideLinks();
const res = await api.listAppGuides();
setGuides(res.data || []);
} catch (err) {
console.error('Không thể tải danh sách hướng dẫn:', err);
console.error('Không thể tải danh sách hướng dẫn sinh viên:', err);
} finally {
setGuidesLoading(false);
}
@@ -117,7 +117,6 @@ export const ApplicationsTab: React.FC = () => {
setAppName(app.name);
setAppDescription(app.description);
setAppDownloadUrl(app.downloadUrl);
// Standardize representation to 'MacOS'
setAppPlatform(app.platform === 'macOS' ? 'MacOS' : app.platform);
setShowAppModal(true);
};
@@ -127,7 +126,6 @@ export const ApplicationsTab: React.FC = () => {
alert('Vui lòng nhập tên ứng dụng và đường dẫn tải.');
return;
}
// Force write first letters uppercase
let finalPlatform = appPlatform;
if (finalPlatform.toLowerCase() === 'macos') {
finalPlatform = 'MacOS';
@@ -168,7 +166,7 @@ export const ApplicationsTab: React.FC = () => {
setShowGuideModal(true);
};
const handleOpenEditGuide = (guide: GuideLinkItem) => {
const handleOpenEditGuide = (guide: AppGuideItem) => {
setEditingGuide(guide);
setGuideTitle(guide.title);
setGuideUrl(guide.url);
@@ -183,9 +181,9 @@ export const ApplicationsTab: React.FC = () => {
try {
setGuideSaving(true);
if (editingGuide) {
await api.updateGuideLink(editingGuide.id, guideTitle.trim(), guideUrl.trim());
await api.updateAppGuide(editingGuide.id, guideTitle.trim(), guideUrl.trim());
} else {
await api.createGuideLink(guideTitle.trim(), guideUrl.trim());
await api.createAppGuide(guideTitle.trim(), guideUrl.trim());
}
setShowGuideModal(false);
await fetchGuides();
@@ -197,9 +195,9 @@ export const ApplicationsTab: React.FC = () => {
};
const handleDeleteGuide = async (id: number, title: string) => {
if (window.confirm(`Bạn có chắc chắn muốn xóa tài liệu hướng dẫn "${title}"?`)) {
if (window.confirm(`Bạn có chắc chắn muốn xóa tài liệu hướng dẫn sinh viên "${title}"?`)) {
try {
await api.deleteGuideLink(id);
await api.deleteAppGuide(id);
await fetchGuides();
} catch (err: any) {
alert(err.message || 'Xóa hướng dẫn thất bại');
@@ -229,7 +227,6 @@ export const ApplicationsTab: React.FC = () => {
)}
</header>
{/* Sub-tab Switch Header */}
<div style={{ padding: '0 2rem' }}>
<div style={{
display: 'flex',
@@ -388,10 +385,10 @@ export const ApplicationsTab: React.FC = () => {
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
<polyline points="14 2 14 8 20 8" />
</svg>
<p style={{ fontSize: '0.95rem' }}>Chưa tài liệu hướng dẫn nào.</p>
<p style={{ fontSize: '0.95rem' }}>Chưa tài liệu hướng dẫn sinh viên nào.</p>
{isSuperAdmin && (
<button className="btn btn-secondary" onClick={handleOpenAddGuide} style={{ marginTop: '1rem' }}>
Thêm tài liệu hướng dẫn đu tiên
Thêm hướng dẫn sinh viên đu tiên
</button>
)}
</div>
@@ -403,7 +400,7 @@ export const ApplicationsTab: React.FC = () => {
<thead>
<tr>
<th style={{ padding: '1.15rem 1.5rem', width: '15%', fontWeight: 700, color: 'var(--text-secondary)' }}>Loại tài liệu</th>
<th style={{ padding: '1.15rem 1.5rem', width: '50%', fontWeight: 700, color: 'var(--text-secondary)' }}>Tiêu đ hướng dẫn</th>
<th style={{ padding: '1.15rem 1.5rem', width: '50%', fontWeight: 700, color: 'var(--text-secondary)' }}>Tiêu đ hướng dẫn sinh viên</th>
<th style={{ padding: '1.15rem 1.5rem', width: '25%', fontWeight: 700, color: 'var(--text-secondary)' }}>Đưng dẫn liên kết</th>
{isSuperAdmin && <th style={{ padding: '1.15rem 1.5rem', width: '10%', textAlign: 'right', fontWeight: 700, color: 'var(--text-secondary)' }}>Thao tác</th>}
</tr>
@@ -590,7 +587,7 @@ export const ApplicationsTab: React.FC = () => {
<div className="modal-overlay" onClick={() => setShowGuideModal(false)}>
<div className="modal-container" style={{ maxWidth: '480px' }} onClick={e => e.stopPropagation()}>
<div className="modal-header">
<h2 className="modal-title">{editingGuide ? 'Cập nhật hướng dẫn' : 'Thêm tài liệu hướng dẫn'}</h2>
<h2 className="modal-title">{editingGuide ? 'Cập nhật hướng dẫn sinh viên' : 'Thêm tài liệu hướng dẫn sinh viên'}</h2>
<button className="modal-close-btn" onClick={() => setShowGuideModal(false)} aria-label="Đóng">&times;</button>
</div>
<div className="modal-body" style={{ padding: '1.5rem' }}>
@@ -601,7 +598,7 @@ export const ApplicationsTab: React.FC = () => {
type="text"
value={guideTitle}
onChange={e => setGuideTitle(e.target.value)}
placeholder="VD: Hướng dẫn cài đặt và đồng bộ dữ liệu"
placeholder="VD: Hướng dẫn cài đặt và chạy ứng dụng cho sinh viên"
style={{
width: '100%',
padding: '0.6rem 0.85rem',