@7365admin1/layer-common 4.2.0 → 4.2.1-staging.259
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.
|
@@ -418,6 +418,42 @@
|
|
|
418
418
|
|
|
419
419
|
<v-divider />
|
|
420
420
|
|
|
421
|
+
<!-- Invitation Note -->
|
|
422
|
+
<v-col cols="12">
|
|
423
|
+
<div class="mt-5 pb-5">
|
|
424
|
+
<div class="d-flex pr-5">
|
|
425
|
+
<p class="mr-6 font-weight-medium flex-grow-1">
|
|
426
|
+
Invitation Note
|
|
427
|
+
<span class="d-block text-caption screen-hint mt-1">
|
|
428
|
+
Turning this on appends the text message below as a note
|
|
429
|
+
within the contractor's invitation link.
|
|
430
|
+
</span>
|
|
431
|
+
</p>
|
|
432
|
+
<v-switch
|
|
433
|
+
color="success"
|
|
434
|
+
hide-details
|
|
435
|
+
v-model="currentEntryPassSettings.onboardingInvitationNoteEnabled"
|
|
436
|
+
@update:modelValue="updateInvitationNoteEnabled()"
|
|
437
|
+
/>
|
|
438
|
+
</div>
|
|
439
|
+
<v-textarea
|
|
440
|
+
placeholder="Enter note here"
|
|
441
|
+
variant="outlined"
|
|
442
|
+
density="comfortable"
|
|
443
|
+
rows="4"
|
|
444
|
+
no-resize
|
|
445
|
+
class="mt-3"
|
|
446
|
+
:disabled="!currentEntryPassSettings.onboardingInvitationNoteEnabled"
|
|
447
|
+
:error-messages="invitationNoteError"
|
|
448
|
+
v-model="currentEntryPassSettings.onboardingInvitationNoteText"
|
|
449
|
+
@update:modelValue="invitationNoteError = ''"
|
|
450
|
+
@blur="saveInvitationNote()"
|
|
451
|
+
/>
|
|
452
|
+
</div>
|
|
453
|
+
</v-col>
|
|
454
|
+
|
|
455
|
+
<v-divider />
|
|
456
|
+
|
|
421
457
|
<!-- Printer Setup -->
|
|
422
458
|
<v-col cols="12">
|
|
423
459
|
<div class="mt-5 pb-5">
|
|
@@ -609,6 +645,8 @@ const currentEntryPassSettings = ref<Record<string, any>>({
|
|
|
609
645
|
onboardingSubText: "",
|
|
610
646
|
onboardingPrinterVendorId: "",
|
|
611
647
|
onboardingPrinterProductId: "",
|
|
648
|
+
onboardingInvitationNoteEnabled: false,
|
|
649
|
+
onboardingInvitationNoteText: "",
|
|
612
650
|
status: "",
|
|
613
651
|
createdBy: "",
|
|
614
652
|
updatedBy: "",
|
|
@@ -799,6 +837,10 @@ watchEffect(() => {
|
|
|
799
837
|
onboardingPrinterProductId: data.settings?.onboarding?.printer?.productId
|
|
800
838
|
? String(data.settings.onboarding.printer.productId)
|
|
801
839
|
: "",
|
|
840
|
+
onboardingInvitationNoteEnabled:
|
|
841
|
+
data.settings?.onboarding?.invitationNote?.isEnabled ?? false,
|
|
842
|
+
onboardingInvitationNoteText:
|
|
843
|
+
data.settings?.onboarding?.invitationNote?.text ?? "",
|
|
802
844
|
createdAt: data.createdAt ?? "",
|
|
803
845
|
updatedAt: data.updatedAt ?? "",
|
|
804
846
|
};
|
|
@@ -844,6 +886,14 @@ function buildPayload() {
|
|
|
844
886
|
vendorId: Number(currentEntryPassSettings.value.onboardingPrinterVendorId) || null,
|
|
845
887
|
productId: Number(currentEntryPassSettings.value.onboardingPrinterProductId) || null,
|
|
846
888
|
},
|
|
889
|
+
invitationNote: {
|
|
890
|
+
isEnabled:
|
|
891
|
+
currentEntryPassSettings.value.onboardingInvitationNoteEnabled ?? false,
|
|
892
|
+
// Kept even while the toggle is off - flipping it off is "stop
|
|
893
|
+
// appending this", not "throw away what I typed", so turning it
|
|
894
|
+
// back on restores the same note rather than a blank box.
|
|
895
|
+
text: (currentEntryPassSettings.value.onboardingInvitationNoteText || "").trim(),
|
|
896
|
+
},
|
|
847
897
|
},
|
|
848
898
|
},
|
|
849
899
|
};
|
|
@@ -893,6 +943,43 @@ async function updateOnboardingEnabled() {
|
|
|
893
943
|
getSiteEntryPassSettings();
|
|
894
944
|
}
|
|
895
945
|
|
|
946
|
+
/** Blank while the toggle is on means every contractor registration would
|
|
947
|
+
get an empty note appended - flagged on the field rather than silently
|
|
948
|
+
saved, mirroring the resident-contractor settings screen. */
|
|
949
|
+
const invitationNoteError = ref("");
|
|
950
|
+
|
|
951
|
+
function invitationNoteIsValid() {
|
|
952
|
+
const enabled = currentEntryPassSettings.value.onboardingInvitationNoteEnabled;
|
|
953
|
+
const text = (currentEntryPassSettings.value.onboardingInvitationNoteText || "").trim();
|
|
954
|
+
if (enabled && !text) {
|
|
955
|
+
invitationNoteError.value = "Enter the note to append to the invitation link.";
|
|
956
|
+
return false;
|
|
957
|
+
}
|
|
958
|
+
invitationNoteError.value = "";
|
|
959
|
+
return true;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
async function updateInvitationNoteEnabled() {
|
|
963
|
+
if (!invitationNoteIsValid()) return;
|
|
964
|
+
await _save(buildPayload());
|
|
965
|
+
showMessage("Invitation note updated!", "success");
|
|
966
|
+
getSiteEntryPassSettings();
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// This section has no Save button of its own (the one below it belongs to
|
|
970
|
+
// Printer Setup), so the note text persists on blur - otherwise a site
|
|
971
|
+
// could type a note, flip nothing else, and lose it on navigation.
|
|
972
|
+
async function saveInvitationNote() {
|
|
973
|
+
if (!invitationNoteIsValid()) return;
|
|
974
|
+
const saved = getSiteEntryPassSettingsReq.value?.data?.settings?.onboarding
|
|
975
|
+
?.invitationNote?.text ?? "";
|
|
976
|
+
const current = (currentEntryPassSettings.value.onboardingInvitationNoteText || "").trim();
|
|
977
|
+
if (saved === current) return;
|
|
978
|
+
await _save(buildPayload());
|
|
979
|
+
showMessage("Invitation note saved!", "success");
|
|
980
|
+
getSiteEntryPassSettings();
|
|
981
|
+
}
|
|
982
|
+
|
|
896
983
|
async function scanOnboardingPrinter() {
|
|
897
984
|
if (!isWebUsbSupported.value) {
|
|
898
985
|
showMessage("Web USB is not supported in this browser", "error");
|
|
@@ -160,6 +160,15 @@ const props = defineProps({
|
|
|
160
160
|
type: String,
|
|
161
161
|
default: "",
|
|
162
162
|
},
|
|
163
|
+
/*
|
|
164
|
+
* Pre-bind the invitation to one site.
|
|
165
|
+
*
|
|
166
|
+
* This prop has been declared since the component was written and was never
|
|
167
|
+
* read anywhere - `invite.site` was only ever filled by the Site picker. A
|
|
168
|
+
* caller that already knows the site (onboarding step 6, "Invite Site Admin",
|
|
169
|
+
* which is about the site created in step 4) had no way to say so. It is
|
|
170
|
+
* wired to `invite` below.
|
|
171
|
+
*/
|
|
163
172
|
site: {
|
|
164
173
|
type: Object as PropType<TCustomerSite>,
|
|
165
174
|
default: () => ({
|
|
@@ -225,17 +234,34 @@ watch(
|
|
|
225
234
|
() => {
|
|
226
235
|
invite.value.org = props.org || ""
|
|
227
236
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
237
|
+
/*
|
|
238
|
+
* `hideApp` HIDES the App field (see the `v-if` in the template). It also
|
|
239
|
+
* used to overwrite the value with a literal "property_management_agency",
|
|
240
|
+
* so a caller that hid the field could not choose what it was hiding, and
|
|
241
|
+
* every organisation - security, cleaning, landscaping - was invited into
|
|
242
|
+
* property management. Hiding a field is not the same as deciding it.
|
|
243
|
+
*
|
|
244
|
+
* `adminState: false` keeps its existing fallback: that flag is about the
|
|
245
|
+
* ORGANISATION-admin invitation, which is a separate flow, and changing it
|
|
246
|
+
* here would move where those members land.
|
|
247
|
+
*/
|
|
233
248
|
invite.value.app = props.adminState
|
|
234
249
|
? (props.app || "")
|
|
235
250
|
: "property_management_agency"
|
|
236
251
|
},
|
|
237
252
|
{ immediate: true }
|
|
238
253
|
)
|
|
254
|
+
|
|
255
|
+
/* A caller-supplied site wins; the picker still works when there is none. */
|
|
256
|
+
watch(
|
|
257
|
+
() => props.site,
|
|
258
|
+
(site) => {
|
|
259
|
+
if (!site?.site) return
|
|
260
|
+
invite.value.site = site.site
|
|
261
|
+
invite.value.siteName = site.name || ""
|
|
262
|
+
},
|
|
263
|
+
{ immediate: true, deep: true }
|
|
264
|
+
)
|
|
239
265
|
// invite.value.app = props.app;
|
|
240
266
|
// invite.value.org = props.org ?? "";
|
|
241
267
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@7365admin1/layer-common",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "4.2.
|
|
5
|
+
"version": "4.2.1-staging.259",
|
|
6
6
|
"author": "7365admin1",
|
|
7
7
|
"main": "./nuxt.config.ts",
|
|
8
8
|
"//files": "What a consumer extending this layer actually loads. Without this npm ships the whole working tree - the changesets, the CI workflows, the render harness in tools/ and any scratch directory that happened to exist at publish time. Nuxt resolves a layer by directory, so every runtime directory below has to stay listed; adding a new top-level runtime directory means adding it here too.",
|