@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,32 +1,32 @@
1
1
  <template>
2
- <v-card width="100%">
3
- <!-- Title bar -->
4
- <v-toolbar color="grey-darken-3" style="min-height: 56px">
5
- <v-row no-gutters class="fill-height px-6" align="center">
6
- <span
7
- class="font-weight-bold text-subtitle-1 text-white text-uppercase"
8
- style="letter-spacing: 0.5px; line-height: 1.3"
9
- >
10
- {{ definition.title }}
11
- </span>
12
- <v-spacer v-if="$slots['title-actions']" />
13
- <slot name="title-actions" />
14
- </v-row>
15
- </v-toolbar>
16
-
17
- <!-- Submission metadata bar (readonly only) -->
2
+ <v-card class="screen-modal" width="100%">
3
+ <!-- The title row was a `grey-darken-3` v-toolbar with white uppercase
4
+ text: the same hardcoded dark slab on both themes. A `v-card-title` on
5
+ `.screen-modal` is the same row on the card's own surface, so it
6
+ follows the theme - and the actions slot keeps its place on the right. -->
7
+ <v-card-title class="d-flex align-center ga-2">
8
+ <span class="flex-grow-1">{{ definition.title }}</span>
9
+ <slot name="title-actions" />
10
+ </v-card-title>
11
+
12
+ <!-- Submission metadata bar (readonly only). Shown for an actual
13
+ submission (submissionStatus) OR a pure template preview that
14
+ requires payment — a preview has no submission yet, but should
15
+ still tell the admin the form carries a fee. -->
18
16
  <div
19
- v-if="readonly && (submissionStatus)"
20
- class="px-6 py-2 d-flex align-center ga-4"
21
- style="background: #f5f5f5; border-bottom: 1px solid #e0e0e0; flex-wrap: wrap"
17
+ v-if="readonly && (submissionStatus || requiresPayment)"
18
+ class="online-form-fill__meta px-6 py-2 d-flex align-center ga-4"
22
19
  >
23
- <v-chip
20
+ <!-- `StatusChip` IS the design's status pill: it maps the WORD to a tone
21
+ through the shared `utils/status.ts`, so "Pending" is the same amber
22
+ here as on a work order, and it carries `--tone-bg` with the ink so
23
+ both halves of the measured pair arrive together. The `v-chip` it
24
+ replaces painted a flat fixed-palette fill under a white label. -->
25
+ <StatusChip
24
26
  v-if="submissionStatus"
25
- :color="submissionStatusColor"
26
- variant="flat"
27
- size="x-small"
27
+ :status="submissionStatus"
28
28
  class="text-capitalize"
29
- >{{ submissionStatus }}</v-chip>
29
+ />
30
30
  <span v-if="(initialValues as any).block" class="text-caption text-medium-emphasis">
31
31
  Block: <strong>{{ (initialValues as any).block }}</strong>
32
32
  </span>
@@ -37,18 +37,21 @@
37
37
  Unit: <strong>{{ submissionUnit }}</strong>
38
38
  </span>
39
39
  <template v-if="requiresPayment">
40
- <v-chip
41
- v-if="initialManagementValues?.paymentStatus"
42
- color="green"
43
- variant="flat"
44
- size="x-small"
45
- >Payment {{ initialManagementValues.paymentStatus }}</v-chip>
46
- <v-chip
47
- v-else
48
- color="orange"
49
- variant="flat"
50
- size="x-small"
51
- >Payment Not Paid</v-chip>
40
+ <!-- The payment pair is not a status WORD the shared map knows, so the
41
+ tone is given directly - the same pill, the same measured pair.
42
+ A preview has no submission to be paid/unpaid yet, so it shows
43
+ the configured fee instead of a status that doesn't apply. -->
44
+ <StatusChip
45
+ v-if="!submissionStatus"
46
+ tone="info"
47
+ :label="`Requires Payment: $${paymentAmount}`"
48
+ />
49
+ <StatusChip
50
+ v-else-if="initialManagementValues?.paymentStatus"
51
+ tone="ok"
52
+ :label="`Payment ${initialManagementValues.paymentStatus}`"
53
+ />
54
+ <StatusChip v-else tone="warn" label="Payment Not Paid" />
52
55
  <span
53
56
  v-if="initialManagementValues?.paymentOrderId"
54
57
  class="text-caption text-medium-emphasis"
@@ -58,17 +61,21 @@
58
61
 
59
62
  <!-- Scrollable body -->
60
63
  <v-card-text
61
- style="max-height: 76vh; overflow-y: auto"
62
- class="pa-6"
64
+ style="max-height: 76vh"
65
+ class="screen-modal__body pa-6"
63
66
  >
64
- <v-form v-model="validForm">
67
+ <!-- `.filter-field` is a DESCENDANT selector (`.filter-field .v-field`),
68
+ so one class on the form gives every input below it the design's
69
+ 40px/10px/13.5px geometry. Every `:rules` below is untouched, and no
70
+ field becomes an `AppField` - AppField carries no rules, and Submit
71
+ is gated on `validForm`, which only exists because these rules run. -->
72
+ <v-form v-model="validForm" class="filter-field">
65
73
  <template v-for="(block, i) in displayBlocks" :key="i">
66
74
 
67
75
  <!-- ADDRESS BLOCK -->
68
76
  <div
69
77
  v-if="block.type === 'address'"
70
- class="mb-4 pa-3"
71
- style="background: #f5f5f5; border-radius: 6px"
78
+ class="online-form-fill__panel mb-4 pa-3"
72
79
  >
73
80
  <v-row no-gutters>
74
81
  <v-col cols="5">
@@ -91,7 +98,11 @@
91
98
  :key="field.key"
92
99
  :cols="field.cols || 6"
93
100
  >
94
- <InputLabel :title="field.label" />
101
+ <!-- `required` was never passed, so the design system's own
102
+ asterisk never drew: a field the form REFUSES to submit
103
+ without looked identical to an optional one. The rule below
104
+ is keyed on the same `field.required`. -->
105
+ <InputLabel :title="field.label" :required="!readonly && !!field.required" />
95
106
  <v-text-field
96
107
  v-if="field.fieldType === 'text'"
97
108
  v-model="values[field.key]"
@@ -137,7 +148,7 @@
137
148
 
138
149
  <!-- SINGLE FULL-WIDTH FIELD -->
139
150
  <div v-else-if="block.type === 'field'" class="mb-0">
140
- <InputLabel :title="block.field.label" />
151
+ <InputLabel :title="block.field.label" :required="!readonly && !!block.field.required" />
141
152
  <v-text-field
142
153
  v-if="block.field.fieldType === 'text'"
143
154
  v-model="values[block.field.key]"
@@ -233,20 +244,50 @@
233
244
  </div>
234
245
 
235
246
  <!-- PARAGRAPH (terms / info text) -->
247
+ <!-- `color: #333` was a near-black on a dark card: the terms text was
248
+ invisible on the dark theme (measured 1.32:1). `--text` is the
249
+ design's own ink and `--border` the design's own rule. -->
236
250
  <p
237
251
  v-else-if="block.type === 'paragraph'"
238
- class="text-body-2 mb-3"
239
- style="
240
- line-height: 1.65;
241
- color: #333;
242
- text-align: justify;
243
- border-left: 3px solid #ddd;
244
- padding-left: 10px;
245
- "
252
+ class="online-form-fill__para text-body-2 mb-3"
246
253
  >
247
254
  {{ resolveText(block.text) }}
248
255
  </p>
249
256
 
257
+ <!-- ORDERED LIST -->
258
+ <div v-else-if="block.type === 'ordered-list'" class="mb-3">
259
+ <div
260
+ v-if="block.title"
261
+ class="text-body-2 font-weight-bold mb-1"
262
+ style="text-decoration: underline; text-underline-offset: 3px"
263
+ >{{ block.title }}</div>
264
+ <ol style="padding-left: 22px; margin: 0">
265
+ <li
266
+ v-for="(item, itemIdx) in block.items"
267
+ :key="itemIdx"
268
+ class="text-body-2 mb-1"
269
+ style="line-height: 1.55; color: var(--text)"
270
+ >{{ item }}</li>
271
+ </ol>
272
+ </div>
273
+
274
+ <!-- UNORDERED LIST -->
275
+ <div v-else-if="block.type === 'unordered-list'" class="mb-3">
276
+ <div
277
+ v-if="block.title"
278
+ class="text-body-2 font-weight-bold mb-1"
279
+ style="text-decoration: underline; text-underline-offset: 3px"
280
+ >{{ block.title }}</div>
281
+ <ul style="padding-left: 22px; margin: 0">
282
+ <li
283
+ v-for="(item, itemIdx) in block.items"
284
+ :key="itemIdx"
285
+ class="text-body-2 mb-1"
286
+ style="line-height: 1.55; color: var(--text)"
287
+ >{{ item }}</li>
288
+ </ul>
289
+ </div>
290
+
250
291
  <!-- DIVIDER -->
251
292
  <v-divider v-else-if="block.type === 'divider'" class="my-4" />
252
293
 
@@ -265,6 +306,12 @@
265
306
  class="mt-3 mb-5"
266
307
  >
267
308
  <span class="text-caption text-medium-emphasis d-block mb-1">{{ block.label }}</span>
309
+ <!-- DELIBERATELY NOT TOKENISED. `detectSigBackground` reads the
310
+ saved PNG and decides whether its ink is black or white; this
311
+ plate has to match THAT ink, not the current theme. A white
312
+ signature on a `--card` plate is invisible on the light theme,
313
+ and a black one on the dark theme - which is the whole reason
314
+ the detection exists. -->
268
315
  <div
269
316
  v-if="initialValues[block.key]"
270
317
  :style="{
@@ -283,15 +330,14 @@
283
330
  </div>
284
331
  <div
285
332
  v-else
286
- style="border-bottom: 1px dashed #bbb; height: 56px; background: #fafafa; border-radius: 4px"
333
+ class="online-form-fill__sig-blank"
287
334
  />
288
335
  </div>
289
336
 
290
337
  <!-- ACKNOWLEDGEMENT -->
291
338
  <div
292
339
  v-else-if="block.type === 'acknowledgement'"
293
- class="mb-4 pa-3"
294
- style="background: #f9f9f9; border-radius: 6px; border: 1px solid #eee"
340
+ class="online-form-fill__panel online-form-fill__panel--bordered mb-4 pa-3"
295
341
  >
296
342
  <span class="text-body-2 font-weight-medium">{{ resolveText(block.text) }}</span>
297
343
  </div>
@@ -299,10 +345,10 @@
299
345
  <!-- MANAGEMENT USE -->
300
346
  <div
301
347
  v-else-if="block.type === 'management-use'"
302
- class="pa-4 mt-2"
303
- :style="approvalMode && selectedAction === 'approved'
304
- ? 'background: #e8f5e9; border-radius: 6px; border: 1px solid #a5d6a7'
305
- : 'background: #f0f0f0; border-radius: 6px; opacity: 0.75'"
348
+ class="online-form-fill__panel pa-4 mt-2"
349
+ :class="approvalMode && selectedAction === 'approved'
350
+ ? 'online-form-fill__panel--ok'
351
+ : 'online-form-fill__panel--dim'"
306
352
  >
307
353
  <v-row no-gutters class="mb-2">
308
354
  <span class="text-caption font-weight-bold text-medium-emphasis">
@@ -326,7 +372,7 @@
326
372
  />
327
373
  <div
328
374
  v-else
329
- style="border-bottom: 1px solid #aaa; min-width: 120px; height: 22px; font-size: 13px; padding-top: 2px"
375
+ class="online-form-fill__mgmt-line"
330
376
  >{{ managementValues[item] || '' }}</div>
331
377
  </div>
332
378
  </v-row>
@@ -344,7 +390,7 @@
344
390
  <!-- Approval action panel -->
345
391
  <div
346
392
  v-if="readonly && approvalMode"
347
- style="border-top: 1px solid #e0e0e0; padding: 12px 16px; background: #fafafa; display: flex; flex-direction: column; gap: 10px"
393
+ class="online-form-fill__approve"
348
394
  >
349
395
  <v-text-field
350
396
  v-model="adminRemarks"
@@ -355,35 +401,35 @@
355
401
  :error="remarksRequired && adminRemarks.trim().length === 0"
356
402
  :error-messages="remarksRequired && adminRemarks.trim().length === 0 ? 'Remarks are required' : ''"
357
403
  />
358
- <div class="d-flex align-center ga-2 justify-end">
359
- <v-btn variant="text" class="text-none" size="small" @click="emit('cancel')">Close</v-btn>
404
+ <!-- The three verdicts keep their colour coding - it is what tells them
405
+ apart - but on the theme's own status colours rather than fixed
406
+ palette entries, so both the tonal and the flat state follow the
407
+ theme. Confirm was a hardcoded `grey-darken-3` fill and is now the
408
+ design's primary button, which is what it is. -->
409
+ <div class="d-flex align-center ga-2 justify-end flex-wrap">
410
+ <v-btn variant="outlined" class="screen-btn-ghost" @click="emit('cancel')">Close</v-btn>
360
411
  <v-btn
361
412
  :variant="selectedAction === 'resubmission' ? 'flat' : 'tonal'"
362
- color="orange-darken-1"
413
+ color="warning"
363
414
  class="text-none"
364
- size="small"
365
415
  @click="selectAction('resubmission')"
366
416
  >Resubmit</v-btn>
367
417
  <v-btn
368
418
  :variant="selectedAction === 'rejected' ? 'flat' : 'tonal'"
369
- color="red"
419
+ color="error"
370
420
  class="text-none"
371
- size="small"
372
421
  @click="selectAction('rejected')"
373
422
  >Reject</v-btn>
374
423
  <v-btn
375
424
  :variant="selectedAction === 'approved' ? 'flat' : 'tonal'"
376
- color="green"
425
+ color="success"
377
426
  class="text-none"
378
- size="small"
379
427
  @click="selectAction('approved')"
380
428
  >Approve</v-btn>
381
429
  <v-btn
382
430
  v-if="selectedAction"
383
431
  variant="flat"
384
- color="grey-darken-3"
385
- class="text-none"
386
- size="small"
432
+ class="screen-btn-primary"
387
433
  :disabled="!canConfirm"
388
434
  :loading="updatingStatus"
389
435
  @click="confirmStatusUpdate"
@@ -391,24 +437,25 @@
391
437
  </div>
392
438
  </div>
393
439
 
394
- <!-- Normal action bar -->
395
- <v-toolbar v-else density="compact">
396
- <v-row no-gutters>
397
- <template v-if="readonly">
398
- <v-col cols="12">
399
- <v-btn tile block variant="text" class="text-none" size="48" @click="emit('cancel')">Close</v-btn>
400
- </v-col>
401
- </template>
402
- <template v-else>
403
- <v-col cols="6">
404
- <v-btn tile block variant="text" class="text-none" size="48" :disabled="submitting" @click="emit('cancel')">Cancel</v-btn>
405
- </v-col>
406
- <v-col cols="6">
407
- <v-btn tile block variant="flat" color="black" class="text-none" size="48" :disabled="!validForm || submitting" :loading="submitting" @click="submit">Submit</v-btn>
408
- </v-col>
409
- </template>
410
- </v-row>
411
- </v-toolbar>
440
+ <!-- The design's footer: equal-width buttons, ghost then primary, on a
441
+ bordered strip. Submit was a hardcoded `color="black"` block fill. Its
442
+ `:disabled="!validForm || submitting"` is untouched - the gate is still
443
+ the form's own validity. -->
444
+ <div v-else class="screen-modal__footer">
445
+ <template v-if="readonly">
446
+ <v-btn variant="outlined" class="screen-btn-ghost" @click="emit('cancel')">Close</v-btn>
447
+ </template>
448
+ <template v-else>
449
+ <v-btn variant="outlined" class="screen-btn-ghost" :disabled="submitting" @click="emit('cancel')">Cancel</v-btn>
450
+ <v-btn
451
+ variant="flat"
452
+ class="screen-btn-primary"
453
+ :disabled="!validForm || submitting"
454
+ :loading="submitting"
455
+ @click="submit"
456
+ >Submit</v-btn>
457
+ </template>
458
+ </div>
412
459
  </v-card>
413
460
  </template>
414
461
  <script setup lang="ts">
@@ -433,6 +480,7 @@ const props = defineProps({
433
480
  approvalMode: { type: Boolean, default: false },
434
481
  initialManagementValues: { type: Object as PropType<Record<string, string>>, default: () => ({}) },
435
482
  formType: { type: String, default: "" },
483
+ paymentAmount: { type: Number, default: 0 },
436
484
  /** Optional custom submit handler. Receives the collected form values.
437
485
  * If omitted the component submits to /api/online-forms automatically. */
438
486
  submitFn: {
@@ -586,25 +634,13 @@ function confirmStatusUpdate() {
586
634
 
587
635
  const requiredRule = (v: any) => (v !== null && v !== undefined && v !== "") || "This field is required";
588
636
 
589
- const submissionStatusColor = computed(() => {
590
- switch (props.submissionStatus?.toLowerCase()) {
591
- case "approved": return "green";
592
- case "pending": return "orange";
593
- case "resubmission": return "orange";
594
- case "rejected": return "red";
595
- default: return "grey";
596
- }
597
- });
598
-
599
- const PAYMENT_REQUIRED_FORM_TYPES = new Set([
600
- "Application for Electronic Access Card",
601
- "Application for Booking of BBQ Pit",
602
- "Application for Moving In/Out & Delivery",
603
- "Application for Main Entrance RFID Transponder",
604
- ]);
637
+ // The local status -> colour switch this file carried is gone: `StatusChip`
638
+ // maps the word through the shared `utils/status.ts`, which already had
639
+ // approved/pending/rejected and now has resubmission too. One mapping, not a
640
+ // second private copy that could drift from it.
605
641
 
606
642
  const requiresPayment = computed(() => {
607
- if (!PAYMENT_REQUIRED_FORM_TYPES.has(props.formType)) return false;
643
+ if (props.paymentAmount <= 0) return false;
608
644
  if (props.formType === "Application for Main Entrance RFID Transponder") {
609
645
  return !!(props.initialValues.reasonLost || props.initialValues.reasonDamaged);
610
646
  }
@@ -743,3 +779,74 @@ async function submit() {
743
779
  }
744
780
  }
745
781
  </script>
782
+
783
+ <style scoped>
784
+ /*
785
+ * Every surface below was a hardcoded near-white hex - `#f5f5f5`, `#f9f9f9`,
786
+ * `#f0f0f0`, `#fafafa` - with THEMED text on top of it. On the dark theme that
787
+ * put the design's near-white ink on a near-white plate: the address strip read
788
+ * 1.05:1, the acknowledgement 1.08:1 and the management panel 1:1, i.e. text
789
+ * that was there and could not be seen. `--bg` is the design's own recessed
790
+ * surface and follows the theme, so the same rows read correctly on both.
791
+ */
792
+ .online-form-fill__meta {
793
+ flex-wrap: wrap;
794
+ background: var(--bg);
795
+ border-bottom: 1px solid var(--border);
796
+ }
797
+
798
+ .online-form-fill__panel {
799
+ background: var(--bg);
800
+ border-radius: var(--r-inner);
801
+ }
802
+
803
+ .online-form-fill__panel--bordered {
804
+ border: 1px solid var(--border);
805
+ }
806
+
807
+ /* The approved state of the management panel. `--ok-bg` / `--ok` are the
808
+ design's own success pair; it was `#e8f5e9` on `#a5d6a7`, the same greens on
809
+ both themes. */
810
+ .online-form-fill__panel--ok {
811
+ background: var(--ok-bg);
812
+ border: 1px solid var(--ok);
813
+ }
814
+
815
+ .online-form-fill__panel--dim {
816
+ opacity: 0.75;
817
+ }
818
+
819
+ .online-form-fill__para {
820
+ line-height: 1.65;
821
+ color: var(--text);
822
+ text-align: justify;
823
+ border-left: 3px solid var(--border);
824
+ padding-left: 10px;
825
+ }
826
+
827
+ /* The ruled line a management entry is written on, and the empty signature
828
+ plate - both were fixed greys. */
829
+ .online-form-fill__mgmt-line {
830
+ border-bottom: 1px solid var(--border);
831
+ min-width: 120px;
832
+ height: 22px;
833
+ font-size: var(--fs-cell);
834
+ padding-top: 2px;
835
+ }
836
+
837
+ .online-form-fill__sig-blank {
838
+ border-bottom: 1px dashed var(--border);
839
+ height: 56px;
840
+ background: var(--bg);
841
+ border-radius: var(--r-inner-sm);
842
+ }
843
+
844
+ .online-form-fill__approve {
845
+ display: flex;
846
+ flex-direction: column;
847
+ gap: 10px;
848
+ padding: 12px 16px;
849
+ background: var(--bg);
850
+ border-top: 1px solid var(--border);
851
+ }
852
+ </style>
@@ -5,25 +5,25 @@
5
5
  width="560"
6
6
  persistent
7
7
  >
8
- <v-card max-height="85vh" class="d-flex flex-column">
9
- <v-toolbar color="grey-darken-3" class="flex-grow-0">
10
- <v-toolbar-title class="text-subtitle-1 font-weight-bold text-white text-uppercase">
11
- {{ form?.formType }}
12
- </v-toolbar-title>
13
- </v-toolbar>
8
+ <!-- The title row was a `grey-darken-3` v-toolbar: the same hardcoded grey
9
+ slab on both themes, with white text sitting on it. A `v-card-title` on
10
+ `.screen-modal` is the same row on the card's own surface, so it
11
+ follows the theme. -->
12
+ <v-card class="screen-modal d-flex flex-column">
13
+ <v-card-title class="flex-grow-0">{{ form?.formType }}</v-card-title>
14
14
 
15
- <v-card-subtitle class="px-6 pt-3 pb-0 text-caption text-medium-emphasis flex-grow-0">
15
+ <v-card-subtitle class="screen-hint px-6 pb-0 flex-grow-0">
16
16
  Form preview — fields are read-only
17
17
  </v-card-subtitle>
18
18
 
19
- <v-card-text class="px-6 py-4 flex-grow-1" style="overflow-y: auto">
19
+ <v-card-text class="screen-modal__body px-6 py-4 flex-grow-1">
20
20
  <template v-for="(input, index) in form?.inputs" :key="index">
21
21
  <v-text-field
22
22
  v-if="input.dataType === 'Text Input'"
23
23
  :label="input.label"
24
24
  density="comfortable"
25
25
  variant="outlined"
26
- class="mb-1"
26
+ class="filter-field mb-1"
27
27
  :hint="input.required ? 'Required' : ''"
28
28
  persistent-hint
29
29
  readonly
@@ -34,7 +34,7 @@
34
34
  density="comfortable"
35
35
  variant="outlined"
36
36
  rows="3"
37
- class="mb-1"
37
+ class="filter-field mb-1"
38
38
  :hint="input.required ? 'Required' : ''"
39
39
  persistent-hint
40
40
  readonly
@@ -45,7 +45,7 @@
45
45
  type="date"
46
46
  density="comfortable"
47
47
  variant="outlined"
48
- class="mb-1"
48
+ class="filter-field mb-1"
49
49
  :hint="input.required ? 'Required' : ''"
50
50
  persistent-hint
51
51
  readonly
@@ -56,7 +56,7 @@
56
56
  :items="input.options || []"
57
57
  density="comfortable"
58
58
  variant="outlined"
59
- class="mb-1"
59
+ class="filter-field mb-1"
60
60
  :hint="input.required ? 'Required' : ''"
61
61
  persistent-hint
62
62
  readonly
@@ -65,29 +65,24 @@
65
65
  v-else-if="input.dataType === 'Checkbox'"
66
66
  :label="input.label"
67
67
  density="comfortable"
68
- class="mb-1"
68
+ class="filter-field mb-1"
69
69
  readonly
70
70
  />
71
71
  </template>
72
72
  </v-card-text>
73
73
 
74
- <v-toolbar density="compact" class="flex-grow-0">
75
- <v-row no-gutters>
76
- <v-col cols="12">
77
- <v-btn
78
- tile
79
- block
80
- variant="flat"
81
- color="black"
82
- class="text-none"
83
- height="48"
84
- @click="$emit('update:modelValue', false)"
85
- >
86
- Close Preview
87
- </v-btn>
88
- </v-col>
89
- </v-row>
90
- </v-toolbar>
74
+ <!-- The design's modal footer. The Close button was a `color="black"`
75
+ square-cornered block fill - the same black on both themes, and the
76
+ shape of a primary action for what is only a dismiss. -->
77
+ <div class="screen-modal__footer flex-grow-0">
78
+ <v-btn
79
+ variant="outlined"
80
+ class="screen-btn-ghost"
81
+ @click="$emit('update:modelValue', false)"
82
+ >
83
+ Close Preview
84
+ </v-btn>
85
+ </div>
91
86
  </v-card>
92
87
  </v-dialog>
93
88
  </template>