@ozdao/martyrs 0.2.561 → 0.2.563

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 (197) hide show
  1. package/dist/{abac-DC2x92Pa.js → abac-DYoheWuc.js} +2 -1
  2. package/dist/{core.logger-VRHh-WUW.js → core.cache-DALYFDdy.js} +10 -59
  3. package/dist/core.logger-C3q8A9dl.js +51 -0
  4. package/dist/core.server.js +1 -1
  5. package/dist/{crud-DFFgLl09.js → crud-C7FSTUes.js} +2 -1
  6. package/dist/inventory.server.js +4 -3
  7. package/dist/{main-DQtUY5ma.js → main-CmjWiDVF.js} +2837 -2548
  8. package/dist/marketplace.server.js +389 -0
  9. package/dist/martyrs/src/components/Button/{Button.vue.js → Button.vue2.js} +3 -3
  10. package/dist/martyrs/src/components/Button/Button.vue2.js.map +1 -0
  11. package/dist/martyrs/src/components/Checkbox/Checkbox.vue.js +1 -1
  12. package/dist/martyrs/src/components/Checkbox/Checkbox.vue.js.map +1 -1
  13. package/dist/martyrs/src/components/FieldBig/FieldBig.vue.js +1 -1
  14. package/dist/martyrs/src/components/Menu/{Menu.vue2.js → Menu.vue.js} +2 -2
  15. package/dist/martyrs/src/components/Menu/Menu.vue.js.map +1 -0
  16. package/dist/martyrs/src/components/Select/{Select.vue2.js → Select.vue.js} +2 -2
  17. package/dist/martyrs/src/components/Select/Select.vue.js.map +1 -0
  18. package/dist/martyrs/src/components/Spoiler/{Spoiler.vue.js → Spoiler.vue2.js} +2 -2
  19. package/dist/martyrs/src/components/Spoiler/Spoiler.vue2.js.map +1 -0
  20. package/dist/martyrs/src/modules/auth/views/components/pages/EnterPassword.vue.js +1 -1
  21. package/dist/martyrs/src/modules/auth/views/components/pages/Invite.vue.js +1 -1
  22. package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js +2 -2
  23. package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEditAccount.vue.js +1 -1
  24. package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEditProfile.vue.js +1 -1
  25. package/dist/martyrs/src/modules/auth/views/components/pages/ResetPassword.vue.js +1 -1
  26. package/dist/martyrs/src/modules/auth/views/components/pages/SignIn.vue.js +1 -1
  27. package/dist/martyrs/src/modules/auth/views/components/pages/SignUp.vue.js +1 -1
  28. package/dist/martyrs/src/modules/auth/views/components/sections/ProfileEditCredentials.vue.js +1 -1
  29. package/dist/martyrs/src/modules/community/components/layouts/Community.vue.js +1 -1
  30. package/dist/martyrs/src/modules/community/components/pages/BlogPost.vue.js +1 -1
  31. package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.js +1 -1
  32. package/dist/martyrs/src/modules/core/views/components/blocks/CardHeader.vue.js +1 -1
  33. package/dist/martyrs/src/modules/core/views/components/blocks/PopupAuth.vue.js +1 -1
  34. package/dist/martyrs/src/modules/core/views/components/blocks/PopupDateSelector.vue.js +1 -1
  35. package/dist/martyrs/src/modules/core/views/components/layouts/Client.vue.js +3 -6
  36. package/dist/martyrs/src/modules/core/views/components/layouts/Client.vue.js.map +1 -1
  37. package/dist/martyrs/src/modules/core/views/components/partials/Header.vue.js +3 -3
  38. package/dist/martyrs/src/modules/core/views/components/partials/Header.vue.js.map +1 -1
  39. package/dist/martyrs/src/modules/core/views/components/partials/Navigation.vue.js +1 -1
  40. package/dist/martyrs/src/modules/core/views/components/partials/NavigationBar.vue.js +1 -1
  41. package/dist/martyrs/src/modules/core/views/components/sections/Filters.vue.js +59 -171
  42. package/dist/martyrs/src/modules/core/views/components/sections/Filters.vue.js.map +1 -1
  43. package/dist/martyrs/src/modules/core/views/components/sections/filters/FilterCheckbox.vue2.js +64 -0
  44. package/dist/martyrs/src/modules/core/views/components/sections/filters/FilterCheckbox.vue2.js.map +1 -0
  45. package/dist/martyrs/src/modules/core/views/components/sections/filters/FilterDateRange.vue2.js +160 -0
  46. package/dist/martyrs/src/modules/core/views/components/sections/filters/FilterDateRange.vue2.js.map +1 -0
  47. package/dist/martyrs/src/modules/core/views/components/sections/filters/FilterOptions.vue.js +46 -0
  48. package/dist/martyrs/src/modules/core/views/components/sections/filters/FilterOptions.vue.js.map +1 -0
  49. package/dist/martyrs/src/modules/core/views/components/sections/filters/FilterRange.vue.js +105 -0
  50. package/dist/martyrs/src/modules/core/views/components/sections/filters/FilterRange.vue.js.map +1 -0
  51. package/dist/martyrs/src/modules/core/views/components/sections/filters/FiltersGroup.vue.js +166 -0
  52. package/dist/martyrs/src/modules/core/views/components/sections/filters/FiltersGroup.vue.js.map +1 -0
  53. package/dist/martyrs/src/modules/core/views/utils/vue-app-renderer.js +4 -0
  54. package/dist/martyrs/src/modules/core/views/utils/vue-app-renderer.js.map +1 -1
  55. package/dist/martyrs/src/modules/events/components/elements/ButtonCheck.vue.js +1 -1
  56. package/dist/martyrs/src/modules/events/components/elements/ButtonJoin.vue.js +1 -1
  57. package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.js +1 -1
  58. package/dist/martyrs/src/modules/events/components/pages/EditEventTickets.vue.js +1 -1
  59. package/dist/martyrs/src/modules/events/components/pages/Event.vue.js +2 -0
  60. package/dist/martyrs/src/modules/events/components/pages/Event.vue.js.map +1 -1
  61. package/dist/martyrs/src/modules/events/components/sections/EditTickets.vue.js +1 -1
  62. package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.js +2 -2
  63. package/dist/martyrs/src/modules/inventory/components/forms/AdjustmentForm.vue.js +2 -2
  64. package/dist/martyrs/src/modules/inventory/components/forms/ColumnSettingsMenu.vue.js +1 -1
  65. package/dist/martyrs/src/modules/inventory/components/forms/HistoryView.vue.js +1 -1
  66. package/dist/martyrs/src/modules/inventory/components/forms/StockAlertsForm.vue.js +2 -2
  67. package/dist/martyrs/src/modules/inventory/components/pages/InventoryEdit.vue.js +2 -2
  68. package/dist/martyrs/src/modules/landing/components/sections/SectionFeatures.vue.js +1 -1
  69. package/dist/martyrs/src/modules/landing/components/sections/SectionFeatures.vue.js.map +1 -1
  70. package/dist/martyrs/src/modules/landing/components/sections/SectionGuide.vue.js +1 -1
  71. package/dist/martyrs/src/modules/marketplace/marketplace.client.js +5 -9
  72. package/dist/martyrs/src/modules/marketplace/marketplace.client.js.map +1 -1
  73. package/dist/martyrs/src/modules/marketplace/views/components/pages/Marketplace.vue.js +242 -0
  74. package/dist/martyrs/src/modules/marketplace/views/components/pages/Marketplace.vue.js.map +1 -0
  75. package/dist/martyrs/src/modules/marketplace/views/router/marketplace.router.js +39 -0
  76. package/dist/martyrs/src/modules/marketplace/views/router/marketplace.router.js.map +1 -0
  77. package/dist/martyrs/src/modules/marketplace/views/store/marketplace.js +65 -2
  78. package/dist/martyrs/src/modules/marketplace/views/store/marketplace.js.map +1 -1
  79. package/dist/martyrs/src/modules/music/components/cards/AlbumCard.vue.js +1 -1
  80. package/dist/martyrs/src/modules/music/components/cards/ArtistCardSmall.vue.js +1 -1
  81. package/dist/martyrs/src/modules/music/components/cards/PlaylistCard.vue.js +1 -1
  82. package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.js +1 -1
  83. package/dist/martyrs/src/modules/music/components/forms/AlbumForm.vue.js +2 -2
  84. package/dist/martyrs/src/modules/music/components/forms/ArtistForm.vue.js +2 -2
  85. package/dist/martyrs/src/modules/music/components/forms/PlaylistForm.vue.js +1 -1
  86. package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.js +1 -1
  87. package/dist/martyrs/src/modules/music/components/forms/TrackForm.vue.js +2 -2
  88. package/dist/martyrs/src/modules/music/components/pages/Album.vue.js +1 -1
  89. package/dist/martyrs/src/modules/music/components/pages/Artist.vue.js +1 -1
  90. package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.js +1 -1
  91. package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.js +1 -1
  92. package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.js +1 -1
  93. package/dist/martyrs/src/modules/music/components/pages/Track.vue.js +1 -1
  94. package/dist/martyrs/src/modules/music/components/pages/TrackCreate.vue.js +1 -1
  95. package/dist/martyrs/src/modules/music/components/player/MusicPlayer.vue.js +1 -1
  96. package/dist/martyrs/src/modules/orders/components/forms/FormApplicationDetails.vue.js +2 -2
  97. package/dist/martyrs/src/modules/orders/components/forms/FormCustomerDetails.vue.js +2 -2
  98. package/dist/martyrs/src/modules/orders/components/forms/FormSelectCustomer.vue.js +1 -1
  99. package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js +2 -2
  100. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js +1 -1
  101. package/dist/martyrs/src/modules/orders/components/pages/OrderCreateBackoffice.vue.js +1 -1
  102. package/dist/martyrs/src/modules/orders/components/sections/ApplicationDetails.vue.js +1 -1
  103. package/dist/martyrs/src/modules/orders/components/sections/CustomerDetails.vue.js +1 -1
  104. package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js +2 -0
  105. package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js.map +1 -1
  106. package/dist/martyrs/src/modules/orders/components/sections/FormPayment.vue.js +1 -1
  107. package/dist/martyrs/src/modules/organizations/components/blocks/CardDepartment.vue.js +1 -1
  108. package/dist/martyrs/src/modules/organizations/components/blocks/CardOrganization.vue.js +4 -4
  109. package/dist/martyrs/src/modules/organizations/components/blocks/CardOrganization.vue.js.map +1 -1
  110. package/dist/martyrs/src/modules/organizations/components/elements/ButtonToggleMembership.vue.js +1 -1
  111. package/dist/martyrs/src/modules/organizations/components/forms/AddExistingMembersForm.vue.js +1 -1
  112. package/dist/martyrs/src/modules/organizations/components/forms/DepartmentForm.vue.js +2 -2
  113. package/dist/martyrs/src/modules/organizations/components/forms/InviteForm.vue.js +1 -1
  114. package/dist/martyrs/src/modules/organizations/components/pages/Department.vue.js +1 -1
  115. package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.js +1 -1
  116. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationBackoffice.vue.js +1 -1
  117. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js +2 -2
  118. package/dist/martyrs/src/modules/organizations/components/sections/Documents.vue.js +1 -1
  119. package/dist/martyrs/src/modules/organizations/components/sections/MembersAdd.vue.js +2 -2
  120. package/dist/martyrs/src/modules/organizations/components/sections/Organizations.vue.js +1 -1
  121. package/dist/martyrs/src/modules/pages/views/components/blocks/CardPage.vue.js +1 -1
  122. package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.js +1 -1
  123. package/dist/martyrs/src/modules/pages/views/components/partials/SidebarPages.vue.js +1 -1
  124. package/dist/martyrs/src/modules/products/components/pages/Categories.vue.js +1 -1
  125. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js +4 -2
  126. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js.map +1 -1
  127. package/dist/martyrs/src/modules/products/components/pages/Product.vue.js +1 -1
  128. package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js +2 -2
  129. package/dist/martyrs/src/modules/products/components/pages/Products.vue.js +1 -1
  130. package/dist/martyrs/src/modules/products/components/sections/EditAttributes.vue.js +1 -1
  131. package/dist/martyrs/src/modules/products/components/sections/EditDiscounts.vue.js +2 -2
  132. package/dist/martyrs/src/modules/products/components/sections/EditVariants.vue.js +2 -2
  133. package/dist/martyrs/src/modules/products/components/sections/FilterProducts.vue.js +1 -1
  134. package/dist/martyrs/src/modules/products/components/sections/ProductConfigurator.vue.js +1 -1
  135. package/dist/martyrs/src/modules/products/components/sections/ProductsRecommended.vue.js +1 -1
  136. package/dist/martyrs/src/modules/products/components/sections/SectionProduct.vue.js +1 -1
  137. package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttToolbar.vue.js +1 -1
  138. package/dist/martyrs/src/modules/reports/components/sections/FormReport.vue.js +2 -2
  139. package/dist/martyrs/src/modules/spots/components/blocks/SpotMemberModify.vue.js +1 -1
  140. package/dist/martyrs/src/modules/spots/components/layouts/Spots.vue.js +1 -1
  141. package/dist/martyrs/src/modules/spots/components/pages/Map.vue.js +1 -1
  142. package/dist/martyrs/src/modules/spots/components/pages/Spot.vue.js +1 -1
  143. package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.js +2 -2
  144. package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.js +2 -2
  145. package/dist/martyrs/src/modules/wallet/views/components/blocks/CryptoDeposit.vue.js +1 -1
  146. package/dist/martyrs/src/modules/wallet/views/components/pages/Wallet.vue.js +2 -2
  147. package/dist/martyrs.css +1 -1
  148. package/dist/martyrs.es.js +1 -1
  149. package/dist/music.server.js +4 -3
  150. package/dist/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/utils.js +1 -1
  151. package/dist/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/utils.js +1 -1
  152. package/dist/orders.server.js +2 -2
  153. package/dist/organizations.server.js +10 -215
  154. package/dist/products.server.js +4 -3
  155. package/dist/queryProcessorOrganizations-BB11WFpc.js +221 -0
  156. package/dist/rents.server.js +2 -1
  157. package/dist/style.css +10 -1
  158. package/dist/{web-Cyc6i_pv.js → web-cNKIl_cL.js} +1 -1
  159. package/package.json +1 -1
  160. package/src/components/Button/Button.vue +1 -1
  161. package/src/components/Checkbox/Checkbox.vue +1 -1
  162. package/src/modules/core/views/components/layouts/Client.vue +7 -11
  163. package/src/modules/core/views/components/partials/Header.vue +1 -1
  164. package/src/modules/core/views/components/sections/Filters.vue +47 -161
  165. package/src/modules/core/views/components/sections/filters/FilterCheckbox.vue +12 -31
  166. package/src/modules/core/views/components/sections/filters/FilterDateRange.vue +15 -15
  167. package/src/modules/core/views/components/sections/filters/FilterOptions.vue +12 -43
  168. package/src/modules/core/views/components/sections/filters/FilterRange.vue +59 -36
  169. package/src/modules/core/views/components/sections/filters/FiltersGroup.vue +177 -0
  170. package/src/modules/core/views/utils/vue-app-renderer.js +12 -0
  171. package/src/modules/landing/components/sections/SectionFeatures.vue +1 -1
  172. package/src/modules/marketplace/controllers/marketplace.controller.js +123 -0
  173. package/src/modules/marketplace/controllers/utils/lookupConfigs.js +130 -0
  174. package/src/modules/marketplace/controllers/utils/queryProcessorMarketplace.js +211 -0
  175. package/src/modules/marketplace/marketplace.client.js +3 -10
  176. package/src/modules/marketplace/marketplace.server.js +22 -0
  177. package/src/modules/marketplace/routes/marketplace.routes.js +34 -0
  178. package/src/modules/marketplace/views/components/pages/Marketplace.vue +273 -0
  179. package/src/modules/marketplace/views/router/marketplace.router.js +37 -30
  180. package/src/modules/marketplace/views/store/marketplace.js +74 -3
  181. package/src/modules/organizations/components/blocks/CardOrganization.vue +8 -8
  182. package/src/modules/organizations/controllers/organizations.controller.js +1 -1
  183. package/src/modules/organizations/controllers/utils/queryProcessorOrganizations.js +8 -1
  184. package/dist/martyrs/src/components/Button/Button.vue.js.map +0 -1
  185. package/dist/martyrs/src/components/Menu/Menu.vue2.js.map +0 -1
  186. package/dist/martyrs/src/components/Select/Select.vue2.js.map +0 -1
  187. package/dist/martyrs/src/components/Spoiler/Spoiler.vue.js.map +0 -1
  188. package/dist/martyrs/src/modules/marketplace/marketplace.router.js +0 -63
  189. package/dist/martyrs/src/modules/marketplace/marketplace.router.js.map +0 -1
  190. package/dist/martyrs/src/modules/marketplace/views/components/layouts/Marketplace.vue.js +0 -326
  191. package/dist/martyrs/src/modules/marketplace/views/components/layouts/Marketplace.vue.js.map +0 -1
  192. package/dist/martyrs/src/modules/marketplace/views/components/pages/Catalog.vue.js +0 -74
  193. package/dist/martyrs/src/modules/marketplace/views/components/pages/Catalog.vue.js.map +0 -1
  194. package/src/modules/core/views/components/sections/filters/FilterPrice.vue +0 -81
  195. package/src/modules/marketplace/marketplace.router.js +0 -66
  196. package/src/modules/marketplace/views/components/layouts/Marketplace.vue +0 -363
  197. package/src/modules/marketplace/views/components/pages/Catalog.vue +0 -73
@@ -0,0 +1,177 @@
1
+ <template>
2
+ <div>
3
+ <div v-if="showHeader" class="flex-v-center flex-nowrap flex mn-b-medium">
4
+ <h3 class="flex-child-full">Filters</h3>
5
+ </div>
6
+
7
+ <div class="filters-content">
8
+ <div
9
+ v-for="filter in filters"
10
+ :key="filter.value"
11
+ class="mn-b-medium"
12
+ >
13
+ <h4 class="mn-b-small">{{ filter.title }}</h4>
14
+
15
+ <!-- Checkbox Filter -->
16
+ <FilterCheckbox
17
+ v-if="filter.type === 'checkbox'"
18
+ v-model="workingValues[filter.value]"
19
+ :options="filter.options"
20
+ @apply="handleApply(filter.value)"
21
+ />
22
+
23
+ <!-- Range Filter -->
24
+ <FilterRange
25
+ v-else-if="filter.type === 'range'"
26
+ v-model="workingValues[filter.value]"
27
+ :minPlaceholder="filter.minPlaceholder || 'Min'"
28
+ :maxPlaceholder="filter.maxPlaceholder || 'Max'"
29
+ :label="filter.label"
30
+ @apply="handleApply(filter.value)"
31
+ />
32
+
33
+ <!-- Date Filter -->
34
+ <FilterDateRange
35
+ v-else-if="filter.type === 'date'"
36
+ v-model="workingValues[filter.value]"
37
+ @apply="handleApply(filter.value)"
38
+ />
39
+
40
+ <!-- Radio/Options Filter -->
41
+ <FilterOptions
42
+ v-else-if="filter.type === 'radio'"
43
+ v-model="workingValues[filter.value]"
44
+ :options="filter.options"
45
+ />
46
+ </div>
47
+ </div>
48
+
49
+ <div class="flex gap-thin mn-t-medium">
50
+ <button
51
+ v-if="showApplyButton"
52
+ @click="applyFilters"
53
+ class="button bg-main flex-child-full"
54
+ >
55
+ Apply
56
+ </button>
57
+ <button
58
+ v-if="showResetButton"
59
+ @click="resetFilters"
60
+ class="button bg-light"
61
+ :class="{ 'flex-child-full': !showApplyButton }"
62
+ >
63
+ Reset Filters
64
+ </button>
65
+ </div>
66
+ </div>
67
+ </template>
68
+
69
+ <script setup>
70
+ import { ref, reactive, watch } from 'vue'
71
+ import { useGlobalMixins } from '@martyrs/src/modules/core/views/mixins/mixins.js'
72
+ import FilterCheckbox from './FilterCheckbox.vue'
73
+ import FilterRange from './FilterRange.vue'
74
+ import FilterDateRange from './FilterDateRange.vue'
75
+ import FilterOptions from './FilterOptions.vue'
76
+
77
+ const props = defineProps({
78
+ filters: {
79
+ type: Array,
80
+ required: true
81
+ },
82
+ immediate: {
83
+ type: Boolean,
84
+ default: false
85
+ },
86
+ showHeader: {
87
+ type: Boolean,
88
+ default: true
89
+ },
90
+ showApplyButton: {
91
+ type: Boolean,
92
+ default: false
93
+ },
94
+ showResetButton: {
95
+ type: Boolean,
96
+ default: true
97
+ }
98
+ })
99
+
100
+ const selected = defineModel('selected', {
101
+ type: Object,
102
+ default: () => ({})
103
+ })
104
+
105
+ const { returnCurrency } = useGlobalMixins()
106
+
107
+ const workingValues = reactive({})
108
+
109
+ // Initialize working values
110
+ watch(() => props.filters, (newFilters) => {
111
+ newFilters.forEach(filter => {
112
+ if (!workingValues[filter.value]) {
113
+ if (filter.type === 'checkbox') {
114
+ workingValues[filter.value] = [...(selected.value[filter.value] || [])]
115
+ } else if (filter.type === 'range') {
116
+ workingValues[filter.value] = { ...(selected.value[filter.value] || { min: '', max: '' }) }
117
+ } else if (filter.type === 'date') {
118
+ workingValues[filter.value] = selected.value[filter.value] || null
119
+ } else {
120
+ workingValues[filter.value] = selected.value[filter.value] || null
121
+ }
122
+ }
123
+ })
124
+ }, { immediate: true, deep: true })
125
+
126
+ // Sync selected to workingValues
127
+ watch(selected, (newValue) => {
128
+ Object.keys(newValue).forEach(key => {
129
+ const filter = props.filters.find(f => f.value === key)
130
+ if (filter) {
131
+ if (filter.type === 'checkbox') {
132
+ workingValues[key] = [...(newValue[key] || [])]
133
+ } else if (filter.type === 'range') {
134
+ workingValues[key] = { ...(newValue[key] || { min: '', max: '' }) }
135
+ } else {
136
+ workingValues[key] = newValue[key]
137
+ }
138
+ }
139
+ })
140
+ }, { deep: true })
141
+
142
+ const handleApply = (filterValue) => {
143
+ if (props.immediate) {
144
+ const updated = { ...selected.value }
145
+ updated[filterValue] = workingValues[filterValue]
146
+ selected.value = updated
147
+ }
148
+ }
149
+
150
+ const applyFilters = () => {
151
+ const updated = {}
152
+ Object.keys(workingValues).forEach(key => {
153
+ updated[key] = workingValues[key]
154
+ })
155
+ selected.value = updated
156
+ }
157
+
158
+ const resetFilters = () => {
159
+ props.filters.forEach(filter => {
160
+ if (filter.type === 'checkbox') {
161
+ workingValues[filter.value] = []
162
+ } else if (filter.type === 'range') {
163
+ workingValues[filter.value] = { min: '', max: '' }
164
+ } else if (filter.type === 'date') {
165
+ workingValues[filter.value] = null
166
+ } else {
167
+ workingValues[filter.value] = null
168
+ }
169
+
170
+ // Удаляем ключ из selected
171
+ delete selected.value[filter.value]
172
+ })
173
+ }
174
+ </script>
175
+
176
+ <style scoped>
177
+ </style>
@@ -79,6 +79,8 @@ export function renderAndMountApp({ createApp, hooks = {} }) {
79
79
  }
80
80
 
81
81
 
82
+
83
+
82
84
  if (initialState) {
83
85
  console.log('[AUTH COOKIE DEBUG] Browser initialState.auth:', initialState.auth);
84
86
  console.log('[AUTH COOKIE DEBUG] Has token?', !!initialState?.auth?.access?.token);
@@ -89,6 +91,7 @@ export function renderAndMountApp({ createApp, hooks = {} }) {
89
91
 
90
92
  if (initialState?.auth?.access?.token) {
91
93
  console.log('[AUTH COOKIE DEBUG] Setting auth token from initialState');
94
+
92
95
  setAuthToken(initialState.auth.access.token);
93
96
  } else if (initialState?.auth && !initialState.auth.access?.status) {
94
97
  // Если SSR сбросил auth (из-за ошибки), удаляем куку в браузере
@@ -106,6 +109,12 @@ export function renderAndMountApp({ createApp, hooks = {} }) {
106
109
  }
107
110
  }
108
111
 
112
+ const savedPosition = localStorage.getItem('position');
113
+
114
+ if (savedPosition) {
115
+ store.core.state.position = JSON.parse(savedPosition);
116
+ }
117
+
109
118
  // app.config.globalProperties.$i18n.locale = router.currentRoute.value.params.locale
110
119
  // app.config.globalProperties.$i18n.locale = router.currentRoute.value.params.locale
111
120
  // If user browser locae supported then change locale
@@ -171,6 +180,9 @@ export async function render({ url, cookies, ssrContext, createApp}) {
171
180
  }
172
181
  }
173
182
 
183
+
184
+
185
+
174
186
  if (user) {
175
187
  // [LOADING 27] SSR auth initialization
176
188
  performance.mark('loading-27-start');
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <section id="howtobuy">
3
- <h2 class="w-100 w-max-50r mn-b-small" v-html="t('title')"/>
3
+ <h2 class="w-100 w-max-50r mn-l-auto mn-r-auto mn-b-small" v-html="t('title')"/>
4
4
 
5
5
  <div class="cols-3 mobile:cols-1 gap-thin">
6
6
  <div
@@ -0,0 +1,123 @@
1
+ import Cache from '@martyrs/src/modules/core/controllers/classes/core.cache.js';
2
+ import queryProcessorCore from '@martyrs/src/modules/core/controllers/utils/queryProcessor.js';
3
+ import { getLookupStages } from '@martyrs/src/modules/organizations/controllers/utils/queryProcessorOrganizations.js';
4
+ import lookupConfigs from './utils/lookupConfigs.js';
5
+ import {
6
+ getBasicMatchConditions,
7
+ getPriceConditions,
8
+ getCategoryConditions,
9
+ getContainConditions,
10
+ getSpotsLocationStages,
11
+ } from './utils/queryProcessorMarketplace.js';
12
+
13
+ const controllerFactory = db => {
14
+ const Spot = db.spot;
15
+
16
+ const cache = new Cache({ ttlSeconds: 60 * 5 });
17
+
18
+ const readCatalog = async (req, res) => {
19
+ console.log('marketplace catalog query', req.query);
20
+
21
+ try {
22
+ const cacheKey = JSON.stringify(req.query);
23
+
24
+ let cachedResult = await cache.get(cacheKey);
25
+ if (cachedResult) {
26
+ return res.status(200).send(cachedResult);
27
+ }
28
+
29
+ const matchConditions = getBasicMatchConditions(req.query);
30
+
31
+ const stages = [
32
+ // Базовые фильтры spots (delivery, payment)
33
+ ...(matchConditions.length > 0 ? [{ $match: { $and: matchConditions } }] : []),
34
+
35
+ // Геопоиск ПЕРВЫМ (если есть location)
36
+ ...(req.query.location || req.query.city || req.query.state || req.query.country
37
+ ? (await getSpotsLocationStages(req.query)).stages
38
+ : [{ $addFields: { distance: null } }]),
39
+
40
+ // Lookups (без availability пока)
41
+ ...getLookupStages(['products', 'organizations'], lookupConfigs),
42
+
43
+ // Фильтр по наличию products
44
+ ...getContainConditions(['products', 'organizations']),
45
+
46
+ // Фильтр по ценам
47
+ ...getPriceConditions(req.query.priceMin, req.query.priceMax),
48
+
49
+ // Фильтр по категориям
50
+ ...getCategoryConditions(req.query.categories),
51
+
52
+ // Group по organization
53
+ {
54
+ $group: {
55
+ _id: { $arrayElemAt: ['$organizations._id', 0] },
56
+ profile: { $first: { $arrayElemAt: ['$organizations.profile', 0] } },
57
+ rating: { $first: { $arrayElemAt: ['$organizations.rating', 0] } },
58
+ official: { $first: { $arrayElemAt: ['$organizations.official', 0] } },
59
+ views: { $first: { $arrayElemAt: ['$organizations.views', 0] } },
60
+ spots: {
61
+ $push: {
62
+ _id: '$_id',
63
+ name: '$profile.name',
64
+ address: '$address',
65
+ location: '$location',
66
+ distance: '$distance',
67
+ delivery: '$delivery',
68
+ payment: '$payment',
69
+ },
70
+ },
71
+ products: { $first: '$products' },
72
+ distance: { $min: '$distance' },
73
+ },
74
+ },
75
+
76
+ // Добавляем numberOfProducts
77
+ {
78
+ $addFields: {
79
+ numberOfProducts: { $size: { $ifNull: ['$products', []] } },
80
+ },
81
+ },
82
+
83
+ // Финальная структура
84
+ {
85
+ $project: {
86
+ _id: 1,
87
+ profile: 1,
88
+ rating: 1,
89
+ official: 1,
90
+ views: 1,
91
+ spots: 1,
92
+ products: 1,
93
+ distance: 1,
94
+ numberOfProducts: 1,
95
+ },
96
+ },
97
+
98
+ // Сортировка
99
+ ...queryProcessorCore.getSortingOptions(req.query.sortParam || 'distance', req.query.sortOrder),
100
+
101
+ // Пагинация
102
+ ...queryProcessorCore.getPaginationOptions(req.query.skip, req.query.limit),
103
+ ].filter(Boolean);
104
+
105
+ console.log('Marketplace pipeline:', JSON.stringify(stages, null, 2));
106
+
107
+ const catalog = await Spot.aggregate(stages);
108
+
109
+ await cache.setWithTags(cacheKey, catalog, ['marketplace_catalog']);
110
+
111
+ res.status(200).send(catalog);
112
+ } catch (err) {
113
+ console.error('Marketplace catalog error:', err);
114
+ res.status(500).send({ message: err.message });
115
+ }
116
+ };
117
+
118
+ return {
119
+ readCatalog,
120
+ };
121
+ };
122
+
123
+ export default controllerFactory;
@@ -0,0 +1,130 @@
1
+ const lookupConfigs = {
2
+ availability: {
3
+ lookup: {
4
+ from: 'stockavailabilities',
5
+ localField: '_id',
6
+ foreignField: 'storage',
7
+ pipeline: [
8
+ {
9
+ $match: {
10
+ $expr: { $gt: ['$available', 0] },
11
+ },
12
+ },
13
+ {
14
+ $project: {
15
+ _id: 1,
16
+ product: 1,
17
+ variant: 1,
18
+ available: 1,
19
+ quantity: 1,
20
+ },
21
+ },
22
+ ],
23
+ as: 'availability',
24
+ },
25
+ },
26
+ variants: {
27
+ lookup: {
28
+ from: 'variants',
29
+ let: { variantIds: '$availability.variant' },
30
+ pipeline: [
31
+ {
32
+ $match: {
33
+ $expr: {
34
+ $in: ['$_id', '$$variantIds'],
35
+ },
36
+ status: 'published',
37
+ },
38
+ },
39
+ {
40
+ $project: {
41
+ _id: 1,
42
+ product: 1,
43
+ name: 1,
44
+ price: 1,
45
+ unit: 1,
46
+ images: 1,
47
+ sku: 1,
48
+ },
49
+ },
50
+ ],
51
+ as: 'variants',
52
+ },
53
+ },
54
+ products: {
55
+ lookup: {
56
+ from: 'products',
57
+ localField: 'organization',
58
+ foreignField: 'owner.target',
59
+ pipeline: [
60
+ {
61
+ $match: {
62
+ status: 'published',
63
+ },
64
+ },
65
+ {
66
+ $lookup: {
67
+ from: 'variants',
68
+ localField: '_id',
69
+ foreignField: 'product',
70
+ pipeline: [
71
+ {
72
+ $project: {
73
+ _id: 1,
74
+ name: 1,
75
+ price: 1,
76
+ unit: 1,
77
+ images: 1,
78
+ sku: 1,
79
+ },
80
+ },
81
+ ],
82
+ as: 'variants',
83
+ },
84
+ },
85
+ {
86
+ $project: {
87
+ _id: 1,
88
+ name: 1,
89
+ description: 1,
90
+ images: 1,
91
+ category: 1,
92
+ 'owner.target': 1,
93
+ 'owner.type': 1,
94
+ variants: 1,
95
+ },
96
+ },
97
+ ],
98
+ as: 'products',
99
+ },
100
+ },
101
+ organizations: {
102
+ lookup: {
103
+ from: 'organizations',
104
+ let: { orgIds: '$products.owner.target' },
105
+ pipeline: [
106
+ {
107
+ $match: {
108
+ $expr: {
109
+ $in: ['$_id', '$$orgIds'],
110
+ },
111
+ },
112
+ },
113
+ {
114
+ $project: {
115
+ _id: 1,
116
+ 'profile.name': 1,
117
+ 'profile.photo': 1,
118
+ 'profile.description': 1,
119
+ 'profile.tags': 1,
120
+ rating: 1,
121
+ official: 1,
122
+ },
123
+ },
124
+ ],
125
+ as: 'organizations',
126
+ },
127
+ },
128
+ };
129
+
130
+ export default lookupConfigs;
@@ -0,0 +1,211 @@
1
+ import { Types } from 'mongoose';
2
+ import * as googleMapsServicesJs from '@googlemaps/google-maps-services-js';
3
+
4
+ const ObjectId = Types.ObjectId;
5
+ const { Client } = googleMapsServicesJs;
6
+ const client = new Client({});
7
+
8
+ /**
9
+ * Get basic match conditions for spots (delivery, payment)
10
+ */
11
+ const getBasicMatchConditions = query => {
12
+ const conditions = [];
13
+
14
+ if (query.delivery) {
15
+ // Нормализуем в массив и фильтруем пустые значения
16
+ let deliveryMethods = Array.isArray(query.delivery)
17
+ ? query.delivery
18
+ : typeof query.delivery === 'string'
19
+ ? query.delivery.split(',')
20
+ : [];
21
+
22
+ deliveryMethods = deliveryMethods.filter(Boolean).map(m => m.trim());
23
+
24
+ if (deliveryMethods.length > 0) {
25
+ // $in = spots которые поддерживают ХОТЯ БЫ ОДИН метод
26
+ conditions.push({ delivery: { $in: deliveryMethods } });
27
+ }
28
+ }
29
+
30
+ if (query.payment) {
31
+ // Нормализуем в массив и фильтруем пустые значения
32
+ let paymentMethods = Array.isArray(query.payment)
33
+ ? query.payment
34
+ : typeof query.payment === 'string'
35
+ ? query.payment.split(',')
36
+ : [];
37
+
38
+ paymentMethods = paymentMethods.filter(Boolean).map(m => m.trim());
39
+
40
+ if (paymentMethods.length > 0) {
41
+ // $in = spots которые поддерживают ХОТЯ БЫ ОДИН метод
42
+ conditions.push({ payment: { $in: paymentMethods } });
43
+ }
44
+ }
45
+
46
+ return conditions;
47
+ };
48
+
49
+ /**
50
+ * Get price filter conditions for variants
51
+ */
52
+ const getPriceConditions = (priceMin, priceMax) => {
53
+ if (!priceMin && !priceMax) return [];
54
+
55
+ const conditions = {};
56
+
57
+ if (priceMin !== undefined && priceMin !== null && priceMin !== '') {
58
+ conditions['products.variants.price'] = { $gte: parseFloat(priceMin) };
59
+ }
60
+
61
+ if (priceMax !== undefined && priceMax !== null && priceMax !== '') {
62
+ if (conditions['products.variants.price']) {
63
+ conditions['products.variants.price'].$lte = parseFloat(priceMax);
64
+ } else {
65
+ conditions['products.variants.price'] = { $lte: parseFloat(priceMax) };
66
+ }
67
+ }
68
+
69
+ return Object.keys(conditions).length > 0 ? [{ $match: conditions }] : [];
70
+ };
71
+
72
+ /**
73
+ * Get category filter conditions for products
74
+ */
75
+ const getCategoryConditions = categories => {
76
+ if (!categories || categories.length === 0) return [];
77
+
78
+ const categoriesArray = Array.isArray(categories) ? categories : categories.split(',');
79
+
80
+ return [
81
+ {
82
+ $match: {
83
+ 'products.category': { $in: categoriesArray.map(id => new ObjectId(id)) },
84
+ },
85
+ },
86
+ ];
87
+ };
88
+
89
+ /**
90
+ * Get contain conditions (spots must have availability, products, etc)
91
+ */
92
+ const getContainConditions = contain => {
93
+ if (!contain) return [];
94
+
95
+ const conditions = contain.map(property => ({
96
+ [property]: { $exists: true, $not: { $size: 0 } },
97
+ }));
98
+
99
+ return conditions.length > 0 ? [{ $match: { $and: conditions } }] : [];
100
+ };
101
+
102
+ /**
103
+ * Геофильтрация для Spots (адаптировано из organizations)
104
+ */
105
+ const hasLocationParams = query => query.location || query.address || query.city || query.state || query.country;
106
+
107
+ const resolveLocation = async query => {
108
+ if (query.location) {
109
+ const parsedLocation = typeof query.location === 'string' ? JSON.parse(query.location) : query.location;
110
+ const coordinates = parsedLocation.lng ? [parsedLocation.lng, parsedLocation.lat] : parsedLocation.coordinates;
111
+ return { coordinates: coordinates.map(coord => parseFloat(coord)) };
112
+ }
113
+ const searchString = [query.address, query.city, query.state, query.country].filter(Boolean).join(', ');
114
+ try {
115
+ const geoResponse = await client.geocode({
116
+ params: {
117
+ address: searchString,
118
+ key: process.env.GOOGLE_MAPS_API_KEY,
119
+ },
120
+ });
121
+ if (!geoResponse.data.results?.length) {
122
+ throw new Error('Unable to geocode the provided location.');
123
+ }
124
+ const { lng, lat } = geoResponse.data.results[0].geometry.location;
125
+ return { coordinates: [lng, lat] };
126
+ } catch (err) {
127
+ throw new Error('Error occurred while geocoding.');
128
+ }
129
+ };
130
+
131
+ const getRadius = query => {
132
+ if (query.locationRadius) return parseFloat(query.locationRadius) / 6378.1;
133
+ if (query.city) return 25 / 6378.1;
134
+ if (query.state) return 50 / 6378.1;
135
+ return null;
136
+ };
137
+
138
+ const getDistanceStages = location => [
139
+ {
140
+ $addFields: {
141
+ distance: {
142
+ $function: {
143
+ body: `function(spotCoords, userCoords, isMiles) {
144
+ function toRad(x) {
145
+ return x * Math.PI / 180;
146
+ }
147
+ var lon1 = spotCoords[0];
148
+ var lat1 = spotCoords[1];
149
+ var lon2 = userCoords[0];
150
+ var lat2 = userCoords[1];
151
+ var R = 6371;
152
+ if (isMiles) R = 3959;
153
+ var x1 = lat2 - lat1;
154
+ var dLat = toRad(x1);
155
+ var x2 = lon2 - lon1;
156
+ var dLon = toRad(x2);
157
+ var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
158
+ Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
159
+ Math.sin(dLon / 2) * Math.sin(dLon / 2);
160
+ var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
161
+ var d = R * c;
162
+ return d;
163
+ }`,
164
+ args: ['$location.coordinates', location.coordinates, false],
165
+ lang: 'js',
166
+ },
167
+ },
168
+ },
169
+ },
170
+ ];
171
+
172
+ const getSpotsLocationStages = async query => {
173
+ if (!hasLocationParams(query)) {
174
+ return { stages: [], userLocation: null };
175
+ }
176
+ const location = await resolveLocation(query);
177
+ const radius = getRadius(query);
178
+ const geoStages = radius
179
+ ? [
180
+ {
181
+ $match: {
182
+ 'location.coordinates': {
183
+ $geoWithin: {
184
+ $centerSphere: [[location.coordinates[0], location.coordinates[1]], radius],
185
+ },
186
+ },
187
+ },
188
+ },
189
+ ]
190
+ : [];
191
+ return {
192
+ stages: [...geoStages, ...getDistanceStages(location)],
193
+ userLocation: location,
194
+ };
195
+ };
196
+
197
+ export {
198
+ getBasicMatchConditions,
199
+ getPriceConditions,
200
+ getCategoryConditions,
201
+ getContainConditions,
202
+ getSpotsLocationStages,
203
+ };
204
+
205
+ export default {
206
+ getBasicMatchConditions,
207
+ getPriceConditions,
208
+ getCategoryConditions,
209
+ getContainConditions,
210
+ getSpotsLocationStages,
211
+ };