feat: Toast 알림 시스템 + 어드민 UX 개선
All checks were successful
Client CI/CD / deploy (push) Successful in 29s

- Toast 알림 컴포넌트 추가 (success/error/warn/info)
- AnnouncementAdmin 초기 로딩 상태 + 에러 표시
- DownloadAdmin 로딩 상태 추가
- UserAdmin/AnnouncementAdmin에 Toast 피드백 적용
- API client 5xx/네트워크 에러 자동 재시도

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-15 03:42:20 +09:00
parent f93d81b6d9
commit 254617530c
9 changed files with 190 additions and 13 deletions

View File

@@ -52,9 +52,20 @@ async function parseResponse(res) {
return res.json();
}
export async function apiFetch(path, options = {}) {
export async function apiFetch(path, options = {}, _retryCount = 0) {
const token = localStorage.getItem('token');
const res = await doFetch(path, options, token);
let res;
try {
res = await doFetch(path, options, token);
} catch (e) {
// 네트워크 에러 (오프라인 등) — 재시도
if (_retryCount < 2) {
await delay(1000 * (_retryCount + 1));
return apiFetch(path, options, _retryCount + 1);
}
throw e;
}
if (res.status === 401) {
try {
@@ -79,6 +90,16 @@ export async function apiFetch(path, options = {}) {
}
}
// 5xx 서버 에러 — 최대 2회 재시도 (exponential backoff)
if (res.status >= 500 && _retryCount < 2) {
await delay(1000 * (_retryCount + 1));
return apiFetch(path, options, _retryCount + 1);
}
if (!res.ok) throw await parseError(res);
return parseResponse(res);
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}