feat: 삭제 다이얼로그 로딩 상태, 업로드 버튼 소실 버그 수정
- 삭제 다이얼로그에 로딩 스피너 표시 및 버튼 비활성화 - 번역/아이콘 업로드 버튼이 로딩 중에도 사라지지 않도록 조건 수정
This commit is contained in:
parent
b3be6f3a61
commit
4108e4547d
1 changed files with 30 additions and 14 deletions
|
|
@ -146,14 +146,14 @@ export default function Admin({ isMobile = false }) {
|
||||||
// 파일 상태: { name, status: 'pending' | 'processing' | 'success' | 'error', error?: string, progress?: number }
|
// 파일 상태: { name, status: 'pending' | 'processing' | 'success' | 'error', error?: string, progress?: number }
|
||||||
const [pendingFiles, setPendingFiles] = useState([]);
|
const [pendingFiles, setPendingFiles] = useState([]);
|
||||||
const [isModListExpanded, setIsModListExpanded] = useState(false); // 등록된 모드 목록 펼치기/접기
|
const [isModListExpanded, setIsModListExpanded] = useState(false); // 등록된 모드 목록 펼치기/접기
|
||||||
const [deleteModDialog, setDeleteModDialog] = useState({ show: false, modId: null }); // 모드 삭제 확인 다이얼로그
|
const [deleteModDialog, setDeleteModDialog] = useState({ show: false, modId: null, loading: false }); // 모드 삭제 확인 다이얼로그
|
||||||
const [clearingFiles, setClearingFiles] = useState(false); // 완료 항목 삭제 중 (애니메이션용)
|
const [clearingFiles, setClearingFiles] = useState(false); // 완료 항목 삭제 중 (애니메이션용)
|
||||||
|
|
||||||
// 아이콘 관리 상태
|
// 아이콘 관리 상태
|
||||||
const [iconMods, setIconMods] = useState([]); // 등록된 아이콘 모드 목록
|
const [iconMods, setIconMods] = useState([]); // 등록된 아이콘 모드 목록
|
||||||
const [iconUploading, setIconUploading] = useState(false);
|
const [iconUploading, setIconUploading] = useState(false);
|
||||||
const [isIconDragging, setIsIconDragging] = useState(false);
|
const [isIconDragging, setIsIconDragging] = useState(false);
|
||||||
const [deleteIconDialog, setDeleteIconDialog] = useState({ show: false, modId: null });
|
const [deleteIconDialog, setDeleteIconDialog] = useState({ show: false, modId: null, loading: false });
|
||||||
const [isIconListExpanded, setIsIconListExpanded] = useState(false);
|
const [isIconListExpanded, setIsIconListExpanded] = useState(false);
|
||||||
const [pendingIconFiles, setPendingIconFiles] = useState([]); // 아이콘 파일 대기열
|
const [pendingIconFiles, setPendingIconFiles] = useState([]); // 아이콘 파일 대기열
|
||||||
const [clearingIconFiles, setClearingIconFiles] = useState(false);
|
const [clearingIconFiles, setClearingIconFiles] = useState(false);
|
||||||
|
|
@ -2103,7 +2103,7 @@ export default function Admin({ isMobile = false }) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 업로드 버튼 */}
|
{/* 업로드 버튼 */}
|
||||||
{pendingFiles.some(f => f.status === 'pending') && (
|
{(pendingFiles.some(f => f.status === 'pending') || translationLoading) && (
|
||||||
<button
|
<button
|
||||||
onClick={startTranslationUpload}
|
onClick={startTranslationUpload}
|
||||||
disabled={translationLoading}
|
disabled={translationLoading}
|
||||||
|
|
@ -2292,7 +2292,7 @@ export default function Admin({ isMobile = false }) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 업로드 시작 버튼 */}
|
{/* 업로드 시작 버튼 */}
|
||||||
{pendingIconFiles.some(f => f.status === 'pending') && (
|
{(pendingIconFiles.some(f => f.status === 'pending') || iconUploading) && (
|
||||||
<motion.button
|
<motion.button
|
||||||
onClick={startIconUpload}
|
onClick={startIconUpload}
|
||||||
disabled={iconUploading}
|
disabled={iconUploading}
|
||||||
|
|
@ -2748,19 +2748,27 @@ export default function Admin({ isMobile = false }) {
|
||||||
</p>
|
</p>
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<button
|
<button
|
||||||
onClick={() => setDeleteModDialog({ show: false, modId: null })}
|
onClick={() => setDeleteModDialog({ show: false, modId: null, loading: false })}
|
||||||
className="flex-1 py-2.5 bg-zinc-800 hover:bg-zinc-700 text-white font-medium rounded-xl transition-colors"
|
disabled={deleteModDialog.loading}
|
||||||
|
className="flex-1 py-2.5 bg-zinc-800 hover:bg-zinc-700 disabled:opacity-50 text-white font-medium rounded-xl transition-colors"
|
||||||
>
|
>
|
||||||
취소
|
취소
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
setDeleteModDialog(prev => ({ ...prev, loading: true }));
|
||||||
await handleDeleteTranslation(deleteModDialog.modId);
|
await handleDeleteTranslation(deleteModDialog.modId);
|
||||||
setDeleteModDialog({ show: false, modId: null });
|
setDeleteModDialog({ show: false, modId: null, loading: false });
|
||||||
}}
|
}}
|
||||||
className="flex-1 py-2.5 bg-red-600 hover:bg-red-500 text-white font-medium rounded-xl transition-colors"
|
disabled={deleteModDialog.loading}
|
||||||
|
className="flex-1 py-2.5 bg-red-600 hover:bg-red-500 disabled:bg-red-800 text-white font-medium rounded-xl transition-colors flex items-center justify-center gap-2"
|
||||||
>
|
>
|
||||||
삭제
|
{deleteModDialog.loading ? (
|
||||||
|
<>
|
||||||
|
<Loader2 size={16} className="animate-spin" />
|
||||||
|
삭제 중...
|
||||||
|
</>
|
||||||
|
) : '삭제'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
@ -2791,19 +2799,27 @@ export default function Admin({ isMobile = false }) {
|
||||||
</p>
|
</p>
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<button
|
<button
|
||||||
onClick={() => setDeleteIconDialog({ show: false, modId: null })}
|
onClick={() => setDeleteIconDialog({ show: false, modId: null, loading: false })}
|
||||||
className="flex-1 py-2.5 bg-zinc-800 hover:bg-zinc-700 text-white font-medium rounded-xl transition-colors"
|
disabled={deleteIconDialog.loading}
|
||||||
|
className="flex-1 py-2.5 bg-zinc-800 hover:bg-zinc-700 disabled:opacity-50 text-white font-medium rounded-xl transition-colors"
|
||||||
>
|
>
|
||||||
취소
|
취소
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
setDeleteIconDialog(prev => ({ ...prev, loading: true }));
|
||||||
await deleteIconMod(deleteIconDialog.modId);
|
await deleteIconMod(deleteIconDialog.modId);
|
||||||
setDeleteIconDialog({ show: false, modId: null });
|
setDeleteIconDialog({ show: false, modId: null, loading: false });
|
||||||
}}
|
}}
|
||||||
className="flex-1 py-2.5 bg-red-600 hover:bg-red-500 text-white font-medium rounded-xl transition-colors"
|
disabled={deleteIconDialog.loading}
|
||||||
|
className="flex-1 py-2.5 bg-red-600 hover:bg-red-500 disabled:bg-red-800 text-white font-medium rounded-xl transition-colors flex items-center justify-center gap-2"
|
||||||
>
|
>
|
||||||
삭제
|
{deleteIconDialog.loading ? (
|
||||||
|
<>
|
||||||
|
<Loader2 size={16} className="animate-spin" />
|
||||||
|
삭제 중...
|
||||||
|
</>
|
||||||
|
) : '삭제'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue