@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
@@ -2,12 +2,12 @@
2
2
  <button
3
3
  @click="increase"
4
4
  :class="[
5
- 'sort-toggle',
6
- { 'darker': props.darker }
5
+ 'flex-gap-2 items-center px-3 py-2 rounded text-sm font-medium focus:outline-none text-light-300 border-2 border-dark-550 h-10',
6
+ props.darker ? 'bg-dark-400 min-w-25' : 'bg-dark-350 min-w-20'
7
7
  ]"
8
8
  >
9
- <component :is="getCurrentIcon()" class="icon" />
10
- <span class="text">{{ getCurrentText() }}</span>
9
+ <component :is="getCurrentIcon()" class="w-4 h-4 flex-shrink-0" />
10
+ <span class="text-center flex-1">{{ getCurrentText() }}</span>
11
11
  </button>
12
12
  </template>
13
13
 
@@ -19,13 +19,34 @@ let sortOptions = ref(["none", "asc", "desc", "none"]);
19
19
  const currentOpt = ref(0);
20
20
 
21
21
  const props = defineProps({
22
- filter: Object,
23
- index: Number,
24
- expandedFilter: Number,
25
- filterBuilder: Object,
26
- options: Object,
27
- current: String,
28
- darker: Boolean
22
+ filter: {
23
+ type: Object,
24
+ default: () => ({})
25
+ },
26
+ index: {
27
+ type: Number,
28
+ default: 0
29
+ },
30
+ expandedFilter: {
31
+ type: Number,
32
+ default: null
33
+ },
34
+ filterBuilder: {
35
+ type: Object,
36
+ default: () => ({})
37
+ },
38
+ options: {
39
+ type: Array,
40
+ default: () => ['none', 'asc', 'desc', 'none']
41
+ },
42
+ current: {
43
+ type: String,
44
+ default: 'none'
45
+ },
46
+ darker: {
47
+ type: Boolean,
48
+ default: false
49
+ }
29
50
  });
30
51
 
31
52
  if (props.options) sortOptions.value = props.options;
@@ -40,7 +61,7 @@ const increase = () => {
40
61
 
41
62
  const getCurrentIcon = () => {
42
63
  const current = sortOptions.value[currentOpt.value];
43
-
64
+
44
65
  // Handle filter options (All, WL, BL)
45
66
  if (props.options && props.options.includes('All')) {
46
67
  switch (current) {
@@ -50,7 +71,7 @@ const getCurrentIcon = () => {
50
71
  default: return FilterIcon;
51
72
  }
52
73
  }
53
-
74
+
54
75
  // Handle sort options (none, asc, desc)
55
76
  switch (current) {
56
77
  case 'asc': return UpIcon;
@@ -62,12 +83,12 @@ const getCurrentIcon = () => {
62
83
 
63
84
  const getCurrentText = () => {
64
85
  const current = sortOptions.value[currentOpt.value];
65
-
86
+
66
87
  // Handle filter options (All, WL, BL)
67
88
  if (props.options && props.options.includes('All')) {
68
89
  return current;
69
90
  }
70
-
91
+
71
92
  // Handle sort options
72
93
  switch (current) {
73
94
  case 'asc': return 'Low';
@@ -77,31 +98,3 @@ const getCurrentText = () => {
77
98
  }
78
99
  };
79
100
  </script>
80
-
81
- <style scoped>
82
- .sort-toggle {
83
- @apply flex items-center gap-2 px-3 py-2 rounded text-sm font-medium focus:outline-none;
84
- background: oklch(0.2603 0 0);
85
- border: 2px solid oklch(0.2809 0 0);
86
- color: oklch(0.90 0 0);
87
- min-width: 80px;
88
- height: 40px;
89
- }
90
-
91
- .sort-toggle.darker {
92
- background: oklch(0.2046 0 0);
93
- border: 2px solid oklch(0.2809 0 0);
94
- color: oklch(0.90 0 0);
95
- min-width: 100px;
96
- height: 40px;
97
- padding: 0 0.75rem;
98
- }
99
-
100
- .icon {
101
- @apply w-4 h-4 flex-shrink-0;
102
- }
103
-
104
- .text {
105
- @apply text-center flex-1;
106
- }
107
- </style>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="border-b border-dark-600 w-full px-2 md:px-4 text-white text-xs py-4 grid items-center bg-dark-300">
2
+ <div class="relative border-b border-dark-550 w-full px-2 md:px-4 text-white text-xs py-4 grid items-center bg-dark-300">
3
3
  <slot />
4
4
  </div>
5
5
  </template>
@@ -1,79 +1,73 @@
1
1
  <template>
2
- <div class="table-component">
2
+ <div class="table-component" style="border-color: var(--color-border);">
3
3
  <slot />
4
4
  </div>
5
5
  </template>
6
- <style lang="scss">
6
+
7
+ <style scoped lang="scss">
7
8
  .table-component {
8
- @apply relative box-border flex flex-col rounded-lg border border-dark-600 bg-dark-500 bg-clip-padding;
9
- @apply overflow-x-auto overflow-y-auto;
10
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
9
+ @apply relative box-border flex flex-col rounded-lg;
10
+ @apply bg-dark-500 bg-clip-padding overflow-auto shadow-sm;
11
+
12
+ max-height: calc(100vh - 200px);
11
13
  overscroll-behavior: auto;
12
- max-height: calc(100vh - 300px);
13
14
  -webkit-overflow-scrolling: touch;
14
15
  touch-action: pan-x pan-y;
15
16
 
16
- /* iPad Pro and larger tablets - more space for UTILS */
17
- @media (min-width: 768px) and (max-width: 1440px) {
18
- max-height: calc(100vh - 400px);
17
+ @media (min-width: 768px) {
18
+ max-height: calc(100vh - 280px);
19
+ }
20
+
21
+ @media (min-width: 1024px) {
22
+ max-height: calc(100vh - 240px);
19
23
  }
20
24
 
21
- /* iPad portrait - even more space needed */
22
- @media (min-width: 768px) and (max-width: 1100px) and (orientation: portrait) {
23
- max-height: calc(100vh - 450px);
25
+ @media (min-width: 1280px) {
26
+ max-height: calc(100vh - 220px);
24
27
  }
25
28
 
26
- /* PWA mode - account for status bar and home indicator */
27
29
  @media (display-mode: standalone) {
28
- max-height: calc(100vh - 420px);
30
+ max-height: calc(100vh - 240px);
29
31
 
30
- @media (min-width: 768px) and (max-width: 1440px) {
31
- max-height: calc(100vh - 480px);
32
+ @media (min-width: 768px) {
33
+ max-height: calc(100vh - 320px);
32
34
  }
33
35
 
34
- /* iPad portrait PWA - maximum space for UTILS */
35
- @media (min-width: 768px) and (max-width: 1100px) and (orientation: portrait) {
36
- max-height: calc(100vh - 500px);
36
+ @media (min-width: 1024px) {
37
+ max-height: calc(100vh - 280px);
37
38
  }
38
- }
39
- }
40
39
 
41
- .table-component > .grid:not(:first-child) {
42
- border-bottom: 1px solid oklch(0.26 0 0);
43
- // Only enforce min-width on desktop, allow mobile to fit screen
44
- @media (min-width: 768px) {
45
- min-width: 640px;
40
+ @media (min-width: 1280px) {
41
+ max-height: calc(100vh - 260px);
42
+ }
46
43
  }
47
- }
48
44
 
49
- /* Remove border from last row */
50
- .table-component > .grid:last-child {
51
- border-bottom: none;
52
- }
45
+ & > :not(:first-child) {
46
+ @apply border-b border-dark-500;
53
47
 
54
- /* Odd rows (lighter) */
55
- .table-component > .grid:nth-child(odd) {
56
- @apply bg-dark-300;
57
- }
48
+ @media (min-width: 768px) {
49
+ min-width: 640px;
50
+ }
51
+ }
58
52
 
59
- /* Even rows (darker) */
60
- .table-component > .grid:nth-child(even) {
61
- @apply bg-dark-400;
62
- }
53
+ & > :last-child {
54
+ @apply border-b-0 rounded-b-lg overflow-hidden;
55
+ }
63
56
 
64
- /* First grid child (header) keeps its own background */
65
- .table-component > .grid:first-child {
66
- border-bottom: 1px solid oklch(0.26 0 0);
67
- @apply rounded-t-lg;
68
- overflow: hidden;
69
- @media (min-width: 768px) {
70
- min-width: 640px;
57
+ & > :nth-child(odd) {
58
+ @apply bg-dark-300;
71
59
  }
72
- }
73
60
 
74
- /* Last row rounded bottom corners */
75
- .table-component > .grid:last-child {
76
- @apply rounded-b-lg;
77
- overflow: hidden;
61
+ & > :nth-child(even) {
62
+ @apply bg-dark-400;
63
+ }
64
+
65
+ & > :first-child {
66
+ @apply border-b border-dark-500 rounded-t-lg overflow-hidden;
67
+
68
+ @media (min-width: 768px) {
69
+ min-width: 640px;
70
+ }
71
+ }
78
72
  }
79
73
  </style>
@@ -3,7 +3,7 @@
3
3
  <template #header> Check Stock <BoxIcon class="ml-4" /> </template>
4
4
  <!-- Event ID -->
5
5
  <div class="input-wrapper mt-7 mb-4">
6
- <label class="label-override mb-2">Event ID or URL <StadiumIcon /></label>
6
+ <label class="label-override mb-2 flex">Event ID or URL <StadiumIcon /></label>
7
7
  <div class="input-default required">
8
8
  <input
9
9
  :placeholder="!isEU(ui.currentCountry.siteId) ? '102PDA9125510GYU' : '529171'"
@@ -13,46 +13,37 @@
13
13
  </div>
14
14
  <!-- Presale Code -->
15
15
  <div class="input-wrapper mb-4">
16
- <label class="label-override mb-2">Presale code <AwardIcon /></label>
16
+ <label class="label-override mb-2 flex">Presale code <AwardIcon /></label>
17
17
  <div class="input-default">
18
18
  <input placeholder="Presale code" v-model="presaleCode" />
19
19
  </div>
20
20
  </div>
21
21
  <!-- DID -->
22
22
  <div class="input-wrapper mb-4" v-if="!isEU(ui.currentCountry.siteId)">
23
- <label class="label-override mb-2">DID <AwardIcon /></label>
23
+ <label class="label-override mb-2 flex">DID <AwardIcon /></label>
24
24
  <div class="input-default">
25
25
  <input placeholder="psl" v-model="eventDid" />
26
26
  </div>
27
27
  </div>
28
28
  <!-- CL ORIGIN -->
29
29
  <div class="input-wrapper mb-8" v-if="isEU(ui.currentCountry.siteId)">
30
- <label class="label-override mb-2">CL Origin / SubChannel ID <AwardIcon /></label>
30
+ <label class="label-override mb-2 flex">CL Origin / SubChannel ID <AwardIcon /></label>
31
31
  <div class="input-default">
32
32
  <input placeholder="ORIGIN2" v-model="clOrigin" />
33
33
  </div>
34
34
  </div>
35
- <button
36
- class="button-default ml-auto mt-4 flex w-48 items-center justify-center gap-x-2 bg-dark-400 text-xs"
37
- @click="done()">
35
+ <button class="btn-modal ml-auto mt-4 w-48" @click="done()">
38
36
  Check Stock
39
- <BoxIcon />
37
+ <BoxIcon class="ml-2" />
40
38
  </button>
41
39
  </Modal>
42
40
  </template>
43
- <style lang="scss" scoped>
44
- .input-wrapper {
45
- label {
46
- @apply flex;
47
- }
48
- }
49
- </style>
50
41
  <script setup>
51
42
  import Modal from "@/components/ui/Modal.vue";
52
43
  import { StadiumIcon, BoxIcon, AwardIcon } from "@/components/icons";
53
44
  import { useUIStore } from "@/stores/ui";
54
45
  import { ref } from "vue";
55
- import { isEU } from "@/stores/utils";
46
+ import { isEU } from "@/libs/utils/eventUrl";
56
47
 
57
48
  const ui = useUIStore();
58
49
  const eventId = ref("");
@@ -1,84 +1,39 @@
1
1
  <template>
2
- <div class="task-controls flex-row">
3
- <div class="control-buttons mb-4 xl:mb-0">
4
- <button @click="$emit('startAll')" class="bg-green-400 smooth-hover responsive-button border-none">
5
- Start <PlayIcon />
2
+ <div class="flex-row gap-x-3">
3
+ <div class="flex gap-x-3 items-center w-full mb-4 xl:mb-0">
4
+ <button @click="$emit('startAll')" class="btn-control-success" aria-label="Start all tasks">
5
+ Start <PlayIcon class="ml-2" />
6
6
  </button>
7
- <button @click="$emit('stopAll')" class="bg-red-400 smooth-hover responsive-button border-none">
8
- Stop <PauseIcon />
7
+ <button @click="$emit('stopAll')" class="btn-control-danger" aria-label="Stop all tasks">
8
+ Stop <PauseIcon class="ml-2" />
9
9
  </button>
10
- <button @click="$emit('deleteAll')" class="bg-dark-400 smooth-hover responsive-button border border-dark-650 hover:border-dark-700">
11
- Delete <TrashIcon />
10
+ <button @click="$emit('deleteAll')" class="btn-action-responsive bg-dark-400 border border-dark-650 hover:border-dark-700 smooth-hover min-w-20 max-w-30 flex-grow xl:flex-initial" aria-label="Delete all tasks">
11
+ Delete <TrashIcon class="ml-2" />
12
12
  </button>
13
13
  <h4 class="text-light-300 text-sm flex-grow xl:flex-initial"></h4>
14
14
  </div>
15
15
  <div class="flex gap-x-3">
16
16
  <button
17
17
  :disabled="ui.disabledButtons['add-tasks']"
18
- class="bg-dark-400 disabled:opacity-70 smooth-hover flex-grow xl:flex-initial w-36 border border-dark-650 hover:border-dark-700"
18
+ class="btn-modal disabled:opacity-70 flex-grow xl:flex-initial w-36"
19
19
  @click="ui.toggleModal('create-task')"
20
- >
21
- Create Task
22
- <PlusIcon class="ml-2" />
20
+ aria-label="Create new task">
21
+ Create Task <PlusIcon class="ml-2" />
23
22
  </button>
24
-
25
23
  <button
26
- class="bg-dark-400 smooth-hover flex-grow xl:flex-initial w-36 border border-dark-650 hover:border-dark-700"
24
+ class="btn-modal flex-grow xl:flex-initial w-36"
27
25
  @click="ui.toggleModal('mass-edit-presale-code')"
28
26
  :disabled="ui.disabledButtons['mass-edit']"
29
27
  v-if="ui.currentModule == 'TM'"
30
- >
31
- Mass Edit
32
- <EditIcon class="ml-2" />
28
+ aria-label="Mass edit presale codes">
29
+ Mass Edit <EditIcon class="ml-2" />
33
30
  </button>
34
31
  </div>
35
32
  </div>
36
33
  </template>
37
34
  <script setup>
38
- import { ref } from "vue";
39
35
  import { useUIStore } from "@/stores/ui";
40
- import { PlayIcon, PauseIcon, TrashIcon, ExpandIcon, ShrinkIcon, PlusIcon, EditIcon } from "@/components/icons";
36
+ import { PlayIcon, PauseIcon, TrashIcon, PlusIcon, EditIcon } from "@/components/icons";
41
37
 
42
38
  const ui = useUIStore();
43
- const isExpanded = ref(false);
44
39
  </script>
45
- <style lang="scss" scoped>
46
- button {
47
- @apply text-white h-10 rounded-md text-xs flex items-center justify-center font-medium px-4;
48
- transition: all 0.15s ease;
49
-
50
- &.bg-dark-400:active, &.bg-dark-400:focus {
51
- outline: 1px solid oklch(0.72 0.15 145);
52
- outline-offset: 0;
53
- border-color: oklch(0.72 0.15 145) !important;
54
- }
55
- }
56
-
57
- .responsive-button {
58
- min-width: 80px;
59
- max-width: 120px;
60
- @apply flex-grow xl:flex-initial;
61
-
62
- @media (max-width: 768px) {
63
- @apply h-10 text-xs;
64
- }
65
- }
66
-
67
- .task-controls {
68
- @apply gap-x-3;
69
- .control-buttons {
70
- @apply flex gap-x-3 items-center w-full;
71
- button {
72
- svg {
73
- @apply ml-2;
74
- }
75
- }
76
- }
77
- .expand-shrink {
78
- @apply flex gap-x-2;
79
- button {
80
- @apply text-white text-xs px-4 flex items-center justify-center gap-x-4 duration-200 border border-light-300 hover:border-light-400;
81
- }
82
- }
83
- }
84
- </style>
@@ -1,11 +1,11 @@
1
1
  <template>
2
- <div class="mobile-controls flex items-center justify-between" v-once>
3
- <div class="expand-shrink">
4
- <button class="mobile-btn" @click="$emit('expand')">
2
+ <div class="flex items-center justify-between" v-once>
3
+ <div class="flex gap-x-2">
4
+ <button class="btn-control-mobile" @click="$emit('expand')" aria-label="Expand all tasks">
5
5
  Expand
6
6
  <ExpandIcon />
7
7
  </button>
8
- <button class="mobile-btn" @click="$emit('fold')">
8
+ <button class="btn-control-mobile" @click="$emit('fold')" aria-label="Collapse all tasks">
9
9
  Fold
10
10
  <ShrinkIcon />
11
11
  </button>
@@ -13,20 +13,5 @@
13
13
  </div>
14
14
  </template>
15
15
  <script setup>
16
- import { useUIStore } from "@/stores/ui";
17
-
18
- import { PlayIcon, PauseIcon, TrashIcon, ExpandIcon, ShrinkIcon, EditIcon } from "@/components/icons";
19
- const ui = useUIStore();
16
+ import { ExpandIcon, ShrinkIcon } from "@/components/icons";
20
17
  </script>
21
- <style lang="scss" scoped>
22
- .mobile-controls {
23
- .expand-shrink {
24
- @apply flex gap-x-2;
25
- .mobile-btn {
26
- @apply text-white text-xs px-3 flex items-center justify-center gap-x-1 h-10 rounded-md bg-dark-400 border border-dark-650 hover:border-dark-700 transition-all duration-150 font-medium;
27
- width: 80px;
28
- font-size: 11px;
29
- }
30
- }
31
- }
32
- </style>
@@ -6,7 +6,7 @@
6
6
  </template>
7
7
 
8
8
  <!-- Task Form -->
9
- <div class="form-grid mb-4 mt-4">
9
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4 mt-4">
10
10
  <!-- Event ID -->
11
11
  <FormField label="Event ID" :icon="StadiumIcon" required>
12
12
  <input placeholder="827474" v-model="task.eventId" required />
@@ -38,30 +38,12 @@
38
38
  </FormField>
39
39
 
40
40
  <!-- Task Amount -->
41
- <div class="input-wrapper">
42
- <label class="label-override mb-2">
43
- Amount
44
- <span class="ml-2 h-[18px]">#</span>
45
- </label>
46
- <div class="input-default">
47
- <input placeholder="20" min="1" type="number" pattern="\d*" v-model="task.taskQuantity" />
48
- <div class="input-incrementer">
49
- <button @click="task.taskQuantity++">
50
- <UpIcon />
51
- </button>
52
- <button @click="if (task.taskQuantity > 1) task.taskQuantity--;">
53
- <DownIcon />
54
- </button>
55
- </div>
56
- </div>
57
- </div>
41
+ <FormField label="Amount" :icon="HashIcon" incrementer @increment="task.taskQuantity++" @decrement="task.taskQuantity > 1 && task.taskQuantity--">
42
+ <input placeholder="20" min="1" type="number" pattern="\d*" v-model="task.taskQuantity" />
43
+ </FormField>
58
44
 
59
45
  <!-- Profile Tag(s) -->
60
- <div class="input-wrapper">
61
- <label class="label-override mb-2">
62
- Profile Tag(s)
63
- <TagIcon />
64
- </label>
46
+ <FormField label="Profile Tag(s)" :icon="TagIcon" noWrapper>
65
47
  <MultiDropdown
66
48
  class="w-full will-change-auto"
67
49
  :onSelect="(v) => (task.profileTags = v)"
@@ -71,14 +53,10 @@
71
53
  return { label: opt, value: opt };
72
54
  })
73
55
  " />
74
- </div>
56
+ </FormField>
75
57
 
76
58
  <!-- Account Tag -->
77
- <div class="input-wrapper">
78
- <label class="label-override mb-2">
79
- Account Tag
80
- <ScannerIcon />
81
- </label>
59
+ <FormField label="Account Tag" :icon="ScannerIcon" noWrapper>
82
60
  <Dropdown
83
61
  :onClick="(f) => (task.accountTag = f)"
84
62
  default="Default tag"
@@ -87,7 +65,7 @@
87
65
  :allowDefault="false"
88
66
  :capitalize="true"
89
67
  class="dropdown w-full" />
90
- </div>
68
+ </FormField>
91
69
 
92
70
  <!-- Start Offset -->
93
71
  <FormField label="Start Offset (Minutes)" :icon="ShieldIcon" incrementer @increment="task.startOffset = (task.startOffset || 0) + 1" @decrement="task.startOffset > 0 && task.startOffset--">
@@ -101,47 +79,18 @@
101
79
  </div>
102
80
  <div class="mb-3 border border-dark-650" />
103
81
  <!-- Task Switches -->
104
- <div class="task-switches mb-4 grid grid-cols-4 justify-between gap-y-4">
105
- <div class="switch-wrapper flex flex-col">
106
- <h4>
107
- <span class="hidden xs:block">Do Not Pay</span>
108
- <span class="block xs:hidden">DNP</span>
109
- <SavingsIcon class="scale-90" />
110
- </h4>
111
- <Switch class="mx-auto" v-model="task.doNotPay" />
112
- </div>
113
- <div class="switch-wrapper flex flex-col">
114
- <h4>
115
- <span class="hidden xs:block">Smart Timer</span>
116
- <span class="block xs:hidden">Timer</span>
117
- <TimerIcon class="scale-90" />
118
- </h4>
119
- <Switch class="mx-auto" v-model="task.smartTimer" />
120
- </div>
121
- <div class="switch-wrapper flex flex-col">
122
- <h4>
123
- <span class="hidden xs:block">Quick Queue</span>
124
- <span class="block xs:hidden">Quick Q.</span>
125
- <SkiIcon class="scale-90" />
126
- </h4>
127
- <Switch class="mx-auto" v-model="task.quickQueue" />
128
- </div>
129
- <div class="switch-wrapper flex flex-col">
130
- <h4>
131
- Manual
132
- <HandIcon />
133
- </h4>
134
- <Switch class="mx-auto" v-model="task.manual" />
135
- </div>
82
+ <div class="mb-4 grid grid-cols-4 justify-between gap-y-4">
83
+ <TaskToggle :icon="SavingsIcon" label="Do Not Pay" responsive-label="DNP" v-model="task.doNotPay" />
84
+ <TaskToggle :icon="TimerIcon" label="Smart Timer" responsive-label="Timer" v-model="task.smartTimer" />
85
+ <TaskToggle :icon="SkiIcon" label="Quick Queue" responsive-label="Quick Q." v-model="task.quickQueue" />
86
+ <TaskToggle :icon="HandIcon" label="Manual" v-model="task.manual" icon-class="" />
136
87
  </div>
137
88
 
138
89
  <!-- Task prefab -->
139
90
  <div class="my-3 border border-dark-650" />
140
- <button
141
- class="button-default ml-auto mt-4 bg-dark-400"
142
- @click="createTask">
91
+ <button class="btn-modal ml-auto mt-4 w-36" @click="createTask">
143
92
  Create
144
- <EditIcon />
93
+ <EditIcon class="ml-2" />
145
94
  </button>
146
95
  </Modal>
147
96
  </template>
@@ -151,7 +100,7 @@ import { ref, watch } from "vue";
151
100
  import { countries } from "@/stores/countries";
152
101
  import Modal from "@/components/ui/Modal.vue";
153
102
  import FormField from "@/components/ui/FormField.vue";
154
- import Switch from "@/components/ui/controls/atomic/Switch.vue";
103
+ import TaskToggle from "@/components/ui/TaskToggle.vue";
155
104
  import {
156
105
  MailIcon,
157
106
  CameraIcon,
@@ -162,20 +111,17 @@ import {
162
111
  TagIcon,
163
112
  SkiIcon,
164
113
  HandIcon,
165
- GroupIcon,
166
114
  ShieldIcon,
167
115
  TimerIcon,
168
116
  SavingsIcon,
169
- EditIcon,
170
- UpIcon,
171
- DownIcon,
172
- SandclockIcon,
173
- CartIcon
117
+ EditIcon
174
118
  } from "@/components/icons";
175
119
  import { useUIStore } from "@/stores/ui";
176
120
  import Dropdown from "@/components/ui/controls/atomic/Dropdown.vue";
177
121
  import MultiDropdown from "@/components/ui/controls/atomic/MultiDropdown.vue";
178
- import { firstUpper, parseAxsEventUrl, removeDuplicates } from "@/stores/utils";
122
+ import { firstUpper } from "@/libs/utils/string";
123
+ import { parseAxsEventUrl } from "@/libs/utils/eventUrl";
124
+ import { removeDuplicates } from "@/libs/utils/array";
179
125
 
180
126
  const ui = useUIStore();
181
127
 
@@ -250,7 +196,6 @@ watch(
250
196
  if (country) ui.setCurrentCountry(country, false, ui.currentModule);
251
197
 
252
198
  task.value.eventId = parsed.eventId;
253
- debugger;
254
199
  if (parsed.promoId) task.value.promoId = parsed.promoId;
255
200
  } catch (ex) {
256
201
  ui.logger.Error("Could not parse url (2)", ex);
@@ -258,47 +203,4 @@ watch(
258
203
  }
259
204
  );
260
205
 
261
- // fetchConfigs();
262
206
  </script>
263
-
264
- <style lang="scss" scoped>
265
- .label-override {
266
- @apply flex items-center;
267
- color: #e1e1e4 !important;
268
-
269
- svg {
270
- @apply ml-2;
271
-
272
- path {
273
- fill: #e1e1e4 !important;
274
- }
275
- }
276
- }
277
-
278
- .task-switches {
279
- h4 {
280
- color: #e1e1e4;
281
- @apply mx-auto flex items-center gap-x-2 text-center text-xs;
282
- }
283
-
284
- .switch-wrapper {
285
- @apply gap-y-2;
286
- }
287
- }
288
-
289
- @media (max-width: 720px) {
290
- .task-switches {
291
- h4 {
292
- font-size: 12px !important;
293
- }
294
- }
295
- }
296
-
297
- .switch-wrapper {
298
- svg {
299
- path {
300
- fill: oklch(0.65 0 0) !important;
301
- }
302
- }
303
- }
304
- </style>