feat(src/composables/useFeed.ts): добавляет поддержку бесконечной прокрутки для ленты новостей

 feat(package.json): добавляет скрипт для генерации спрайта и обновляет зависимости
🔧 refactor(src/composables/useChat.ts): упрощает логику управления чатом, убирает устаревшие функции
🔧 refactor(src/views/chat/ChatRoomView.vue): обновляет логику загрузки сообщений с использованием новых хуков
🔧 refactor(src/views/matches/MatchesView.vue): улучшает обработку совпадений с использованием новых хуков
 feat(src/App.vue): добавляет загрузку справочных данных с использованием Vue Query
 feat(src/main.ts): интегрирует Vue Query в приложение для управления состоянием запросов
 feat(src/views/profile/MyProfileView.vue): добавляет мутацию для удаления профиля с использованием Vue Query
🔧 refactor(src/components/layout/BottomNav.vue): заменяет компонент иконки на более универсальный компонент AppIcon
This commit is contained in:
Oscar
2026-06-09 10:29:52 +03:00
parent 56c7fb22e9
commit 78fe3b5a98
46 changed files with 658 additions and 416 deletions

View File

@@ -4,7 +4,7 @@
<h1 class="matches-view__title">
Совпадения
</h1>
<span class="meta">{{ matches.length }} {{ matches.length === 1 ? 'человек' : 'людей' }}</span>
<span class="meta">{{ (matches ?? []).length }} {{ (matches ?? []).length === 1 ? 'человек' : 'людей' }}</span>
</header>
<div v-if="loading" class="matches-view__loading">
@@ -12,7 +12,7 @@
</div>
<EmptyState
v-else-if="matches.length === 0"
v-else-if="(matches ?? []).length === 0"
title="Пока нет совпадений"
description="Ставьте лайки, чтобы находить тех, кто ответит взаимностью"
icon="heart"
@@ -20,7 +20,7 @@
<div v-else class="matches-list">
<article
v-for="match in matches"
v-for="match in (matches ?? [])"
:key="match.id"
class="match-card"
>
@@ -61,26 +61,25 @@
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { computed } from 'vue'
import { useRouter } from 'vue-router'
import type { MatchDto, ProfileResponseDto } from '@/api/api'
import { apiClient } from '@/api/client'
import AppButton from '@/components/common/AppButton.vue'
import EmptyState from '@/components/common/EmptyState.vue'
import LoadingSpinner from '@/components/common/LoadingSpinner.vue'
import { useAuth } from '@/composables/useAuth'
import { useChat } from '@/composables/useChat'
import { useUi } from '@/composables/useUi'
type EnrichedMatch = MatchDto & { partnerProfile: ProfileResponseDto }
import { useChatsQuery } from '@/queries/useChatsQuery'
import { useMatchesQuery } from '@/queries/useMatchesQuery'
import type { EnrichedMatch } from '@/queries/useMatchesQuery'
const authStore = useAuth()
const chatStore = useChat()
const uiStore = useUi()
const router = useRouter()
const matches = ref<EnrichedMatch[]>([])
const loading = ref(false)
const profileId = computed(() => authStore.activeProfile?.id)
const { data: matches, isLoading: loading } = useMatchesQuery(profileId)
const { openChat: openChatMutation } = useChatsQuery(profileId)
function calcAge(birthDate: string): number | undefined {
const birth = new Date(birthDate)
@@ -93,42 +92,14 @@ function calcAge(birthDate: string): number | undefined {
return age
}
onMounted(async () => {
const profileId = authStore.activeProfile?.id
if (!profileId)
return
loading.value = true
try {
const matchDtos = await apiClient.api.likesControllerGetMyMatches({ profileId })
matches.value = await Promise.all(
matchDtos.map(async (m) => {
const partnerProfileId = m.profile1Id === profileId ? m.profile2Id : m.profile1Id
const partnerProfile = await apiClient.api.profilesControllerFindOne(partnerProfileId)
return { ...m, partnerProfile }
}),
)
}
catch {
uiStore.addToast('Не удалось загрузить совпадения', 'error')
}
finally {
loading.value = false
}
})
async function openChat(match: EnrichedMatch) {
const profileId = authStore.activeProfile?.id
if (!profileId)
return
try {
const chat = await chatStore.openChat(profileId, match.id)
const chat = await openChatMutation.mutateAsync({ matchId: match.id })
router.push(`/chats/${chat.id}`)
}
catch (err: unknown) {
const msg = (err as { response?: { data?: { message?: string } } })
?.response
?.data
?.message ?? 'Не удалось открыть чат'
?.response?.data?.message ?? 'Не удалось открыть чат'
uiStore.addToast(msg, 'error')
}
}