feat: implementa funcionalidade de favoritar jogos

This commit is contained in:
2026-05-28 12:47:11 -05:00
parent 20a4a14a4a
commit ac51e11f33
3 changed files with 296 additions and 6 deletions

View File

@@ -88,9 +88,19 @@
<span class="text-xs font-semibold uppercase leading-[1.4] tracking-[0.96px] text-[#777169] md:hidden">
Jogo
</span>
<strong class="text-base font-medium leading-6 tracking-[0.16px] text-[#0c0a09]">
{{ game.name }}
</strong>
<div class="flex items-center gap-2">
<strong class="text-base font-medium leading-6 tracking-[0.16px] text-[#0c0a09]">
{{ game.name }}
</strong>
<button type="button" :disabled="togglingId === game.name"
:aria-label="favoriteIds.has(game.name) ? 'Remover dos favoritos' : 'Adicionar aos favoritos'"
@click="toggleFavorite(game)"
class="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full transition hover:bg-[#f0efed] disabled:cursor-not-allowed disabled:opacity-50">
<Icon
:name="togglingId === game.name ? 'mdi:loading' : favoriteIds.has(game.name) ? 'mdi:heart' : 'mdi:heart-outline'"
:class="['text-base', togglingId === game.name ? 'animate-spin text-[#777169]' : favoriteIds.has(game.name) ? 'text-rose-500' : 'text-[#777169]']" />
</button>
</div>
</div>
<div v-for="stat in getGameStats(game)" :key="stat.label"
@@ -116,6 +126,7 @@ definePageMeta({
})
const RANKINGS_API_BASE_URL = 'https://api-ranking-jogos-production.up.railway.app/api/v1'
const WISHLIST_API_BASE_URL = 'https://gameverse-wishlist-production.up.railway.app'
const rankingOptions = [
{
@@ -195,6 +206,8 @@ const selectedRanking = ref('weekly')
const rankings = ref([])
const isLoading = ref(false)
const errorMessage = ref('')
const favoriteIds = ref(new Set())
const togglingId = ref(null)
const selectedRankingMeta = computed(() => {
return rankingOptions.find((option) => option.value === selectedRanking.value) ?? rankingOptions[0]
@@ -266,8 +279,81 @@ async function fetchRankings() {
}
}
async function fetchFavorites() {
if (!token.value) return
try {
const data = await $fetch(`${WISHLIST_API_BASE_URL}/api/wishlist`, {
headers: {
Authorization: `Bearer ${token.value}`
}
})
const ids = new Set(
(data?.data ?? [])
.filter((item) => item.is_favorite === 1 || item.is_favorite === true)
.map((item) => item.game_id)
)
favoriteIds.value = ids
} catch {
// falha silenciosa — favoritos são secundários ao ranking
}
}
async function toggleFavorite(game) {
if (!token.value) {
await navigateTo('/login')
return
}
const gameId = game.name
togglingId.value = gameId
try {
if (favoriteIds.value.has(gameId)) {
await $fetch(`${WISHLIST_API_BASE_URL}/api/wishlist/${encodeURIComponent(gameId)}`, {
method: 'DELETE',
headers: {
Authorization: `Bearer ${token.value}`
}
})
favoriteIds.value = new Set([...favoriteIds.value].filter((id) => id !== gameId))
$toast.success(`${gameId} removido dos favoritos.`, { duration: 4000 })
} else {
await $fetch(`${WISHLIST_API_BASE_URL}/api/wishlist`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token.value}`
},
body: {
game_id: gameId,
is_wishlist: false,
is_favorite: true,
price_alert: false
}
})
favoriteIds.value = new Set([...favoriteIds.value, gameId])
$toast.success(`${gameId} adicionado aos favoritos!`, { duration: 4000 })
}
} catch (error) {
const statusCode = error?.statusCode ?? error?.response?.status ?? error?.data?.statusCode
if (statusCode === 401) {
clearToken()
$toast.error('Sua sessão expirou. Faça login novamente.', { duration: 8000 })
await navigateTo('/login')
return
}
$toast.error('Erro ao atualizar favoritos. Tente novamente.', { duration: 6000 })
} finally {
togglingId.value = null
}
}
onMounted(() => {
fetchRankings()
fetchFavorites()
})
watch(selectedRanking, () => {