@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.
Files changed (283) hide show
  1. package/assets/css/primitives.css +1113 -0
  2. package/assets/css/screens.css +1097 -0
  3. package/assets/css/shell.css +258 -0
  4. package/assets/css/tokens.css +236 -0
  5. package/components/AcceptDialog.vue +17 -18
  6. package/components/AccessCard/AvailableStats.vue +24 -16
  7. package/components/AccessCardAddForm.vue +42 -42
  8. package/components/AccessCardAssignToUnitForm.vue +13 -21
  9. package/components/AccessCardDeleteDialog.vue +41 -39
  10. package/components/AccessCardDetailsDialog.vue +125 -79
  11. package/components/AccessCardPreviewDialog.vue +58 -84
  12. package/components/AccessCardQrTagging.vue +60 -63
  13. package/components/AccessCardReplaceForm.vue +27 -23
  14. package/components/AccessManagement.vue +86 -85
  15. package/components/AddEqupmentForm.vue +18 -22
  16. package/components/AddPassKeyToVisitor.vue +95 -73
  17. package/components/AppButton.vue +62 -0
  18. package/components/AppCard.vue +20 -0
  19. package/components/AppDateField.vue +49 -0
  20. package/components/AppField.vue +76 -0
  21. package/components/AppKpiTile.vue +65 -0
  22. package/components/AppSegmented.vue +38 -0
  23. package/components/AppSelect.vue +247 -0
  24. package/components/AreaChecklistHistoryLogs.vue +51 -44
  25. package/components/AreaChecklistHistoryMain.vue +14 -7
  26. package/components/AreaFormDialog.vue +71 -59
  27. package/components/AreaMain.vue +73 -107
  28. package/components/AttachmentsViewer.vue +84 -22
  29. package/components/AttendanceCheckInOutDialog.vue +85 -88
  30. package/components/AttendanceDetailsDialog.vue +57 -63
  31. package/components/AttendanceMain.vue +4 -3
  32. package/components/AttendanceMapSearchDialog.vue +42 -44
  33. package/components/AttendanceSettingsDialog.vue +79 -63
  34. package/components/Avatar/Main.vue +54 -2
  35. package/components/BillingMain.vue +26 -30
  36. package/components/BtnUploadFile.vue +53 -11
  37. package/components/BuildingForm.vue +34 -27
  38. package/components/BuildingManagement/buildings.vue +39 -39
  39. package/components/BuildingManagement/units.vue +26 -42
  40. package/components/BuildingUnitFormAdd.vue +20 -23
  41. package/components/BuildingUnitFormEdit.vue +8 -4
  42. package/components/BulletinBoardForm.vue +19 -24
  43. package/components/BulletinBoardManagement.vue +49 -57
  44. package/components/BulletinBoardView.vue +9 -6
  45. package/components/BulletinExpirationChip.vue +13 -4
  46. package/components/Button/Close.vue +2 -2
  47. package/components/CameraForm.vue +21 -22
  48. package/components/CameraMain.vue +50 -49
  49. package/components/Card/DeleteConfirmation.vue +24 -22
  50. package/components/Card/MemberInfoSummary.vue +28 -3
  51. package/components/Card/Toggle.vue +15 -3
  52. package/components/CardToolbar.vue +37 -0
  53. package/components/Carousel.vue +56 -36
  54. package/components/Chat/Bubbles.vue +43 -14
  55. package/components/Chat/Information.vue +49 -32
  56. package/components/Chat/ListCard.vue +38 -9
  57. package/components/Chat/Message.vue +41 -15
  58. package/components/Chat/Navigation.vue +27 -15
  59. package/components/Chat/SkeletonLoader.vue +9 -2
  60. package/components/ChecklistItemRow.vue +25 -1
  61. package/components/CleaningScheduleMain.vue +44 -49
  62. package/components/ClientDetailForm.vue +81 -56
  63. package/components/ClientMain.vue +92 -82
  64. package/components/ConfirmDialog.vue +14 -8
  65. package/components/Container/Standard.vue +9 -7
  66. package/components/CreateSubsciptionPlan.vue +148 -89
  67. package/components/DashboardEmptyState.vue +48 -3
  68. package/components/DashboardMain.vue +924 -676
  69. package/components/DashboardPanel.vue +84 -21
  70. package/components/DeliveryCompany.vue +34 -20
  71. package/components/Dialog/DeleteConfirmation.vue +20 -21
  72. package/components/Dialog/ReplaceAutofillPrompt.vue +19 -26
  73. package/components/Dialog/ReusablePrompt.vue +30 -29
  74. package/components/Dialog/UpdateMoreAction.vue +62 -59
  75. package/components/DocumentForm.vue +14 -21
  76. package/components/DocumentManagement.vue +162 -108
  77. package/components/DocumentViewer.vue +29 -12
  78. package/components/DrawImage.vue +29 -21
  79. package/components/EntryPass/QrTemplatePreview.vue +27 -16
  80. package/components/EntryPassInformation.vue +40 -10
  81. package/components/EntryPassMain.vue +49 -27
  82. package/components/EquipmentItemMain.vue +84 -97
  83. package/components/EquipmentManagementMain.vue +81 -103
  84. package/components/Facility/BookingSetup.vue +43 -52
  85. package/components/Feedback/Form.vue +26 -12
  86. package/components/FeedbackMain.vue +35 -49
  87. package/components/FileInput.vue +75 -58
  88. package/components/FileInputWithList.vue +59 -12
  89. package/components/FormDialog.vue +60 -21
  90. package/components/HidAccessLogDashboard.vue +512 -490
  91. package/components/HidCameraCaptureDialog.vue +216 -0
  92. package/components/HidEnabledGate.vue +67 -9
  93. package/components/HidIntercomManagement.vue +1322 -653
  94. package/components/HidQrCodeConfiguration.vue +1030 -258
  95. package/components/HidReaderForm.vue +142 -59
  96. package/components/HidReaderManagement.vue +211 -323
  97. package/components/HidServiceSettingsPanel.vue +44 -13
  98. package/components/HidUserEnrollment.vue +1185 -412
  99. package/components/HygieneUpdateMoreAction.vue +44 -44
  100. package/components/IncidentReport/Authorities.vue +30 -18
  101. package/components/IncidentReport/IncidentInformation.vue +10 -10
  102. package/components/IncidentReport/IncidentInformationDownload.vue +3 -4
  103. package/components/IncidentReport/affectedEntities.vue +41 -20
  104. package/components/Input/Date.vue +3 -0
  105. package/components/Input/DatePicker.vue +1 -2
  106. package/components/Input/DateTimePicker.vue +1 -1
  107. package/components/Input/File.vue +55 -10
  108. package/components/Input/FileV2.vue +39 -6
  109. package/components/Input/InputPhoneNumberV2.vue +2 -1
  110. package/components/Input/ListGroupSelection.vue +56 -8
  111. package/components/Input/NRICNumber.vue +1 -0
  112. package/components/Input/NewDate.vue +1 -0
  113. package/components/Input/Number.vue +1 -0
  114. package/components/Input/Password.vue +1 -0
  115. package/components/Input/PhoneNumber.vue +21 -1
  116. package/components/Input/VehicleNumber.vue +1 -0
  117. package/components/InputLabel.vue +2 -2
  118. package/components/InvitationClientForm.vue +21 -19
  119. package/components/InvitationForm.vue +15 -21
  120. package/components/InvitationMain.vue +46 -61
  121. package/components/Layout/Header.vue +263 -36
  122. package/components/Layout/NavigationDrawer.vue +300 -30
  123. package/components/ListItem.vue +33 -3
  124. package/components/LocalPagination.vue +27 -3
  125. package/components/ManageChecklistMain.vue +136 -86
  126. package/components/MemberInformation.vue +32 -16
  127. package/components/MemberMain.vue +113 -93
  128. package/components/MyAttendanceMain.vue +3 -5
  129. package/components/NavigationItem.vue +83 -3
  130. package/components/Nfc/NFCPatrolReportMain.vue +47 -33
  131. package/components/Nfc/NFCPatrolRouteForm.vue +18 -20
  132. package/components/Nfc/NFCPatrolRouteMain.vue +116 -103
  133. package/components/Nfc/NFCPatrolSettings.vue +14 -4
  134. package/components/Nfc/NFCTagForm.vue +22 -8
  135. package/components/Nfc/NFCTagMain.vue +41 -43
  136. package/components/Nfc/PatrolReport/DailyReportTab.vue +8 -1
  137. package/components/Nfc/PatrolReport/MonthlyReportTab.vue +8 -1
  138. package/components/Nfc/PatrolReport/MonthlyReportTable.vue +5 -3
  139. package/components/Nfc/PatrolReport/PatrolActivityTable.vue +26 -6
  140. package/components/Nfc/PatrolReport/PatrolReportTab.vue +8 -0
  141. package/components/Nfc/PatrolReport/PatrolRouteSummary.vue +41 -9
  142. package/components/Nfc/PatrolReport/RemarksDialog.vue +39 -9
  143. package/components/Nfc/PatrolReport/ReportEmptyState.vue +29 -9
  144. package/components/Nfc/PatrolReport/ReportFilters.vue +19 -10
  145. package/components/Nfc/PatrolReport/ReportLocationHeader.vue +32 -6
  146. package/components/Nfc/PatrolReport/SummaryReportTable.vue +28 -6
  147. package/components/NotificationSettings.vue +373 -0
  148. package/components/NumberSettingField.vue +9 -2
  149. package/components/OnlineFormConfigurationForm.vue +725 -237
  150. package/components/OnlineFormFill.vue +213 -106
  151. package/components/OnlineFormRenderPreview.vue +25 -30
  152. package/components/OnlineFormsConfiguration.vue +113 -109
  153. package/components/OrgViewDialog.vue +34 -16
  154. package/components/OvernightParkingAvailability.vue +49 -26
  155. package/components/OvernightParkingManagement.vue +78 -18
  156. package/components/PageHeader.vue +43 -0
  157. package/components/PassInformation.vue +109 -53
  158. package/components/PasswordConfirmation.vue +44 -26
  159. package/components/PeopleForm.vue +41 -20
  160. package/components/PhotoUpload.vue +110 -48
  161. package/components/PlaceholderComponent.vue +35 -19
  162. package/components/PlanActionsMenu.vue +12 -2
  163. package/components/PlanStatusBadge.vue +7 -8
  164. package/components/PlateNumberDisplay.vue +9 -6
  165. package/components/QrTemplate/PrintDialog.vue +66 -43
  166. package/components/RolePermissionFormCreate.vue +104 -79
  167. package/components/RolePermissionFormPreviewUpdate.vue +111 -109
  168. package/components/RolePermissionMain.vue +183 -81
  169. package/components/ScanVisitorQRCode.vue +99 -35
  170. package/components/ScheduleAreaMain.vue +34 -59
  171. package/components/ScheduleTaskForm.vue +61 -42
  172. package/components/ScheduleTaskMain.vue +56 -69
  173. package/components/SearchVehicleNumberUser.vue +39 -37
  174. package/components/ServiceProviderFormCreate.vue +29 -20
  175. package/components/ServiceProviderInvitationPrompt.vue +155 -0
  176. package/components/ServiceProviderMain.vue +601 -432
  177. package/components/Signature.vue +40 -34
  178. package/components/SignaturePad.vue +5 -29
  179. package/components/SiteSettings.vue +41 -11
  180. package/components/SiteSettingsWorkOrder.vue +61 -30
  181. package/components/SlideCardGroup.vue +35 -11
  182. package/components/Snackbar.vue +36 -3
  183. package/components/SpecificAttr.vue +18 -8
  184. package/components/StatusChip.vue +156 -0
  185. package/components/StockCard.vue +17 -12
  186. package/components/SubscriptionPlanTable.vue +207 -140
  187. package/components/SwitchContext.vue +201 -9
  188. package/components/TableHygiene.vue +36 -46
  189. package/components/TableList.vue +10 -10
  190. package/components/TableListSecondary.vue +105 -54
  191. package/components/TableMain.vue +251 -78
  192. package/components/TableV3.vue +61 -70
  193. package/components/TiptapEditor.vue +33 -40
  194. package/components/TiptapEditorQr.vue +5 -2
  195. package/components/Tooltip/Info.vue +69 -24
  196. package/components/UnitMain.vue +40 -60
  197. package/components/UnitPersonCard.vue +42 -13
  198. package/components/VehicleAddSelection.vue +48 -32
  199. package/components/VehicleForm.vue +112 -129
  200. package/components/VehicleManagement.vue +26 -12
  201. package/components/VehicleUpdateMoreAction.vue +59 -46
  202. package/components/VisitorDataFromScannedQRCodeForm.vue +90 -65
  203. package/components/VisitorForm.vue +774 -210
  204. package/components/VisitorFormSelection.vue +40 -37
  205. package/components/VisitorManagement.vue +239 -82
  206. package/components/VisitorPassKeyQRScanner.vue +65 -18
  207. package/components/VisitorSearchResultSummary.vue +60 -16
  208. package/components/VisitorSocketPopUp.vue +22 -14
  209. package/components/VisitorsReportPreview.vue +44 -29
  210. package/components/WorkOrder/Create.vue +26 -17
  211. package/components/WorkOrder/ListView.vue +38 -7
  212. package/components/WorkOrder/Main.vue +62 -59
  213. package/composables/useFeedback.ts +3 -3
  214. package/composables/useHidAmico.ts +269 -0
  215. package/composables/useHidNavigation.ts +2 -9
  216. package/composables/useMember.ts +3 -3
  217. package/composables/useNFCPatrolDailyReport.ts +13 -0
  218. package/composables/useNFCPatrolMonthlyReport.ts +22 -56
  219. package/composables/useNFCPatrolReport.ts +13 -0
  220. package/composables/useNotificationPreference.ts +87 -0
  221. package/composables/useOnlineFormPages.ts +2 -0
  222. package/composables/useRole.ts +22 -0
  223. package/composables/useServiceProvider.ts +3 -3
  224. package/composables/useServiceProviderInvitation.ts +145 -0
  225. package/composables/useSipWebPhone.ts +336 -0
  226. package/composables/useSubscriptionPlan.ts +62 -0
  227. package/composables/useThemePreference.ts +63 -0
  228. package/composables/useVisitor.ts +6 -1
  229. package/composables/useWebUsb.ts +127 -37
  230. package/composables/useWorkOrder.ts +17 -3
  231. package/error.vue +30 -6
  232. package/nuxt.config.ts +36 -0
  233. package/package.json +25 -4
  234. package/pages/[org]/[site]/access-mgmt/administrator/index.vue +2 -2
  235. package/pages/[org]/[site]/access-mgmt/{identity-mapping → hid-cards}/index.vue +2 -2
  236. package/pages/[org]/[site]/access-mgmt/intercom/index.vue +1 -1
  237. package/pages/notification-settings.vue +19 -0
  238. package/pages/payment-method-linked.vue +34 -10
  239. package/pages/require-customer.vue +48 -10
  240. package/pages/require-organization-membership.vue +32 -8
  241. package/pages/unauthorized.vue +29 -4
  242. package/plugins/secure-member.client.ts +21 -56
  243. package/plugins/vuetify.ts +69 -2
  244. package/types/nfc-patrol-report.ts +3 -2
  245. package/types/site.d.ts +71 -0
  246. package/types/subscription.ts +18 -11
  247. package/utils/breadcrumb.test.ts +108 -0
  248. package/utils/breadcrumb.ts +82 -0
  249. package/utils/dashboard.test.ts +118 -0
  250. package/utils/dashboard.ts +53 -0
  251. package/utils/data.test.ts +95 -0
  252. package/utils/data.ts +40 -2
  253. package/utils/hid-discover.test.ts +102 -0
  254. package/utils/list-page.test.ts +60 -0
  255. package/utils/list-page.ts +38 -0
  256. package/utils/materialSymbols.ts +363 -0
  257. package/utils/nav-sections.test.ts +190 -0
  258. package/utils/nav-sections.ts +151 -0
  259. package/utils/nfc-patrol-report.test.ts +130 -0
  260. package/utils/nfc-patrol-report.ts +101 -0
  261. package/utils/role.test.ts +69 -0
  262. package/utils/role.ts +10 -0
  263. package/utils/route-name.test.ts +85 -0
  264. package/utils/route-name.ts +24 -0
  265. package/utils/status.test.ts +110 -0
  266. package/utils/status.ts +135 -0
  267. package/utils/table-card.test.ts +84 -0
  268. package/utils/theme-aa-ledger.ts +148 -0
  269. package/utils/theme.test.ts +485 -7
  270. package/utils/theme.ts +295 -110
  271. package/.changeset/README.md +0 -8
  272. package/.changeset/config.json +0 -11
  273. package/.editorconfig +0 -12
  274. package/.github/workflows/main.yml +0 -17
  275. package/.github/workflows/publish-staging.yml +0 -47
  276. package/.github/workflows/publish.yml +0 -39
  277. package/PUBLISHING.md +0 -269
  278. package/components/HidIdentityMapping.vue +0 -975
  279. package/components/ScheduleTaskAreaFormDialog.vue +0 -144
  280. package/components/ScheduleTaskAreaUpdateMoreAction.vue +0 -109
  281. package/components/ScheduleTastTicketMain.vue +0 -182
  282. package/components/TableWithButton.vue +0 -94
  283. package/test/visitor-socket.test.mjs +0 -36
@@ -1,77 +1,60 @@
1
1
  <template>
2
2
  <v-row no-gutters class="pa-0">
3
3
  <v-col cols="12" class="mb-2">
4
- <v-row no-gutters align="center">
5
- <v-col cols="12" md="6" class="d-flex align-center">
6
- <v-btn
7
- class="text-none me-2"
8
- rounded="pill"
9
- variant="tonal"
10
- size="large"
11
- @click="setDocument()"
4
+ <PageHeader title="Documents">
5
+ <template #actions>
6
+ <AppButton
7
+ v-if="canCreate && canCreateFolder"
8
+ variant="ghost"
9
+ icon="mdi-folder-plus-outline"
10
+ @click="openCreateFolderDialog()"
11
+ >
12
+ Create Folder
13
+ </AppButton>
14
+
15
+ <AppButton
12
16
  v-if="canCreate && canCreateDocument"
17
+ icon="mdi-plus"
18
+ @click="setDocument()"
13
19
  >
14
20
  Add Document
15
- </v-btn>
21
+ </AppButton>
22
+ </template>
23
+ </PageHeader>
24
+
25
+ <div class="doc-filters">
26
+ <AppField
27
+ v-model="search"
28
+ search
29
+ icon="mdi-magnify"
30
+ placeholder="Search"
31
+ klass="doc-filters__search"
32
+ />
16
33
 
17
- <v-btn
18
- class="text-none"
19
- rounded="pill"
20
- variant="tonal"
21
- size="large"
22
- @click="openCreateFolderDialog()"
23
- v-if="canCreate && canCreateFolder"
24
- >
25
- Create Folder
26
- </v-btn>
27
- </v-col>
28
-
29
- <v-col
30
- cols="12"
31
- md="6"
32
- class="d-flex justify-end align-center mt-4 mt-md-0"
33
- >
34
- <v-text-field
35
- v-model="search"
36
- placeholder="Search"
37
- density="comfortable"
38
- variant="outlined"
39
- hide-details
40
- rounded="lg"
41
- class="me-3"
42
- style="max-width: 220px"
43
- />
44
-
45
- <v-menu v-model="filterMenu" offset-y>
46
- <template #activator="{ props }">
47
- <v-btn
48
- v-bind="props"
49
- variant="outlined"
50
- rounded="lg"
51
- class="filtertype-btn text-none"
52
- style="max-width: 220px"
53
- >
54
- {{ selectedFileType || "Filter by File Type" }}
55
- </v-btn>
56
- </template>
34
+ <v-menu v-model="filterMenu" offset-y>
35
+ <template #activator="{ props }">
36
+ <button v-bind="props" type="button" class="doc-filters__type">
37
+ <span>{{ selectedFileType || "Filter by File Type" }}</span>
38
+ <v-icon size="18">mdi-chevron-down</v-icon>
39
+ </button>
40
+ </template>
57
41
 
58
- <v-card class="filtertype-card">
59
- <v-list class="pa-0">
60
- <v-list-item
61
- v-for="(type, idx) in fileTypes"
62
- :key="idx"
63
- @click="selectFileType(type)"
64
- class="filtertype-item"
65
- >
66
- <v-list-item-title class="text-subtitle-2">
67
- {{ type }}
68
- </v-list-item-title>
69
- </v-list-item>
70
- </v-list>
71
- </v-card>
72
- </v-menu>
73
- </v-col>
74
- </v-row>
42
+ <v-card class="filtertype-card">
43
+ <v-list class="pa-0">
44
+ <v-list-item
45
+ v-for="(type, idx) in fileTypes"
46
+ :key="idx"
47
+ @click="selectFileType(type)"
48
+ class="filtertype-item"
49
+ >
50
+ <v-list-item-title class="text-subtitle-2">
51
+ {{ type }}
52
+ </v-list-item-title>
53
+ </v-list-item>
54
+ </v-list>
55
+ </v-card>
56
+ </v-menu>
57
+ </div>
75
58
  </v-col>
76
59
 
77
60
  <v-col cols="12" class="mb-2" v-if="isInsideFolder">
@@ -82,7 +65,7 @@
82
65
  variant="text"
83
66
  @click="goBackFolder"
84
67
  />
85
- <v-icon size="18" color="grey-darken-2">mdi-folder</v-icon>
68
+ <v-icon size="18" style="color: var(--muted)">mdi-folder</v-icon>
86
69
  <span class="text-body-2 font-weight-medium">{{
87
70
  currentFolderPath
88
71
  }}</span>
@@ -102,6 +85,15 @@
102
85
  @update:page="page = $event"
103
86
  @row-click="tableRowClickHandler"
104
87
  >
88
+ <!--
89
+ A failed request is not an empty folder. Without this the table drew
90
+ its neutral "No data available" for a 500, which reads as "there are
91
+ no documents here" - a statement the server never made.
92
+ -->
93
+ <template v-if="getDocumentError" #no-data>
94
+ <DashboardEmptyState error />
95
+ </template>
96
+
105
97
  <template v-if="isInsideFolder" #breadcrumb>
106
98
  <div class="d-flex align-center flex-wrap ga-1">
107
99
  <v-btn
@@ -114,18 +106,18 @@
114
106
  />
115
107
 
116
108
  <span
117
- class="breadcrumb-segment text-body-2 text-grey-darken-1 cursor-pointer"
109
+ class="breadcrumb-segment text-body-2 breadcrumb-segment--link cursor-pointer"
118
110
  @click="navigateToRoot"
119
111
  >Home</span
120
112
  >
121
113
  <template v-for="(folder, idx) in folderStack" :key="folder.id">
122
- <v-icon size="14" color="grey-darken-1">mdi-chevron-right</v-icon>
114
+ <v-icon size="14" style="color: var(--muted)">mdi-chevron-right</v-icon>
123
115
  <span
124
116
  :class="[
125
117
  'breadcrumb-segment text-body-2 font-weight-medium',
126
118
  idx === folderStack.length - 1
127
- ? 'text-black'
128
- : 'text-grey-darken-1 cursor-pointer',
119
+ ? 'breadcrumb-segment--current'
120
+ : 'breadcrumb-segment--link cursor-pointer',
129
121
  ]"
130
122
  @click="
131
123
  idx < folderStack.length - 1 && navigateToStackIndex(idx)
@@ -140,7 +132,7 @@
140
132
  <v-icon
141
133
  size="18"
142
134
  :color="
143
- isFolderItem(item._raw) ? 'amber-darken-2' : 'grey-darken-2'
135
+ isFolderItem(item._raw) ? 'warning' : 'muted'
144
136
  "
145
137
  >
146
138
  {{
@@ -221,7 +213,7 @@
221
213
  <!-- Create Folder Dialog -->
222
214
  <v-dialog v-model="createFolderDialog" width="450" persistent>
223
215
  <v-card width="100%">
224
- <v-toolbar class="pa-0" density="compact">
216
+ <v-toolbar class="pa-0 screen-dialog-bar" density="compact">
225
217
  <v-row no-gutters class="w-100">
226
218
  <v-col cols="12" class="pa-4">
227
219
  <span class="font-weight-medium text-h6">Create Folder</span>
@@ -251,7 +243,7 @@
251
243
  </v-form>
252
244
  </v-card-text>
253
245
 
254
- <v-toolbar class="pa-0" density="compact">
246
+ <v-toolbar class="pa-0 screen-dialog-bar" density="compact">
255
247
  <v-row no-gutters class="w-100">
256
248
  <v-col cols="6" class="pa-0">
257
249
  <v-btn
@@ -288,7 +280,7 @@
288
280
  <!-- Edit Folder Dialog -->
289
281
  <v-dialog v-model="editFolderDialog" width="450" persistent>
290
282
  <v-card width="100%" class="folder-dialog-card">
291
- <v-toolbar class="pa-0 folder-dialog-toolbar" density="compact">
283
+ <v-toolbar class="pa-0 folder-dialog-toolbar screen-dialog-bar" density="compact">
292
284
  <v-row no-gutters class="w-100">
293
285
  <v-col cols="12" class="pa-4">
294
286
  <span class="font-weight-medium text-h6">Edit Folder</span>
@@ -323,7 +315,7 @@
323
315
  </v-form>
324
316
  </v-card-text>
325
317
 
326
- <v-toolbar class="pa-0" density="compact">
318
+ <v-toolbar class="pa-0 screen-dialog-bar" density="compact">
327
319
  <v-row no-gutters class="w-100">
328
320
  <v-col cols="6" class="pa-0">
329
321
  <v-btn
@@ -360,7 +352,7 @@
360
352
  <!-- Delete Folder Dialog -->
361
353
  <v-dialog v-model="deleteFolderDialog" width="450" persistent>
362
354
  <v-card width="100%" class="folder-dialog-card">
363
- <v-toolbar density="compact" class="pl-4 folder-dialog-toolbar">
355
+ <v-toolbar density="compact" class="pl-4 folder-dialog-toolbar screen-dialog-bar">
364
356
  <span class="font-weight-medium text-h6">Delete Folder</span>
365
357
  </v-toolbar>
366
358
 
@@ -374,7 +366,7 @@
374
366
  </p>
375
367
  </v-card-text>
376
368
 
377
- <v-toolbar density="compact" class="pa-0">
369
+ <v-toolbar density="compact" class="pa-0 screen-dialog-bar">
378
370
  <v-row no-gutters class="w-100">
379
371
  <v-col cols="6" class="pa-0">
380
372
  <v-btn
@@ -502,7 +494,7 @@
502
494
  </v-col>
503
495
  </v-row>
504
496
  </v-card-text>
505
- <v-toolbar class="pa-0" density="compact">
497
+ <v-toolbar class="pa-0 screen-dialog-bar" density="compact">
506
498
  <v-row no-gutters>
507
499
  <v-col cols="6" class="pa-0">
508
500
  <v-btn
@@ -566,7 +558,7 @@
566
558
  persistent
567
559
  >
568
560
  <v-card width="100%">
569
- <v-toolbar density="compact" class="pl-4">
561
+ <v-toolbar density="compact" class="pl-4 screen-dialog-bar">
570
562
  <span class="font-weight-medium text-h5">Delete Document</span>
571
563
  </v-toolbar>
572
564
  <v-card-text>
@@ -576,7 +568,7 @@
576
568
  </p>
577
569
  </v-card-text>
578
570
 
579
- <v-toolbar density="compact">
571
+ <v-toolbar class="screen-dialog-bar" density="compact">
580
572
  <v-row no-gutters>
581
573
  <v-col cols="6">
582
574
  <v-btn
@@ -614,6 +606,10 @@
614
606
  </v-row>
615
607
  </template>
616
608
  <script setup lang="ts">
609
+ // Relative import, never Nuxt auto-import: this layer's `utils/` are auto-imported
610
+ // into the consuming apps but not reliably into the layer's own components.
611
+ import { readListPage } from "../utils/list-page";
612
+
617
613
  definePageMeta({
618
614
  middleware: ["01-auth", "02-org"],
619
615
  memberOnly: true,
@@ -753,6 +749,7 @@ const {
753
749
  data: getDocumentReq,
754
750
  refresh: getDocuments,
755
751
  status: getAllReqStatus,
752
+ error: getDocumentError,
756
753
  } = useLazyAsyncData(
757
754
  "get-all-documents",
758
755
  () =>
@@ -771,12 +768,16 @@ const {
771
768
 
772
769
  const loading = computed(() => getAllReqStatus.value === "pending");
773
770
 
771
+ // The page totals are the server's count of the WHOLE list, read through the
772
+ // one helper that knows how a paginated reply is shaped - never re-derived
773
+ // from the rows on this page. Applied unconditionally so that when a request
774
+ // fails the reply goes null and the header falls back to the placeholder,
775
+ // instead of leaving the previous page's total on screen as if it still held.
774
776
  watchEffect(() => {
775
- if (getDocumentReq.value) {
776
- items.value = getDocumentReq.value.items;
777
- pages.value = getDocumentReq.value.pages;
778
- pageRange.value = getDocumentReq.value.pageRange;
779
- }
777
+ const listPage = readListPage<Record<string, any>>(getDocumentReq.value);
778
+ items.value = listPage.items;
779
+ pages.value = listPage.pages;
780
+ pageRange.value = listPage.pageRange;
780
781
  });
781
782
 
782
783
  function formatDate(value?: string | null) {
@@ -1197,36 +1198,87 @@ function selectFileType(type: string) {
1197
1198
  </script>
1198
1199
 
1199
1200
  <style scoped>
1201
+ /*
1202
+ * EVERY COLOUR IN THIS BLOCK WAS A LITERAL. `#fff` menus, `#fafafa` bars,
1203
+ * `#e0e0e0` rules and `#38475a` ink do not follow the theme, so in dark mode
1204
+ * this screen drew white slabs on the dark page. All of them are tokens now;
1205
+ * nothing about the layout, the flow or the actions changed.
1206
+ */
1207
+
1208
+ /* The breadcrumb was `text-grey-darken-1` and `text-black` - the same two
1209
+ greys on the dark page, i.e. black lettering on a dark card. */
1210
+ .breadcrumb-segment--link {
1211
+ color: var(--muted);
1212
+ }
1213
+
1214
+ .breadcrumb-segment--current {
1215
+ color: var(--text);
1216
+ }
1217
+
1200
1218
  .table-download-btn {
1201
1219
  min-width: 106px;
1202
1220
  height: 30px;
1203
- border-radius: 4px;
1204
- background-color: #e3e3e3;
1205
- color: #38475a;
1221
+ border-radius: var(--r-tag);
1222
+ background-color: var(--hover);
1223
+ color: var(--text2);
1206
1224
  font-size: 12px;
1207
- font-weight: 500;
1225
+ font-weight: 600;
1208
1226
  box-shadow: none;
1209
1227
  }
1210
1228
 
1211
1229
  .table-download-btn:hover {
1212
- background-color: #d8d8d8;
1230
+ background-color: var(--thead);
1231
+ }
1232
+
1233
+ /* The filter row under the title: the design puts search and filters on one
1234
+ line, right-aligned, rather than in a second full-width toolbar. */
1235
+ .doc-filters {
1236
+ display: flex;
1237
+ align-items: center;
1238
+ justify-content: flex-end;
1239
+ flex-wrap: wrap;
1240
+ gap: 8px;
1241
+ margin-top: 12px;
1213
1242
  }
1214
1243
 
1215
- .filtertype-btn {
1216
- justify-content: flex-start;
1244
+ .doc-filters :deep(.doc-filters__search) {
1245
+ flex: 0 0 auto;
1217
1246
  width: 220px;
1247
+ min-width: 0;
1248
+ }
1249
+
1250
+ .doc-filters__type {
1251
+ display: flex;
1252
+ align-items: center;
1253
+ justify-content: space-between;
1254
+ gap: 8px;
1255
+ width: 220px;
1256
+ height: 38px;
1257
+ padding: 0 12px;
1258
+ border: 1px solid var(--border);
1259
+ border-radius: var(--r-inner);
1260
+ background: var(--card);
1261
+ color: var(--text);
1262
+ font-size: 13px;
1263
+ font-weight: 600;
1264
+ text-align: left;
1265
+ }
1266
+
1267
+ .doc-filters__type:hover {
1268
+ background: var(--hover);
1218
1269
  }
1219
1270
 
1220
1271
  .filtertype-card {
1221
- background: #fff;
1222
- border-radius: 8px;
1272
+ background: var(--card);
1273
+ border: 1px solid var(--border);
1274
+ border-radius: var(--r-inner);
1223
1275
  min-width: 160px;
1224
- box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
1276
+ box-shadow: var(--shadow-menu);
1225
1277
  overflow: hidden;
1226
1278
  }
1227
1279
 
1228
1280
  .filtertype-item {
1229
- border-bottom: 1px solid #f0f0f0;
1281
+ border-bottom: 1px solid var(--border);
1230
1282
  padding: 10px 16px;
1231
1283
  }
1232
1284
 
@@ -1235,27 +1287,29 @@ function selectFileType(type: string) {
1235
1287
  }
1236
1288
 
1237
1289
  .folder-path-bar {
1238
- border: 1px solid #e0e0e0;
1239
- border-radius: 8px;
1240
- background: #fafafa;
1290
+ border: 1px solid var(--border);
1291
+ border-radius: var(--r-inner);
1292
+ background: var(--thead);
1293
+ color: var(--text);
1241
1294
  }
1242
1295
 
1243
1296
  .folder-action-btn {
1244
- color: #38475a;
1297
+ color: var(--text2);
1245
1298
  }
1246
1299
 
1247
1300
  .folder-action-list {
1248
1301
  min-width: 180px;
1249
- border-radius: 8px;
1250
- background: #fff;
1251
- box-shadow: 0 10px 28px rgba(15, 23, 42, 0.22);
1302
+ border-radius: var(--r-inner);
1303
+ background: var(--card);
1304
+ border: 1px solid var(--border);
1305
+ box-shadow: var(--shadow-menu);
1252
1306
  overflow: hidden;
1253
1307
  }
1254
1308
 
1255
1309
  .folder-action-item {
1256
1310
  min-height: 40px;
1257
- border-bottom: 1px solid #eef0f2;
1258
- color: #38475a;
1311
+ border-bottom: 1px solid var(--border);
1312
+ color: var(--text2);
1259
1313
  }
1260
1314
 
1261
1315
  .folder-action-item:last-child {
@@ -1263,11 +1317,11 @@ function selectFileType(type: string) {
1263
1317
  }
1264
1318
 
1265
1319
  .folder-dialog-card {
1266
- border-radius: 6px;
1320
+ border-radius: var(--r-inner);
1267
1321
  overflow: hidden;
1268
1322
  }
1269
1323
 
1270
1324
  .folder-dialog-toolbar {
1271
- border-bottom: 1px solid #eef0f2;
1325
+ border-bottom: 1px solid var(--border);
1272
1326
  }
1273
1327
  </style>
@@ -1,14 +1,24 @@
1
1
  <template>
2
2
  <v-dialog :model-value="modelValue" :max-width="fileType === 'image' ? '1200' : '900'" scrollable
3
3
  @update:model-value="emit('update:modelValue', $event)">
4
- <v-card>
5
- <v-toolbar density="compact">
6
- <v-toolbar-title class="text-subtitle-2 text-truncate">{{ fileName }}</v-toolbar-title>
7
- <v-spacer />
8
- <v-btn icon="mdi-open-in-new" variant="text" size="small" @click="openInNewTab()" />
9
- <v-btn icon="mdi-close" variant="text" size="small" @click="emit('update:modelValue', false)" />
10
- </v-toolbar>
11
- <v-card-text class="pa-0"
4
+ <!-- The card wears `.screen-modal` for the 16px corner, the `--card`
5
+ surface and the modal shadow. The `v-toolbar` header was a fixed
6
+ grey slab that stays grey on the dark theme; the design's modal
7
+ header is a title and its controls on the card's own surface over
8
+ a 1px `--border` rule, which is what this now draws. -->
9
+ <v-card class="screen-modal">
10
+ <v-card-title class="d-flex align-center ga-1 doc-viewer__head">
11
+ <span class="flex-grow-1 text-truncate">{{ fileName }}</span>
12
+ <!-- `.screen-modal__close` is the handoff's modal control:
13
+ 32x32, 8px radius, borderless, `--muted` ink. The handoff
14
+ draws only a close in that row; a second control beside it
15
+ is a case it is silent on, so it takes the same shape. -->
16
+ <v-btn icon="mdi-open-in-new" variant="text" size="small" class="screen-modal__close"
17
+ @click="openInNewTab()" />
18
+ <v-btn icon="mdi-close" variant="text" size="small" class="screen-modal__close"
19
+ @click="emit('update:modelValue', false)" />
20
+ </v-card-title>
21
+ <v-card-text class="screen-modal__body pa-0"
12
22
  :style="{ height: fileType === 'image' ? 'auto' : '75vh', 'overflow-y': fileType === 'image' ? 'auto' : 'auto' }">
13
23
  <!-- Image Viewer -->
14
24
  <v-img v-if="fileType === 'image'" :src="getFileUrl(fileId)" :alt="fileName" class="w-100" />
@@ -24,13 +34,12 @@
24
34
  <iframe v-else :src="getFileUrl(fileId)" width="100%" height="100%" style="border: none;"
25
35
  :title="fileName" />
26
36
  </v-card-text>
27
- <v-card-actions>
28
- <v-spacer />
29
- <v-btn variant="text" class="text-none" @click="openInNewTab()">
37
+ <div class="screen-modal__footer">
38
+ <v-btn variant="outlined" class="screen-btn-ghost" @click="openInNewTab()">
30
39
  <v-icon start>mdi-download</v-icon>
31
40
  Open / Download
32
41
  </v-btn>
33
- </v-card-actions>
42
+ </div>
34
43
  </v-card>
35
44
  </v-dialog>
36
45
  </template>
@@ -73,3 +82,11 @@ function openInNewTab() {
73
82
  window.open(getFileUrl(props.fileId), '_blank', 'noopener,noreferrer');
74
83
  }
75
84
  </script>
85
+
86
+ <style scoped>
87
+ /* The handoff's modal header sits over a 1px --border rule, the same rule the
88
+ footer strip sits under. */
89
+ .doc-viewer__head {
90
+ border-bottom: 1px solid var(--border);
91
+ }
92
+ </style>
@@ -4,32 +4,25 @@
4
4
  transition="dialog-top-transition"
5
5
  max-width="1000"
6
6
  >
7
- <v-card class="pa-1">
8
- <v-toolbar>
9
- <v-spacer></v-spacer>
10
- <v-btn icon="mdi-close" @click="emit('onCloseDialog')" />
11
- </v-toolbar>
12
- <canvas id="imageCanvas" />
13
- <v-card-title class="text-end">
7
+ <v-card class="screen-modal">
8
+ <div class="draw-image__head">
14
9
  <v-btn
15
- color="orange-darken-3"
16
- size="small"
17
- variant="flat"
18
- style="height: 40px; margin-right: 12px"
19
- @click="onClearDrawing()"
20
- >
10
+ class="screen-modal__close"
11
+ variant="text"
12
+ icon="mdi-close"
13
+ aria-label="Close"
14
+ @click="emit('onCloseDialog')"
15
+ />
16
+ </div>
17
+ <canvas id="imageCanvas" />
18
+ <div class="screen-modal__footer">
19
+ <v-btn class="screen-btn-ghost" variant="outlined" @click="onClearDrawing()">
21
20
  Clear Drawing
22
21
  </v-btn>
23
- <v-btn
24
- color="blue-darken-3"
25
- size="small"
26
- variant="flat"
27
- style="height: 40px"
28
- @click="submit"
29
- >
22
+ <v-btn class="screen-btn-primary" variant="flat" @click="submit">
30
23
  Submit
31
24
  </v-btn>
32
- </v-card-title>
25
+ </div>
33
26
  </v-card>
34
27
  </v-dialog>
35
28
  </template>
@@ -170,3 +163,18 @@ async function onClearDrawing() {
170
163
  ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
171
164
  }
172
165
  </script>
166
+
167
+ <style scoped>
168
+ /* The design's modal has a title row; this dialog has never had a title, only
169
+ a close - so the row keeps that and just moves the close onto the design's
170
+ borderless 32px square. No copy invented. */
171
+ .draw-image__head {
172
+ display: flex;
173
+ justify-content: flex-end;
174
+ padding: 12px 12px 0;
175
+ }
176
+
177
+ /* The canvas itself is untouched: its width/height are computed in script from
178
+ its own bounding box, so a layout rule here would quietly move the drawing
179
+ coordinates - a behaviour change no render can prove. */
180
+ </style>
@@ -6,24 +6,28 @@
6
6
  persistent
7
7
  @update:model-value="emit('update:modelValue', $event)"
8
8
  >
9
- <v-card>
10
- <v-toolbar
11
- style="height: 12px"
12
- :color="isDark ? 'grey-darken-4' : 'white'"
13
- >
14
- <v-spacer></v-spacer>
9
+ <v-card class="screen-modal">
10
+ <!-- Was a 12px-tall `v-toolbar` themed by hand (`white` / `grey-darken-4`)
11
+ carrying a `grey-darken-1` icon button. The design's modal close is a
12
+ borderless 32px square on `--muted`, so the whole bar goes and the
13
+ close sits on the card's own surface. -->
14
+ <div class="d-flex justify-end pa-2">
15
15
  <v-btn
16
- color="grey-darken-1"
16
+ variant="text"
17
17
  icon="mdi-close"
18
+ class="screen-modal__close"
19
+ aria-label="Close preview"
18
20
  @click="emit('update:modelValue', false)"
19
21
  ></v-btn>
20
- </v-toolbar>
22
+ </div>
21
23
 
22
- <v-card-text style="padding: 0 !important">
24
+ <v-card-text class="screen-modal__body pa-0">
23
25
  <v-container>
24
26
  <v-row no-gutters class="text-center">
25
27
  <v-col cols="12">
26
- <p class="font-weight-bold text-h5 mb-3">{{ header }}</p>
28
+ <!-- `text-h5` is Vuetify's 24px/400 Roboto scale. The design's
29
+ modal title token is `--fs-card-title` / `--fw-card-title`. -->
30
+ <p class="qr-preview__title mb-3">{{ header }}</p>
27
31
  <p>{{ subText }}</p>
28
32
  </v-col>
29
33
 
@@ -53,8 +57,8 @@
53
57
  </v-col>
54
58
 
55
59
  <v-col cols="12" class="mt-5">
56
- <p class="font-weight-bold text-h5 mb-2">Company Name</p>
57
- <p class="font-weight-bold text-h5 mb-3">BL 01/03/24</p>
60
+ <p class="qr-preview__title mb-2">Company Name</p>
61
+ <p class="qr-preview__title mb-3">BL 01/03/24</p>
58
62
  <p class="mb-1">{{ `Date: ${dateStr} ${timeStr}` }}</p>
59
63
  <p class="mb-1">Access: Door</p>
60
64
  <p>Scan and press level 1. One time use.</p>
@@ -67,7 +71,6 @@
67
71
  </template>
68
72
 
69
73
  <script lang="ts" setup>
70
- import { useTheme } from "vuetify";
71
74
  import QRCode from "qrcode";
72
75
 
73
76
  defineProps({
@@ -87,9 +90,6 @@ defineProps({
87
90
 
88
91
  const emit = defineEmits(["update:modelValue"]);
89
92
 
90
- const { global: themeGlobal } = useTheme();
91
- const isDark = computed(() => themeGlobal.current.value.dark);
92
-
93
93
  const qrSmall = ref<string>("");
94
94
  const qrLarge = ref<string>("");
95
95
 
@@ -102,3 +102,14 @@ const now = new Date();
102
102
  const dateStr = now.toLocaleDateString();
103
103
  const timeStr = now.toLocaleTimeString();
104
104
  </script>
105
+
106
+ <style scoped>
107
+ /* The pass body is a printed artefact, so its own sizes stay. Only the two
108
+ heading lines move off Vuetify's Roboto display scale onto the design's
109
+ modal-title token. */
110
+ .qr-preview__title {
111
+ font-size: var(--fs-card-title);
112
+ font-weight: var(--fw-card-title);
113
+ color: var(--text);
114
+ }
115
+ </style>