@opengis/cms 0.0.22 → 0.0.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.
Files changed (211) hide show
  1. package/package.json +2 -10
  2. package/src/index.js +23 -0
  3. package/module/cms/card/cms.content.table/index.yml +0 -17
  4. package/module/cms/card/cms.content.table/main_info.hbs +0 -26
  5. package/module/cms/card/cms.menu.table/content_info.hbs +0 -16
  6. package/module/cms/card/cms.menu.table/index.yml +0 -18
  7. package/module/cms/card/cms.menu.table/main_info.hbs +0 -22
  8. package/module/cms/card/cms.settings.table/index.yml +0 -13
  9. package/module/cms/card/cms.settings.table/main_info.hbs +0 -20
  10. package/module/cms/cls/content.status.json +0 -18
  11. package/module/cms/cls/user_type.json +0 -10
  12. package/module/cms/form/admin.users.form.json +0 -78
  13. package/module/cms/form/cms.content.form.json +0 -79
  14. package/module/cms/form/cms.menu.form.json +0 -69
  15. package/module/cms/form/cms.settings.form.json +0 -32
  16. package/module/cms/menu.json +0 -24
  17. package/module/cms/router.js +0 -169
  18. package/module/cms/select/cms.page_type.sql +0 -2
  19. package/module/cms/select/collection.sql +0 -1
  20. package/module/cms/select/locale.sql +0 -17
  21. package/module/cms/select/news_tag_id.sql +0 -12
  22. package/module/cms/select/tag_id.sql +0 -1
  23. package/module/cms/table/admin.users.table.json +0 -54
  24. package/module/cms/table/cms.content.table.json +0 -106
  25. package/module/cms/table/cms.menu.table.json +0 -73
  26. package/module/cms/table/cms.settings.table.json +0 -57
  27. package/module/cms/table/collection.default.table.json +0 -102
  28. package/module/cms/table/single.default.table.json +0 -115
  29. package/src/App.css +0 -52
  30. package/src/App.vue +0 -62
  31. package/src/assets/image.png +0 -0
  32. package/src/assets/main.css +0 -3
  33. package/src/assets/tailwind-3.4.17.js +0 -113
  34. package/src/components/LanguageSwitcher.vue +0 -73
  35. package/src/components/SettingsCard.vue +0 -40
  36. package/src/components/builder/CreateForm.vue +0 -128
  37. package/src/components/builder/formTypeSchema.js +0 -145
  38. package/src/components/builder/tabs/index.ts +0 -9
  39. package/src/components/builder/tabs/vs-builder-edit.vue +0 -133
  40. package/src/components/builder/tabs/vs-builder-monaco.vue +0 -29
  41. package/src/components/builder/tabs/vs-builder-preview.vue +0 -39
  42. package/src/components/builder/vs-builder-datatable-controls.vue +0 -138
  43. package/src/components/builder/vs-builder-datatable-form.vue +0 -80
  44. package/src/components/builder/vs-builder-datatable.vue +0 -191
  45. package/src/components/builder/vs-builder-list-item.vue +0 -110
  46. package/src/components/collections/CollectionsBreadcrumb.vue +0 -52
  47. package/src/components/collections/CollectionsGrid.vue +0 -176
  48. package/src/components/collections/ContentBlock.vue +0 -75
  49. package/src/components/collections/formWrapper.vue +0 -156
  50. package/src/components/dashboard/ContentItem.vue +0 -82
  51. package/src/components/dashboard/DashboardHeader.vue +0 -33
  52. package/src/components/dashboard/QuickActions.vue +0 -84
  53. package/src/components/dashboard/RecentContent.vue +0 -54
  54. package/src/components/dashboard/StatCard.vue +0 -63
  55. package/src/components/dashboard/StatsGrid.vue +0 -28
  56. package/src/components/form-components/MonacoEditor.vue +0 -104
  57. package/src/components/form-components/VsFormMeta.vue +0 -40
  58. package/src/components/form-components/VsFormTags.vue +0 -150
  59. package/src/components/form-components/custom-datatable/vs-form-custom-datatable-add.vue +0 -84
  60. package/src/components/form-components/custom-datatable/vs-form-custom-datatable-controls.vue +0 -106
  61. package/src/components/form-components/index.js +0 -23
  62. package/src/components/form-components/reference/vs-form-reference-add.vue +0 -92
  63. package/src/components/form-components/reference/vs-form-reference-controls.vue +0 -101
  64. package/src/components/form-components/reference-list/referenceOptionList.js +0 -78
  65. package/src/components/form-components/reference-list/vs-form-reference-add.vue +0 -145
  66. package/src/components/form-components/reference-list/vs-form-reference-choce.vue +0 -39
  67. package/src/components/form-components/reference-list/vs-form-reference-controls.vue +0 -110
  68. package/src/components/form-components/reference-skeleton/about-skeleton.vue +0 -37
  69. package/src/components/form-components/reference-skeleton/banner-skeleton.vue +0 -29
  70. package/src/components/form-components/reference-skeleton/body-skeleton.vue +0 -56
  71. package/src/components/form-components/reference-skeleton/cards-skeleton.vue +0 -47
  72. package/src/components/form-components/reference-skeleton/documents-skeleton.vue +0 -64
  73. package/src/components/form-components/reference-skeleton/faq-skeleton.vue +0 -64
  74. package/src/components/form-components/reference-skeleton/form-skeleton.vue +0 -41
  75. package/src/components/form-components/reference-skeleton/index.js +0 -36
  76. package/src/components/form-components/reference-skeleton/infoLine-skeleton.vue +0 -37
  77. package/src/components/form-components/reference-skeleton/news-skeleton.vue +0 -54
  78. package/src/components/form-components/reference-skeleton/slider-skeleton.vue +0 -41
  79. package/src/components/form-components/reference-skeleton/tabs-skeleton.vue +0 -40
  80. package/src/components/form-components/reference-skeleton/team-skeleton.vue +0 -103
  81. package/src/components/form-components/reference-skeleton/usefulLinks-skeleton.vue +0 -52
  82. package/src/components/form-components/reference-skeleton/video-skeleton.vue +0 -36
  83. package/src/components/form-components/testReferenceTypes.js +0 -773
  84. package/src/components/form-components/vs-form-color-picker.vue +0 -29
  85. package/src/components/form-components/vs-form-custom-datatable.vue +0 -214
  86. package/src/components/form-components/vs-form-integer.vue +0 -86
  87. package/src/components/form-components/vs-form-key-value.vue +0 -201
  88. package/src/components/form-components/vs-form-marcdown-md.vue +0 -3
  89. package/src/components/form-components/vs-form-media-select.vue +0 -780
  90. package/src/components/form-components/vs-form-reference-list.vue +0 -97
  91. package/src/components/form-components/vs-form-reference.vue +0 -59
  92. package/src/components/form-components/vs-form-relation.vue +0 -30
  93. package/src/components/form-components/vs-form-reletion-link.vue +0 -34
  94. package/src/components/form-components/vs-form-select-collection.vue +0 -0
  95. package/src/components/form-components/vs-form-slug.vue +0 -72
  96. package/src/components/form-components/vs-form-tiptap.vue +0 -7
  97. package/src/components/form-components/vs-richtext-md.vue +0 -3
  98. package/src/components/icons/BellIcon.vue +0 -17
  99. package/src/components/icons/GlobeIcon.vue +0 -18
  100. package/src/components/icons/KeyIcon.vue +0 -20
  101. package/src/components/icons/PaletteIcon.vue +0 -22
  102. package/src/components/icons/SettingsIcon.vue +0 -19
  103. package/src/components/icons/ShieldIcon.vue +0 -18
  104. package/src/components/icons/UsersIcon.vue +0 -19
  105. package/src/components/icons/icon-chevron-right.vue +0 -16
  106. package/src/components/icons/icon-drag.vue +0 -20
  107. package/src/components/icons/icon-file-text.vue +0 -21
  108. package/src/components/icons/icon-folder.vue +0 -18
  109. package/src/components/icons/icon-grid.vue +0 -17
  110. package/src/components/icons/icon-group.vue +0 -19
  111. package/src/components/icons/icon-home.vue +0 -16
  112. package/src/components/icons/icon-image.vue +0 -18
  113. package/src/components/icons/icon-list.vue +0 -20
  114. package/src/components/icons/icon-more.vue +0 -17
  115. package/src/components/icons/icon-plus.vue +0 -17
  116. package/src/components/icons-types/icon-array.vue +0 -22
  117. package/src/components/icons-types/icon-boolean.vue +0 -18
  118. package/src/components/icons-types/icon-datalist.vue +0 -22
  119. package/src/components/icons-types/icon-date.vue +0 -20
  120. package/src/components/icons-types/icon-datetime.vue +0 -20
  121. package/src/components/icons-types/icon-file.vue +0 -21
  122. package/src/components/icons-types/icon-gallery.vue +0 -18
  123. package/src/components/icons-types/icon-image.vue +0 -19
  124. package/src/components/icons-types/icon-integer.vue +0 -20
  125. package/src/components/icons-types/icon-merkdown.vue +0 -18
  126. package/src/components/icons-types/icon-multiselect.vue +0 -22
  127. package/src/components/icons-types/icon-number.vue +0 -20
  128. package/src/components/icons-types/icon-radio.vue +0 -22
  129. package/src/components/icons-types/icon-reference-list.vue +0 -22
  130. package/src/components/icons-types/icon-reference.vue +0 -20
  131. package/src/components/icons-types/icon-relation.vue +0 -22
  132. package/src/components/icons-types/icon-richtext.vue +0 -18
  133. package/src/components/icons-types/icon-select.vue +0 -22
  134. package/src/components/icons-types/icon-slug.vue +0 -19
  135. package/src/components/icons-types/icon-text.vue +0 -19
  136. package/src/components/icons-types/index.js +0 -43
  137. package/src/components/layout/Layout.vue +0 -67
  138. package/src/components/layout/Sidebar.vue +0 -128
  139. package/src/components/media/FileUploadProgress.vue +0 -29
  140. package/src/components/media/MediaBreadcrumb.vue +0 -42
  141. package/src/components/media/MediaCreateFolder.vue +0 -59
  142. package/src/components/media/MediaFileInfo.vue +0 -148
  143. package/src/components/media/MediaGrid.vue +0 -148
  144. package/src/components/media/MediaList.vue +0 -148
  145. package/src/components/media/MediaViewControls.vue +0 -38
  146. package/src/components/media/TypeTag.vue +0 -23
  147. package/src/components/menu/AddNewItemInTree.vue +0 -75
  148. package/src/components/menu/MenuBody.vue +0 -149
  149. package/src/components/menu/MenuItem.vue +0 -73
  150. package/src/components/menu/MenuList.vue +0 -101
  151. package/src/components/referencec/index.ts +0 -7
  152. package/src/components/referencec/vs-reference-faq.vue +0 -61
  153. package/src/components/referencec/vs-reference-user-card.vue +0 -40
  154. package/src/components/settings/NotificationSettings.vue +0 -32
  155. package/src/components/settings/SettingsTable.vue +0 -50
  156. package/src/components/settings/SettingsTitle.vue +0 -33
  157. package/src/components/settings/SettingsToggleItem.vue +0 -25
  158. package/src/components/sidebar/DropdownMenu.vue +0 -34
  159. package/src/components/sidebar/SettingsSidebar.vue +0 -121
  160. package/src/components/sidebar/SidebarFooter.vue +0 -52
  161. package/src/components/sidebar/SidebarHeader.vue +0 -57
  162. package/src/components/sidebar/SidebarMenu.vue +0 -78
  163. package/src/components/ui/EmptyData.vue +0 -76
  164. package/src/components/ui/UniversalTable.vue +0 -310
  165. package/src/components/ui/UniversalTableFilters.vue +0 -0
  166. package/src/components/ui/UniversalTablePagination.vue +0 -118
  167. package/src/components/ui/VsPreview.vue +0 -75
  168. package/src/composables/useCollectionView.ts +0 -21
  169. package/src/composables/useDebounce.ts +0 -26
  170. package/src/composables/useMonaco.ts +0 -28
  171. package/src/composables/useTheme.ts +0 -40
  172. package/src/content/test-slug/metadata.json +0 -1
  173. package/src/i18n.ts +0 -75
  174. package/src/index.css +0 -3
  175. package/src/index.ts +0 -122
  176. package/src/locales/en.json +0 -778
  177. package/src/locales/uk.json +0 -797
  178. package/src/main.ts +0 -41
  179. package/src/pages/Dashboard.vue +0 -168
  180. package/src/pages/EmailPage.vue +0 -183
  181. package/src/pages/FeedbackPage.vue +0 -232
  182. package/src/pages/MediaPage.vue +0 -372
  183. package/src/pages/TagsPage.vue +0 -207
  184. package/src/pages/builder/BuilderPage.vue +0 -195
  185. package/src/pages/builder/EditCollectionPage.vue +0 -163
  186. package/src/pages/collections/ArticlesPage.vue +0 -385
  187. package/src/pages/collections/CollectionsPage.vue +0 -146
  188. package/src/pages/collections/SingletonsPage.vue +0 -119
  189. package/src/pages/collections/contentForm.vue +0 -484
  190. package/src/pages/collections/schema/seo.ts +0 -27
  191. package/src/pages/menu/MenuAddPage.vue +0 -123
  192. package/src/pages/menu/MenuItemPage.vue +0 -183
  193. package/src/pages/menu/MenuPage.vue +0 -133
  194. package/src/pages/settings/ApiKeys.vue +0 -75
  195. package/src/pages/settings/Appearance.vue +0 -80
  196. package/src/pages/settings/Logs.vue +0 -260
  197. package/src/pages/settings/PermissionsPage.vue +0 -237
  198. package/src/pages/settings/Settings.vue +0 -186
  199. package/src/pages/settings/Users.vue +0 -109
  200. package/src/pages/settings/general.vue +0 -154
  201. package/src/pages/settings/generalScheme.js +0 -132
  202. package/src/pages/users/AddUser.vue +0 -106
  203. package/src/pages/users/UsersPage.vue +0 -98
  204. package/src/props/builder.ts +0 -67
  205. package/src/props/content.ts +0 -56
  206. package/src/props/media.ts +0 -63
  207. package/src/router/index.ts +0 -181
  208. package/src/types/fastify-auth.d.ts +0 -4
  209. package/src/utils/getField.js +0 -270
  210. package/src/utils/translit.js +0 -19
  211. package/src/vite-env.d.ts +0 -1
package/src/main.ts DELETED
@@ -1,41 +0,0 @@
1
- import { createApp } from "vue";
2
- /*import formComponents from "./components/form-components";
3
- import referenceComponents from "./components/referencec";
4
- import iconsTypes from "./components/icons-types";*/
5
- import App from "./App.vue";
6
-
7
- import '@opengis/core/dist/index.css'
8
- import '@opengis/form/dist/index.css'
9
- // import v3core from '@opengis/v3-core';
10
- // import v3core from '../../v3-core/src/misc/import-file.ts';
11
- //
12
-
13
- import richtext from '@opengis/richtext'
14
- //import richtext from '../../richtext/src/misc/import-file.js'
15
-
16
- import router from "./router";
17
- import { i18n, initI18n } from "./i18n.ts";
18
- // import "./assets/main.css";
19
- // import '@opengis/v3-core/dist/style.css';
20
-
21
- const app = createApp(App);
22
- /*v3core.install(app, createApp, {
23
- i18nConfig: i18n,
24
- });*/
25
-
26
- /*Object.entries({ ...formComponents, ...iconsTypes, ...referenceComponents }).forEach(([key, value]) => {
27
- app.component(key, value);
28
- });*/
29
-
30
- app.use(router);
31
- app.use(i18n);
32
- app.use(richtext, { i18nConfig: i18n });
33
- app.config.globalProperties.$settings = {
34
- locale: 'uk',
35
- locales: ['en', 'uk']
36
- }
37
-
38
- // Ініціалізуємо i18n перед монтуванням
39
- initI18n().then(() => {
40
- app.mount("#app");
41
- });
@@ -1,168 +0,0 @@
1
- <template>
2
- <div class="w-full max-w-7xl mx-auto space-y-8">
3
- <!-- Header Section -->
4
- <DashboardHeader />
5
-
6
- <!-- Stats Cards -->
7
- <StatsGrid :stats="statsData" />
8
-
9
- <!-- Main Content Grid -->
10
- <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
11
- <!-- Recent Content -->
12
- <RecentContent
13
- :content="recentContent"
14
- class="lg:col-span-2"
15
- />
16
-
17
- <!-- Quick Actions -->
18
- <div>
19
- <QuickActions />
20
- </div>
21
- </div>
22
- </div>
23
- </template>
24
-
25
- <script setup lang="ts">
26
- import { ref, onMounted } from 'vue';
27
- import DashboardHeader from '../components/dashboard/DashboardHeader.vue';
28
- import StatsGrid from '../components/dashboard/StatsGrid.vue';
29
- import RecentContent from '../components/dashboard/RecentContent.vue';
30
- import QuickActions from '../components/dashboard/QuickActions.vue';
31
- import { useI18n } from 'vue-i18n';
32
-
33
- const { t } = useI18n();
34
-
35
- // Types
36
- interface StatItem {
37
- id: string;
38
- title: string;
39
- value: string;
40
- description: string;
41
- change: {
42
- value: string;
43
- isPositive: boolean;
44
- };
45
- icon: string;
46
- color: string;
47
- }
48
-
49
- interface ContentItem {
50
- id: number;
51
- type: 'Article' | 'Post';
52
- status: 'published' | 'draft' | 'review';
53
- title: string;
54
- author: string;
55
- updated_at: string;
56
- views: number;
57
- }
58
-
59
-
60
-
61
- // Data
62
- const statsData = ref<StatItem[]>([
63
- {
64
- id: 'total-content',
65
- title: t('dashboard.totalContent'),
66
- value: '2,847',
67
- description: t('dashboard.articlesPostsPages'),
68
- change: { value: '+12.5%', isPositive: true },
69
- icon: 'file-text',
70
- color: 'blue'
71
- },
72
- {
73
- id: 'active-users',
74
- title: t('dashboard.activeUsers'),
75
- value: '1,234',
76
- description: t('dashboard.monthlyActiveUsers'),
77
- change: { value: '+8.2%', isPositive: true },
78
- icon: 'users',
79
- color: 'emerald'
80
- },
81
- {
82
- id: 'media-files',
83
- title: t('dashboard.mediaFiles'),
84
- value: '5,692',
85
- description: t('dashboard.imagesVideosDocs'),
86
- change: { value: '+23.1%', isPositive: true },
87
- icon: 'image',
88
- color: 'purple'
89
- },
90
- {
91
- id: 'new-media',
92
- title: t('dashboard.newMediaFiles'),
93
- value: '89.2K',
94
- description: t('dashboard.thisMonth'),
95
- change: { value: '-2.4%', isPositive: false },
96
- icon: 'eye',
97
- color: 'orange'
98
- }
99
- ]);
100
-
101
- const recentContent = ref<ContentItem[]>([
102
- {
103
- id: 1,
104
- type: 'Article',
105
- status: 'published',
106
- title: t('dashboard.gettingStartedWithNextJs14'),
107
- author: t('dashboard.sarahJohnson'),
108
- updated_at: '2024-01-15',
109
- views: 1247
110
- },
111
- {
112
- id: 2,
113
- type: 'Post',
114
- status: 'draft',
115
- title: t('dashboard.advancedReactPatterns'),
116
- author: t('dashboard.mikeChen'),
117
- updated_at: '2024-01-14',
118
- views: 0
119
- },
120
- {
121
- id: 3,
122
- type: 'Article',
123
- status: 'published',
124
- title: t('dashboard.uiUxDesignPrinciples'),
125
- author: t('dashboard.emmaWilson'),
126
- updated_at: '2024-01-13',
127
- views: 892
128
- },
129
- {
130
- id: 4,
131
- type: 'Post',
132
- status: 'review',
133
- title: t('dashboard.databaseOptimizationTips'),
134
- author: t('dashboard.alexRodriguez'),
135
- updated_at: '2024-01-12',
136
- views: 0
137
- }
138
- ]);
139
-
140
- const rewriteStatsData = (data: any) => {
141
- statsData.value = statsData.value.map(stat => {
142
- switch (stat.id) {
143
- case 'total-content':
144
- return { ...stat, value: data.totalContent?.toLocaleString() ?? stat.value };
145
- case 'active-users':
146
- return { ...stat, value: data.totalUsers?.toLocaleString() ?? stat.value };
147
- case 'media-files':
148
- return { ...stat, value: data.totalMediaFiles?.toLocaleString() ?? stat.value };
149
- case 'new-media':
150
- return { ...stat, value: data.newMediaFiles?.toLocaleString() ?? stat.value };
151
- default:
152
- return stat;
153
- }
154
- });
155
- }
156
-
157
- const fetchDashboardData = async () => {
158
- const res = await fetch('api/cms-stat');
159
- const data = await res.json();
160
-
161
- recentContent.value = data.recentContent;
162
- rewriteStatsData(data.stat);
163
- };
164
-
165
- onMounted(() => {
166
- fetchDashboardData();
167
- });
168
- </script>
@@ -1,183 +0,0 @@
1
- <template>
2
-
3
- <div class="w-full max-w-7xl mx-auto space-y-6">
4
- <SettingsTitle :title="$t('email.title')" :description="$t('email.description')" />
5
- <div class="rounded-xl text-card-foreground shadow-lg border-0 bg-white dark:bg-slate-800 backdrop-blur-sm">
6
- <div class="flex flex-col space-y-1.5 p-6 border-b border-slate-200 dark:border-slate-700 bg-gradient-to-r from-slate-50 dark:from-slate-800 to-white dark:to-slate-800">
7
- <h3 class="tracking-tight text-xl font-semibold text-slate-800 dark:text-slate-100 flex items-center">
8
- <TableCellsMerge class="text-emerald-500 mr-2"/>
9
- {{ $t('email.title') }}
10
- </h3>
11
- </div>
12
- <div class="p-6 space-y-4">
13
- <div class="flex justify-between">
14
- <VsFilter
15
- :schema="filterScheme"
16
- view="inline"
17
- @change="handleChange"
18
- />
19
- </div>
20
- <div class="overflow-x-auto" v-if="email?.length">
21
- <table class="min-w-full divide-y divide-gray-200">
22
- <thead class="bg-gray-100">
23
- <tr>
24
- <th class="px-4 py-2 text-left text-sm font-semibold text-gray-700">№</th>
25
- <th class="px-4 py-2 text-left text-sm font-semibold text-gray-700">{{ $t('feedback.table.email') }}</th>
26
- <th class="px-4 py-2 text-left text-sm font-semibold text-gray-700">{{ $t('feedback.table.cdate') }}</th>
27
- <th class="px-4 py-2 text-left text-sm font-semibold text-gray-700"></th>
28
- </tr>
29
- </thead>
30
- <tbody class="divide-y divide-gray-200" v-for="(email, index) in email" :key="email?.message_id">
31
-
32
- <tr class="cursor-pointer dark:text-white">
33
- <td class="px-4 py-2 text-sm text-gray-800 dark:text-white">{{ email?.num }}</td>
34
- <td class="px-4 py-2 text-sm text-gray-800 dark:text-white">{{ email?.email }}</td>
35
- <td class="px-4 py-2 text-sm text-gray-800 dark:text-white">{{ formatDate(email?.created_at) }}</td>
36
- </tr>
37
- </tbody>
38
- </table>
39
- </div>
40
- <div class='bg-white dark:bg-slate-800 backdrop-blur-sm0 text-center p-6 rounded-xl' v-else>
41
- <h3 class='text-lg font-semibold'>{{ $t('feedback.table.noFeedback') }}</h3>
42
- </div>
43
-
44
- <div class="my-5 pr-2">
45
- <div class="paginationWrapper relative flex justify-center">
46
- <VsPagination
47
- :total
48
- :maxPages="6"
49
- :defaultPage="page"
50
- :pageSize="limit"
51
- :goTo="false"
52
- size="medium"
53
- backgroundColor="#e5e7eb"
54
- :borderedCellSelected="true"
55
- :pageSizes="[16, 32, 48]"
56
- @pageChange="handlePageChange"
57
- @pageSizeChange="changeLimit"
58
- />
59
- </div>
60
- </div>
61
-
62
- </div>
63
- </div>
64
- </div>
65
- </template>
66
- <script>
67
- import SettingsTitle from '@/components/settings/SettingsTitle.vue';
68
- import VsFilter from '@opengis/filter';
69
- import {
70
- TableCellsMerge,
71
- ArrowDown,
72
- ArrowUp,
73
- ArrowRightFromLine,
74
- } from "lucide-vue-next";
75
-
76
- export default {
77
- components: {
78
- SettingsTitle,
79
- VsFilter,
80
- TableCellsMerge,
81
- ArrowDown,
82
- ArrowUp,
83
- ArrowRightFromLine
84
- },
85
- data() {
86
- return {
87
- email: null,
88
- total: 0,
89
- openIndex: null,
90
- limit: 16,
91
- page: 1,
92
- filterValue: '',
93
- filterScheme: [],
94
- }
95
- },
96
- async created() {
97
- this.$router.replace({
98
- query: { page: 1 }
99
- })
100
- await this.getData();
101
- },
102
- methods: {
103
- async getData() {
104
- try {
105
- const response = await fetch(`/api/email-list?limit=${this.limit}&page=${this.page}`);
106
- const data = await response.json();
107
- this.email = data?.rows;
108
- this.total = data?.total;
109
- this.filterScheme = data?.filters;
110
- } catch (err) {
111
- console.error(err.toString())
112
- }
113
- },
114
- async handleChange(filters) {
115
- const filterStr = Object.entries(filters?.data)
116
- .filter(([, v]) => v != null)
117
- .map(([key, val]) => `${key}=${val}`)
118
- .join('|');
119
-
120
- this.filterValue = filterStr;
121
-
122
- if (this.filterValue ==='no-url') {
123
- this.$router.replace({
124
- query: { page: 1 }
125
- })
126
- } else {
127
- this.$router.replace({
128
- query: { filter:this.filterValue, page: 1 }
129
- })
130
-
131
- };
132
- this.page = 1;
133
- await this.getData();
134
- },
135
- async handlePageChange(page) {
136
- this.page = page;
137
- if (this.filterValue==='no-url' || !this.filterValue) {
138
- this.$router.replace({
139
- query: { page }
140
- })
141
- } else {
142
- this.$router.replace({
143
- query: { filter:this.filterValue, page}
144
- })
145
-
146
- }
147
- await this.getData();
148
- },
149
- async changeLimit(limit) {
150
- this.limit = limit;
151
- this.page = 1;
152
- await this.getData();
153
- },
154
- toggle(index) {
155
- this.openIndex = this.openIndex === index ? null : index
156
- },
157
- onEnter(el) {
158
- el.style.height = '0'
159
- el.style.opacity = '0'
160
- requestAnimationFrame(() => {
161
- el.style.transition = 'all 0.3s ease'
162
- el.style.height = el.scrollHeight + 'px'
163
- el.style.opacity = '1'
164
- })
165
- },
166
- onLeave(el) {
167
- el.style.height = el.scrollHeight + 'px'
168
- el.style.opacity = '1'
169
- requestAnimationFrame(() => {
170
- el.style.transition = 'all 0.3s ease'
171
- el.style.height = '0'
172
- el.style.opacity = '0'
173
- })
174
- },
175
- formatDate(date) {
176
- if (!date) return null;
177
- const options = { year: "numeric", month: "2-digit", day: "2-digit" };
178
- return new Date(date).toLocaleDateString("uk-UA", options);
179
- }
180
- }
181
-
182
- }
183
- </script>
@@ -1,232 +0,0 @@
1
- <template>
2
-
3
- <div class="w-full max-w-7xl mx-auto space-y-6">
4
- <SettingsTitle :title="$t('feedback.title')" :description="$t('feedback.description')" />
5
- <div class="rounded-xl text-card-foreground shadow-lg border-0 bg-white dark:bg-slate-800 backdrop-blur-sm">
6
- <div class="flex flex-col space-y-1.5 p-6 border-b border-slate-200 dark:border-slate-700 bg-gradient-to-r from-slate-50 dark:from-slate-800 to-white dark:to-slate-800">
7
- <h3 class="tracking-tight text-xl font-semibold text-slate-800 dark:text-slate-100 flex items-center">
8
- <TableCellsMerge class="text-emerald-500 mr-2"/>
9
- {{ $t('feedback.title') }}
10
- </h3>
11
- </div>
12
- <div class="p-6 space-y-4">
13
- <div class="flex justify-between">
14
- <VsFilter
15
- :schema="filterScheme"
16
- view="inline"
17
- @change="handleChange"
18
- />
19
- </div>
20
- <div class="overflow-x-auto" v-if="feedback?.length">
21
- <table class="min-w-full divide-y divide-gray-200">
22
- <thead class="bg-gray-100">
23
- <tr>
24
- <th class="px-4 py-2 text-left text-sm font-semibold text-gray-700">№</th>
25
- <th class="px-4 py-2 text-left text-sm font-semibold text-gray-700">{{ $t('feedback.table.userName') }}</th>
26
- <th class="px-4 py-2 text-left text-sm font-semibold text-gray-700">{{ $t('feedback.table.email') }}</th>
27
- <th class="px-4 py-2 text-left text-sm font-semibold text-gray-700">{{ $t('feedback.table.cdate') }}</th>
28
- <th class="px-4 py-2 text-left text-sm font-semibold text-gray-700">{{ $t('feedback.table.phone') }}</th>
29
- <th class="px-4 py-2 text-left text-sm font-semibold text-gray-700"></th>
30
- </tr>
31
- </thead>
32
- <tbody class="divide-y divide-gray-200" v-for="(feedback, index) in feedback" :key="feedback?.message_id">
33
-
34
- <tr class="cursor-pointer dark:text-white" @click="toggle(feedback?.message_id)">
35
- <td class="px-4 py-2 text-sm text-gray-800 dark:text-white">{{ feedback?.num }}</td>
36
- <td class="px-4 py-2 text-sm text-gray-800 dark:text-white">{{feedback?.user_name}}</td>
37
- <td class="px-4 py-2 text-sm text-gray-800 dark:text-white">{{ feedback?.email }}</td>
38
- <td class="px-4 py-2 text-sm text-gray-800 dark:text-white">{{ formatDate(feedback?.created_at) }}</td>
39
- <td class="px-4 py-2 text-sm text-gray-800 dark:text-white">{{feedback?.phone}}</td>
40
- <td class="px-4 py-2 text-sm text-gray-800 dark:text-white">
41
- <div>
42
- <ArrowUp v-if="openIndex === feedback?.message_id"/>
43
- <ArrowDown v-else/>
44
- </div>
45
- </td>
46
- </tr>
47
- <Transition name="collapse" @enter="onEnter" @leave="onLeave">
48
- <tr v-show="openIndex === feedback?.message_id">
49
- <td colspan="6" class="bg-gray-50 px-4 py-3 text-sm text-gray-700 dark:text-slate-300">
50
- <div ref="content" class="transition-all duration-300 ease-in-out space-y-2">
51
-
52
- <div v-if="feedback?.message_text">
53
- <b>{{ $t('feedback.table.messageText') }}:</b>
54
- <p class="whitespace-pre-line mt-1">{{ feedback.message_text }}</p>
55
- </div>
56
-
57
- <div v-if="feedback?.feedback_type">
58
- <b>{{ $t('feedback.table.feedbackType') }}:</b>
59
- <span>{{ feedback.feedback_type }}</span>
60
- </div>
61
-
62
- <div v-if="feedback?.telegram_link">
63
- <b>Telegram:</b>
64
- <a :href="feedback.telegram_link" class="text-blue-500 underline " target="_blank">{{ feedback.telegram_link }}</a>
65
- </div>
66
-
67
- <div v-if="feedback?.linkedin_link">
68
- <b>LinkedIn:</b>
69
- <a :href="feedback.linkedin_link" class="text-blue-500 underline " target="_blank">{{ feedback.linkedin_link }}</a>
70
- </div>
71
-
72
- <div v-if="feedback?.portfolio_link">
73
- <b>{{ $t('feedback.table.portfolioLink') }}:</b>
74
- <a :href="feedback.portfolio_link" class="text-blue-500 underline " target="_blank">{{ feedback.portfolio_link }}</a>
75
- </div>
76
- </div>
77
- </td>
78
- </tr>
79
- </Transition>
80
- </tbody>
81
- </table>
82
- </div>
83
- <div class='bg-white dark:bg-slate-800 backdrop-blur-sm0 text-center p-6 rounded-xl' v-else>
84
- <h3 class='text-lg font-semibold'>{{ $t('feedback.table.noFeedback') }}</h3>
85
- </div>
86
-
87
- <div class="my-5 pr-2">
88
- <div class="paginationWrapper relative flex justify-center">
89
- <VsPagination
90
- :total
91
- :maxPages="6"
92
- :defaultPage="page"
93
- :pageSize="limit"
94
- :goTo="false"
95
- size="medium"
96
- backgroundColor="#e5e7eb"
97
- :borderedCellSelected="true"
98
- :pageSizes="[16, 32, 48]"
99
- @pageChange="handlePageChange"
100
- @pageSizeChange="changeLimit"
101
- />
102
- </div>
103
- </div>
104
-
105
- </div>
106
- </div>
107
- </div>
108
- </template>
109
- <script>
110
- import SettingsTitle from '@/components/settings/SettingsTitle.vue';
111
- import {
112
- TableCellsMerge,
113
- ArrowDown,
114
- ArrowUp,
115
- ArrowRightFromLine,
116
- } from "lucide-vue-next";
117
- import VsFilter from '@opengis/filter';
118
-
119
- export default {
120
- components: {
121
- SettingsTitle,
122
- TableCellsMerge,
123
- ArrowDown,
124
- ArrowUp,
125
- ArrowRightFromLine,
126
- VsFilter
127
- },
128
- data() {
129
- return {
130
- feedback: null,
131
- total: 0,
132
- openIndex: null,
133
- limit: 16,
134
- page: 1,
135
- filterValue: '',
136
- filterScheme: [],
137
- }
138
- },
139
- async created() {
140
- this.$router.replace({
141
- query: { page: 1 }
142
- })
143
- await this.getData();
144
- },
145
- methods: {
146
- async getData() {
147
- try {
148
- const response = await fetch(`/api/feedback?limit=${this.limit}&page=${this.page}${(this.filterValue ==='no-url') ? '':`&filter=${this.filterValue}`}`);
149
- const data = await response.json();
150
- this.feedback = data?.rows;
151
- this.total = data?.total;
152
-
153
- // Clean filter schema to only include valid IFilterItem properties
154
- const cleanFilters = (data?.filters || []).map((filter) => {
155
- const { extra, title, ...cleanFilter } = filter;
156
- return cleanFilter;
157
- });
158
- this.filterScheme = cleanFilters;
159
- } catch (err) {
160
- console.error(err.toString())
161
- }
162
- },
163
- async handleChange(filters) {
164
- const filterStr = Object.entries(filters?.data)
165
- .filter(([, v]) => v != null)
166
- .map(([key, val]) => `${key}=${val}`)
167
- .join('|');
168
-
169
- this.filterValue = filterStr;
170
-
171
- if (this.filterValue ==='no-url') {
172
- this.$router.replace({
173
- query: { page: 1 }
174
- })
175
- } else {
176
- this.$router.replace({
177
- query: { filter:this.filterValue, page: 1 }
178
- })
179
-
180
- };
181
- this.page = 1;
182
- await this.getData();
183
- },
184
- async handlePageChange(page) {
185
- this.page = page;
186
- if (this.filterValue==='no-url' || !this.filterValue) {
187
- this.$router.replace({
188
- query: { page }
189
- })
190
- } else {
191
- this.$router.replace({
192
- query: { filter:this.filterValue, page}
193
- })
194
-
195
- }
196
- await this.getData();
197
- },
198
- async changeLimit(limit) {
199
- this.limit = limit;
200
- this.page = 1;
201
- await this.getData();
202
- },
203
- toggle(index) {
204
- this.openIndex = this.openIndex === index ? null : index
205
- },
206
- onEnter(el) {
207
- el.style.height = '0'
208
- el.style.opacity = '0'
209
- requestAnimationFrame(() => {
210
- el.style.transition = 'all 0.3s ease'
211
- el.style.height = el.scrollHeight + 'px'
212
- el.style.opacity = '1'
213
- })
214
- },
215
- onLeave(el) {
216
- el.style.height = el.scrollHeight + 'px'
217
- el.style.opacity = '1'
218
- requestAnimationFrame(() => {
219
- el.style.transition = 'all 0.3s ease'
220
- el.style.height = '0'
221
- el.style.opacity = '0'
222
- })
223
- },
224
- formatDate(date) {
225
- if (!date) return null;
226
- const options = { year: "numeric", month: "2-digit", day: "2-digit" };
227
- return new Date(date).toLocaleDateString("uk-UA", options);
228
- }
229
- }
230
-
231
- }
232
- </script>