@necrolab/dashboard 0.5.15 → 0.5.17

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 (137) hide show
  1. package/backend/api.js +2 -3
  2. package/eslint.config.js +46 -0
  3. package/index.html +2 -1
  4. package/package.json +5 -2
  5. package/src/App.vue +70 -566
  6. package/src/assets/css/base/mixins.scss +72 -0
  7. package/src/assets/css/base/reset.scss +0 -2
  8. package/src/assets/css/base/scroll.scss +43 -36
  9. package/src/assets/css/base/typography.scss +9 -10
  10. package/src/assets/css/base/variables.scss +43 -0
  11. package/src/assets/css/components/accessibility.scss +37 -0
  12. package/src/assets/css/components/buttons.scss +61 -74
  13. package/src/assets/css/components/forms.scss +31 -32
  14. package/src/assets/css/components/headers.scss +13 -21
  15. package/src/assets/css/components/modals.scss +2 -2
  16. package/src/assets/css/components/search-groups.scss +28 -22
  17. package/src/assets/css/components/tables.scss +5 -7
  18. package/src/assets/css/components/toasts.scss +7 -7
  19. package/src/assets/css/components/utilities.scss +295 -0
  20. package/src/assets/css/main.scss +55 -139
  21. package/src/components/Auth/LoginForm.vue +7 -86
  22. package/src/components/Console/ConsoleToolbar.vue +123 -0
  23. package/src/components/Editors/Account/Account.vue +12 -12
  24. package/src/components/Editors/Account/AccountView.vue +38 -111
  25. package/src/components/Editors/Account/CreateAccount.vue +11 -61
  26. package/src/components/Editors/Account/{AccountCreator.vue → CreateAccountBatch.vue} +28 -59
  27. package/src/components/Editors/AdminFileEditor.vue +179 -0
  28. package/src/components/Editors/Profile/CreateProfile.vue +77 -150
  29. package/src/components/Editors/Profile/Profile.vue +20 -21
  30. package/src/components/Editors/Profile/ProfileCountryChooser.vue +16 -60
  31. package/src/components/Editors/Profile/ProfileView.vue +41 -116
  32. package/src/components/Editors/ProxyFileEditor.vue +86 -0
  33. package/src/components/Editors/TagLabel.vue +16 -55
  34. package/src/components/Editors/TagToggle.vue +20 -8
  35. package/src/components/Filter/Filter.vue +66 -79
  36. package/src/components/Filter/FilterPreview.vue +153 -135
  37. package/src/components/Filter/PriceSortToggle.vue +36 -43
  38. package/src/components/Table/Header.vue +1 -1
  39. package/src/components/Table/Table.vue +45 -51
  40. package/src/components/Tasks/CheckStock.vue +7 -16
  41. package/src/components/Tasks/Controls/DesktopControls.vue +15 -60
  42. package/src/components/Tasks/Controls/MobileControls.vue +5 -20
  43. package/src/components/Tasks/CreateTaskAXS.vue +20 -118
  44. package/src/components/Tasks/CreateTaskTM.vue +33 -189
  45. package/src/components/Tasks/EventDetailRow.vue +21 -0
  46. package/src/components/Tasks/MassEdit.vue +6 -16
  47. package/src/components/Tasks/QuickSettings.vue +140 -216
  48. package/src/components/Tasks/ScrapeVenue.vue +4 -13
  49. package/src/components/Tasks/Stats.vue +20 -39
  50. package/src/components/Tasks/Task.vue +64 -270
  51. package/src/components/Tasks/TaskLabel.vue +9 -3
  52. package/src/components/Tasks/TaskView.vue +45 -64
  53. package/src/components/Tasks/Utilities.vue +10 -44
  54. package/src/components/Tasks/ViewTask.vue +23 -107
  55. package/src/components/icons/Close.vue +2 -8
  56. package/src/components/icons/Gear.vue +8 -8
  57. package/src/components/icons/Hash.vue +5 -0
  58. package/src/components/icons/Key.vue +2 -8
  59. package/src/components/icons/Pencil.vue +2 -8
  60. package/src/components/icons/Profile.vue +2 -8
  61. package/src/components/icons/Sell.vue +2 -8
  62. package/src/components/icons/Spinner.vue +4 -7
  63. package/src/components/icons/Wildcard.vue +2 -8
  64. package/src/components/icons/index.js +3 -5
  65. package/src/components/ui/ActionButtonGroup.vue +113 -52
  66. package/src/components/ui/BalanceIndicator.vue +60 -0
  67. package/src/components/ui/EmptyState.vue +24 -0
  68. package/src/components/ui/EnableDisableToggle.vue +23 -0
  69. package/src/components/ui/FormField.vue +49 -49
  70. package/src/components/ui/IconLabel.vue +23 -0
  71. package/src/components/ui/InfoRow.vue +21 -54
  72. package/src/components/ui/Modal.vue +161 -54
  73. package/src/components/ui/Navbar.vue +63 -44
  74. package/src/components/ui/ReadonlyFieldsSection.vue +31 -0
  75. package/src/components/ui/ReconnectIndicator.vue +111 -124
  76. package/src/components/ui/SectionCard.vue +6 -14
  77. package/src/components/ui/Splash.vue +2 -10
  78. package/src/components/ui/StatusBadge.vue +26 -28
  79. package/src/components/ui/TaskToggle.vue +54 -0
  80. package/src/components/ui/controls/CountryChooser.vue +29 -66
  81. package/src/components/ui/controls/EyeToggle.vue +1 -1
  82. package/src/components/ui/controls/atomic/Checkbox.vue +40 -121
  83. package/src/components/ui/controls/atomic/Dropdown.vue +103 -139
  84. package/src/components/ui/controls/atomic/MultiDropdown.vue +72 -120
  85. package/src/components/ui/controls/atomic/Switch.vue +21 -84
  86. package/src/composables/useCodeEditor.js +117 -0
  87. package/src/composables/useColorMapping.js +15 -0
  88. package/src/composables/useCopyToClipboard.js +1 -1
  89. package/src/composables/useDateFormatting.js +21 -0
  90. package/src/composables/useDeviceDetection.js +14 -0
  91. package/src/composables/useDropdownPosition.js +1 -4
  92. package/src/composables/useDynamicTableHeight.js +31 -0
  93. package/src/composables/useEnableDisable.js +6 -0
  94. package/src/composables/useFilterCSS.js +71 -0
  95. package/src/composables/useFormValidation.js +92 -0
  96. package/src/composables/useGetAllTags.js +9 -0
  97. package/src/composables/useIOSViewportHandling.js +76 -0
  98. package/src/composables/useNotchHandling.js +306 -0
  99. package/src/composables/useRowSelection.js +0 -3
  100. package/src/composables/useTableRender.js +23 -0
  101. package/src/composables/useTicketPricing.js +16 -0
  102. package/src/composables/useWindowDimensions.js +21 -0
  103. package/src/composables/useZoomPrevention.js +96 -0
  104. package/src/constants/tableLayout.js +14 -0
  105. package/src/libs/Filter.js +14 -20
  106. package/src/libs/panzoom.js +1 -5
  107. package/src/libs/utils/array.js +58 -0
  108. package/src/{stores/utils.js → libs/utils/dataGeneration.js} +2 -250
  109. package/src/libs/utils/eventUrl.js +40 -0
  110. package/src/libs/utils/string.js +3 -0
  111. package/src/libs/utils/time.js +20 -0
  112. package/src/libs/utils/validation.js +64 -0
  113. package/src/main.js +0 -2
  114. package/src/stores/connection.js +1 -29
  115. package/src/stores/logger.js +6 -12
  116. package/src/stores/sampleData.js +1 -2
  117. package/src/stores/ui.js +80 -71
  118. package/src/utils/tableHelpers.js +1 -0
  119. package/src/views/Accounts.vue +19 -38
  120. package/src/views/Console.vue +74 -253
  121. package/src/views/Editor.vue +47 -1114
  122. package/src/views/FilterBuilder.vue +190 -461
  123. package/src/views/Login.vue +3 -28
  124. package/src/views/Profiles.vue +17 -32
  125. package/src/views/Tasks.vue +51 -38
  126. package/tailwind.config.js +82 -71
  127. package/workbox-config.cjs +47 -5
  128. package/docs/plans/2026-02-08-tailwind-consolidation.md +0 -2438
  129. package/exit +0 -209
  130. package/run +0 -177
  131. package/src/assets/css/base/color-fallbacks.scss +0 -10
  132. package/src/assets/img/background.svg.backup +0 -11
  133. package/src/components/icons/SquareCheck.vue +0 -18
  134. package/src/components/icons/SquareUncheck.vue +0 -18
  135. package/src/components/ui/controls/atomic/LoadingButton.vue +0 -45
  136. package/switch-branch.sh +0 -41
  137. /package/public/{reconnect-logo.png → img/reconnect-logo.png} +0 -0
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="table-component">
2
+ <div class="table-component relative box-border flex flex-col rounded-lg bg-dark-500 bg-clip-padding overflow-hidden shadow-sm">
3
3
  <Header class="grid-cols-10 gap-2 text-center lg:grid-cols-12">
4
4
  <div class="col-span-1 flex items-center justify-start lg:col-span-2">
5
5
  <Checkbox
@@ -9,50 +9,50 @@
9
9
  :isHeader="true" />
10
10
  <div class="mx-auto hidden items-center lg:flex" @click="ui.toggleSort('eventId')">
11
11
  <EventIcon class="lg:mr-3" />
12
- <h4 class="hidden lg:flex">Event</h4>
12
+ <h4 class="hidden lg:flex text-white">Event</h4>
13
13
  <DownIcon v-if="ui.sortData.sortBy === 'eventId' && !ui.sortData.reversed" class="ml-1" />
14
14
  <UpIcon v-if="ui.sortData.sortBy === 'eventId' && ui.sortData.reversed" class="ml-1" />
15
15
  </div>
16
16
  </div>
17
- <div class="col-span-2 flex items-center justify-center" v-once>
17
+ <div class="col-span-2 flex items-center justify-center lg:col-span-3 xl:col-span-2" v-once>
18
18
  <TicketIcon class="mr-0 lg:mr-3" />
19
- <h4 class="hidden lg:flex">Tickets</h4>
19
+ <h4 class="hidden lg:flex text-white">Tickets</h4>
20
20
  </div>
21
21
  <div
22
- class="col-span-5 flex items-center justify-center md:col-span-4 lg:col-span-5"
22
+ class="col-span-6 flex items-center justify-center md:col-span-5 lg:col-span-4 xl:col-span-5"
23
23
  @click="ui.toggleSort('status')">
24
24
  <StatusIcon class="mr-0 lg:mr-3" />
25
- <h4 class="hidden lg:flex">Status</h4>
25
+ <h4 class="hidden lg:flex text-white">Status</h4>
26
26
  <DownIcon v-if="ui.sortData.sortBy === 'status' && !ui.sortData.reversed" class="ml-1" />
27
27
  <UpIcon v-if="ui.sortData.sortBy === 'status' && ui.sortData.reversed" class="ml-1" />
28
28
  </div>
29
- <div class="col-span-2 flex items-center justify-center lg:col-span-3" v-once>
29
+ <div class="col-span-1 flex items-center justify-end md:col-span-2 md:justify-center lg:col-span-3" v-once>
30
30
  <ClickIcon class="mr-0 lg:mr-3" />
31
- <h4 class="hidden lg:flex">Actions</h4>
31
+ <h4 class="hidden lg:flex text-white">Actions</h4>
32
32
  </div>
33
- <div class="absolute right-5 top-3.5 hidden items-center lg:flex">
34
- <h4 class="text-center text-xs">ID</h4>
33
+ <div class="absolute right-5 top-3.5 hidden items-center xl:flex">
34
+ <h4 class="text-center text-xs text-white">ID</h4>
35
35
  </div>
36
36
  </Header>
37
37
  <div
38
- class="hidden-scrollbars stop-pan flex flex-col divide-y divide-dark-650 overflow-y-auto overflow-x-hidden"
38
+ class="hidden-scrollbars touch-pan-y flex flex-col divide-y divide-dark-650 overflow-y-auto overflow-x-hidden"
39
39
  :style="{ maxHeight: dynamicTableHeight }">
40
- <div v-for="(task, i) in getTasksInOrder()" :key="task.taskId" class="task-row-container">
41
- <Task :task="task" :preferEventName="props.preferEventName" :class="i % 2 == 1 ? 'table-row-even' : 'table-row-odd'" />
40
+ <div v-for="(task, i) in getTasksInOrder()" :key="task.taskId" class="shrink-0 min-h-14.5 md:min-h-17.25 has-[.event-details]:min-h-18.75 mobile-portrait:min-h-12.5 transition-colors duration-150 ease-in-out hover:!bg-dark-550">
41
+ <Task :task="task" :preferEventName="props.preferEventName" :class="getRowClass(i)" />
42
42
  </div>
43
43
  <div
44
44
  v-if="getTasksInOrder().length === 0"
45
- class="empty-state flex flex-col items-center justify-center py-8 text-center">
45
+ class="empty-state flex flex-col items-center justify-center py-8 text-center bg-dark-400 text-light-500 text-sm font-medium">
46
46
  <div
47
47
  v-if="
48
48
  !ui.queueStats.queued && !ui.queueStats.sleeping && ui.queueStats.nextQueuePasses.length === 0
49
49
  ">
50
- <TasksIcon class="mx-auto mb-3 h-12 w-12 text-dark-400 opacity-50" />
50
+ <TasksIcon class="mx-auto empty-state-icon" />
51
51
  <p class="text-sm text-light-400">No tasks yet</p>
52
52
  <p class="mt-1 text-xs text-light-500">Create tasks to get started</p>
53
53
  </div>
54
54
  <div v-else>
55
- <TasksIcon class="mx-auto mb-3 h-12 w-12 text-dark-400 opacity-50" />
55
+ <TasksIcon class="mx-auto empty-state-icon" />
56
56
  <p class="text-sm text-light-400">No tasks match current filters</p>
57
57
  <p class="mt-1 text-xs text-light-500">Adjust filters to see tasks</p>
58
58
  </div>
@@ -60,58 +60,28 @@
60
60
  </div>
61
61
  </div>
62
62
  </template>
63
- <style lang="scss" scoped>
64
- h4 {
65
- @apply text-white;
66
- }
67
-
68
- .stop-pan {
69
- touch-action: pan-y pan-up pan-down;
70
- }
71
-
72
- .task-row-container {
73
- min-height: 69px;
74
- flex-shrink: 0;
75
- transition: background-color 0.15s ease;
76
-
77
- &:hover {
78
- @apply bg-dark-550 !important;
79
- }
80
-
81
- // Increase height when showing eventName to accommodate multi-line display (desktop only)
82
- @media (min-width: 1024px) {
83
- &:has(.event-details) {
84
- min-height: 75px;
85
- }
86
- }
87
-
88
- @media (max-width: 768px) {
89
- min-height: 58px;
90
- }
91
-
92
- @media (max-width: 480px) and (orientation: portrait) {
93
- min-height: 50px;
94
- }
95
- }
96
-
97
- .empty-state {
98
- @apply bg-dark-400;
99
- font-size: 14px;
100
- font-weight: 500;
101
- }
102
- </style>
103
63
  <script setup>
104
64
  import { computed, ref, onMounted, onUnmounted } from "vue";
105
- import { Table, Header } from "@/components/Table";
65
+ import { Header } from "@/components/Table";
106
66
  import { EventIcon, TicketIcon, StatusIcon, ClickIcon, DownIcon, UpIcon, TasksIcon } from "@/components/icons";
107
67
  import Task from "./Task.vue";
108
68
  import Checkbox from "@/components/ui/controls/atomic/Checkbox.vue";
109
69
  import { useUIStore } from "@/stores/ui";
70
+ import { getRowClass } from "@/utils/tableHelpers";
110
71
 
111
72
  const props = defineProps({
112
- tasks: { type: Object },
113
- searchQuery: { type: String, default: "" },
114
- preferEventName: { type: Boolean, default: false }
73
+ tasks: {
74
+ type: Object,
75
+ required: true
76
+ },
77
+ searchQuery: {
78
+ type: String,
79
+ default: ''
80
+ },
81
+ preferEventName: {
82
+ type: Boolean,
83
+ default: false
84
+ }
115
85
  });
116
86
 
117
87
  const shouldTaskShow = (task) => {
@@ -189,8 +159,11 @@ onUnmounted(() => {
189
159
  });
190
160
 
191
161
  const dynamicTableHeight = computed(() => {
162
+ // Detect PWA mode (standalone display)
163
+ const isPWA = window.matchMedia('(display-mode: standalone)').matches;
164
+
192
165
  // Calculate available space for table
193
- const headerHeight = 55; // Header + navbar
166
+ const headerHeight = windowWidth.value >= 1024 ? 80 : 64; // Navbar padding (lg:pt-20 vs pt-16)
194
167
  const titleHeight = 45; // Tasks title and mobile controls
195
168
  const controlsHeight = windowWidth.value >= 650 ? 55 : 0; // Desktop controls
196
169
  // On desktop: stats + filters all in one row (45px)
@@ -203,9 +176,17 @@ const dynamicTableHeight = computed(() => {
203
176
  : ui.queueStats.show
204
177
  ? 130
205
178
  : 90; // Mobile: stats row + stacked filters
206
- const utilitiesHeight = windowWidth.value <= 768 ? 180 : 160; // Increase mobile utilities space to prevent cutoff
207
- const margins =
208
- windowWidth.value >= 1024 ? 20 : windowWidth.value <= 480 && windowHeight.value > windowWidth.value ? 8 : 12;
179
+
180
+ // Reserve more space for UTILS on iPhone PWA to prevent overflow
181
+ const utilitiesHeight = isPWA && windowWidth.value <= 768
182
+ ? 260 // iPhone PWA: extra space for UTILS
183
+ : windowWidth.value > 1024
184
+ ? 200 // Desktop
185
+ : windowWidth.value <= 768
186
+ ? 220 // Mobile browser
187
+ : 180; // Tablet
188
+
189
+ const margins = windowWidth.value >= 1024 ? 30 : windowWidth.value <= 480 && windowHeight.value > windowWidth.value ? 8 : 12;
209
190
 
210
191
  const totalUsedSpace =
211
192
  headerHeight + titleHeight + controlsHeight + filtersAndStatsHeight + utilitiesHeight + margins;
@@ -1,58 +1,24 @@
1
1
  <template>
2
- <div class="utilities-wrapper grid grid-cols-1 gap-3 lg:grid-cols-1" v-if="ui.currentModule == 'TM'">
3
- <div class="lg:justify-self-end">
4
- <h4 class="hidden lg:block text-white opacity-40 uppercase font-medium mb-1">Utils</h4>
5
- <div class="flex gap-3 justify-between lg:justify-start">
6
- <button class="button-default w-44 bg-dark-400 flex items-center justify-center gap-x-2 utility-btn" @click="ui.toggleModal('scrape-venue')">
2
+ <div class="grid grid-cols-1 gap-3 mt-4 mb-6 md:mb-10" v-if="ui.currentModule == 'TM'">
3
+ <div>
4
+ <h4 class="hidden lg:block text-white opacity-40 uppercase font-medium mb-1 text-xs">Utils</h4>
5
+ <div class="flex gap-3 flex-wrap justify-between lg:justify-start">
6
+ <button class="btn-modal w-40 sm:w-44" @click="ui.toggleModal('scrape-venue')">
7
7
  Scrape Venue
8
- <ScrapeIcon />
8
+ <ScrapeIcon class="w-3.5 h-3.5 flex-shrink-0 ml-2" />
9
9
  </button>
10
- <button class="button-default w-44 bg-dark-400 flex items-center justify-center gap-x-2 utility-btn" @click="ui.toggleModal('check-stock')">
10
+ <button class="btn-modal w-40 sm:w-44" @click="ui.toggleModal('check-stock')">
11
11
  Check Stock
12
- <BoxIcon />
12
+ <BoxIcon class="w-3.5 h-3.5 flex-shrink-0 ml-2" />
13
13
  </button>
14
14
  </div>
15
- <h4 class="text-white opacity-40 uppercase font-medium block lg:hidden">Utils</h4>
15
+ <h4 class="text-white opacity-40 uppercase font-medium block lg:hidden text-xs text-center mt-2 px-4">Utils</h4>
16
16
  </div>
17
17
  </div>
18
18
  </template>
19
19
  <script setup>
20
- import { BoxIcon, ScrapeIcon, CameraIcon, GroupIcon } from "@/components/icons";
20
+ import { BoxIcon, ScrapeIcon } from "@/components/icons";
21
21
  import { useUIStore } from "@/stores/ui";
22
22
 
23
23
  const ui = useUIStore();
24
24
  </script>
25
- <style lang="scss" scoped>
26
- .utilities-wrapper {
27
- margin-bottom: 2rem;
28
-
29
- // Add extra margin on mobile to prevent buttons from being cut off
30
- @media (max-width: 768px) {
31
- margin-top: 1rem;
32
- margin-bottom: 2.5rem;
33
- }
34
- }
35
-
36
- .utility-btn {
37
- height: 42px;
38
-
39
- @media (max-width: 768px) {
40
- height: 40px;
41
- font-size: 0.75rem;
42
- }
43
- }
44
-
45
- button {
46
- font-size: 0.75rem;
47
-
48
- svg {
49
- width: 14px;
50
- height: 14px;
51
- flex-shrink: 0;
52
- }
53
- }
54
-
55
- h4 {
56
- font-size: 12px;
57
- }
58
- </style>
@@ -96,10 +96,10 @@
96
96
  label="Password">
97
97
  {{ showPassword ? taskSnapshot.password : "••••••••" }}
98
98
  <template #action>
99
- <button @click.stop="showPassword = !showPassword" class="flex items-center justify-center w-8 h-8 rounded transition-all hover:bg-dark-600">
99
+ <button @click.stop="showPassword = !showPassword" class="flex items-center justify-center square-8 rounded transition-all hover:bg-dark-550">
100
100
  <EyeToggle :visible="showPassword" />
101
101
  </button>
102
- <button @click.stop="copy(taskSnapshot.password, 'Copied password')" class="copy-button flex items-center justify-center w-8 h-8 rounded transition-all hover:bg-dark-600 text-light-500 hover:text-light-300">
102
+ <button @click.stop="copy(taskSnapshot.password, 'Copied password')" class="copy-button flex items-center justify-center square-8 rounded transition-all hover:bg-dark-550 text-light-500 hover:text-light-300">
103
103
  <CopyIcon class="w-4 h-4" />
104
104
  </button>
105
105
  </template>
@@ -146,53 +146,32 @@
146
146
  <!-- Task Settings Toggles -->
147
147
  <SectionCard title="Task Settings" class="mb-4">
148
148
  <div class="grid grid-cols-2 gap-4 md:grid-cols-3">
149
- <div class="toggle-item">
150
- <div class="toggle-label">
151
- <TimerIcon class="h-4 w-4" />
152
- <span>Smart Timer</span>
153
- </div>
149
+ <div class="flex flex-col items-center gap-2">
150
+ <IconLabel :icon="TimerIcon" label="Smart Timer" />
154
151
  <Switch v-model="toggles.smartTimer" disabled />
155
152
  </div>
156
- <div class="toggle-item">
157
- <div class="toggle-label">
158
- <GroupIcon class="h-4 w-4" />
159
- <span>Login Later</span>
160
- </div>
153
+ <div class="flex flex-col items-center gap-2">
154
+ <IconLabel :icon="GroupIcon" label="Login Later" />
161
155
  <Switch v-model="toggles.loginAfterCart" disabled />
162
156
  </div>
163
- <div class="toggle-item">
164
- <div class="toggle-label">
165
- <HandIcon class="h-4 w-4" />
166
- <span>Manual</span>
167
- </div>
157
+ <div class="flex flex-col items-center gap-2">
158
+ <IconLabel :icon="HandIcon" label="Manual" />
168
159
  <Switch v-model="toggles.manual" disabled />
169
160
  </div>
170
- <div class="toggle-item">
171
- <div class="toggle-label">
172
- <SavingsIcon class="h-4 w-4" />
173
- <span>Do Not Pay</span>
174
- </div>
161
+ <div class="flex flex-col items-center gap-2">
162
+ <IconLabel :icon="SavingsIcon" label="Do Not Pay" />
175
163
  <Switch v-model="toggles.doNotPay" disabled />
176
164
  </div>
177
- <div class="toggle-item">
178
- <div class="toggle-label">
179
- <LoyaltyIcon class="h-4 w-4" />
180
- <span>Presale Mode</span>
181
- </div>
165
+ <div class="flex flex-col items-center gap-2">
166
+ <IconLabel :icon="LoyaltyIcon" label="Presale Mode" />
182
167
  <Switch v-model="toggles.presaleMode" disabled />
183
168
  </div>
184
- <div class="toggle-item">
185
- <div class="toggle-label">
186
- <SkiIcon class="h-4 w-4" />
187
- <span>Quick Queue</span>
188
- </div>
169
+ <div class="flex flex-col items-center gap-2">
170
+ <IconLabel :icon="SkiIcon" label="Quick Queue" />
189
171
  <Switch v-model="toggles.quickQueue" disabled />
190
172
  </div>
191
- <div class="toggle-item">
192
- <div class="toggle-label">
193
- <SandclockIcon class="h-4 w-4" />
194
- <span>Aged Account</span>
195
- </div>
173
+ <div class="flex flex-col items-center gap-2">
174
+ <IconLabel :icon="SandclockIcon" label="Aged Account" />
196
175
  <Switch v-model="toggles.agedAccount" disabled />
197
176
  </div>
198
177
  </div>
@@ -207,8 +186,12 @@ import Switch from "@/components/ui/controls/atomic/Switch.vue";
207
186
  import EyeToggle from "@/components/ui/controls/EyeToggle.vue";
208
187
  import InfoRow from "@/components/ui/InfoRow.vue";
209
188
  import SectionCard from "@/components/ui/SectionCard.vue";
189
+ import IconLabel from "@/components/ui/IconLabel.vue";
210
190
  import { useUIStore } from "@/stores/ui";
211
191
  import { useCopyToClipboard } from "@/composables/useCopyToClipboard";
192
+ import { useColorMapping } from "@/composables/useColorMapping";
193
+ import { useDateFormatting } from "@/composables/useDateFormatting";
194
+ import { useTicketPricing } from "@/composables/useTicketPricing";
212
195
  import {
213
196
  EyeIcon,
214
197
  StadiumIcon,
@@ -235,6 +218,9 @@ import {
235
218
 
236
219
  const ui = useUIStore();
237
220
  const { copy } = useCopyToClipboard();
221
+ const { colorToClass } = useColorMapping();
222
+ const { formatEventDate: formatDate } = useDateFormatting();
223
+ const { isTotalPrice } = useTicketPricing();
238
224
  const showPassword = ref(false);
239
225
 
240
226
  const props = defineProps({
@@ -274,74 +260,4 @@ const toggles = computed(() => ({
274
260
  quickQueue: taskSnapshot.value.quickQueue,
275
261
  agedAccount: taskSnapshot.value.agedAccount
276
262
  }));
277
-
278
- const formatDate = (dateString) => {
279
- if (!dateString) return "";
280
- try {
281
- const date = new Date(dateString);
282
- const options = {
283
- month: "short",
284
- day: "numeric",
285
- year: "numeric",
286
- hour: "numeric",
287
- minute: "2-digit",
288
- hour12: true
289
- };
290
- return date.toLocaleString("en-US", options).replace(",", "");
291
- } catch {
292
- return dateString;
293
- }
294
- };
295
-
296
- const isTotalPrice = (line, index, lines) => {
297
- const trimmed = line.trim();
298
- const nonEmptyLines = lines.filter((l) => l.trim());
299
- const isLastLine = index === lines.lastIndexOf(nonEmptyLines[nonEmptyLines.length - 1]);
300
- if (!isLastLine) return false;
301
- // Match currency symbols ($, €, £, etc.) OR currency codes (USD, EUR, AUD, etc.)
302
- const totalPricePattern = /^([$€£¥₹₽¢]|[A-Z]{3})\s*[\d,]+\.?\d*$/;
303
- return totalPricePattern.test(trimmed) && !trimmed.includes("(");
304
- };
305
-
306
- const colorToClass = (color) => {
307
- const colorMap = {
308
- red: "bg-red-400",
309
- green: "bg-green-400",
310
- yellow: "bg-yellow-400",
311
- blue: "bg-blue-400"
312
- };
313
- return colorMap[color?.toLowerCase()] || "bg-gray-400";
314
- };
315
263
  </script>
316
-
317
- <style lang="scss" scoped>
318
- .toggle-item {
319
- @apply flex flex-col items-center gap-2;
320
- }
321
-
322
- .toggle-label {
323
- @apply flex items-center gap-2 text-xs;
324
- color: oklch(0.9 0 0);
325
-
326
- svg {
327
- color: oklch(0.9 0 0) !important;
328
- width: 16px !important;
329
- height: 16px !important;
330
- }
331
- }
332
-
333
- .status-indicator {
334
- @apply h-2 w-2 flex-shrink-0 rounded-full;
335
- }
336
-
337
- .info-icon {
338
- @apply h-4 w-4 flex-shrink-0;
339
- color: oklch(0.9 0 0) !important;
340
-
341
- svg {
342
- color: oklch(0.9 0 0) !important;
343
- width: 16px !important;
344
- height: 16px !important;
345
- }
346
- }
347
- </style>
@@ -5,17 +5,11 @@
5
5
  viewBox="0 0 17 17"
6
6
  fill="none"
7
7
  xmlns="http://www.w3.org/2000/svg"
8
- class="close-icon"
8
+ class="w-4 h-4"
9
9
  >
10
10
  <path
11
11
  d="M2.20006 16.375L0.625061 14.8L6.92506 8.5L0.625061 2.2L2.20006 0.625L8.50006 6.925L14.8001 0.625L16.3751 2.2L10.0751 8.5L16.3751 14.8L14.8001 16.375L8.50006 10.075L2.20006 16.375Z"
12
12
  fill="currentColor"
13
13
  />
14
14
  </svg>
15
- </template>
16
-
17
- <style scoped>
18
- .close-icon {
19
- @apply w-4 h-4;
20
- }
21
- </style>
15
+ </template>
@@ -1,8 +1,8 @@
1
- <template>
2
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
3
- <path
4
- fill="#fff"
5
- d="M495.9 166.6c3.2 8.7 .5 18.4-6.4 24.6l-43.3 39.4c1.1 8.3 1.7 16.8 1.7 25.4s-.6 17.1-1.7 25.4l43.3 39.4c6.9 6.2 9.6 15.9 6.4 24.6c-4.4 11.9-9.7 23.3-15.8 34.3l-4.7 8.1c-6.6 11-14 21.4-22.1 31.2c-5.9 7.2-15.7 9.6-24.5 6.8l-55.7-17.7c-13.4 10.3-28.2 18.9-44 25.4l-12.5 57.1c-2 9.1-9 16.3-18.2 17.8c-13.8 2.3-28 3.5-42.5 3.5s-28.7-1.2-42.5-3.5c-9.2-1.5-16.2-8.7-18.2-17.8l-12.5-57.1c-15.8-6.5-30.6-15.1-44-25.4L83.1 425.9c-8.8 2.8-18.6 .3-24.5-6.8c-8.1-9.8-15.5-20.2-22.1-31.2l-4.7-8.1c-6.1-11-11.4-22.4-15.8-34.3c-3.2-8.7-.5-18.4 6.4-24.6l43.3-39.4C64.6 273.1 64 264.6 64 256s.6-17.1 1.7-25.4L22.4 191.2c-6.9-6.2-9.6-15.9-6.4-24.6c4.4-11.9 9.7-23.3 15.8-34.3l4.7-8.1c6.6-11 14-21.4 22.1-31.2c5.9-7.2 15.7-9.6 24.5-6.8l55.7 17.7c13.4-10.3 28.2-18.9 44-25.4l12.5-57.1c2-9.1 9-16.3 18.2-17.8C227.3 1.2 241.5 0 256 0s28.7 1.2 42.5 3.5c9.2 1.5 16.2 8.7 18.2 17.8l12.5 57.1c15.8 6.5 30.6 15.1 44 25.4l55.7-17.7c8.8-2.8 18.6-.3 24.5 6.8c8.1 9.8 15.5 20.2 22.1 31.2l4.7 8.1c6.1 11 11.4 22.4 15.8 34.3zM256 336a80 80 0 1 0 0-160 80 80 0 1 0 0 160z"
6
- />
7
- </svg>
8
- </template>
1
+ <template>
2
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
3
+ <path
4
+ fill="#fff"
5
+ d="M495.9 166.6c3.2 8.7 .5 18.4-6.4 24.6l-43.3 39.4c1.1 8.3 1.7 16.8 1.7 25.4s-.6 17.1-1.7 25.4l43.3 39.4c6.9 6.2 9.6 15.9 6.4 24.6c-4.4 11.9-9.7 23.3-15.8 34.3l-4.7 8.1c-6.6 11-14 21.4-22.1 31.2c-5.9 7.2-15.7 9.6-24.5 6.8l-55.7-17.7c-13.4 10.3-28.2 18.9-44 25.4l-12.5 57.1c-2 9.1-9 16.3-18.2 17.8c-13.8 2.3-28 3.5-42.5 3.5s-28.7-1.2-42.5-3.5c-9.2-1.5-16.2-8.7-18.2-17.8l-12.5-57.1c-15.8-6.5-30.6-15.1-44-25.4L83.1 425.9c-8.8 2.8-18.6 .3-24.5-6.8c-8.1-9.8-15.5-20.2-22.1-31.2l-4.7-8.1c-6.1-11-11.4-22.4-15.8-34.3c-3.2-8.7-.5-18.4 6.4-24.6l43.3-39.4C64.6 273.1 64 264.6 64 256s.6-17.1 1.7-25.4L22.4 191.2c-6.9-6.2-9.6-15.9-6.4-24.6c4.4-11.9 9.7-23.3 15.8-34.3l4.7-8.1c6.6-11 14-21.4 22.1-31.2c5.9-7.2 15.7-9.6 24.5-6.8l55.7 17.7c13.4-10.3 28.2-18.9 44-25.4l12.5-57.1c2-9.1 9-16.3 18.2-17.8C227.3 1.2 241.5 0 256 0s28.7 1.2 42.5 3.5c9.2 1.5 16.2 8.7 18.2 17.8l12.5 57.1c15.8 6.5 30.6 15.1 44 25.4l55.7-17.7c8.8-2.8 18.6-.3 24.5 6.8c8.1 9.8 15.5 20.2 22.1 31.2l4.7 8.1c6.1 11 11.4 22.4 15.8 34.3zM256 336a80 80 0 1 0 0-160 80 80 0 1 0 0 160z"
6
+ />
7
+ </svg>
8
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
3
+ <path d="M10 3L8 21M16 3L14 21M4 8H20M3 16H19" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
4
+ </svg>
5
+ </template>
@@ -5,17 +5,11 @@
5
5
  viewBox="0 0 16 9"
6
6
  fill="none"
7
7
  xmlns="http://www.w3.org/2000/svg"
8
- class="key-icon"
8
+ class="w-4 h-4"
9
9
  >
10
10
  <path
11
11
  d="M4.44791 5.89583C4.09843 5.89583 3.79936 5.77129 3.5507 5.52221C3.30161 5.27355 3.17707 4.97448 3.17707 4.625C3.17707 4.27552 3.30161 3.97624 3.5507 3.72716C3.79936 3.4785 4.09843 3.35417 4.44791 3.35417C4.79739 3.35417 5.09645 3.4785 5.34511 3.72716C5.5942 3.97624 5.71874 4.27552 5.71874 4.625C5.71874 4.97448 5.5942 5.27355 5.34511 5.52221C5.09645 5.77129 4.79739 5.89583 4.44791 5.89583ZM4.44791 8.4375C3.38888 8.4375 2.4887 8.06684 1.74739 7.32552C1.00607 6.5842 0.635406 5.68403 0.635406 4.625C0.635406 3.56597 1.00607 2.6658 1.74739 1.92448C2.4887 1.18316 3.38888 0.8125 4.44791 0.8125C5.15745 0.8125 5.80092 0.987239 6.3783 1.33672C6.95526 1.6862 7.41318 2.14688 7.75207 2.71875H13.3437L15.25 4.625L12.3906 7.48438L11.1198 6.53125L9.84895 7.48438L8.49869 6.53125H7.75207C7.41318 7.10313 6.95526 7.5638 6.3783 7.91328C5.80092 8.26276 5.15745 8.4375 4.44791 8.4375ZM4.44791 7.16667C5.04096 7.16667 5.56264 6.98663 6.01294 6.62656C6.46281 6.26649 6.76188 5.81111 6.91015 5.26042H8.89582L9.81718 5.91172L11.1198 4.94271L12.2476 5.81641L13.4391 4.625L12.8036 3.98958H6.91015C6.76188 3.43889 6.46281 2.98351 6.01294 2.62344C5.56264 2.26337 5.04096 2.08333 4.44791 2.08333C3.74895 2.08333 3.1506 2.33221 2.65285 2.82995C2.15511 3.32769 1.90624 3.92604 1.90624 4.625C1.90624 5.32396 2.15511 5.92231 2.65285 6.42005C3.1506 6.9178 3.74895 7.16667 4.44791 7.16667Z"
12
12
  fill="currentColor"
13
13
  />
14
14
  </svg>
15
- </template>
16
-
17
- <style scoped>
18
- .key-icon {
19
- @apply w-4 h-4;
20
- }
21
- </style>
15
+ </template>
@@ -5,17 +5,11 @@
5
5
  viewBox="0 0 19 20"
6
6
  fill="none"
7
7
  xmlns="http://www.w3.org/2000/svg"
8
- class="pencil-icon"
8
+ class="w-4 h-4"
9
9
  >
10
10
  <path
11
11
  d="M0.75 20V16.5H18.25V20H0.75ZM2.5 14.75V11.4688L10.4187 3.55004L13.7 6.83129L5.78125 14.75H2.5ZM4.25 13H5.0375L11.25 6.83129L10.4187 6.00004L4.25 12.2125V13ZM14.6844 5.86879L11.4031 2.58754L12.9781 1.01254C13.1385 0.837536 13.3427 0.753536 13.5906 0.760536C13.8385 0.768119 14.0427 0.852119 14.2031 1.01254L16.2594 3.06879C16.4198 3.2292 16.5 3.42987 16.5 3.67079C16.5 3.91112 16.4198 4.11879 16.2594 4.29379L14.6844 5.86879Z"
12
12
  fill="currentColor"
13
13
  />
14
14
  </svg>
15
- </template>
16
-
17
- <style scoped>
18
- .pencil-icon {
19
- @apply w-4 h-4;
20
- }
21
- </style>
15
+ </template>
@@ -2,17 +2,11 @@
2
2
  <svg
3
3
  xmlns="http://www.w3.org/2000/svg"
4
4
  viewBox="0 0 1024 1024"
5
- class="profile-icon"
5
+ class="w-4 h-4"
6
6
  >
7
7
  <path
8
8
  fill="currentColor"
9
9
  d="M0 1024v-72.874521c0-149.917478 93.497315-353.841814 241.330575-402.948929l9.031614-2.998349 4.497524 8.117483a316.618401 316.618401 0 0 0 33.201237 48.485506l10.567354 12.688138-16.088705 4.387828c-118.178851 32.579628-201.986378 215.917734-206.88612 332.341454h872.519723c-4.899742-116.387154-99.457449-299.834957-217.6363-332.341454l-16.088705-4.387828 10.457658-12.578442a316.874358 316.874358 0 0 0 33.201237-48.485507l4.497524-8.117483 8.921918 2.888654c147.979521 49.107115 252.300146 252.994886 252.300147 402.948929V1024H0z m511.91334-365.652386a246.888491 246.888491 0 0 1-255.95667-255.95667V256.129989a246.888491 246.888491 0 0 1 255.95667-255.95667 246.888491 246.888491 0 0 1 255.956671 255.95667v146.260955a246.888491 246.888491 0 0 1-255.956671 255.95667z m182.826193-402.217625A182.826193 182.826193 0 1 0 329.087147 256.129989v146.260955a182.826193 182.826193 0 1 0 365.652386 0V256.129989z"
10
10
  />
11
11
  </svg>
12
- </template>
13
-
14
- <style scoped>
15
- .profile-icon {
16
- @apply w-4 h-4;
17
- }
18
- </style>
12
+ </template>
@@ -5,17 +5,11 @@
5
5
  viewBox="0 0 16 16"
6
6
  fill="none"
7
7
  xmlns="http://www.w3.org/2000/svg"
8
- class="sell-icon"
8
+ class="w-4 h-4"
9
9
  >
10
10
  <path
11
11
  d="M9.68747 15.05C9.39997 15.3375 9.04372 15.4812 8.61872 15.4812C8.19372 15.4812 7.83747 15.3375 7.54997 15.05L0.949969 8.44995C0.812469 8.31245 0.70322 8.14995 0.62222 7.96245C0.54072 7.77495 0.499969 7.57495 0.499969 7.36245V1.99995C0.499969 1.58745 0.64697 1.2342 0.94097 0.940204C1.23447 0.646704 1.58747 0.499954 1.99997 0.499954H7.36247C7.57497 0.499954 7.77497 0.540454 7.96247 0.621454C8.14997 0.702954 8.31247 0.812454 8.44997 0.949954L15.05 7.5687C15.3375 7.8562 15.4812 8.2092 15.4812 8.6277C15.4812 9.0467 15.3375 9.39995 15.05 9.68745L9.68747 15.05ZM8.61872 14L13.9812 8.63745L7.36247 1.99995H1.99997V7.36245L8.61872 14ZM3.87497 4.99995C4.18747 4.99995 4.45297 4.89045 4.67147 4.67145C4.89047 4.45295 4.99997 4.18745 4.99997 3.87495C4.99997 3.56245 4.89047 3.29695 4.67147 3.07845C4.45297 2.85945 4.18747 2.74995 3.87497 2.74995C3.56247 2.74995 3.29697 2.85945 3.07847 3.07845C2.85947 3.29695 2.74997 3.56245 2.74997 3.87495C2.74997 4.18745 2.85947 4.45295 3.07847 4.67145C3.29697 4.89045 3.56247 4.99995 3.87497 4.99995Z"
12
12
  fill="currentColor"
13
13
  />
14
14
  </svg>
15
- </template>
16
-
17
- <style scoped>
18
- .sell-icon {
19
- @apply w-4 h-4;
20
- }
21
- </style>
15
+ </template>
@@ -1,19 +1,16 @@
1
1
  <template>
2
- <svg class="spinner" viewBox="0 0 50 50">
2
+ <svg class="spinner mx-auto h-7.5 w-7.5" viewBox="0 0 50 50">
3
3
  <circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5"></circle>
4
4
  </svg>
5
5
  </template>
6
6
 
7
7
  <style lang="scss" scoped>
8
8
  .spinner {
9
- @apply mx-auto;
10
- animation: rotate 2s linear infinite;
11
9
  z-index: 2;
12
- width: 30px;
13
- height: 30px;
14
-
10
+ animation: rotate 2s linear infinite;
11
+
15
12
  & .path {
16
- stroke: rgba(70, 198, 210, 100%);
13
+ stroke: oklch(0.75 0.1 195);
17
14
  stroke-linecap: round;
18
15
  animation: dash 1.5s ease-in-out infinite;
19
16
  }
@@ -2,17 +2,11 @@
2
2
  <svg
3
3
  xmlns="http://www.w3.org/2000/svg"
4
4
  viewBox="0 0 512 512"
5
- class="wildcard-icon"
5
+ class="w-4 h-4"
6
6
  >
7
7
  <path
8
8
  fill="currentColor"
9
9
  d="M208 32c0-17.7 14.3-32 32-32h32c17.7 0 32 14.3 32 32V172.9l122-70.4c15.3-8.8 34.9-3.6 43.7 11.7l16 27.7c8.8 15.3 3.6 34.9-11.7 43.7L352 256l122 70.4c15.3 8.8 20.5 28.4 11.7 43.7l-16 27.7c-8.8 15.3-28.4 20.6-43.7 11.7L304 339.1V480c0 17.7-14.3 32-32 32H240c-17.7 0-32-14.3-32-32V339.1L86 409.6c-15.3 8.8-34.9 3.6-43.7-11.7l-16-27.7c-8.8-15.3-3.6-34.9 11.7-43.7L160 256 38 185.6c-15.3-8.8-20.5-28.4-11.7-43.7l16-27.7C51.1 98.8 70.7 93.6 86 102.4l122 70.4V32z"
10
10
  />
11
11
  </svg>
12
- </template>
13
-
14
- <style scoped>
15
- .wildcard-icon {
16
- @apply w-4 h-4;
17
- }
18
- </style>
12
+ </template>
@@ -47,8 +47,6 @@ import CloseIcon from "./Close.vue";
47
47
  import KeyIcon from "./Key.vue";
48
48
  import PencilIcon from "./Pencil.vue";
49
49
  import SellIcon from "./Sell.vue";
50
- import SquareCheckIcon from "./SquareCheck.vue";
51
- import SquareUncheckIcon from "./SquareUncheck.vue";
52
50
  import WildcardIcon from "./Wildcard.vue";
53
51
  import ProfileIcon from "./Profile.vue";
54
52
  import CloseXIcon from "./CloseX.vue";
@@ -56,6 +54,7 @@ import CheckIcon from "./Check.vue";
56
54
  import SpinnerIcon from "./Spinner.vue";
57
55
  import EyeIcon from "./Eye.vue";
58
56
  import CopyIcon from "./Copy.vue";
57
+ import HashIcon from "./Hash.vue";
59
58
 
60
59
  export {
61
60
  EditIcon,
@@ -103,13 +102,12 @@ export {
103
102
  KeyIcon,
104
103
  PencilIcon,
105
104
  SellIcon,
106
- SquareCheckIcon,
107
- SquareUncheckIcon,
108
105
  WildcardIcon,
109
106
  ProfileIcon,
110
107
  CloseXIcon,
111
108
  CheckIcon,
112
109
  SpinnerIcon,
113
110
  EyeIcon,
114
- CopyIcon
111
+ CopyIcon,
112
+ HashIcon
115
113
  };