@coopenomics/desktop 2025.11.20-alpha-2 → 2025.11.24-alpha-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/extensions/coopgram/README.md +65 -0
- package/extensions/coopgram/entities/CoopgramChat/api/index.ts +19 -0
- package/extensions/coopgram/entities/CoopgramChat/index.ts +2 -0
- package/extensions/coopgram/entities/CoopgramChat/model/index.ts +2 -0
- package/extensions/coopgram/entities/CoopgramChat/model/store.ts +58 -0
- package/extensions/coopgram/entities/CoopgramChat/model/types.ts +3 -0
- package/extensions/coopgram/entities/index.ts +1 -0
- package/extensions/coopgram/index.ts +2 -0
- package/extensions/coopgram/install.ts +41 -0
- package/extensions/coopgram/pages/CoopgramPage/features/CreateMatrixAccount/index.ts +2 -0
- package/extensions/coopgram/pages/CoopgramPage/features/CreateMatrixAccount/model/useCreateMatrixAccount.ts +38 -0
- package/extensions/coopgram/pages/CoopgramPage/features/CreateMatrixAccount/ui/CreateMatrixAccountButton.vue +59 -0
- package/extensions/coopgram/pages/CoopgramPage/index.ts +1 -0
- package/extensions/coopgram/pages/CoopgramPage/ui/CoopgramPage.vue +123 -0
- package/extensions/coopgram/pages/CoopgramPage/ui/index.ts +1 -0
- package/extensions/coopgram/pages/index.ts +1 -0
- package/extensions/coopgram/widgets/MatrixRegistration/index.ts +3 -0
- package/extensions/coopgram/widgets/MatrixRegistration/model/types.ts +4 -0
- package/extensions/coopgram/widgets/MatrixRegistration/model/useMatrixRegistration.ts +102 -0
- package/extensions/coopgram/widgets/MatrixRegistration/ui/MatrixRegistration.vue +339 -0
- package/extensions/powerup/POWERUP_TEXTS_SUMMARY.md +121 -0
- package/extensions/powerup/USER_GUIDE.md +240 -0
- package/extensions/powerup/entities/index.ts +2 -0
- package/extensions/powerup/features/index.ts +2 -0
- package/extensions/powerup/index.ts +2 -0
- package/extensions/powerup/install.ts +53 -12
- package/extensions/powerup/pages/LogsPage/index.ts +1 -0
- package/extensions/powerup/pages/LogsPage/ui/LogsPage.vue +17 -0
- package/extensions/powerup/pages/LogsPage/ui/index.ts +1 -0
- package/extensions/powerup/pages/MonitorPage/index.ts +1 -0
- package/extensions/powerup/pages/MonitorPage/ui/MonitorPage.vue +62 -0
- package/extensions/powerup/pages/MonitorPage/ui/index.ts +1 -0
- package/extensions/powerup/pages/SettingsPage/index.ts +1 -0
- package/extensions/powerup/pages/SettingsPage/ui/SettingsPage.vue +126 -0
- package/extensions/powerup/pages/SettingsPage/ui/index.ts +1 -0
- package/extensions/powerup/pages/index.ts +4 -0
- package/extensions/powerup/widgets/AxonWalletCard/index.ts +1 -0
- package/extensions/powerup/widgets/AxonWalletCard/ui/AxonWalletCard.vue +173 -0
- package/extensions/powerup/widgets/CpuResourceWidget/index.ts +1 -0
- package/extensions/powerup/widgets/CpuResourceWidget/ui/CpuResourceWidget.vue +307 -0
- package/extensions/powerup/widgets/NetResourceWidget/index.ts +1 -0
- package/extensions/powerup/widgets/NetResourceWidget/ui/NetResourceWidget.vue +308 -0
- package/extensions/powerup/widgets/PowerupLogItem/index.ts +1 -0
- package/extensions/powerup/widgets/PowerupLogItem/ui/PowerupLogItem.vue +124 -0
- package/extensions/powerup/widgets/PowerupLogItem/ui/index.ts +1 -0
- package/extensions/powerup/widgets/RamResourceWidget/index.ts +1 -0
- package/extensions/powerup/widgets/RamResourceWidget/ui/RamResourceWidget.vue +290 -0
- package/extensions/powerup/widgets/ResourceInfoWidget/index.ts +1 -0
- package/extensions/powerup/widgets/ResourceInfoWidget/ui/ResourceInfoWidget.vue +484 -0
- package/extensions/powerup/widgets/index.ts +7 -0
- package/package.json +6 -6
- package/src/entities/Extension/api/index.ts +15 -1
- package/src/entities/Extension/model/store.ts +13 -1
- package/src/entities/Session/model/store.ts +1 -0
- package/src/pages/Union/ConnectionAgreement/ConnectionAgreementPage.vue +1 -1
- package/src/shared/api/errors.ts +10 -1
- package/src/shared/lib/utils/pluralizeHours.ts +30 -3
- package/src/shared/ui/AxonWalletDisplay/index.ts +1 -0
- package/src/shared/ui/AxonWalletDisplay/ui/AxonWalletDisplay.vue +82 -0
- package/src/shared/ui/ZodForm/ZodForm.vue +129 -14
- package/src/shared/ui/index.ts +2 -0
- package/src/widgets/ConnectionDashboard/ui/SubscriptionsCard.vue +12 -36
- package/src/widgets/ExtensionLogsList/index.ts +1 -0
- package/src/widgets/ExtensionLogsList/ui/ExtensionLogsList.vue +169 -0
- package/src/widgets/ExtensionLogsList/ui/index.ts +1 -0
- package/src/widgets/ExtensionSettings/ui/ExtensionSettings.vue +43 -7
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Coopgram Extension
|
|
2
|
+
|
|
3
|
+
Расширение для интеграции Matrix чата в кооперативную систему.
|
|
4
|
+
|
|
5
|
+
## Описание
|
|
6
|
+
|
|
7
|
+
Coopgram предоставляет встроенный Matrix чат для пользователей кооператива. Расширение:
|
|
8
|
+
|
|
9
|
+
- Получает временный токен аутентификации через GraphQL API
|
|
10
|
+
- Отображает Matrix клиент (Element Web) в iframe
|
|
11
|
+
- Автоматически аутентифицирует пользователя с полученным токеном
|
|
12
|
+
|
|
13
|
+
## Структура
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
coopgram/
|
|
17
|
+
├── install.ts # Конфигурация рабочего стола
|
|
18
|
+
├── entities/
|
|
19
|
+
│ └── CoopgramChat/ # Entity для работы с Matrix токенами
|
|
20
|
+
│ ├── api/ # GraphQL запросы через SDK
|
|
21
|
+
│ └── model/ # Store и типы данных из SDK
|
|
22
|
+
├── pages/
|
|
23
|
+
│ └── CoopgramPage/ # Главная страница с iframe
|
|
24
|
+
├── shared/ # Общие компоненты
|
|
25
|
+
└── widgets/ # Виджеты
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## SDK интеграция
|
|
29
|
+
|
|
30
|
+
Расширение использует типизированные запросы из SDK:
|
|
31
|
+
|
|
32
|
+
- **Query**: `Queries.Coopgram.GetToken`
|
|
33
|
+
- **Selector**: `coopgramTokenSelector`
|
|
34
|
+
- **Типы**: Автоматически генерируются из GraphQL схемы
|
|
35
|
+
|
|
36
|
+
## Работа с iframe URL
|
|
37
|
+
|
|
38
|
+
1. При загрузке страницы вызывается `coopgramStore.loadToken()`
|
|
39
|
+
2. Entity отправляет типизированный GraphQL запрос через SDK: `Queries.Coopgram.GetToken`
|
|
40
|
+
3. Бэкенд проверяет/создает Matrix пользователя и генерирует токен
|
|
41
|
+
4. Бэкенд формирует полную iframe URL с токеном аутентификации
|
|
42
|
+
5. Store сохраняет полученную ссылку в состоянии (типизировано через SDK)
|
|
43
|
+
6. Страница загружает iframe с готовой ссылкой
|
|
44
|
+
7. Пользователь автоматически входит в Matrix чат
|
|
45
|
+
|
|
46
|
+
## Конфигурация
|
|
47
|
+
|
|
48
|
+
- **MATRIX_CLIENT_URL**: URL Element Web клиента
|
|
49
|
+
- **workspace**: 'coopgram'
|
|
50
|
+
- **defaultRoute**: 'chat'
|
|
51
|
+
|
|
52
|
+
## Архитектура
|
|
53
|
+
|
|
54
|
+
Расширение построено по принципам Feature-Sliced Design (FSD):
|
|
55
|
+
|
|
56
|
+
- **Entities**: `CoopgramChat` - бизнес-сущность для работы с Matrix токенами
|
|
57
|
+
- **Pages**: `CoopgramPage` - UI страница без бизнес-логики
|
|
58
|
+
- **Store**: Pinia store для управления состоянием токена
|
|
59
|
+
- **API**: Функции для GraphQL запросов
|
|
60
|
+
|
|
61
|
+
## Зависимости
|
|
62
|
+
|
|
63
|
+
- GraphQL API с resolver `getToken`
|
|
64
|
+
- Matrix Synapse сервер
|
|
65
|
+
- Element Web клиент
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { client } from 'src/shared/api/client';
|
|
2
|
+
import { Queries } from '@coopenomics/sdk';
|
|
3
|
+
import type { ICoopgramAccountStatus } from '../model/types';
|
|
4
|
+
|
|
5
|
+
async function getAccountStatus(): Promise<ICoopgramAccountStatus> {
|
|
6
|
+
const { [Queries.Coopgram.GetAccountStatus.name]: output } = await client.Query(
|
|
7
|
+
Queries.Coopgram.GetAccountStatus.query,
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
hasAccount: output.hasAccount,
|
|
12
|
+
matrixUsername: output.matrixUsername || undefined,
|
|
13
|
+
iframeUrl: output.iframeUrl || undefined,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const api = {
|
|
18
|
+
getAccountStatus,
|
|
19
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { defineStore } from 'pinia';
|
|
2
|
+
import { ref, Ref } from 'vue';
|
|
3
|
+
import { api } from '../api';
|
|
4
|
+
import type { ICoopgramAccountStatus } from './types';
|
|
5
|
+
|
|
6
|
+
const namespace = 'coopgramChatStore';
|
|
7
|
+
|
|
8
|
+
interface ICoopgramChatStore {
|
|
9
|
+
accountStatus: Ref<ICoopgramAccountStatus | null>;
|
|
10
|
+
isLoading: Ref<boolean>;
|
|
11
|
+
error: Ref<string | null>;
|
|
12
|
+
loadAccountStatus: () => Promise<ICoopgramAccountStatus | null>;
|
|
13
|
+
clearAccountStatus: () => void;
|
|
14
|
+
clearError: () => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const useCoopgramChatStore = defineStore(
|
|
18
|
+
namespace,
|
|
19
|
+
(): ICoopgramChatStore => {
|
|
20
|
+
const accountStatus = ref<ICoopgramAccountStatus | null>(null);
|
|
21
|
+
const isLoading = ref(false);
|
|
22
|
+
const error = ref<string | null>(null);
|
|
23
|
+
|
|
24
|
+
const loadAccountStatus = async (): Promise<ICoopgramAccountStatus | null> => {
|
|
25
|
+
isLoading.value = true;
|
|
26
|
+
error.value = null;
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const status = await api.getAccountStatus();
|
|
30
|
+
accountStatus.value = status;
|
|
31
|
+
return status;
|
|
32
|
+
} catch (err) {
|
|
33
|
+
console.error('Failed to load Coopgram account status:', err);
|
|
34
|
+
error.value = 'Не удалось получить статус аккаунта. Попробуйте обновить страницу.';
|
|
35
|
+
return null;
|
|
36
|
+
} finally {
|
|
37
|
+
isLoading.value = false;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const clearAccountStatus = () => {
|
|
42
|
+
accountStatus.value = null;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const clearError = () => {
|
|
46
|
+
error.value = null;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
accountStatus,
|
|
51
|
+
isLoading,
|
|
52
|
+
error,
|
|
53
|
+
loadAccountStatus,
|
|
54
|
+
clearAccountStatus,
|
|
55
|
+
clearError,
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CoopgramChat';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { markRaw } from 'vue';
|
|
2
|
+
import { CoopgramPage } from './pages/CoopgramPage';
|
|
3
|
+
import { agreementsBase } from 'src/shared/lib/consts/workspaces';
|
|
4
|
+
import type { IWorkspaceConfig } from 'src/shared/lib/types/workspace';
|
|
5
|
+
|
|
6
|
+
export default async function (): Promise<IWorkspaceConfig[]> {
|
|
7
|
+
return [{
|
|
8
|
+
workspace: 'coopgram',
|
|
9
|
+
extension_name: 'coopgram',
|
|
10
|
+
title: 'Коопграм',
|
|
11
|
+
icon: 'fa-solid fa-comments',
|
|
12
|
+
defaultRoute: 'chat', // Маршрут по умолчанию для рабочего стола чата
|
|
13
|
+
routes: [
|
|
14
|
+
{
|
|
15
|
+
meta: {
|
|
16
|
+
title: 'Кооперативный мессенджер',
|
|
17
|
+
icon: 'fa-solid fa-comments',
|
|
18
|
+
roles: ['user', 'chairman', 'member'],
|
|
19
|
+
},
|
|
20
|
+
path: '/:coopname/coopgram',
|
|
21
|
+
name: 'coopgram',
|
|
22
|
+
component: markRaw(CoopgramPage),
|
|
23
|
+
children: [
|
|
24
|
+
{
|
|
25
|
+
path: 'chat',
|
|
26
|
+
name: 'coopgram-chat',
|
|
27
|
+
component: markRaw(CoopgramPage),
|
|
28
|
+
meta: {
|
|
29
|
+
title: 'Кооперативный мессенджер',
|
|
30
|
+
icon: 'fa-solid fa-comments',
|
|
31
|
+
roles: ['user', 'chairman', 'member'],
|
|
32
|
+
agreements: agreementsBase,
|
|
33
|
+
requiresAuth: true,
|
|
34
|
+
},
|
|
35
|
+
children: [],
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
}];
|
|
41
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ref } from 'vue';
|
|
2
|
+
import { client } from 'src/shared/api/client';
|
|
3
|
+
import { Mutations } from '@coopenomics/sdk';
|
|
4
|
+
|
|
5
|
+
export function useCreateMatrixAccount() {
|
|
6
|
+
const isLoading = ref(false);
|
|
7
|
+
const error = ref<string | null>(null);
|
|
8
|
+
|
|
9
|
+
const createAccount = async (username: string, password: string): Promise<boolean> => {
|
|
10
|
+
isLoading.value = true;
|
|
11
|
+
error.value = null;
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const { [Mutations.Coopgram.CreateAccount.name]: result } = await client.Mutation(
|
|
15
|
+
Mutations.Coopgram.CreateAccount.mutation,
|
|
16
|
+
{
|
|
17
|
+
variables: {
|
|
18
|
+
data: { username, password },
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
return result;
|
|
24
|
+
} catch (err: any) {
|
|
25
|
+
console.error('Failed to create Matrix account:', err);
|
|
26
|
+
error.value = err?.message || 'Не удалось создать аккаунт Matrix';
|
|
27
|
+
return false;
|
|
28
|
+
} finally {
|
|
29
|
+
isLoading.value = false;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
createAccount,
|
|
35
|
+
isLoading,
|
|
36
|
+
error,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
button.create-account-button(
|
|
3
|
+
@click="handleCreateAccount",
|
|
4
|
+
:disabled="isLoading || !password",
|
|
5
|
+
type="button"
|
|
6
|
+
)
|
|
7
|
+
span(v-if="isLoading") Создание аккаунта...
|
|
8
|
+
span(v-else) Создать аккаунт Matrix
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script lang="ts" setup>
|
|
12
|
+
import { useCreateMatrixAccount } from '../model/useCreateMatrixAccount';
|
|
13
|
+
|
|
14
|
+
const props = defineProps<{
|
|
15
|
+
username: string;
|
|
16
|
+
password: string;
|
|
17
|
+
}>();
|
|
18
|
+
|
|
19
|
+
const emit = defineEmits<{
|
|
20
|
+
success: [];
|
|
21
|
+
error: [message: string];
|
|
22
|
+
}>();
|
|
23
|
+
|
|
24
|
+
const { createAccount, isLoading, error } = useCreateMatrixAccount();
|
|
25
|
+
|
|
26
|
+
const handleCreateAccount = async () => {
|
|
27
|
+
const success = await createAccount(props.username, props.password);
|
|
28
|
+
|
|
29
|
+
if (success) {
|
|
30
|
+
emit('success');
|
|
31
|
+
} else {
|
|
32
|
+
emit('error', error.value || 'Не удалось создать аккаунт');
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<style scoped>
|
|
38
|
+
.create-account-button {
|
|
39
|
+
padding: 0.875rem 2rem;
|
|
40
|
+
background-color: #28a745;
|
|
41
|
+
color: white;
|
|
42
|
+
border: none;
|
|
43
|
+
border-radius: 6px;
|
|
44
|
+
font-size: 1rem;
|
|
45
|
+
font-weight: 500;
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
transition: background-color 0.2s;
|
|
48
|
+
width: 100%;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.create-account-button:hover:not(:disabled) {
|
|
52
|
+
background-color: #218838;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.create-account-button:disabled {
|
|
56
|
+
background-color: #6c757d;
|
|
57
|
+
cursor: not-allowed;
|
|
58
|
+
}
|
|
59
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ui'
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
div
|
|
3
|
+
// Лоадер пока получаем статус аккаунта
|
|
4
|
+
WindowLoader(v-if="coopgramStore.isLoading", text="Проверка статуса аккаунта...")
|
|
5
|
+
|
|
6
|
+
// Сообщение об ошибке
|
|
7
|
+
div(v-else-if="coopgramStore.error", class="error-message")
|
|
8
|
+
p {{ coopgramStore.error }}
|
|
9
|
+
button(@click="retryLoadStatus", class="retry-button") Повторить попытку
|
|
10
|
+
|
|
11
|
+
// Виджет регистрации Matrix аккаунта
|
|
12
|
+
MatrixRegistration(
|
|
13
|
+
v-else-if="coopgramStore.accountStatus && !coopgramStore.accountStatus.hasAccount",
|
|
14
|
+
@account-created="handleAccountCreated"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
// Лоадер пока загружается iframe Matrix клиента
|
|
18
|
+
WindowLoader(
|
|
19
|
+
v-else-if="coopgramStore.accountStatus?.iframeUrl && isIframeLoading",
|
|
20
|
+
text="Загрузка Matrix клиента..."
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
// Iframe с Matrix клиентом после полной загрузки
|
|
24
|
+
iframe(
|
|
25
|
+
v-else-if="coopgramStore.accountStatus?.iframeUrl",
|
|
26
|
+
v-show="!isIframeLoading",
|
|
27
|
+
:src="coopgramStore.accountStatus.iframeUrl",
|
|
28
|
+
class="matrix-iframe",
|
|
29
|
+
frameborder="0",
|
|
30
|
+
width="100%",
|
|
31
|
+
:style="{ height: 'calc(100vh - 56px)' }"
|
|
32
|
+
@load="onIframeLoaded"
|
|
33
|
+
)
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script lang="ts" setup>
|
|
37
|
+
import { ref, onMounted, watch } from 'vue';
|
|
38
|
+
import { WindowLoader } from 'src/shared/ui/Loader';
|
|
39
|
+
import { useCoopgramChatStore } from '../../../entities/CoopgramChat/model';
|
|
40
|
+
import { MatrixRegistration } from '../../../widgets/MatrixRegistration';
|
|
41
|
+
|
|
42
|
+
const coopgramStore = useCoopgramChatStore();
|
|
43
|
+
const isIframeLoading = ref(true);
|
|
44
|
+
let iframeLoadTimeout: number | null = null;
|
|
45
|
+
|
|
46
|
+
// Сбрасываем состояние загрузки iframe при изменении URL
|
|
47
|
+
watch(() => coopgramStore.accountStatus?.iframeUrl, () => {
|
|
48
|
+
if (coopgramStore.accountStatus?.iframeUrl) {
|
|
49
|
+
isIframeLoading.value = true;
|
|
50
|
+
|
|
51
|
+
// Очищаем предыдущий таймаут
|
|
52
|
+
if (iframeLoadTimeout) {
|
|
53
|
+
clearTimeout(iframeLoadTimeout);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Устанавливаем таймаут на 5 секунд как fallback
|
|
57
|
+
iframeLoadTimeout = window.setTimeout(() => {
|
|
58
|
+
isIframeLoading.value = false;
|
|
59
|
+
}, 5000);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
function onIframeLoaded() {
|
|
64
|
+
// Очищаем таймаут, если загрузка произошла раньше
|
|
65
|
+
if (iframeLoadTimeout) {
|
|
66
|
+
clearTimeout(iframeLoadTimeout);
|
|
67
|
+
iframeLoadTimeout = null;
|
|
68
|
+
}
|
|
69
|
+
isIframeLoading.value = false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function retryLoadStatus() {
|
|
73
|
+
coopgramStore.clearError();
|
|
74
|
+
await coopgramStore.loadAccountStatus();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function handleAccountCreated() {
|
|
78
|
+
// После успешного создания аккаунта перезагружаем статус
|
|
79
|
+
await coopgramStore.loadAccountStatus();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
onMounted(async () => {
|
|
83
|
+
await coopgramStore.loadAccountStatus();
|
|
84
|
+
});
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<style scoped>
|
|
88
|
+
.matrix-iframe {
|
|
89
|
+
width: 100%;
|
|
90
|
+
border: none;
|
|
91
|
+
display: block;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.error-message {
|
|
95
|
+
display: flex;
|
|
96
|
+
flex-direction: column;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
height: calc(100vh - 56px);
|
|
100
|
+
text-align: center;
|
|
101
|
+
padding: 2rem;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.error-message p {
|
|
105
|
+
margin-bottom: 1rem;
|
|
106
|
+
color: #dc3545;
|
|
107
|
+
font-size: 1.1rem;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.retry-button {
|
|
111
|
+
padding: 0.5rem 1rem;
|
|
112
|
+
background-color: #007bff;
|
|
113
|
+
color: white;
|
|
114
|
+
border: none;
|
|
115
|
+
border-radius: 0.25rem;
|
|
116
|
+
cursor: pointer;
|
|
117
|
+
font-size: 1rem;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.retry-button:hover {
|
|
121
|
+
background-color: #0056b3;
|
|
122
|
+
}
|
|
123
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as CoopgramPage } from './CoopgramPage.vue';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CoopgramPage } from './CoopgramPage';
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { ref, computed } from 'vue';
|
|
2
|
+
import { client } from 'src/shared/api/client';
|
|
3
|
+
import { Queries } from '@coopenomics/sdk';
|
|
4
|
+
|
|
5
|
+
export function useMatrixRegistration() {
|
|
6
|
+
const username = ref('');
|
|
7
|
+
const password = ref('');
|
|
8
|
+
const confirmPassword = ref('');
|
|
9
|
+
const usernameAvailable = ref<boolean | null>(null);
|
|
10
|
+
const checkingUsername = ref(false);
|
|
11
|
+
|
|
12
|
+
const isSubmitting = ref(false);
|
|
13
|
+
const error = ref<string | null>(null);
|
|
14
|
+
|
|
15
|
+
const validateForm = (): boolean => {
|
|
16
|
+
if (!username.value || !password.value || !confirmPassword.value) {
|
|
17
|
+
error.value = 'Заполните все поля';
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (usernameAvailable.value === false) {
|
|
22
|
+
error.value = 'Пользователь с таким именем уже существует';
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (password.value !== confirmPassword.value) {
|
|
27
|
+
error.value = 'Пароли не совпадают';
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
error.value = null;
|
|
32
|
+
return true;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const resetForm = () => {
|
|
36
|
+
username.value = '';
|
|
37
|
+
password.value = '';
|
|
38
|
+
confirmPassword.value = '';
|
|
39
|
+
usernameAvailable.value = null;
|
|
40
|
+
error.value = null;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Асинхронная проверка доступности username
|
|
44
|
+
const checkUsernameAvailability = async (value: string): Promise<boolean> => {
|
|
45
|
+
if (!value || value.length < 3) return false;
|
|
46
|
+
|
|
47
|
+
checkingUsername.value = true;
|
|
48
|
+
try {
|
|
49
|
+
const { [Queries.Coopgram.CheckUsernameAvailability.name]: result } = await client.Query(
|
|
50
|
+
Queries.Coopgram.CheckUsernameAvailability.query,
|
|
51
|
+
{
|
|
52
|
+
variables: {
|
|
53
|
+
data: { username: value },
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
usernameAvailable.value = result;
|
|
58
|
+
return result;
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error('Failed to check username availability:', err);
|
|
61
|
+
usernameAvailable.value = false; // В случае ошибки считаем недоступным
|
|
62
|
+
return false;
|
|
63
|
+
} finally {
|
|
64
|
+
checkingUsername.value = false;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Правило валидации для username
|
|
69
|
+
const validateUsernameAsync = async (val: string): Promise<string | boolean> => {
|
|
70
|
+
if (!val) {
|
|
71
|
+
usernameAvailable.value = null;
|
|
72
|
+
return 'Введите имя пользователя';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (val.length < 3) {
|
|
76
|
+
usernameAvailable.value = null;
|
|
77
|
+
return 'Имя пользователя должно содержать минимум 3 символа';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(val)) {
|
|
81
|
+
usernameAvailable.value = null;
|
|
82
|
+
return 'Имя пользователя может содержать только буквы, цифры, подчеркивания и дефисы';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const available = await checkUsernameAvailability(val);
|
|
86
|
+
return available || 'Пользователь с таким именем уже существует';
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
username,
|
|
91
|
+
password,
|
|
92
|
+
confirmPassword,
|
|
93
|
+
usernameAvailable: computed(() => usernameAvailable.value),
|
|
94
|
+
checkingUsername: computed(() => checkingUsername.value),
|
|
95
|
+
isSubmitting,
|
|
96
|
+
error,
|
|
97
|
+
validateForm,
|
|
98
|
+
resetForm,
|
|
99
|
+
checkUsernameAvailability,
|
|
100
|
+
validateUsernameAsync,
|
|
101
|
+
};
|
|
102
|
+
}
|