@necrolab/dashboard 0.4.220 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/.prettierrc +27 -1
  2. package/.vscode/extensions.json +1 -1
  3. package/README.md +64 -2
  4. package/artwork/image.png +0 -0
  5. package/backend/api.js +26 -24
  6. package/backend/auth.js +2 -2
  7. package/backend/batching.js +1 -1
  8. package/backend/endpoints.js +8 -11
  9. package/backend/index.js +2 -2
  10. package/backend/mock-data.js +27 -36
  11. package/backend/mock-src/classes/logger.js +5 -7
  12. package/backend/mock-src/classes/utils.js +3 -2
  13. package/backend/mock-src/ticketmaster.js +4 -4
  14. package/backend/validator.js +2 -2
  15. package/config/configs.json +0 -1
  16. package/dev-server.js +134 -0
  17. package/exit +209 -0
  18. package/index.html +78 -8
  19. package/index.js +1 -1
  20. package/jsconfig.json +16 -0
  21. package/package.json +39 -25
  22. package/postcss.config.js +1 -1
  23. package/postinstall.js +124 -20
  24. package/public/android-chrome-192x192.png +0 -0
  25. package/public/android-chrome-512x512.png +0 -0
  26. package/public/apple-touch-icon.png +0 -0
  27. package/public/favicon-16x16.png +0 -0
  28. package/public/favicon-32x32.png +0 -0
  29. package/public/favicon.ico +0 -0
  30. package/public/img/logo_trans.png +0 -0
  31. package/public/img/necro_logo.png +0 -0
  32. package/public/manifest.json +16 -10
  33. package/run +176 -9
  34. package/src/App.vue +498 -85
  35. package/src/assets/css/base/reset.scss +43 -0
  36. package/src/assets/css/base/scroll.scss +114 -0
  37. package/src/assets/css/base/typography.scss +37 -0
  38. package/src/assets/css/components/buttons.scss +216 -0
  39. package/src/assets/css/components/forms.scss +221 -0
  40. package/src/assets/css/components/modals.scss +13 -0
  41. package/src/assets/css/components/tables.scss +27 -0
  42. package/src/assets/css/components/toasts.scss +100 -0
  43. package/src/assets/css/main.scss +201 -122
  44. package/src/assets/img/background.svg +2 -2
  45. package/src/assets/img/background.svg.backup +11 -0
  46. package/src/assets/img/logo_trans.png +0 -0
  47. package/src/components/Auth/LoginForm.vue +62 -11
  48. package/src/components/Editors/Account/Account.vue +116 -40
  49. package/src/components/Editors/Account/AccountCreator.vue +88 -39
  50. package/src/components/Editors/Account/AccountView.vue +102 -34
  51. package/src/components/Editors/Account/CreateAccount.vue +80 -32
  52. package/src/components/Editors/Profile/CreateProfile.vue +269 -83
  53. package/src/components/Editors/Profile/Profile.vue +132 -47
  54. package/src/components/Editors/Profile/ProfileCountryChooser.vue +82 -20
  55. package/src/components/Editors/Profile/ProfileView.vue +89 -32
  56. package/src/components/Editors/TagLabel.vue +67 -6
  57. package/src/components/Editors/TagToggle.vue +7 -2
  58. package/src/components/Filter/Filter.vue +288 -71
  59. package/src/components/Filter/FilterPreview.vue +202 -31
  60. package/src/components/Filter/PriceSortToggle.vue +76 -6
  61. package/src/components/Table/Header.vue +1 -1
  62. package/src/components/Table/Row.vue +1 -1
  63. package/src/components/Table/Table.vue +19 -2
  64. package/src/components/Tasks/CheckStock.vue +6 -8
  65. package/src/components/Tasks/Controls/DesktopControls.vue +27 -17
  66. package/src/components/Tasks/Controls/MobileControls.vue +8 -45
  67. package/src/components/Tasks/CreateTaskAXS.vue +80 -72
  68. package/src/components/Tasks/CreateTaskTM.vue +95 -141
  69. package/src/components/Tasks/MassEdit.vue +4 -6
  70. package/src/components/Tasks/QuickSettings.vue +199 -30
  71. package/src/components/Tasks/ScrapeVenue.vue +5 -6
  72. package/src/components/Tasks/Stats.vue +50 -24
  73. package/src/components/Tasks/Task.vue +384 -179
  74. package/src/components/Tasks/TaskLabel.vue +2 -2
  75. package/src/components/Tasks/TaskView.vue +136 -48
  76. package/src/components/Tasks/Utilities.vue +25 -10
  77. package/src/components/Tasks/ViewTask.vue +321 -0
  78. package/src/components/icons/Bag.vue +1 -1
  79. package/src/components/icons/Check.vue +5 -0
  80. package/src/components/icons/Close.vue +21 -0
  81. package/src/components/icons/CloseX.vue +5 -0
  82. package/src/components/icons/Eye.vue +6 -0
  83. package/src/components/icons/Key.vue +21 -0
  84. package/src/components/icons/Loyalty.vue +1 -1
  85. package/src/components/icons/Mail.vue +2 -2
  86. package/src/components/icons/Pencil.vue +21 -0
  87. package/src/components/icons/Play.vue +2 -2
  88. package/src/components/icons/Profile.vue +18 -0
  89. package/src/components/icons/Reload.vue +4 -5
  90. package/src/components/icons/Sandclock.vue +2 -2
  91. package/src/components/icons/Sell.vue +21 -0
  92. package/src/components/icons/Spinner.vue +42 -0
  93. package/src/components/icons/SquareCheck.vue +18 -0
  94. package/src/components/icons/SquareUncheck.vue +18 -0
  95. package/src/components/icons/Stadium.vue +1 -1
  96. package/src/components/icons/Wildcard.vue +18 -0
  97. package/src/components/icons/index.js +26 -1
  98. package/src/components/ui/Modal.vue +107 -13
  99. package/src/components/ui/Navbar.vue +175 -40
  100. package/src/components/ui/ReconnectIndicator.vue +351 -55
  101. package/src/components/ui/Splash.vue +5 -35
  102. package/src/components/ui/controls/CountryChooser.vue +200 -62
  103. package/src/components/ui/controls/atomic/Checkbox.vue +119 -10
  104. package/src/components/ui/controls/atomic/Dropdown.vue +216 -39
  105. package/src/components/ui/controls/atomic/LoadingButton.vue +45 -0
  106. package/src/components/ui/controls/atomic/MultiDropdown.vue +300 -37
  107. package/src/components/ui/controls/atomic/Switch.vue +53 -25
  108. package/src/composables/useClickOutside.js +21 -0
  109. package/src/composables/useDropdownPosition.js +174 -0
  110. package/src/libs/Filter.js +60 -24
  111. package/src/registerServiceWorker.js +1 -1
  112. package/src/stores/connection.js +4 -4
  113. package/src/stores/sampleData.js +172 -199
  114. package/src/stores/ui.js +55 -20
  115. package/src/stores/utils.js +30 -4
  116. package/src/types/index.js +41 -0
  117. package/src/utils/debug.js +1 -0
  118. package/src/views/Accounts.vue +116 -50
  119. package/src/views/Console.vue +394 -79
  120. package/src/views/Editor.vue +1176 -123
  121. package/src/views/FilterBuilder.vue +528 -250
  122. package/src/views/Login.vue +76 -14
  123. package/src/views/Profiles.vue +119 -34
  124. package/src/views/Tasks.vue +266 -98
  125. package/static/offline.html +192 -50
  126. package/switch-branch.sh +41 -0
  127. package/tailwind.config.js +119 -27
  128. package/vite.config.js +73 -16
  129. package/workbox-config.cjs +63 -0
  130. package/ICONS.md +0 -21
  131. package/public/img/background.svg +0 -14
  132. package/public/img/logo.png +0 -0
  133. package/public/img/logo_icon.png +0 -0
  134. package/public/img/logo_icon_2.png +0 -0
  135. package/src/assets/css/_input.scss +0 -143
  136. package/src/assets/img/logo.png +0 -0
  137. package/src/assets/img/logo_icon.png +0 -0
  138. package/src/assets/img/logo_icon_2.png +0 -0
  139. package/vue.config.js +0 -32
  140. package/workbox-config.js +0 -7
@@ -1,105 +1,238 @@
1
1
  <template>
2
- <div>
3
- <div class="flex gap-5 items-center pt-5 pb-2">
4
- <!-- Heading -->
5
- <GearIcon class="w-5 cursor-pointer" @click="ui.toggleModal('quick-settings')" />
6
- <h4 class="text-white text-base font-bold">
7
- Tasks
8
- <span class="text-light-300 pl-1">{{ taskCount }}</span>
9
- </h4>
10
- <ul class="mobile-icons">
11
- <li>
12
- <button
13
- class="text-sm"
14
- :disabled="ui.disabledButtons['add-tasks']"
15
- @click="ui.toggleModal('create-task')"
16
- >
17
- <span class="mb-0.5">+</span>
18
- </button>
19
- </li>
20
- <li>
21
- <button @click="ui.deleteTasks()">
22
- <TrashIcon class="h-3.5 w-3.5" />
23
- </button>
24
- </li>
25
- </ul>
26
- </div>
2
+ <div class="tasks-page">
3
+ <div class="flex items-center justify-between pb-2" style="padding-top: 1.5rem">
4
+ <div class="flex items-center justify-center gap-4">
5
+ <GearIcon
6
+ class="w-5 cursor-pointer smooth-hover"
7
+ @click="ui.toggleModal('quick-settings')"
8
+ />
9
+ <h4 class="text-base font-semibold text-light-300">
10
+ Tasks
11
+ <span class="text-sm font-medium text-light-400 pl-1">{{ taskCount }}</span>
12
+ </h4>
13
+ </div>
14
+ <ul class="mobile-icons mobile-header-controls">
15
+ <li>
16
+ <button @click="ui.startTasks()"><PlayIcon class="w-4 h-4" /></button>
17
+ </li>
18
+ <li>
19
+ <button @click="ui.stopTasks()"><PauseIcon class="w-4 h-4" /></button>
20
+ </li>
21
+ <li>
22
+ <button
23
+ class="text-sm"
24
+ :disabled="ui.disabledButtons['add-tasks']"
25
+ @click="ui.toggleModal('create-task')"
26
+ >
27
+ <PlusIcon class="w-4 h-4" />
28
+ </button>
29
+ </li>
30
+ <li>
31
+ <button @click="ui.deleteTasks()"><TrashIcon class="h-3.5 w-3.5" /></button>
32
+ </li>
33
+ </ul>
34
+ </div>
27
35
 
28
- <Stats />
29
-
30
- <!-- Controls -->
31
- <div class="controls-wrapper mb-6 sm:ml-0 md:ml-0.5 lg:ml-0 ml-0">
32
- <DesktopControls
33
- class="hidden lg:flex"
34
- @stopAll="ui.stopTasks()"
35
- @startAll="ui.startTasks()"
36
- @expand="ui.expandTasks()"
37
- @fold="ui.foldTasks()"
38
- @deleteAll="ui.deleteTasks()"
39
- />
40
- <MobileControls
41
- class="flex lg:hidden"
42
- @stopAll="ui.stopTasks()"
43
- @startAll="ui.startTasks()"
44
- @deleteAll="ui.deleteTasks()"
45
- @expand="ui.expandTasks()"
46
- @fold="ui.foldTasks()"
36
+ <div class="controls-wrapper">
37
+ <div class="controls-wrapper lg:mb-3">
38
+ <DesktopControls
39
+ class="desktop-controls-hide"
40
+ @stopAll="ui.stopTasks()"
41
+ @startAll="ui.startTasks()"
42
+ @deleteAll="ui.deleteTasks()"
43
+ />
44
+ </div>
45
+
46
+ <!-- Mobile: Stats + Filter on same row -->
47
+ <div class="flex md:hidden items-center justify-between gap-2 mb-1">
48
+ <Stats class="stats-component flex-1" />
49
+ <PriceSortToggle
50
+ class="min-w-20 max-w-28 flex-shrink-0 h-8"
51
+ :options="['All', 'Checkout']"
52
+ :darker="true"
53
+ :current="ui.taskFilter"
54
+ @change="(e) => ui.setTaskFilter(e)"
55
+ />
56
+ </div>
57
+
58
+ <!-- Desktop: Event Dropdown + Search + Filter + Stats on ONE row -->
59
+ <div class="hidden md:flex items-center gap-2 lg:mb-2 mb-1">
60
+ <div
61
+ v-if="uniqEventIds.length > 1"
62
+ class="w-52 flex-shrink-0"
63
+ >
64
+ <Dropdown
65
+ :onClick="(f) => ui.setCurrentEvent(f)"
66
+ default="All events"
67
+ :chosen="ui.currentEvent"
68
+ :options="uniqEventIds"
69
+ :allowDefault="true"
70
+ class="input-default w-full hover:bg-dark-400 event-dropdown"
71
+ rightAmount="right-2"
72
+ />
73
+ </div>
74
+ <div class="w-52 flex-shrink-0">
75
+ <div class="input-default flex items-center">
76
+ <input
77
+ v-model="taskSearchQuery"
78
+ type="text"
79
+ placeholder="Search tasks..."
80
+ class="h-full w-full bg-transparent text-sm text-white outline-none"
47
81
  />
82
+ <span v-if="taskSearchQuery" class="ml-2 text-xs text-light-500">{{ filteredTaskCount }}</span>
83
+ </div>
48
84
  </div>
49
- <div class="flex items-center gap-2 mb-2">
50
- <div
51
- v-if="uniqEventIds.length > 1"
52
- class="w-full min-w-32 max-w-72 md:max-w-48 flex rounded input-default hover:bg-dark-400"
53
- style="height: 2.5rem !important"
54
- >
55
- <Dropdown
56
- :onClick="(f) => ui.setCurrentEvent(f)"
57
- default="All events"
58
- :chosen="ui.currentEvent"
59
- :options="uniqEventIds"
60
- :allowDefault="true"
61
- class="w-56"
62
- rightAmount="right-2"
63
- />
64
- </div>
65
- <div>
66
- <PriceSortToggle
67
- class="h-10 hover:bg-dark-400 border-dark-550 border-2 min-w-24"
68
- :options="['All', 'Checkout']"
69
- :darker="true"
70
- :current="ui.taskFilter"
71
- @change="(e) => ui.setTaskFilter(e)"
72
- />
73
- </div>
85
+ <PriceSortToggle
86
+ class="min-w-24 max-w-28 flex-shrink-0"
87
+ :options="['All', 'Checkout']"
88
+ :darker="true"
89
+ :current="ui.taskFilter"
90
+ @change="(e) => ui.setTaskFilter(e)"
91
+ />
92
+ <Stats class="stats-component ml-auto" />
93
+ </div>
94
+
95
+ <!-- Mobile: Event Dropdown + Search stacked -->
96
+ <div class="flex md:hidden flex-col gap-2 mb-1">
97
+ <div
98
+ v-if="uniqEventIds.length > 1"
99
+ class="w-full"
100
+ >
101
+ <Dropdown
102
+ :onClick="(f) => ui.setCurrentEvent(f)"
103
+ default="All events"
104
+ :chosen="ui.currentEvent"
105
+ :options="uniqEventIds"
106
+ :allowDefault="true"
107
+ class="input-default w-full hover:bg-dark-400 event-dropdown"
108
+ rightAmount="right-2"
109
+ />
110
+ </div>
111
+ <div class="w-full">
112
+ <div class="input-default flex items-center">
113
+ <input
114
+ v-model="taskSearchQuery"
115
+ type="text"
116
+ placeholder="Search tasks..."
117
+ class="h-full w-full bg-transparent text-sm text-white outline-none"
118
+ />
119
+ <span v-if="taskSearchQuery" class="ml-2 text-xs text-light-500">{{ filteredTaskCount }}</span>
120
+ </div>
74
121
  </div>
122
+ </div>
75
123
 
76
- <!-- Tasks (Table) -->
77
- <TaskView class="mb-6" :tasks="ui.tasks" />
78
- <!-- Utilities -->
79
- <Utilities />
80
- <!-- Modal -->
81
- <transition-group name="fade" mode="out-in">
82
- <CreateTaskTM v-if="ui.currentModule == 'TM' && activeModal === 'create-task'" @new="ui.addNewTask" />
83
- <CreateTaskAXS v-if="ui.currentModule == 'AXS' && activeModal === 'create-task'" @new="ui.addNewTask" />
84
-
85
- <!-- TODO: make the same changes as above -->
86
- <CheckStock v-if="activeModal === 'check-stock'" />
87
- <ScrapeVenue v-if="activeModal === 'scrape-venue'" />
88
- <MassEditPresaleCode v-if="activeModal === 'mass-edit-presale-code'" />
89
- <QuickSettings v-if="activeModal === 'quick-settings'" />
90
- </transition-group>
124
+ <TaskView class="lg:mb-3 mb-2" :tasks="ui.tasks" :searchQuery="taskSearchQuery" />
125
+
126
+ <Utilities class="utilities-section" />
91
127
  </div>
128
+
129
+ <transition-group name="fade">
130
+ <CreateTaskTM
131
+ v-if="ui.currentModule == 'TM' && activeModal === 'create-task'"
132
+ @new="ui.addNewTask"
133
+ />
134
+ <CreateTaskAXS
135
+ v-if="ui.currentModule == 'AXS' && activeModal === 'create-task'"
136
+ @new="ui.addNewTask"
137
+ />
138
+ <CheckStock v-if="activeModal === 'check-stock'" />
139
+ <ScrapeVenue v-if="activeModal === 'scrape-venue'" />
140
+ <MassEditPresaleCode v-if="activeModal === 'mass-edit-presale-code'" />
141
+ <QuickSettings v-if="activeModal === 'quick-settings'" />
142
+ </transition-group>
143
+ </div>
92
144
  </template>
93
145
  <style lang="scss" scoped>
94
146
  .custom-dropdown-content {
95
- top: 2.6rem !important;
96
- left: -13px;
97
- @apply border border-light-300;
147
+ top: 2.6rem !important;
148
+ left: -13px;
149
+ @apply border border-dark-650;
150
+ }
151
+
152
+ /* ==========================================================================
153
+ TASKS PAGE RESPONSIVE LAYOUT - MOBILE FIRST
154
+ ========================================================================== */
155
+
156
+ /* Default mobile layout */
157
+ .desktop-controls-hide {
158
+ display: none;
159
+ }
160
+
161
+ .mobile-header-controls {
162
+ display: flex;
163
+ }
164
+
165
+ /* Event dropdown base styling */
166
+ .event-dropdown {
167
+ min-width: 0;
168
+ /* Match PriceSortToggle height instead of input-default */
169
+ height: 40px !important;
170
+ }
171
+
172
+ .event-dropdown .dropdown-value {
173
+ max-width: 100%;
174
+ overflow: hidden;
175
+ text-overflow: ellipsis;
176
+ white-space: nowrap;
177
+ }
178
+
179
+ /* Small mobile screens (portrait) */
180
+ @media (max-width: 480px) and (orientation: portrait) {
181
+ .event-dropdown {
182
+ height: 40px !important; /* Match PriceSortToggle height exactly */
183
+ }
184
+
185
+ .event-dropdown .dropdown-value {
186
+ max-width: calc(100vw - 140px);
187
+ font-size: 0.875rem;
188
+ }
189
+
190
+ .event-dropdown .dropdown-display {
191
+ padding-right: 2rem;
192
+ }
193
+ }
194
+
195
+ /* Extra small screens */
196
+ @media (max-width: 375px) and (orientation: portrait) {
197
+ .event-dropdown {
198
+ height: 40px !important; /* Maintain 40px height to match PriceSortToggle */
199
+ }
200
+
201
+ .event-dropdown .dropdown-value {
202
+ max-width: calc(100vw - 120px);
203
+ font-size: 0.8rem;
204
+ }
205
+ }
206
+
207
+ /* Mobile landscape - hide non-essential elements */
208
+ @media (max-height: 500px) and (orientation: landscape) {
209
+ .stats-component,
210
+ .utilities-section,
211
+ .filter-controls {
212
+ display: none;
213
+ }
214
+
215
+ .pb-2 {
216
+ padding-top: 1rem !important;
217
+ padding-bottom: 0.25rem;
218
+ margin-bottom: 0.25rem;
219
+ }
220
+ }
221
+
222
+ /* Tablet and small desktop - show desktop controls */
223
+ @media (min-width: 650px) {
224
+ .desktop-controls-hide {
225
+ display: flex;
226
+ }
227
+
228
+ .mobile-header-controls {
229
+ display: none;
230
+ }
98
231
  }
99
232
  </style>
100
233
  <script setup>
101
- import { computed } from "vue";
102
- import { MobileControls, DesktopControls } from "@/components/Tasks/Controls";
234
+ import { computed, onMounted, ref } from "vue";
235
+ import { DesktopControls } from "@/components/Tasks/Controls";
103
236
  import TaskView from "@/components/Tasks/TaskView.vue";
104
237
  import Utilities from "@/components/Tasks/Utilities.vue";
105
238
  import CreateTaskTM from "@/components/Tasks/CreateTaskTM.vue";
@@ -110,22 +243,57 @@ import MassEditPresaleCode from "@/components/Tasks/MassEdit.vue";
110
243
  import Dropdown from "@/components/ui/controls/atomic/Dropdown.vue";
111
244
  import Stats from "@/components/Tasks/Stats.vue";
112
245
  import { useUIStore } from "@/stores/ui";
113
- import { TrashIcon, GearIcon } from "@/components/icons";
246
+ import { TrashIcon, GearIcon, PlusIcon, PlayIcon, PauseIcon } from "@/components/icons";
114
247
  import QuickSettings from "@/components/Tasks/QuickSettings.vue";
115
248
  import PriceSortToggle from "@/components/Filter/PriceSortToggle.vue";
249
+
116
250
  const ui = useUIStore();
117
251
  const activeModal = computed(() => ui.activeModal);
118
252
  const taskCount = computed(() => Object.keys(ui.getSelectedTasks()).length);
119
253
  ui.refreshQueueStats();
120
254
 
255
+ const taskSearchQuery = ref('');
256
+
257
+ const filteredTaskCount = computed(() => {
258
+ if (!taskSearchQuery.value.trim()) return '';
259
+
260
+ const searchLower = taskSearchQuery.value.toLowerCase().trim();
261
+ let count = 0;
262
+
263
+ Object.values(ui.tasks).forEach(task => {
264
+ if (task.hidden) return;
265
+
266
+ const searchableText = [
267
+ task.eventId,
268
+ task.eventName,
269
+ task.eventVenue,
270
+ task.email,
271
+ task.taskId,
272
+ task.status,
273
+ task.profileName,
274
+ task.presaleCode,
275
+ task.reservedTicketsList
276
+ ].filter(Boolean).join(' ').toLowerCase();
277
+
278
+ if (searchableText.includes(searchLower)) count++;
279
+ });
280
+
281
+ return count;
282
+ });
283
+
284
+ // Ensure "All events" is always selected on page load
285
+ onMounted(() => {
286
+ ui.setCurrentEvent("");
287
+ });
288
+
121
289
  const uniqEventIds = computed(() => {
122
- const ids = [
123
- ...new Set(
124
- Object.values(ui.tasks)
125
- .filter((t) => t.siteId === ui.currentCountry.siteId && !t.eventId.includes("@"))
126
- .map((v) => v.eventId)
127
- )
128
- ];
129
- return ids;
290
+ const ids = [
291
+ ...new Set(
292
+ Object.values(ui.tasks)
293
+ .filter((t) => t.siteId === ui.currentCountry.siteId && !t.eventId?.includes("@"))
294
+ .map((v) => `${v.eventName} (${v.eventId})`)
295
+ ),
296
+ ];
297
+ return ids;
130
298
  });
131
299
  </script>