@necrolab/dashboard 0.5.14 → 0.5.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/backend/api.js +2 -3
  2. package/eslint.config.js +46 -0
  3. package/index.html +2 -1
  4. package/package.json +5 -2
  5. package/src/App.vue +140 -170
  6. package/src/assets/css/base/mixins.scss +72 -0
  7. package/src/assets/css/base/reset.scss +0 -2
  8. package/src/assets/css/base/scroll.scss +43 -36
  9. package/src/assets/css/base/typography.scss +9 -10
  10. package/src/assets/css/base/variables.scss +43 -0
  11. package/src/assets/css/components/accessibility.scss +37 -0
  12. package/src/assets/css/components/buttons.scss +58 -15
  13. package/src/assets/css/components/forms.scss +31 -32
  14. package/src/assets/css/components/headers.scss +119 -0
  15. package/src/assets/css/components/modals.scss +2 -2
  16. package/src/assets/css/components/search-groups.scss +28 -19
  17. package/src/assets/css/components/tables.scss +5 -7
  18. package/src/assets/css/components/toasts.scss +7 -7
  19. package/src/assets/css/components/utilities.scss +220 -0
  20. package/src/assets/css/main.scss +72 -75
  21. package/src/components/Auth/LoginForm.vue +5 -84
  22. package/src/components/Editors/Account/Account.vue +8 -10
  23. package/src/components/Editors/Account/AccountCreator.vue +28 -59
  24. package/src/components/Editors/Account/AccountView.vue +38 -86
  25. package/src/components/Editors/Account/CreateAccount.vue +8 -50
  26. package/src/components/Editors/Profile/CreateProfile.vue +74 -131
  27. package/src/components/Editors/Profile/Profile.vue +15 -17
  28. package/src/components/Editors/Profile/ProfileCountryChooser.vue +16 -60
  29. package/src/components/Editors/Profile/ProfileView.vue +46 -96
  30. package/src/components/Editors/TagLabel.vue +16 -55
  31. package/src/components/Editors/TagToggle.vue +20 -8
  32. package/src/components/Filter/Filter.vue +62 -75
  33. package/src/components/Filter/FilterPreview.vue +161 -135
  34. package/src/components/Filter/PriceSortToggle.vue +36 -43
  35. package/src/components/Table/Header.vue +1 -1
  36. package/src/components/Table/Table.vue +61 -12
  37. package/src/components/Tasks/CheckStock.vue +7 -16
  38. package/src/components/Tasks/Controls/DesktopControls.vue +15 -60
  39. package/src/components/Tasks/Controls/MobileControls.vue +5 -20
  40. package/src/components/Tasks/CreateTaskAXS.vue +20 -118
  41. package/src/components/Tasks/CreateTaskTM.vue +33 -189
  42. package/src/components/Tasks/EventDetailRow.vue +21 -0
  43. package/src/components/Tasks/MassEdit.vue +6 -16
  44. package/src/components/Tasks/QuickSettings.vue +140 -216
  45. package/src/components/Tasks/ScrapeVenue.vue +4 -13
  46. package/src/components/Tasks/Stats.vue +19 -38
  47. package/src/components/Tasks/Task.vue +65 -268
  48. package/src/components/Tasks/TaskLabel.vue +9 -3
  49. package/src/components/Tasks/TaskView.vue +43 -63
  50. package/src/components/Tasks/Utilities.vue +10 -42
  51. package/src/components/Tasks/ViewTask.vue +23 -107
  52. package/src/components/icons/Close.vue +2 -8
  53. package/src/components/icons/Gear.vue +8 -8
  54. package/src/components/icons/Hash.vue +5 -0
  55. package/src/components/icons/Key.vue +2 -8
  56. package/src/components/icons/Pencil.vue +2 -8
  57. package/src/components/icons/Profile.vue +2 -8
  58. package/src/components/icons/Sell.vue +2 -8
  59. package/src/components/icons/Spinner.vue +4 -7
  60. package/src/components/icons/SquareCheck.vue +2 -8
  61. package/src/components/icons/SquareUncheck.vue +2 -8
  62. package/src/components/icons/Wildcard.vue +2 -8
  63. package/src/components/icons/index.js +3 -1
  64. package/src/components/ui/ActionButtonGroup.vue +113 -52
  65. package/src/components/ui/BalanceIndicator.vue +60 -0
  66. package/src/components/ui/EmptyState.vue +24 -0
  67. package/src/components/ui/EnableDisableToggle.vue +23 -0
  68. package/src/components/ui/FormField.vue +48 -48
  69. package/src/components/ui/IconLabel.vue +23 -0
  70. package/src/components/ui/InfoRow.vue +21 -54
  71. package/src/components/ui/Modal.vue +78 -37
  72. package/src/components/ui/Navbar.vue +60 -41
  73. package/src/components/ui/ReadonlyFieldsSection.vue +31 -0
  74. package/src/components/ui/ReconnectIndicator.vue +111 -124
  75. package/src/components/ui/SectionCard.vue +6 -14
  76. package/src/components/ui/Splash.vue +2 -10
  77. package/src/components/ui/StatusBadge.vue +26 -28
  78. package/src/components/ui/TaskToggle.vue +54 -0
  79. package/src/components/ui/controls/CountryChooser.vue +27 -64
  80. package/src/components/ui/controls/EyeToggle.vue +1 -1
  81. package/src/components/ui/controls/atomic/Checkbox.vue +40 -121
  82. package/src/components/ui/controls/atomic/Dropdown.vue +102 -95
  83. package/src/components/ui/controls/atomic/MultiDropdown.vue +72 -94
  84. package/src/components/ui/controls/atomic/Switch.vue +21 -84
  85. package/src/composables/useColorMapping.js +15 -0
  86. package/src/composables/useCopyToClipboard.js +1 -1
  87. package/src/composables/useDateFormatting.js +21 -0
  88. package/src/composables/useDeviceDetection.js +14 -0
  89. package/src/composables/useDropdownPosition.js +5 -6
  90. package/src/composables/useDynamicTableHeight.js +31 -0
  91. package/src/composables/useRowSelection.js +0 -3
  92. package/src/composables/useTicketPricing.js +16 -0
  93. package/src/composables/useWindowDimensions.js +21 -0
  94. package/src/libs/Filter.js +14 -20
  95. package/src/libs/panzoom.js +1 -5
  96. package/src/libs/utils/array.js +60 -0
  97. package/src/{stores/utils.js → libs/utils/dataGeneration.js} +2 -250
  98. package/src/libs/utils/eventUrl.js +40 -0
  99. package/src/libs/utils/string.js +28 -0
  100. package/src/libs/utils/time.js +20 -0
  101. package/src/libs/utils/validation.js +88 -0
  102. package/src/main.js +0 -2
  103. package/src/stores/connection.js +1 -4
  104. package/src/stores/logger.js +6 -12
  105. package/src/stores/sampleData.js +1 -2
  106. package/src/stores/ui.js +59 -36
  107. package/src/views/Accounts.vue +17 -31
  108. package/src/views/Console.vue +76 -176
  109. package/src/views/Editor.vue +217 -383
  110. package/src/views/FilterBuilder.vue +190 -373
  111. package/src/views/Login.vue +3 -28
  112. package/src/views/Profiles.vue +12 -22
  113. package/src/views/Tasks.vue +51 -38
  114. package/tailwind.config.js +82 -71
  115. package/workbox-config.cjs +47 -5
  116. package/docs/plans/2026-02-08-tailwind-consolidation.md +0 -2416
  117. package/exit +0 -209
  118. package/run +0 -177
  119. package/switch-branch.sh +0 -41
  120. /package/public/{reconnect-logo.png → img/reconnect-logo.png} +0 -0
@@ -1,7 +1,6 @@
1
1
  export default (function (f) {
2
2
  const panzoom = f();
3
3
  window.panzoom = panzoom;
4
- // module.exports = panzoom;
5
4
  return panzoom;
6
5
  })(function () {
7
6
  var define, module, exports;
@@ -718,7 +717,6 @@ export default (function (f) {
718
717
  failTransformOrigin();
719
718
  }
720
719
  function failTransformOrigin(options) {
721
- console.error(options);
722
720
  throw new Error(
723
721
  [
724
722
  "Cannot parse transform origin.",
@@ -783,7 +781,6 @@ export default (function (f) {
783
781
  setTimeout(tryAttach, 100);
784
782
  return;
785
783
  }
786
- console.error("Cannot find the panzoom element", globalName);
787
784
  return;
788
785
  }
789
786
  var options = collectOptions(panzoomScript);
@@ -1107,8 +1104,7 @@ export default (function (f) {
1107
1104
  var easing = typeof options.easing === "function" ? options.easing : animations[options.easing];
1108
1105
  if (!easing) {
1109
1106
  if (options.easing) {
1110
- console.warn("Unknown easing function in amator: " + options.easing);
1111
- }
1107
+ }
1112
1108
  easing = animations.ease;
1113
1109
  }
1114
1110
  var step = typeof options.step === "function" ? options.step : noop;
@@ -0,0 +1,60 @@
1
+ const removeDuplicates = (arr) => [...new Set(arr)];
2
+
3
+ const pickRandom = (arr) => arr[Math.floor(Math.random() * arr.length)];
4
+
5
+ function betterSort(a, b) {
6
+ if (a === undefined || a === null) return b === undefined || b === null ? 0 : -1;
7
+ if (b === undefined || b === null) return 1;
8
+
9
+ const aStr = String(a);
10
+ const bStr = String(b);
11
+
12
+ if (!isNaN(aStr) && !isNaN(bStr)) {
13
+ return Number(aStr) - Number(bStr);
14
+ }
15
+
16
+ const aParts = aStr.split(/(\d+)/).filter(Boolean);
17
+ const bParts = bStr.split(/(\d+)/).filter(Boolean);
18
+
19
+ const len = Math.min(aParts.length, bParts.length);
20
+ for (let i = 0; i < len; i++) {
21
+ if (!isNaN(aParts[i]) && !isNaN(bParts[i])) {
22
+ const numA = parseInt(aParts[i], 10);
23
+ const numB = parseInt(bParts[i], 10);
24
+ if (numA !== numB) return numA - numB;
25
+ } else {
26
+ const cmp = aParts[i].localeCompare(bParts[i]);
27
+ if (cmp !== 0) return cmp;
28
+ }
29
+ }
30
+
31
+ return aParts.length - bParts.length;
32
+ }
33
+
34
+ function sortTaskIds(a, b) {
35
+ const parseId = (id) => {
36
+ if (!id) return { prefix: "", num: -1 };
37
+
38
+ if (/^\d+$/.test(id)) {
39
+ return { prefix: "", num: parseInt(id, 10) };
40
+ }
41
+
42
+ const match = id.match(/^([A-Za-z-]+)(\d+)$/);
43
+ if (match) {
44
+ return { prefix: match[1], num: parseInt(match[2], 10) };
45
+ }
46
+
47
+ return { prefix: id, num: -1 };
48
+ };
49
+
50
+ const aInfo = parseId(a);
51
+ const bInfo = parseId(b);
52
+
53
+ if (aInfo.prefix !== bInfo.prefix) {
54
+ return aInfo.prefix.localeCompare(bInfo.prefix);
55
+ }
56
+
57
+ return aInfo.num - bInfo.num;
58
+ }
59
+
60
+ export { removeDuplicates, pickRandom, betterSort, sortTaskIds };
@@ -1,4 +1,4 @@
1
- import cities from "./cities.json";
1
+ import cities from "@/stores/cities.json";
2
2
 
3
3
  function generateStreetAddress() {
4
4
  const streetTypes = [
@@ -47,8 +47,6 @@ function generateStreetAddress() {
47
47
  "Pleasant View",
48
48
  "Rolling",
49
49
  "Scenic",
50
- "Shady Grove",
51
- "Stone Gate",
52
50
  "Sunset",
53
51
  "Valley View",
54
52
  "Willow Brook",
@@ -315,93 +313,6 @@ function generateStreetAddress() {
315
313
  return `${houseNumber} ${streetName} ${streetType}`.trim().replace(/\s+/g, " ");
316
314
  }
317
315
 
318
- const sortAlphaNum = (a, b) => {
319
- var reA = /[^a-zA-Z]/g;
320
- var reN = /[^0-9]/g;
321
- var AInt = parseInt(a, 10);
322
- var BInt = parseInt(b, 10);
323
-
324
- if (isNaN(AInt) && isNaN(BInt)) {
325
- var aA = a.replace(reA, "");
326
- var bA = b.replace(reA, "");
327
- if (aA === bA) {
328
- var aN = parseInt(a.replace(reN, ""), 10);
329
- var bN = parseInt(b.replace(reN, ""), 10);
330
- return aN === bN ? 0 : aN > bN ? 1 : -1;
331
- } else {
332
- return aA > bA ? 1 : -1;
333
- }
334
- } else if (isNaN(AInt)) {
335
- //A is not an Int
336
- return 1; //to make alphanumeric sort first return -1 here
337
- } else if (isNaN(BInt)) {
338
- //B is not an Int
339
- return -1; //to make alphanumeric sort first return 1 here
340
- } else {
341
- return AInt > BInt ? 1 : -1;
342
- }
343
- };
344
-
345
- const timeDifference = (date1, date2) => {
346
- let dif = date1 - date2;
347
- if (dif < 0) return "00:00";
348
-
349
- const dayDif = Math.floor(dif / 1000 / 60 / 60 / 24);
350
- dif -= dayDif * 1000 * 60 * 60 * 24;
351
- const hourDif = Math.floor(dif / 1000 / 60 / 60);
352
- dif -= hourDif * 1000 * 60 * 60;
353
- const minDif = Math.floor(dif / 1000 / 60);
354
- dif -= minDif * 1000 * 60;
355
- const secDif = Math.floor(dif / 1000);
356
-
357
- const strMin = String(minDif).padStart(2, "0");
358
- const strSec = String(secDif).padStart(2, "0");
359
- const str = `${strMin}:${strSec}`;
360
- if (str === "NaN:NaN") return "00:00";
361
- return str;
362
- };
363
-
364
- const parseAxsEventUrl = (url) => {
365
- const HOST = "www.axs.com";
366
-
367
- if (!url.startsWith("https://")) return { eventId: url };
368
- if (!url.includes(`https://${HOST}`)) return {};
369
-
370
- const siteMatch = url.match(new RegExp(`https://${HOST}(/uk)?`));
371
- const eventMatch = url.match(/\/events\/(\d+)/);
372
- const promoMatch = url.match(/\/promopage\/(\d+)/);
373
-
374
- if (!siteMatch || !eventMatch) return {};
375
-
376
- const siteId = siteMatch[1] === "/uk" ? "AXS_UK" : "AXS_US";
377
- const eventId = eventMatch[1];
378
- const promoId = promoMatch?.[1];
379
-
380
- const result = { eventId, siteId };
381
- if (promoId) result.promoId = promoId;
382
-
383
- return result;
384
- };
385
-
386
- const parseTmEventUrl = (url) => {
387
- if (!url.includes("https://")) {
388
- return { eventId: url };
389
- }
390
- const urlRegex = /^.*?\/([^/?]+)(?:\?(.*))?$/i;
391
- const [, eventId, queryString = ""] = url.match(urlRegex) || [];
392
- const queryParams = new URLSearchParams(queryString);
393
-
394
- return {
395
- eventId: eventId,
396
- eventDid: queryParams.get("did"),
397
- clOrigin: queryParams.get("subchannel_id") || queryParams.get("CL_ORIGIN")
398
- };
399
- };
400
-
401
- const isEU = (siteId) => !["US", "AU", "UK", "CA", "NZ", "IE"].includes(siteId.split("_")?.[1] || siteId);
402
-
403
- const removeDuplicates = (arr) => [...new Set(arr)];
404
-
405
316
  const pickRandom = (arr) => arr[Math.floor(Math.random() * arr.length)];
406
317
 
407
318
  const fakeId = () => {
@@ -418,163 +329,4 @@ const fakeId = () => {
418
329
  return profile;
419
330
  };
420
331
 
421
- // Card type definitions with their patterns and gaps
422
- const CARD_TYPES = {
423
- visa: {
424
- pattern: /^4\d{12}(?:\d{3})?$/,
425
- gaps: [4, 8, 12]
426
- },
427
- mastercard: {
428
- pattern: /^5[1-5]\d{14}$/,
429
- gaps: [4, 8, 12]
430
- },
431
- amex: {
432
- pattern: /^3[47]\d{13}$/,
433
- gaps: [4, 10]
434
- }
435
- };
436
-
437
- // Implementation of Luhn algorithm for card number validation
438
- function luhnCheck(cardNumber) {
439
- const digits = cardNumber.replace(/\D/g, "");
440
- let sum = 0;
441
- let isEven = false;
442
-
443
- // Loop from right to left
444
- for (let i = digits.length - 1; i >= 0; i--) {
445
- let digit = parseInt(digits[i], 10);
446
-
447
- if (isEven) {
448
- digit *= 2;
449
- if (digit > 9) {
450
- digit -= 9;
451
- }
452
- }
453
-
454
- sum += digit;
455
- isEven = !isEven;
456
- }
457
-
458
- return sum % 10 === 0;
459
- }
460
-
461
- const getCardType = (str) => {
462
- switch (str?.[0]) {
463
- default:
464
- case "4":
465
- return "Visa";
466
- case "3":
467
- return "Amex";
468
- case "5":
469
- return "Master";
470
- }
471
- };
472
-
473
- // Format card number with proper spacing
474
- function formatCardNumber(cardNumber, gaps) {
475
- try {
476
- const cleanNumber = cardNumber.replace(/\D/g, "");
477
- const formatted = cleanNumber.split("");
478
-
479
- // Insert spaces at the specified gaps
480
- gaps.forEach((gap, index) => {
481
- if (formatted.length > gap + index) {
482
- formatted.splice(gap + index, 0, " ");
483
- }
484
- });
485
-
486
- return formatted.join("");
487
- } catch {
488
- return cardNumber;
489
- }
490
- }
491
-
492
- // Main validation function
493
- function validateCard(cardNumber) {
494
- const cleanNumber = cardNumber.replace(/\s+/g, "");
495
- const type = getCardType(cleanNumber);
496
- const cardTypeInfo = CARD_TYPES[type] || CARD_TYPES.visa; // Default to visa gaps if unknown
497
-
498
- const isValid =
499
- cleanNumber.length >= 13 && cleanNumber.length <= 19 && /^\d+$/.test(cleanNumber) && luhnCheck(cleanNumber);
500
-
501
- return {
502
- type,
503
- invalid: !isValid,
504
- formatted: formatCardNumber(cleanNumber, cardTypeInfo.gaps)
505
- };
506
- }
507
-
508
- function sortTaskIds(a, b) {
509
- const parseId = (id) => {
510
- if (!id) return { prefix: "", num: -1 };
511
-
512
- if (/^\d+$/.test(id)) {
513
- return { prefix: "", num: parseInt(id, 10) };
514
- }
515
-
516
- const match = id.match(/^([A-Za-z-]+)(\d+)$/);
517
- if (match) {
518
- return { prefix: match[1], num: parseInt(match[2], 10) };
519
- }
520
-
521
- return { prefix: id, num: -1 };
522
- };
523
-
524
- const aInfo = parseId(a);
525
- const bInfo = parseId(b);
526
-
527
- if (aInfo.prefix !== bInfo.prefix) {
528
- return aInfo.prefix.localeCompare(bInfo.prefix);
529
- }
530
-
531
- return aInfo.num - bInfo.num;
532
- }
533
-
534
- const firstUpper = (str) => `${str[0].toUpperCase()}${str.slice(1).toLowerCase()}`;
535
-
536
- function betterSort(a, b) {
537
- if (a === undefined || a === null) return b === undefined || b === null ? 0 : -1;
538
- if (b === undefined || b === null) return 1;
539
-
540
- const aStr = String(a);
541
- const bStr = String(b);
542
-
543
- if (!isNaN(aStr) && !isNaN(bStr)) {
544
- return Number(aStr) - Number(bStr);
545
- }
546
-
547
- const aParts = aStr.split(/(\d+)/).filter(Boolean);
548
- const bParts = bStr.split(/(\d+)/).filter(Boolean);
549
-
550
- const len = Math.min(aParts.length, bParts.length);
551
- for (let i = 0; i < len; i++) {
552
- if (!isNaN(aParts[i]) && !isNaN(bParts[i])) {
553
- const numA = parseInt(aParts[i], 10);
554
- const numB = parseInt(bParts[i], 10);
555
- if (numA !== numB) return numA - numB;
556
- } else {
557
- const cmp = aParts[i].localeCompare(bParts[i]);
558
- if (cmp !== 0) return cmp;
559
- }
560
- }
561
-
562
- return aParts.length - bParts.length;
563
- }
564
-
565
- export {
566
- generateStreetAddress,
567
- timeDifference,
568
- sortAlphaNum,
569
- parseAxsEventUrl,
570
- parseTmEventUrl,
571
- isEU,
572
- removeDuplicates,
573
- pickRandom,
574
- fakeId,
575
- getCardType,
576
- validateCard,
577
- sortTaskIds,
578
- firstUpper,
579
- betterSort
580
- };
332
+ export { fakeId, generateStreetAddress, cities };
@@ -0,0 +1,40 @@
1
+ const parseAxsEventUrl = (url) => {
2
+ const HOST = "www.axs.com";
3
+
4
+ if (!url.startsWith("https://")) return { eventId: url };
5
+ if (!url.includes(`https://${HOST}`)) return {};
6
+
7
+ const siteMatch = url.match(new RegExp(`https://${HOST}(/uk)?`));
8
+ const eventMatch = url.match(/\/events\/(\d+)/);
9
+ const promoMatch = url.match(/\/promopage\/(\d+)/);
10
+
11
+ if (!siteMatch || !eventMatch) return {};
12
+
13
+ const siteId = siteMatch[1] === "/uk" ? "AXS_UK" : "AXS_US";
14
+ const eventId = eventMatch[1];
15
+ const promoId = promoMatch?.[1];
16
+
17
+ const result = { eventId, siteId };
18
+ if (promoId) result.promoId = promoId;
19
+
20
+ return result;
21
+ };
22
+
23
+ const parseTmEventUrl = (url) => {
24
+ if (!url.includes("https://")) {
25
+ return { eventId: url };
26
+ }
27
+ const urlRegex = /^.*?\/([^/?]+)(?:\?(.*))?$/i;
28
+ const [, eventId, queryString = ""] = url.match(urlRegex) || [];
29
+ const queryParams = new URLSearchParams(queryString);
30
+
31
+ return {
32
+ eventId: eventId,
33
+ eventDid: queryParams.get("did"),
34
+ clOrigin: queryParams.get("subchannel_id") || queryParams.get("CL_ORIGIN")
35
+ };
36
+ };
37
+
38
+ const isEU = (siteId) => !["US", "AU", "UK", "CA", "NZ", "IE"].includes(siteId.split("_")?.[1] || siteId);
39
+
40
+ export { parseAxsEventUrl, parseTmEventUrl, isEU };
@@ -0,0 +1,28 @@
1
+ const firstUpper = (str) => `${str[0].toUpperCase()}${str.slice(1).toLowerCase()}`;
2
+
3
+ const sortAlphaNum = (a, b) => {
4
+ var reA = /[^a-zA-Z]/g;
5
+ var reN = /[^0-9]/g;
6
+ var AInt = parseInt(a, 10);
7
+ var BInt = parseInt(b, 10);
8
+
9
+ if (isNaN(AInt) && isNaN(BInt)) {
10
+ var aA = a.replace(reA, "");
11
+ var bA = b.replace(reA, "");
12
+ if (aA === bA) {
13
+ var aN = parseInt(a.replace(reN, ""), 10);
14
+ var bN = parseInt(b.replace(reN, ""), 10);
15
+ return aN === bN ? 0 : aN > bN ? 1 : -1;
16
+ } else {
17
+ return aA > bA ? 1 : -1;
18
+ }
19
+ } else if (isNaN(AInt)) {
20
+ return 1;
21
+ } else if (isNaN(BInt)) {
22
+ return -1;
23
+ } else {
24
+ return AInt > BInt ? 1 : -1;
25
+ }
26
+ };
27
+
28
+ export { firstUpper, sortAlphaNum };
@@ -0,0 +1,20 @@
1
+ const timeDifference = (date1, date2) => {
2
+ let dif = date1 - date2;
3
+ if (dif < 0) return "00:00";
4
+
5
+ const dayDif = Math.floor(dif / 1000 / 60 / 60 / 24);
6
+ dif -= dayDif * 1000 * 60 * 60 * 24;
7
+ const hourDif = Math.floor(dif / 1000 / 60 / 60);
8
+ dif -= hourDif * 1000 * 60 * 60;
9
+ const minDif = Math.floor(dif / 1000 / 60);
10
+ dif -= minDif * 1000 * 60;
11
+ const secDif = Math.floor(dif / 1000);
12
+
13
+ const strMin = String(minDif).padStart(2, "0");
14
+ const strSec = String(secDif).padStart(2, "0");
15
+ const str = `${strMin}:${strSec}`;
16
+ if (str === "NaN:NaN") return "00:00";
17
+ return str;
18
+ };
19
+
20
+ export { timeDifference };
@@ -0,0 +1,88 @@
1
+ // Card type definitions with their patterns and gaps
2
+ const CARD_TYPES = {
3
+ visa: {
4
+ pattern: /^4\d{12}(?:\d{3})?$/,
5
+ gaps: [4, 8, 12]
6
+ },
7
+ mastercard: {
8
+ pattern: /^5[1-5]\d{14}$/,
9
+ gaps: [4, 8, 12]
10
+ },
11
+ amex: {
12
+ pattern: /^3[47]\d{13}$/,
13
+ gaps: [4, 10]
14
+ }
15
+ };
16
+
17
+ // Implementation of Luhn algorithm for card number validation
18
+ function luhnCheck(cardNumber) {
19
+ const digits = cardNumber.replace(/\D/g, "");
20
+ let sum = 0;
21
+ let isEven = false;
22
+
23
+ // Loop from right to left
24
+ for (let i = digits.length - 1; i >= 0; i--) {
25
+ let digit = parseInt(digits[i], 10);
26
+
27
+ if (isEven) {
28
+ digit *= 2;
29
+ if (digit > 9) {
30
+ digit -= 9;
31
+ }
32
+ }
33
+
34
+ sum += digit;
35
+ isEven = !isEven;
36
+ }
37
+
38
+ return sum % 10 === 0;
39
+ }
40
+
41
+ const getCardType = (str) => {
42
+ switch (str?.[0]) {
43
+ default:
44
+ case "4":
45
+ return "Visa";
46
+ case "3":
47
+ return "Amex";
48
+ case "5":
49
+ return "Master";
50
+ }
51
+ };
52
+
53
+ // Format card number with proper spacing
54
+ function formatCardNumber(cardNumber, gaps) {
55
+ try {
56
+ const cleanNumber = cardNumber.replace(/\D/g, "");
57
+ const formatted = cleanNumber.split("");
58
+
59
+ // Insert spaces at the specified gaps
60
+ gaps.forEach((gap, index) => {
61
+ if (formatted.length > gap + index) {
62
+ formatted.splice(gap + index, 0, " ");
63
+ }
64
+ });
65
+
66
+ return formatted.join("");
67
+ } catch {
68
+ return cardNumber;
69
+ }
70
+ }
71
+
72
+ // Main validation function
73
+ function validateCard(cardNumber) {
74
+ const cleanNumber = cardNumber.replace(/\s+/g, "");
75
+ const type = getCardType(cleanNumber);
76
+ const cardTypeInfo = CARD_TYPES[type] || CARD_TYPES.visa; // Default to visa gaps if unknown
77
+
78
+ const isValid =
79
+ cleanNumber.length >= 13 && cleanNumber.length <= 19 && /^\d+$/.test(cleanNumber) && luhnCheck(cleanNumber);
80
+
81
+ return {
82
+ type,
83
+ invalid: !isValid,
84
+ formatted: formatCardNumber(cleanNumber, cardTypeInfo.gaps)
85
+ };
86
+ }
87
+
88
+ export { luhnCheck, validateCard, getCardType, formatCardNumber };
package/src/main.js CHANGED
@@ -14,8 +14,6 @@ import "./registerServiceWorker";
14
14
  const app = createApp(App);
15
15
 
16
16
  app.config.performance = true;
17
- app.config.globalProperties.window = window;
18
- app.config.globalProperties.document = document;
19
17
 
20
18
  app.use(createPinia());
21
19
  app.use(router);
@@ -2,7 +2,7 @@ import { useUIStore } from "@/stores/ui";
2
2
  import WebsocketHeartbeatJs from "websocket-heartbeat-js";
3
3
  import { decode } from "@msgpack/msgpack";
4
4
  import router from "@/router/index";
5
- import { sortTaskIds } from "@/stores/utils";
5
+ import { sortTaskIds } from "@/libs/utils/array";
6
6
 
7
7
  export class ConnectionHandler {
8
8
  handleWebsocketMessages(msg) {
@@ -118,7 +118,6 @@ export class ConnectionHandler {
118
118
  } else if (msg.update) {
119
119
  try {
120
120
  Object.entries(msg.update).forEach((change) => (this.ui.tasks[msg.id][change[0]] = change[1]));
121
- // eslint-disable-next-line no-empty
122
121
  } catch {}
123
122
  } else {
124
123
  if (!this.ui.tasks[msg.id]) this.ui.tasks[msg.id] = msg.task;
@@ -148,7 +147,6 @@ export class ConnectionHandler {
148
147
  break;
149
148
 
150
149
  case "auth":
151
- // redirect to / if on login page, but successfully logged in
152
150
  if (router.currentRoute.value.name === "login") router.push("/");
153
151
  this.ui.setProfile(msg);
154
152
  break;
@@ -230,7 +228,6 @@ export class ConnectionHandler {
230
228
  hasShownDisconnect = true;
231
229
  };
232
230
 
233
- // this.socket.addEventListener('message', );
234
231
  }
235
232
 
236
233
  sendContinueTask(taskId, continueType) {
@@ -44,20 +44,15 @@ class Logger {
44
44
 
45
45
  args.unshift(timestamp);
46
46
 
47
- // Format objects for console output
48
- const formattedArgs = args.map((arg) => {
49
- if (typeof arg === "object" && arg !== null) {
50
- console.log(arg._value ? arg._value : arg);
51
- return arg;
52
- }
53
- return arg;
54
- });
55
-
56
47
  // For styled console output in browser
57
48
  if (style) {
58
- console.log(`%c${formattedArgs.join(" ")}`, style);
49
+ /* eslint-disable no-console */
50
+ console.log(`%c${args.join(" ")}`, style);
51
+ /* eslint-enable no-console */
59
52
  } else {
60
- console.log(...formattedArgs);
53
+ /* eslint-disable no-console */
54
+ console.log(...args);
55
+ /* eslint-enable no-console */
61
56
  }
62
57
  }
63
58
 
@@ -95,7 +90,6 @@ class Logger {
95
90
  }
96
91
  }
97
92
 
98
- // Export as an object instead of using module.exports
99
93
  export const createLogger = (args) => {
100
94
  const logger = new Logger();
101
95
  logger.defaultArgs = typeof args === "string" ? [args] : Array.isArray(args) ? args : undefined;
@@ -19,14 +19,13 @@ export default {
19
19
  email: "grantelam@hotmail.com",
20
20
  password: "Dkstrhf4srth56Gksj",
21
21
  status: "Event already happened long long long long long long longlong long long long",
22
- inQueue: queueStats,
23
22
  statusColor: "red",
24
23
  manual: false,
25
24
  quickQueue: false,
26
25
  loginAfterCart: false,
27
26
  quantity: 8,
28
27
  proxy: "http://events1597:yEXBe4Hs@23.26.22.61:61234",
29
- eventId: "01005D5C92031D57",
28
+ eventId: "grantelam@hotmail.com",
30
29
  reservedTicketsList: "• 2x 301/E ($86.47) \n• 2x 306/U ($86.47) \n$345.88",
31
30
  expirationTime: null,
32
31
  doNotPay: false,