feat: 삭제 다이얼로그 로딩 상태, 업로드 버튼 소실 버그 수정

- 삭제 다이얼로그에 로딩 스피너 표시 및 버튼 비활성화
- 번역/아이콘 업로드 버튼이 로딩 중에도 사라지지 않도록 조건 수정
This commit is contained in:
caadiq 2025-12-26 20:28:26 +09:00
parent b3be6f3a61
commit 4108e4547d

View file

@ -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>