diff --git a/docs/history.md b/docs/history.md index 17058b3..a4f7c7b 100644 --- a/docs/history.md +++ b/docs/history.md @@ -1,5 +1,8 @@ # 의사결정 이력 +## 2026-03-27 v0.1.50 +- 신규 티어표 저장 직후 요청 실패는 별도 요청용 티어표를 또 만드는 것보다, 방금 저장된 실제 티어표 ID를 그대로 이어받아 요청하는 편이 구조가 단순하고 안전하다고 판단했다. + ## 2026-03-27 v0.1.49 - 템플릿 등록 요청 모달은 체크리스트 설명이 먼저 읽히고 상태가 우측에서 한눈에 보여야 하므로, 라벨 좌측·상태 우측 구조로 정리하기로 했다. - 관리자 입장에서는 `요청 목록`과 `저장된 전체 티어표 목록`이 서로 다른 성격이므로, 같은 화면 안에서도 서브 탭으로 분리해 맥락을 명확히 하는 편이 더 적합하다고 판단했다. diff --git a/docs/spec.md b/docs/spec.md index 3591226..ad07de8 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -150,6 +150,7 @@ - 제목 입력이 비어 있는 동안에는 무분별한 도배 방지를 위한 관리자 임의 삭제 가능성 안내 문구를 표시한다. - `freeform` 티어표는 보드가 비어 있고 커스텀 아이템이 준비된 상태에서만 `템플릿 등록 요청`을 보낼 수 있다. - `템플릿 등록 요청` 전에는 체크리스트 모달로 `제목 직접 입력`, `보드 비움 상태`를 확인하고 두 조건이 충족될 때만 전송할 수 있다. +- 신규 티어표를 막 저장한 직후에도, 템플릿 요청은 새로 발급된 실제 티어표 ID를 기준으로 이어서 처리한다. - 기존 게임 티어표는 커스텀 아이템이 포함되어 있으면 `템플릿 업데이트 요청`을 보낼 수 있다. - 티어표는 편집 화면에서 16:9 썸네일 이미지를 별도로 선택해 저장할 수 있고, 목록 카드에서는 그 이미지를 상단 대표 썸네일로 사용한다. - 편집 화면 상단 헤더는 좌측 제목/설명, 우측 썸네일 카드 구조를 사용하며 모바일에서는 한 열로 접힌다. diff --git a/docs/update.md b/docs/update.md index 84d34bf..f31d574 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,5 +1,8 @@ # 업데이트 로그 +## 2026-03-27 v0.1.50 +- **신규 티어표 등록 요청 타이밍 수정**: 막 저장한 티어표에서 곧바로 템플릿 등록 요청을 보낼 때도 `new`가 아닌 실제 저장된 티어표 ID로 이어서 요청하도록 수정해, 신규 작성 직후 요청 실패 문제를 해결 + ## 2026-03-27 v0.1.49 - **템플릿 등록 요청 모달 레이아웃 보정**: 체크리스트 문구 줄바꿈과 버튼 겹침 문제를 수정하고, 설명은 좌측·상태 배지는 우측에 배치되도록 요청 모달 레이아웃을 다시 정리 - **관리자 티어표 화면 분리**: `티어표 관리` 탭 안에서 `템플릿 요청 관리 / 전체 티어표 관리`를 서브 탭으로 분리해, 요청 목록과 저장된 전체 티어표 목록이 섞여 보이지 않도록 개선 diff --git a/frontend/src/views/TierEditorView.vue b/frontend/src/views/TierEditorView.vue index 5f3ee20..7f41faa 100644 --- a/frontend/src/views/TierEditorView.vue +++ b/frontend/src/views/TierEditorView.vue @@ -443,14 +443,17 @@ async function persistTierList({ showModal = false } = {}) { await uploadPendingThumbnail() const payload = buildPayload(tierListId.value && tierListId.value !== 'new' ? tierListId.value : null) const res = await api.saveTierList(payload) - if (tierListId.value === 'new') history.replaceState({}, '', `/editor/${gameId.value}/${res.tierList.id}`) + const savedTierListId = res.tierList?.id || tierListId.value + if (tierListId.value === 'new' && res.tierList?.id) { + await router.replace(`/editor/${gameId.value}/${res.tierList.id}`) + } updatedAt.value = Number(res.tierList?.updatedAt || Date.now()) authorName.value = res.tierList?.authorName || effectiveAuthorName.value authorAccountName.value = res.tierList?.authorAccountName || authorAccountName.value favoriteCount.value = Number(res.tierList?.favoriteCount || favoriteCount.value || 0) isFavorited.value = !!res.tierList?.isFavorited if (showModal) isSaveModalOpen.value = true - return res + return { ...res, savedTierListId } } async function save() { @@ -514,8 +517,8 @@ async function requestTemplate(type) { try { isRequestingTemplate.value = true - await persistTierList({ showModal: false }) - await api.requestTierListTemplate(tierListId.value, { type }) + const persisted = await persistTierList({ showModal: false }) + await api.requestTierListTemplate(persisted.savedTierListId, { type }) if (type === 'create') closeTemplateRequestModal() toast.success(type === 'create' ? '템플릿 등록 요청을 보냈어요.' : '템플릿 업데이트 요청을 보냈어요.') } catch (e) {