@7365admin1/layer-common 3.0.31-staging.12 → 3.0.31-staging.14
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/components/DashboardMain.vue +202 -54
- package/components/VisitorForm.vue +33 -40
- package/package.json +1 -1
|
@@ -984,60 +984,44 @@
|
|
|
984
984
|
<div
|
|
985
985
|
v-for="item in formattedActivePatrolItems"
|
|
986
986
|
:key="item.id || item._id"
|
|
987
|
-
class="
|
|
988
|
-
style="
|
|
989
|
-
padding: 16px 20px;
|
|
990
|
-
border: 1px solid #e2e8f0;
|
|
991
|
-
border-radius: 12px;
|
|
992
|
-
margin-bottom: 12px;
|
|
993
|
-
background-color: #ffffff;
|
|
994
|
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02);
|
|
995
|
-
"
|
|
987
|
+
class="active-patrol-row"
|
|
996
988
|
>
|
|
997
|
-
<div
|
|
998
|
-
<strong
|
|
999
|
-
|
|
1000
|
-
display: block;
|
|
1001
|
-
font-size: 15px;
|
|
1002
|
-
font-weight: 700;
|
|
1003
|
-
color: #0b2f47;
|
|
1004
|
-
margin-bottom: 4px;
|
|
1005
|
-
"
|
|
1006
|
-
>{{ item.title || item.name }}</strong
|
|
1007
|
-
>
|
|
1008
|
-
<span style="font-size: 13px; color: #94a3b8">{{
|
|
1009
|
-
item.subtitle || item.location || ""
|
|
1010
|
-
}}</span>
|
|
989
|
+
<div class="active-patrol-main">
|
|
990
|
+
<strong>{{ item.title || item.name }}</strong>
|
|
991
|
+
<span>{{ item.subtitle || item.location || "" }}</span>
|
|
1011
992
|
</div>
|
|
1012
993
|
|
|
1013
|
-
<div
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
item.
|
|
1022
|
-
|
|
994
|
+
<div class="active-patrol-assignees">
|
|
995
|
+
<div class="active-patrol-assignee">
|
|
996
|
+
<AvatarMain :name="item.primaryAssignee" :size="24" />
|
|
997
|
+
<span>{{ item.primaryAssignee }}</span>
|
|
998
|
+
</div>
|
|
999
|
+
<span
|
|
1000
|
+
v-if="item.extraAssigneeCount > 0"
|
|
1001
|
+
class="active-patrol-more-pill active-patrol-tooltip"
|
|
1002
|
+
:data-tooltip="item.extraAssignees.join(', ')"
|
|
1003
|
+
>
|
|
1004
|
+
+{{ item.extraAssigneeCount }}
|
|
1005
|
+
</span>
|
|
1023
1006
|
</div>
|
|
1024
1007
|
|
|
1025
|
-
<div
|
|
1008
|
+
<div class="active-patrol-statuses">
|
|
1026
1009
|
<div
|
|
1027
|
-
|
|
1028
|
-
style="
|
|
1029
|
-
padding: 6px 16px;
|
|
1030
|
-
border-radius: 20px;
|
|
1031
|
-
font-size: 13px;
|
|
1032
|
-
font-weight: 500;
|
|
1033
|
-
text-transform: capitalize;
|
|
1034
|
-
"
|
|
1010
|
+
class="active-patrol-status-pill"
|
|
1011
|
+
:style="getPatrolStatusStyle(item.primaryStatus)"
|
|
1035
1012
|
>
|
|
1036
|
-
{{ item.
|
|
1013
|
+
{{ item.primaryStatus }}
|
|
1037
1014
|
</div>
|
|
1015
|
+
<span
|
|
1016
|
+
v-if="item.extraStatusCount > 0"
|
|
1017
|
+
class="active-patrol-more-pill active-patrol-tooltip"
|
|
1018
|
+
:data-tooltip="item.extraStatuses.join(', ')"
|
|
1019
|
+
>
|
|
1020
|
+
+{{ item.extraStatusCount }}
|
|
1021
|
+
</span>
|
|
1038
1022
|
</div>
|
|
1039
1023
|
|
|
1040
|
-
<div
|
|
1024
|
+
<div class="active-patrol-action">
|
|
1041
1025
|
<v-btn
|
|
1042
1026
|
variant="outlined"
|
|
1043
1027
|
class="text-none font-weight-medium"
|
|
@@ -2767,18 +2751,23 @@ const activePatrolItems = computed<any[]>(
|
|
|
2767
2751
|
|
|
2768
2752
|
const formattedActivePatrolItems = computed<any[]>(() => {
|
|
2769
2753
|
return activePatrolItems.value.map((item) => {
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
if (Array.isArray(person)) {
|
|
2776
|
-
person = person.join(", ");
|
|
2777
|
-
}
|
|
2754
|
+
const statuses = normalizeListValue(item.status || "Pending");
|
|
2755
|
+
const assignees = normalizeListValue(
|
|
2756
|
+
item.person || item.assignedTo || "Unassigned"
|
|
2757
|
+
);
|
|
2758
|
+
|
|
2778
2759
|
return {
|
|
2779
2760
|
...item,
|
|
2780
|
-
status,
|
|
2781
|
-
|
|
2761
|
+
status: statuses.join(", "),
|
|
2762
|
+
statuses,
|
|
2763
|
+
primaryStatus: statuses[0] || "Pending",
|
|
2764
|
+
extraStatuses: statuses.slice(1),
|
|
2765
|
+
extraStatusCount: Math.max(0, statuses.length - 1),
|
|
2766
|
+
person: assignees.join(", "),
|
|
2767
|
+
assignees,
|
|
2768
|
+
primaryAssignee: assignees[0] || "Unassigned",
|
|
2769
|
+
extraAssignees: assignees.slice(1),
|
|
2770
|
+
extraAssigneeCount: Math.max(0, assignees.length - 1),
|
|
2782
2771
|
};
|
|
2783
2772
|
});
|
|
2784
2773
|
});
|
|
@@ -3948,6 +3937,20 @@ function normalizeStatus(value: any) {
|
|
|
3948
3937
|
return text.replace(/[_-]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
3949
3938
|
}
|
|
3950
3939
|
|
|
3940
|
+
function normalizeListValue(value: any) {
|
|
3941
|
+
if (Array.isArray(value)) {
|
|
3942
|
+
return value
|
|
3943
|
+
.flatMap((entry) => normalizeListValue(entry))
|
|
3944
|
+
.map((entry) => String(entry).trim())
|
|
3945
|
+
.filter(Boolean);
|
|
3946
|
+
}
|
|
3947
|
+
|
|
3948
|
+
return String(value || "")
|
|
3949
|
+
.split(",")
|
|
3950
|
+
.map((entry) => entry.trim())
|
|
3951
|
+
.filter(Boolean);
|
|
3952
|
+
}
|
|
3953
|
+
|
|
3951
3954
|
function getStatusTone(status: any) {
|
|
3952
3955
|
const s = String(status || "").toLowerCase();
|
|
3953
3956
|
if (
|
|
@@ -4415,6 +4418,151 @@ function formatDashboardTime(value?: string) {
|
|
|
4415
4418
|
border: 2px solid #f9c97c;
|
|
4416
4419
|
}
|
|
4417
4420
|
|
|
4421
|
+
.active-patrol-row {
|
|
4422
|
+
align-items: center;
|
|
4423
|
+
background-color: #ffffff;
|
|
4424
|
+
border: 1px solid #e2e8f0;
|
|
4425
|
+
border-radius: 8px;
|
|
4426
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02);
|
|
4427
|
+
display: grid;
|
|
4428
|
+
gap: 10px;
|
|
4429
|
+
grid-template-columns: 150px minmax(0, 1fr) max-content max-content;
|
|
4430
|
+
margin-bottom: 12px;
|
|
4431
|
+
min-height: 64px;
|
|
4432
|
+
overflow: visible;
|
|
4433
|
+
padding: 12px 14px;
|
|
4434
|
+
}
|
|
4435
|
+
|
|
4436
|
+
.active-patrol-main {
|
|
4437
|
+
min-width: 0;
|
|
4438
|
+
}
|
|
4439
|
+
|
|
4440
|
+
.active-patrol-main strong {
|
|
4441
|
+
color: #0b2f47;
|
|
4442
|
+
display: block;
|
|
4443
|
+
font-size: 13px;
|
|
4444
|
+
font-weight: 700;
|
|
4445
|
+
line-height: 1.25;
|
|
4446
|
+
margin-bottom: 3px;
|
|
4447
|
+
overflow-wrap: anywhere;
|
|
4448
|
+
}
|
|
4449
|
+
|
|
4450
|
+
.active-patrol-main span {
|
|
4451
|
+
color: #94a3b8;
|
|
4452
|
+
display: block;
|
|
4453
|
+
font-size: 11px;
|
|
4454
|
+
line-height: 1.25;
|
|
4455
|
+
overflow-wrap: anywhere;
|
|
4456
|
+
}
|
|
4457
|
+
|
|
4458
|
+
.active-patrol-assignees {
|
|
4459
|
+
align-items: center;
|
|
4460
|
+
display: flex;
|
|
4461
|
+
gap: 6px;
|
|
4462
|
+
min-width: 0;
|
|
4463
|
+
}
|
|
4464
|
+
|
|
4465
|
+
.active-patrol-assignee {
|
|
4466
|
+
align-items: center;
|
|
4467
|
+
background: #f8fafc;
|
|
4468
|
+
border: 1px solid #e7edf3;
|
|
4469
|
+
border-radius: 999px;
|
|
4470
|
+
display: inline-flex;
|
|
4471
|
+
flex: 1 1 auto;
|
|
4472
|
+
gap: 6px;
|
|
4473
|
+
max-width: 100%;
|
|
4474
|
+
min-width: 0;
|
|
4475
|
+
padding: 2px 8px 2px 3px;
|
|
4476
|
+
}
|
|
4477
|
+
|
|
4478
|
+
.active-patrol-assignee span {
|
|
4479
|
+
color: #475569;
|
|
4480
|
+
font-size: 11px;
|
|
4481
|
+
font-weight: 600;
|
|
4482
|
+
line-height: 1.2;
|
|
4483
|
+
min-width: 0;
|
|
4484
|
+
overflow: hidden;
|
|
4485
|
+
text-overflow: ellipsis;
|
|
4486
|
+
white-space: nowrap;
|
|
4487
|
+
}
|
|
4488
|
+
|
|
4489
|
+
.active-patrol-statuses {
|
|
4490
|
+
align-items: center;
|
|
4491
|
+
display: flex;
|
|
4492
|
+
gap: 6px;
|
|
4493
|
+
justify-content: flex-start;
|
|
4494
|
+
min-width: 0;
|
|
4495
|
+
}
|
|
4496
|
+
|
|
4497
|
+
.active-patrol-status-pill {
|
|
4498
|
+
border-radius: 20px;
|
|
4499
|
+
font-size: 11px;
|
|
4500
|
+
font-weight: 600;
|
|
4501
|
+
line-height: 1.2;
|
|
4502
|
+
padding: 5px 10px;
|
|
4503
|
+
text-transform: capitalize;
|
|
4504
|
+
white-space: nowrap;
|
|
4505
|
+
}
|
|
4506
|
+
|
|
4507
|
+
.active-patrol-more-pill {
|
|
4508
|
+
align-items: center;
|
|
4509
|
+
background: #eef3f8;
|
|
4510
|
+
border: 1px solid #dbe4ed;
|
|
4511
|
+
border-radius: 999px;
|
|
4512
|
+
color: #607386;
|
|
4513
|
+
display: inline-flex;
|
|
4514
|
+
flex: 0 0 auto;
|
|
4515
|
+
font-size: 11px;
|
|
4516
|
+
font-weight: 800;
|
|
4517
|
+
height: 24px;
|
|
4518
|
+
justify-content: center;
|
|
4519
|
+
line-height: 1;
|
|
4520
|
+
min-width: 30px;
|
|
4521
|
+
padding: 0 8px;
|
|
4522
|
+
position: relative;
|
|
4523
|
+
white-space: nowrap;
|
|
4524
|
+
}
|
|
4525
|
+
|
|
4526
|
+
.active-patrol-action {
|
|
4527
|
+
justify-self: end;
|
|
4528
|
+
text-align: right;
|
|
4529
|
+
}
|
|
4530
|
+
|
|
4531
|
+
.active-patrol-tooltip::after {
|
|
4532
|
+
background: #0f2638;
|
|
4533
|
+
border-radius: 6px;
|
|
4534
|
+
bottom: calc(100% + 8px);
|
|
4535
|
+
box-shadow: 0 8px 24px rgba(15, 38, 56, 0.18);
|
|
4536
|
+
color: #ffffff;
|
|
4537
|
+
content: attr(data-tooltip);
|
|
4538
|
+
font-size: 11px;
|
|
4539
|
+
font-weight: 600;
|
|
4540
|
+
left: 50%;
|
|
4541
|
+
line-height: 1.35;
|
|
4542
|
+
max-width: 260px;
|
|
4543
|
+
opacity: 0;
|
|
4544
|
+
padding: 7px 9px;
|
|
4545
|
+
pointer-events: none;
|
|
4546
|
+
position: absolute;
|
|
4547
|
+
text-align: left;
|
|
4548
|
+
transform: translate(-50%, 4px);
|
|
4549
|
+
transition: opacity 0.14s ease, transform 0.14s ease;
|
|
4550
|
+
white-space: normal;
|
|
4551
|
+
width: max-content;
|
|
4552
|
+
z-index: 5;
|
|
4553
|
+
}
|
|
4554
|
+
|
|
4555
|
+
.active-patrol-tooltip:hover::after {
|
|
4556
|
+
opacity: 1;
|
|
4557
|
+
transform: translate(-50%, 0);
|
|
4558
|
+
}
|
|
4559
|
+
|
|
4560
|
+
@media (max-width: 960px) {
|
|
4561
|
+
.active-patrol-row {
|
|
4562
|
+
grid-template-columns: 120px minmax(0, 1fr) max-content max-content;
|
|
4563
|
+
}
|
|
4564
|
+
}
|
|
4565
|
+
|
|
4418
4566
|
.figma-icon-badge {
|
|
4419
4567
|
align-items: center;
|
|
4420
4568
|
border-radius: 50%;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<div class="w-100 d-flex justify-space-between ga-2">
|
|
13
13
|
<span class="text-subtitle-1 w-100 font-weight-bold mb-3">{{
|
|
14
14
|
formTitle
|
|
15
|
-
|
|
15
|
+
}}</span>
|
|
16
16
|
<span v-if="withStep2 || withStep3" class="text-subtitle-2 font-weight-bold" style="text-wrap: nowrap">Step
|
|
17
17
|
<span class="text-primary-button">{{ contractorStep }}</span>/{{ withStep3 ? 3 : withStep2 ? 2 : 1 }}</span>
|
|
18
18
|
</div>
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
<v-list-item-title @click.stop="handleAddNewContractorType" class="d-flex align-center ga-1">
|
|
31
31
|
<span><v-icon icon="mdi-plus" /></span> Add "<strong>{{
|
|
32
32
|
contractorTypeInput
|
|
33
|
-
|
|
33
|
+
}}</strong>" as custom contractor type.
|
|
34
34
|
</v-list-item-title>
|
|
35
35
|
</v-list-item>
|
|
36
36
|
</template>
|
|
@@ -99,16 +99,38 @@
|
|
|
99
99
|
<span class="text-subtitle-1">{{ item.name || 'Unknown' }}</span>
|
|
100
100
|
<span class="text-subtitle-1 text-no-wrap">NRIC: {{ item.nric || 'N/A' }}</span>
|
|
101
101
|
</div>
|
|
102
|
-
<div v-if="getPersonContactOptions(item).length < 2 && getPersonPlateOptions(item).length < 2"
|
|
103
|
-
class="d-flex align-center justify-space-between ga-4 w-100">
|
|
104
|
-
<span class="text-subtitle-1">{{ getPersonContactOptions(item)[0] || 'N/A' }}</span>
|
|
105
|
-
<span class="text-subtitle-1 text-no-wrap">{{ getPersonPlateOptions(item)[0] || 'N/A' }}</span>
|
|
106
|
-
</div>
|
|
107
102
|
</v-list-item>
|
|
108
103
|
</v-list>
|
|
109
104
|
</v-menu>
|
|
110
105
|
</v-col>
|
|
111
106
|
|
|
107
|
+
|
|
108
|
+
<v-col v-if="shouldShowField('plateNumber')" cols="12">
|
|
109
|
+
<v-row>
|
|
110
|
+
<v-col cols="12">
|
|
111
|
+
<InputLabel class="text-capitalize" title="Vehicle Number" :required="isVehicleRequired" />
|
|
112
|
+
<!-- <v-text-field v-model.trim.uppercase="visitor.plateNumber" density="comfortable" /> -->
|
|
113
|
+
<v-menu v-model="vehicleSearchMenu" location="bottom" offset-y :close-on-content-click="false">
|
|
114
|
+
<template #activator="{ props }">
|
|
115
|
+
<InputVehicleNumber v-bind="props" v-model="visitor.plateNumber" density="comfortable"
|
|
116
|
+
@update:model-value="handleUpdateVehicleNumber" />
|
|
117
|
+
</template>
|
|
118
|
+
|
|
119
|
+
<v-list v-if="vehicleSearchResults.length" class="pa-1">
|
|
120
|
+
<v-list-item v-for="(item, index) in vehicleSearchResults" :key="item._id || index"
|
|
121
|
+
@click="selectAutofillSearchResult(item, 'vehicleNumber')"
|
|
122
|
+
class="cursor-pointer nric-search-item">
|
|
123
|
+
<div class="d-flex align-center justify-space-between ga-4 w-100">
|
|
124
|
+
<span class="text-subtitle-1">{{ item.name || 'Unknown' }}</span>
|
|
125
|
+
<span class="text-subtitle-1 text-no-wrap">NRIC: {{ item.nric || 'N/A' }}</span>
|
|
126
|
+
</div>
|
|
127
|
+
</v-list-item>
|
|
128
|
+
</v-list>
|
|
129
|
+
</v-menu>
|
|
130
|
+
</v-col>
|
|
131
|
+
</v-row>
|
|
132
|
+
</v-col>
|
|
133
|
+
|
|
112
134
|
<v-col v-if="shouldShowField('deliveryType')" cols="12">
|
|
113
135
|
<v-row>
|
|
114
136
|
<v-col cols="12">
|
|
@@ -137,7 +159,7 @@
|
|
|
137
159
|
class="d-flex align-center ga-1">
|
|
138
160
|
<span><v-icon icon="mdi-plus" /></span>Add "<strong>{{
|
|
139
161
|
companyNameInput
|
|
140
|
-
|
|
162
|
+
}}</strong>" as new company.
|
|
141
163
|
</v-list-item-title>
|
|
142
164
|
<v-list-item-title v-else-if="!companyNameInput && companyNames.length === 0">
|
|
143
165
|
Start typing to search for companies.
|
|
@@ -167,7 +189,7 @@
|
|
|
167
189
|
class="d-flex align-center ga-1">
|
|
168
190
|
<span><v-icon icon="mdi-plus" /></span>Add "<strong>{{
|
|
169
191
|
companyNameInput
|
|
170
|
-
|
|
192
|
+
}}</strong>" as new company.
|
|
171
193
|
</v-list-item-title>
|
|
172
194
|
<v-list-item-title v-else-if="!companyNameInput && companyNames.length === 0">
|
|
173
195
|
Start typing to search for companies.
|
|
@@ -181,36 +203,7 @@
|
|
|
181
203
|
</v-col>
|
|
182
204
|
</template>
|
|
183
205
|
|
|
184
|
-
<v-col v-if="shouldShowField('plateNumber')" cols="12">
|
|
185
|
-
<v-row>
|
|
186
|
-
<v-col cols="12">
|
|
187
|
-
<InputLabel class="text-capitalize" title="Vehicle Number" :required="isVehicleRequired" />
|
|
188
|
-
<!-- <v-text-field v-model.trim.uppercase="visitor.plateNumber" density="comfortable" /> -->
|
|
189
|
-
<v-menu v-model="vehicleSearchMenu" location="bottom" offset-y :close-on-content-click="false">
|
|
190
|
-
<template #activator="{ props }">
|
|
191
|
-
<InputVehicleNumber v-bind="props" v-model="visitor.plateNumber" density="comfortable"
|
|
192
|
-
@update:model-value="handleUpdateVehicleNumber" />
|
|
193
|
-
</template>
|
|
194
206
|
|
|
195
|
-
<v-list v-if="vehicleSearchResults.length" class="pa-1">
|
|
196
|
-
<v-list-item v-for="(item, index) in vehicleSearchResults" :key="item._id || index"
|
|
197
|
-
@click="selectAutofillSearchResult(item, 'vehicleNumber')"
|
|
198
|
-
class="cursor-pointer nric-search-item">
|
|
199
|
-
<div class="d-flex align-center justify-space-between ga-4 w-100">
|
|
200
|
-
<span class="text-subtitle-1">{{ item.name || 'Unknown' }}</span>
|
|
201
|
-
<span class="text-subtitle-1 text-no-wrap">NRIC: {{ item.nric || 'N/A' }}</span>
|
|
202
|
-
</div>
|
|
203
|
-
<div v-if="getPersonContactOptions(item).length < 2 && getPersonPlateOptions(item).length < 2"
|
|
204
|
-
class="d-flex align-center justify-space-between ga-4 w-100">
|
|
205
|
-
<span class="text-subtitle-1">{{ getPersonContactOptions(item)[0] || 'N/A' }}</span>
|
|
206
|
-
<span class="text-subtitle-1 text-no-wrap">{{ getPersonPlateOptions(item)[0] || 'N/A' }}</span>
|
|
207
|
-
</div>
|
|
208
|
-
</v-list-item>
|
|
209
|
-
</v-list>
|
|
210
|
-
</v-menu>
|
|
211
|
-
</v-col>
|
|
212
|
-
</v-row>
|
|
213
|
-
</v-col>
|
|
214
207
|
|
|
215
208
|
<v-col v-if="shouldShowField('block')" cols="12">
|
|
216
209
|
<InputLabel class="text-capitalize" title="Block" required />
|
|
@@ -431,7 +424,7 @@
|
|
|
431
424
|
</v-data-table>
|
|
432
425
|
|
|
433
426
|
<div class="d-flex justify-end mt-8">
|
|
434
|
-
<v-btn v-if="!skipNonCheckedOutNric"
|
|
427
|
+
<v-btn v-if="!skipNonCheckedOutNric" color="red" variant="flat" size="large" class="text-none px-10"
|
|
435
428
|
:loading="loading.searchingNonCheckedOut" @click="handleSkipNricNonCheckedOut">
|
|
436
429
|
Skip NRIC: {{ visitor.nric || "N/A" }}
|
|
437
430
|
</v-btn>
|
|
@@ -1012,7 +1005,7 @@ function selectAutofillSearchResult(item: Partial<TPeople>, source: Exclude<Auto
|
|
|
1012
1005
|
const contactOptions = getPersonContactOptions(item);
|
|
1013
1006
|
const plateOptions = getPersonPlateOptions(item);
|
|
1014
1007
|
|
|
1015
|
-
if (contactOptions.length > 1 || plateOptions.length > 1) {
|
|
1008
|
+
if (source === "nric" && (contactOptions.length > 1 || plateOptions.length > 1)) {
|
|
1016
1009
|
nricSearchMenu.value = false;
|
|
1017
1010
|
phoneSearchMenu.value = false;
|
|
1018
1011
|
vehicleSearchMenu.value = false;
|