@necrolab/dashboard 0.4.61 → 0.4.208
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 +1 -27
- package/.vscode/extensions.json +1 -1
- package/README.md +79 -43
- package/backend/api.js +48 -40
- package/backend/auth.js +3 -3
- package/backend/batching.js +1 -1
- package/backend/endpoints.js +77 -13
- package/backend/index.js +2 -2
- package/backend/mock-data.js +38 -29
- package/backend/mock-src/classes/logger.js +8 -8
- package/backend/mock-src/classes/utils.js +3 -7
- package/backend/mock-src/database.js +0 -0
- package/backend/mock-src/ticketmaster.js +79 -79
- package/backend/validator.js +2 -2
- package/config/configs.json +3 -2
- package/config/filter.json +3 -2
- package/index.html +10 -81
- package/index.js +1 -1
- package/package.json +25 -40
- package/postcss.config.js +1 -1
- package/postinstall.js +17 -98
- 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/manifest.json +7 -12
- package/public/sw.js +2 -0
- package/public/workbox-49fdaf31.js +2 -0
- package/public/workbox-49fdaf31.js.map +1 -0
- package/public/workbox-88575b92.js +2 -0
- package/public/workbox-88575b92.js.map +1 -0
- package/public/workbox-a67a7b11.js +2 -0
- package/public/workbox-a67a7b11.js.map +1 -0
- package/public/workbox-d4314735.js +2 -0
- package/public/workbox-d4314735.js.map +1 -0
- package/public/workbox-e0f89ef3.js +2 -0
- package/public/workbox-e0f89ef3.js.map +1 -0
- package/run +9 -176
- package/src/App.vue +85 -498
- package/src/assets/css/_input.scss +99 -144
- package/src/assets/css/main.scss +99 -450
- package/src/assets/img/background.svg +2 -2
- package/src/assets/img/logo_icon.png +0 -0
- package/src/components/Auth/LoginForm.vue +11 -62
- package/src/components/Editors/Account/Account.vue +40 -116
- package/src/components/Editors/Account/AccountCreator.vue +39 -88
- package/src/components/Editors/Account/AccountView.vue +34 -102
- package/src/components/Editors/Account/CreateAccount.vue +32 -80
- package/src/components/Editors/Profile/CreateProfile.vue +83 -269
- package/src/components/Editors/Profile/Profile.vue +47 -132
- package/src/components/Editors/Profile/ProfileCountryChooser.vue +20 -82
- package/src/components/Editors/Profile/ProfileView.vue +34 -91
- package/src/components/Editors/TagLabel.vue +6 -67
- package/src/components/Filter/Filter.vue +72 -289
- package/src/components/Filter/FilterPreview.vue +30 -171
- package/src/components/Filter/PriceSortToggle.vue +4 -74
- package/src/components/Table/Header.vue +1 -1
- package/src/components/Table/Row.vue +1 -1
- package/src/components/Table/Table.vue +2 -19
- package/src/components/Tasks/CheckStock.vue +13 -28
- package/src/components/Tasks/Controls/DesktopControls.vue +17 -17
- package/src/components/Tasks/Controls/MobileControls.vue +45 -8
- package/src/components/Tasks/CreateTaskAXS.vue +73 -79
- package/src/components/Tasks/CreateTaskTM.vue +142 -94
- package/src/components/Tasks/MassEdit.vue +7 -9
- package/src/components/Tasks/QuickSettings.vue +55 -169
- package/src/components/Tasks/ScrapeVenue.vue +4 -7
- package/src/components/Tasks/Stats.vue +23 -52
- package/src/components/Tasks/Task.vue +136 -378
- package/src/components/Tasks/TaskView.vue +47 -107
- package/src/components/Tasks/Utilities.vue +6 -5
- package/src/components/icons/Bag.vue +1 -1
- package/src/components/icons/Loyalty.vue +1 -1
- package/src/components/icons/Mail.vue +2 -2
- package/src/components/icons/Play.vue +2 -2
- package/src/components/icons/Reload.vue +5 -4
- package/src/components/icons/Sandclock.vue +2 -2
- package/src/components/icons/Stadium.vue +1 -1
- package/src/components/icons/index.js +1 -24
- package/src/components/ui/Modal.vue +13 -105
- package/src/components/ui/Navbar.vue +38 -171
- package/src/components/ui/ReconnectIndicator.vue +55 -351
- package/src/components/ui/Splash.vue +35 -5
- package/src/components/ui/controls/CountryChooser.vue +62 -200
- package/src/components/ui/controls/atomic/Checkbox.vue +10 -119
- package/src/components/ui/controls/atomic/Dropdown.vue +39 -208
- package/src/components/ui/controls/atomic/MultiDropdown.vue +37 -300
- package/src/libs/Filter.js +170 -200
- package/src/registerServiceWorker.js +1 -1
- package/src/stores/connection.js +53 -51
- package/src/stores/logger.js +3 -11
- package/src/stores/sampleData.js +235 -207
- package/src/stores/ui.js +44 -112
- package/src/stores/utils.js +6 -90
- package/src/views/Accounts.vue +35 -44
- package/src/views/Console.vue +90 -341
- package/src/views/Editor.vue +123 -1176
- package/src/views/FilterBuilder.vue +251 -607
- package/src/views/Login.vue +14 -76
- package/src/views/Profiles.vue +25 -44
- package/src/views/Tasks.vue +100 -187
- package/static/offline.html +50 -192
- package/tailwind.config.js +26 -104
- package/vite.config.js +16 -73
- package/vue.config.js +32 -0
- package/workbox-config.js +11 -0
- package/artwork/image.png +0 -0
- package/dev-server.js +0 -136
- package/exit +0 -209
- package/jsconfig.json +0 -16
- package/src/assets/css/_utilities.scss +0 -388
- package/src/assets/img/background.svg.backup +0 -11
- package/src/components/icons/Check.vue +0 -5
- package/src/components/icons/Close.vue +0 -21
- package/src/components/icons/CloseX.vue +0 -5
- package/src/components/icons/Key.vue +0 -21
- package/src/components/icons/Pencil.vue +0 -21
- package/src/components/icons/Profile.vue +0 -18
- package/src/components/icons/Sell.vue +0 -21
- package/src/components/icons/Spinner.vue +0 -42
- package/src/components/icons/SquareCheck.vue +0 -18
- package/src/components/icons/SquareUncheck.vue +0 -18
- package/src/components/icons/Wildcard.vue +0 -18
- package/src/components/ui/controls/atomic/LoadingButton.vue +0 -45
- package/src/composables/useClickOutside.js +0 -21
- package/src/composables/useDropdownPosition.js +0 -174
- package/src/types/index.js +0 -41
- package/src/utils/debug.js +0 -1
- package/switch-branch.sh +0 -41
- package/workbox-config.cjs +0 -63
- /package/src/assets/img/{logo_icon-old.png → logo_icon_2.png} +0 -0
|
@@ -1,76 +1,67 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<h4 class="text-heading">Filter creator</h4>
|
|
8
|
-
</div>
|
|
9
|
-
<div class="flex items-center">
|
|
10
|
-
<input
|
|
11
|
-
class="relative flex h-10 w-48 items-center rounded-l rounded-r-none border-2 border-dark-550 bg-dark-500 p-2 text-sm text-white"
|
|
12
|
-
placeholder="Event ID"
|
|
13
|
-
v-model="eventId" />
|
|
14
|
-
<button
|
|
15
|
-
class="smooth-hover relative flex h-10 items-center rounded-r border-2 border-dark-550 bg-dark-400 px-3 text-sm font-medium text-white"
|
|
16
|
-
@click="updateShownVenue">
|
|
17
|
-
Load
|
|
18
|
-
</button>
|
|
19
|
-
</div>
|
|
20
|
-
</div>
|
|
21
|
-
|
|
22
|
-
<div class="card-dark mb-2 overflow-hidden p-3">
|
|
23
|
-
<div class="h-full w-full">
|
|
2
|
+
<div v-html="`<style>${filterBuilder.cssClasses}</style>`" />
|
|
3
|
+
<div v-html="`<style>${filterBuilder.temporaryCSS}</style>`" />
|
|
4
|
+
<div class="ios-wrapper mt-3">
|
|
5
|
+
<div class="bg-dark-500 mt-6 m-4 p-2 rounded shadow border-2 border-dark-550">
|
|
6
|
+
<div class="lg:px-3 px-0 mx-3 pb-8 mt-5">
|
|
24
7
|
<!-- Main -->
|
|
25
|
-
<div class="grid
|
|
8
|
+
<div class="grid grid-cols-1 md:grid-cols-5 gap-0 md:gap-8">
|
|
26
9
|
<!-- Map -->
|
|
27
|
-
<div
|
|
28
|
-
|
|
29
|
-
<div
|
|
30
|
-
<
|
|
10
|
+
<div class="col-span-3 w-auto h-auto rounded-lg relative">
|
|
11
|
+
<!-- Heading -->
|
|
12
|
+
<div class="text-white">
|
|
13
|
+
<h4 class="text-2xl font-bold" @click="filterBuilder.log()">Filter creator</h4>
|
|
14
|
+
<div class="flex items-center">
|
|
15
|
+
<input
|
|
16
|
+
class="h-6 mt-1 text-sm p-2 bg-dark-500 w-40 flex items-center rounded-l relative border-2 border-dark-550"
|
|
17
|
+
placeholder="Event"
|
|
18
|
+
v-model="eventId"
|
|
19
|
+
/>
|
|
20
|
+
<button
|
|
21
|
+
class="h-6 mt-1 text-sm p-2 bg-dark-550 flex items-center rounded-r relative font-bold border-2 border-dark-550 smooth-hover"
|
|
22
|
+
@click="updateShownVenue"
|
|
23
|
+
>
|
|
24
|
+
Load
|
|
25
|
+
</button>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
<div v-if="svg" class="flex items-center">
|
|
29
|
+
<div class="flex items-center justify-between w-20 px-2 text-white font-black text-xl">
|
|
31
30
|
<span class="cursor-pointer" @click="handleZoom(true)">+</span>
|
|
32
31
|
<span class="cursor-pointer" @click="handleZoom(false)">-</span>
|
|
33
|
-
<ReloadIcon class="
|
|
32
|
+
<ReloadIcon class="cursor-pointer" @click="handleZoom('r')" />
|
|
33
|
+
|
|
34
|
+
<!-- <h3 class="ml-10 text-sm text-white">Auto</h3>
|
|
35
|
+
<Switch class="scale-75 slider-dim" v-model="renderSeats" /> -->
|
|
34
36
|
</div>
|
|
35
37
|
</div>
|
|
36
|
-
<div class="selecto-wrapper
|
|
38
|
+
<div class="overflow-hidden selecto-wrapper">
|
|
37
39
|
<div
|
|
38
40
|
v-if="svg"
|
|
39
|
-
class="
|
|
41
|
+
class="mt-2 overflow-scroll hidden-scrollbars p-2 rounded shadow border-2 border-dark-550"
|
|
42
|
+
>
|
|
43
|
+
<!-- <drag-select v-model="selection"> -->
|
|
40
44
|
<div class="svg-wrapper" id="svg-wrapper" v-html="svg"></div>
|
|
41
|
-
|
|
42
|
-
<div
|
|
43
|
-
v-else
|
|
44
|
-
class="svg-container flex h-full items-center justify-center rounded border-2 border-dark-550 p-2 shadow">
|
|
45
|
-
<div class="text-center">
|
|
46
|
-
<svg
|
|
47
|
-
class="mx-auto mb-3 h-12 w-12 opacity-50"
|
|
48
|
-
viewBox="0 0 19 19"
|
|
49
|
-
fill="none"
|
|
50
|
-
xmlns="http://www.w3.org/2000/svg">
|
|
51
|
-
<path
|
|
52
|
-
d="M2.37499 5.54165V2.37498L5.54166 3.95831L2.37499 5.54165ZM14.25 5.54165V2.37498L17.4167 3.95831L14.25 5.54165ZM8.70833 4.74998V1.58331L11.875 3.16665L8.70833 4.74998ZM8.70833 17.4166C7.70555 17.3903 6.77218 17.3079 5.9082 17.1696C5.0437 17.0308 4.29162 16.8559 3.65195 16.6448C3.01176 16.4337 2.50694 16.1896 2.13749 15.9125C1.76805 15.6354 1.58333 15.3451 1.58333 15.0416V7.91665C1.58333 7.58678 1.79127 7.27988 2.20716 6.99594C2.62252 6.71252 3.18645 6.46183 3.89895 6.24385C4.61145 6.02641 5.4493 5.85488 6.4125 5.72927C7.37569 5.60419 8.40486 5.54165 9.49999 5.54165C10.5951 5.54165 11.6243 5.60419 12.5875 5.72927C13.5507 5.85488 14.3885 6.02641 15.101 6.24385C15.8135 6.46183 16.3775 6.71252 16.7928 6.99594C17.2087 7.27988 17.4167 7.58678 17.4167 7.91665V15.0416C17.4167 15.3451 17.2319 15.6354 16.8625 15.9125C16.493 16.1896 15.9885 16.4337 15.3488 16.6448C14.7086 16.8559 13.9565 17.0308 13.0926 17.1696C12.2281 17.3079 11.2944 17.3903 10.2917 17.4166V14.25H8.70833V17.4166ZM9.49999 8.70831C10.7799 8.70831 11.885 8.63231 12.8155 8.48031C13.7454 8.32884 14.4875 8.15415 15.0417 7.95623C15.0417 7.89026 14.5403 7.73509 13.5375 7.49073C12.5347 7.2469 11.1889 7.12498 9.49999 7.12498C7.81111 7.12498 6.46527 7.2469 5.46249 7.49073C4.45972 7.73509 3.95833 7.89026 3.95833 7.95623C4.51249 8.15415 5.25481 8.32884 6.18529 8.48031C7.11523 8.63231 8.22013 8.70831 9.49999 8.70831ZM7.12499 15.7146V12.6666H11.875V15.7146C12.9305 15.609 13.7948 15.4538 14.4677 15.2491C15.1406 15.0448 15.5958 14.8635 15.8333 14.7052V9.34165C15.1076 9.63192 14.1972 9.86283 13.1021 10.0344C12.0069 10.2059 10.8062 10.2916 9.49999 10.2916C8.19374 10.2916 6.99305 10.2059 5.89791 10.0344C4.80277 9.86283 3.89236 9.63192 3.16666 9.34165V14.7052C3.40416 14.8635 3.85937 15.0448 4.53229 15.2491C5.2052 15.4538 6.06944 15.609 7.12499 15.7146Z"
|
|
53
|
-
fill="#F5F5F5" />
|
|
54
|
-
</svg>
|
|
55
|
-
<p class="text-sm text-light-400">No Map</p>
|
|
56
|
-
<p class="text-xs text-light-500">
|
|
57
|
-
Enter an event ID and click "Load" to display the venue map
|
|
58
|
-
</p>
|
|
59
|
-
</div>
|
|
45
|
+
<!-- </drag-select> -->
|
|
60
46
|
</div>
|
|
61
47
|
</div>
|
|
62
48
|
</div>
|
|
63
|
-
<div class="col-span-
|
|
64
|
-
<div class="mb-2
|
|
65
|
-
<
|
|
49
|
+
<div class="col-span-2 mt-10">
|
|
50
|
+
<div class="flex justify-between mb-2 items-center text-white">
|
|
51
|
+
<button
|
|
52
|
+
@click="filterBuilder.selectFirstRow"
|
|
53
|
+
class="border-2 rounded border-dark-550 px-1 h-8 w-full min-w-14 text-gray bg-dark-500 overflow-hidden smooth-hover"
|
|
54
|
+
>
|
|
55
|
+
First rows
|
|
56
|
+
</button>
|
|
57
|
+
|
|
58
|
+
<div class="rounded flex justify-between gap-2 items-center" v-if="hasLoaded">
|
|
66
59
|
<PriceSortToggle
|
|
67
60
|
:current="filterBuilder.globalFilter.priceSort"
|
|
68
61
|
class="smooth-hover"
|
|
69
|
-
@change="(e) => filterBuilder.updateGlobalFilter({ priceSort: e })"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
<SavingsIcon class="h-4 w-4 text-light-400" />
|
|
73
|
-
<label class="text-sm text-light-400">Max Price:</label>
|
|
62
|
+
@change="(e) => filterBuilder.updateGlobalFilter({ priceSort: e })"
|
|
63
|
+
/>
|
|
64
|
+
|
|
74
65
|
<input
|
|
75
66
|
type="number"
|
|
76
67
|
:value="filterBuilder.globalFilter.maxPrice"
|
|
@@ -80,87 +71,72 @@
|
|
|
80
71
|
maxPrice: parseInt(e.target.value || 0)
|
|
81
72
|
})
|
|
82
73
|
"
|
|
83
|
-
class="
|
|
84
|
-
placeholder="max"
|
|
74
|
+
class="w-14 bg-dark-500 border-2 border-dark-550 px-1 pl-2 h-8 rounded"
|
|
75
|
+
placeholder="max"
|
|
76
|
+
/>
|
|
85
77
|
</div>
|
|
86
78
|
</div>
|
|
87
|
-
<Table class="
|
|
88
|
-
<Header
|
|
89
|
-
<div class="flex
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
79
|
+
<Table class="border-2 border-dark-550 shadow-xl">
|
|
80
|
+
<Header>
|
|
81
|
+
<div class="flex items-center font-bold gap-2">
|
|
82
|
+
<span class="text-xl lg:block hidden">Filters</span>
|
|
83
|
+
<span class="text-xl text-light-300">{{ filterBuilder.filters.length }}</span>
|
|
84
|
+
<PriceSortToggle
|
|
85
|
+
class="w-14 smooth-hover"
|
|
86
|
+
:options="['All', 'WL', 'BL']"
|
|
87
|
+
@change="(e) => (shownFilters = e)"
|
|
88
|
+
/>
|
|
89
|
+
<div
|
|
90
|
+
class="flex gap-1 h-8 items-center justify-self-end border-2 border-dark-550 p-2 rounded smooth-hover"
|
|
91
|
+
@click="saveFilter"
|
|
92
|
+
>
|
|
93
|
+
<EditIcon />
|
|
94
|
+
<button class="lg:block hidden">Save</button>
|
|
93
95
|
</div>
|
|
94
|
-
<div
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
<button class="
|
|
100
|
-
<EditIcon class="h-4 w-4" />
|
|
101
|
-
<span class="hidden lg:block">Save</span>
|
|
102
|
-
</button>
|
|
103
|
-
<button class="header-btn clear-btn" @click="filterBuilder.reset(false)">
|
|
104
|
-
<TrashIcon class="h-4 w-4" />
|
|
105
|
-
<span class="hidden lg:block">Clear</span>
|
|
106
|
-
</button>
|
|
96
|
+
<div
|
|
97
|
+
class="flex gap-1 h-8 items-center absolute right-5 justify-self-end border-2 border-dark-550 p-2 rounded smooth-hover"
|
|
98
|
+
@click="filterBuilder.reset(false)"
|
|
99
|
+
>
|
|
100
|
+
<TrashIcon />
|
|
101
|
+
<button class="lg:block hidden">Clear</button>
|
|
107
102
|
</div>
|
|
108
103
|
</div>
|
|
109
104
|
</Header>
|
|
110
|
-
<div class="hidden-scrollbars
|
|
111
|
-
<div v-if="filterBuilder.filters.length"
|
|
105
|
+
<div class="overflow-scroll hidden-scrollbars h-96">
|
|
106
|
+
<div v-if="filterBuilder.filters.length">
|
|
112
107
|
<draggable
|
|
113
108
|
:list="filterBuilder.filters"
|
|
114
109
|
handle=".handle"
|
|
115
110
|
item-key="id"
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
drag-class="sortable-drag"
|
|
119
|
-
:animation="200"
|
|
120
|
-
:easing="'cubic-bezier(0.4, 0, 0.2, 1)'"
|
|
121
|
-
:force-fallback="false"
|
|
122
|
-
@change="
|
|
123
|
-
() => {
|
|
124
|
-
filterBuilder.updateCss();
|
|
125
|
-
cssUpdateTrigger++;
|
|
126
|
-
}
|
|
127
|
-
">
|
|
111
|
+
@change="filterBuilder.updateCss()"
|
|
112
|
+
>
|
|
128
113
|
<template #item="{ element: f, index: i }">
|
|
129
114
|
<Filter
|
|
130
115
|
v-if="doesFilterShow(f)"
|
|
131
116
|
:filter="f"
|
|
132
117
|
:index="i"
|
|
133
118
|
:filterBuilder="filterBuilder"
|
|
134
|
-
|
|
119
|
+
/>
|
|
135
120
|
</template>
|
|
136
121
|
</draggable>
|
|
137
122
|
</div>
|
|
138
|
-
<
|
|
139
|
-
v-else
|
|
140
|
-
class="empty-state flex flex-col items-center justify-center py-8 text-center">
|
|
141
|
-
<FilterIcon class="mb-3 h-12 w-12 text-dark-400 opacity-50" />
|
|
142
|
-
<p class="text-sm text-light-400">No filters yet</p>
|
|
143
|
-
<p class="mt-1 text-xs text-light-500">Click on the map to create filters</p>
|
|
144
|
-
</div>
|
|
123
|
+
<p v-else class="text-dark-400 m-2">No filters yet...</p>
|
|
145
124
|
</div>
|
|
146
125
|
</Table>
|
|
147
|
-
<div class="
|
|
126
|
+
<div class="flex items-center justify-between font-bold text-white gap-2 my-2">
|
|
148
127
|
<button
|
|
149
|
-
@click="
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
? 'text-gray cursor-not-allowed opacity-50'
|
|
155
|
-
: 'text-gray smooth-hover hover:border-light-300 hover:bg-dark-400'
|
|
156
|
-
]"
|
|
157
|
-
:title="hasWildcardFilter ? 'Wildcard filter already exists' : 'Add wildcard filter'">
|
|
128
|
+
@click="
|
|
129
|
+
filterBuilder.addFilter({ buyAny: true, eventId: filterBuilder.currentEventId })
|
|
130
|
+
"
|
|
131
|
+
class="border-2 rounded border-dark-550 px-2 h-8 text-gray bg-dark-500 overflow-hidden shadow smooth-hover"
|
|
132
|
+
>
|
|
158
133
|
* Wildcard
|
|
159
134
|
</button>
|
|
160
135
|
<button
|
|
161
136
|
@click="ui.toggleModal('preview-filter')"
|
|
162
|
-
class="
|
|
163
|
-
|
|
137
|
+
class="border-2 gap-2 flex justify-between items-center rounded border-dark-550 px-2 h-8 text-gray bg-dark-500 overflow-hidden shadow smooth-hover"
|
|
138
|
+
>
|
|
139
|
+
<CameraIcon />
|
|
164
140
|
JSON
|
|
165
141
|
</button>
|
|
166
142
|
</div>
|
|
@@ -168,7 +144,7 @@
|
|
|
168
144
|
</div>
|
|
169
145
|
</div>
|
|
170
146
|
|
|
171
|
-
<transition-group name="fade">
|
|
147
|
+
<transition-group name="fade" mode="out-in">
|
|
172
148
|
<FilterPreview v-if="activeModal === 'preview-filter'" :filter="filterBuilder" />
|
|
173
149
|
</transition-group>
|
|
174
150
|
</div>
|
|
@@ -177,15 +153,20 @@
|
|
|
177
153
|
|
|
178
154
|
<script setup>
|
|
179
155
|
import draggable from "vuedraggable";
|
|
180
|
-
import { ref, nextTick, watch, computed
|
|
181
|
-
import { onBeforeRouteLeave } from "vue-router";
|
|
156
|
+
import { ref, nextTick, watch, computed } from "vue";
|
|
182
157
|
import { Table, Header } from "@/components/Table";
|
|
183
158
|
import Filter from "@/components/Filter/Filter.vue";
|
|
184
|
-
import { FilterIcon } from "@/components/icons";
|
|
185
159
|
import DragSelect from "dragselect";
|
|
186
|
-
import { DEBUG } from "@/utils/debug";
|
|
187
160
|
|
|
188
|
-
|
|
161
|
+
const DEBUG = window.location.href.startsWith("http://localhost:5173");
|
|
162
|
+
var RendererFactory;
|
|
163
|
+
if (DEBUG) {
|
|
164
|
+
RendererFactory = class {
|
|
165
|
+
constructor() {}
|
|
166
|
+
};
|
|
167
|
+
} else RendererFactory = import("@necrolab/tm-renderer");
|
|
168
|
+
|
|
169
|
+
import { ReloadIcon, TrashIcon, EditIcon, CameraIcon } from "@/components/icons";
|
|
189
170
|
import { sendSaveFilter } from "@/stores/requests";
|
|
190
171
|
import PriceSortToggle from "@/components/Filter/PriceSortToggle.vue";
|
|
191
172
|
import { useUIStore } from "@/stores/ui";
|
|
@@ -197,273 +178,151 @@ const activeModal = computed(() => ui.activeModal);
|
|
|
197
178
|
const ui = useUIStore();
|
|
198
179
|
const hasLoaded = ref(false);
|
|
199
180
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
// };
|
|
204
|
-
// window.onkeydown = (e) => {
|
|
205
|
-
// if (e.keyCode === 16) isShiftPressed = true;
|
|
206
|
-
// };
|
|
207
|
-
|
|
208
|
-
// const doDragSelect = () => {
|
|
209
|
-
// // https://dragselect.com/docs/API/Settings
|
|
210
|
-
// const ds = new DragSelect({
|
|
211
|
-
// selectables: [
|
|
212
|
-
// ...document.querySelectorAll("path[row]"),
|
|
213
|
-
// ...document.querySelectorAll("path[generaladmission]")
|
|
214
|
-
// ],
|
|
215
|
-
// area: document.getElementById("svg-wrapper"),
|
|
216
|
-
// selectionThreshold: 0.1,
|
|
217
|
-
// multiSelectKeys: []
|
|
218
|
-
// });
|
|
219
|
-
|
|
220
|
-
// ds.subscribe("DS:start:pre", () => {
|
|
221
|
-
// // ui.logger.Info("DS:start:pre - shift pressed:", isShiftPressed);
|
|
222
|
-
// if (!isShiftPressed) {
|
|
223
|
-
// ds.stop(false, false);
|
|
224
|
-
// ds.start();
|
|
225
|
-
// } else {
|
|
226
|
-
// panzoomInstance.pause();
|
|
227
|
-
// }
|
|
228
|
-
// });
|
|
229
|
-
|
|
230
|
-
// const parseSelected = (items) => {
|
|
231
|
-
// const parsed = items
|
|
232
|
-
// .map((e) => {
|
|
233
|
-
// return {
|
|
234
|
-
// section: e.attributes.sectionname?.nodeValue || e.attributes.name?.nodeValue,
|
|
235
|
-
// row: e.attributes.row?.nodeValue,
|
|
236
|
-
// GA: e.attributes.generaladmission?.nodeValue,
|
|
237
|
-
// name: e.attributes.name?.nodeValue
|
|
238
|
-
// };
|
|
239
|
-
// })
|
|
240
|
-
// .filter((e) => !filterBuilder.value.isUnselectable(e.section, e.row));
|
|
241
|
-
|
|
242
|
-
// const sectionMapping = {};
|
|
243
|
-
// parsed
|
|
244
|
-
// .filter((p) => !p.GA)
|
|
245
|
-
// .forEach((p) => {
|
|
246
|
-
// if (!sectionMapping[p.section]) sectionMapping[p.section] = [];
|
|
247
|
-
// sectionMapping[p.section].push(p);
|
|
248
|
-
// });
|
|
249
|
-
// parsed
|
|
250
|
-
// .filter((p) => p.GA)
|
|
251
|
-
// .forEach((p) => {
|
|
252
|
-
// sectionMapping[p.section] = {
|
|
253
|
-
// GA: true,
|
|
254
|
-
// section: p.section,
|
|
255
|
-
// name: p.name
|
|
256
|
-
// };
|
|
257
|
-
// });
|
|
258
|
-
// return sectionMapping;
|
|
259
|
-
// };
|
|
260
|
-
|
|
261
|
-
// ds.subscribe("DS:update:pre", (e) => {
|
|
262
|
-
// // ui.logger.Info("DS:update:pre - shift pressed:", isShiftPressed, e.items);
|
|
263
|
-
// filterBuilder.value.isDragging = true;
|
|
264
|
-
// if (!isShiftPressed) return;
|
|
265
|
-
// const sectionMapping = parseSelected(e.items);
|
|
266
|
-
// filterBuilder.value.clearHighlight();
|
|
267
|
-
// Object.entries(sectionMapping).forEach(([section, rows]) => {
|
|
268
|
-
// if (rows.GA) {
|
|
269
|
-
// const isSelected = filterBuilder.value.filters.find(
|
|
270
|
-
// (f) => filterBuilder.value.isForCurrentEvent(f) && f.section === section
|
|
271
|
-
// );
|
|
272
|
-
// if (isSelected) return;
|
|
273
|
-
// filterBuilder.value.highlight({ section: section }, true);
|
|
274
|
-
// } else
|
|
275
|
-
// rows.forEach((row) => {
|
|
276
|
-
// const isSelected = filterBuilder.value.filters.find(
|
|
277
|
-
// (f) =>
|
|
278
|
-
// (f.section === section && f.rows?.includes(row.row)) ||
|
|
279
|
-
// (!f.rows && f.section === section && filterBuilder.value.isForCurrentEvent(f))
|
|
280
|
-
// );
|
|
281
|
-
// if (isSelected) return;
|
|
282
|
-
|
|
283
|
-
// filterBuilder.value.highlight({ section, row: row.row });
|
|
284
|
-
// });
|
|
285
|
-
// });
|
|
286
|
-
// });
|
|
287
|
-
|
|
288
|
-
// ds.subscribe("DS:end", (e) => {
|
|
289
|
-
// filterBuilder.value.isDragging = false;
|
|
290
|
-
// panzoomInstance.resume();
|
|
291
|
-
// filterBuilder.value.clearHighlight();
|
|
292
|
-
// [...document.querySelectorAll("path")].map((f) => (f.style = ""));
|
|
293
|
-
// if (!isShiftPressed) return;
|
|
294
|
-
// const sectionMapping = parseSelected(e.items);
|
|
295
|
-
// const secNameMapping = filterBuilder.value.getSectionNameMapping();
|
|
296
|
-
|
|
297
|
-
// Object.entries(sectionMapping).forEach(([section, rows]) => {
|
|
298
|
-
// if (rows.GA) {
|
|
299
|
-
// const isSelected = filterBuilder.value.filters.find(
|
|
300
|
-
// (f) => filterBuilder.value.isForCurrentEvent(f) && f.section === secNameMapping[section]
|
|
301
|
-
// );
|
|
302
|
-
// if (isSelected) return;
|
|
303
|
-
// filterBuilder.value.addFilter({
|
|
304
|
-
// event: filterBuilder.value.currentEventId,
|
|
305
|
-
// section: secNameMapping[section]
|
|
306
|
-
// });
|
|
307
|
-
// } else {
|
|
308
|
-
// const unselectedRows = [];
|
|
309
|
-
// rows.forEach((row) => {
|
|
310
|
-
// const isSelected = filterBuilder.value.filters.find(
|
|
311
|
-
// (f) =>
|
|
312
|
-
// (f.section === section && f.rows?.includes(row.row)) ||
|
|
313
|
-
// (!f.rows && f.section === section && filterBuilder.value.isForCurrentEvent(f))
|
|
314
|
-
// );
|
|
315
|
-
// if (isSelected) return;
|
|
316
|
-
// unselectedRows.push(row.row);
|
|
317
|
-
// });
|
|
318
|
-
// if (unselectedRows.length === 0) return;
|
|
319
|
-
// filterBuilder.value.addFilter({
|
|
320
|
-
// event: filterBuilder.value.currentEventId,
|
|
321
|
-
// section,
|
|
322
|
-
// rows: unselectedRows
|
|
323
|
-
// });
|
|
324
|
-
// }
|
|
325
|
-
// });
|
|
326
|
-
// isShiftPressed = false;
|
|
327
|
-
// });
|
|
328
|
-
// };
|
|
329
|
-
|
|
330
|
-
const panzoomOptions = {
|
|
331
|
-
maxZoom: 8, // max zoom-in factor
|
|
332
|
-
minZoom: 0.8, // max zoom-out factor
|
|
333
|
-
panOnlyWhenZoomed: true,
|
|
334
|
-
bounds: true,
|
|
335
|
-
boundsPadding: 0.1, // Add padding to ensure it stays within bounds
|
|
336
|
-
transformOrigin: { x: 0.5, y: 0.5 }, // Center the zoom
|
|
337
|
-
contain: true // Force the image to stay within the parent container
|
|
181
|
+
let isShiftPressed = false;
|
|
182
|
+
window.onkeyup = (e) => {
|
|
183
|
+
if (e.keyCode === 16) isShiftPressed = false;
|
|
338
184
|
};
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
const svg = ref("");
|
|
342
|
-
const eventId = ref("");
|
|
343
|
-
const renderSeats = ref(false);
|
|
344
|
-
let renderer;
|
|
345
|
-
|
|
346
|
-
const shownFilters = ref("All");
|
|
347
|
-
const filterBuilder = ref(new FilterBuilder());
|
|
348
|
-
|
|
349
|
-
const hasWildcardFilter = computed(() => {
|
|
350
|
-
return filterBuilder.value.filters.some((filter) => filter.buyAny && filterBuilder.value.isForCurrentEvent(filter));
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
const addWildcardFilter = () => {
|
|
354
|
-
if (!hasWildcardFilter.value) {
|
|
355
|
-
// Close any expanded filter first
|
|
356
|
-
filterBuilder.value.setExpandedFilter(null);
|
|
357
|
-
filterBuilder.value.addFilter({ buyAny: true, eventId: filterBuilder.value.currentEventId });
|
|
358
|
-
filterBuilder.value.updateCss();
|
|
359
|
-
}
|
|
185
|
+
window.onkeydown = (e) => {
|
|
186
|
+
if (e.keyCode === 16) isShiftPressed = true;
|
|
360
187
|
};
|
|
361
188
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
if (!svgWrapper || !svg.value) return;
|
|
189
|
+
const doDragSelect = () => {
|
|
190
|
+
// https://dragselect.com/docs/API/Settings
|
|
191
|
+
const ds = new DragSelect({
|
|
192
|
+
selectables: [
|
|
193
|
+
...document.querySelectorAll("path[row]"),
|
|
194
|
+
...document.querySelectorAll("path[generaladmission]")
|
|
195
|
+
],
|
|
196
|
+
area: document.getElementById("svg-wrapper"),
|
|
197
|
+
selectionThreshold: 0.1,
|
|
198
|
+
multiSelectKeys: []
|
|
199
|
+
});
|
|
374
200
|
|
|
375
|
-
|
|
376
|
-
//
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
201
|
+
ds.subscribe("DS:start:pre", () => {
|
|
202
|
+
// ui.logger.Info("DS:start:pre - shift pressed:", isShiftPressed);
|
|
203
|
+
if (!isShiftPressed) {
|
|
204
|
+
ds.stop(false, false);
|
|
205
|
+
ds.start();
|
|
206
|
+
} else {
|
|
207
|
+
panzoomInstance.pause();
|
|
380
208
|
}
|
|
209
|
+
});
|
|
381
210
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
211
|
+
const parseSelected = (items) => {
|
|
212
|
+
const parsed = items
|
|
213
|
+
.map((e) => {
|
|
214
|
+
return {
|
|
215
|
+
section: e.attributes.sectionname?.nodeValue || e.attributes.name?.nodeValue,
|
|
216
|
+
row: e.attributes.row?.nodeValue,
|
|
217
|
+
GA: e.attributes.generaladmission?.nodeValue,
|
|
218
|
+
name: e.attributes.name?.nodeValue
|
|
219
|
+
};
|
|
220
|
+
})
|
|
221
|
+
.filter((e) => !filterBuilder.value.isUnselectable(e.section, e.row));
|
|
222
|
+
|
|
223
|
+
const sectionMapping = {};
|
|
224
|
+
parsed
|
|
225
|
+
.filter((p) => !p.GA)
|
|
226
|
+
.forEach((p) => {
|
|
227
|
+
if (!sectionMapping[p.section]) sectionMapping[p.section] = [];
|
|
228
|
+
sectionMapping[p.section].push(p);
|
|
229
|
+
});
|
|
230
|
+
parsed
|
|
231
|
+
.filter((p) => p.GA)
|
|
232
|
+
.forEach((p) => {
|
|
233
|
+
sectionMapping[p.section] = {
|
|
234
|
+
GA: true,
|
|
235
|
+
section: p.section,
|
|
236
|
+
name: p.name
|
|
237
|
+
};
|
|
238
|
+
});
|
|
239
|
+
return sectionMapping;
|
|
403
240
|
};
|
|
404
241
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
242
|
+
ds.subscribe("DS:update:pre", (e) => {
|
|
243
|
+
// ui.logger.Info("DS:update:pre - shift pressed:", isShiftPressed, e.items);
|
|
244
|
+
filterBuilder.value.isDragging = true;
|
|
245
|
+
if (!isShiftPressed) return;
|
|
246
|
+
const sectionMapping = parseSelected(e.items);
|
|
247
|
+
filterBuilder.value.clearHighlight();
|
|
248
|
+
Object.entries(sectionMapping).forEach(([section, rows]) => {
|
|
249
|
+
if (rows.GA) {
|
|
250
|
+
const isSelected = filterBuilder.value.filters.find(
|
|
251
|
+
(f) => filterBuilder.value.isForCurrentEvent(f) && f.section === section
|
|
252
|
+
);
|
|
253
|
+
if (isSelected) return;
|
|
254
|
+
filterBuilder.value.highlight({ section: section }, true);
|
|
255
|
+
} else
|
|
256
|
+
rows.forEach((row) => {
|
|
257
|
+
const isSelected = filterBuilder.value.filters.find(
|
|
258
|
+
(f) =>
|
|
259
|
+
(f.section === section && f.rows?.includes(row.row)) ||
|
|
260
|
+
(!f.rows && f.section === section && filterBuilder.value.isForCurrentEvent(f))
|
|
261
|
+
);
|
|
262
|
+
if (isSelected) return;
|
|
263
|
+
|
|
264
|
+
filterBuilder.value.highlight({ section, row: row.row });
|
|
265
|
+
});
|
|
411
266
|
});
|
|
412
|
-
};
|
|
267
|
+
});
|
|
413
268
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
269
|
+
ds.subscribe("DS:end", (e) => {
|
|
270
|
+
filterBuilder.value.isDragging = false;
|
|
271
|
+
panzoomInstance.resume();
|
|
272
|
+
filterBuilder.value.clearHighlight();
|
|
273
|
+
[...document.querySelectorAll("path")].map((f) => (f.style = ""));
|
|
274
|
+
if (!isShiftPressed) return;
|
|
275
|
+
const sectionMapping = parseSelected(e.items);
|
|
276
|
+
const secNameMapping = filterBuilder.value.getSectionNameMapping();
|
|
277
|
+
|
|
278
|
+
Object.entries(sectionMapping).forEach(([section, rows]) => {
|
|
279
|
+
if (rows.GA) {
|
|
280
|
+
const isSelected = filterBuilder.value.filters.find(
|
|
281
|
+
(f) => filterBuilder.value.isForCurrentEvent(f) && f.section === secNameMapping[section]
|
|
282
|
+
);
|
|
283
|
+
if (isSelected) return;
|
|
284
|
+
filterBuilder.value.addFilter({
|
|
285
|
+
event: filterBuilder.value.currentEventId,
|
|
286
|
+
section: secNameMapping[section]
|
|
287
|
+
});
|
|
288
|
+
} else {
|
|
289
|
+
const unselectedRows = [];
|
|
290
|
+
rows.forEach((row) => {
|
|
291
|
+
const isSelected = filterBuilder.value.filters.find(
|
|
292
|
+
(f) =>
|
|
293
|
+
(f.section === section && f.rows?.includes(row.row)) ||
|
|
294
|
+
(!f.rows && f.section === section && filterBuilder.value.isForCurrentEvent(f))
|
|
295
|
+
);
|
|
296
|
+
if (isSelected) return;
|
|
297
|
+
unselectedRows.push(row.row);
|
|
298
|
+
});
|
|
299
|
+
if (unselectedRows.length === 0) return;
|
|
300
|
+
filterBuilder.value.addFilter({
|
|
301
|
+
event: filterBuilder.value.currentEventId,
|
|
302
|
+
section,
|
|
303
|
+
rows: unselectedRows
|
|
304
|
+
});
|
|
305
|
+
}
|
|
420
306
|
});
|
|
421
|
-
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
// Cleanup function
|
|
425
|
-
const cleanupStyles = () => {
|
|
426
|
-
// Remove by ID to ensure we get it even if reference is lost
|
|
427
|
-
const existingStyle = document.getElementById(STYLE_ELEMENT_ID);
|
|
428
|
-
if (existingStyle) {
|
|
429
|
-
existingStyle.remove();
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
if (styleElement) {
|
|
433
|
-
styleElement.remove();
|
|
434
|
-
styleElement = null;
|
|
435
|
-
}
|
|
307
|
+
isShiftPressed = false;
|
|
308
|
+
});
|
|
436
309
|
};
|
|
437
310
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
311
|
+
const panzoomOptions = {
|
|
312
|
+
maxZoom: 8, // max zoom-in facor
|
|
313
|
+
minZoom: 0.8, // max zoom-out factor
|
|
314
|
+
panOnlyWhenZoomed: true,
|
|
315
|
+
bounds: true
|
|
441
316
|
};
|
|
317
|
+
let panzoomInstance;
|
|
442
318
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
setupCSSUpdates();
|
|
448
|
-
|
|
449
|
-
// Watch for reactive updates
|
|
450
|
-
watch(
|
|
451
|
-
cssUpdateTrigger,
|
|
452
|
-
() => {
|
|
453
|
-
injectStyles();
|
|
454
|
-
},
|
|
455
|
-
{ immediate: true }
|
|
456
|
-
);
|
|
457
|
-
|
|
458
|
-
// Cleanup on unmount
|
|
459
|
-
onUnmounted(() => {
|
|
460
|
-
cleanupStyles();
|
|
461
|
-
});
|
|
319
|
+
const svg = ref("");
|
|
320
|
+
const eventId = ref("");
|
|
321
|
+
const renderSeats = ref(false);
|
|
322
|
+
let renderer;
|
|
462
323
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
cleanupStyles();
|
|
466
|
-
});
|
|
324
|
+
const shownFilters = ref("All");
|
|
325
|
+
const filterBuilder = ref(new FilterBuilder());
|
|
467
326
|
|
|
468
327
|
const doesFilterShow = (filter) => {
|
|
469
328
|
if ((filter.event || filter.eventId) !== filterBuilder.value.currentEventId) return;
|
|
@@ -473,12 +332,10 @@ const doesFilterShow = (filter) => {
|
|
|
473
332
|
};
|
|
474
333
|
|
|
475
334
|
let rendererFactory;
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
})
|
|
480
|
-
console.error("Failed to initialize renderer:", error);
|
|
481
|
-
});
|
|
335
|
+
if (!DEBUG)
|
|
336
|
+
RendererFactory.then((r) => {
|
|
337
|
+
rendererFactory = new r.default();
|
|
338
|
+
});
|
|
482
339
|
|
|
483
340
|
const updateShownVenue = async () => {
|
|
484
341
|
eventId.value = eventId.value.trim();
|
|
@@ -491,16 +348,13 @@ const updateShownVenue = async () => {
|
|
|
491
348
|
return;
|
|
492
349
|
}
|
|
493
350
|
|
|
494
|
-
renderer = rendererFactory.createRenderer(eventId.value,
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
renderer.
|
|
500
|
-
|
|
501
|
-
includeDetailedAttributes: true,
|
|
502
|
-
renderRowBlocks: true
|
|
503
|
-
});
|
|
351
|
+
renderer = rendererFactory.createRenderer(eventId.value, "", country);
|
|
352
|
+
filterBuilder.value.highlightedSeatColor = renderer.c.highlightedSeatColor;
|
|
353
|
+
renderer.c.logFullError = true;
|
|
354
|
+
renderer.c.includeDetailedAttributes = true;
|
|
355
|
+
renderer.c.renderRowBlocks = true;
|
|
356
|
+
renderer.setFetchAvailabilityData(false);
|
|
357
|
+
renderer.setUrlProxy("/api/cors?url=");
|
|
504
358
|
|
|
505
359
|
try {
|
|
506
360
|
await renderer.render();
|
|
@@ -522,46 +376,18 @@ const updateShownVenue = async () => {
|
|
|
522
376
|
if (panzoomInstance?.dispose) panzoomInstance.dispose();
|
|
523
377
|
const elem = document.getElementById("svg-wrapper");
|
|
524
378
|
try {
|
|
525
|
-
|
|
526
|
-
if (elem && elem.children[0]) {
|
|
527
|
-
const svg = elem.children[0];
|
|
528
|
-
const isDesktop = window.innerWidth >= 1024;
|
|
529
|
-
|
|
530
|
-
// Ensure SVG doesn't exceed container width
|
|
531
|
-
svg.style.maxWidth = "100%";
|
|
532
|
-
svg.style.height = "auto";
|
|
533
|
-
svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
|
534
|
-
|
|
535
|
-
// Additional desktop constraints to prevent expansion
|
|
536
|
-
if (isDesktop) {
|
|
537
|
-
svg.style.maxHeight = "100%";
|
|
538
|
-
svg.style.width = "100%";
|
|
539
|
-
svg.style.objectFit = "contain";
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
// Initialize panzoom with updated options
|
|
543
|
-
panzoomInstance = panzoom(svg, panzoomOptions);
|
|
544
|
-
|
|
545
|
-
// Reset to initial position
|
|
546
|
-
panzoomInstance.moveTo(0, 0);
|
|
547
|
-
panzoomInstance.zoomAbs(0, 0, 1);
|
|
548
|
-
}
|
|
379
|
+
panzoomInstance = panzoom(elem.children[0], panzoomOptions);
|
|
549
380
|
} catch (e) {
|
|
550
381
|
ui.logger.Error("Couldnt use panzoom", e);
|
|
551
382
|
}
|
|
552
383
|
await nextTick();
|
|
553
384
|
await loadFilter();
|
|
554
385
|
filterBuilder.value.reload(eventId.value);
|
|
555
|
-
|
|
556
|
-
// Re-setup CSS system after reload
|
|
557
|
-
setupCSSUpdates();
|
|
558
|
-
filterBuilder.value.updateCss();
|
|
559
|
-
// doDragSelect();
|
|
386
|
+
doDragSelect();
|
|
560
387
|
};
|
|
561
388
|
|
|
562
389
|
const loadFilter = async () => {
|
|
563
390
|
try {
|
|
564
|
-
if (!eventId.value) return;
|
|
565
391
|
const res = await fetch(`/api/filter/load?eventId=${eventId.value}`);
|
|
566
392
|
const data = await res.json();
|
|
567
393
|
if (eventId.value) ui.showSuccess("Loaded filter data");
|
|
@@ -589,22 +415,16 @@ const saveFilter = async () => {
|
|
|
589
415
|
const handleZoom = (zoomEvent) => {
|
|
590
416
|
// handle zoom reset
|
|
591
417
|
if (zoomEvent === "r") {
|
|
592
|
-
//
|
|
593
|
-
panzoomInstance.
|
|
594
|
-
|
|
418
|
+
// reset zoom
|
|
419
|
+
panzoomInstance.smoothZoomAbs(0, 0, 1);
|
|
420
|
+
// reset location
|
|
595
421
|
return;
|
|
596
422
|
}
|
|
597
423
|
|
|
598
|
-
//
|
|
424
|
+
// handle zoom in / out
|
|
599
425
|
const { scale } = panzoomInstance.getTransform();
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
const newScale = zoomEvent ? scale + scale / 3 : scale - scale / 3;
|
|
603
|
-
|
|
604
|
-
// Apply zoom with bounds checking
|
|
605
|
-
if (newScale >= panzoomOptions.minZoom && newScale <= panzoomOptions.maxZoom) {
|
|
606
|
-
panzoomInstance.smoothZoom(0, 0, newScale / scale);
|
|
607
|
-
}
|
|
426
|
+
if (zoomEvent) return panzoomInstance.smoothZoomAbs(0, 0, scale + scale / 3);
|
|
427
|
+
else return panzoomInstance.smoothZoomAbs(0, 0, scale - scale / 3);
|
|
608
428
|
};
|
|
609
429
|
|
|
610
430
|
watch(renderSeats, async () => {
|
|
@@ -617,191 +437,15 @@ watch(renderSeats, async () => {
|
|
|
617
437
|
})();
|
|
618
438
|
</script>
|
|
619
439
|
|
|
620
|
-
<style scoped>
|
|
621
|
-
.slider-dim {
|
|
622
|
-
width: 60px;
|
|
623
|
-
height: 30px;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
.compact-filter {
|
|
627
|
-
font-size: 0.75rem;
|
|
628
|
-
padding: 0.25rem !important;
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
.compact-filter .handle {
|
|
632
|
-
transform: scale(0.8);
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
/* Enhanced table and filter styling */
|
|
636
|
-
.filters-container {
|
|
637
|
-
@apply space-y-0;
|
|
638
|
-
padding: 4px;
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
/* Dragging states for better UX */
|
|
642
|
-
.sortable-ghost {
|
|
643
|
-
@apply opacity-30;
|
|
644
|
-
border: 1px solid #44454b;
|
|
645
|
-
background-color: rgba(68, 69, 75, 0.1);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
.sortable-chosen .drag-handle {
|
|
649
|
-
border: 1px solid #44454b;
|
|
650
|
-
background-color: rgba(68, 69, 75, 0.2);
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
.sortable-drag {
|
|
654
|
-
@apply z-50 rotate-1 scale-105 transform shadow-xl;
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
/* Header button styling */
|
|
658
|
-
.header-btn {
|
|
659
|
-
@apply flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium transition-all duration-200 hover:scale-105;
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
.save-btn {
|
|
663
|
-
background-color: rgba(34, 197, 94, 0.2);
|
|
664
|
-
border-color: rgba(74, 222, 128, 0.5);
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
.save-btn:hover {
|
|
668
|
-
background-color: rgba(34, 197, 94, 0.3);
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
.clear-btn {
|
|
672
|
-
background-color: rgba(239, 68, 68, 0.2);
|
|
673
|
-
border-color: rgba(248, 113, 113, 0.5);
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
.clear-btn:hover {
|
|
677
|
-
background-color: rgba(239, 68, 68, 0.3);
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
.filter-builder-container {
|
|
681
|
-
height: 90vh;
|
|
682
|
-
overflow: hidden;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
.card-dark {
|
|
686
|
-
height: calc(100vh - 175px);
|
|
687
|
-
min-height: 500px;
|
|
688
|
-
overflow: hidden;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
@media (max-width: 768px) {
|
|
692
|
-
.filter-builder-container {
|
|
693
|
-
overflow: auto;
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
.card-dark {
|
|
697
|
-
height: auto;
|
|
698
|
-
overflow: auto;
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
/* Mobile portrait header spacing fixes */
|
|
703
|
-
@media (max-width: 640px) {
|
|
704
|
-
.filter-builder-container .flex-center {
|
|
705
|
-
gap: 0.5rem;
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
/* iPhone landscape and tablet portrait mode fixes */
|
|
710
|
-
@media (max-width: 1023px) and (max-height: 768px) {
|
|
711
|
-
.filter-builder-container {
|
|
712
|
-
height: auto;
|
|
713
|
-
min-height: 100vh;
|
|
714
|
-
overflow: auto;
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
.card-dark {
|
|
718
|
-
height: auto;
|
|
719
|
-
min-height: 500px;
|
|
720
|
-
overflow: auto;
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
/* Desktop: enforce grid column constraints */
|
|
725
|
-
@media (min-width: 1024px) {
|
|
726
|
-
.lg\\:grid-cols-5 > .lg\\:col-span-3 {
|
|
727
|
-
max-width: 60%; /* 3/5 of grid */
|
|
728
|
-
flex-shrink: 0;
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
.svg-container {
|
|
733
|
-
min-height: 300px;
|
|
734
|
-
height: 100%;
|
|
735
|
-
width: 100%;
|
|
736
|
-
position: relative;
|
|
737
|
-
overflow: auto;
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
/* Desktop: constrain svg-container to prevent expansion */
|
|
741
|
-
@media (min-width: 1024px) {
|
|
742
|
-
.svg-container {
|
|
743
|
-
position: relative;
|
|
744
|
-
max-width: 100%;
|
|
745
|
-
max-height: 100%;
|
|
746
|
-
overflow: hidden;
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
</style>
|
|
750
|
-
|
|
751
440
|
<style>
|
|
752
|
-
/* Global styles needed for dynamically injected SVG content and Filter.js CSS injection */
|
|
753
|
-
.svg-wrapper {
|
|
754
|
-
position: relative;
|
|
755
|
-
transform-origin: 0 0;
|
|
756
|
-
min-width: 100%;
|
|
757
|
-
min-height: 100%;
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
/* Desktop constraints - prevent svg-wrapper from expanding beyond container */
|
|
761
|
-
@media (min-width: 1024px) {
|
|
762
|
-
.svg-wrapper {
|
|
763
|
-
position: absolute;
|
|
764
|
-
top: 0;
|
|
765
|
-
left: 0;
|
|
766
|
-
width: 100%;
|
|
767
|
-
height: 100%;
|
|
768
|
-
max-width: 100%;
|
|
769
|
-
max-height: 100%;
|
|
770
|
-
min-width: unset;
|
|
771
|
-
min-height: unset;
|
|
772
|
-
overflow: hidden;
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
|
|
776
441
|
.svg-wrapper > svg {
|
|
777
|
-
width: 100%;
|
|
778
|
-
height: auto;
|
|
779
442
|
background: center center no-repeat;
|
|
443
|
+
overflow: hidden;
|
|
780
444
|
background-size: contain;
|
|
781
445
|
}
|
|
782
446
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
max-width: 100%;
|
|
787
|
-
max-height: 100%;
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
/* Ensure Filter.js generated CSS works properly */
|
|
792
|
-
.svg-wrapper path {
|
|
793
|
-
pointer-events: auto;
|
|
794
|
-
cursor: pointer;
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
.svg-wrapper path[generaladmission] {
|
|
798
|
-
pointer-events: auto;
|
|
799
|
-
cursor: pointer;
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
/* Hover effects for general admission seats */
|
|
803
|
-
.svg-wrapper path[generaladmission]:hover {
|
|
804
|
-
pointer-events: all;
|
|
805
|
-
cursor: pointer;
|
|
447
|
+
.slider-dim {
|
|
448
|
+
width: 60px;
|
|
449
|
+
height: 30px;
|
|
806
450
|
}
|
|
807
451
|
</style>
|