@7365admin1/layer-common 3.2.2-staging.118 → 3.2.2-staging.120

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.
@@ -1,24 +1,19 @@
1
1
  <template>
2
- <v-card width="100%" :loading="processing">
3
- <v-toolbar>
4
- <v-row
5
- no-gutters
6
- class="fill-height px-6 d-flex ga-2 justify-space-between"
7
- align="center"
8
- >
9
- <span class="font-weight-bold text-h5 text-capitalize">
10
- {{ prop.mode }} Vehicle <span>({{ formatVehicleType(type) }})</span>
11
- </span>
12
- <span>
13
- <ButtonClose @click="emit('close:all')" icon-only />
14
- </span>
15
- </v-row>
16
- </v-toolbar>
17
-
18
- <v-card-text style="max-height: 100vh; overflow-y: auto" class="pa-5 my-3">
19
- <span class="text-subtitle-1 w-100 font-weight-bold mb-3"
20
- >General Information</span
21
- >
2
+ <v-card width="100%" class="screen-modal vehicle-form" :loading="processing">
3
+ <div class="vehicle-form__head">
4
+ <v-card-title class="text-capitalize">
5
+ {{ prop.mode }} Vehicle ({{ formatVehicleType(type) }})
6
+ </v-card-title>
7
+ <AppButton
8
+ variant="icon"
9
+ icon="mdi-close"
10
+ aria-label="Close"
11
+ @click="emit('close:all')"
12
+ />
13
+ </div>
14
+
15
+ <div class="screen-modal__body vehicle-form__body filter-field">
16
+ <span class="vehicle-form__section">General Information</span>
22
17
  <v-form
23
18
  ref="formRef"
24
19
  v-model="validForm"
@@ -209,24 +204,20 @@
209
204
  :cols="newPlateNumbers.length > 1 ? '1' : '0'"
210
205
  class="d-flex align-start"
211
206
  >
212
- <v-btn
213
- icon="mdi-delete-outline"
214
- variant="text"
215
- color="error"
207
+ <AppButton
216
208
  v-if="newPlateNumbers.length > 1"
209
+ variant="icon"
210
+ icon="mdi-delete-outline"
211
+ class="vehicle-form__remove"
212
+ :aria-label="`Remove plate ${index + 1}`"
217
213
  @click="removePlate(index)"
218
214
  />
219
215
  </v-col>
220
216
  </v-row>
221
217
 
222
- <v-btn
223
- prepend-icon="mdi-plus"
224
- variant="outlined"
225
- class="text-none"
226
- @click="addPlate"
227
- >
218
+ <AppButton variant="ghost" icon="mdi-plus" @click="addPlate">
228
219
  Add Plate
229
- </v-btn>
220
+ </AppButton>
230
221
  </template>
231
222
  </template>
232
223
 
@@ -300,21 +291,19 @@
300
291
 
301
292
  <v-col cols="12" :class="[showSubscriptionDateOptions && 'mt-5']">
302
293
  <v-row justify="center">
303
- <v-col cols="6">
304
- <v-btn
305
- block
306
- color="primary"
307
- variant="text"
308
- class="text-none font-weight-bold"
309
- :text="
310
- showSubscriptionDateOptions
311
- ? 'Hide Subscription Options'
312
- : 'Show Subscription Options'
313
- "
294
+ <v-col cols="6" class="d-flex justify-center">
295
+ <AppButton
296
+ variant="ghost"
314
297
  @click="
315
298
  showSubscriptionDateOptions = !showSubscriptionDateOptions
316
299
  "
317
- ></v-btn>
300
+ >
301
+ {{
302
+ showSubscriptionDateOptions
303
+ ? "Hide Subscription Options"
304
+ : "Show Subscription Options"
305
+ }}
306
+ </AppButton>
318
307
  </v-col>
319
308
  </v-row>
320
309
  </v-col>
@@ -323,82 +312,41 @@
323
312
  <v-col cols="12">
324
313
  <v-row no-gutters>
325
314
  <v-col cols="12" class="text-center">
326
- <span
327
- class="text-none text-subtitle-2 font-weight-medium text-error"
328
- >
329
- {{ message }}
330
- </span>
315
+ <span class="vehicle-form__error">{{ message }}</span>
331
316
  </v-col>
332
317
  </v-row>
333
318
  </v-col>
334
319
  </v-row>
335
320
  </v-form>
336
- </v-card-text>
337
- <v-row no-gutters class="w-100" v-if="errorMessage">
338
- <p class="text-error w-100 text-center text-subtitle-2">
339
- {{ errorMessage }}
340
- </p>
341
- </v-row>
342
- <v-toolbar density="compact">
343
- <v-row no-gutters>
344
- <v-col cols="6">
345
- <v-btn
346
- v-if="prop.mode === 'add'"
347
- tile
348
- block
349
- variant="text"
350
- class="text-none"
351
- size="48"
352
- @click="back"
353
- text="Back to Selection"
354
- />
355
- <v-btn
356
- v-else
357
- tile
358
- block
359
- variant="text"
360
- class="text-none"
361
- size="48"
362
- @click="close"
363
- text="Close"
364
- />
365
- </v-col>
366
- <v-col cols="6">
367
- <v-btn
368
- tile
369
- block
370
- variant="flat"
371
- color="black"
372
- class="text-none"
373
- size="48"
374
- :disabled="!validForm || processing"
375
- @click="submit"
376
- :text="prop.mode == 'add' ? 'Submit' : 'Update'"
377
- />
378
- </v-col>
379
- </v-row>
380
- </v-toolbar>
321
+ </div>
322
+ <p v-if="errorMessage" class="vehicle-form__error vehicle-form__error--block">
323
+ {{ errorMessage }}
324
+ </p>
325
+ <div class="vehicle-form__footer">
326
+ <AppButton v-if="prop.mode === 'add'" variant="ghost" @click="back">
327
+ Back to Selection
328
+ </AppButton>
329
+ <AppButton v-else variant="ghost" @click="close">Close</AppButton>
330
+ <AppButton :disabled="!validForm || processing" @click="submit">
331
+ {{ prop.mode == "add" ? "Submit" : "Update" }}
332
+ </AppButton>
333
+ </div>
381
334
 
382
335
  <v-dialog v-model="showMatchingPeopleDialog" max-width="700" persistent>
383
- <v-card :loading="checkingUnit">
384
- <v-toolbar>
385
- <v-toolbar-title>
386
- <v-row no-gutters class="d-flex align-center justify-space-between">
387
- <span class="font-weight-bold">
388
- Matching Records for "{{ searchUnitName ?? "-" }}"
389
- </span>
390
- <span>
391
- <v-btn
392
- icon="mdi-close"
393
- variant="text"
394
- @click="handleCloseMatchDialog"
395
- />
396
- </span>
397
- </v-row>
398
- </v-toolbar-title>
399
- </v-toolbar>
336
+ <v-card class="screen-modal vehicle-match" :loading="checkingUnit">
337
+ <div class="vehicle-form__head">
338
+ <v-card-title>
339
+ Matching Records for "{{ searchUnitName ?? "-" }}"
340
+ </v-card-title>
341
+ <AppButton
342
+ variant="icon"
343
+ icon="mdi-close"
344
+ aria-label="Close"
345
+ @click="handleCloseMatchDialog"
346
+ />
347
+ </div>
400
348
 
401
- <v-card-text max-height="400" style="overflow-y: auto">
349
+ <div class="screen-modal__body vehicle-match__body">
402
350
  <v-list lines="three">
403
351
  <v-list-item
404
352
  v-if="matchingPeople.length > 0 || checkingUnit"
@@ -414,24 +362,19 @@
414
362
  NRIC: {{ v.nric || "-" }}
415
363
  </v-list-item-subtitle>
416
364
 
417
- <div class="mt-1">
418
- <v-chip
365
+ <div class="mt-1 d-flex flex-wrap ga-1">
366
+ <StatusChip
419
367
  v-for="p in v.plates"
420
368
  :key="p?.plateNumber"
421
- size="small"
422
- class="mr-1"
369
+ tone="neutral"
370
+ :dot="false"
423
371
  >
424
372
  {{ p?.plateNumber }}
425
- </v-chip>
373
+ </StatusChip>
426
374
  </div>
427
375
 
428
376
  <template #append>
429
- <v-btn
430
- variant="flat"
431
- color="primary"
432
- @click="selectPeopleRecord(v)"
433
- >Select</v-btn
434
- >
377
+ <AppButton @click="selectPeopleRecord(v)">Select</AppButton>
435
378
  </template>
436
379
  </v-list-item>
437
380
  <v-empty-state
@@ -441,16 +384,13 @@
441
384
  subtitle="The NRIC you entered does not match any existing records."
442
385
  >
443
386
  <template #actions>
444
- <v-btn
445
- variant="flat"
446
- color="primary"
447
- @click="showMatchingPeopleDialog = false"
448
- >Close</v-btn
449
- >
387
+ <AppButton @click="showMatchingPeopleDialog = false">
388
+ Close
389
+ </AppButton>
450
390
  </template>
451
391
  </v-empty-state>
452
392
  </v-list>
453
- </v-card-text>
393
+ </div>
454
394
  </v-card>
455
395
  </v-dialog>
456
396
  </v-card>
@@ -1123,4 +1063,47 @@ onMounted(() => {
1123
1063
  .class-readonly {
1124
1064
  pointer-events: none;
1125
1065
  }
1066
+
1067
+ .vehicle-form__head {
1068
+ display: flex;
1069
+ align-items: center;
1070
+ justify-content: space-between;
1071
+ padding-right: 12px;
1072
+ }
1073
+
1074
+ .vehicle-form__body,
1075
+ .vehicle-match__body {
1076
+ padding: 4px 20px 0;
1077
+ }
1078
+
1079
+ .vehicle-form__section {
1080
+ display: block;
1081
+ margin-bottom: 4px;
1082
+ font-size: var(--fs-cell);
1083
+ font-weight: 800;
1084
+ color: var(--text);
1085
+ }
1086
+
1087
+ .vehicle-form__remove {
1088
+ color: var(--err);
1089
+ }
1090
+
1091
+ .vehicle-form__error {
1092
+ font-size: var(--fs-cell);
1093
+ font-weight: 500;
1094
+ color: var(--err);
1095
+ }
1096
+
1097
+ .vehicle-form__error--block {
1098
+ width: 100%;
1099
+ margin: 0;
1100
+ text-align: center;
1101
+ }
1102
+
1103
+ .vehicle-form__footer {
1104
+ display: flex;
1105
+ justify-content: flex-end;
1106
+ gap: 8px;
1107
+ padding: 16px 20px 20px;
1108
+ }
1126
1109
  </style>
@@ -1,55 +1,37 @@
1
1
  <template>
2
- <v-card width="100%">
3
- <v-toolbar>
4
- <template v-if="$slots.header">
5
- <slot name="header" :title="title" :onClose="onClose" />
6
- </template>
7
- <template v-else>
8
- <v-row no-gutters class="fill-height px-6" align="center">
9
- <span class="font-weight-bold text-h5 text-capitalize">{{
10
- title
11
- }}</span>
12
- </v-row>
13
- </template>
14
- </v-toolbar>
2
+ <v-card width="100%" class="screen-modal more-action">
3
+ <template v-if="$slots.header">
4
+ <slot name="header" :title="title" :onClose="onClose" />
5
+ </template>
6
+ <v-card-title v-else class="text-capitalize">{{ title }}</v-card-title>
15
7
 
16
- <v-card-text style="max-height: 100vh; overflow-y: auto" class="pb-0">
8
+ <div class="screen-modal__body more-action__body">
17
9
  <slot name="content" />
18
- </v-card-text>
10
+ </div>
19
11
 
20
- <v-toolbar class="pa-0" density="compact">
21
- <v-row no-gutters>
22
- <v-col :cols="canDelete || canUpdate ? 6 : 12" class="pa-0">
23
- <v-btn block variant="text" class="text-none" size="large" @click="emit('close')" height="48">
24
- Close
25
- </v-btn>
26
- </v-col>
12
+ <div class="more-action__footer">
13
+ <AppButton variant="ghost" @click="emit('close')">Close</AppButton>
27
14
 
28
- <v-col cols="6" class="pa-0" v-if="canDelete || canUpdate">
29
- <v-menu>
30
- <template #activator="{ props }">
31
- <v-btn block variant="flat" color="black" class="text-none" height="48" v-bind="props" tile>
32
- More actions
33
- </v-btn>
34
- </template>
15
+ <v-menu v-if="canDelete || canUpdate">
16
+ <template #activator="{ props }">
17
+ <AppButton v-bind="props">More actions</AppButton>
18
+ </template>
35
19
 
36
- <v-list class="pa-0">
37
- <v-list-item v-if="canUpdate" @click="emit('edit')">
38
- <v-list-item-title class="text-subtitle-2">
39
- {{ editButtonLabel }}
40
- </v-list-item-title>
41
- </v-list-item>
20
+ <v-list class="more-action__menu">
21
+ <v-list-item v-if="canUpdate" @click="emit('edit')">
22
+ <v-list-item-title class="more-action__item">
23
+ {{ editButtonLabel }}
24
+ </v-list-item-title>
25
+ </v-list-item>
42
26
 
43
- <v-list-item v-if="canDelete" @click="emit('delete')" class="text-red">
44
- <v-list-item-title class="text-subtitle-2">
45
- {{ deleteButtonLabel }}
46
- </v-list-item-title>
47
- </v-list-item>
48
- </v-list>
49
- </v-menu>
50
- </v-col>
51
- </v-row>
52
- </v-toolbar>
27
+ <v-list-item v-if="canDelete" @click="emit('delete')">
28
+ <v-list-item-title class="more-action__item more-action__item--danger">
29
+ {{ deleteButtonLabel }}
30
+ </v-list-item-title>
31
+ </v-list-item>
32
+ </v-list>
33
+ </v-menu>
34
+ </div>
53
35
  </v-card>
54
36
  </template>
55
37
 
@@ -81,4 +63,35 @@ const emit = defineEmits(["close", "edit", "delete"]);
81
63
  const { canUpdate, editButtonLabel, deleteButtonLabel, title } = prop;
82
64
  </script>
83
65
 
84
- <style scoped></style>
66
+ <style scoped>
67
+ .more-action__body {
68
+ padding: 4px 20px;
69
+ }
70
+
71
+ .more-action__footer {
72
+ display: flex;
73
+ justify-content: flex-end;
74
+ gap: 8px;
75
+ padding: 16px 20px 20px;
76
+ }
77
+
78
+ /* The dropdown is teleported out of the card, so it needs the card's own
79
+ surface and rule said again rather than inheriting Vuetify's grey sheet. */
80
+ .more-action__menu {
81
+ padding: 4px 0;
82
+ background: var(--card);
83
+ border: 1px solid var(--border);
84
+ border-radius: var(--r-inner);
85
+ }
86
+
87
+ .more-action__item {
88
+ font-size: var(--fs-cell);
89
+ font-weight: var(--fw-btn);
90
+ color: var(--text);
91
+ }
92
+
93
+ /* The delete row was Vuetify's `text-red`; same meaning, on the token. */
94
+ .more-action__item--danger {
95
+ color: var(--err);
96
+ }
97
+ </style>
@@ -1,24 +1,25 @@
1
1
  <template>
2
- <v-card width="100%" :loading="processing">
3
- <v-toolbar>
4
- <v-row
5
- no-gutters
6
- class="fill-height px-6 d-flex justify-space-between align-center"
7
- align="center"
8
- >
9
- <span class="font-weight-bold text-h5 text-capitalize">
10
- Visitor Information
11
- </span>
12
- <ButtonClose @click="emit('close')" />
13
- </v-row>
14
- </v-toolbar>
15
- <v-card-text style="max-height: 100vh; overflow-y: auto" class="pa-5 my-3">
2
+ <v-card width="100%" class="screen-modal visitor-scan" :loading="processing">
3
+ <div class="visitor-scan__head">
4
+ <v-card-title>Visitor Information</v-card-title>
5
+ <AppButton
6
+ variant="icon"
7
+ icon="mdi-close"
8
+ aria-label="Close"
9
+ @click="emit('close')"
10
+ />
11
+ </div>
12
+ <div class="screen-modal__body visitor-scan__body">
16
13
  <div class="w-100 d-flex justify-space-between ga-2">
17
14
  <!-- <span v-if="withStep2 || withStep3" class="text-subtitle-2 font-weight-bold" style="text-wrap: nowrap">Step
18
15
  <span class="text-primary-button">{{ contractorStep }}</span>/{{ withStep3 ? 3 : withStep2 ? 2 : 1 }}</span> -->
19
16
  </div>
20
17
  <!-- <v-form ref="formRef" v-model="validForm" :disabled="processing" @click="errorMessage = ''"> -->
21
- <v-row no-gutters class="pt-4">
18
+ <!-- `.filter-field` is the design's input on its own (40px, 10px radius,
19
+ 13.5px). It is a DESCENDANT selector, so one class on the row gives
20
+ it to every field here - including the composed `Input/*` controls,
21
+ which are shared with other screens and are not edited. -->
22
+ <v-row no-gutters class="pt-4 filter-field">
22
23
  <v-col cols="12">
23
24
  <InputLabel class="text-capitalize" title="Full Name" />
24
25
  <v-text-field
@@ -134,22 +135,16 @@
134
135
  </v-col>
135
136
 
136
137
  <v-col v-else cols="12">
137
- <v-card elevation="4" height="100%" width="100%">
138
- <v-col cols="12" class="d-flex justify-center pb-0">
139
- <span
140
- class="text-h6 font-weight-bold d-flex text-center text-success"
141
- >
142
- {{
143
- visitorInfo.checkIn
144
- ? standardFormatDateTime(visitorInfo.checkIn)
145
- : "N/A"
146
- }}
147
- </span>
148
- </v-col>
149
- <v-col cols="12" class="d-flex justify-center">
150
- Actual Check In
151
- </v-col>
152
- </v-card>
138
+ <AppCard class="visitor-scan__checkin">
139
+ <span class="visitor-scan__checkin-time">
140
+ {{
141
+ visitorInfo.checkIn
142
+ ? standardFormatDateTime(visitorInfo.checkIn)
143
+ : "N/A"
144
+ }}
145
+ </span>
146
+ <span class="visitor-scan__checkin-label">Actual Check In</span>
147
+ </AppCard>
153
148
  </v-col>
154
149
 
155
150
  <!-- <v-col cols="12" class="mt-4">
@@ -194,41 +189,31 @@
194
189
  </v-col> -->
195
190
  </v-row>
196
191
  <!-- </v-form> -->
197
- </v-card-text>
192
+ </div>
198
193
 
199
- <v-toolbar density="compact">
200
- <v-row no-gutters>
201
- <v-col cols="6">
202
- <v-btn text="Close" block size="48" tile @click="emit('close')" />
203
- </v-col>
204
- <v-col cols="6">
205
- <v-btn
206
- v-if="!visitorInfo.checkIn && !visitorInfo.checkOut"
207
- block
208
- text="Check In"
209
- variant="flat"
210
- color="success"
211
- size="48"
212
- tile
213
- :disabled="processing"
214
- @click="emit('check-in-out', 'checkIn', visitorInfo)"
215
- :loading="processing"
216
- />
217
- <v-btn
218
- v-if="visitorInfo.checkIn && !visitorInfo.checkOut"
219
- block
220
- text="Confirm Check Out"
221
- variant="flat"
222
- color="error"
223
- size="48"
224
- tile
225
- :disabled="processing"
226
- @click="emit('check-in-out', 'checkOut', visitorInfo)"
227
- :loading="processing"
228
- />
229
- </v-col>
230
- </v-row>
231
- </v-toolbar>
194
+ <!--
195
+ Check In and Confirm Check Out are mutually exclusive - only ever one of
196
+ them is on the glass - so both are the screen's single primary action.
197
+ The handoff draws no green/red button, and inventing one only to fail
198
+ contrast is the trade that was already made and reverted once.
199
+ -->
200
+ <div class="visitor-scan__footer">
201
+ <AppButton variant="ghost" @click="emit('close')">Close</AppButton>
202
+ <AppButton
203
+ v-if="!visitorInfo.checkIn && !visitorInfo.checkOut"
204
+ :disabled="processing"
205
+ @click="emit('check-in-out', 'checkIn', visitorInfo)"
206
+ >
207
+ Check In
208
+ </AppButton>
209
+ <AppButton
210
+ v-if="visitorInfo.checkIn && !visitorInfo.checkOut"
211
+ :disabled="processing"
212
+ @click="emit('check-in-out', 'checkOut', visitorInfo)"
213
+ >
214
+ Confirm Check Out
215
+ </AppButton>
216
+ </div>
232
217
  </v-card>
233
218
  </template>
234
219
  <script setup lang="ts">
@@ -315,3 +300,43 @@ const location = computed({
315
300
  set: () => {}, // readonly, do nothing on set
316
301
  });
317
302
  </script>
303
+
304
+ <style scoped>
305
+ .visitor-scan__head {
306
+ display: flex;
307
+ align-items: center;
308
+ justify-content: space-between;
309
+ padding-right: 12px;
310
+ }
311
+
312
+ .visitor-scan__body {
313
+ padding: 4px 20px 0;
314
+ }
315
+
316
+ .visitor-scan__footer {
317
+ display: flex;
318
+ justify-content: flex-end;
319
+ gap: 8px;
320
+ padding: 16px 20px 20px;
321
+ }
322
+
323
+ /* The check-in stamp, on the card primitive instead of a 4dp Vuetify sheet. */
324
+ .visitor-scan__checkin {
325
+ display: flex;
326
+ flex-direction: column;
327
+ align-items: center;
328
+ gap: 4px;
329
+ padding: 16px;
330
+ }
331
+
332
+ .visitor-scan__checkin-time {
333
+ font-size: 18px;
334
+ font-weight: 800;
335
+ color: var(--ok);
336
+ }
337
+
338
+ .visitor-scan__checkin-label {
339
+ font-size: var(--fs-cell);
340
+ color: var(--text2);
341
+ }
342
+ </style>