Files
mono/components/desktop/extensions/chatcoop/pages/ChatCoopPage/ui/ChatCoopPage.vue
T
2026-03-28 21:09:57 +05:00

202 lines
5.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template lang="pug">
div
// Лоадер пока получаем статус аккаунта
WindowLoader(v-if="chatcoopStore.isLoading", text="Проверка статуса аккаунта...")
// Сообщение об ошибке
div(v-else-if="chatcoopStore.error", class="error-message")
p {{ chatcoopStore.error }}
button(@click="retryLoadStatus", class="retry-button") Повторить попытку
// Виджет регистрации Matrix аккаунта
MatrixRegistration(
v-else-if="chatcoopStore.accountStatus && !chatcoopStore.accountStatus.hasAccount",
@account-created="handleAccountCreated"
)
// Лоадер пока загружается iframe Matrix клиента
WindowLoader(
v-else-if="iframeSrc && isIframeLoading",
text="Загрузка клиента..."
)
// Заглушка для мобильных устройств
div(v-else-if="isMobile", class="mobile-stub")
div.mobile-stub-content
div.mobile-icon
i.fas.fa-mobile-alt
h2 Мобильный клиент доступен
p На мобильных устройствах кооперативный мессенджер работает только через мобильное приложение Element X.
p Перейдите на страницу с инструкциями по подключению.
q-btn(@click="goToMobileClient", class="mobile-button", color="primary", icon="fa-mobile-alt")
| Перейти к мобильному клиенту
// Iframe с Matrix клиентом после полной загрузки
iframe(
v-else-if="iframeSrc",
v-show="!isIframeLoading",
:src="iframeSrc",
class="matrix-iframe",
frameborder="0",
width="100%",
:style="{ height: 'calc(100vh - 51px)' }"
@load="onIframeLoaded"
allow="camera; microphone; display-capture"
)
</template>
<script lang="ts" setup>
import { computed, ref, onMounted, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { WindowLoader } from 'src/shared/ui/Loader';
import { useChatCoopChatStore } from '../../../entities/ChatCoopChat/model';
import { MatrixRegistration } from '../../../widgets/MatrixRegistration';
import { useWindowSize } from 'src/shared/hooks/useWindowSize';
import { buildMatrixIframeSrc } from '../../../shared/lib/matrixIframeDeepLink';
const chatcoopStore = useChatCoopChatStore();
const router = useRouter();
const route = useRoute();
const { isMobile } = useWindowSize();
const isIframeLoading = ref(true);
let iframeLoadTimeout: number | null = null;
const matrixRoomParam = computed((): string | undefined => {
const q = route.query.matrix_room;
if (Array.isArray(q)) return q[0]?.toString();
return typeof q === 'string' ? q : undefined;
});
const iframeSrc = computed((): string | undefined => {
const base = chatcoopStore.accountStatus?.iframeUrl;
if (!base) return undefined;
return buildMatrixIframeSrc(base, matrixRoomParam.value);
});
function startIframeLoading() {
if (!iframeSrc.value) return;
isIframeLoading.value = true;
// Очищаем предыдущий таймаут
if (iframeLoadTimeout) {
clearTimeout(iframeLoadTimeout);
}
// Устанавливаем таймаут на 5 секунд как fallback
iframeLoadTimeout = window.setTimeout(() => {
isIframeLoading.value = false;
}, 5000);
}
// Сбрасываем состояние загрузки iframe при изменении URL
watch(iframeSrc, () => {
startIframeLoading();
});
function onIframeLoaded() {
// Очищаем таймаут, если загрузка произошла раньше
if (iframeLoadTimeout) {
clearTimeout(iframeLoadTimeout);
iframeLoadTimeout = null;
}
isIframeLoading.value = false;
}
async function retryLoadStatus() {
chatcoopStore.clearError();
await chatcoopStore.loadAccountStatus();
}
async function handleAccountCreated() {
// После успешного создания аккаунта перезагружаем статус
await chatcoopStore.loadAccountStatus();
}
function goToMobileClient() {
router.push({ name: 'chatcoop-mobile' });
}
onMounted(async () => {
await chatcoopStore.loadAccountStatus();
// Инициализируем загрузку iframe после получения статуса аккаунта
startIframeLoading();
});
</script>
<style scoped>
.matrix-iframe {
width: 100%;
border: none;
display: block;
}
.error-message {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: calc(100vh - 51px);
text-align: center;
padding: 2rem;
}
.error-message p {
margin-bottom: 1rem;
color: #dc3545;
font-size: 1.1rem;
}
.retry-button {
padding: 0.5rem 1rem;
background-color: #007bff;
color: white;
border: none;
border-radius: 0.25rem;
cursor: pointer;
font-size: 1rem;
}
.retry-button:hover {
background-color: #0056b3;
}
.mobile-stub {
display: flex;
align-items: center;
justify-content: center;
height: calc(100vh - 51px);
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.mobile-stub-content {
text-align: center;
padding: 2rem;
max-width: 400px;
}
.mobile-icon {
font-size: 4rem;
margin-bottom: 1.5rem;
opacity: 0.9;
}
.mobile-stub-content h2 {
margin: 0 0 1rem 0;
font-size: 2rem;
font-weight: 600;
}
.mobile-stub-content p {
margin: 0 0 1.5rem 0;
opacity: 0.9;
line-height: 1.6;
font-size: 1.1rem;
}
.mobile-button {
margin-top: 1rem;
}
</style>