릴리스: v0.1.43 토스트와 즐겨찾기 추가
This commit is contained in:
@@ -1,15 +1,17 @@
|
||||
<script setup>
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import Sortable from 'sortablejs'
|
||||
import * as htmlToImage from 'html-to-image'
|
||||
import { api } from '../lib/api'
|
||||
import { toApiUrl } from '../lib/runtime'
|
||||
import { useAuthStore } from '../stores/auth'
|
||||
import { useToast } from '../composables/useToast'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const auth = useAuthStore()
|
||||
const toast = useToast()
|
||||
const gameId = computed(() => route.params.gameId)
|
||||
const tierListId = computed(() => route.params.tierListId)
|
||||
const gameName = ref('')
|
||||
@@ -41,6 +43,9 @@ const authorAccountName = ref('')
|
||||
const updatedAt = ref(0)
|
||||
const isDragActive = ref(false)
|
||||
const iconSize = ref(80)
|
||||
const isFavoriteBusy = ref(false)
|
||||
const favoriteCount = ref(0)
|
||||
const isFavorited = ref(false)
|
||||
|
||||
const boardEl = ref(null)
|
||||
const exportBoardEl = ref(null)
|
||||
@@ -78,6 +83,13 @@ const untitledWarning = computed(
|
||||
!hasCustomTitle.value &&
|
||||
'제목 없이 저장된 티어표는 무분별한 도배 방지를 위해 관리자에 의해 임의 삭제될 수 있어요.'
|
||||
)
|
||||
const canFavorite = computed(() => !!auth.user && !isNewTierList.value && !canEdit.value)
|
||||
|
||||
watch(error, (message) => {
|
||||
if (!message) return
|
||||
toast.error(message)
|
||||
error.value = ''
|
||||
})
|
||||
|
||||
function formatTitleDate(ts) {
|
||||
const date = new Date(ts)
|
||||
@@ -390,6 +402,8 @@ async function save() {
|
||||
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
|
||||
isSaveModalOpen.value = true
|
||||
} catch (e) {
|
||||
error.value = '저장 실패: 로그인 상태인지 확인해주세요.'
|
||||
@@ -409,12 +423,28 @@ async function removeTierList() {
|
||||
const ok = window.confirm(`"${title.value || gameName.value || '이 티어표'}"를 삭제할까요?`)
|
||||
if (!ok) return
|
||||
await api.deleteTierList(tierListId.value)
|
||||
toast.success('티어표를 삭제했어요.')
|
||||
router.push(gameId.value === 'freeform' ? '/me' : `/games/${gameId.value}`)
|
||||
} catch (e) {
|
||||
error.value = '티어표 삭제에 실패했어요.'
|
||||
}
|
||||
}
|
||||
|
||||
async function toggleFavorite() {
|
||||
if (!canFavorite.value || isFavoriteBusy.value) return
|
||||
try {
|
||||
isFavoriteBusy.value = true
|
||||
const data = isFavorited.value ? await api.unfavoriteTierList(tierListId.value) : await api.favoriteTierList(tierListId.value)
|
||||
favoriteCount.value = Number(data.tierList?.favoriteCount || 0)
|
||||
isFavorited.value = !!data.tierList?.isFavorited
|
||||
toast.success(isFavorited.value ? '즐겨찾기에 추가했어요.' : '즐겨찾기를 해제했어요.')
|
||||
} catch (e) {
|
||||
error.value = '즐겨찾기 처리에 실패했어요.'
|
||||
} finally {
|
||||
isFavoriteBusy.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
;(async () => {
|
||||
await auth.refresh()
|
||||
@@ -455,6 +485,8 @@ onMounted(() => {
|
||||
authorName.value = t.authorName || ''
|
||||
authorAccountName.value = t.authorAccountName || ''
|
||||
updatedAt.value = Number(t.updatedAt || 0)
|
||||
favoriteCount.value = Number(t.favoriteCount || 0)
|
||||
isFavorited.value = !!t.isFavorited
|
||||
groups.value = t.groups
|
||||
const map = {}
|
||||
;(t.pool || []).forEach((it) => (map[it.id] = it))
|
||||
@@ -525,6 +557,9 @@ onUnmounted(() => {
|
||||
<button v-if="canEdit && !isNewTierList" class="btn btn--danger" @click="removeTierList">삭제</button>
|
||||
</div>
|
||||
<div class="actions__right">
|
||||
<button v-if="canFavorite" class="btn btn--ghost" :disabled="isFavoriteBusy" @click="toggleFavorite">
|
||||
{{ isFavorited ? '★ 즐겨찾기' : '☆ 즐겨찾기' }} {{ favoriteCount }}
|
||||
</button>
|
||||
<label class="toggle" :class="{ 'toggle--disabled': !canEdit }">
|
||||
<input v-model="isPublic" type="checkbox" :disabled="!canEdit" />
|
||||
<span>{{ isPublic ? '공개 ON' : '공개 OFF' }}</span>
|
||||
@@ -534,8 +569,6 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div v-if="error" class="error">{{ error }}</div>
|
||||
|
||||
<div v-if="isSaveModalOpen" class="modalOverlay" @click.self="closeSaveModal">
|
||||
<div class="modalCard" role="dialog" aria-modal="true" aria-labelledby="saveModalTitle">
|
||||
<div id="saveModalTitle" class="modalCard__title">저장 완료</div>
|
||||
|
||||
Reference in New Issue
Block a user