This commit is contained in:
@@ -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 có tài liệu hướng dẫn nào.</p>
|
||||
<p style={{ fontSize: '0.95rem' }}>Chưa có 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">×</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',
|
||||
|
||||
Reference in New Issue
Block a user