ваше сообщение коммита
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="email-connection">
|
||||
<div v-if="!showVerification">
|
||||
<div v-if="!showVerification" class="email-form">
|
||||
<input
|
||||
v-model="email"
|
||||
type="email"
|
||||
@@ -12,10 +12,11 @@
|
||||
:disabled="isLoading || !isValidEmail"
|
||||
class="email-btn"
|
||||
>
|
||||
Получить код
|
||||
{{ isLoading ? 'Отправка...' : 'Получить код' }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-else class="verification-form">
|
||||
<p class="verification-info">Код отправлен на {{ email }}</p>
|
||||
<input
|
||||
v-model="code"
|
||||
type="text"
|
||||
@@ -24,10 +25,16 @@
|
||||
/>
|
||||
<button
|
||||
@click="verifyCode"
|
||||
:disabled="isLoading"
|
||||
:disabled="isLoading || !code"
|
||||
class="verify-btn"
|
||||
>
|
||||
Подтвердить
|
||||
{{ isLoading ? 'Проверка...' : 'Подтвердить' }}
|
||||
</button>
|
||||
<button
|
||||
@click="resetForm"
|
||||
class="reset-btn"
|
||||
>
|
||||
Изменить email
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="error" class="error">{{ error }}</div>
|
||||
@@ -36,21 +43,17 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import axios from 'axios';
|
||||
import axios from '@/api/axios';
|
||||
import { useAuth } from '@/composables/useAuth';
|
||||
|
||||
const props = defineProps({
|
||||
onEmailAuth: {
|
||||
type: Function,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
const emit = defineEmits(['close']);
|
||||
const { linkIdentity } = useAuth();
|
||||
|
||||
const email = ref('');
|
||||
const code = ref('');
|
||||
const error = ref('');
|
||||
const isLoading = ref(false);
|
||||
const showVerification = ref(false);
|
||||
const isConnecting = ref(false);
|
||||
|
||||
const isValidEmail = computed(() => {
|
||||
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.value);
|
||||
@@ -59,11 +62,19 @@ const isValidEmail = computed(() => {
|
||||
const requestCode = async () => {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
await props.onEmailAuth(email.value);
|
||||
showVerification.value = true;
|
||||
error.value = '';
|
||||
|
||||
const response = await axios.post('/api/auth/email/request-verification', {
|
||||
email: email.value
|
||||
});
|
||||
|
||||
if (response.data.success) {
|
||||
showVerification.value = true;
|
||||
} else {
|
||||
error.value = response.data.error || 'Ошибка отправки кода';
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = err.message || 'Ошибка отправки кода';
|
||||
error.value = err.response?.data?.error || 'Ошибка отправки кода';
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
@@ -72,37 +83,80 @@ const requestCode = async () => {
|
||||
const verifyCode = async () => {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
await props.onEmailAuth(email.value, code.value);
|
||||
error.value = '';
|
||||
|
||||
const response = await axios.post('/api/auth/email/verify', {
|
||||
email: email.value,
|
||||
code: code.value
|
||||
});
|
||||
|
||||
if (response.data.success) {
|
||||
// Связываем email с текущим пользователем
|
||||
await linkIdentity('email', email.value);
|
||||
emit('close');
|
||||
} else {
|
||||
error.value = response.data.error || 'Неверный код';
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = err.message || 'Неверный код';
|
||||
error.value = err.response?.data?.error || 'Ошибка проверки кода';
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
email.value = '';
|
||||
code.value = '';
|
||||
error.value = '';
|
||||
showVerification.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.email-connection {
|
||||
margin: 10px 0;
|
||||
padding: 20px;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.email-form,
|
||||
.verification-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.email-input,
|
||||
.code-input {
|
||||
padding: 8px;
|
||||
margin-right: 10px;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.email-btn,
|
||||
.verify-btn,
|
||||
.reset-btn {
|
||||
padding: 10px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.email-btn,
|
||||
.verify-btn {
|
||||
padding: 10px 20px;
|
||||
background-color: #48bb78;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
background-color: #e2e8f0;
|
||||
color: #4a5568;
|
||||
}
|
||||
|
||||
.verification-info {
|
||||
color: #4a5568;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,68 +1,135 @@
|
||||
<template>
|
||||
<div class="telegram-connect">
|
||||
<p>Подключите свой аккаунт Telegram для быстрой авторизации.</p>
|
||||
<button @click="connectTelegram" class="connect-button">
|
||||
<span class="telegram-icon">📱</span> Подключить Telegram
|
||||
</button>
|
||||
|
||||
<div v-if="loading" class="loading">Загрузка...</div>
|
||||
<div v-if="!showQR" class="intro">
|
||||
<p>Подключите свой аккаунт Telegram для быстрой авторизации</p>
|
||||
<button @click="startConnection" class="connect-button" :disabled="loading">
|
||||
<span class="telegram-icon">📱</span>
|
||||
{{ loading ? 'Загрузка...' : 'Подключить Telegram' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-else class="qr-section">
|
||||
<p>Отсканируйте QR-код в приложении Telegram</p>
|
||||
<div class="qr-container" v-html="qrCode"></div>
|
||||
<p class="or-divider">или</p>
|
||||
<a :href="botLink" target="_blank" class="bot-link">
|
||||
Открыть бота в Telegram
|
||||
</a>
|
||||
<button @click="resetConnection" class="reset-button">
|
||||
Отмена
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="error" class="error">{{ error }}</div>
|
||||
<div v-if="success" class="success">{{ success }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import axios from 'axios';
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import axios from '@/api/axios';
|
||||
import { useAuth } from '@/composables/useAuth';
|
||||
import QRCode from 'qrcode';
|
||||
|
||||
const emit = defineEmits(['close']);
|
||||
const { linkIdentity } = useAuth();
|
||||
|
||||
const loading = ref(false);
|
||||
const error = ref('');
|
||||
const success = ref('');
|
||||
const isConnecting = ref(false);
|
||||
const showQR = ref(false);
|
||||
const qrCode = ref('');
|
||||
const botLink = ref('');
|
||||
const pollInterval = ref(null);
|
||||
const connectionToken = ref('');
|
||||
|
||||
async function connectTelegram() {
|
||||
const startConnection = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
error.value = '';
|
||||
success.value = '';
|
||||
|
||||
// Запрос на получение ссылки для авторизации через Telegram
|
||||
const response = await axios.get('/api/auth/telegram', {
|
||||
withCredentials: true
|
||||
});
|
||||
const response = await axios.post('/api/auth/telegram/start-connection');
|
||||
|
||||
if (response.data.error) {
|
||||
error.value = `Ошибка при подключении Telegram: ${response.data.error}`;
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.data.authUrl) {
|
||||
success.value = 'Перейдите по ссылке для авторизации через Telegram';
|
||||
window.open(response.data.authUrl, '_blank');
|
||||
if (response.data.success) {
|
||||
connectionToken.value = response.data.token;
|
||||
botLink.value = `https://t.me/${response.data.botUsername}?start=${connectionToken.value}`;
|
||||
|
||||
// Генерируем QR-код
|
||||
const qr = await QRCode.toDataURL(botLink.value);
|
||||
qrCode.value = `<img src="${qr}" alt="Telegram QR Code" />`;
|
||||
|
||||
showQR.value = true;
|
||||
startPolling();
|
||||
} else {
|
||||
error.value = 'Не удалось получить ссылку для авторизации';
|
||||
error.value = response.data.error || 'Не удалось начать процесс подключения';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error connecting Telegram:', err);
|
||||
error.value = 'Ошибка при подключении Telegram';
|
||||
error.value = err.response?.data?.error || 'Ошибка при подключении Telegram';
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const checkConnection = async () => {
|
||||
try {
|
||||
const response = await axios.post('/api/auth/telegram/check-connection', {
|
||||
token: connectionToken.value
|
||||
});
|
||||
|
||||
if (response.data.success && response.data.telegramId) {
|
||||
// Связываем Telegram с текущим пользователем
|
||||
await linkIdentity('telegram', response.data.telegramId);
|
||||
stopPolling();
|
||||
emit('close');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking connection:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const startPolling = () => {
|
||||
pollInterval.value = setInterval(checkConnection, 2000);
|
||||
};
|
||||
|
||||
const stopPolling = () => {
|
||||
if (pollInterval.value) {
|
||||
clearInterval(pollInterval.value);
|
||||
pollInterval.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
const resetConnection = () => {
|
||||
stopPolling();
|
||||
showQR.value = false;
|
||||
error.value = '';
|
||||
qrCode.value = '';
|
||||
botLink.value = '';
|
||||
connectionToken.value = '';
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
stopPolling();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.telegram-connect {
|
||||
padding: 20px;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.intro,
|
||||
.qr-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.connect-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px 15px;
|
||||
padding: 10px 20px;
|
||||
background-color: #0088cc;
|
||||
color: white;
|
||||
border: none;
|
||||
@@ -72,7 +139,7 @@ async function connectTelegram() {
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.connect-button:hover {
|
||||
.connect-button:hover:not(:disabled) {
|
||||
background-color: #0077b5;
|
||||
}
|
||||
|
||||
@@ -81,23 +148,60 @@ async function connectTelegram() {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.loading, .error, .success {
|
||||
.qr-container {
|
||||
background: white;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.loading {
|
||||
background-color: #f8f9fa;
|
||||
.qr-container img {
|
||||
max-width: 200px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.or-divider {
|
||||
color: #666;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.bot-link {
|
||||
color: #0088cc;
|
||||
text-decoration: none;
|
||||
padding: 8px 16px;
|
||||
border: 1px solid #0088cc;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.bot-link:hover {
|
||||
background-color: #0088cc;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.reset-button {
|
||||
padding: 8px 16px;
|
||||
background-color: #e2e8f0;
|
||||
color: #4a5568;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.reset-button:hover {
|
||||
background-color: #cbd5e0;
|
||||
}
|
||||
|
||||
.error {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
color: #e53e3e;
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.success {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
button:disabled {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,53 +1,65 @@
|
||||
<template>
|
||||
<div class="wallet-connection">
|
||||
<button
|
||||
@click="connectWallet"
|
||||
:disabled="isLoading"
|
||||
class="wallet-btn"
|
||||
>
|
||||
{{ isConnected ? 'Подключено' : 'Подключить кошелек' }}
|
||||
</button>
|
||||
<div v-if="!isConnected" class="connect-section">
|
||||
<p>Подключите свой кошелек для доступа к расширенным функциям</p>
|
||||
<button
|
||||
@click="connectWallet"
|
||||
:disabled="isLoading"
|
||||
class="wallet-btn"
|
||||
>
|
||||
<span class="wallet-icon">💳</span>
|
||||
{{ isLoading ? 'Подключение...' : 'Подключить кошелек' }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-else class="status-section">
|
||||
<p>Кошелек подключен</p>
|
||||
<p class="address">{{ formatAddress(address) }}</p>
|
||||
</div>
|
||||
<div v-if="error" class="error">{{ error }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, inject, computed } from 'vue';
|
||||
import { connectWithWallet } from '../../services/wallet';
|
||||
import { ethers } from 'ethers';
|
||||
import { SiweMessage } from 'siwe';
|
||||
import axios from 'axios';
|
||||
import { ref, computed } from 'vue';
|
||||
import { useAuth } from '@/composables/useAuth';
|
||||
import { connectWithWallet } from '@/services/wallet';
|
||||
|
||||
// Определяем props
|
||||
const props = defineProps({
|
||||
isAuthenticated: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
const emit = defineEmits(['close']);
|
||||
const { linkIdentity } = useAuth();
|
||||
|
||||
// Определяем состояние
|
||||
const isLoading = ref(false);
|
||||
const auth = inject('auth');
|
||||
const isConnecting = ref(false);
|
||||
const error = ref('');
|
||||
const address = ref('');
|
||||
|
||||
// Вычисляемое свойство для статуса подключения
|
||||
const isConnected = computed(() => auth.isAuthenticated.value);
|
||||
const isConnected = computed(() => !!address.value);
|
||||
|
||||
const emit = defineEmits(['connect']);
|
||||
const formatAddress = (addr) => {
|
||||
if (!addr) return '';
|
||||
return `${addr.slice(0, 6)}...${addr.slice(-4)}`;
|
||||
};
|
||||
|
||||
// Метод подключения кошелька
|
||||
const connectWallet = async () => {
|
||||
if (isLoading.value) return;
|
||||
|
||||
try {
|
||||
isLoading.value = true;
|
||||
error.value = '';
|
||||
|
||||
// Подключаем кошелек
|
||||
const result = await connectWithWallet();
|
||||
await auth.checkAuth();
|
||||
console.log('Wallet connected, auth state:', auth.isAuthenticated.value);
|
||||
emit('connect', result);
|
||||
} catch (error) {
|
||||
console.error('Error connecting wallet:', error);
|
||||
|
||||
if (result.success) {
|
||||
address.value = result.address;
|
||||
|
||||
// Связываем кошелек с текущим пользователем
|
||||
await linkIdentity('wallet', result.address);
|
||||
emit('close');
|
||||
} else {
|
||||
error.value = result.error || 'Не удалось подключить кошелек';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error connecting wallet:', err);
|
||||
error.value = err.message || 'Произошла ошибка при подключении кошелька';
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
@@ -56,25 +68,57 @@ const connectWallet = async () => {
|
||||
|
||||
<style scoped>
|
||||
.wallet-connection {
|
||||
margin: 10px 0;
|
||||
padding: 20px;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.connect-section,
|
||||
.status-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wallet-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px 20px;
|
||||
background-color: #4a5568;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
transition: background-color 0.2s;
|
||||
font-size: 16px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.wallet-btn:hover:not(:disabled) {
|
||||
background-color: #2d3748;
|
||||
}
|
||||
|
||||
.wallet-btn:disabled {
|
||||
.wallet-icon {
|
||||
margin-right: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.address {
|
||||
font-family: monospace;
|
||||
background-color: #f7fafc;
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #e53e3e;
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import axios from '../api/axios';
|
||||
|
||||
export function useAuth() {
|
||||
@@ -20,7 +20,19 @@ export function useAuth() {
|
||||
try {
|
||||
const response = await axios.get('/api/auth/identities');
|
||||
if (response.data.success) {
|
||||
identities.value = response.data.identities;
|
||||
// Фильтруем идентификаторы: убираем гостевые и оставляем только уникальные
|
||||
const filteredIdentities = response.data.identities
|
||||
.filter(identity => identity.provider !== 'guest')
|
||||
.reduce((acc, identity) => {
|
||||
// Для каждого типа провайдера оставляем только один идентификатор
|
||||
const existingIdentity = acc.find(i => i.provider === identity.provider);
|
||||
if (!existingIdentity) {
|
||||
acc.push(identity);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
identities.value = filteredIdentities;
|
||||
console.log('User identities updated:', identities.value);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -28,6 +40,21 @@ export function useAuth() {
|
||||
}
|
||||
};
|
||||
|
||||
// Периодическое обновление идентификаторов
|
||||
let identitiesInterval;
|
||||
|
||||
const startIdentitiesPolling = () => {
|
||||
if (identitiesInterval) return;
|
||||
identitiesInterval = setInterval(updateIdentities, 30000); // Обновляем каждые 30 секунд
|
||||
};
|
||||
|
||||
const stopIdentitiesPolling = () => {
|
||||
if (identitiesInterval) {
|
||||
clearInterval(identitiesInterval);
|
||||
identitiesInterval = null;
|
||||
}
|
||||
};
|
||||
|
||||
const checkTokenBalances = async (address) => {
|
||||
try {
|
||||
const response = await axios.get(`/api/auth/check-tokens/${address}`);
|
||||
@@ -81,6 +108,15 @@ export function useAuth() {
|
||||
await checkTokenBalances(newAddress);
|
||||
}
|
||||
|
||||
// Обновляем идентификаторы при любом изменении аутентификации
|
||||
if (authenticated) {
|
||||
await updateIdentities();
|
||||
startIdentitiesPolling();
|
||||
} else {
|
||||
stopIdentitiesPolling();
|
||||
identities.value = [];
|
||||
}
|
||||
|
||||
console.log('Auth updated:', {
|
||||
authenticated: isAuthenticated.value,
|
||||
userId: userId.value,
|
||||
@@ -91,11 +127,10 @@ export function useAuth() {
|
||||
});
|
||||
|
||||
// Если пользователь только что аутентифицировался или сменил аккаунт,
|
||||
// пробуем связать сообщения и обновить идентификаторы
|
||||
// пробуем связать сообщения
|
||||
if (authenticated && (!wasAuthenticated || (previousUserId && previousUserId !== newUserId))) {
|
||||
console.log('Auth change detected, linking messages and updating identities');
|
||||
console.log('Auth change detected, linking messages');
|
||||
linkMessages();
|
||||
updateIdentities();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -343,6 +378,11 @@ export function useAuth() {
|
||||
onMounted(async () => {
|
||||
await checkAuth();
|
||||
});
|
||||
|
||||
// Очищаем интервал при размонтировании компонента
|
||||
onUnmounted(() => {
|
||||
stopIdentitiesPolling();
|
||||
});
|
||||
|
||||
return {
|
||||
isAuthenticated,
|
||||
|
||||
@@ -97,22 +97,22 @@
|
||||
</div>
|
||||
|
||||
<!-- Добавляем дополнительные кнопки авторизации -->
|
||||
<div v-if="!isAuthenticated && messages.length > 0" class="auth-buttons">
|
||||
<div v-if="!isAuthenticated" class="auth-buttons">
|
||||
<h3>Авторизация через:</h3>
|
||||
<div v-if="!showTelegramVerification" class="auth-btn-container">
|
||||
<button @click="handleTelegramAuth" class="auth-btn telegram-btn">
|
||||
Подключить Telegram
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="showTelegramVerification" class="verification-block">
|
||||
<div class="verification-code">
|
||||
<div v-if="showTelegramVerification" class="verification-block">
|
||||
<div class="verification-code">
|
||||
<span>Код верификации:</span>
|
||||
<code @click="copyCode(telegramVerificationCode)">{{ telegramVerificationCode }}</code>
|
||||
<code @click="copyCode(telegramVerificationCode)">{{ telegramVerificationCode }}</code>
|
||||
<span v-if="codeCopied" class="copied-message">Скопировано!</span>
|
||||
</div>
|
||||
</div>
|
||||
<a :href="telegramBotLink" target="_blank" class="bot-link">Открыть бота Telegram</a>
|
||||
<button @click="cancelTelegramAuth" class="cancel-btn">Отмена</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Сообщение об ошибке в Telegram -->
|
||||
<div v-if="telegramError" class="error-message">
|
||||
@@ -124,9 +124,9 @@
|
||||
<button @click="handleEmailAuth" class="auth-btn email-btn">
|
||||
Подключить Email
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Форма для Email верификации (встроена в auth-buttons) -->
|
||||
<!-- Форма для Email верификации -->
|
||||
<div v-if="showEmailForm" class="email-form">
|
||||
<p>Введите ваш email для получения кода подтверждения:</p>
|
||||
<div class="email-form-container">
|
||||
@@ -139,15 +139,15 @@
|
||||
/>
|
||||
<button @click="sendEmailVerification" class="send-email-btn" :disabled="isEmailSending">
|
||||
{{ isEmailSending ? 'Отправка...' : 'Отправить код' }}
|
||||
</button>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button @click="cancelEmailAuth" class="cancel-btn">Отмена</button>
|
||||
<p v-if="emailFormatError" class="email-format-error">Пожалуйста, введите корректный email</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Форма для ввода кода верификации Email (встроена в auth-buttons) -->
|
||||
<!-- Форма для ввода кода верификации Email -->
|
||||
<div v-if="showEmailVerificationInput" class="email-verification-form">
|
||||
<p>На ваш email <strong>{{ emailVerificationEmail }}</strong> отправлен код подтверждения.</p>
|
||||
<div class="email-form-container">
|
||||
@@ -164,42 +164,48 @@
|
||||
</div>
|
||||
<button @click="cancelEmailAuth" class="cancel-btn">Отмена</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Сообщение об ошибке в Email -->
|
||||
<div v-if="emailError" class="error-message">
|
||||
{{ emailError }}
|
||||
<button class="close-error" @click="clearEmailError">×</button>
|
||||
</div>
|
||||
<div v-if="emailError" class="error-message">
|
||||
{{ emailError }}
|
||||
<button class="close-error" @click="clearEmailError">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Блок информации о пользователе -->
|
||||
<div v-if="isAuthenticated" class="user-info">
|
||||
<h3>Идентификаторы:</h3>
|
||||
<div class="user-info-item">
|
||||
<span class="user-info-label">Кошелек:</span>
|
||||
<span v-if="auth.address?.value" class="user-info-value">{{ truncateAddress(auth.address.value) }}</span>
|
||||
<span v-if="hasIdentityType('wallet')" class="user-info-value">
|
||||
{{ truncateAddress(getIdentityValue('wallet')) }}
|
||||
</span>
|
||||
<button v-else @click="handleWalletAuth" class="connect-btn">
|
||||
Подключить кошелек
|
||||
</button>
|
||||
</div>
|
||||
<div class="user-info-item">
|
||||
<span class="user-info-label">Telegram:</span>
|
||||
<span v-if="auth.telegramId?.value" class="user-info-value">{{ auth.telegramId.value }}</span>
|
||||
<span v-if="hasIdentityType('telegram')" class="user-info-value">
|
||||
{{ getIdentityValue('telegram') }}
|
||||
</span>
|
||||
<button v-else @click="handleTelegramAuth" class="connect-btn">
|
||||
Подключить Telegram
|
||||
</button>
|
||||
</div>
|
||||
<div class="user-info-item">
|
||||
<span class="user-info-label">Email:</span>
|
||||
<span v-if="auth.email?.value" class="user-info-value">{{ auth.email.value }}</span>
|
||||
<span v-if="hasIdentityType('email')" class="user-info-value">
|
||||
{{ getIdentityValue('email') }}
|
||||
</span>
|
||||
<button v-else @click="handleEmailAuth" class="connect-btn">
|
||||
Подключить Email
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Блок форм подключения -->
|
||||
<div v-if="showEmailForm || showTelegramVerification || showEmailVerificationInput" class="connect-forms">
|
||||
<!-- Блок форм подключения для аутентифицированных пользователей -->
|
||||
<div v-if="isAuthenticated && (showEmailForm || showTelegramVerification || showEmailVerificationInput)" class="connect-forms">
|
||||
<!-- Форма для Email верификации -->
|
||||
<div v-if="showEmailForm" class="email-form">
|
||||
<p>Введите ваш email для получения кода подтверждения:</p>
|
||||
@@ -249,16 +255,6 @@
|
||||
<a :href="telegramBotLink" target="_blank" class="bot-link">Открыть бота Telegram</a>
|
||||
<button @click="cancelTelegramAuth" class="cancel-btn">Отмена</button>
|
||||
</div>
|
||||
|
||||
<!-- Сообщения об ошибках -->
|
||||
<div v-if="telegramError" class="error-message">
|
||||
{{ telegramError }}
|
||||
<button class="close-error" @click="telegramError = ''">×</button>
|
||||
</div>
|
||||
<div v-if="emailError" class="error-message">
|
||||
{{ emailError }}
|
||||
<button class="close-error" @click="clearEmailError">×</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Блок баланса токенов -->
|
||||
@@ -542,6 +538,9 @@ const sendEmailVerification = async () => {
|
||||
console.log('Showing verification code input form for email:', emailVerificationEmail.value);
|
||||
} else {
|
||||
emailError.value = response.data.error || 'Ошибка инициализации аутентификации по email';
|
||||
// Возвращаем форму ввода email в исходное состояние
|
||||
showEmailForm.value = true;
|
||||
showEmailVerificationInput.value = false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error in email init request:', error);
|
||||
@@ -550,6 +549,9 @@ const sendEmailVerification = async () => {
|
||||
} else {
|
||||
emailError.value = 'Ошибка при запросе кода подтверждения';
|
||||
}
|
||||
// Возвращаем форму ввода email в исходное состояние
|
||||
showEmailForm.value = true;
|
||||
showEmailVerificationInput.value = false;
|
||||
} finally {
|
||||
isEmailSending.value = false;
|
||||
}
|
||||
@@ -1401,6 +1403,18 @@ const cancelEmailAuth = () => {
|
||||
emailFormatError.value = false;
|
||||
};
|
||||
|
||||
// Методы для работы с идентификаторами
|
||||
const hasIdentityType = (type) => {
|
||||
if (!auth.identities?.value) return false;
|
||||
return auth.identities.value.some(identity => identity.provider === type);
|
||||
};
|
||||
|
||||
const getIdentityValue = (type) => {
|
||||
if (!auth.identities?.value) return null;
|
||||
const identity = auth.identities.value.find(identity => identity.provider === type);
|
||||
return identity ? identity.provider_id : null;
|
||||
};
|
||||
|
||||
// Функции жизненного цикла
|
||||
onMounted(async () => {
|
||||
console.log('HomeView.vue: компонент загружен');
|
||||
|
||||
Reference in New Issue
Block a user