205 lines
7.7 KiB
Vue
205 lines
7.7 KiB
Vue
<!--
|
||
Copyright (c) 2024-2025 Тарабанов Александр Викторович
|
||
All rights reserved.
|
||
|
||
This software is proprietary and confidential.
|
||
Unauthorized copying, modification, or distribution is prohibited.
|
||
|
||
For licensing inquiries: info@hb3-accelerator.com
|
||
Website: https://hb3-accelerator.com
|
||
GitHub: https://github.com/HB3-ACCELERATOR
|
||
-->
|
||
|
||
<template>
|
||
<div id="app">
|
||
<div v-if="isLoading" class="loading-overlay">
|
||
<div class="loading-spinner" />
|
||
</div>
|
||
|
||
<RouterView v-slot="{ Component }">
|
||
<component
|
||
:is="Component"
|
||
:isAuthenticated="auth.isAuthenticated.value"
|
||
:identities="auth.identities.value"
|
||
:tokenBalances="tokenBalances"
|
||
:isLoadingTokens="isLoadingTokens"
|
||
@auth-action-completed="handleAuthActionCompleted"
|
||
/>
|
||
</RouterView>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, watch, onMounted, computed, onUnmounted } from 'vue';
|
||
import { RouterView } from 'vue-router';
|
||
import { useAuth, provideAuth } from './composables/useAuth';
|
||
import { fetchTokenBalances } from './services/tokens';
|
||
import eventBus from './utils/eventBus';
|
||
|
||
// Импорт стилей
|
||
import './assets/styles/variables.css';
|
||
import './assets/styles/base.css';
|
||
import './assets/styles/layout.css';
|
||
import './assets/styles/global.css';
|
||
|
||
// Состояние загрузки
|
||
const isLoading = ref(false);
|
||
|
||
// Использование composable для аутентификации
|
||
const auth = useAuth();
|
||
|
||
// --- Логика загрузки баланса токенов ---
|
||
const tokenBalances = ref({});
|
||
const isLoadingTokens = ref(false);
|
||
|
||
const identities = computed(() => auth.identities.value);
|
||
|
||
const hasIdentityType = (type) => {
|
||
if (!identities.value) return false;
|
||
return identities.value.some((identity) => identity.provider === type);
|
||
};
|
||
|
||
const getIdentityValue = (type) => {
|
||
if (!identities.value) return null;
|
||
const identity = identities.value.find((identity) => identity.provider === type);
|
||
return identity ? identity.provider_id : null;
|
||
};
|
||
|
||
const refreshTokenBalances = async () => {
|
||
if (!hasIdentityType('wallet') || !auth.isAuthenticated.value) {
|
||
tokenBalances.value = {}; // Очищаем, если нет кошелька или не авторизован
|
||
return;
|
||
}
|
||
|
||
isLoadingTokens.value = true;
|
||
try {
|
||
const walletAddress = getIdentityValue('wallet');
|
||
// console.log('[App] Обновление балансов для адреса:', walletAddress);
|
||
|
||
const balances = await fetchTokenBalances(walletAddress);
|
||
// console.log('[App] Полученные балансы:', balances);
|
||
|
||
tokenBalances.value = balances || {};
|
||
} catch (error) {
|
||
// console.error('[App] Ошибка при получении балансов:', error);
|
||
tokenBalances.value = {};
|
||
} finally {
|
||
isLoadingTokens.value = false;
|
||
}
|
||
};
|
||
|
||
// Следим за изменениями в идентификаторах
|
||
watch(identities, (newIdentities, oldIdentities) => {
|
||
if (auth.isAuthenticated.value) {
|
||
const newWalletId = getIdentityValue('wallet');
|
||
const oldWalletIdentity = oldIdentities ? oldIdentities.find(id => id.provider === 'wallet') : null;
|
||
const oldWalletId = oldWalletIdentity ? oldWalletIdentity.provider_id : null;
|
||
|
||
if (newWalletId !== oldWalletId) {
|
||
// console.log('[App] Обнаружено изменение идентификатора кошелька, обновляем балансы');
|
||
refreshTokenBalances();
|
||
} else if (hasIdentityType('wallet') && Object.keys(tokenBalances.value).length === 0 && !isLoadingTokens.value) {
|
||
// Если кошелек есть, но баланс пустой и не грузится - пробуем загрузить
|
||
// console.log('[App] Кошелек есть, но баланс пуст, пытаемся загрузить.');
|
||
refreshTokenBalances();
|
||
}
|
||
}
|
||
}, { deep: true });
|
||
|
||
// Мониторинг изменений состояния аутентификации
|
||
watch(auth.isAuthenticated, (isAuth) => {
|
||
// console.log('[App] Состояние аутентификации изменилось:', isAuth);
|
||
if (isAuth) {
|
||
// Убираем задержку, полагаемся на watch(identities) или прямо вызываем
|
||
// setTimeout(refreshTokenBalances, 500);
|
||
refreshTokenBalances(); // Вызываем сразу, если нужно обновить при смене auth
|
||
} else {
|
||
// Очищаем баланс при выходе
|
||
tokenBalances.value = {};
|
||
}
|
||
});
|
||
|
||
// --- Возвращаем и улучшаем функцию-обработчик ---
|
||
const handleAuthActionCompleted = async () => {
|
||
// console.log('[App] Auth action completed, triggering updates...');
|
||
isLoading.value = true; // Показываем индикатор загрузки
|
||
try {
|
||
// 1. Проверяем аутентификацию (обновит identities и isAuthenticated)
|
||
await auth.checkAuth();
|
||
// console.log('[App] auth.checkAuth() completed. isAuthenticated:', auth.isAuthenticated.value);
|
||
|
||
// 2. Обновляем баланс (использует обновленные identities)
|
||
await refreshTokenBalances();
|
||
// console.log('[App] refreshTokenBalances() completed.');
|
||
|
||
// 3. Явно оповещаем компоненты об изменении состояния авторизации
|
||
// Передаем актуальное состояние из useAuth
|
||
eventBus.emit('auth-state-changed', {
|
||
isAuthenticated: auth.isAuthenticated.value,
|
||
authType: auth.authType.value, // Предполагаем, что authType есть в useAuth
|
||
userId: auth.userId.value, // Предполагаем, что userId есть в useAuth
|
||
fromApp: true // Флаг, что событие от App.vue
|
||
});
|
||
// console.log('[App] auth-state-changed event emitted.');
|
||
|
||
} catch (error) {
|
||
// console.error("[App] Error during auth action handling:", error);
|
||
} finally {
|
||
isLoading.value = false; // Скрываем индикатор загрузки
|
||
}
|
||
};
|
||
|
||
// Первичная загрузка баланса при монтировании, если пользователь уже авторизован
|
||
onMounted(() => {
|
||
if (auth.isAuthenticated.value) {
|
||
refreshTokenBalances();
|
||
}
|
||
|
||
// Подписываемся на событие изменения настроек аутентификации
|
||
const unsubscribe = eventBus.on('auth-settings-saved', () => {
|
||
// console.log('[App] Получено событие сохранения настроек аутентификации, обновляем балансы');
|
||
if (auth.isAuthenticated.value) {
|
||
refreshTokenBalances();
|
||
}
|
||
});
|
||
|
||
// Отписываемся при размонтировании компонента
|
||
onUnmounted(() => {
|
||
if (unsubscribe) {
|
||
unsubscribe();
|
||
}
|
||
});
|
||
});
|
||
|
||
provideAuth();
|
||
</script>
|
||
|
||
<style>
|
||
.loading-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(255, 255, 255, 0.7);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.loading-spinner {
|
||
width: 50px;
|
||
height: 50px;
|
||
border: 5px solid var(--color-grey-light);
|
||
border-top: 5px solid var(--color-primary);
|
||
border-radius: 50%;
|
||
animation: spin 2s linear infinite;
|
||
}
|
||
|
||
@keyframes spin {
|
||
0% { transform: rotate(0deg); }
|
||
100% { transform: rotate(360deg); }
|
||
}
|
||
</style>
|