@7365admin1/layer-common 1.8.0

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 (198) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +11 -0
  3. package/.editorconfig +12 -0
  4. package/.github/workflows/main.yml +17 -0
  5. package/.github/workflows/publish.yml +39 -0
  6. package/.nuxtrc +1 -0
  7. package/.playground/app.vue +41 -0
  8. package/.playground/eslint.config.mjs +6 -0
  9. package/.playground/nuxt.config.ts +22 -0
  10. package/.playground/pages/feedback.vue +30 -0
  11. package/CHANGELOG.md +263 -0
  12. package/README.md +73 -0
  13. package/app.vue +3 -0
  14. package/components/AccessCardAddForm.vue +363 -0
  15. package/components/AccessManagement.vue +420 -0
  16. package/components/Avatar/Main.vue +68 -0
  17. package/components/BillingMain.vue +66 -0
  18. package/components/BtnUploadFile.vue +139 -0
  19. package/components/BuildingForm.vue +303 -0
  20. package/components/BuildingManagement/buildings.vue +335 -0
  21. package/components/BuildingManagement/units.vue +350 -0
  22. package/components/BuildingUnitFormAdd.vue +441 -0
  23. package/components/BuildingUnitFormEdit.vue +429 -0
  24. package/components/CameraForm.vue +264 -0
  25. package/components/CameraMain.vue +352 -0
  26. package/components/Card/DeleteConfirmation.vue +51 -0
  27. package/components/Card/MemberInfoSummary.vue +44 -0
  28. package/components/Card/Toggle.vue +25 -0
  29. package/components/Chat/Bubbles.vue +53 -0
  30. package/components/Chat/Information.vue +416 -0
  31. package/components/Chat/ListCard.vue +62 -0
  32. package/components/Chat/Message.vue +158 -0
  33. package/components/Chat/Navigation.vue +150 -0
  34. package/components/ConfirmDialog.vue +66 -0
  35. package/components/Container/Standard.vue +33 -0
  36. package/components/DashboardPlaceholder.vue +1524 -0
  37. package/components/Dialog/DeleteConfirmation.vue +51 -0
  38. package/components/Dialog/ReplaceAutofillPrompt.vue +49 -0
  39. package/components/Dialog/UpdateMoreAction.vue +103 -0
  40. package/components/DocumentForm.vue +187 -0
  41. package/components/DocumentManagement.vue +376 -0
  42. package/components/Editor.vue +95 -0
  43. package/components/EntryPassMain.vue +518 -0
  44. package/components/Feedback/Form.vue +173 -0
  45. package/components/FeedbackDetail.vue +599 -0
  46. package/components/FeedbackMain.vue +588 -0
  47. package/components/FormDialog.vue +65 -0
  48. package/components/ImageCarousel.vue +138 -0
  49. package/components/Input/Date.vue +177 -0
  50. package/components/Input/DateTimePicker.vue +131 -0
  51. package/components/Input/File.vue +236 -0
  52. package/components/Input/FileV2.vue +234 -0
  53. package/components/Input/InputPhoneNumberV2.vue +164 -0
  54. package/components/Input/ListGroupSelection.vue +96 -0
  55. package/components/Input/NRICNumber.vue +53 -0
  56. package/components/Input/NewDate.vue +123 -0
  57. package/components/Input/Number.vue +124 -0
  58. package/components/Input/Password.vue +22 -0
  59. package/components/Input/PhoneNumber.vue +188 -0
  60. package/components/Input/VehicleNumber.vue +49 -0
  61. package/components/InputLabel.vue +22 -0
  62. package/components/InvitationForm.vue +359 -0
  63. package/components/InvitationMain.vue +310 -0
  64. package/components/Layout/Header.vue +129 -0
  65. package/components/Layout/NavigationDrawer.vue +44 -0
  66. package/components/ListItem.vue +35 -0
  67. package/components/ListView.vue +87 -0
  68. package/components/LocalPagination.vue +31 -0
  69. package/components/MemberMain.vue +459 -0
  70. package/components/NFC/NFCPatrolReportMain.vue +591 -0
  71. package/components/NFC/NFCPatrolRouteForm.vue +596 -0
  72. package/components/NFC/NFCPatrolRouteMain.vue +539 -0
  73. package/components/NFC/NFCTagForm.vue +236 -0
  74. package/components/NFC/NFCTagMain.vue +337 -0
  75. package/components/NFC/PatrolSettings.vue +130 -0
  76. package/components/NavigationItem.vue +83 -0
  77. package/components/NumberSettingField.vue +107 -0
  78. package/components/OnlineFormConfigurationForm.vue +290 -0
  79. package/components/OnlineFormsConfiguration.vue +429 -0
  80. package/components/PeopleForm.vue +452 -0
  81. package/components/PlaceholderComponent.vue +34 -0
  82. package/components/RolePermissionFormCreate.vue +161 -0
  83. package/components/RolePermissionFormPreviewUpdate.vue +183 -0
  84. package/components/RolePermissionMain.vue +361 -0
  85. package/components/SearchVehicleNumberUser.vue +91 -0
  86. package/components/ServiceProviderFormCreate.vue +154 -0
  87. package/components/ServiceProviderMain.vue +547 -0
  88. package/components/SignaturePad.vue +73 -0
  89. package/components/Snackbar.vue +23 -0
  90. package/components/SpecificAttr.vue +53 -0
  91. package/components/SupplyManagement.vue +292 -0
  92. package/components/SwitchContext.vue +108 -0
  93. package/components/TableList.vue +150 -0
  94. package/components/TableListSecondary.vue +164 -0
  95. package/components/TableMain.vue +142 -0
  96. package/components/TableWithButton.vue +94 -0
  97. package/components/VehicleUpdateMoreAction.vue +84 -0
  98. package/components/VideoPlayer.vue +125 -0
  99. package/components/VisitorForm.vue +659 -0
  100. package/components/VisitorFormSelection.vue +53 -0
  101. package/components/VisitorManagement.vue +490 -0
  102. package/components/WorkOrder/Create.vue +284 -0
  103. package/components/WorkOrder/Detail.vue +71 -0
  104. package/components/WorkOrder/ListView.vue +96 -0
  105. package/components/WorkOrder/Main.vue +489 -0
  106. package/components/Workorder.vue +1 -0
  107. package/composables/useAddress.ts +107 -0
  108. package/composables/useBuilding.ts +250 -0
  109. package/composables/useBuildingUnit.ts +116 -0
  110. package/composables/useCard.ts +46 -0
  111. package/composables/useCommonPermission.ts +207 -0
  112. package/composables/useCustomer.ts +113 -0
  113. package/composables/useCustomerSite.ts +56 -0
  114. package/composables/useDashboard.ts +31 -0
  115. package/composables/useDashboardData.ts +425 -0
  116. package/composables/useDocument.ts +57 -0
  117. package/composables/useFacility.ts +246 -0
  118. package/composables/useFeedback.ts +119 -0
  119. package/composables/useFile.ts +55 -0
  120. package/composables/useInvoice.ts +18 -0
  121. package/composables/useLocal.ts +131 -0
  122. package/composables/useLocalAuth.ts +137 -0
  123. package/composables/useLocalSetup.ts +13 -0
  124. package/composables/useMember.ts +111 -0
  125. package/composables/useNFCPatrolRoute.ts +77 -0
  126. package/composables/useNFCPatrolSettings.ts +19 -0
  127. package/composables/useNFCPatrolTag.ts +53 -0
  128. package/composables/useOnlineForm.ts +67 -0
  129. package/composables/useOrg.ts +129 -0
  130. package/composables/usePDFDownload.ts +25 -0
  131. package/composables/usePaymentMethod.ts +101 -0
  132. package/composables/usePeople.ts +81 -0
  133. package/composables/usePermission.ts +54 -0
  134. package/composables/usePhoneCountries.ts +561 -0
  135. package/composables/usePrice.ts +15 -0
  136. package/composables/usePromoCode.ts +36 -0
  137. package/composables/useRecapPermission.ts +26 -0
  138. package/composables/useRole.ts +104 -0
  139. package/composables/useSecurityUtils.ts +18 -0
  140. package/composables/useServiceProvider.ts +224 -0
  141. package/composables/useSite.ts +109 -0
  142. package/composables/useSiteEntryPassSettings.ts +46 -0
  143. package/composables/useSiteSettings.ts +123 -0
  144. package/composables/useSubscription.ts +150 -0
  145. package/composables/useUser.ts +132 -0
  146. package/composables/useUtils.ts +445 -0
  147. package/composables/useVerification.ts +34 -0
  148. package/composables/useVisitor.ts +120 -0
  149. package/composables/useWorkOrder.ts +85 -0
  150. package/error.vue +41 -0
  151. package/layouts/plain.vue +7 -0
  152. package/middleware/01.auth.ts +20 -0
  153. package/middleware/02.org.ts +21 -0
  154. package/middleware/03.customer.ts +13 -0
  155. package/middleware/member.ts +4 -0
  156. package/nuxt.config.ts +54 -0
  157. package/package.json +39 -0
  158. package/pages/index.vue +3 -0
  159. package/pages/payment-method-linked.vue +31 -0
  160. package/pages/require-customer.vue +56 -0
  161. package/pages/require-organization-membership.vue +47 -0
  162. package/pages/unauthorized.vue +29 -0
  163. package/plugins/API.ts +21 -0
  164. package/plugins/iconify.client.ts +5 -0
  165. package/plugins/secure-member.client.ts +86 -0
  166. package/plugins/vuetify.ts +62 -0
  167. package/public/bg-camera.jpg +0 -0
  168. package/public/bg-city.jpg +0 -0
  169. package/public/bg-condo.jpg +0 -0
  170. package/public/images/icons/delete-icon.png +0 -0
  171. package/public/sprite.svg +1 -0
  172. package/tsconfig.json +3 -0
  173. package/types/address.d.ts +13 -0
  174. package/types/building.d.ts +27 -0
  175. package/types/camera.d.ts +31 -0
  176. package/types/card.d.ts +22 -0
  177. package/types/customer.d.ts +27 -0
  178. package/types/document.d.ts +6 -0
  179. package/types/feedback.d.ts +68 -0
  180. package/types/local.d.ts +74 -0
  181. package/types/member.d.ts +21 -0
  182. package/types/online-form.d.ts +15 -0
  183. package/types/org.d.ts +13 -0
  184. package/types/people.d.ts +24 -0
  185. package/types/permission.d.ts +25 -0
  186. package/types/phone-number.d.ts +10 -0
  187. package/types/price.d.ts +17 -0
  188. package/types/promo-code.d.ts +19 -0
  189. package/types/role.d.ts +11 -0
  190. package/types/select.d.ts +4 -0
  191. package/types/service-provider.d.ts +15 -0
  192. package/types/site.d.ts +20 -0
  193. package/types/subscription.d.ts +23 -0
  194. package/types/user.d.ts +19 -0
  195. package/types/verification.d.ts +20 -0
  196. package/types/visitor.d.ts +42 -0
  197. package/types/work-order.d.ts +42 -0
  198. package/utils/phoneMasks.ts +1703 -0
@@ -0,0 +1,124 @@
1
+ <script setup lang="ts">
2
+ import { ref, computed, nextTick, useAttrs } from "vue";
3
+
4
+ const props = defineProps({
5
+ infinityEnabled: { type: Boolean, default: false }, // Enable ∞ display for 0
6
+ });
7
+
8
+ const modelValue = defineModel<number>(); // Store actual number
9
+ const inputRef = ref<HTMLInputElement | null>(null);
10
+ const attrs = useAttrs();
11
+
12
+ let cursorPosition = 0;
13
+ let forceCursorToEnd = false;
14
+
15
+ // Computed property to format value with commas or infinity sign
16
+ const formattedValue = computed({
17
+ get: () => {
18
+ if (props.infinityEnabled && modelValue.value === 0) return "∞"; // Show ∞ if enabled
19
+ return modelValue.value?.toLocaleString() ?? "";
20
+ },
21
+ set: (val: string) => {
22
+ if (props.infinityEnabled && val === "∞") {
23
+ modelValue.value = 0; // Convert back to 0 internally
24
+ return;
25
+ }
26
+
27
+ const rawValue = val.replace(/\D/g, ""); // Remove non-numeric characters
28
+ const numericValue = rawValue ? Number(rawValue) : 0;
29
+
30
+ if (!isNaN(numericValue)) {
31
+ modelValue.value = numericValue;
32
+ nextTick(() => restoreCursor());
33
+ }
34
+ },
35
+ });
36
+
37
+ // Handle keydown for navigation & number changes
38
+ const handleKeyDown = (event: KeyboardEvent) => {
39
+ if (!inputRef.value || modelValue.value === undefined) return;
40
+
41
+ const { selectionStart, selectionEnd, value } = inputRef.value;
42
+ const isAllSelected = selectionStart === 0 && selectionEnd === value.length;
43
+
44
+ if (
45
+ !/^\d$/.test(event.key) &&
46
+ ![
47
+ "Backspace",
48
+ "Delete",
49
+ "ArrowLeft",
50
+ "ArrowRight",
51
+ "ArrowUp",
52
+ "ArrowDown",
53
+ ].includes(event.key)
54
+ ) {
55
+ event.preventDefault();
56
+ return;
57
+ }
58
+
59
+ if (isAllSelected && /^\d$/.test(event.key)) {
60
+ event.preventDefault();
61
+ modelValue.value = Number(event.key);
62
+ forceCursorToEnd = true;
63
+ nextTick(() => restoreCursor());
64
+ return;
65
+ }
66
+
67
+ if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
68
+ forceCursorToEnd = false;
69
+ return;
70
+ }
71
+
72
+ if (event.key === "ArrowUp") {
73
+ event.preventDefault();
74
+ modelValue.value += 1;
75
+ forceCursorToEnd = true;
76
+ } else if (event.key === "ArrowDown") {
77
+ event.preventDefault();
78
+ modelValue.value = Math.max(0, modelValue.value - 1);
79
+ forceCursorToEnd = true;
80
+ } else {
81
+ cursorPosition = selectionStart || 0;
82
+ }
83
+
84
+ nextTick(() => restoreCursor());
85
+ };
86
+
87
+ // Restore cursor position
88
+ const restoreCursor = () => {
89
+ if (!inputRef.value) return;
90
+ const length = formattedValue.value.length;
91
+
92
+ if (forceCursorToEnd) {
93
+ inputRef.value.setSelectionRange(length, length);
94
+ } else {
95
+ inputRef.value.setSelectionRange(cursorPosition, cursorPosition);
96
+ }
97
+ };
98
+ </script>
99
+
100
+ <template>
101
+ <v-text-field
102
+ ref="inputRef"
103
+ v-model="formattedValue"
104
+ v-bind="attrs"
105
+ type="text"
106
+ @keydown="handleKeyDown"
107
+ >
108
+ <template v-if="$slots.prepend" v-slot:prepend>
109
+ <slot name="prepend"></slot>
110
+ </template>
111
+
112
+ <template v-if="$slots.append" v-slot:append>
113
+ <slot name="append"></slot>
114
+ </template>
115
+
116
+ <template v-if="$slots['append-inner']" v-slot:append-inner>
117
+ <slot name="append-inner"></slot>
118
+ </template>
119
+
120
+ <template v-if="$slots['prepend-inner']" v-slot:prepend-inner>
121
+ <slot name="prepend-inner"></slot>
122
+ </template>
123
+ </v-text-field>
124
+ </template>
@@ -0,0 +1,22 @@
1
+ <template>
2
+ <v-text-field
3
+ id="_password"
4
+ v-model="password"
5
+ :type="showPassword ? 'text' : 'password'"
6
+ :append-inner-icon="showPassword ? 'mdi-eye-off' : 'mdi-eye'"
7
+ v-bind="$attrs"
8
+ autocomplete="off"
9
+ @click:append-inner="togglePasswordVisibility"
10
+ />
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ // Define the props for the v-model
15
+ const password = defineModel({ default: "" });
16
+
17
+ // Control password visibility
18
+ const showPassword = ref(false);
19
+ const togglePasswordVisibility = () => {
20
+ showPassword.value = !showPassword.value;
21
+ };
22
+ </script>
@@ -0,0 +1,188 @@
1
+ <template>
2
+ <v-row dense>
3
+ <!-- Country/Dial Code -->
4
+ <v-col cols="4">
5
+ <v-select
6
+ v-model="localDialCode"
7
+ :items="countryOptions"
8
+ item-title="display"
9
+ item-value="label"
10
+ density="comfortable"
11
+ :rules="[dialCodeRequired]"
12
+ hide-details="auto"
13
+ placeholder="Select Country"
14
+ z-index="100000000"
15
+ :menu-props="{
16
+ maxHeight: 300,
17
+ zIndex: 3000
18
+ }"
19
+ no-data-text="No countries available"
20
+ >
21
+ <template #selection="{ item }">
22
+ <span class="text-body-2">{{ item.raw.dialCode }}</span>
23
+ </template>
24
+ <template #item="{ item }">
25
+ <v-list-item-title>
26
+ {{ item.raw.display }}
27
+ </v-list-item-title>
28
+ </template>
29
+ </v-select>
30
+ </v-col>
31
+
32
+ <!-- Phone Number -->
33
+ <v-col cols="8">
34
+ <v-text-field
35
+ v-model="localPhoneNumber"
36
+ :placeholder="selectedCountry?.placeholder || 'Phone Number'"
37
+ density="comfortable"
38
+ :rules="phoneValidationRules"
39
+ hide-details="auto"
40
+ type="tel"
41
+ @input="handlePhoneInput"
42
+ />
43
+ </v-col>
44
+ </v-row>
45
+ </template>
46
+
47
+ <script setup lang="ts">
48
+ const props = defineProps({
49
+ dialCode: {
50
+ type: String,
51
+ default: "+65",
52
+ },
53
+ phoneNumber: {
54
+ type: String,
55
+ default: "",
56
+ },
57
+ required: {
58
+ type: Boolean,
59
+ default: true,
60
+ },
61
+ });
62
+
63
+ const emit = defineEmits([
64
+ "update:dialCode",
65
+ "update:phoneNumber",
66
+ "update:isValid",
67
+ ]);
68
+
69
+ const { countries, getCountryByDialCode, formatPhoneNumber } =
70
+ usePhoneCountries();
71
+
72
+ const initialCountry = countries.find(
73
+ (country) => country.dialCode === props.dialCode
74
+ );
75
+ const localDialCode = ref(initialCountry?.label || props.dialCode);
76
+ const localPhoneNumber = ref(props.phoneNumber);
77
+
78
+ const countryOptions = computed(() => {
79
+ return countries.map((country) => ({
80
+ ...country,
81
+ display: `${country.country} (${country.dialCode})`,
82
+ }));
83
+ });
84
+
85
+ const selectedCountry = computed(() => {
86
+ const selected = countries.find(
87
+ (country) => country.label === localDialCode.value
88
+ );
89
+ return selected;
90
+ });
91
+
92
+ const dialCodeRequired = (v: string) => {
93
+ if (!props.required) return true;
94
+ return !!v || "Country code is required";
95
+ };
96
+
97
+ const phoneRequired = (v: string) => {
98
+ if (!props.required) return true;
99
+ return !!v || "Phone number is required";
100
+ };
101
+
102
+ const phoneDigitsOnly = (v: string) => {
103
+ if (!v) return props.required ? "Phone number is required" : true;
104
+ return (
105
+ /^\d+$/.test(v.replace(/\s|-|\(|\)/g, "")) || "Only numbers are allowed"
106
+ );
107
+ };
108
+
109
+ const phoneValidLength = (v: string) => {
110
+ if (!v || !selectedCountry.value) return true;
111
+
112
+ const cleanNumber = v.replace(/\s|-|\(|\)/g, "");
113
+ const { minLength, maxLength } = selectedCountry.value;
114
+
115
+ if (cleanNumber.length < minLength) {
116
+ return `Phone number must be at least ${minLength} digits`;
117
+ }
118
+ if (cleanNumber.length > maxLength) {
119
+ return `Phone number must not exceed ${maxLength} digits`;
120
+ }
121
+ return true;
122
+ };
123
+
124
+ const phoneCountryFormat = (v: string) => {
125
+ if (!v || !selectedCountry.value?.format) return true;
126
+
127
+ const cleanNumber = v.replace(/\s|-|\(|\)/g, "");
128
+ return (
129
+ selectedCountry.value.format.test(cleanNumber) ||
130
+ `Invalid ${selectedCountry.value.country} phone number format`
131
+ );
132
+ };
133
+
134
+ const phoneValidationRules = computed(() => [
135
+ phoneRequired,
136
+ phoneDigitsOnly,
137
+ phoneValidLength,
138
+ phoneCountryFormat,
139
+ ]);
140
+
141
+ const handlePhoneInput = (event: Event) => {
142
+ const target = event.target as HTMLInputElement;
143
+ const actualDialCode = selectedCountry.value?.dialCode || localDialCode.value;
144
+ const formatted = formatPhoneNumber(target.value, actualDialCode);
145
+ localPhoneNumber.value = formatted;
146
+ };
147
+
148
+ const isValid = computed(() => {
149
+ if (!props.required && !localPhoneNumber.value) return true;
150
+
151
+ return phoneValidationRules.value.every(
152
+ (rule) => rule(localPhoneNumber.value) === true
153
+ );
154
+ });
155
+
156
+ watch(localDialCode, (val) => {
157
+ const actualDialCode = selectedCountry.value?.dialCode || val;
158
+ emit("update:dialCode", actualDialCode);
159
+ });
160
+ watch(localPhoneNumber, (val) => emit("update:phoneNumber", val));
161
+ watch(isValid, (val) => emit("update:isValid", val));
162
+
163
+ watch(
164
+ () => props.dialCode,
165
+ (val) => {
166
+ // Find the country with matching dialCode and set the label
167
+ const matchingCountry = countries.find(
168
+ (country) => country.dialCode === val
169
+ );
170
+ localDialCode.value = matchingCountry?.label || val;
171
+ }
172
+ );
173
+ watch(
174
+ () => props.phoneNumber,
175
+ (val) => (localPhoneNumber.value = val)
176
+ );
177
+
178
+ watch(localDialCode, () => {
179
+ if (localPhoneNumber.value) {
180
+ const actualDialCode =
181
+ selectedCountry.value?.dialCode || localDialCode.value;
182
+ localPhoneNumber.value = formatPhoneNumber(
183
+ localPhoneNumber.value,
184
+ actualDialCode
185
+ );
186
+ }
187
+ });
188
+ </script>
@@ -0,0 +1,49 @@
1
+ <template>
2
+ <v-text-field
3
+ v-model="model"
4
+ :rules="rules"
5
+ :maxlength="maxlength"
6
+ :placeholder="placeholder"
7
+ :counter="maxlength"
8
+ @input="onInput"
9
+ outlined
10
+ :disabled="disabled"
11
+ :readonly="readonly"
12
+ clearable
13
+ />
14
+ </template>
15
+
16
+ <script setup>
17
+
18
+ const props = defineProps({
19
+ placeholder: {
20
+ type: String,
21
+ default: 'Vehicle Number'
22
+ },
23
+ rules: {
24
+ type: Array,
25
+ default: () => []
26
+ },
27
+ maxlength: {
28
+ type: [Number, String],
29
+ default: false
30
+ },
31
+ disabled: {
32
+ type: Boolean,
33
+ },
34
+ readonly: {
35
+ type: Boolean,
36
+ }
37
+ })
38
+
39
+ const model = defineModel({required: true })
40
+
41
+ function onInput(event) {
42
+ const value = typeof event === 'string' ? event : event?.target?.value || ''
43
+
44
+ let formatted = value.replace(/[^A-Za-z0-9]/g, '')
45
+ formatted = formatted.toUpperCase()
46
+
47
+ model.value = formatted
48
+ }
49
+ </script>
@@ -0,0 +1,22 @@
1
+ <template>
2
+ <span :class="`text-subtitle-2 font-weight-medium ${props.class}`">
3
+ {{ title }} <span v-if="props.required" class="text-error">*</span>
4
+ </span>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ const props = defineProps({
9
+ title: {
10
+ type: String,
11
+ required: true,
12
+ },
13
+ required: {
14
+ type: Boolean,
15
+ default: false,
16
+ },
17
+ class: {
18
+ type: String,
19
+ default: "",
20
+ },
21
+ });
22
+ </script>