@7365admin1/layer-common 3.2.7 → 3.2.8-staging.201
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/assets/css/primitives.css +1113 -0
- package/assets/css/screens.css +1097 -0
- package/assets/css/shell.css +258 -0
- package/assets/css/tokens.css +236 -0
- package/components/AcceptDialog.vue +17 -18
- package/components/AccessCard/AvailableStats.vue +24 -16
- package/components/AccessCardAddForm.vue +42 -42
- package/components/AccessCardAssignToUnitForm.vue +13 -21
- package/components/AccessCardDeleteDialog.vue +41 -39
- package/components/AccessCardDetailsDialog.vue +125 -79
- package/components/AccessCardPreviewDialog.vue +58 -84
- package/components/AccessCardQrTagging.vue +60 -63
- package/components/AccessCardReplaceForm.vue +27 -23
- package/components/AccessManagement.vue +86 -85
- package/components/AddEqupmentForm.vue +18 -22
- package/components/AddPassKeyToVisitor.vue +95 -73
- package/components/AppButton.vue +62 -0
- package/components/AppCard.vue +20 -0
- package/components/AppDateField.vue +49 -0
- package/components/AppField.vue +76 -0
- package/components/AppKpiTile.vue +65 -0
- package/components/AppSegmented.vue +38 -0
- package/components/AppSelect.vue +247 -0
- package/components/AreaChecklistHistoryLogs.vue +51 -44
- package/components/AreaChecklistHistoryMain.vue +14 -7
- package/components/AreaFormDialog.vue +71 -59
- package/components/AreaMain.vue +73 -107
- package/components/AttachmentsViewer.vue +84 -22
- package/components/AttendanceCheckInOutDialog.vue +85 -88
- package/components/AttendanceDetailsDialog.vue +57 -63
- package/components/AttendanceMain.vue +4 -3
- package/components/AttendanceMapSearchDialog.vue +42 -44
- package/components/AttendanceSettingsDialog.vue +79 -63
- package/components/Avatar/Main.vue +54 -2
- package/components/BillingMain.vue +26 -30
- package/components/BtnUploadFile.vue +53 -11
- package/components/BuildingForm.vue +34 -27
- package/components/BuildingManagement/buildings.vue +39 -39
- package/components/BuildingManagement/units.vue +26 -42
- package/components/BuildingUnitFormAdd.vue +20 -23
- package/components/BuildingUnitFormEdit.vue +8 -4
- package/components/BulletinBoardForm.vue +19 -24
- package/components/BulletinBoardManagement.vue +49 -57
- package/components/BulletinBoardView.vue +9 -6
- package/components/BulletinExpirationChip.vue +13 -4
- package/components/Button/Close.vue +2 -2
- package/components/CameraForm.vue +21 -22
- package/components/CameraMain.vue +50 -49
- package/components/Card/DeleteConfirmation.vue +24 -22
- package/components/Card/MemberInfoSummary.vue +28 -3
- package/components/Card/Toggle.vue +15 -3
- package/components/CardToolbar.vue +37 -0
- package/components/Carousel.vue +56 -36
- package/components/Chat/Bubbles.vue +43 -14
- package/components/Chat/Information.vue +49 -32
- package/components/Chat/ListCard.vue +38 -9
- package/components/Chat/Message.vue +41 -15
- package/components/Chat/Navigation.vue +27 -15
- package/components/Chat/SkeletonLoader.vue +9 -2
- package/components/ChecklistItemRow.vue +25 -1
- package/components/CleaningScheduleMain.vue +44 -49
- package/components/ClientDetailForm.vue +81 -56
- package/components/ClientMain.vue +92 -82
- package/components/ConfirmDialog.vue +14 -8
- package/components/Container/Standard.vue +9 -7
- package/components/CreateSubsciptionPlan.vue +148 -89
- package/components/DashboardEmptyState.vue +48 -3
- package/components/DashboardMain.vue +924 -676
- package/components/DashboardPanel.vue +84 -21
- package/components/DeliveryCompany.vue +34 -20
- package/components/Dialog/DeleteConfirmation.vue +20 -21
- package/components/Dialog/ReplaceAutofillPrompt.vue +19 -26
- package/components/Dialog/ReusablePrompt.vue +30 -29
- package/components/Dialog/UpdateMoreAction.vue +62 -59
- package/components/DocumentForm.vue +14 -21
- package/components/DocumentManagement.vue +162 -108
- package/components/DocumentViewer.vue +29 -12
- package/components/DrawImage.vue +29 -21
- package/components/EntryPass/QrTemplatePreview.vue +27 -16
- package/components/EntryPassInformation.vue +40 -10
- package/components/EntryPassMain.vue +49 -27
- package/components/EquipmentItemMain.vue +84 -97
- package/components/EquipmentManagementMain.vue +81 -103
- package/components/Facility/BookingSetup.vue +43 -52
- package/components/Feedback/Form.vue +26 -12
- package/components/FeedbackMain.vue +35 -49
- package/components/FileInput.vue +75 -58
- package/components/FileInputWithList.vue +59 -12
- package/components/FormDialog.vue +60 -21
- package/components/HidAccessLogDashboard.vue +512 -490
- package/components/HidCameraCaptureDialog.vue +216 -0
- package/components/HidEnabledGate.vue +67 -9
- package/components/HidIntercomManagement.vue +1322 -653
- package/components/HidQrCodeConfiguration.vue +1030 -258
- package/components/HidReaderForm.vue +142 -59
- package/components/HidReaderManagement.vue +211 -323
- package/components/HidServiceSettingsPanel.vue +44 -13
- package/components/HidUserEnrollment.vue +1185 -412
- package/components/HygieneUpdateMoreAction.vue +44 -44
- package/components/IncidentReport/Authorities.vue +30 -18
- package/components/IncidentReport/IncidentInformation.vue +10 -10
- package/components/IncidentReport/IncidentInformationDownload.vue +3 -4
- package/components/IncidentReport/affectedEntities.vue +41 -20
- package/components/Input/Date.vue +3 -0
- package/components/Input/DatePicker.vue +1 -2
- package/components/Input/DateTimePicker.vue +1 -1
- package/components/Input/File.vue +55 -10
- package/components/Input/FileV2.vue +39 -6
- package/components/Input/InputPhoneNumberV2.vue +2 -1
- package/components/Input/ListGroupSelection.vue +56 -8
- package/components/Input/NRICNumber.vue +1 -0
- package/components/Input/NewDate.vue +1 -0
- package/components/Input/Number.vue +1 -0
- package/components/Input/Password.vue +1 -0
- package/components/Input/PhoneNumber.vue +21 -1
- package/components/Input/VehicleNumber.vue +1 -0
- package/components/InputLabel.vue +2 -2
- package/components/InvitationClientForm.vue +21 -19
- package/components/InvitationForm.vue +15 -21
- package/components/InvitationMain.vue +46 -61
- package/components/Layout/Header.vue +263 -36
- package/components/Layout/NavigationDrawer.vue +300 -30
- package/components/ListItem.vue +33 -3
- package/components/LocalPagination.vue +27 -3
- package/components/ManageChecklistMain.vue +136 -86
- package/components/MemberInformation.vue +32 -16
- package/components/MemberMain.vue +113 -93
- package/components/MyAttendanceMain.vue +3 -5
- package/components/NavigationItem.vue +83 -3
- package/components/Nfc/NFCPatrolReportMain.vue +47 -33
- package/components/Nfc/NFCPatrolRouteForm.vue +18 -20
- package/components/Nfc/NFCPatrolRouteMain.vue +116 -103
- package/components/Nfc/NFCPatrolSettings.vue +14 -4
- package/components/Nfc/NFCTagForm.vue +22 -8
- package/components/Nfc/NFCTagMain.vue +41 -43
- package/components/Nfc/PatrolReport/DailyReportTab.vue +8 -1
- package/components/Nfc/PatrolReport/MonthlyReportTab.vue +8 -1
- package/components/Nfc/PatrolReport/MonthlyReportTable.vue +5 -3
- package/components/Nfc/PatrolReport/PatrolActivityTable.vue +26 -6
- package/components/Nfc/PatrolReport/PatrolReportTab.vue +8 -0
- package/components/Nfc/PatrolReport/PatrolRouteSummary.vue +41 -9
- package/components/Nfc/PatrolReport/RemarksDialog.vue +39 -9
- package/components/Nfc/PatrolReport/ReportEmptyState.vue +29 -9
- package/components/Nfc/PatrolReport/ReportFilters.vue +19 -10
- package/components/Nfc/PatrolReport/ReportLocationHeader.vue +32 -6
- package/components/Nfc/PatrolReport/SummaryReportTable.vue +28 -6
- package/components/NotificationSettings.vue +373 -0
- package/components/NumberSettingField.vue +9 -2
- package/components/OnlineFormConfigurationForm.vue +725 -237
- package/components/OnlineFormFill.vue +213 -106
- package/components/OnlineFormRenderPreview.vue +25 -30
- package/components/OnlineFormsConfiguration.vue +113 -109
- package/components/OrgViewDialog.vue +34 -16
- package/components/OvernightParkingAvailability.vue +49 -26
- package/components/OvernightParkingManagement.vue +78 -18
- package/components/PageHeader.vue +43 -0
- package/components/PassInformation.vue +109 -53
- package/components/PasswordConfirmation.vue +44 -26
- package/components/PeopleForm.vue +41 -20
- package/components/PhotoUpload.vue +110 -48
- package/components/PlaceholderComponent.vue +35 -19
- package/components/PlanActionsMenu.vue +12 -2
- package/components/PlanStatusBadge.vue +7 -8
- package/components/PlateNumberDisplay.vue +9 -6
- package/components/QrTemplate/PrintDialog.vue +66 -43
- package/components/RolePermissionFormCreate.vue +104 -79
- package/components/RolePermissionFormPreviewUpdate.vue +111 -109
- package/components/RolePermissionMain.vue +183 -81
- package/components/ScanVisitorQRCode.vue +99 -35
- package/components/ScheduleAreaMain.vue +34 -59
- package/components/ScheduleTaskForm.vue +61 -42
- package/components/ScheduleTaskMain.vue +56 -69
- package/components/SearchVehicleNumberUser.vue +39 -37
- package/components/ServiceProviderFormCreate.vue +29 -20
- package/components/ServiceProviderInvitationPrompt.vue +155 -0
- package/components/ServiceProviderMain.vue +601 -432
- package/components/Signature.vue +40 -34
- package/components/SignaturePad.vue +5 -29
- package/components/SiteSettings.vue +41 -11
- package/components/SiteSettingsWorkOrder.vue +61 -30
- package/components/SlideCardGroup.vue +35 -11
- package/components/Snackbar.vue +36 -3
- package/components/SpecificAttr.vue +18 -8
- package/components/StatusChip.vue +156 -0
- package/components/StockCard.vue +17 -12
- package/components/SubscriptionPlanTable.vue +207 -140
- package/components/SwitchContext.vue +201 -9
- package/components/TableHygiene.vue +36 -46
- package/components/TableList.vue +10 -10
- package/components/TableListSecondary.vue +105 -54
- package/components/TableMain.vue +251 -78
- package/components/TableV3.vue +61 -70
- package/components/TiptapEditor.vue +33 -40
- package/components/TiptapEditorQr.vue +5 -2
- package/components/Tooltip/Info.vue +69 -24
- package/components/UnitMain.vue +40 -60
- package/components/UnitPersonCard.vue +42 -13
- package/components/VehicleAddSelection.vue +48 -32
- package/components/VehicleForm.vue +112 -129
- package/components/VehicleManagement.vue +26 -12
- package/components/VehicleUpdateMoreAction.vue +59 -46
- package/components/VisitorDataFromScannedQRCodeForm.vue +90 -65
- package/components/VisitorForm.vue +774 -210
- package/components/VisitorFormSelection.vue +40 -37
- package/components/VisitorManagement.vue +239 -82
- package/components/VisitorPassKeyQRScanner.vue +65 -18
- package/components/VisitorSearchResultSummary.vue +60 -16
- package/components/VisitorSocketPopUp.vue +22 -14
- package/components/VisitorsReportPreview.vue +44 -29
- package/components/WorkOrder/Create.vue +26 -17
- package/components/WorkOrder/ListView.vue +38 -7
- package/components/WorkOrder/Main.vue +62 -59
- package/composables/useFeedback.ts +3 -3
- package/composables/useHidAmico.ts +269 -0
- package/composables/useHidNavigation.ts +2 -9
- package/composables/useMember.ts +3 -3
- package/composables/useNFCPatrolDailyReport.ts +13 -0
- package/composables/useNFCPatrolMonthlyReport.ts +22 -56
- package/composables/useNFCPatrolReport.ts +13 -0
- package/composables/useNotificationPreference.ts +87 -0
- package/composables/useOnlineFormPages.ts +2 -0
- package/composables/useRole.ts +22 -0
- package/composables/useServiceProvider.ts +3 -3
- package/composables/useServiceProviderInvitation.ts +145 -0
- package/composables/useSipWebPhone.ts +336 -0
- package/composables/useSubscriptionPlan.ts +62 -0
- package/composables/useThemePreference.ts +63 -0
- package/composables/useVisitor.ts +6 -1
- package/composables/useWebUsb.ts +127 -37
- package/composables/useWorkOrder.ts +17 -3
- package/error.vue +30 -6
- package/nuxt.config.ts +36 -0
- package/package.json +25 -4
- package/pages/[org]/[site]/access-mgmt/administrator/index.vue +2 -2
- package/pages/[org]/[site]/access-mgmt/{identity-mapping → hid-cards}/index.vue +2 -2
- package/pages/[org]/[site]/access-mgmt/intercom/index.vue +1 -1
- package/pages/notification-settings.vue +19 -0
- package/pages/payment-method-linked.vue +34 -10
- package/pages/require-customer.vue +48 -10
- package/pages/require-organization-membership.vue +32 -8
- package/pages/unauthorized.vue +29 -4
- package/plugins/secure-member.client.ts +21 -56
- package/plugins/vuetify.ts +69 -2
- package/types/nfc-patrol-report.ts +3 -2
- package/types/site.d.ts +71 -0
- package/types/subscription.ts +18 -11
- package/utils/breadcrumb.test.ts +108 -0
- package/utils/breadcrumb.ts +82 -0
- package/utils/dashboard.test.ts +118 -0
- package/utils/dashboard.ts +53 -0
- package/utils/data.test.ts +95 -0
- package/utils/data.ts +40 -2
- package/utils/hid-discover.test.ts +102 -0
- package/utils/list-page.test.ts +60 -0
- package/utils/list-page.ts +38 -0
- package/utils/materialSymbols.ts +363 -0
- package/utils/nav-sections.test.ts +190 -0
- package/utils/nav-sections.ts +151 -0
- package/utils/nfc-patrol-report.test.ts +130 -0
- package/utils/nfc-patrol-report.ts +101 -0
- package/utils/role.test.ts +69 -0
- package/utils/role.ts +10 -0
- package/utils/route-name.test.ts +85 -0
- package/utils/route-name.ts +24 -0
- package/utils/status.test.ts +110 -0
- package/utils/status.ts +135 -0
- package/utils/table-card.test.ts +84 -0
- package/utils/theme-aa-ledger.ts +148 -0
- package/utils/theme.test.ts +485 -7
- package/utils/theme.ts +295 -110
- package/.changeset/README.md +0 -8
- package/.changeset/config.json +0 -11
- package/.editorconfig +0 -12
- package/.github/workflows/main.yml +0 -17
- package/.github/workflows/publish-staging.yml +0 -47
- package/.github/workflows/publish.yml +0 -39
- package/PUBLISHING.md +0 -269
- package/components/HidIdentityMapping.vue +0 -975
- package/components/ScheduleTaskAreaFormDialog.vue +0 -144
- package/components/ScheduleTaskAreaUpdateMoreAction.vue +0 -109
- package/components/ScheduleTastTicketMain.vue +0 -182
- package/components/TableWithButton.vue +0 -94
- package/test/visitor-socket.test.mjs +0 -36
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-card width="100%">
|
|
3
|
-
<v-toolbar>
|
|
2
|
+
<v-card width="100%" class="screen-modal">
|
|
3
|
+
<v-toolbar class="screen-dialog-bar">
|
|
4
4
|
<v-row no-gutters class="fill-height px-6" align="center" justify="space-between">
|
|
5
|
-
<span class="
|
|
5
|
+
<span class="screen-card-title text-capitalize">
|
|
6
6
|
{{ prop.mode }} Access Card
|
|
7
7
|
</span>
|
|
8
8
|
<v-btn-toggle
|
|
@@ -19,7 +19,10 @@
|
|
|
19
19
|
</v-btn-toggle>
|
|
20
20
|
</v-row>
|
|
21
21
|
</v-toolbar>
|
|
22
|
-
|
|
22
|
+
<!-- The height cap stays ON THE BODY. `.screen-modal` caps the CARD, which
|
|
23
|
+
only reaches the glass inside a dialog's flex column; mounted on its own
|
|
24
|
+
the footer would fall below the fold. -->
|
|
25
|
+
<v-card-text class="screen-modal__body pa-0" style="max-height: 100vh">
|
|
23
26
|
<!-- Bulk Upload Mode -->
|
|
24
27
|
<template v-if="uploadMode === 'bulk'">
|
|
25
28
|
<v-row no-gutters class="px-6 pt-4 pb-2">
|
|
@@ -63,12 +66,12 @@
|
|
|
63
66
|
|
|
64
67
|
<!-- Column Guide -->
|
|
65
68
|
<div class="mt-3">
|
|
66
|
-
<p class="text-caption font-weight-bold text-
|
|
69
|
+
<p class="text-caption font-weight-bold text-fontgray mb-1 text-uppercase">
|
|
67
70
|
Template Column Guide
|
|
68
71
|
</p>
|
|
69
72
|
<v-table density="compact" class="text-caption rounded border">
|
|
70
73
|
<thead>
|
|
71
|
-
<tr class="
|
|
74
|
+
<tr class="template-guide-head">
|
|
72
75
|
<th class="text-left text-caption font-weight-bold py-1 px-2">Column</th>
|
|
73
76
|
<th class="text-left text-caption font-weight-bold py-1 px-2">Format / Accepted Values</th>
|
|
74
77
|
<th class="text-left text-caption font-weight-bold py-1 px-2">Example</th>
|
|
@@ -77,8 +80,8 @@
|
|
|
77
80
|
<tbody>
|
|
78
81
|
<tr v-for="col in templateColumnGuide" :key="col.name">
|
|
79
82
|
<td class="py-1 px-2 font-weight-medium" style="white-space: nowrap">{{ col.name }}</td>
|
|
80
|
-
<td class="py-1 px-2 text-
|
|
81
|
-
<td class="py-1 px-2 text-
|
|
83
|
+
<td class="py-1 px-2 text-fontgray">{{ col.format }}</td>
|
|
84
|
+
<td class="py-1 px-2 text-fontgray">{{ col.example }}</td>
|
|
82
85
|
</tr>
|
|
83
86
|
</tbody>
|
|
84
87
|
</v-table>
|
|
@@ -306,7 +309,7 @@
|
|
|
306
309
|
></span>
|
|
307
310
|
<span class="d-flex align-center">
|
|
308
311
|
Anti Pass Back
|
|
309
|
-
<v-icon class="ml-1
|
|
312
|
+
<v-icon class="ml-1 text-fontgray" size="small"
|
|
310
313
|
>mdi-help-circle</v-icon
|
|
311
314
|
>
|
|
312
315
|
<v-checkbox
|
|
@@ -382,39 +385,25 @@
|
|
|
382
385
|
</v-row>
|
|
383
386
|
</v-form>
|
|
384
387
|
</v-card-text>
|
|
385
|
-
<v-
|
|
386
|
-
<v-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
block
|
|
405
|
-
variant="flat"
|
|
406
|
-
color="black"
|
|
407
|
-
class="text-none"
|
|
408
|
-
size="48"
|
|
409
|
-
:disabled="(uploadMode === 'single' ? !validForm : !bulkFile || !entryPassTemplate.id || templateLoading) || disable"
|
|
410
|
-
@click="submit"
|
|
411
|
-
:loading="disable"
|
|
412
|
-
>
|
|
413
|
-
Submit
|
|
414
|
-
</v-btn>
|
|
415
|
-
</v-col>
|
|
416
|
-
</v-row>
|
|
417
|
-
</v-toolbar>
|
|
388
|
+
<v-card-actions class="screen-modal__footer">
|
|
389
|
+
<v-btn
|
|
390
|
+
variant="flat"
|
|
391
|
+
class="text-none screen-btn-ghost"
|
|
392
|
+
:disabled="disable"
|
|
393
|
+
@click="cancel"
|
|
394
|
+
>
|
|
395
|
+
Cancel
|
|
396
|
+
</v-btn>
|
|
397
|
+
<v-btn
|
|
398
|
+
variant="flat"
|
|
399
|
+
class="text-none screen-btn-primary"
|
|
400
|
+
:disabled="(uploadMode === 'single' ? !validForm : !bulkFile || !entryPassTemplate.id || templateLoading) || disable"
|
|
401
|
+
:loading="disable"
|
|
402
|
+
@click="submit"
|
|
403
|
+
>
|
|
404
|
+
Submit
|
|
405
|
+
</v-btn>
|
|
406
|
+
</v-card-actions>
|
|
418
407
|
</v-card>
|
|
419
408
|
</template>
|
|
420
409
|
<script setup lang="ts">
|
|
@@ -813,3 +802,14 @@ async function submit() {
|
|
|
813
802
|
}
|
|
814
803
|
}
|
|
815
804
|
</script>
|
|
805
|
+
|
|
806
|
+
<style scoped>
|
|
807
|
+
/*
|
|
808
|
+
* The template guide's header row. `bg-grey-lighten-4` was a fixed near-white,
|
|
809
|
+
* i.e. a bright band across a dark card; `--thead` is the design's own table
|
|
810
|
+
* head wash and is defined per theme.
|
|
811
|
+
*/
|
|
812
|
+
.template-guide-head {
|
|
813
|
+
background: var(--thead);
|
|
814
|
+
}
|
|
815
|
+
</style>
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-card width="100%">
|
|
3
|
-
<v-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
</v-row>
|
|
7
|
-
</v-toolbar>
|
|
8
|
-
<v-card-text style="max-height: 100vh; overflow-y: auto" class="pa-0">
|
|
2
|
+
<v-card width="100%" class="screen-modal">
|
|
3
|
+
<v-card-title>Assign Access Card to Unit</v-card-title>
|
|
4
|
+
|
|
5
|
+
<v-card-text class="screen-modal__body pa-0">
|
|
9
6
|
<v-form v-model="validForm" :disabled="loading">
|
|
10
7
|
<v-row no-gutters class="px-6 pt-4 pb-2">
|
|
11
8
|
<!-- Building -->
|
|
@@ -147,10 +144,10 @@
|
|
|
147
144
|
/>
|
|
148
145
|
<div class="text-caption mt-1">
|
|
149
146
|
<template v-if="availableLoading">
|
|
150
|
-
<span class="
|
|
147
|
+
<span class="screen-hint">Loading available count...</span>
|
|
151
148
|
</template>
|
|
152
149
|
<template v-else-if="availableCount !== null">
|
|
153
|
-
<span :class="availableCount === 0 ? 'text-error' : '
|
|
150
|
+
<span :class="availableCount === 0 ? 'text-error' : 'screen-hint'">
|
|
154
151
|
Available: {{ availableCount }}
|
|
155
152
|
</span>
|
|
156
153
|
</template>
|
|
@@ -160,29 +157,24 @@
|
|
|
160
157
|
</v-form>
|
|
161
158
|
</v-card-text>
|
|
162
159
|
|
|
163
|
-
<v-
|
|
160
|
+
<v-card-actions class="screen-modal__footer">
|
|
164
161
|
<v-row no-gutters>
|
|
165
|
-
<v-col cols="6">
|
|
162
|
+
<v-col cols="6" class="pr-2">
|
|
166
163
|
<v-btn
|
|
167
|
-
tile
|
|
168
164
|
block
|
|
169
|
-
variant="
|
|
170
|
-
class="text-none"
|
|
171
|
-
size="48"
|
|
165
|
+
variant="outlined"
|
|
166
|
+
class="text-none screen-btn-ghost"
|
|
172
167
|
@click="cancel"
|
|
173
168
|
:disabled="loading"
|
|
174
169
|
>
|
|
175
170
|
Cancel
|
|
176
171
|
</v-btn>
|
|
177
172
|
</v-col>
|
|
178
|
-
<v-col cols="6">
|
|
173
|
+
<v-col cols="6" class="pl-2">
|
|
179
174
|
<v-btn
|
|
180
|
-
tile
|
|
181
175
|
block
|
|
182
176
|
variant="flat"
|
|
183
|
-
|
|
184
|
-
class="text-none"
|
|
185
|
-
size="48"
|
|
177
|
+
class="text-none screen-btn-primary"
|
|
186
178
|
:disabled="!validForm || loading || availableCount === 0 || (availableCount !== null && form.quantity > availableCount)"
|
|
187
179
|
:loading="loading"
|
|
188
180
|
@click="submit"
|
|
@@ -191,7 +183,7 @@
|
|
|
191
183
|
</v-btn>
|
|
192
184
|
</v-col>
|
|
193
185
|
</v-row>
|
|
194
|
-
</v-
|
|
186
|
+
</v-card-actions>
|
|
195
187
|
</v-card>
|
|
196
188
|
</template>
|
|
197
189
|
<script setup lang="ts">
|
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
<!-- 520px is the handoff's `--modal-w`; the card wears `.screen-modal` for
|
|
3
|
+
the 16px corner, the `--card` surface and the modal shadow. The two
|
|
4
|
+
`v-toolbar`s it used for the title row and the footer were grey slabs
|
|
5
|
+
that stay grey on the dark theme - a `v-card-title` and the shared
|
|
6
|
+
`.screen-modal__footer` are the same rows on the card's own surface. -->
|
|
7
|
+
<v-dialog :model-value="modelValue" width="520" persistent>
|
|
8
|
+
<v-card class="screen-modal" width="100%">
|
|
9
|
+
<v-card-title>Delete Card</v-card-title>
|
|
7
10
|
|
|
8
|
-
<v-card-text>
|
|
9
|
-
<p class="text-
|
|
11
|
+
<v-card-text class="screen-modal__body">
|
|
12
|
+
<p class="text-center mb-4">
|
|
10
13
|
Are you sure you want to delete this card? This action cannot be
|
|
11
14
|
undone.
|
|
12
15
|
</p>
|
|
13
16
|
|
|
14
17
|
<v-form v-model="validForm" :disabled="loading">
|
|
15
18
|
<InputLabel class="text-capitalize font-weight-bold" title="Remarks" required />
|
|
19
|
+
<!-- Still a `v-textarea`, not an `AppField`: Delete Card is gated on
|
|
20
|
+
`validForm`, which only exists because this `:rules` runs.
|
|
21
|
+
`.filter-field` gives it the design's 10px corner and 13.5px
|
|
22
|
+
type without taking the validation away. -->
|
|
16
23
|
<v-textarea
|
|
17
24
|
v-model="remarks"
|
|
25
|
+
class="filter-field"
|
|
18
26
|
placeholder="Enter remarks..."
|
|
19
27
|
persistent-placeholder
|
|
20
28
|
rows="3"
|
|
@@ -29,38 +37,32 @@
|
|
|
29
37
|
</v-row>
|
|
30
38
|
</v-card-text>
|
|
31
39
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
>
|
|
59
|
-
Delete Card
|
|
60
|
-
</v-btn>
|
|
61
|
-
</v-col>
|
|
62
|
-
</v-row>
|
|
63
|
-
</v-toolbar>
|
|
40
|
+
<!-- The design's footer: two equal-width buttons, ghost then primary, on
|
|
41
|
+
a bordered strip. The confirming button was a hardcoded color="black"
|
|
42
|
+
fill - the same black on both themes. The handoff draws no
|
|
43
|
+
destructive button, so it takes the primary shape like every other
|
|
44
|
+
modal's confirm; the destructive-variant gap stays a design
|
|
45
|
+
decision. `loading` keeps it a v-btn: AppButton has no in-flight
|
|
46
|
+
state, and this is the only signal the delete is running. -->
|
|
47
|
+
<div class="screen-modal__footer">
|
|
48
|
+
<v-btn
|
|
49
|
+
variant="outlined"
|
|
50
|
+
class="screen-btn-ghost"
|
|
51
|
+
:disabled="loading"
|
|
52
|
+
@click="handleClose"
|
|
53
|
+
>
|
|
54
|
+
Close
|
|
55
|
+
</v-btn>
|
|
56
|
+
<v-btn
|
|
57
|
+
variant="flat"
|
|
58
|
+
class="screen-btn-primary"
|
|
59
|
+
:loading="loading"
|
|
60
|
+
:disabled="!validForm || loading"
|
|
61
|
+
@click="handleConfirm"
|
|
62
|
+
>
|
|
63
|
+
Delete Card
|
|
64
|
+
</v-btn>
|
|
65
|
+
</div>
|
|
64
66
|
</v-card>
|
|
65
67
|
</v-dialog>
|
|
66
68
|
</template>
|
|
@@ -1,117 +1,109 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-dialog :model-value="modelValue" width="480" persistent>
|
|
3
|
-
<v-card width="100%">
|
|
4
|
-
<
|
|
5
|
-
<v-
|
|
3
|
+
<v-card width="100%" class="screen-modal card-details">
|
|
4
|
+
<div class="card-details__head">
|
|
5
|
+
<v-card-title>
|
|
6
6
|
Card Details — {{ card?.cardNo ?? "N/A" }}
|
|
7
|
-
</v-
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
</v-toolbar>
|
|
7
|
+
</v-card-title>
|
|
8
|
+
<AppButton variant="icon" icon="mdi-close" aria-label="Close"
|
|
9
|
+
@click="emit('update:modelValue', false)" />
|
|
10
|
+
</div>
|
|
12
11
|
|
|
13
|
-
<
|
|
12
|
+
<div class="screen-modal__body card-details__body">
|
|
14
13
|
<div v-if="pending" class="d-flex justify-center align-center py-8">
|
|
15
|
-
<v-progress-circular indeterminate color="
|
|
14
|
+
<v-progress-circular indeterminate color="accent" />
|
|
16
15
|
</div>
|
|
17
16
|
|
|
18
|
-
<div v-else-if="!details" class="
|
|
17
|
+
<div v-else-if="!details" class="card-details__empty">
|
|
19
18
|
No details available.
|
|
20
19
|
</div>
|
|
21
20
|
|
|
22
21
|
<div v-else class="d-flex flex-column ga-3">
|
|
23
22
|
<div>
|
|
24
|
-
<div class="
|
|
25
|
-
<div class="
|
|
23
|
+
<div class="card-details__label">Card No</div>
|
|
24
|
+
<div class="card-details__value">{{ details.cardNo ?? "N/A" }}</div>
|
|
26
25
|
</div>
|
|
27
26
|
|
|
28
27
|
<div>
|
|
29
|
-
<div class="
|
|
30
|
-
<div class="
|
|
28
|
+
<div class="card-details__label">Type</div>
|
|
29
|
+
<div class="card-details__value">{{ details.type ?? "N/A" }}</div>
|
|
31
30
|
</div>
|
|
32
31
|
|
|
33
32
|
<div v-if="details.status">
|
|
34
|
-
<div class="
|
|
35
|
-
<
|
|
36
|
-
:color="statusColor(details.status)"
|
|
37
|
-
variant="flat"
|
|
38
|
-
size="x-small"
|
|
39
|
-
class="text-capitalize font-weight-medium mt-1"
|
|
40
|
-
>
|
|
41
|
-
{{ details.status ?? "N/A" }}
|
|
42
|
-
</v-chip>
|
|
33
|
+
<div class="card-details__label">Status</div>
|
|
34
|
+
<StatusChip class="mt-1 text-capitalize" :status="details.status" />
|
|
43
35
|
</div>
|
|
44
36
|
|
|
45
37
|
<div>
|
|
46
|
-
<div class="
|
|
47
|
-
<div class="
|
|
38
|
+
<div class="card-details__label">Activated</div>
|
|
39
|
+
<div class="card-details__value">{{ details.isActivated ? "Yes" : "No" }}</div>
|
|
48
40
|
</div>
|
|
49
41
|
|
|
50
42
|
<div v-if="details.site?.name">
|
|
51
|
-
<div class="
|
|
52
|
-
<div class="
|
|
43
|
+
<div class="card-details__label">Site</div>
|
|
44
|
+
<div class="card-details__value">{{ details.site?.name ?? "N/A" }}</div>
|
|
53
45
|
</div>
|
|
54
46
|
|
|
55
47
|
<div>
|
|
56
|
-
<div class="
|
|
57
|
-
<div class="
|
|
48
|
+
<div class="card-details__label">User</div>
|
|
49
|
+
<div class="card-details__value">
|
|
58
50
|
{{ details.userCred?.name ?? details.user?.name ?? "N/A" }}
|
|
59
51
|
<template v-if="details.user?.email">({{ details.user.email }})</template>
|
|
60
52
|
</div>
|
|
61
53
|
</div>
|
|
62
54
|
|
|
63
55
|
<div v-if="details.userType">
|
|
64
|
-
<div class="
|
|
65
|
-
<div class="
|
|
56
|
+
<div class="card-details__label">User Type</div>
|
|
57
|
+
<div class="card-details__value">{{ details.userType }}</div>
|
|
66
58
|
</div>
|
|
67
59
|
|
|
68
60
|
<!-- Visitor / Resident Credentials -->
|
|
69
61
|
<template v-if="details.userCred">
|
|
70
62
|
<v-divider />
|
|
71
|
-
<div class="
|
|
63
|
+
<div class="card-details__section">
|
|
72
64
|
{{ details.userType ?? "Visitor Information" }}
|
|
73
65
|
</div>
|
|
74
66
|
|
|
75
67
|
<div v-if="details.userCred.email">
|
|
76
|
-
<div class="
|
|
77
|
-
<div class="
|
|
68
|
+
<div class="card-details__label">Email</div>
|
|
69
|
+
<div class="card-details__value">{{ details.userCred.email }}</div>
|
|
78
70
|
</div>
|
|
79
71
|
|
|
80
72
|
<div v-if="details.userCred.nric">
|
|
81
|
-
<div class="
|
|
82
|
-
<div class="
|
|
73
|
+
<div class="card-details__label">NRIC</div>
|
|
74
|
+
<div class="card-details__value">{{ details.userCred.nric }}</div>
|
|
83
75
|
</div>
|
|
84
76
|
|
|
85
77
|
<div v-if="details.userCred.contact">
|
|
86
|
-
<div class="
|
|
87
|
-
<div class="
|
|
78
|
+
<div class="card-details__label">Contact</div>
|
|
79
|
+
<div class="card-details__value">{{ details.userCred.contact }}</div>
|
|
88
80
|
</div>
|
|
89
81
|
|
|
90
82
|
<div v-if="details.userCred.company">
|
|
91
|
-
<div class="
|
|
92
|
-
<div class="
|
|
83
|
+
<div class="card-details__label">Company</div>
|
|
84
|
+
<div class="card-details__value">{{ details.userCred.company }}</div>
|
|
93
85
|
</div>
|
|
94
86
|
|
|
95
87
|
<div v-if="details.userCred.plateNumber">
|
|
96
|
-
<div class="
|
|
97
|
-
<div class="
|
|
88
|
+
<div class="card-details__label">Plate Number</div>
|
|
89
|
+
<div class="card-details__value">{{ details.userCred.plateNumber }}</div>
|
|
98
90
|
</div>
|
|
99
91
|
<v-divider />
|
|
100
92
|
</template>
|
|
101
93
|
|
|
102
94
|
<div>
|
|
103
|
-
<div class="
|
|
104
|
-
<div class="
|
|
95
|
+
<div class="card-details__label">Created At</div>
|
|
96
|
+
<div class="card-details__value">{{ formatDate(details.createdAt) }}</div>
|
|
105
97
|
</div>
|
|
106
98
|
|
|
107
99
|
<div>
|
|
108
|
-
<div class="
|
|
109
|
-
<div class="
|
|
100
|
+
<div class="card-details__label">Updated At</div>
|
|
101
|
+
<div class="card-details__value">{{ formatDate(details.updatedAt) }}</div>
|
|
110
102
|
</div>
|
|
111
103
|
|
|
112
104
|
<div v-if="details.remarks">
|
|
113
|
-
<div class="
|
|
114
|
-
<div class="
|
|
105
|
+
<div class="card-details__label">Remarks</div>
|
|
106
|
+
<div class="card-details__value">{{ details.remarks }}</div>
|
|
115
107
|
</div>
|
|
116
108
|
|
|
117
109
|
<!-- History -->
|
|
@@ -121,7 +113,7 @@
|
|
|
121
113
|
class="d-flex align-center justify-space-between cursor-pointer"
|
|
122
114
|
@click="historyOpen = !historyOpen"
|
|
123
115
|
>
|
|
124
|
-
<div class="
|
|
116
|
+
<div class="card-details__section">
|
|
125
117
|
History ({{ details.history.length }})
|
|
126
118
|
</div>
|
|
127
119
|
<v-icon size="16" :icon="historyOpen ? 'mdi-chevron-up' : 'mdi-chevron-down'" />
|
|
@@ -137,37 +129,36 @@
|
|
|
137
129
|
<div class="d-flex flex-column align-center" style="width: 20px; flex-shrink: 0;">
|
|
138
130
|
<div
|
|
139
131
|
class="timeline-dot rounded-circle mt-1"
|
|
140
|
-
:class="(entry
|
|
132
|
+
:class="isAssignment(entry) ? 'timeline-dot--assigned' : 'timeline-dot--returned'"
|
|
141
133
|
/>
|
|
142
134
|
<div
|
|
143
135
|
v-if="idx < sortedHistory.length - 1"
|
|
144
|
-
class="timeline-line
|
|
136
|
+
class="timeline-line mt-1"
|
|
145
137
|
/>
|
|
146
138
|
</div>
|
|
147
139
|
|
|
148
140
|
<!-- Entry content -->
|
|
149
141
|
<div class="d-flex flex-column ga-1 pb-4 flex-grow-1">
|
|
150
142
|
<div class="d-flex align-center justify-space-between">
|
|
151
|
-
<
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
<span class="text-caption text-grey">{{ formatDate(entry.createdAt) }}</span>
|
|
143
|
+
<StatusChip :status="isAssignment(entry) ? 'Assigned' : 'Returned'">
|
|
144
|
+
<v-icon
|
|
145
|
+
size="13"
|
|
146
|
+
class="mr-1"
|
|
147
|
+
:icon="isAssignment(entry) ? 'mdi-account-arrow-right' : 'mdi-arrow-u-left-top'"
|
|
148
|
+
/>{{ isAssignment(entry) ? "Assigned" : "Returned" }}
|
|
149
|
+
</StatusChip>
|
|
150
|
+
<span class="card-details__label">{{ formatDate(entry.createdAt) }}</span>
|
|
160
151
|
</div>
|
|
161
152
|
|
|
162
153
|
<!-- Assignment entry -->
|
|
163
154
|
<template v-if="entry.type === 'assigned' || entry.visitorId">
|
|
164
|
-
<div class="
|
|
165
|
-
<div class="
|
|
155
|
+
<div class="card-details__value">{{ entry.name ?? "N/A" }}</div>
|
|
156
|
+
<div class="card-details__sub">
|
|
166
157
|
<span v-if="entry.nric">NRIC: {{ entry.nric }}</span>
|
|
167
158
|
<span v-if="entry.contact" class="ml-2">· {{ entry.contact }}</span>
|
|
168
159
|
<span v-if="entry.email && !entry.nric && !entry.contact">{{ entry.email }}</span>
|
|
169
160
|
</div>
|
|
170
|
-
<div class="
|
|
161
|
+
<div class="card-details__sub">
|
|
171
162
|
<span v-if="entry.company">{{ entry.company }}</span>
|
|
172
163
|
<span v-if="entry.plateNumber" class="ml-2">· {{ entry.plateNumber }}</span>
|
|
173
164
|
</div>
|
|
@@ -176,12 +167,10 @@
|
|
|
176
167
|
<!-- Return/checkout entry -->
|
|
177
168
|
<template v-else>
|
|
178
169
|
<div class="d-flex align-center ga-2">
|
|
179
|
-
<
|
|
180
|
-
|
|
181
|
-
</v-chip>
|
|
182
|
-
<span v-if="entry.damage" class="text-caption text-error">Damaged</span>
|
|
170
|
+
<StatusChip :status="entry.status" :label="entry.status ?? 'N/A'" />
|
|
171
|
+
<span v-if="entry.damage" class="card-details__damage">Damaged</span>
|
|
183
172
|
</div>
|
|
184
|
-
<div v-if="entry.remarks" class="
|
|
173
|
+
<div v-if="entry.remarks" class="card-details__sub">
|
|
185
174
|
Remarks: {{ entry.remarks }}
|
|
186
175
|
</div>
|
|
187
176
|
</template>
|
|
@@ -190,7 +179,7 @@
|
|
|
190
179
|
</template>
|
|
191
180
|
</template>
|
|
192
181
|
</div>
|
|
193
|
-
</
|
|
182
|
+
</div>
|
|
194
183
|
</v-card>
|
|
195
184
|
</v-dialog>
|
|
196
185
|
</template>
|
|
@@ -245,15 +234,12 @@ watch(
|
|
|
245
234
|
}
|
|
246
235
|
);
|
|
247
236
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
available: "grey",
|
|
255
|
-
};
|
|
256
|
-
return map[status] ?? "grey";
|
|
237
|
+
/**
|
|
238
|
+
* A history entry is an ASSIGNMENT if it says so or carries a visitor; the
|
|
239
|
+
* alternative is a return. Was written out three times inline.
|
|
240
|
+
*/
|
|
241
|
+
function isAssignment(entry: Record<string, any>) {
|
|
242
|
+
return entry.type === "assigned" || Boolean(entry.visitorId);
|
|
257
243
|
}
|
|
258
244
|
|
|
259
245
|
function formatDate(date: string) {
|
|
@@ -270,14 +256,74 @@ function formatDate(date: string) {
|
|
|
270
256
|
</script>
|
|
271
257
|
|
|
272
258
|
<style scoped>
|
|
259
|
+
.card-details__head {
|
|
260
|
+
display: flex;
|
|
261
|
+
align-items: center;
|
|
262
|
+
justify-content: space-between;
|
|
263
|
+
padding-right: 12px;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.card-details__body {
|
|
267
|
+
padding: 0 20px 20px;
|
|
268
|
+
max-height: 70vh;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.card-details__label {
|
|
272
|
+
font-size: var(--fs-breadcrumb);
|
|
273
|
+
color: var(--text2);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.card-details__value {
|
|
277
|
+
font-size: var(--fs-cell);
|
|
278
|
+
font-weight: var(--fw-cell);
|
|
279
|
+
color: var(--text);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.card-details__section {
|
|
283
|
+
font-size: var(--fs-section-label);
|
|
284
|
+
font-weight: var(--fw-section-label);
|
|
285
|
+
letter-spacing: var(--ls-section-label);
|
|
286
|
+
text-transform: uppercase;
|
|
287
|
+
color: var(--text2);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.card-details__sub {
|
|
291
|
+
font-size: var(--fs-breadcrumb);
|
|
292
|
+
color: var(--text2);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.card-details__empty {
|
|
296
|
+
padding: 32px 0;
|
|
297
|
+
text-align: center;
|
|
298
|
+
font-size: var(--fs-cell);
|
|
299
|
+
color: var(--muted);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.card-details__damage {
|
|
303
|
+
font-size: var(--fs-breadcrumb);
|
|
304
|
+
color: var(--err);
|
|
305
|
+
}
|
|
306
|
+
|
|
273
307
|
.timeline-dot {
|
|
274
308
|
width: 10px;
|
|
275
309
|
height: 10px;
|
|
276
310
|
flex-shrink: 0;
|
|
277
311
|
}
|
|
312
|
+
|
|
313
|
+
/* Were `bg-blue` / `bg-orange` / `bg-grey-lighten-2` - three fixed Vuetify hues
|
|
314
|
+
that do not follow the theme. Same meanings, as tokens. */
|
|
315
|
+
.timeline-dot--assigned {
|
|
316
|
+
background: var(--info);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.timeline-dot--returned {
|
|
320
|
+
background: var(--warn);
|
|
321
|
+
}
|
|
322
|
+
|
|
278
323
|
.timeline-line {
|
|
279
324
|
width: 2px;
|
|
280
325
|
flex-grow: 1;
|
|
281
326
|
min-height: 16px;
|
|
327
|
+
background: var(--border);
|
|
282
328
|
}
|
|
283
329
|
</style>
|