@necrolab/dashboard 0.4.3
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/.claude/settings.local.json +45 -0
- package/.eslintrc.js +24 -0
- package/.prettierignore +1 -0
- package/.prettierrc +10 -0
- package/.vscode/extensions.json +3 -0
- package/ICONS.md +21 -0
- package/README.md +65 -0
- package/backend/api.js +430 -0
- package/backend/auth.js +62 -0
- package/backend/batching.js +43 -0
- package/backend/endpoints.js +343 -0
- package/backend/index.js +23 -0
- package/backend/mock-data.js +66 -0
- package/backend/mock-src/classes/logger.js +112 -0
- package/backend/mock-src/classes/utils.js +42 -0
- package/backend/mock-src/ticketmaster.js +92 -0
- package/backend/validator.js +62 -0
- package/config/configs.json +20 -0
- package/config/filter.json +3 -0
- package/config/presale.csv +3 -0
- package/config/proxies.txt +6 -0
- package/config/used-codes.json +4 -0
- package/index.html +114 -0
- package/index.js +2 -0
- package/jsconfig.json +16 -0
- package/package.json +48 -0
- package/postcss.config.js +6 -0
- package/postinstall.js +9 -0
- 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/flags/ae.svg +1 -0
- package/public/flags/at.svg +1 -0
- package/public/flags/au.svg +1 -0
- package/public/flags/be.svg +1 -0
- package/public/flags/ch.svg +1 -0
- package/public/flags/cz.svg +1 -0
- package/public/flags/de.svg +1 -0
- package/public/flags/dk.svg +1 -0
- package/public/flags/es.svg +1 -0
- package/public/flags/nl.svg +1 -0
- package/public/flags/no.svg +1 -0
- package/public/flags/nz.svg +1 -0
- package/public/flags/pl.svg +1 -0
- package/public/flags/se.svg +1 -0
- package/public/flags/uk.svg +1 -0
- package/public/flags/us.svg +1 -0
- package/public/img/award.svg +3 -0
- package/public/img/background.svg +14 -0
- package/public/img/bag_w.svg +12 -0
- package/public/img/banks/amex.svg +4 -0
- package/public/img/banks/mastercard.svg +4 -0
- package/public/img/banks/visa.svg +4 -0
- package/public/img/camera.svg +3 -0
- package/public/img/close.svg +3 -0
- package/public/img/controls/disable.svg +5 -0
- package/public/img/controls/enable.svg +5 -0
- package/public/img/groups.svg +3 -0
- package/public/img/hand.svg +3 -0
- package/public/img/key.svg +3 -0
- 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/public/img/logo_trans.png +0 -0
- package/public/img/loyalty.svg +3 -0
- package/public/img/mail.svg +3 -0
- package/public/img/pencil.svg +3 -0
- package/public/img/profile.svg +4 -0
- package/public/img/reload.svg +3 -0
- package/public/img/sandclock.svg +25 -0
- package/public/img/save.svg +5 -0
- package/public/img/savings.svg +3 -0
- package/public/img/scanner.svg +3 -0
- package/public/img/sell.svg +3 -0
- package/public/img/shield.svg +3 -0
- package/public/img/ski.svg +3 -0
- package/public/img/stadium.svg +8 -0
- package/public/img/stadium_w.svg +8 -0
- package/public/img/timer.svg +3 -0
- package/public/manifest.json +27 -0
- package/public/robots.txt +2 -0
- package/run +10 -0
- package/src/App.vue +307 -0
- package/src/assets/css/_input.scss +197 -0
- package/src/assets/css/main.scss +269 -0
- package/src/assets/css/tailwind.css +3 -0
- package/src/assets/img/award.svg +3 -0
- package/src/assets/img/background.svg +11 -0
- package/src/assets/img/camera.svg +3 -0
- package/src/assets/img/close.svg +3 -0
- package/src/assets/img/eyes/closed.svg +13 -0
- package/src/assets/img/eyes/open.svg +12 -0
- package/src/assets/img/groups.svg +3 -0
- package/src/assets/img/hand.svg +3 -0
- package/src/assets/img/key.svg +3 -0
- 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/src/assets/img/logo_trans.png +0 -0
- package/src/assets/img/loyalty.svg +3 -0
- package/src/assets/img/mail.svg +3 -0
- package/src/assets/img/pencil.svg +3 -0
- package/src/assets/img/reload.svg +3 -0
- package/src/assets/img/savings.svg +3 -0
- package/src/assets/img/scanner.svg +3 -0
- package/src/assets/img/sell.svg +3 -0
- package/src/assets/img/shield.svg +3 -0
- package/src/assets/img/ski.svg +3 -0
- package/src/assets/img/square_check.svg +5 -0
- package/src/assets/img/square_uncheck.svg +5 -0
- package/src/assets/img/stadium.svg +8 -0
- package/src/assets/img/timer.svg +3 -0
- package/src/assets/img/wildcard.svg +7 -0
- package/src/components/Auth/LoginForm.vue +48 -0
- package/src/components/Editors/Account/Account.vue +119 -0
- package/src/components/Editors/Account/AccountCreator.vue +147 -0
- package/src/components/Editors/Account/AccountView.vue +87 -0
- package/src/components/Editors/Account/CreateAccount.vue +106 -0
- package/src/components/Editors/Profile/CreateProfile.vue +321 -0
- package/src/components/Editors/Profile/Profile.vue +142 -0
- package/src/components/Editors/Profile/ProfileCountryChooser.vue +75 -0
- package/src/components/Editors/Profile/ProfileView.vue +96 -0
- package/src/components/Editors/TagLabel.vue +16 -0
- package/src/components/Editors/TagToggle.vue +41 -0
- package/src/components/Filter/Filter.vue +409 -0
- package/src/components/Filter/FilterPreview.vue +236 -0
- package/src/components/Filter/PriceSortToggle.vue +105 -0
- package/src/components/Table/Header.vue +5 -0
- package/src/components/Table/Row.vue +5 -0
- package/src/components/Table/Table.vue +14 -0
- package/src/components/Table/index.js +4 -0
- package/src/components/Tasks/CheckStock.vue +62 -0
- package/src/components/Tasks/Controls/DesktopControls.vue +73 -0
- package/src/components/Tasks/Controls/MobileControls.vue +32 -0
- package/src/components/Tasks/Controls/index.js +3 -0
- package/src/components/Tasks/CreateTaskAXS.vue +339 -0
- package/src/components/Tasks/CreateTaskTM.vue +459 -0
- package/src/components/Tasks/MassEdit.vue +50 -0
- package/src/components/Tasks/QuickSettings.vue +167 -0
- package/src/components/Tasks/ScrapeVenue.vue +42 -0
- package/src/components/Tasks/Stats.vue +66 -0
- package/src/components/Tasks/Task.vue +296 -0
- package/src/components/Tasks/TaskLabel.vue +20 -0
- package/src/components/Tasks/TaskView.vue +126 -0
- package/src/components/Tasks/Utilities.vue +33 -0
- package/src/components/icons/Award.vue +8 -0
- package/src/components/icons/Bag.vue +8 -0
- package/src/components/icons/BagWhite.vue +8 -0
- package/src/components/icons/Box.vue +8 -0
- package/src/components/icons/Camera.vue +8 -0
- package/src/components/icons/Cart.vue +8 -0
- package/src/components/icons/Check.vue +5 -0
- package/src/components/icons/Checkmark.vue +11 -0
- package/src/components/icons/Click.vue +8 -0
- package/src/components/icons/Close.vue +21 -0
- package/src/components/icons/CloseX.vue +5 -0
- package/src/components/icons/Console.vue +13 -0
- package/src/components/icons/Down.vue +8 -0
- package/src/components/icons/Edit.vue +13 -0
- package/src/components/icons/Event.vue +8 -0
- package/src/components/icons/Expand.vue +8 -0
- package/src/components/icons/Filter.vue +13 -0
- package/src/components/icons/Gear.vue +8 -0
- package/src/components/icons/Group.vue +8 -0
- package/src/components/icons/Hand.vue +8 -0
- package/src/components/icons/Key.vue +21 -0
- package/src/components/icons/Logout.vue +13 -0
- package/src/components/icons/Loyalty.vue +8 -0
- package/src/components/icons/Mail.vue +8 -0
- package/src/components/icons/Menu.vue +8 -0
- package/src/components/icons/Pause.vue +5 -0
- package/src/components/icons/Pencil.vue +21 -0
- package/src/components/icons/Play.vue +8 -0
- package/src/components/icons/Plus.vue +8 -0
- package/src/components/icons/Profile.vue +18 -0
- package/src/components/icons/Reload.vue +7 -0
- package/src/components/icons/Sandclock.vue +33 -0
- package/src/components/icons/Savings.vue +8 -0
- package/src/components/icons/Scanner.vue +8 -0
- package/src/components/icons/Scrape.vue +8 -0
- package/src/components/icons/Sell.vue +21 -0
- package/src/components/icons/Shield.vue +8 -0
- package/src/components/icons/Shrink.vue +8 -0
- package/src/components/icons/Ski.vue +8 -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 +13 -0
- package/src/components/icons/StadiumWhite.vue +13 -0
- package/src/components/icons/Status.vue +8 -0
- package/src/components/icons/Tag.vue +8 -0
- package/src/components/icons/Tasks.vue +13 -0
- package/src/components/icons/Ticket.vue +8 -0
- package/src/components/icons/Timer.vue +8 -0
- package/src/components/icons/Trash.vue +8 -0
- package/src/components/icons/Up.vue +10 -0
- package/src/components/icons/Wildcard.vue +18 -0
- package/src/components/icons/index.js +111 -0
- package/src/components/ui/Modal.vue +61 -0
- package/src/components/ui/Navbar.vue +207 -0
- package/src/components/ui/ReconnectIndicator.vue +90 -0
- package/src/components/ui/Splash.vue +24 -0
- package/src/components/ui/controls/CountryChooser.vue +87 -0
- package/src/components/ui/controls/EyeToggle.vue +11 -0
- package/src/components/ui/controls/atomic/Checkbox.vue +28 -0
- package/src/components/ui/controls/atomic/Dropdown.vue +138 -0
- package/src/components/ui/controls/atomic/LoadingButton.vue +45 -0
- package/src/components/ui/controls/atomic/MultiDropdown.vue +262 -0
- package/src/components/ui/controls/atomic/Switch.vue +84 -0
- package/src/libs/Filter.js +593 -0
- package/src/libs/ansii.js +565 -0
- package/src/libs/panzoom.js +1413 -0
- package/src/main.js +23 -0
- package/src/registerServiceWorker.js +32 -0
- package/src/router/index.js +65 -0
- package/src/stores/cities.json +1 -0
- package/src/stores/connection.js +399 -0
- package/src/stores/countries.js +88 -0
- package/src/stores/logger.js +103 -0
- package/src/stores/requests.js +88 -0
- package/src/stores/sampleData.js +1034 -0
- package/src/stores/ui.js +584 -0
- package/src/stores/utils.js +554 -0
- package/src/types/index.js +42 -0
- package/src/utils/debug.js +1 -0
- package/src/views/Accounts.vue +191 -0
- package/src/views/Console.vue +224 -0
- package/src/views/Editor.vue +785 -0
- package/src/views/FilterBuilder.vue +785 -0
- package/src/views/Login.vue +27 -0
- package/src/views/Profiles.vue +209 -0
- package/src/views/Tasks.vue +157 -0
- package/static/offline.html +184 -0
- package/tailwind.config.js +57 -0
- package/vite.config.js +63 -0
- package/vue.config.js +32 -0
- package/workbox-config.js +66 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex flex-col justify-center mt-20" v-once>
|
|
3
|
+
<div class="mx-auto flex w-auto rounded-xl mb-8">
|
|
4
|
+
<img src="@/assets/img/logo_trans.png" class="h-14 mr-4 z-30 object-cover" alt="Logo: Necro" />
|
|
5
|
+
</div>
|
|
6
|
+
<h2 class="text-3xl text-white text-center font-bold mb-4">Login</h2>
|
|
7
|
+
|
|
8
|
+
<div class="login">
|
|
9
|
+
<LoginForm />
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
</template>
|
|
13
|
+
<script setup>
|
|
14
|
+
import LoginForm from "@/components/Auth/LoginForm.vue";
|
|
15
|
+
</script>
|
|
16
|
+
<style lang="scss" scoped>
|
|
17
|
+
.login {
|
|
18
|
+
// @apply m-auto;
|
|
19
|
+
@media (min-width: 900px) {
|
|
20
|
+
width: 400px;
|
|
21
|
+
@apply m-auto;
|
|
22
|
+
}
|
|
23
|
+
@media (max-width: 899px) {
|
|
24
|
+
@apply px-6;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
</style>
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<div class="flex-between pt-5 pb-2">
|
|
4
|
+
<!-- Heading -->
|
|
5
|
+
<div class="flex-center gap-4">
|
|
6
|
+
<GroupIcon class="cursor-pointer smooth-hover text-white" />
|
|
7
|
+
<h4 class="text-heading">
|
|
8
|
+
Profiles
|
|
9
|
+
<span class="text-subheading pl-1">{{ ui.getSelectedProfiles().length }}</span>
|
|
10
|
+
</h4>
|
|
11
|
+
</div>
|
|
12
|
+
<ul class="mobile-icons">
|
|
13
|
+
<li>
|
|
14
|
+
<EyeToggle v-model="privacy" />
|
|
15
|
+
</li>
|
|
16
|
+
<li>
|
|
17
|
+
<button
|
|
18
|
+
:disabled="ui.disabledButtons['add-profiles']"
|
|
19
|
+
@click="ui.toggleModal('create-profile', true)"
|
|
20
|
+
class="smooth-hover"
|
|
21
|
+
>
|
|
22
|
+
<PlusIcon class="w-4 h-4" />
|
|
23
|
+
</button>
|
|
24
|
+
</li>
|
|
25
|
+
<li>
|
|
26
|
+
<button
|
|
27
|
+
:disabled="ui.disabledButtons['add-profiles']"
|
|
28
|
+
@click="disable"
|
|
29
|
+
class="smooth-hover text-red-400"
|
|
30
|
+
>
|
|
31
|
+
<CloseXIcon />
|
|
32
|
+
</button>
|
|
33
|
+
</li>
|
|
34
|
+
<li>
|
|
35
|
+
<button
|
|
36
|
+
:disabled="ui.disabledButtons['add-profiles']"
|
|
37
|
+
@click="enable"
|
|
38
|
+
class="smooth-hover text-green-400"
|
|
39
|
+
>
|
|
40
|
+
<CheckIcon />
|
|
41
|
+
</button>
|
|
42
|
+
</li>
|
|
43
|
+
</ul>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div class="flex justify-between mb-3">
|
|
47
|
+
<div class="sm:w-auto w-full flex items-center justify-start gap-1">
|
|
48
|
+
<TagToggle
|
|
49
|
+
class="smooth-hover rounded-l min-w-9"
|
|
50
|
+
:options="['All', 'Enabled', 'Disabled']"
|
|
51
|
+
@change="(f) => (ui.search.profiles.show = f)"
|
|
52
|
+
/>
|
|
53
|
+
<TagToggle
|
|
54
|
+
class="smooth-hover min-w-14"
|
|
55
|
+
:options="['Name', 'Card']"
|
|
56
|
+
@change="(f) => (ui.search.profiles.field = f)"
|
|
57
|
+
/>
|
|
58
|
+
|
|
59
|
+
<input
|
|
60
|
+
class="h-10 min-w-32 lg:min-w-38 text-white text-sm p-2 bg-dark-500 relative border-2 border-dark-550"
|
|
61
|
+
:placeholder="`Search ${ui.search.profiles.field}s`"
|
|
62
|
+
v-model="ui.search.profiles.query"
|
|
63
|
+
/>
|
|
64
|
+
|
|
65
|
+
<!-- <TagToggle
|
|
66
|
+
class="smooth-hover w-32 rounded-r"
|
|
67
|
+
:options="allTags"
|
|
68
|
+
@change="(f) => (ui.search.profiles.tag = f)"
|
|
69
|
+
/> -->
|
|
70
|
+
<Dropdown
|
|
71
|
+
class="rounded-r-lg w-32 bg-dark-500 relative z-50 border-2 border-dark-550 search-dropdown"
|
|
72
|
+
style="margin-left: 0 !important; border-width: 2px !important"
|
|
73
|
+
rightAmount="right-1"
|
|
74
|
+
default="Any"
|
|
75
|
+
:value="ui.search.profiles.tag"
|
|
76
|
+
:onClick="(f) => (ui.search.profiles.tag = f)"
|
|
77
|
+
:options="allTags"
|
|
78
|
+
:capitalize="true"
|
|
79
|
+
/>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div class="gap-3 lg:flex hidden">
|
|
83
|
+
<div
|
|
84
|
+
class="bg-dark-400 border border-light-300 justify-between px-4 w-36 flex text-white text-xs font-medium items-center rounded-md ml-auto h-10"
|
|
85
|
+
>
|
|
86
|
+
<p>Privacy</p>
|
|
87
|
+
<Switch class="scale-75" v-model="privacy" />
|
|
88
|
+
</div>
|
|
89
|
+
<button
|
|
90
|
+
:disabled="ui.disabledButtons['disable-profiles']"
|
|
91
|
+
@click="disable"
|
|
92
|
+
class="bg-red-400 disabled:opacity-70 smooth-hover border-none w-36 flex text-white text-xs font-medium justify-center items-center rounded-md ml-auto h-10"
|
|
93
|
+
>
|
|
94
|
+
Disable <img class="w-4 h-4 ml-2" src="/img/controls/disable.svg" />
|
|
95
|
+
</button>
|
|
96
|
+
<button
|
|
97
|
+
:disabled="ui.disabledButtons['enable-profiles']"
|
|
98
|
+
@click="enable"
|
|
99
|
+
class="bg-green-400 disabled:opacity-70 smooth-hover border-none w-36 flex text-white text-xs font-medium justify-center items-center rounded-md ml-auto h-10"
|
|
100
|
+
>
|
|
101
|
+
Enable <img class="w-4 h-4 ml-2" src="/img/controls/enable.svg" />
|
|
102
|
+
</button>
|
|
103
|
+
<button
|
|
104
|
+
:disabled="ui.disabledButtons['add-profiles']"
|
|
105
|
+
class="bg-dark-400 disabled:opacity-70 smooth-hover w-36 flex text-white text-xs font-medium justify-center items-center rounded-md border border-light-300 hover:border-light-400 ml-auto h-10"
|
|
106
|
+
@click="ui.toggleModal('create-profile')"
|
|
107
|
+
>
|
|
108
|
+
Add Profile
|
|
109
|
+
<PlusIcon class="ml-2" />
|
|
110
|
+
</button>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<!-- Tasks (Table) -->
|
|
115
|
+
<ProfileView :tasks="processedTasks" />
|
|
116
|
+
|
|
117
|
+
<!-- Modal -->
|
|
118
|
+
<transition-group name="fade" mode="out-in">
|
|
119
|
+
<CreateProfile v-if="activeModal === 'create-profile'" />
|
|
120
|
+
</transition-group>
|
|
121
|
+
</div>
|
|
122
|
+
</template>
|
|
123
|
+
<style lang="scss" scoped>
|
|
124
|
+
.custom-dropdown-content {
|
|
125
|
+
top: 2.6rem !important;
|
|
126
|
+
left: -13px;
|
|
127
|
+
@apply border border-light-300;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* Search dropdown should always be h-10 and have no left corners */
|
|
131
|
+
.search-dropdown {
|
|
132
|
+
height: 2.5rem !important; /* Always 40px regardless of screen size */
|
|
133
|
+
border-top-left-radius: 0 !important;
|
|
134
|
+
border-bottom-left-radius: 0 !important;
|
|
135
|
+
}
|
|
136
|
+
</style>
|
|
137
|
+
<script setup>
|
|
138
|
+
import { computed, ref, watch } from "vue";
|
|
139
|
+
import ProfileView from "@/components/Editors/Profile/ProfileView.vue";
|
|
140
|
+
import CreateProfile from "@/components/Editors/Profile/CreateProfile.vue";
|
|
141
|
+
import { useUIStore } from "@/stores/ui";
|
|
142
|
+
import { PlusIcon, GroupIcon, CloseXIcon, CheckIcon } from "@/components/icons";
|
|
143
|
+
import Dropdown from "@/components/ui/controls/atomic/Dropdown.vue";
|
|
144
|
+
import EyeToggle from "@/components/ui/controls/EyeToggle.vue";
|
|
145
|
+
import TagToggle from "@/components/Editors/TagToggle.vue";
|
|
146
|
+
import Switch from "@/components/ui/controls/atomic/Switch.vue";
|
|
147
|
+
|
|
148
|
+
const ui = useUIStore();
|
|
149
|
+
ui.search.profiles.results = ui.profiles;
|
|
150
|
+
|
|
151
|
+
const activeModal = computed(() => ui.activeModal);
|
|
152
|
+
const filterFieldMap = { Name: "profileName", Card: "cardNumber" };
|
|
153
|
+
const allTags = ref([]);
|
|
154
|
+
const privacy = ref(true);
|
|
155
|
+
|
|
156
|
+
const processedTasks = computed(() => {
|
|
157
|
+
return ui.search.profiles.results.map((e) => ({ ...e, privacy: privacy.value }));
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
watch(
|
|
161
|
+
() =>
|
|
162
|
+
ui.search.profiles.query +
|
|
163
|
+
ui.search.profiles.field +
|
|
164
|
+
ui.search.profiles.show +
|
|
165
|
+
ui.profiles.length +
|
|
166
|
+
ui.search.profiles.tag,
|
|
167
|
+
() => {
|
|
168
|
+
const { query, show, field, tag } = ui.search.profiles;
|
|
169
|
+
|
|
170
|
+
let profs = ui.profiles;
|
|
171
|
+
if (show === "Enabled") profs = profs.filter((p) => p.enabled);
|
|
172
|
+
if (show === "Disabled") profs = profs.filter((p) => !p.enabled);
|
|
173
|
+
|
|
174
|
+
if (tag !== "Any") profs = profs.filter((p) => p.tags.includes(tag));
|
|
175
|
+
|
|
176
|
+
if (!query) return (ui.search.profiles.results = profs);
|
|
177
|
+
let searchRegex = new RegExp(query, "i");
|
|
178
|
+
|
|
179
|
+
const f = (p) => searchRegex.test(p[filterFieldMap[field]]);
|
|
180
|
+
ui.search.profiles.results = profs.filter(f);
|
|
181
|
+
|
|
182
|
+
allTags.value = getAllTags();
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const enable = async () => {
|
|
187
|
+
const selected = ui.getSelectedProfiles().filter((p) => !p.enabled);
|
|
188
|
+
if (!window.confirm(`Do you really want to enable all selected profiles? (${selected.length})`)) return;
|
|
189
|
+
await Promise.all(selected.map(async (profile) => await ui.addProfile({ ...profile, enabled: true })));
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const disable = async () => {
|
|
193
|
+
const selected = ui.getSelectedProfiles().filter((p) => p.enabled);
|
|
194
|
+
if (!window.confirm(`Do you really want to disable all selected profiles? (${selected.length})`)) return;
|
|
195
|
+
await Promise.all(selected.map(async (profile) => await ui.addProfile({ ...profile, enabled: false })));
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const getAllTags = () => {
|
|
199
|
+
let tags = ["Any"];
|
|
200
|
+
ui.search.profiles.results.forEach((p) =>
|
|
201
|
+
p.tags.forEach((tag) => {
|
|
202
|
+
if (!tags.includes(tag)) tags.push(tag);
|
|
203
|
+
})
|
|
204
|
+
);
|
|
205
|
+
return tags;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
allTags.value = getAllTags();
|
|
209
|
+
</script>
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<div class="flex-between pt-5 pb-2">
|
|
4
|
+
<!-- Heading -->
|
|
5
|
+
<div class="flex-center gap-4">
|
|
6
|
+
<GearIcon class="w-5 cursor-pointer smooth-hover" @click="ui.toggleModal('quick-settings')" />
|
|
7
|
+
<h4 class="text-heading">
|
|
8
|
+
Tasks
|
|
9
|
+
<span class="text-subheading pl-1">{{ taskCount }}</span>
|
|
10
|
+
</h4>
|
|
11
|
+
</div>
|
|
12
|
+
<ul class="mobile-icons mobile-header-controls">
|
|
13
|
+
<li>
|
|
14
|
+
<button @click="ui.startTasks()">
|
|
15
|
+
<PlayIcon class="w-4 h-4" />
|
|
16
|
+
</button>
|
|
17
|
+
</li>
|
|
18
|
+
<li>
|
|
19
|
+
<button @click="ui.stopTasks()">
|
|
20
|
+
<PauseIcon class="w-4 h-4" />
|
|
21
|
+
</button>
|
|
22
|
+
</li>
|
|
23
|
+
<li>
|
|
24
|
+
<button
|
|
25
|
+
class="text-sm"
|
|
26
|
+
:disabled="ui.disabledButtons['add-tasks']"
|
|
27
|
+
@click="ui.toggleModal('create-task')"
|
|
28
|
+
>
|
|
29
|
+
<PlusIcon class="w-4 h-4" />
|
|
30
|
+
</button>
|
|
31
|
+
</li>
|
|
32
|
+
<li>
|
|
33
|
+
<button @click="ui.deleteTasks()">
|
|
34
|
+
<TrashIcon class="h-3.5 w-3.5" />
|
|
35
|
+
</button>
|
|
36
|
+
</li>
|
|
37
|
+
</ul>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<Stats />
|
|
41
|
+
|
|
42
|
+
<!-- Controls -->
|
|
43
|
+
<div class="controls-wrapper mb-6">
|
|
44
|
+
<DesktopControls
|
|
45
|
+
class="desktop-controls-hide"
|
|
46
|
+
@stopAll="ui.stopTasks()"
|
|
47
|
+
@startAll="ui.startTasks()"
|
|
48
|
+
@deleteAll="ui.deleteTasks()"
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="flex items-center justify-between gap-2 mb-2">
|
|
52
|
+
<div class="flex items-center gap-2">
|
|
53
|
+
<div
|
|
54
|
+
v-if="uniqEventIds.length > 1"
|
|
55
|
+
class="min-w-32 max-w-72 md:max-w-48"
|
|
56
|
+
>
|
|
57
|
+
<Dropdown
|
|
58
|
+
:onClick="(f) => ui.setCurrentEvent(f)"
|
|
59
|
+
default="All events"
|
|
60
|
+
:chosen="ui.currentEvent"
|
|
61
|
+
:options="uniqEventIds"
|
|
62
|
+
:allowDefault="true"
|
|
63
|
+
class="input-default w-full hover:bg-dark-400 h-10"
|
|
64
|
+
rightAmount="right-2"
|
|
65
|
+
/>
|
|
66
|
+
</div>
|
|
67
|
+
<PriceSortToggle
|
|
68
|
+
class="min-w-24 max-w-28"
|
|
69
|
+
:options="['All', 'Checkout']"
|
|
70
|
+
:darker="true"
|
|
71
|
+
:current="ui.taskFilter"
|
|
72
|
+
@change="(e) => ui.setTaskFilter(e)"
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
<div class="flex gap-x-3">
|
|
76
|
+
<button @click="ui.expandTasks()" class="bg-dark-400 smooth-hover w-36 border border-light-300 hover:border-light-400 text-white h-10 rounded-md text-xs flex items-center justify-center font-medium px-4">
|
|
77
|
+
Expand <ExpandIcon class="ml-2" />
|
|
78
|
+
</button>
|
|
79
|
+
<button @click="ui.foldTasks()" class="bg-dark-400 smooth-hover w-36 border border-light-300 hover:border-light-400 text-white h-10 rounded-md text-xs flex items-center justify-center font-medium px-4">
|
|
80
|
+
Fold <ShrinkIcon class="ml-2" />
|
|
81
|
+
</button>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<!-- Tasks (Table) -->
|
|
86
|
+
<TaskView class="mb-6" :tasks="ui.tasks" />
|
|
87
|
+
<!-- Utilities -->
|
|
88
|
+
<Utilities />
|
|
89
|
+
<!-- Modal -->
|
|
90
|
+
<transition-group name="fade" mode="out-in">
|
|
91
|
+
<CreateTaskTM v-if="ui.currentModule == 'TM' && activeModal === 'create-task'" @new="ui.addNewTask" />
|
|
92
|
+
<CreateTaskAXS v-if="ui.currentModule == 'AXS' && activeModal === 'create-task'" @new="ui.addNewTask" />
|
|
93
|
+
|
|
94
|
+
<CheckStock v-if="activeModal === 'check-stock'" />
|
|
95
|
+
<ScrapeVenue v-if="activeModal === 'scrape-venue'" />
|
|
96
|
+
<MassEditPresaleCode v-if="activeModal === 'mass-edit-presale-code'" />
|
|
97
|
+
<QuickSettings v-if="activeModal === 'quick-settings'" />
|
|
98
|
+
</transition-group>
|
|
99
|
+
</div>
|
|
100
|
+
</template>
|
|
101
|
+
<style lang="scss" scoped>
|
|
102
|
+
.custom-dropdown-content {
|
|
103
|
+
top: 2.6rem !important;
|
|
104
|
+
left: -13px;
|
|
105
|
+
@apply border border-light-300;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.desktop-controls-hide {
|
|
109
|
+
display: none !important;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.mobile-header-controls {
|
|
113
|
+
display: flex !important;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@media (min-width: 650px) {
|
|
117
|
+
.desktop-controls-hide {
|
|
118
|
+
display: flex !important;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.mobile-header-controls {
|
|
122
|
+
display: none !important;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
</style>
|
|
126
|
+
<script setup>
|
|
127
|
+
import { computed } from "vue";
|
|
128
|
+
import { DesktopControls } from "@/components/Tasks/Controls";
|
|
129
|
+
import TaskView from "@/components/Tasks/TaskView.vue";
|
|
130
|
+
import Utilities from "@/components/Tasks/Utilities.vue";
|
|
131
|
+
import CreateTaskTM from "@/components/Tasks/CreateTaskTM.vue";
|
|
132
|
+
import CreateTaskAXS from "@/components/Tasks/CreateTaskAXS.vue";
|
|
133
|
+
import CheckStock from "@/components/Tasks/CheckStock.vue";
|
|
134
|
+
import ScrapeVenue from "@/components/Tasks/ScrapeVenue.vue";
|
|
135
|
+
import MassEditPresaleCode from "@/components/Tasks/MassEdit.vue";
|
|
136
|
+
import Dropdown from "@/components/ui/controls/atomic/Dropdown.vue";
|
|
137
|
+
import Stats from "@/components/Tasks/Stats.vue";
|
|
138
|
+
import { useUIStore } from "@/stores/ui";
|
|
139
|
+
import { TrashIcon, GearIcon, PlusIcon, PlayIcon, PauseIcon, ExpandIcon, ShrinkIcon } from "@/components/icons";
|
|
140
|
+
import QuickSettings from "@/components/Tasks/QuickSettings.vue";
|
|
141
|
+
import PriceSortToggle from "@/components/Filter/PriceSortToggle.vue";
|
|
142
|
+
const ui = useUIStore();
|
|
143
|
+
const activeModal = computed(() => ui.activeModal);
|
|
144
|
+
const taskCount = computed(() => Object.keys(ui.getSelectedTasks()).length);
|
|
145
|
+
ui.refreshQueueStats();
|
|
146
|
+
|
|
147
|
+
const uniqEventIds = computed(() => {
|
|
148
|
+
const ids = [
|
|
149
|
+
...new Set(
|
|
150
|
+
Object.values(ui.tasks)
|
|
151
|
+
.filter((t) => t.siteId === ui.currentCountry.siteId && !t.eventId.includes("@"))
|
|
152
|
+
.map((v) => v.eventId)
|
|
153
|
+
)
|
|
154
|
+
];
|
|
155
|
+
return ids;
|
|
156
|
+
});
|
|
157
|
+
</script>
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
|
6
|
+
<title>Site Offline</title>
|
|
7
|
+
<meta name="theme-color" content="rgba(28, 28, 49, 1)" />
|
|
8
|
+
<style>
|
|
9
|
+
body,
|
|
10
|
+
html {
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
14
|
+
background-color: rgba(28, 28, 49, 1);
|
|
15
|
+
color: #fff;
|
|
16
|
+
height: 100%;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
html,
|
|
20
|
+
body {
|
|
21
|
+
/* Prevent scrolling on both axes */
|
|
22
|
+
overflow: hidden;
|
|
23
|
+
position: fixed;
|
|
24
|
+
width: 100%;
|
|
25
|
+
height: 100%;
|
|
26
|
+
|
|
27
|
+
/* Prevent touch actions except for buttons */
|
|
28
|
+
touch-action: none;
|
|
29
|
+
-ms-touch-action: none;
|
|
30
|
+
|
|
31
|
+
/* Prevent text selection */
|
|
32
|
+
-webkit-user-select: none;
|
|
33
|
+
-moz-user-select: none;
|
|
34
|
+
-ms-user-select: none;
|
|
35
|
+
user-select: none;
|
|
36
|
+
|
|
37
|
+
/* Prevent pinch zoom */
|
|
38
|
+
-webkit-touch-callout: none;
|
|
39
|
+
-webkit-text-size-adjust: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.container {
|
|
43
|
+
display: flex;
|
|
44
|
+
justify-content: center;
|
|
45
|
+
align-items: center;
|
|
46
|
+
min-height: 100vh;
|
|
47
|
+
}
|
|
48
|
+
.error-card {
|
|
49
|
+
background-color: rgba(39, 39, 67, 0.4);
|
|
50
|
+
border-radius: 0.5rem;
|
|
51
|
+
padding: 2rem;
|
|
52
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
53
|
+
text-align: center;
|
|
54
|
+
max-width: 20rem;
|
|
55
|
+
width: 100%;
|
|
56
|
+
margin: auto;
|
|
57
|
+
}
|
|
58
|
+
.icon-wrapper {
|
|
59
|
+
background-color: #4a4a61;
|
|
60
|
+
width: 4rem;
|
|
61
|
+
height: 4rem;
|
|
62
|
+
border-radius: 50%;
|
|
63
|
+
display: flex;
|
|
64
|
+
justify-content: center;
|
|
65
|
+
align-items: center;
|
|
66
|
+
margin: 0 auto 1rem;
|
|
67
|
+
font-size: 2rem;
|
|
68
|
+
color: #ee8282;
|
|
69
|
+
}
|
|
70
|
+
h1 {
|
|
71
|
+
font-size: 1.5rem;
|
|
72
|
+
margin-bottom: 0.5rem;
|
|
73
|
+
}
|
|
74
|
+
p {
|
|
75
|
+
color: rgba(255, 255, 255, 0.7);
|
|
76
|
+
margin-bottom: 1.5rem;
|
|
77
|
+
}
|
|
78
|
+
.refresh-button {
|
|
79
|
+
background-color: #4a4a61;
|
|
80
|
+
color: white;
|
|
81
|
+
border: none;
|
|
82
|
+
padding: 0.5rem 1rem;
|
|
83
|
+
border-radius: 0.25rem;
|
|
84
|
+
font-size: 1rem;
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
transition: background-color 0.3s ease;
|
|
87
|
+
/* Enable touch actions specifically for the button */
|
|
88
|
+
touch-action: manipulation;
|
|
89
|
+
-webkit-tap-highlight-color: transparent;
|
|
90
|
+
touch-action: auto;
|
|
91
|
+
-webkit-touch-callout: none;
|
|
92
|
+
cursor: pointer;
|
|
93
|
+
}
|
|
94
|
+
.refresh-button:hover {
|
|
95
|
+
background-color: rgba(255, 255, 255, 0.2);
|
|
96
|
+
}
|
|
97
|
+
.refresh-button:focus {
|
|
98
|
+
outline: none;
|
|
99
|
+
box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.3);
|
|
100
|
+
}
|
|
101
|
+
/* Add active state for better touch feedback */
|
|
102
|
+
.refresh-button:active {
|
|
103
|
+
background-color: rgba(255, 255, 255, 0.3);
|
|
104
|
+
transform: scale(0.98);
|
|
105
|
+
}
|
|
106
|
+
</style>
|
|
107
|
+
</head>
|
|
108
|
+
<body>
|
|
109
|
+
<div class="container">
|
|
110
|
+
<div class="error-card">
|
|
111
|
+
<div class="icon-wrapper"><span style="margin-bottom: 0.2rem">⚠</span></div>
|
|
112
|
+
<h1>Site Offline</h1>
|
|
113
|
+
<p>We're down. Please try again.</p>
|
|
114
|
+
<button class="refresh-button" id="refreshButton">Refresh Page</button>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
<script>
|
|
118
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
119
|
+
const button = document.getElementById("refreshButton");
|
|
120
|
+
|
|
121
|
+
// Handle button click/touch
|
|
122
|
+
button.addEventListener("click", function (e) {
|
|
123
|
+
window.location.reload();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// Prevent zoom and scroll on the page but allow button interaction
|
|
127
|
+
document.addEventListener(
|
|
128
|
+
"touchstart",
|
|
129
|
+
function (e) {
|
|
130
|
+
if (!e.target.classList.contains("refresh-button")) {
|
|
131
|
+
e.preventDefault();
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
{ passive: false }
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
document.addEventListener(
|
|
138
|
+
"touchmove",
|
|
139
|
+
function (e) {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
},
|
|
142
|
+
{ passive: false }
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
document.addEventListener(
|
|
146
|
+
"touchend",
|
|
147
|
+
function (e) {
|
|
148
|
+
if (e.target !== button) {
|
|
149
|
+
e.preventDefault();
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
{ passive: false }
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
// Prevent zoom via gesture
|
|
156
|
+
document.addEventListener("gesturestart", function (e) {
|
|
157
|
+
e.preventDefault();
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Prevent zoom via mousewheel/trackpad
|
|
161
|
+
document.addEventListener(
|
|
162
|
+
"wheel",
|
|
163
|
+
function (e) {
|
|
164
|
+
if (e.ctrlKey) {
|
|
165
|
+
e.preventDefault();
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
{ passive: false }
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
// Prevent double-tap zoom
|
|
172
|
+
let lastTap = 0;
|
|
173
|
+
document.addEventListener("touchend", function (e) {
|
|
174
|
+
const currentTime = new Date().getTime();
|
|
175
|
+
const tapLength = currentTime - lastTap;
|
|
176
|
+
if (tapLength < 500 && tapLength > 0) {
|
|
177
|
+
e.preventDefault();
|
|
178
|
+
}
|
|
179
|
+
lastTap = currentTime;
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
</script>
|
|
183
|
+
</body>
|
|
184
|
+
</html>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
|
|
4
|
+
theme: {
|
|
5
|
+
colors: {
|
|
6
|
+
transparent: "transparent",
|
|
7
|
+
white: "#FFFFFF",
|
|
8
|
+
lightgray: "#e5e7eb",
|
|
9
|
+
green: {
|
|
10
|
+
400: "#44b744",
|
|
11
|
+
500: "#22c55e"
|
|
12
|
+
},
|
|
13
|
+
red: {
|
|
14
|
+
300: "#F87171",
|
|
15
|
+
400: "#EE8282"
|
|
16
|
+
},
|
|
17
|
+
dark: {
|
|
18
|
+
300: "#1B1C2B",
|
|
19
|
+
400: "#2D2F4A",
|
|
20
|
+
500: "#202036",
|
|
21
|
+
550: "#292a43",
|
|
22
|
+
600: "#25263c"
|
|
23
|
+
},
|
|
24
|
+
light: {
|
|
25
|
+
300: "#4A4A61",
|
|
26
|
+
400: "#A7A8AF"
|
|
27
|
+
},
|
|
28
|
+
gray: "#9CA3AF",
|
|
29
|
+
border: "#29293F"
|
|
30
|
+
},
|
|
31
|
+
screens: {
|
|
32
|
+
xs: "500px",
|
|
33
|
+
sm: "640px",
|
|
34
|
+
// => @media (min-width: 640px) { ... }
|
|
35
|
+
|
|
36
|
+
md: "768px",
|
|
37
|
+
// => @media (min-width: 768px) { ... }
|
|
38
|
+
|
|
39
|
+
ipadlg: "1000px",
|
|
40
|
+
lg: "1030px",
|
|
41
|
+
// => @media (min-width: 1024px) { ... }
|
|
42
|
+
|
|
43
|
+
xl: "1280px",
|
|
44
|
+
// => @media (min-width: 1280px) { ... }
|
|
45
|
+
|
|
46
|
+
"2xl": "1536px",
|
|
47
|
+
// => @media (min-width: 1536px) { ... }
|
|
48
|
+
landscape: {
|
|
49
|
+
raw: "(orientation: landscape)"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
plugins: [],
|
|
54
|
+
experimental: {
|
|
55
|
+
optimizeUniversalDefaults: false
|
|
56
|
+
}
|
|
57
|
+
};
|