@coopenomics/desktop 2025.5.13 → 2025.5.14

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/index.html CHANGED
@@ -20,6 +20,25 @@
20
20
  <meta property="og:image" content="<%- SITE_IMAGE %>" />
21
21
  </head>
22
22
  <body>
23
+ <script>
24
+ try {
25
+ var theme = localStorage.getItem('theme-mode');
26
+ if (theme === 'dark') {
27
+ document.body.style.background = '#121212';
28
+ } else if (theme === 'light') {
29
+ document.body.style.background = '#f5f5f5';
30
+ }
31
+ } catch (e) {
32
+ console.log('error on set theme', e);
33
+ }
34
+ // Показываем лоадер только после того, как DOM готов
35
+ document.addEventListener('DOMContentLoaded', function() {
36
+ try {
37
+ var loader = document.querySelector('.loader-container');
38
+ if (loader) loader.style.display = 'flex';
39
+ } catch (e) {}
40
+ });
41
+ </script>
23
42
  <style>
24
43
  body {
25
44
  margin: 0;
@@ -42,7 +61,7 @@
42
61
  }
43
62
 
44
63
  .loader-container {
45
- display: flex;
64
+ display: none;
46
65
  justify-content: center;
47
66
  align-items: center;
48
67
  height: 100%;
@@ -57,7 +76,7 @@
57
76
  border-radius: 50%;
58
77
  position: relative;
59
78
  animation: rotate 2s linear infinite;
60
- border-top: 3px solid black;
79
+ border-top: 3px solid rgb(131, 130, 130);
61
80
  border-right: 3px solid transparent;
62
81
  }
63
82
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coopenomics/desktop",
3
- "version": "2025.5.13",
3
+ "version": "2025.5.14",
4
4
  "description": "A Desktop Project",
5
5
  "productName": "Desktop App",
6
6
  "author": "Alex Ant <dacom.dark.sun@gmail.com>",
@@ -24,8 +24,8 @@
24
24
  "start": "node -r ./alias-resolver.js dist/ssr/index.js"
25
25
  },
26
26
  "dependencies": {
27
- "@coopenomics/controller": "2025.5.13",
28
- "@coopenomics/sdk": "2025.5.13",
27
+ "@coopenomics/controller": "2025.5.14",
28
+ "@coopenomics/sdk": "2025.5.14",
29
29
  "@dicebear/collection": "^9.0.1",
30
30
  "@dicebear/core": "^9.0.1",
31
31
  "@fortawesome/fontawesome-svg-core": "^6.5.2",
@@ -49,7 +49,7 @@
49
49
  "@wharfkit/wallet-plugin-privatekey": "^1.1.0",
50
50
  "axios": "^1.2.1",
51
51
  "compression": "^1.7.4",
52
- "cooptypes": "2025.5.13",
52
+ "cooptypes": "2025.5.14",
53
53
  "dompurify": "^3.1.7",
54
54
  "dotenv": "^16.4.5",
55
55
  "email-regex": "^5.0.0",
@@ -101,5 +101,5 @@
101
101
  "npm": ">= 6.13.4",
102
102
  "yarn": ">= 1.21.1"
103
103
  },
104
- "gitHead": "a09959d75164067d5a5a507a3554787d88ed45d3"
104
+ "gitHead": "515a374f86b8c38fa9e725072b3816782e5c734c"
105
105
  }
@@ -21,6 +21,7 @@ const initialAccountState: IGeneratedAccount = {
21
21
  const initialUserDataState: IRegisterAccount = {
22
22
  email: '',
23
23
  username: '',
24
+ public_key: '',
24
25
  type: AccountTypes.individual,
25
26
  individual_data: {
26
27
  first_name: '',
@@ -5,8 +5,10 @@ import type { Router } from 'vue-router'
5
5
  import { useBranchOverlayProcess } from '../watch-branch-overlay'
6
6
  import { setupNavigationGuard } from '../navigation-guard-setup'
7
7
  import { useInitExtensionsProcess } from 'src/processes/init-installed-extensions'
8
+ import { applyThemeFromStorage } from 'src/shared/lib/utils'
8
9
 
9
10
  export async function useInitAppProcess(router: Router) {
11
+ applyThemeFromStorage()
10
12
  const system = useSystemStore()
11
13
  await system.loadSystemInfo()
12
14
 
@@ -0,0 +1,24 @@
1
+ import {
2
+ AccountTypes,
3
+ type IAccount,
4
+ } from 'src/entities/Account/types'
5
+
6
+ /**
7
+ * Функция для получения отформатированного имени участника
8
+ * @param account - объект аккаунта пользователя
9
+ * @returns форматированное имя/наименование
10
+ */
11
+ export const getName = (account: IAccount) => {
12
+ const d = account.private_account
13
+ if (!d) return ''
14
+ switch (d.type) {
15
+ case AccountTypes.individual:
16
+ return `${d.individual_data?.last_name} ${d.individual_data?.first_name} ${d.individual_data?.middle_name}`
17
+ case AccountTypes.entrepreneur:
18
+ return `ИП ${d.entrepreneur_data?.last_name} ${d.entrepreneur_data?.first_name} ${d.entrepreneur_data?.middle_name}`
19
+ case AccountTypes.organization:
20
+ return d.organization_data?.short_name
21
+ default:
22
+ return ''
23
+ }
24
+ }
@@ -4,3 +4,5 @@ export * from './notEmptyPhoneRule'
4
4
  export * from './notEmptyRule'
5
5
  export * from './isDomainRule'
6
6
  export * from './validatePersonalNameRule'
7
+ export * from './account'
8
+ export * from './theme'
@@ -0,0 +1,30 @@
1
+ import { LocalStorage } from 'quasar';
2
+ import { Dark } from 'quasar';
3
+
4
+ const THEME_KEY = 'theme-mode';
5
+
6
+ export function saveThemeToStorage(isDark: boolean) {
7
+ if (process.env.CLIENT) {
8
+ LocalStorage.set(THEME_KEY, isDark ? 'dark' : 'light');
9
+ }
10
+ }
11
+
12
+ export function getThemeFromStorage(): 'dark' | 'light' | null {
13
+ if (process.env.CLIENT) {
14
+ const saved = LocalStorage.getItem(THEME_KEY);
15
+ if (saved === 'dark' || saved === 'light') return saved;
16
+ return null;
17
+ }
18
+ return null;
19
+ }
20
+
21
+ export function applyThemeFromStorage() {
22
+ if (process.env.CLIENT) {
23
+ const saved = getThemeFromStorage();
24
+ if (saved === 'dark') {
25
+ Dark.set(true);
26
+ } else if (saved === 'light') {
27
+ Dark.set(false);
28
+ }
29
+ }
30
+ }
@@ -1,5 +1,5 @@
1
1
  <template lang="pug">
2
- q-item(flat clickable @click="$q.dark.toggle()")
2
+ q-item(flat clickable @click="toggleTheme")
3
3
  q-item-section
4
4
  q-item-label
5
5
  q-icon(:name="isDark ? 'brightness_7' : 'brightness_3'").q-mr-sm
@@ -11,9 +11,11 @@ q-item(flat clickable @click="$q.dark.toggle()")
11
11
 
12
12
  import { useQuasar } from 'quasar';
13
13
  import { computed } from 'vue';
14
+ import { saveThemeToStorage } from 'src/shared/lib/utils';
14
15
 
15
16
  const $q = useQuasar()
16
17
  const isDark = computed(() => $q.dark.isActive)
18
+
17
19
  defineProps({
18
20
  isMobile: {
19
21
  type: Boolean,
@@ -26,6 +28,11 @@ defineProps({
26
28
  required: false
27
29
  }
28
30
  })
31
+
32
+ function toggleTheme() {
33
+ $q.dark.toggle();
34
+ saveThemeToStorage($q.dark.isActive);
35
+ }
29
36
  </script>
30
37
  <style scoped>
31
38
  .btn-font {
@@ -53,6 +53,7 @@ div.scroll-area(style="height: 90vh; overflow-y: auto;")
53
53
  q-td {{ getDocumentTitle(props.row) }}
54
54
 
55
55
  q-tr(
56
+ no-hover
56
57
  v-if="expanded.get(props.row?.id || props.row?.statement?.action?.global_sequence)"
57
58
  :key="`e_${props.row?.id || props.row?.statement?.action?.global_sequence}`"
58
59
  :props="props"
@@ -29,7 +29,6 @@
29
29
  :hideActions="hideActions"
30
30
  @toggle-expand="toggleExpand(props.row.id)"
31
31
  )
32
-
33
32
  template(#header="props")
34
33
  q-tr(:props="props")
35
34
  q-th(auto-width)
@@ -51,14 +50,12 @@
51
50
  :icon="expanded.get(props.row.id) ? 'remove' : 'add'"
52
51
  @click="toggleExpand(props.row.id)"
53
52
  )
54
- q-td {{props.row.id}}
55
- q-td {{ props.row.amount }}
56
- q-td
57
- q-badge(v-if="props.row.type === 'registration'" color="teal") регистрационный
58
- q-badge(v-else color="teal") паевой
59
-
60
- q-td(style="max-width: 150px; word-wrap: break-word; white-space: normal;") {{props.row.username}}
53
+ q-td(style="max-width: 150px; word-wrap: break-word; white-space: normal;") {{ getName(props.row.account) }}
61
54
 
55
+ q-td {{ props.row.amount }} {{props.row.symbol}}
56
+ q-td
57
+ span(v-if="props.row.type === 'registration'") регистрационный
58
+ span(v-else) паевой
62
59
 
63
60
  q-td
64
61
  q-badge(v-if="props.row.status ==='COMPLETED'" color="teal") обработан
@@ -88,6 +85,7 @@
88
85
  import { SetOrderPaidStatusButton } from 'src/features/Payment/SetStatus/ui/SetOrderPaidStatusButton';
89
86
  import PaymentCard from './PaymentCard.vue';
90
87
  import { useWindowSize } from 'src/shared/hooks';
88
+ import { getName } from 'src/shared/lib/utils';
91
89
 
92
90
  const paymentStore = usePaymentStore()
93
91
  const payments = computed(() => paymentStore.payments)
@@ -190,10 +188,11 @@
190
188
 
191
189
 
192
190
  const columns: any[] = [
193
- { name: 'id', align: 'left', label: '№', field: 'id', sortable: true },
191
+ // { name: 'id', align: 'left', label: '№', field: 'id', sortable: true },
192
+ { name: 'account', align: 'left', label: 'От кого', field: 'account', sortable: true },
194
193
  { name: 'amount', align: 'left', label: 'Сумма', field: 'amount', sortable: true },
195
194
  { name: 'type', align: 'left', label: 'Тип платежа', field: '', sortable: false },
196
- { name: 'username', align: 'left', label: 'От кого', field: 'username', sortable: true },
195
+ // { name: 'username', align: 'left', label: 'Аккаунт', field: 'username', sortable: true },
197
196
  { name: 'status', align: 'left', label: 'Статус', field: 'status', sortable: true },
198
197
  { name: 'actions', align: 'left', label: '', field: '', sortable: false, hide: props.hideActions },
199
198
  ] as any
@@ -5,12 +5,20 @@ div.q-pa-xs.col-xs-12.col-sm-6.col-md-4.col-lg-3.q-mt-md
5
5
  div.text-h6 {{ getName(participant) }}
6
6
  q-separator.q-my-md
7
7
  div
8
- div.text-caption Е-почта:
9
- div.text-subtitle1.q-mb-xs {{ participant.provider_account?.email || 'Не указана' }}
10
- div.text-caption Аккаунт:
11
- div.text-subtitle1.q-mb-xs {{ participant.username }}
12
- div.text-caption Зарегистрирован:
13
- div.text-subtitle1 {{ formatDate(participant.blockchain_account?.created) }}
8
+ div.q-mb-md
9
+ div.text-caption Аккаунт:
10
+ div.text-subtitle1.q-mb-xs {{ participant.username }}
11
+ div.q-mb-md
12
+ div.text-caption Дата вступления:
13
+ div.text-subtitle1.q-mb-xs {{ formatDate(String(participant.participant_account?.created_at || '')) == '' ? 'отсутствует' : formatDate(String(participant.participant_account?.created_at || '')) }}
14
+ div
15
+ div.text-caption Активен:
16
+ q-checkbox(
17
+ :model-value="participant.participant_account?.status === 'accepted'"
18
+ disable
19
+ color="primary"
20
+ size="sm"
21
+ )
14
22
  q-card-actions(align="right")
15
23
  q-btn(
16
24
  color="primary"
@@ -12,6 +12,7 @@ div
12
12
 
13
13
  q-tab-panels.q-mt-sm.tab-panels-card(v-model="currentTab" animated)
14
14
  q-tab-panel.q-pa-none(name="info")
15
+ //приватные данные
15
16
  component(:is="useComponent(participant)" :participantData="usePrivateData(participant)" @update="onUpdate")
16
17
 
17
18
  q-tab-panel.q-pa-none(name="document")
@@ -31,17 +31,28 @@ q-table(
31
31
  :icon="expanded.get(props.row.username) ? 'remove' : 'add'"
32
32
  @click="onToggleExpand(props.row.username)"
33
33
  )
34
+
34
35
  q-td(style="max-width: 150px; word-wrap: break-word; white-space: normal;") {{ getName(props.row) }}
35
- q-td {{ props.row.provider_account?.email }}
36
36
  q-td {{ props.row.username }}
37
- q-td {{ formatDate(props.row.blockchain_account?.created) }}
37
+
38
+ q-td {{ formatDate(props.row.participant_account?.created_at) == '' ? 'отсутствует' : formatDate(props.row.participant_account?.created_at) }}
39
+
40
+ q-td
41
+ q-checkbox(
42
+ :model-value="props.row.participant_account?.status === 'accepted'"
43
+ disable
44
+ color="primary"
45
+ size="sm"
46
+ )
47
+
38
48
  q-tr(
49
+ no-hover
39
50
  v-if="expanded.get(props.row.username)"
40
51
  :key="`e_${props.row.username}`"
41
52
  :props="props"
42
53
  class="q-virtual-scroll--with-prev"
43
- )
44
- q-td(colspan="100%")
54
+ ).no-hover
55
+ q-td(colspan="100%").no-hover
45
56
  ParticipantDetails(
46
57
  :participant="props.row"
47
58
  :tab-name="currentTab[props.row.username]"
@@ -62,8 +73,8 @@ import { ref, reactive } from 'vue'
62
73
  import { useWindowSize } from 'src/shared/hooks'
63
74
  import moment from 'moment-with-locales-es6'
64
75
  import { ParticipantCard, ParticipantDetails } from '.'
76
+ import { getName } from 'src/shared/lib/utils'
65
77
  import {
66
- AccountTypes,
67
78
  type IAccount,
68
79
  type IIndividualData,
69
80
  type IOrganizationData,
@@ -91,27 +102,11 @@ const { isMobile } = useWindowSize()
91
102
  // Колонки таблицы
92
103
  const columns: any[] = [
93
104
  { name: 'name', align: 'left', label: 'ФИО / Наименование', field: 'name', sortable: true },
94
- { name: 'email', align: 'left', label: 'Е-почта', field: 'email', sortable: true },
95
105
  { name: 'username', align: 'left', label: 'Аккаунт', field: 'username', sortable: true },
96
- { name: 'created_at', align: 'left', label: 'Зарегистрирован', field: 'created_at', sortable: true },
106
+ { name: 'created_at', align: 'left', label: 'Дата вступления', field: 'created_at', sortable: true },
107
+ { name: 'status', align: 'left', label: 'Активен', field: 'status', sortable: true },
97
108
  ]
98
109
 
99
- // Функция для получения имени участника
100
- const getName = (account: IAccount) => {
101
- const d = account.private_account
102
- if (!d) return ''
103
- switch (d.type) {
104
- case AccountTypes.individual:
105
- return `${d.individual_data?.last_name} ${d.individual_data?.first_name} ${d.individual_data?.middle_name}`
106
- case AccountTypes.entrepreneur:
107
- return `ИП ${d.entrepreneur_data?.last_name} ${d.entrepreneur_data?.first_name} ${d.entrepreneur_data?.middle_name}`
108
- case AccountTypes.organization:
109
- return d.organization_data?.short_name
110
- default:
111
- return ''
112
- }
113
- }
114
-
115
110
  // Форматирование даты
116
111
  const formatDate = (date?: string) =>
117
112
  date ? moment(date).format('DD.MM.YY HH:mm:ss') : ''
@@ -127,3 +122,14 @@ const onUpdate = (account: IAccount, newData: IIndividualData | IOrganizationDat
127
122
  emit('update', account, newData)
128
123
  }
129
124
  </script>
125
+
126
+ <style>
127
+ .no-hover.q-tr--hover,
128
+ .no-hover.q-table__tr--hover,
129
+ .no-hover:hover,
130
+ .no-hover:focus {
131
+ background: transparent !important;
132
+ box-shadow: none !important;
133
+ cursor: default !important;
134
+ }
135
+ </style>