@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.
- package/.prettierrc +27 -1
- package/.vscode/extensions.json +1 -1
- package/README.md +64 -2
- package/artwork/image.png +0 -0
- package/backend/api.js +26 -24
- package/backend/auth.js +2 -2
- package/backend/batching.js +1 -1
- package/backend/endpoints.js +8 -11
- package/backend/index.js +2 -2
- package/backend/mock-data.js +27 -36
- package/backend/mock-src/classes/logger.js +5 -7
- package/backend/mock-src/classes/utils.js +3 -2
- package/backend/mock-src/ticketmaster.js +4 -4
- package/backend/validator.js +2 -2
- package/config/configs.json +0 -1
- package/dev-server.js +134 -0
- package/exit +209 -0
- package/index.html +78 -8
- package/index.js +1 -1
- package/jsconfig.json +16 -0
- package/package.json +39 -25
- package/postcss.config.js +1 -1
- package/postinstall.js +124 -20
- package/public/android-chrome-192x192.png +0 -0
- package/public/android-chrome-512x512.png +0 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/img/logo_trans.png +0 -0
- package/public/img/necro_logo.png +0 -0
- package/public/manifest.json +16 -10
- package/run +176 -9
- package/src/App.vue +498 -85
- package/src/assets/css/base/reset.scss +43 -0
- package/src/assets/css/base/scroll.scss +114 -0
- package/src/assets/css/base/typography.scss +37 -0
- package/src/assets/css/components/buttons.scss +216 -0
- package/src/assets/css/components/forms.scss +221 -0
- package/src/assets/css/components/modals.scss +13 -0
- package/src/assets/css/components/tables.scss +27 -0
- package/src/assets/css/components/toasts.scss +100 -0
- package/src/assets/css/main.scss +201 -122
- package/src/assets/img/background.svg +2 -2
- package/src/assets/img/background.svg.backup +11 -0
- package/src/assets/img/logo_trans.png +0 -0
- package/src/components/Auth/LoginForm.vue +62 -11
- package/src/components/Editors/Account/Account.vue +116 -40
- package/src/components/Editors/Account/AccountCreator.vue +88 -39
- package/src/components/Editors/Account/AccountView.vue +102 -34
- package/src/components/Editors/Account/CreateAccount.vue +80 -32
- package/src/components/Editors/Profile/CreateProfile.vue +269 -83
- package/src/components/Editors/Profile/Profile.vue +132 -47
- package/src/components/Editors/Profile/ProfileCountryChooser.vue +82 -20
- package/src/components/Editors/Profile/ProfileView.vue +89 -32
- package/src/components/Editors/TagLabel.vue +67 -6
- package/src/components/Editors/TagToggle.vue +7 -2
- package/src/components/Filter/Filter.vue +288 -71
- package/src/components/Filter/FilterPreview.vue +202 -31
- package/src/components/Filter/PriceSortToggle.vue +76 -6
- package/src/components/Table/Header.vue +1 -1
- package/src/components/Table/Row.vue +1 -1
- package/src/components/Table/Table.vue +19 -2
- package/src/components/Tasks/CheckStock.vue +6 -8
- package/src/components/Tasks/Controls/DesktopControls.vue +27 -17
- package/src/components/Tasks/Controls/MobileControls.vue +8 -45
- package/src/components/Tasks/CreateTaskAXS.vue +80 -72
- package/src/components/Tasks/CreateTaskTM.vue +95 -141
- package/src/components/Tasks/MassEdit.vue +4 -6
- package/src/components/Tasks/QuickSettings.vue +199 -30
- package/src/components/Tasks/ScrapeVenue.vue +5 -6
- package/src/components/Tasks/Stats.vue +50 -24
- package/src/components/Tasks/Task.vue +384 -179
- package/src/components/Tasks/TaskLabel.vue +2 -2
- package/src/components/Tasks/TaskView.vue +136 -48
- package/src/components/Tasks/Utilities.vue +25 -10
- package/src/components/Tasks/ViewTask.vue +321 -0
- package/src/components/icons/Bag.vue +1 -1
- package/src/components/icons/Check.vue +5 -0
- package/src/components/icons/Close.vue +21 -0
- package/src/components/icons/CloseX.vue +5 -0
- package/src/components/icons/Eye.vue +6 -0
- package/src/components/icons/Key.vue +21 -0
- package/src/components/icons/Loyalty.vue +1 -1
- package/src/components/icons/Mail.vue +2 -2
- package/src/components/icons/Pencil.vue +21 -0
- package/src/components/icons/Play.vue +2 -2
- package/src/components/icons/Profile.vue +18 -0
- package/src/components/icons/Reload.vue +4 -5
- package/src/components/icons/Sandclock.vue +2 -2
- package/src/components/icons/Sell.vue +21 -0
- package/src/components/icons/Spinner.vue +42 -0
- package/src/components/icons/SquareCheck.vue +18 -0
- package/src/components/icons/SquareUncheck.vue +18 -0
- package/src/components/icons/Stadium.vue +1 -1
- package/src/components/icons/Wildcard.vue +18 -0
- package/src/components/icons/index.js +26 -1
- package/src/components/ui/Modal.vue +107 -13
- package/src/components/ui/Navbar.vue +175 -40
- package/src/components/ui/ReconnectIndicator.vue +351 -55
- package/src/components/ui/Splash.vue +5 -35
- package/src/components/ui/controls/CountryChooser.vue +200 -62
- package/src/components/ui/controls/atomic/Checkbox.vue +119 -10
- package/src/components/ui/controls/atomic/Dropdown.vue +216 -39
- package/src/components/ui/controls/atomic/LoadingButton.vue +45 -0
- package/src/components/ui/controls/atomic/MultiDropdown.vue +300 -37
- package/src/components/ui/controls/atomic/Switch.vue +53 -25
- package/src/composables/useClickOutside.js +21 -0
- package/src/composables/useDropdownPosition.js +174 -0
- package/src/libs/Filter.js +60 -24
- package/src/registerServiceWorker.js +1 -1
- package/src/stores/connection.js +4 -4
- package/src/stores/sampleData.js +172 -199
- package/src/stores/ui.js +55 -20
- package/src/stores/utils.js +30 -4
- package/src/types/index.js +41 -0
- package/src/utils/debug.js +1 -0
- package/src/views/Accounts.vue +116 -50
- package/src/views/Console.vue +394 -79
- package/src/views/Editor.vue +1176 -123
- package/src/views/FilterBuilder.vue +528 -250
- package/src/views/Login.vue +76 -14
- package/src/views/Profiles.vue +119 -34
- package/src/views/Tasks.vue +266 -98
- package/static/offline.html +192 -50
- package/switch-branch.sh +41 -0
- package/tailwind.config.js +119 -27
- package/vite.config.js +73 -16
- package/workbox-config.cjs +63 -0
- package/ICONS.md +0 -21
- package/public/img/background.svg +0 -14
- package/public/img/logo.png +0 -0
- package/public/img/logo_icon.png +0 -0
- package/public/img/logo_icon_2.png +0 -0
- package/src/assets/css/_input.scss +0 -143
- package/src/assets/img/logo.png +0 -0
- package/src/assets/img/logo_icon.png +0 -0
- package/src/assets/img/logo_icon_2.png +0 -0
- package/vue.config.js +0 -32
- package/workbox-config.js +0 -7
|
@@ -1,58 +1,67 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<Header class="text-center">
|
|
4
|
-
<div class="col-span-1 lg:col-span-2
|
|
5
|
-
<Checkbox
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
<div class="table-component">
|
|
3
|
+
<Header class="grid-cols-10 gap-2 text-center lg:grid-cols-12">
|
|
4
|
+
<div class="col-span-1 flex items-center justify-start lg:col-span-2">
|
|
5
|
+
<Checkbox
|
|
6
|
+
class="ml-2 mr-4 flex-shrink-0"
|
|
7
|
+
:toggled="ui.mainCheckbox.tasks"
|
|
8
|
+
@valueUpdate="ui.toggleMainCheckbox('tasks')"
|
|
9
|
+
:isHeader="true" />
|
|
10
|
+
<div class="mx-auto hidden items-center lg:flex" @click="ui.toggleSort('eventId')">
|
|
11
|
+
<EventIcon class="lg:mr-3" />
|
|
12
|
+
<h4 class="hidden lg:flex">Event</h4>
|
|
9
13
|
<DownIcon v-if="ui.sortData.sortBy === 'eventId' && !ui.sortData.reversed" class="ml-1" />
|
|
10
14
|
<UpIcon v-if="ui.sortData.sortBy === 'eventId' && ui.sortData.reversed" class="ml-1" />
|
|
11
15
|
</div>
|
|
12
16
|
</div>
|
|
13
|
-
<div class="
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
<h4 class="hidden ipadlg:flex">Quantity</h4>
|
|
17
|
-
</div>
|
|
18
|
-
<div class="col-span-2 flex items-center justify-center" v-once>
|
|
19
|
-
<TicketIcon class="mr-0 ipadlg:mr-3" />
|
|
20
|
-
<h4 class="hidden ipadlg:flex">Tickets</h4>
|
|
17
|
+
<div class="flex items-center justify-center col-span-2" v-once>
|
|
18
|
+
<TicketIcon class="mr-0 lg:mr-3" />
|
|
19
|
+
<h4 class="hidden lg:flex">Tickets</h4>
|
|
21
20
|
</div>
|
|
22
|
-
<div
|
|
23
|
-
class="
|
|
24
|
-
|
|
25
|
-
>
|
|
26
|
-
<StatusIcon class="mr-0 ipadlg:mr-3" />
|
|
27
|
-
<h4 class="hidden ipadlg:flex">Status</h4>
|
|
21
|
+
<div class="flex items-center justify-center col-span-5 md:col-span-4 lg:col-span-5" @click="ui.toggleSort('status')">
|
|
22
|
+
<StatusIcon class="mr-0 lg:mr-3" />
|
|
23
|
+
<h4 class="hidden lg:flex">Status</h4>
|
|
28
24
|
<DownIcon v-if="ui.sortData.sortBy === 'status' && !ui.sortData.reversed" class="ml-1" />
|
|
29
25
|
<UpIcon v-if="ui.sortData.sortBy === 'status' && ui.sortData.reversed" class="ml-1" />
|
|
30
26
|
</div>
|
|
31
|
-
<div class="
|
|
32
|
-
<ClickIcon class="mr-0
|
|
33
|
-
<h4 class="hidden
|
|
27
|
+
<div class="flex items-center justify-center col-span-2 lg:col-span-3" v-once>
|
|
28
|
+
<ClickIcon class="mr-0 lg:mr-3" />
|
|
29
|
+
<h4 class="hidden lg:flex">Actions</h4>
|
|
34
30
|
</div>
|
|
35
|
-
<div class="absolute right-5 hidden
|
|
36
|
-
<h4 class="">ID</h4>
|
|
31
|
+
<div class="absolute right-5 top-3.5 hidden items-center lg:flex" @click="ui.toggleSort('taskId')">
|
|
32
|
+
<h4 class="text-center text-xs">ID</h4>
|
|
37
33
|
<DownIcon v-if="ui.sortData.sortBy === 'taskId' && !ui.sortData.reversed" class="ml-1" />
|
|
38
34
|
<UpIcon v-if="ui.sortData.sortBy === 'taskId' && ui.sortData.reversed" class="ml-1" />
|
|
39
35
|
</div>
|
|
40
36
|
</Header>
|
|
41
37
|
<div
|
|
42
|
-
class="flex flex-col divide-y
|
|
43
|
-
|
|
44
|
-
<div v-for="(task, i) in getTasksInOrder()" :key="
|
|
45
|
-
<Task :task="task" :class="
|
|
38
|
+
class="hidden-scrollbars stop-pan flex flex-col divide-y divide-dark-650 overflow-y-auto overflow-x-hidden"
|
|
39
|
+
:style="{ maxHeight: dynamicTableHeight }">
|
|
40
|
+
<div v-for="(task, i) in getTasksInOrder()" :key="task.taskId" class="task-row-container">
|
|
41
|
+
<Task :task="task" :class="i % 2 == 1 ? 'table-row-even' : 'table-row-odd'" />
|
|
46
42
|
</div>
|
|
47
43
|
<div
|
|
48
44
|
v-if="getTasksInOrder().length === 0"
|
|
49
|
-
class="flex
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
45
|
+
class="empty-state flex flex-col items-center justify-center py-8 text-center">
|
|
46
|
+
<div
|
|
47
|
+
v-if="
|
|
48
|
+
!ui.queueStats.queued && !ui.queueStats.sleeping && ui.queueStats.nextQueuePasses.length === 0
|
|
49
|
+
">
|
|
50
|
+
<TasksIcon class="mx-auto mb-3 h-12 w-12 text-dark-400 opacity-50" />
|
|
51
|
+
<p class="text-sm text-light-400">No tasks yet</p>
|
|
52
|
+
<p class="mt-1 text-xs text-light-500">Create tasks to get started</p>
|
|
53
|
+
</div>
|
|
54
|
+
<div v-else>
|
|
55
|
+
<TasksIcon class="mx-auto mb-3 h-12 w-12 text-dark-400 opacity-50" />
|
|
56
|
+
<p class="text-sm text-light-400">No tasks match current filters</p>
|
|
57
|
+
<p class="mt-1 text-xs text-light-500">Adjust filters to see tasks</p>
|
|
58
|
+
</div>
|
|
53
59
|
</div>
|
|
54
60
|
</div>
|
|
55
|
-
|
|
61
|
+
|
|
62
|
+
<!-- View Task Modal -->
|
|
63
|
+
<ViewTask v-if="ui.activeModal === 'view-task' && ui.selectedTaskForView" :task="ui.selectedTaskForView" />
|
|
64
|
+
</div>
|
|
56
65
|
</template>
|
|
57
66
|
<style lang="scss" scoped>
|
|
58
67
|
h4 {
|
|
@@ -63,36 +72,48 @@ h4 {
|
|
|
63
72
|
touch-action: pan-y pan-up pan-down;
|
|
64
73
|
}
|
|
65
74
|
|
|
66
|
-
.
|
|
67
|
-
|
|
68
|
-
|
|
75
|
+
.task-row-container {
|
|
76
|
+
min-height: 69px;
|
|
77
|
+
flex-shrink: 0;
|
|
78
|
+
transition: background-color 0.15s ease;
|
|
69
79
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
max-height: 45vh !important;
|
|
80
|
+
&:hover {
|
|
81
|
+
@apply bg-dark-550 !important;
|
|
73
82
|
}
|
|
74
|
-
}
|
|
75
83
|
|
|
76
|
-
@media
|
|
77
|
-
|
|
78
|
-
max-height: 58vh !important;
|
|
84
|
+
@media (max-width: 768px) {
|
|
85
|
+
min-height: 58px;
|
|
79
86
|
}
|
|
87
|
+
|
|
88
|
+
@media (max-width: 480px) and (orientation: portrait) {
|
|
89
|
+
min-height: 50px;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.empty-state {
|
|
94
|
+
@apply bg-dark-400;
|
|
95
|
+
color: #969696;
|
|
96
|
+
font-size: 14px;
|
|
97
|
+
font-weight: 500;
|
|
80
98
|
}
|
|
81
99
|
</style>
|
|
82
100
|
<script setup>
|
|
101
|
+
import { computed, ref, onMounted, onUnmounted } from "vue";
|
|
83
102
|
import { Table, Header } from "@/components/Table";
|
|
84
|
-
import { EventIcon,
|
|
103
|
+
import { EventIcon, TicketIcon, StatusIcon, ClickIcon, DownIcon, UpIcon, TasksIcon } from "@/components/icons";
|
|
85
104
|
import Task from "./Task.vue";
|
|
105
|
+
import ViewTask from "./ViewTask.vue";
|
|
86
106
|
import Checkbox from "@/components/ui/controls/atomic/Checkbox.vue";
|
|
87
107
|
import { useUIStore } from "@/stores/ui";
|
|
88
108
|
|
|
89
109
|
const props = defineProps({
|
|
90
|
-
tasks: { type: Object }
|
|
110
|
+
tasks: { type: Object },
|
|
111
|
+
searchQuery: { type: String, default: '' }
|
|
91
112
|
});
|
|
92
113
|
|
|
93
114
|
const shouldTaskShow = (task) => {
|
|
94
115
|
if (ui.taskFilter === "All") return true;
|
|
95
|
-
else if (ui.taskFilter === "Checkout") return task.expirationTime
|
|
116
|
+
else if (ui.taskFilter === "Checkout") return task.expirationTime;
|
|
96
117
|
else return true;
|
|
97
118
|
};
|
|
98
119
|
|
|
@@ -107,6 +128,8 @@ const siteIdEdgeCases = {
|
|
|
107
128
|
|
|
108
129
|
const getTasksInOrder = () => {
|
|
109
130
|
let out = [];
|
|
131
|
+
const searchLower = props.searchQuery?.toLowerCase().trim() || '';
|
|
132
|
+
|
|
110
133
|
ui.taskIdOrder.forEach((id) => {
|
|
111
134
|
if (props.tasks[id] && !props.tasks[id]?.hidden) {
|
|
112
135
|
const task = props.tasks[id];
|
|
@@ -118,9 +141,74 @@ const getTasksInOrder = () => {
|
|
|
118
141
|
return;
|
|
119
142
|
if (ui.currentEvent && task.eventId !== ui.currentEvent) return;
|
|
120
143
|
if (!shouldTaskShow(task)) return;
|
|
144
|
+
|
|
145
|
+
// Search filter
|
|
146
|
+
if (searchLower) {
|
|
147
|
+
const searchableText = [
|
|
148
|
+
task.eventId,
|
|
149
|
+
task.eventName,
|
|
150
|
+
task.eventVenue,
|
|
151
|
+
task.email,
|
|
152
|
+
task.taskId,
|
|
153
|
+
task.status,
|
|
154
|
+
task.profileName,
|
|
155
|
+
task.presaleCode,
|
|
156
|
+
task.reservedTicketsList
|
|
157
|
+
].filter(Boolean).join(' ').toLowerCase();
|
|
158
|
+
|
|
159
|
+
if (!searchableText.includes(searchLower)) return;
|
|
160
|
+
}
|
|
161
|
+
|
|
121
162
|
out.push(task);
|
|
122
163
|
}
|
|
123
164
|
});
|
|
124
165
|
return out;
|
|
125
166
|
};
|
|
167
|
+
|
|
168
|
+
// Dynamic height calculation to prevent page scrolling
|
|
169
|
+
const windowHeight = ref(window.innerHeight);
|
|
170
|
+
const windowWidth = ref(window.innerWidth);
|
|
171
|
+
|
|
172
|
+
const updateDimensions = () => {
|
|
173
|
+
windowHeight.value = window.innerHeight;
|
|
174
|
+
windowWidth.value = window.innerWidth;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
onMounted(() => {
|
|
178
|
+
window.addEventListener("resize", updateDimensions);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
onUnmounted(() => {
|
|
182
|
+
window.removeEventListener("resize", updateDimensions);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const dynamicTableHeight = computed(() => {
|
|
186
|
+
// Calculate available space for table
|
|
187
|
+
const headerHeight = 55; // Header + navbar
|
|
188
|
+
const titleHeight = 45; // Tasks title and mobile controls
|
|
189
|
+
const controlsHeight = windowWidth.value >= 650 ? 55 : 0; // Desktop controls
|
|
190
|
+
// On desktop: stats + filters all in one row (45px)
|
|
191
|
+
// On mobile: stats row (40px) + filters stacked (90px) = 130px
|
|
192
|
+
const filtersAndStatsHeight = windowWidth.value >= 768
|
|
193
|
+
? (ui.queueStats.show ? 50 : 45) // Desktop: single row
|
|
194
|
+
: (ui.queueStats.show ? 130 : 90); // Mobile: stats row + stacked filters
|
|
195
|
+
const utilitiesHeight = windowWidth.value <= 768 ? 90 : 160; // Utilities section height (ensure buttons fully visible)
|
|
196
|
+
const margins =
|
|
197
|
+
windowWidth.value >= 1024 ? 20 : windowWidth.value <= 480 && windowHeight.value > windowWidth.value ? 8 : 12;
|
|
198
|
+
|
|
199
|
+
const totalUsedSpace =
|
|
200
|
+
headerHeight + titleHeight + controlsHeight + filtersAndStatsHeight + utilitiesHeight + margins;
|
|
201
|
+
const availableHeight = windowHeight.value - totalUsedSpace;
|
|
202
|
+
|
|
203
|
+
// Calculate row height based on screen size
|
|
204
|
+
const rowHeight = windowWidth.value <= 768 ? 58 : 69; // Mobile vs desktop row height
|
|
205
|
+
const minRowsToShow = 2; // Always show at least 2 rows
|
|
206
|
+
const minHeight = minRowsToShow * rowHeight;
|
|
207
|
+
|
|
208
|
+
// Calculate how many complete rows can fit
|
|
209
|
+
const maxCompleteRows = Math.floor(Math.max(availableHeight, minHeight) / rowHeight) + 1;
|
|
210
|
+
const exactHeight = maxCompleteRows * rowHeight;
|
|
211
|
+
|
|
212
|
+
return exactHeight + "px";
|
|
213
|
+
});
|
|
126
214
|
</script>
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="grid grid-cols-1 gap-3 lg:grid-cols-1" v-
|
|
2
|
+
<div class="grid grid-cols-1 gap-3 lg:grid-cols-1" v-if="ui.currentModule == 'TM'">
|
|
3
3
|
<div class="lg:justify-self-end">
|
|
4
|
-
<h4 class="hidden lg:block text-white opacity-40 uppercase font-medium">Utils</h4>
|
|
5
|
-
<div class="flex gap-3">
|
|
6
|
-
<button class="button-default
|
|
7
|
-
<ScrapeIcon />
|
|
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')">
|
|
8
7
|
Scrape Venue
|
|
8
|
+
<ScrapeIcon />
|
|
9
9
|
</button>
|
|
10
|
-
<button class="button-default w-44" @click="ui.toggleModal('check-stock')">
|
|
11
|
-
|
|
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')">
|
|
11
|
+
Check Stock
|
|
12
|
+
<BoxIcon />
|
|
12
13
|
</button>
|
|
13
|
-
<!-- Mobile Label -->
|
|
14
14
|
</div>
|
|
15
15
|
<h4 class="text-white opacity-40 uppercase font-medium block lg:hidden">Utils</h4>
|
|
16
16
|
</div>
|
|
@@ -23,10 +23,25 @@ import { useUIStore } from "@/stores/ui";
|
|
|
23
23
|
const ui = useUIStore();
|
|
24
24
|
</script>
|
|
25
25
|
<style lang="scss" scoped>
|
|
26
|
-
|
|
26
|
+
.utility-btn {
|
|
27
27
|
height: 50px;
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
@media (max-width: 768px) {
|
|
30
|
+
height: 40px;
|
|
31
|
+
font-size: 0.75rem;
|
|
32
|
+
}
|
|
29
33
|
}
|
|
34
|
+
|
|
35
|
+
button {
|
|
36
|
+
font-size: 0.75rem;
|
|
37
|
+
|
|
38
|
+
svg {
|
|
39
|
+
width: 14px;
|
|
40
|
+
height: 14px;
|
|
41
|
+
flex-shrink: 0;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
30
45
|
h4 {
|
|
31
46
|
font-size: 12px;
|
|
32
47
|
}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Modal>
|
|
3
|
+
<template #header>
|
|
4
|
+
<span class="flex">View Task <EyeIcon class="ml-4 w-4" /></span>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<!-- Task Overview Card -->
|
|
8
|
+
<div class="section-card mb-4 mt-4">
|
|
9
|
+
<h3 class="section-title">Task Overview</h3>
|
|
10
|
+
<div class="grid grid-cols-1 gap-3">
|
|
11
|
+
<div class="info-row copyable" @click="copy(task.taskId)">
|
|
12
|
+
<span class="info-icon flex items-center justify-center text-base font-bold">#</span>
|
|
13
|
+
<span class="info-label">Task ID</span>
|
|
14
|
+
<span class="info-value">{{ task.taskId }}</span>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="info-row" @click="copy(task.eventId)">
|
|
17
|
+
<StadiumIcon class="info-icon" />
|
|
18
|
+
<span class="info-label">Event ID</span>
|
|
19
|
+
<span class="info-value copyable">{{ task.eventId }}</span>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="info-row" v-if="task.eventName">
|
|
22
|
+
<StadiumWhiteIcon class="info-icon" />
|
|
23
|
+
<span class="info-label">Event Name</span>
|
|
24
|
+
<span class="info-value">{{ task.eventName }}</span>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="info-row" v-if="task.eventVenue">
|
|
27
|
+
<StadiumWhiteIcon class="info-icon" />
|
|
28
|
+
<span class="info-label">Venue</span>
|
|
29
|
+
<span class="info-value">{{ task.eventVenue }}</span>
|
|
30
|
+
</div>
|
|
31
|
+
<div class="info-row" v-if="task.eventLocalDate">
|
|
32
|
+
<StadiumWhiteIcon class="info-icon" />
|
|
33
|
+
<span class="info-label">Date</span>
|
|
34
|
+
<span class="info-value">{{ formatDate(task.eventLocalDate) }}</span>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="info-row">
|
|
37
|
+
<div class="flex items-center gap-2">
|
|
38
|
+
<div class="status-indicator" :class="colorToClass(task.active || task.status.toLowerCase() === 'idle' ? task.statusColor : 'red')"></div>
|
|
39
|
+
<span class="info-label">Status</span>
|
|
40
|
+
</div>
|
|
41
|
+
<span class="info-value uppercase font-semibold whitespace-normal break-words">{{ task.status }}</span>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<!-- Account Details Card -->
|
|
47
|
+
<div class="section-card mb-4">
|
|
48
|
+
<h3 class="section-title">Account Details</h3>
|
|
49
|
+
<div class="grid grid-cols-1 gap-3">
|
|
50
|
+
<div class="info-row" v-if="task.email" @click="copy(task.email)">
|
|
51
|
+
<MailIcon class="info-icon" />
|
|
52
|
+
<span class="info-label">Email</span>
|
|
53
|
+
<span class="info-value copyable">{{ task.email }}</span>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="info-row" v-if="task.password" @click="copy(task.password)">
|
|
56
|
+
<KeyIcon class="info-icon" />
|
|
57
|
+
<span class="info-label">Password</span>
|
|
58
|
+
<span class="info-value copyable">{{ showPassword ? task.password : '••••••••' }}</span>
|
|
59
|
+
<button @click.stop="showPassword = !showPassword" class="ml-auto">
|
|
60
|
+
<EyeToggle :visible="showPassword" />
|
|
61
|
+
</button>
|
|
62
|
+
</div>
|
|
63
|
+
<div class="info-row" v-if="!task.email && !task.password">
|
|
64
|
+
<MailIcon class="info-icon" />
|
|
65
|
+
<span class="info-label">Account</span>
|
|
66
|
+
<span class="info-value text-light-500">No account chosen</span>
|
|
67
|
+
</div>
|
|
68
|
+
<div class="info-row" v-if="task.profileName">
|
|
69
|
+
<ProfileIcon class="info-icon" />
|
|
70
|
+
<span class="info-label">Profile</span>
|
|
71
|
+
<span class="info-value">{{ task.profileName }}</span>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<!-- Task Configuration -->
|
|
77
|
+
<div class="section-card mb-4">
|
|
78
|
+
<h3 class="section-title">Task Configuration</h3>
|
|
79
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
80
|
+
<div class="info-row">
|
|
81
|
+
<BagIcon class="info-icon" />
|
|
82
|
+
<span class="info-label">Ticket Quantity</span>
|
|
83
|
+
<span class="info-value">{{ task.quantity }}</span>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="info-row">
|
|
86
|
+
<ScannerIcon class="info-icon" />
|
|
87
|
+
<span class="info-label">Account Tag</span>
|
|
88
|
+
<span class="info-value">{{ task.accountTag || 'None' }}</span>
|
|
89
|
+
</div>
|
|
90
|
+
<div class="info-row">
|
|
91
|
+
<SellIcon class="info-icon" />
|
|
92
|
+
<span class="info-label">Profile Tags</span>
|
|
93
|
+
<span class="info-value">{{ task.profileTags?.join(', ') || 'None' }}</span>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="info-row" v-if="task.presaleCode" @click="copy(task.presaleCode)">
|
|
96
|
+
<PencilIcon class="info-icon" />
|
|
97
|
+
<span class="info-label">Presale Code</span>
|
|
98
|
+
<span class="info-value copyable">{{ task.presaleCode }}</span>
|
|
99
|
+
</div>
|
|
100
|
+
<div class="info-row" v-if="task.startOffset">
|
|
101
|
+
<ShieldIcon class="info-icon" />
|
|
102
|
+
<span class="info-label">Start Offset</span>
|
|
103
|
+
<span class="info-value">{{ task.startOffset }} min</span>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<!-- Task Settings Toggles -->
|
|
109
|
+
<div class="section-card mb-4">
|
|
110
|
+
<h3 class="section-title mb-3">Task Settings</h3>
|
|
111
|
+
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
|
|
112
|
+
<div class="toggle-item">
|
|
113
|
+
<div class="toggle-label">
|
|
114
|
+
<TimerIcon class="w-4 h-4" />
|
|
115
|
+
<span>Smart Timer</span>
|
|
116
|
+
</div>
|
|
117
|
+
<Switch v-model="toggles.smartTimer" disabled />
|
|
118
|
+
</div>
|
|
119
|
+
<div class="toggle-item">
|
|
120
|
+
<div class="toggle-label">
|
|
121
|
+
<GroupIcon class="w-4 h-4" />
|
|
122
|
+
<span>Login Later</span>
|
|
123
|
+
</div>
|
|
124
|
+
<Switch v-model="toggles.loginAfterCart" disabled />
|
|
125
|
+
</div>
|
|
126
|
+
<div class="toggle-item">
|
|
127
|
+
<div class="toggle-label">
|
|
128
|
+
<HandIcon class="w-4 h-4" />
|
|
129
|
+
<span>Manual</span>
|
|
130
|
+
</div>
|
|
131
|
+
<Switch v-model="toggles.manual" disabled />
|
|
132
|
+
</div>
|
|
133
|
+
<div class="toggle-item">
|
|
134
|
+
<div class="toggle-label">
|
|
135
|
+
<SavingsIcon class="w-4 h-4" />
|
|
136
|
+
<span>Do Not Pay</span>
|
|
137
|
+
</div>
|
|
138
|
+
<Switch v-model="toggles.doNotPay" disabled />
|
|
139
|
+
</div>
|
|
140
|
+
<div class="toggle-item">
|
|
141
|
+
<div class="toggle-label">
|
|
142
|
+
<LoyaltyIcon class="w-4 h-4" />
|
|
143
|
+
<span>Presale Mode</span>
|
|
144
|
+
</div>
|
|
145
|
+
<Switch v-model="toggles.presaleMode" disabled />
|
|
146
|
+
</div>
|
|
147
|
+
<div class="toggle-item">
|
|
148
|
+
<div class="toggle-label">
|
|
149
|
+
<SkiIcon class="w-4 h-4" />
|
|
150
|
+
<span>Quick Queue</span>
|
|
151
|
+
</div>
|
|
152
|
+
<Switch v-model="toggles.quickQueue" disabled />
|
|
153
|
+
</div>
|
|
154
|
+
<div class="toggle-item">
|
|
155
|
+
<div class="toggle-label">
|
|
156
|
+
<SandclockIcon class="w-4 h-4" />
|
|
157
|
+
<span>Aged Account</span>
|
|
158
|
+
</div>
|
|
159
|
+
<Switch v-model="toggles.agedAccount" disabled />
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
</Modal>
|
|
164
|
+
</template>
|
|
165
|
+
|
|
166
|
+
<script setup>
|
|
167
|
+
import { ref, computed, watch } from 'vue';
|
|
168
|
+
import Modal from '@/components/ui/Modal.vue';
|
|
169
|
+
import Switch from '@/components/ui/controls/atomic/Switch.vue';
|
|
170
|
+
import EyeToggle from '@/components/ui/controls/EyeToggle.vue';
|
|
171
|
+
import { useUIStore } from '@/stores/ui';
|
|
172
|
+
import {
|
|
173
|
+
EyeIcon,
|
|
174
|
+
StadiumIcon,
|
|
175
|
+
StadiumWhiteIcon,
|
|
176
|
+
MailIcon,
|
|
177
|
+
KeyIcon,
|
|
178
|
+
ProfileIcon,
|
|
179
|
+
BagIcon,
|
|
180
|
+
ScannerIcon,
|
|
181
|
+
SellIcon,
|
|
182
|
+
PencilIcon,
|
|
183
|
+
ShieldIcon,
|
|
184
|
+
TimerIcon,
|
|
185
|
+
GroupIcon,
|
|
186
|
+
HandIcon,
|
|
187
|
+
SavingsIcon,
|
|
188
|
+
LoyaltyIcon,
|
|
189
|
+
SkiIcon,
|
|
190
|
+
SandclockIcon
|
|
191
|
+
} from '@/components/icons';
|
|
192
|
+
|
|
193
|
+
const ui = useUIStore();
|
|
194
|
+
const showPassword = ref(false);
|
|
195
|
+
|
|
196
|
+
const props = defineProps({
|
|
197
|
+
task: {
|
|
198
|
+
type: Object,
|
|
199
|
+
required: true
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
const toggles = computed(() => ({
|
|
205
|
+
smartTimer: props.task.smartTimer,
|
|
206
|
+
loginAfterCart: props.task.loginAfterCart,
|
|
207
|
+
manual: props.task.manual,
|
|
208
|
+
doNotPay: props.task.doNotPay,
|
|
209
|
+
presaleMode: props.task.presaleMode,
|
|
210
|
+
quickQueue: props.task.quickQueue,
|
|
211
|
+
agedAccount: props.task.agedAccount
|
|
212
|
+
}));
|
|
213
|
+
|
|
214
|
+
const copy = (text) => {
|
|
215
|
+
navigator.clipboard.writeText(text);
|
|
216
|
+
ui.showSuccess(`Copied: ${text}`);
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const formatDate = (dateString) => {
|
|
220
|
+
if (!dateString) return '';
|
|
221
|
+
const date = new Date(dateString);
|
|
222
|
+
return date.toLocaleString();
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const colorToClass = (color) => {
|
|
226
|
+
const colorMap = {
|
|
227
|
+
red: 'bg-red-400',
|
|
228
|
+
green: 'bg-green-400',
|
|
229
|
+
yellow: 'bg-yellow-400',
|
|
230
|
+
blue: 'bg-blue-400'
|
|
231
|
+
};
|
|
232
|
+
return colorMap[color?.toLowerCase()] || 'bg-gray-400';
|
|
233
|
+
};
|
|
234
|
+
</script>
|
|
235
|
+
|
|
236
|
+
<style lang="scss" scoped>
|
|
237
|
+
.section-card {
|
|
238
|
+
@apply rounded-lg border p-4;
|
|
239
|
+
background: oklch(0.2046 0 0);
|
|
240
|
+
border-color: oklch(0.2809 0 0);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.section-title {
|
|
244
|
+
@apply text-sm font-semibold mb-3;
|
|
245
|
+
color: oklch(0.90 0 0);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.info-row {
|
|
249
|
+
@apply flex items-center gap-3 px-3 py-2 rounded-lg;
|
|
250
|
+
background: oklch(0.2603 0 0);
|
|
251
|
+
border: 1px solid oklch(0.2809 0 0);
|
|
252
|
+
min-height: 40px;
|
|
253
|
+
|
|
254
|
+
&.copyable {
|
|
255
|
+
cursor: pointer;
|
|
256
|
+
|
|
257
|
+
&:hover {
|
|
258
|
+
border-color: oklch(0.72 0.15 145);
|
|
259
|
+
background: oklch(0.72 0.15 145 / 0.08);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.info-icon {
|
|
265
|
+
@apply w-4 h-4 flex-shrink-0;
|
|
266
|
+
color: oklch(0.90 0 0) !important;
|
|
267
|
+
|
|
268
|
+
svg {
|
|
269
|
+
color: oklch(0.90 0 0) !important;
|
|
270
|
+
width: 16px !important;
|
|
271
|
+
height: 16px !important;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.info-label {
|
|
276
|
+
@apply text-xs font-medium flex-shrink-0;
|
|
277
|
+
color: oklch(0.65 0 0);
|
|
278
|
+
min-width: 100px;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.info-value {
|
|
282
|
+
@apply text-sm flex-1;
|
|
283
|
+
color: oklch(0.90 0 0);
|
|
284
|
+
overflow-wrap: break-word;
|
|
285
|
+
word-break: break-word;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.copyable {
|
|
289
|
+
cursor: pointer;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.toggle-item {
|
|
293
|
+
@apply flex flex-col items-center gap-2;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.toggle-label {
|
|
297
|
+
@apply flex items-center gap-2 text-xs;
|
|
298
|
+
color: oklch(0.90 0 0);
|
|
299
|
+
|
|
300
|
+
svg {
|
|
301
|
+
color: oklch(0.90 0 0) !important;
|
|
302
|
+
width: 16px !important;
|
|
303
|
+
height: 16px !important;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.status-indicator {
|
|
308
|
+
@apply w-2 h-2 rounded-full flex-shrink-0;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
@media (max-width: 768px) {
|
|
312
|
+
.info-label {
|
|
313
|
+
min-width: 80px;
|
|
314
|
+
font-size: 11px;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.info-value {
|
|
318
|
+
font-size: 13px;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
</style>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<svg width="15" height="18" viewBox="0 0 15 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
3
|
<path
|
|
4
4
|
d="M1.95833 17.4167C1.52292 17.4167 1.15004 17.2618 0.839708 16.952C0.529903 16.6416 0.375 16.2688 0.375 15.8334V6.33335C0.375 5.89794 0.529903 5.52533 0.839708 5.21552C1.15004 4.90519 1.52292 4.75002 1.95833 4.75002H3.54167C3.54167 3.65488 3.92774 2.72124 4.69988 1.9491C5.47149 1.17749 6.40486 0.791687 7.5 0.791687C8.59514 0.791687 9.52878 1.17749 10.3009 1.9491C11.0725 2.72124 11.4583 3.65488 11.4583 4.75002H13.0417C13.4771 4.75002 13.85 4.90519 14.1603 5.21552C14.4701 5.52533 14.625 5.89794 14.625 6.33335V15.8334C14.625 16.2688 14.4701 16.6416 14.1603 16.952C13.85 17.2618 13.4771 17.4167 13.0417 17.4167H1.95833ZM1.95833 15.8334H13.0417V6.33335H1.95833V15.8334ZM7.5 11.0834C8.59514 11.0834 9.52878 10.6973 10.3009 9.92515C11.0725 9.15353 11.4583 8.22016 11.4583 7.12502H9.875C9.875 7.78474 9.6441 8.34551 9.18229 8.80731C8.72049 9.26912 8.15972 9.50002 7.5 9.50002C6.84028 9.50002 6.27951 9.26912 5.81771 8.80731C5.3559 8.34551 5.125 7.78474 5.125 7.12502H3.54167C3.54167 8.22016 3.92774 9.15353 4.69988 9.92515C5.47149 10.6973 6.40486 11.0834 7.5 11.0834ZM5.125 4.75002H9.875C9.875 4.0903 9.6441 3.52953 9.18229 3.06773C8.72049 2.60592 8.15972 2.37502 7.5 2.37502C6.84028 2.37502 6.27951 2.60592 5.81771 3.06773C5.3559 3.52953 5.125 4.0903 5.125 4.75002Z"
|
|
5
|
-
fill="
|
|
5
|
+
fill="currentColor"
|
|
6
6
|
/>
|
|
7
7
|
</svg>
|
|
8
8
|
</template>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg
|
|
3
|
+
width="17"
|
|
4
|
+
height="17"
|
|
5
|
+
viewBox="0 0 17 17"
|
|
6
|
+
fill="none"
|
|
7
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
8
|
+
class="close-icon"
|
|
9
|
+
>
|
|
10
|
+
<path
|
|
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
|
+
fill="currentColor"
|
|
13
|
+
/>
|
|
14
|
+
</svg>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<style scoped>
|
|
18
|
+
.close-icon {
|
|
19
|
+
@apply w-4 h-4;
|
|
20
|
+
}
|
|
21
|
+
</style>
|