@coopenomics/desktop 2025.6.19 → 2025.6.24
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/package.json +7 -7
- package/src/entities/Branch/api/index.ts +1 -2
- package/src/entities/Branch/model/types.ts +2 -1
- package/src/features/Branch/CreateBranch/ui/CreateBranchButton.vue +85 -33
- package/src/features/Branch/DeleteBranch/api/index.ts +15 -0
- package/src/features/Branch/DeleteBranch/index.ts +1 -0
- package/src/features/Branch/DeleteBranch/model/index.ts +44 -0
- package/src/features/Branch/DeleteBranch/ui/DeleteBranchButton.vue +56 -0
- package/src/features/Cooperative/UpdateBoard/index.ts +1 -0
- package/src/features/Cooperative/UpdateBoard/ui/AddMemberDialog.vue +59 -0
- package/src/features/Cooperative/UpdateBoard/ui/index.ts +1 -0
- package/src/features/Meet/CreateMeet/ui/CreateMeetForm.vue +138 -94
- package/src/features/Meet/RestartMeet/ui/RestartMeetForm.vue +135 -73
- package/src/pages/Cooperative/MemberBranchList/ui/MemberBranchListPage.vue +3 -0
- package/src/processes/navigation-guard-setup/index.ts +31 -31
- package/src/shared/ui/UserSearchSelector/UserSearchSelector.vue +328 -0
- package/src/shared/ui/UserSearchSelector/composables/useUserSearch.ts +70 -0
- package/src/shared/ui/UserSearchSelector/index.ts +3 -0
- package/src/shared/ui/UserSearchSelector/model/types.ts +17 -0
- package/src/shared/ui/index.ts +1 -0
- package/src/widgets/Cooperative/Members/ui/Members.vue +167 -135
@@ -1,36 +1,36 @@
|
|
1
|
-
import { Router } from 'vue-router'
|
2
|
-
import { useSessionStore } from 'src/entities/Session'
|
3
|
-
import { useCurrentUserStore } from 'src/entities/User'
|
4
|
-
import { useDesktopStore } from 'src/entities/Desktop/model'
|
5
|
-
import { useSystemStore } from 'src/entities/System/model'
|
6
|
-
import { LocalStorage } from 'quasar'
|
1
|
+
import { Router } from 'vue-router';
|
2
|
+
import { useSessionStore } from 'src/entities/Session';
|
3
|
+
import { useCurrentUserStore } from 'src/entities/User';
|
4
|
+
import { useDesktopStore } from 'src/entities/Desktop/model';
|
5
|
+
import { useSystemStore } from 'src/entities/System/model';
|
6
|
+
import { LocalStorage } from 'quasar';
|
7
7
|
|
8
8
|
function hasAccess(to, userAccount) {
|
9
|
-
if (!to.meta?.roles || to.meta?.roles.length === 0) return true
|
10
|
-
return userAccount && to.meta?.roles.includes(userAccount.role)
|
9
|
+
if (!to.meta?.roles || to.meta?.roles.length === 0) return true;
|
10
|
+
return userAccount && to.meta?.roles.includes(userAccount.role);
|
11
11
|
}
|
12
12
|
|
13
13
|
// Функция для получения URL для редиректа
|
14
14
|
function getRedirectUrl(router: Router, to: any): string {
|
15
15
|
if (process.env.CLIENT) {
|
16
|
-
return router.resolve(to).href
|
16
|
+
return router.resolve(to).href;
|
17
17
|
}
|
18
|
-
return ''
|
18
|
+
return '';
|
19
19
|
}
|
20
20
|
|
21
21
|
export function setupNavigationGuard(router: Router) {
|
22
|
-
const desktops = useDesktopStore()
|
23
|
-
const session = useSessionStore()
|
24
|
-
const currentUser = useCurrentUserStore()
|
25
|
-
const { info } = useSystemStore()
|
22
|
+
const desktops = useDesktopStore();
|
23
|
+
const session = useSessionStore();
|
24
|
+
const currentUser = useCurrentUserStore();
|
25
|
+
const { info } = useSystemStore();
|
26
26
|
|
27
27
|
router.beforeEach(async (to, from, next) => {
|
28
|
-
await desktops.healthCheck()
|
28
|
+
await desktops.healthCheck();
|
29
29
|
|
30
30
|
// если требуется установка
|
31
31
|
if (desktops.health?.status === 'install' && to.name !== 'install') {
|
32
|
-
next({ name: 'install', params: { coopname: info.coopname } })
|
33
|
-
return
|
32
|
+
next({ name: 'install', params: { coopname: info.coopname } });
|
33
|
+
return;
|
34
34
|
}
|
35
35
|
|
36
36
|
// редирект с index
|
@@ -39,18 +39,18 @@ export function setupNavigationGuard(router: Router) {
|
|
39
39
|
if (session.isAuth && currentUser.isRegistrationComplete) {
|
40
40
|
// Если рабочий стол не выбран - выбираем по правам пользователя
|
41
41
|
if (!desktops.activeWorkspaceName) {
|
42
|
-
desktops.selectDefaultWorkspace()
|
42
|
+
desktops.selectDefaultWorkspace();
|
43
43
|
}
|
44
44
|
|
45
45
|
// Переходим на маршрут по умолчанию для выбранного рабочего стола
|
46
|
-
desktops.goToDefaultPage(router)
|
47
|
-
|
48
|
-
return
|
46
|
+
desktops.goToDefaultPage(router);
|
47
|
+
|
48
|
+
return;
|
49
49
|
} else {
|
50
50
|
// Если пользователь не авторизован, используем nonAuthorizedHome
|
51
|
-
const homePage = desktops.currentDesktop?.nonAuthorizedHome
|
52
|
-
next({ name: homePage, params: { coopname: info.coopname } })
|
53
|
-
return
|
51
|
+
const homePage = desktops.currentDesktop?.nonAuthorizedHome;
|
52
|
+
next({ name: homePage, params: { coopname: info.coopname } });
|
53
|
+
return;
|
54
54
|
}
|
55
55
|
}
|
56
56
|
|
@@ -59,19 +59,19 @@ export function setupNavigationGuard(router: Router) {
|
|
59
59
|
// Сохраняем целевой URL для редиректа после входа
|
60
60
|
if (process.env.CLIENT) {
|
61
61
|
// Получаем URL для редиректа
|
62
|
-
const redirectUrl = getRedirectUrl(router, to)
|
63
|
-
LocalStorage.set('redirectAfterLogin', redirectUrl)
|
62
|
+
const redirectUrl = getRedirectUrl(router, to);
|
63
|
+
LocalStorage.set('redirectAfterLogin', redirectUrl);
|
64
64
|
}
|
65
65
|
// Перенаправляем на страницу входа
|
66
|
-
next({ name: 'login-redirect', params: { coopname: info.coopname } })
|
67
|
-
return
|
66
|
+
next({ name: 'login-redirect', params: { coopname: info.coopname } });
|
67
|
+
return;
|
68
68
|
}
|
69
69
|
|
70
70
|
// проверка по ролям
|
71
71
|
if (hasAccess(to, currentUser.userAccount)) {
|
72
|
-
next()
|
72
|
+
next();
|
73
73
|
} else {
|
74
|
-
next({ name: 'permissionDenied' })
|
74
|
+
next({ name: 'permissionDenied' });
|
75
75
|
}
|
76
|
-
})
|
76
|
+
});
|
77
77
|
}
|
@@ -0,0 +1,328 @@
|
|
1
|
+
<template lang="pug">
|
2
|
+
q-select(
|
3
|
+
:label='label',
|
4
|
+
v-model='selectedUser',
|
5
|
+
:options='selectOptions',
|
6
|
+
:option-value='(item) => item?.data?.username',
|
7
|
+
:option-label='(item) => (item ? getDisplayName(item) : "")',
|
8
|
+
use-input,
|
9
|
+
hide-selected,
|
10
|
+
fill-input,
|
11
|
+
input-debounce='300',
|
12
|
+
emit-value,
|
13
|
+
map-options,
|
14
|
+
clearable,
|
15
|
+
:standout='standout',
|
16
|
+
:filled='filled',
|
17
|
+
:outlined='outlined',
|
18
|
+
:dense='dense',
|
19
|
+
:color='color',
|
20
|
+
@filter='onFilter',
|
21
|
+
@update:model-value='onUpdate',
|
22
|
+
:loading='loading',
|
23
|
+
:rules='rules',
|
24
|
+
:key='`user-select-${selectedUser}`'
|
25
|
+
)
|
26
|
+
template(v-slot:option='scope')
|
27
|
+
q-item(v-bind='scope.itemProps')
|
28
|
+
q-item-section(avatar)
|
29
|
+
q-avatar(
|
30
|
+
text-color='white',
|
31
|
+
:icon='getTypeIcon(scope.opt.type)',
|
32
|
+
size='sm',
|
33
|
+
:color='getTypeColor(scope.opt.type)'
|
34
|
+
)
|
35
|
+
q-item-section
|
36
|
+
q-item-label(style='font-weight: bold') {{ getDisplayName(scope.opt) }}
|
37
|
+
q-item-label(caption) {{ getUsernameFromData(scope.opt) }}
|
38
|
+
q-item-label(caption, v-if='getAdditionalInfo(scope.opt)') {{ getAdditionalInfo(scope.opt) }}
|
39
|
+
|
40
|
+
template(v-slot:selected-item)
|
41
|
+
div(v-if='selectedUser')
|
42
|
+
// Если есть полные данные пользователя
|
43
|
+
div(v-if='selectedUserObject')
|
44
|
+
q-avatar(
|
45
|
+
text-color='white',
|
46
|
+
:icon='getTypeIcon(selectedUserObject.type)',
|
47
|
+
size='sm',
|
48
|
+
:color='getTypeColor(selectedUserObject.type)'
|
49
|
+
)
|
50
|
+
// Fallback - показываем только username
|
51
|
+
div(v-else)
|
52
|
+
q-avatar(text-color='white', icon='person', size='sm', color='grey')
|
53
|
+
span.q-ml-sm {{ selectedUser }}
|
54
|
+
|
55
|
+
template(v-slot:no-option)
|
56
|
+
q-item
|
57
|
+
q-item-section.text-grey
|
58
|
+
| {{ searchQuery ? 'Ничего не найдено' : 'Начните вводить для поиска' }}
|
59
|
+
</template>
|
60
|
+
|
61
|
+
<script lang="ts" setup>
|
62
|
+
import { ref, watch, computed, onMounted } from 'vue';
|
63
|
+
import { useUserSearch } from './composables/useUserSearch';
|
64
|
+
import type { UserSearchResult } from './model/types';
|
65
|
+
|
66
|
+
// Пропсы компонента
|
67
|
+
const props = defineProps<{
|
68
|
+
modelValue?: string;
|
69
|
+
label?: string;
|
70
|
+
rules?: ((val: string) => boolean | string)[];
|
71
|
+
dense?: boolean;
|
72
|
+
standout?: boolean | string;
|
73
|
+
filled?: boolean;
|
74
|
+
outlined?: boolean;
|
75
|
+
color?: string;
|
76
|
+
}>();
|
77
|
+
|
78
|
+
// Эмиты
|
79
|
+
const emit = defineEmits<{
|
80
|
+
(e: 'update:modelValue', value: string | undefined): void;
|
81
|
+
}>();
|
82
|
+
|
83
|
+
// Композабл для поиска пользователей
|
84
|
+
const { searchResults, loading, searchUsers } = useUserSearch();
|
85
|
+
|
86
|
+
// Локальное состояние
|
87
|
+
const selectedUser = ref<string | undefined>(props.modelValue);
|
88
|
+
const searchQuery = ref('');
|
89
|
+
const selectedUserData = ref<UserSearchResult | null>(null);
|
90
|
+
|
91
|
+
// Отладка при монтировании
|
92
|
+
onMounted(() => {
|
93
|
+
// console.log('UserSearchSelector mounted');
|
94
|
+
// console.log('searchResults:', searchResults.value);
|
95
|
+
// console.log('loading:', loading.value);
|
96
|
+
// console.log('searchUsers function:', typeof searchUsers);
|
97
|
+
});
|
98
|
+
|
99
|
+
// Следим за изменениями modelValue
|
100
|
+
watch(
|
101
|
+
() => props.modelValue,
|
102
|
+
(newVal) => {
|
103
|
+
// console.log('modelValue changed to:', newVal); // Отладка
|
104
|
+
selectedUser.value = newVal;
|
105
|
+
// Очищаем сохраненные данные при изменении извне
|
106
|
+
if (!newVal) {
|
107
|
+
selectedUserData.value = null;
|
108
|
+
}
|
109
|
+
},
|
110
|
+
);
|
111
|
+
|
112
|
+
// Следим за изменениями selectedUser для отладки
|
113
|
+
watch(selectedUser, (newVal, oldVal) => {
|
114
|
+
// console.log('selectedUser changed from:', oldVal, 'to:', newVal);
|
115
|
+
if (oldVal && !newVal) {
|
116
|
+
// console.warn('selectedUser was cleared! Stack trace:');
|
117
|
+
// console.trace();
|
118
|
+
}
|
119
|
+
});
|
120
|
+
|
121
|
+
// Вычисляемые свойства
|
122
|
+
const label = computed(() => props.label || 'Выберите пользователя');
|
123
|
+
|
124
|
+
// Опции для select - всегда включаем выбранного пользователя
|
125
|
+
const selectOptions = computed(() => {
|
126
|
+
// console.log('Computing selectOptions...'); // Отладка
|
127
|
+
// console.log('searchResults.value:', searchResults.value); // Отладка
|
128
|
+
// console.log('selectedUserData.value:', selectedUserData.value); // Отладка
|
129
|
+
|
130
|
+
const options = [...searchResults.value];
|
131
|
+
|
132
|
+
// Если есть выбранный пользователь, но его нет в результатах поиска, добавляем
|
133
|
+
if (selectedUserData.value) {
|
134
|
+
const isAlreadyInOptions = options.some(
|
135
|
+
(option) =>
|
136
|
+
option.data.username === selectedUserData.value?.data.username,
|
137
|
+
);
|
138
|
+
// console.log('Selected user already in options:', isAlreadyInOptions); // Отладка
|
139
|
+
if (!isAlreadyInOptions) {
|
140
|
+
options.unshift(selectedUserData.value);
|
141
|
+
// console.log('Added selected user to options'); // Отладка
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
// console.log('Final select options:', options); // Отладка
|
146
|
+
return options;
|
147
|
+
});
|
148
|
+
|
149
|
+
// Находим объект выбранного пользователя для отображения
|
150
|
+
const selectedUserObject = computed(() => {
|
151
|
+
// console.log('Computing selectedUserObject...'); // Отладка
|
152
|
+
// console.log('selectedUser.value:', selectedUser.value); // Отладка
|
153
|
+
// console.log('selectedUserData.value:', selectedUserData.value); // Отладка
|
154
|
+
|
155
|
+
// Сначала пробуем использовать сохраненные данные
|
156
|
+
if (
|
157
|
+
selectedUserData.value &&
|
158
|
+
selectedUserData.value.data.username === selectedUser.value
|
159
|
+
) {
|
160
|
+
// console.log('Using saved user data'); // Отладка
|
161
|
+
return selectedUserData.value;
|
162
|
+
}
|
163
|
+
|
164
|
+
// Если нет сохраненных данных, ищем в опциях select
|
165
|
+
if (!selectedUser.value) {
|
166
|
+
// console.log('No selected user'); // Отладка
|
167
|
+
return null;
|
168
|
+
}
|
169
|
+
|
170
|
+
const found = selectOptions.value.find(
|
171
|
+
(result) => result.data.username === selectedUser.value,
|
172
|
+
);
|
173
|
+
// console.log('Found in select options:', found); // Отладка
|
174
|
+
return found || null;
|
175
|
+
});
|
176
|
+
|
177
|
+
// Методы для отображения
|
178
|
+
const getDisplayName = (user: UserSearchResult | null | undefined): string => {
|
179
|
+
if (!user || !user.data) return '';
|
180
|
+
|
181
|
+
try {
|
182
|
+
switch (user.type) {
|
183
|
+
case 'individual':
|
184
|
+
case 'entrepreneur': {
|
185
|
+
const data = user.data as any;
|
186
|
+
return (
|
187
|
+
`${data.last_name || ''} ${data.first_name || ''} ${data.middle_name || ''}`.trim() ||
|
188
|
+
data.username ||
|
189
|
+
''
|
190
|
+
);
|
191
|
+
}
|
192
|
+
case 'organization': {
|
193
|
+
const data = user.data as any;
|
194
|
+
return data.short_name || data.full_name || data.username || '';
|
195
|
+
}
|
196
|
+
default:
|
197
|
+
return user.data?.username || '';
|
198
|
+
}
|
199
|
+
} catch (error) {
|
200
|
+
// console.error('Error in getDisplayName:', error, user);
|
201
|
+
return user.data?.username || '';
|
202
|
+
}
|
203
|
+
};
|
204
|
+
|
205
|
+
const getUsernameFromData = (
|
206
|
+
user: UserSearchResult | null | undefined,
|
207
|
+
): string => {
|
208
|
+
return user?.data?.username || '';
|
209
|
+
};
|
210
|
+
|
211
|
+
const getAdditionalInfo = (
|
212
|
+
user: UserSearchResult | null | undefined,
|
213
|
+
): string => {
|
214
|
+
if (!user || !user.data) return '';
|
215
|
+
|
216
|
+
try {
|
217
|
+
switch (user.type) {
|
218
|
+
case 'entrepreneur': {
|
219
|
+
const data = user.data as any;
|
220
|
+
return `ИП • ИНН: ${data.details?.inn || 'н/д'}`;
|
221
|
+
}
|
222
|
+
case 'organization': {
|
223
|
+
const data = user.data as any;
|
224
|
+
return `Организация • ИНН: ${data.details?.inn || 'н/д'}`;
|
225
|
+
}
|
226
|
+
default:
|
227
|
+
return '';
|
228
|
+
}
|
229
|
+
} catch (error) {
|
230
|
+
// console.error('Error in getAdditionalInfo:', error, user);
|
231
|
+
return '';
|
232
|
+
}
|
233
|
+
};
|
234
|
+
|
235
|
+
const getTypeIcon = (type: string | undefined): string => {
|
236
|
+
switch (type) {
|
237
|
+
case 'individual':
|
238
|
+
return 'person';
|
239
|
+
case 'entrepreneur':
|
240
|
+
return 'business';
|
241
|
+
case 'organization':
|
242
|
+
return 'corporate_fare';
|
243
|
+
default:
|
244
|
+
return 'person';
|
245
|
+
}
|
246
|
+
};
|
247
|
+
|
248
|
+
const getTypeColor = (type: string | undefined): string => {
|
249
|
+
switch (type) {
|
250
|
+
case 'individual':
|
251
|
+
return 'blue';
|
252
|
+
case 'entrepreneur':
|
253
|
+
return 'green';
|
254
|
+
case 'organization':
|
255
|
+
return 'purple';
|
256
|
+
default:
|
257
|
+
return 'grey';
|
258
|
+
}
|
259
|
+
};
|
260
|
+
|
261
|
+
// Обработчики событий
|
262
|
+
const onFilter = (
|
263
|
+
val: string,
|
264
|
+
update: (fn: () => void) => void,
|
265
|
+
abort: () => void,
|
266
|
+
) => {
|
267
|
+
// console.log('onFilter called with:', val); // Отладка
|
268
|
+
searchQuery.value = val;
|
269
|
+
|
270
|
+
if (val.length >= 1) {
|
271
|
+
searchUsers(val)
|
272
|
+
.then(() => {
|
273
|
+
update(() => {
|
274
|
+
return;
|
275
|
+
});
|
276
|
+
})
|
277
|
+
.catch(() => {
|
278
|
+
abort();
|
279
|
+
});
|
280
|
+
} else {
|
281
|
+
if (selectedUserData.value) {
|
282
|
+
searchResults.value = [selectedUserData.value];
|
283
|
+
} else {
|
284
|
+
searchResults.value = [];
|
285
|
+
}
|
286
|
+
update(() => {
|
287
|
+
// console.log('Update callback for short query called'); // Отладка
|
288
|
+
});
|
289
|
+
}
|
290
|
+
};
|
291
|
+
|
292
|
+
const onUpdate = (value: UserSearchResult | string | undefined) => {
|
293
|
+
// console.log('onUpdate called with:', value, 'type:', typeof value); // Отладка
|
294
|
+
|
295
|
+
// Если передан объект результата поиска, извлекаем username и сохраняем данные
|
296
|
+
let username: string | undefined;
|
297
|
+
if (typeof value === 'string') {
|
298
|
+
username = value;
|
299
|
+
// console.log('String value received:', username); // Отладка
|
300
|
+
|
301
|
+
// При передаче строки пытаемся найти соответствующий объект в опциях
|
302
|
+
const foundUser = selectOptions.value.find(
|
303
|
+
(result) => result.data.username === value,
|
304
|
+
);
|
305
|
+
// console.log('Found user for string:', foundUser); // Отладка
|
306
|
+
|
307
|
+
if (foundUser) {
|
308
|
+
selectedUserData.value = foundUser;
|
309
|
+
}
|
310
|
+
} else if (value && typeof value === 'object' && 'data' in value) {
|
311
|
+
username = value.data.username;
|
312
|
+
selectedUserData.value = value; // Сохраняем полные данные пользователя
|
313
|
+
} else {
|
314
|
+
username = undefined;
|
315
|
+
selectedUserData.value = null;
|
316
|
+
}
|
317
|
+
|
318
|
+
selectedUser.value = username;
|
319
|
+
emit('update:modelValue', username);
|
320
|
+
};
|
321
|
+
</script>
|
322
|
+
|
323
|
+
<style scoped>
|
324
|
+
:deep(mark) {
|
325
|
+
background-color: #ffeb3b;
|
326
|
+
padding: 0;
|
327
|
+
}
|
328
|
+
</style>
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import { ref } from 'vue';
|
2
|
+
import { client } from 'src/shared/api/client';
|
3
|
+
import { Queries } from '@coopenomics/sdk';
|
4
|
+
import type { UserSearchResult } from '../model/types';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Композабл для поиска пользователей
|
8
|
+
*/
|
9
|
+
export function useUserSearch() {
|
10
|
+
const searchResults = ref<UserSearchResult[]>([]);
|
11
|
+
const loading = ref(false);
|
12
|
+
const error = ref<string | null>(null);
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Выполняет поиск пользователей по запросу
|
16
|
+
* @param query Поисковый запрос
|
17
|
+
*/
|
18
|
+
const searchUsers = async (query: string): Promise<void> => {
|
19
|
+
if (!query || query.length < 1) {
|
20
|
+
searchResults.value = [];
|
21
|
+
return;
|
22
|
+
}
|
23
|
+
|
24
|
+
loading.value = true;
|
25
|
+
error.value = null;
|
26
|
+
|
27
|
+
try {
|
28
|
+
console.log('Making API call with query:', query); // Отладка
|
29
|
+
|
30
|
+
const response = await client.Query(
|
31
|
+
Queries.Accounts.SearchPrivateAccounts.query,
|
32
|
+
{
|
33
|
+
variables: {
|
34
|
+
data: {
|
35
|
+
query: query.trim(),
|
36
|
+
},
|
37
|
+
},
|
38
|
+
},
|
39
|
+
);
|
40
|
+
|
41
|
+
console.log('API response:', response); // Отладка
|
42
|
+
|
43
|
+
searchResults.value = response.searchPrivateAccounts || [];
|
44
|
+
console.log('Updated searchResults:', searchResults.value); // Отладка
|
45
|
+
} catch (err) {
|
46
|
+
console.error('Ошибка поиска пользователей:', err);
|
47
|
+
error.value = 'Ошибка при поиске пользователей';
|
48
|
+
searchResults.value = [];
|
49
|
+
throw err; // Пробрасываем ошибку для обработки в компоненте
|
50
|
+
} finally {
|
51
|
+
loading.value = false;
|
52
|
+
}
|
53
|
+
};
|
54
|
+
|
55
|
+
/**
|
56
|
+
* Очищает результаты поиска
|
57
|
+
*/
|
58
|
+
const clearResults = () => {
|
59
|
+
searchResults.value = [];
|
60
|
+
error.value = null;
|
61
|
+
};
|
62
|
+
|
63
|
+
return {
|
64
|
+
searchResults,
|
65
|
+
loading,
|
66
|
+
error,
|
67
|
+
searchUsers,
|
68
|
+
clearResults,
|
69
|
+
};
|
70
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import type { Queries } from '@coopenomics/sdk';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Результат поиска пользователя из SDK
|
5
|
+
*/
|
6
|
+
export type UserSearchResult =
|
7
|
+
Queries.Accounts.SearchPrivateAccounts.IOutput['searchPrivateAccounts'][0];
|
8
|
+
|
9
|
+
/**
|
10
|
+
* Данные пользователя для отображения
|
11
|
+
*/
|
12
|
+
export interface UserDisplayData {
|
13
|
+
username: string;
|
14
|
+
displayName: string;
|
15
|
+
type: 'individual' | 'entrepreneur' | 'organization';
|
16
|
+
additionalInfo?: string;
|
17
|
+
}
|
package/src/shared/ui/index.ts
CHANGED