@necrolab/dashboard 0.4.221 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +27 -1
- package/.vscode/extensions.json +1 -1
- package/README.md +64 -2
- package/artwork/image.png +0 -0
- package/backend/api.js +26 -24
- package/backend/auth.js +2 -2
- package/backend/batching.js +1 -1
- package/backend/endpoints.js +8 -11
- package/backend/index.js +2 -2
- package/backend/mock-data.js +27 -36
- package/backend/mock-src/classes/logger.js +5 -7
- package/backend/mock-src/classes/utils.js +3 -2
- package/backend/mock-src/ticketmaster.js +4 -4
- package/backend/validator.js +2 -2
- package/config/configs.json +0 -1
- package/dev-server.js +134 -0
- package/exit +209 -0
- package/index.html +80 -8
- package/index.js +1 -1
- package/jsconfig.json +16 -0
- package/package.json +39 -25
- package/postcss.config.js +1 -1
- package/postinstall.js +124 -20
- package/public/android-chrome-192x192.png +0 -0
- package/public/android-chrome-512x512.png +0 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/img/logo_trans.png +0 -0
- package/public/img/necro_logo.png +0 -0
- package/public/manifest.json +16 -10
- package/public/reconnect-logo.png +0 -0
- package/run +176 -9
- package/src/App.vue +498 -85
- package/src/assets/css/base/reset.scss +43 -0
- package/src/assets/css/base/scroll.scss +114 -0
- package/src/assets/css/base/typography.scss +37 -0
- package/src/assets/css/components/buttons.scss +216 -0
- package/src/assets/css/components/forms.scss +221 -0
- package/src/assets/css/components/modals.scss +13 -0
- package/src/assets/css/components/tables.scss +27 -0
- package/src/assets/css/components/toasts.scss +100 -0
- package/src/assets/css/main.scss +202 -122
- package/src/assets/img/background.svg +2 -2
- package/src/assets/img/background.svg.backup +11 -0
- package/src/assets/img/logo_trans.png +0 -0
- package/src/components/Auth/LoginForm.vue +95 -11
- package/src/components/Editors/Account/Account.vue +116 -40
- package/src/components/Editors/Account/AccountCreator.vue +88 -39
- package/src/components/Editors/Account/AccountView.vue +102 -34
- package/src/components/Editors/Account/CreateAccount.vue +80 -32
- package/src/components/Editors/Profile/CreateProfile.vue +269 -83
- package/src/components/Editors/Profile/Profile.vue +132 -47
- package/src/components/Editors/Profile/ProfileCountryChooser.vue +82 -20
- package/src/components/Editors/Profile/ProfileView.vue +89 -32
- package/src/components/Editors/TagLabel.vue +67 -6
- package/src/components/Editors/TagToggle.vue +7 -2
- package/src/components/Filter/Filter.vue +288 -71
- package/src/components/Filter/FilterPreview.vue +202 -31
- package/src/components/Filter/PriceSortToggle.vue +76 -6
- package/src/components/Table/Header.vue +1 -1
- package/src/components/Table/Row.vue +1 -1
- package/src/components/Table/Table.vue +19 -2
- package/src/components/Tasks/CheckStock.vue +6 -8
- package/src/components/Tasks/Controls/DesktopControls.vue +27 -17
- package/src/components/Tasks/Controls/MobileControls.vue +8 -45
- package/src/components/Tasks/CreateTaskAXS.vue +80 -72
- package/src/components/Tasks/CreateTaskTM.vue +95 -141
- package/src/components/Tasks/MassEdit.vue +4 -6
- package/src/components/Tasks/QuickSettings.vue +199 -30
- package/src/components/Tasks/ScrapeVenue.vue +5 -6
- package/src/components/Tasks/Stats.vue +50 -24
- package/src/components/Tasks/Task.vue +384 -179
- package/src/components/Tasks/TaskLabel.vue +2 -2
- package/src/components/Tasks/TaskView.vue +136 -48
- package/src/components/Tasks/Utilities.vue +25 -10
- package/src/components/Tasks/ViewTask.vue +321 -0
- package/src/components/icons/Bag.vue +1 -1
- package/src/components/icons/Check.vue +5 -0
- package/src/components/icons/Close.vue +21 -0
- package/src/components/icons/CloseX.vue +5 -0
- package/src/components/icons/Eye.vue +6 -0
- package/src/components/icons/Key.vue +21 -0
- package/src/components/icons/Loyalty.vue +1 -1
- package/src/components/icons/Mail.vue +2 -2
- package/src/components/icons/Pencil.vue +21 -0
- package/src/components/icons/Play.vue +2 -2
- package/src/components/icons/Profile.vue +18 -0
- package/src/components/icons/Reload.vue +4 -5
- package/src/components/icons/Sandclock.vue +2 -2
- package/src/components/icons/Sell.vue +21 -0
- package/src/components/icons/Spinner.vue +42 -0
- package/src/components/icons/SquareCheck.vue +18 -0
- package/src/components/icons/SquareUncheck.vue +18 -0
- package/src/components/icons/Stadium.vue +1 -1
- package/src/components/icons/Wildcard.vue +18 -0
- package/src/components/icons/index.js +26 -1
- package/src/components/ui/Modal.vue +107 -13
- package/src/components/ui/Navbar.vue +175 -40
- package/src/components/ui/ReconnectIndicator.vue +351 -55
- package/src/components/ui/Splash.vue +5 -35
- package/src/components/ui/controls/CountryChooser.vue +200 -62
- package/src/components/ui/controls/atomic/Checkbox.vue +119 -10
- package/src/components/ui/controls/atomic/Dropdown.vue +216 -39
- package/src/components/ui/controls/atomic/LoadingButton.vue +45 -0
- package/src/components/ui/controls/atomic/MultiDropdown.vue +300 -37
- package/src/components/ui/controls/atomic/Switch.vue +53 -25
- package/src/composables/useClickOutside.js +21 -0
- package/src/composables/useDropdownPosition.js +174 -0
- package/src/libs/Filter.js +60 -24
- package/src/registerServiceWorker.js +1 -1
- package/src/stores/connection.js +4 -4
- package/src/stores/sampleData.js +172 -199
- package/src/stores/ui.js +55 -20
- package/src/stores/utils.js +30 -4
- package/src/types/index.js +41 -0
- package/src/utils/debug.js +1 -0
- package/src/views/Accounts.vue +116 -50
- package/src/views/Console.vue +394 -77
- package/src/views/Editor.vue +1176 -123
- package/src/views/FilterBuilder.vue +528 -250
- package/src/views/Login.vue +75 -14
- package/src/views/Profiles.vue +119 -34
- package/src/views/Tasks.vue +266 -98
- package/static/offline.html +192 -50
- package/switch-branch.sh +41 -0
- package/tailwind.config.js +119 -27
- package/vite.config.js +73 -16
- package/workbox-config.cjs +63 -0
- package/ICONS.md +0 -21
- package/public/img/background.svg +0 -14
- package/public/img/logo.png +0 -0
- package/public/img/logo_icon.png +0 -0
- package/public/img/logo_icon_2.png +0 -0
- package/src/assets/css/_input.scss +0 -143
- package/src/assets/img/logo.png +0 -0
- package/src/assets/img/logo_icon.png +0 -0
- package/src/assets/img/logo_icon_2.png +0 -0
- package/vue.config.js +0 -32
- package/workbox-config.js +0 -7
|
@@ -7,42 +7,71 @@
|
|
|
7
7
|
</template>
|
|
8
8
|
|
|
9
9
|
<div>
|
|
10
|
-
<div class="my-3 grid grid-cols-12 gap-3
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
10
|
+
<div class="my-3 grid grid-cols-12 gap-3">
|
|
11
|
+
<!-- Account tag -->
|
|
12
|
+
<div class="input-wrapper relative-positioned z-tooltip col-span-4">
|
|
13
|
+
<label class="label-override mb-2">
|
|
14
|
+
Account Tag
|
|
15
|
+
<TagIcon />
|
|
16
|
+
</label>
|
|
17
|
+
<Dropdown
|
|
18
|
+
:class="`input-default dropdown w-full p-4`"
|
|
19
|
+
:default="ui.profile.tags[0]"
|
|
20
|
+
:options="ui.profile.tags"
|
|
21
|
+
:onClick="(f) => (account.tag = f)"
|
|
22
|
+
:capitalize="true"
|
|
23
|
+
:allowDefault="false"
|
|
24
|
+
:chosen="account.tag" />
|
|
23
25
|
</div>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
|
|
27
|
+
<!-- Email -->
|
|
28
|
+
<div class="input-wrapper z-0 col-span-8">
|
|
29
|
+
<label class="label-override mb-2">
|
|
30
|
+
Email
|
|
31
|
+
<MailIcon />
|
|
32
|
+
</label>
|
|
33
|
+
<div :class="`input-default required ${errors.includes('email') ? 'error' : ''}`">
|
|
34
|
+
<input
|
|
35
|
+
placeholder="email@example.com"
|
|
36
|
+
type="email"
|
|
37
|
+
v-model="account.email"
|
|
38
|
+
required
|
|
39
|
+
autocomplete="new-password"
|
|
40
|
+
name="not-email-field-random-12345"
|
|
41
|
+
data-dashlane-rid=""
|
|
42
|
+
data-dashlane-label=""
|
|
43
|
+
data-dashlane-classification=""
|
|
44
|
+
data-form-type="other"
|
|
45
|
+
role="textbox"
|
|
46
|
+
inputmode="email" />
|
|
29
47
|
</div>
|
|
30
48
|
</div>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
49
|
+
|
|
50
|
+
<!-- Password -->
|
|
51
|
+
<div class="input-wrapper z-0 col-span-12">
|
|
52
|
+
<label class="label-override mb-2">
|
|
53
|
+
Password
|
|
54
|
+
<KeyIcon />
|
|
55
|
+
</label>
|
|
56
|
+
<div :class="`input-default required ${errors.includes('password') ? 'error' : ''}`">
|
|
57
|
+
<input
|
|
58
|
+
placeholder="***********"
|
|
59
|
+
type="password"
|
|
60
|
+
v-model="account.password"
|
|
61
|
+
required
|
|
62
|
+
autocomplete="off"
|
|
63
|
+
name="account_password_disableautocomplete" />
|
|
64
|
+
</div>
|
|
37
65
|
</div>
|
|
38
66
|
</div>
|
|
39
|
-
<button
|
|
40
|
-
class="button-default hover:opacity-70 active:opacity-50 bg-dark-400 w-48 text-xs flex items-center justify-center gap-x-2 ml-auto mt-4"
|
|
41
|
-
@click="done()"
|
|
42
|
-
>
|
|
43
|
-
Save <EditIcon />
|
|
44
|
-
</button>
|
|
45
67
|
</div>
|
|
68
|
+
|
|
69
|
+
<button
|
|
70
|
+
class="button-default ml-auto mt-4 flex w-48 items-center justify-center gap-x-2 bg-dark-400 text-xs"
|
|
71
|
+
@click="done()">
|
|
72
|
+
Save
|
|
73
|
+
<EditIcon />
|
|
74
|
+
</button>
|
|
46
75
|
</Modal>
|
|
47
76
|
</template>
|
|
48
77
|
<style lang="scss" scoped>
|
|
@@ -51,6 +80,16 @@
|
|
|
51
80
|
@apply flex;
|
|
52
81
|
}
|
|
53
82
|
}
|
|
83
|
+
.z-0 {
|
|
84
|
+
z-index: 0 !important;
|
|
85
|
+
}
|
|
86
|
+
.z-1 {
|
|
87
|
+
z-index: 1 !important;
|
|
88
|
+
}
|
|
89
|
+
.z-2 {
|
|
90
|
+
z-index: 2 !important;
|
|
91
|
+
}
|
|
92
|
+
|
|
54
93
|
.error {
|
|
55
94
|
border-width: 2px !important;
|
|
56
95
|
border-color: rgb(238 130 130) !important;
|
|
@@ -58,7 +97,16 @@
|
|
|
58
97
|
</style>
|
|
59
98
|
<script setup>
|
|
60
99
|
import Modal from "@/components/ui/Modal.vue";
|
|
61
|
-
import {
|
|
100
|
+
import {
|
|
101
|
+
EditIcon,
|
|
102
|
+
MailIcon,
|
|
103
|
+
KeyIcon,
|
|
104
|
+
ProfileIcon,
|
|
105
|
+
TimerIcon,
|
|
106
|
+
SandclockIcon,
|
|
107
|
+
TagIcon,
|
|
108
|
+
ScannerIcon
|
|
109
|
+
} from "@/components/icons";
|
|
62
110
|
import { useUIStore } from "@/stores/ui";
|
|
63
111
|
import Dropdown from "@/components/ui/controls/atomic/Dropdown.vue";
|
|
64
112
|
|
|
@@ -68,7 +116,7 @@ const ui = useUIStore();
|
|
|
68
116
|
const account = ref({
|
|
69
117
|
email: "",
|
|
70
118
|
password: "",
|
|
71
|
-
tag: ui.profile.
|
|
119
|
+
tag: ui.profile.tags[0]
|
|
72
120
|
});
|
|
73
121
|
|
|
74
122
|
if (ui.currentlyEditing?.email) account.value = ui.currentlyEditing;
|
|
@@ -7,88 +7,92 @@
|
|
|
7
7
|
</template>
|
|
8
8
|
|
|
9
9
|
<div>
|
|
10
|
-
<div class="grid grid-cols-12 gap-3
|
|
10
|
+
<div class="my-3 grid grid-cols-12 gap-3">
|
|
11
11
|
<!-- Profile tag -->
|
|
12
|
-
<div class="input-wrapper col-span-4"
|
|
13
|
-
<label class="label-override mb-2">
|
|
14
|
-
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
/>
|
|
23
|
-
</div>
|
|
12
|
+
<div class="input-wrapper z-dropdown col-span-4">
|
|
13
|
+
<label class="label-override mb-2">
|
|
14
|
+
Profile Tag
|
|
15
|
+
<TagIcon />
|
|
16
|
+
</label>
|
|
17
|
+
<Dropdown
|
|
18
|
+
:class="`input-default dropdown w-full ${errors.includes('profileTag') ? 'error' : ''}`"
|
|
19
|
+
:default="ui.profile.tags[0]"
|
|
20
|
+
:options="ui.profile.tags"
|
|
21
|
+
:onClick="(f) => (profile.tag = f)"
|
|
22
|
+
:capitalize="true" />
|
|
24
23
|
</div>
|
|
25
24
|
|
|
26
25
|
<!-- Card Number -->
|
|
27
|
-
<div class="input-wrapper col-span-8
|
|
28
|
-
<label class="label-override mb-2">
|
|
26
|
+
<div class="input-wrapper z-0 col-span-8">
|
|
27
|
+
<label class="label-override mb-2">
|
|
28
|
+
Card Number
|
|
29
|
+
<CartIcon />
|
|
30
|
+
</label>
|
|
29
31
|
<div :class="`input-default ${errors.includes('cardNumber') ? 'error' : ''}`">
|
|
30
32
|
<input
|
|
33
|
+
ref="cardNumberInput"
|
|
31
34
|
placeholder="Enter card number"
|
|
32
|
-
v-model="
|
|
33
|
-
maxlength="
|
|
35
|
+
v-model="displayCardNumber"
|
|
36
|
+
maxlength="23"
|
|
34
37
|
inputmode="numeric"
|
|
35
38
|
@input="handleCreditCardUpdate"
|
|
36
|
-
|
|
39
|
+
@focus="formatCardNumberDisplay" />
|
|
37
40
|
</div>
|
|
38
41
|
</div>
|
|
39
42
|
|
|
40
43
|
<!-- Country chooser -->
|
|
41
44
|
<div class="input-wrapper col-span-2">
|
|
42
|
-
<label class="label-override mb-2">
|
|
45
|
+
<label class="label-override mb-2">
|
|
46
|
+
Country
|
|
47
|
+
<SandclockIcon />
|
|
48
|
+
</label>
|
|
43
49
|
<ProfileCountryChooser
|
|
44
50
|
class="h-8"
|
|
45
51
|
:value="profile.country"
|
|
46
52
|
:onClick="chooseCountry"
|
|
47
|
-
:disabled="true"
|
|
48
|
-
/>
|
|
53
|
+
:disabled="true" />
|
|
49
54
|
</div>
|
|
50
55
|
|
|
51
56
|
<!-- Exp Year -->
|
|
52
57
|
<div class="input-wrapper col-span-5">
|
|
53
|
-
<label class="label-override mb-2
|
|
54
|
-
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
/>
|
|
70
|
-
</div>
|
|
58
|
+
<label class="label-override z-0 mb-2">
|
|
59
|
+
Expiry Year
|
|
60
|
+
<TimerIcon />
|
|
61
|
+
</label>
|
|
62
|
+
<Dropdown
|
|
63
|
+
:class="`input-default dropdown w-full ${errors.includes('expYear') ? 'error' : ''}`"
|
|
64
|
+
default="Expiry Year"
|
|
65
|
+
:value="
|
|
66
|
+
profile.expYear && !profile?.expYear?.startsWith('20')
|
|
67
|
+
? '20' + profile.expYear
|
|
68
|
+
: profile.expYear
|
|
69
|
+
? profile.expYear
|
|
70
|
+
: undefined
|
|
71
|
+
"
|
|
72
|
+
:options="['2025', '2026', '2027', '2028', '2029', '2030', '2031']"
|
|
73
|
+
:onClick="(f) => (profile.expYear = f)" />
|
|
71
74
|
</div>
|
|
72
75
|
|
|
73
76
|
<!-- Exp Month -->
|
|
74
|
-
<div class="input-wrapper col-span-5">
|
|
75
|
-
<label class="label-override mb-2">
|
|
76
|
-
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
/>
|
|
86
|
-
</div>
|
|
77
|
+
<div class="input-wrapper z-2 col-span-5">
|
|
78
|
+
<label class="label-override mb-2">
|
|
79
|
+
Expiry Month
|
|
80
|
+
<TimerIcon />
|
|
81
|
+
</label>
|
|
82
|
+
<Dropdown
|
|
83
|
+
:class="`input-default dropdown w-full ${errors.includes('expMonth') ? 'error' : ''}`"
|
|
84
|
+
default="Expiry Month"
|
|
85
|
+
:value="profile.expMonth ? profile.expMonth : undefined"
|
|
86
|
+
:options="['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12']"
|
|
87
|
+
:onClick="(f) => (profile.expMonth = f)" />
|
|
87
88
|
</div>
|
|
88
89
|
|
|
89
90
|
<!-- CVV -->
|
|
90
|
-
<div class="input-wrapper col-span-6 md:col-span-4
|
|
91
|
-
<label class="label-override mb-2">
|
|
91
|
+
<div class="input-wrapper z-0 col-span-6 md:col-span-4">
|
|
92
|
+
<label class="label-override mb-2">
|
|
93
|
+
CVV
|
|
94
|
+
<ShieldIcon />
|
|
95
|
+
</label>
|
|
92
96
|
<div :class="`input-default ${errors.includes('cvv') ? 'error' : ''}`">
|
|
93
97
|
<input
|
|
94
98
|
placeholder="183"
|
|
@@ -96,51 +100,88 @@
|
|
|
96
100
|
max="9999"
|
|
97
101
|
maxlength="4"
|
|
98
102
|
minlength="3"
|
|
99
|
-
v-model="profile.cvv"
|
|
100
|
-
/>
|
|
103
|
+
v-model="profile.cvv" />
|
|
101
104
|
</div>
|
|
102
105
|
</div>
|
|
103
106
|
|
|
104
107
|
<!-- City -->
|
|
105
|
-
<div class="input-wrapper col-span-6 md:col-span-4
|
|
106
|
-
<label class="label-override mb-2">
|
|
108
|
+
<div class="input-wrapper z-0 col-span-6 md:col-span-4">
|
|
109
|
+
<label class="label-override mb-2">
|
|
110
|
+
City
|
|
111
|
+
<StadiumIcon />
|
|
112
|
+
</label>
|
|
107
113
|
<div :class="`input-default ${errors.includes('city') ? 'error' : ''}`">
|
|
108
114
|
<input placeholder="Denver" v-model="profile.city" />
|
|
109
115
|
</div>
|
|
110
116
|
</div>
|
|
111
117
|
|
|
112
118
|
<!-- State -->
|
|
113
|
-
<div class="input-wrapper col-span-6 md:col-span-4
|
|
114
|
-
<label class="label-override mb-2">
|
|
115
|
-
|
|
116
|
-
<
|
|
119
|
+
<div class="input-wrapper z-1 col-span-6 md:col-span-4">
|
|
120
|
+
<label class="label-override mb-2">
|
|
121
|
+
State
|
|
122
|
+
<SandclockIcon />
|
|
123
|
+
</label>
|
|
124
|
+
<div v-if="profile.country === 'US'" :class="`${errors.includes('state') ? 'error' : ''}`">
|
|
125
|
+
<Dropdown
|
|
126
|
+
class="input-default w-full"
|
|
127
|
+
default="Select State"
|
|
128
|
+
:onClick="(state) => (profile.state = state)"
|
|
129
|
+
:options="usStates"
|
|
130
|
+
:allowDefault="false"
|
|
131
|
+
rightAmount="right-2"
|
|
132
|
+
:value="profile.state" />
|
|
133
|
+
</div>
|
|
134
|
+
<div v-else :class="`input-default ${errors.includes('state') ? 'error' : ''}`">
|
|
135
|
+
<input disabled placeholder="N/A" value="" />
|
|
117
136
|
</div>
|
|
118
137
|
</div>
|
|
119
138
|
|
|
120
139
|
<!-- Zip -->
|
|
121
|
-
<div class="input-wrapper col-span-6 md:col-span-4
|
|
122
|
-
<label class="label-override mb-2">
|
|
140
|
+
<div class="input-wrapper z-0 col-span-6 md:col-span-4">
|
|
141
|
+
<label class="label-override mb-2">
|
|
142
|
+
Zip
|
|
143
|
+
<KeyIcon />
|
|
144
|
+
</label>
|
|
123
145
|
<div :class="`input-default ${errors.includes('zipCode') ? 'error' : ''}`">
|
|
124
|
-
<input placeholder="
|
|
146
|
+
<input placeholder="10005" type="number" min="1" max="12" v-model="profile.zipCode" />
|
|
125
147
|
</div>
|
|
126
148
|
</div>
|
|
127
149
|
|
|
128
150
|
<!-- Address -->
|
|
129
|
-
<div class="input-wrapper col-span-6 md:col-span-4
|
|
130
|
-
<label class="label-override mb-2">
|
|
151
|
+
<div class="input-wrapper z-0 col-span-6 md:col-span-4">
|
|
152
|
+
<label class="label-override mb-2">
|
|
153
|
+
Address
|
|
154
|
+
<HandIcon />
|
|
155
|
+
</label>
|
|
131
156
|
<div :class="`input-default ${errors.includes('address') ? 'error' : ''}`">
|
|
132
|
-
<input placeholder="
|
|
157
|
+
<input placeholder="100 5th Avenue" v-model="profile.address" />
|
|
133
158
|
</div>
|
|
134
159
|
</div>
|
|
135
160
|
|
|
136
161
|
<!-- Generate -->
|
|
137
|
-
<div class="input-wrapper col-span-6 md:col-span-4
|
|
138
|
-
<label class="label-override mb-2
|
|
139
|
-
|
|
162
|
+
<div class="input-wrapper z-0 col-span-6 md:col-span-4">
|
|
163
|
+
<label class="label-override mb-2">
|
|
164
|
+
Fake ID
|
|
165
|
+
<WildcardIcon />
|
|
166
|
+
</label>
|
|
167
|
+
<div class="input-default mt-2 flex h-10 w-full items-center">
|
|
140
168
|
<button
|
|
141
169
|
@click="generate"
|
|
142
|
-
class="
|
|
143
|
-
|
|
170
|
+
class="flex w-full items-center justify-center gap-2 text-xs text-white">
|
|
171
|
+
<svg
|
|
172
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
173
|
+
width="14"
|
|
174
|
+
height="14"
|
|
175
|
+
viewBox="0 0 24 24"
|
|
176
|
+
fill="none"
|
|
177
|
+
stroke="currentColor"
|
|
178
|
+
stroke-width="2"
|
|
179
|
+
stroke-linecap="round"
|
|
180
|
+
stroke-linejoin="round">
|
|
181
|
+
<rect x="3" y="4" width="18" height="16" rx="2" />
|
|
182
|
+
<line x1="7" y1="2" x2="7" y2="6" />
|
|
183
|
+
<line x1="17" y1="2" x2="17" y2="6" />
|
|
184
|
+
</svg>
|
|
144
185
|
<span>Generate</span>
|
|
145
186
|
</button>
|
|
146
187
|
</div>
|
|
@@ -149,10 +190,10 @@
|
|
|
149
190
|
</div>
|
|
150
191
|
|
|
151
192
|
<button
|
|
152
|
-
class="button-default
|
|
153
|
-
@click="done()"
|
|
154
|
-
|
|
155
|
-
|
|
193
|
+
class="button-default ml-auto mt-4 flex w-48 items-center justify-center gap-x-2 bg-dark-400 text-xs"
|
|
194
|
+
@click="done()">
|
|
195
|
+
Save
|
|
196
|
+
<EditIcon />
|
|
156
197
|
</button>
|
|
157
198
|
</Modal>
|
|
158
199
|
</template>
|
|
@@ -165,6 +206,12 @@
|
|
|
165
206
|
.z-0 {
|
|
166
207
|
z-index: 0 !important;
|
|
167
208
|
}
|
|
209
|
+
.z-1 {
|
|
210
|
+
z-index: 1 !important;
|
|
211
|
+
}
|
|
212
|
+
.z-2 {
|
|
213
|
+
z-index: 2 !important;
|
|
214
|
+
}
|
|
168
215
|
|
|
169
216
|
.error {
|
|
170
217
|
border-width: 2px !important;
|
|
@@ -173,22 +220,89 @@
|
|
|
173
220
|
</style>
|
|
174
221
|
<script setup>
|
|
175
222
|
import Modal from "@/components/ui/Modal.vue";
|
|
223
|
+
import {
|
|
224
|
+
MailIcon,
|
|
225
|
+
CartIcon,
|
|
226
|
+
ShieldIcon,
|
|
227
|
+
StadiumIcon,
|
|
228
|
+
KeyIcon,
|
|
229
|
+
HandIcon,
|
|
230
|
+
ProfileIcon,
|
|
231
|
+
SandclockIcon,
|
|
232
|
+
TimerIcon,
|
|
233
|
+
TagIcon,
|
|
234
|
+
WildcardIcon
|
|
235
|
+
} from "@/components/icons";
|
|
176
236
|
import { EditIcon } from "@/components/icons";
|
|
177
|
-
import ProfileCountryChooser from "@/components/
|
|
237
|
+
import ProfileCountryChooser from "@/components/Editors/Profile/ProfileCountryChooser.vue";
|
|
178
238
|
import { useUIStore } from "@/stores/ui";
|
|
179
239
|
import Dropdown from "@/components/ui/controls/atomic/Dropdown.vue";
|
|
180
|
-
import { ref } from "vue";
|
|
240
|
+
import { ref, computed, watch, nextTick, onMounted } from "vue";
|
|
181
241
|
import { fakeId } from "@/stores/utils";
|
|
182
242
|
import { validateCard } from "@/stores/utils";
|
|
183
243
|
|
|
184
244
|
const props = defineProps({ profile: { type: Object, required: false } });
|
|
185
245
|
const errors = ref([]);
|
|
186
246
|
const ui = useUIStore();
|
|
247
|
+
|
|
248
|
+
// US States list (excluding GA and PR, alphabetically ordered)
|
|
249
|
+
const usStates = [
|
|
250
|
+
"AK",
|
|
251
|
+
"AL",
|
|
252
|
+
"AR",
|
|
253
|
+
"AZ",
|
|
254
|
+
"CA",
|
|
255
|
+
"CO",
|
|
256
|
+
"CT",
|
|
257
|
+
"DE",
|
|
258
|
+
"FL",
|
|
259
|
+
"HI",
|
|
260
|
+
"IA",
|
|
261
|
+
"ID",
|
|
262
|
+
"IL",
|
|
263
|
+
"IN",
|
|
264
|
+
"KS",
|
|
265
|
+
"KY",
|
|
266
|
+
"LA",
|
|
267
|
+
"MA",
|
|
268
|
+
"MD",
|
|
269
|
+
"ME",
|
|
270
|
+
"MI",
|
|
271
|
+
"MN",
|
|
272
|
+
"MO",
|
|
273
|
+
"MS",
|
|
274
|
+
"MT",
|
|
275
|
+
"NC",
|
|
276
|
+
"ND",
|
|
277
|
+
"NE",
|
|
278
|
+
"NH",
|
|
279
|
+
"NJ",
|
|
280
|
+
"NM",
|
|
281
|
+
"NV",
|
|
282
|
+
"NY",
|
|
283
|
+
"OH",
|
|
284
|
+
"OK",
|
|
285
|
+
"OR",
|
|
286
|
+
"PA",
|
|
287
|
+
"RI",
|
|
288
|
+
"SC",
|
|
289
|
+
"SD",
|
|
290
|
+
"TN",
|
|
291
|
+
"TX",
|
|
292
|
+
"UT",
|
|
293
|
+
"VA",
|
|
294
|
+
"VT",
|
|
295
|
+
"WA",
|
|
296
|
+
"WI",
|
|
297
|
+
"WV",
|
|
298
|
+
"WY"
|
|
299
|
+
];
|
|
300
|
+
const cardNumberInput = ref(null);
|
|
187
301
|
const profile = ref({
|
|
188
302
|
cvv: "",
|
|
189
303
|
cardNumber: "",
|
|
190
304
|
city: "",
|
|
191
|
-
tag: ui.profile.
|
|
305
|
+
tag: ui.profile.tags[0],
|
|
192
306
|
state: "",
|
|
193
307
|
country: "US",
|
|
194
308
|
zipCode: ""
|
|
@@ -196,6 +310,54 @@ const profile = ref({
|
|
|
196
310
|
|
|
197
311
|
if (ui.currentlyEditing?.profileName) profile.value = ui.currentlyEditing;
|
|
198
312
|
|
|
313
|
+
// Reactive display value for the formatted card number
|
|
314
|
+
const displayCardNumber = ref("");
|
|
315
|
+
|
|
316
|
+
// Initialize display card number with formatting
|
|
317
|
+
const initializeCardNumberDisplay = () => {
|
|
318
|
+
if (profile.value.cardNumber) {
|
|
319
|
+
const cleanNumber = profile.value.cardNumber.replace(/\s+/g, "");
|
|
320
|
+
if (cleanNumber) {
|
|
321
|
+
const cardInfo = validateCard(cleanNumber);
|
|
322
|
+
displayCardNumber.value = cardInfo.formatted;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
// Format card number display on focus
|
|
328
|
+
const formatCardNumberDisplay = () => {
|
|
329
|
+
if (profile.value.cardNumber) {
|
|
330
|
+
const cleanNumber = profile.value.cardNumber.replace(/\s+/g, "");
|
|
331
|
+
if (cleanNumber) {
|
|
332
|
+
const cardInfo = validateCard(cleanNumber);
|
|
333
|
+
displayCardNumber.value = cardInfo.formatted;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
// Watch for changes in profile.cardNumber to sync with display
|
|
339
|
+
watch(
|
|
340
|
+
() => profile.value.cardNumber,
|
|
341
|
+
(newValue) => {
|
|
342
|
+
if (newValue) {
|
|
343
|
+
const cleanNumber = newValue.replace(/\s+/g, "");
|
|
344
|
+
if (cleanNumber) {
|
|
345
|
+
const cardInfo = validateCard(cleanNumber);
|
|
346
|
+
displayCardNumber.value = cardInfo.formatted;
|
|
347
|
+
}
|
|
348
|
+
} else {
|
|
349
|
+
displayCardNumber.value = "";
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
// Initialize on modal open
|
|
355
|
+
onMounted(() => {
|
|
356
|
+
nextTick(() => {
|
|
357
|
+
initializeCardNumberDisplay();
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
|
|
199
361
|
const generate = () => {
|
|
200
362
|
const fake = fakeId();
|
|
201
363
|
profile.value.city = fake.city;
|
|
@@ -220,7 +382,13 @@ const validate = (p) => {
|
|
|
220
382
|
if (!p.city) errors.value.push("city");
|
|
221
383
|
if (!p.country) errors.value.push("country");
|
|
222
384
|
if (!/^\d{3,4}$/.test(`${p.cvv}`)) errors.value.push("cvv");
|
|
223
|
-
|
|
385
|
+
const cleanCardNumber = p.cardNumber.replace(/\s+/g, "");
|
|
386
|
+
// Validate card number based on type and length
|
|
387
|
+
const isValidCard =
|
|
388
|
+
cleanCardNumber.match(/^4\d{15}$/) || // Visa (16 digits)
|
|
389
|
+
cleanCardNumber.match(/^5[1-5]\d{14}$/) || // Mastercard (16 digits)
|
|
390
|
+
cleanCardNumber.match(/^3[47]\d{13}$/); // AMEX (15 digits)
|
|
391
|
+
if (!isValidCard) errors.value.push("cardNumber");
|
|
224
392
|
if (!p.expYear) errors.value.push("expYear");
|
|
225
393
|
if (!p.expMonth) errors.value.push("expMonth");
|
|
226
394
|
if (!p.expMonth) errors.value.push("expMonth");
|
|
@@ -229,12 +397,30 @@ const validate = (p) => {
|
|
|
229
397
|
|
|
230
398
|
const handleCreditCardUpdate = (event) => {
|
|
231
399
|
const value = event.target.value.replace(/\D/g, "");
|
|
232
|
-
|
|
400
|
+
|
|
401
|
+
// Determine max length based on card type
|
|
402
|
+
let maxLength = 16; // Default for Visa/Mastercard
|
|
403
|
+
if (value.startsWith("3")) {
|
|
404
|
+
maxLength = 15; // AMEX
|
|
405
|
+
} else if (value.startsWith("4") || value.startsWith("5")) {
|
|
406
|
+
maxLength = 16; // Visa/Mastercard
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const subs = value.substring(0, maxLength);
|
|
233
410
|
const cardInfo = validateCard(subs);
|
|
234
|
-
|
|
411
|
+
|
|
412
|
+
// Store clean number (without spaces) in profile
|
|
413
|
+
profile.value.cardNumber = subs;
|
|
414
|
+
// Display formatted number in input
|
|
415
|
+
displayCardNumber.value = cardInfo.formatted;
|
|
235
416
|
};
|
|
236
417
|
|
|
237
418
|
function done() {
|
|
419
|
+
// Clear state if country is not US
|
|
420
|
+
if (profile.value.country !== "US") {
|
|
421
|
+
profile.value.state = "";
|
|
422
|
+
}
|
|
423
|
+
|
|
238
424
|
ui.logger.Info("Created profile", profile.value);
|
|
239
425
|
if (validate(profile.value) !== true) return;
|
|
240
426
|
ui.toggleModal("");
|