@7365admin1/layer-common 4.104.0 → 4.106.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.
- package/CHANGELOG.md +18 -0
- package/components/MemberMain.vue +2 -1
- package/components/OnlineFormFill.vue +6 -5
- package/components/RolePermissionMain.vue +2 -2
- package/components/ServiceProviderMain.vue +20 -9
- package/package.json +1 -1
- package/utils/invite-role-options.ts +2 -1
- package/utils/role.ts +13 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @iservice365/layer-common
|
|
2
2
|
|
|
3
|
+
## 4.106.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 4740604: Online forms review: remarks are optional when approving and still required to reject or request a resubmission (same rule as iMA365).
|
|
8
|
+
|
|
9
|
+
## 4.105.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- c43bf75: Site role pickers (Assign Role, Invite member, Reassign on delete) label organisation-wide roles "Name (organisation)"; site roles keep their plain name. Display only - the same role id is sent.
|
|
14
|
+
|
|
15
|
+
## 4.104.1
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 0112ec7: Service Providers: an unknown staff count (older row with no linked company) shows "-" instead of 0; View Members lists the company's active people on this site (same as Members > Service Providers) instead of one person's memberships.
|
|
20
|
+
|
|
3
21
|
## 4.104.0
|
|
4
22
|
|
|
5
23
|
### Minor Changes
|
|
@@ -374,7 +374,7 @@
|
|
|
374
374
|
v-model="selectedRole"
|
|
375
375
|
:items="pickerRoles"
|
|
376
376
|
item-value="_id"
|
|
377
|
-
:item-title="roleLabel"
|
|
377
|
+
:item-title="props.siteId ? sitePickerRoleLabel : roleLabel"
|
|
378
378
|
density="comfortable"
|
|
379
379
|
:rules="[requiredRule]"
|
|
380
380
|
:error-messages="
|
|
@@ -428,6 +428,7 @@ import {
|
|
|
428
428
|
limitedSites,
|
|
429
429
|
withCurrentRole,
|
|
430
430
|
roleLabel,
|
|
431
|
+
sitePickerRoleLabel,
|
|
431
432
|
} from "../utils/role";
|
|
432
433
|
import { formatLastActive } from "../utils/last-active";
|
|
433
434
|
import { formatMemberDate, memberAccess, memberPerson } from "../utils/member-row";
|
|
@@ -593,11 +593,12 @@ watch(() => props.initialManagementValues, (saved) => {
|
|
|
593
593
|
managementValues.value = { ...loaded, ...managementValues.value };
|
|
594
594
|
}, { immediate: true });
|
|
595
595
|
|
|
596
|
-
|
|
596
|
+
// Owner 2026-10-06: remarks are optional for Approve, required to reject or send back.
|
|
597
|
+
const remarksRequired = computed(() => !!selectedAction.value && selectedAction.value !== "approved");
|
|
597
598
|
|
|
598
599
|
// Same wording as the iMA365 review screen, so office and phone read alike.
|
|
599
600
|
const REVIEW_TEXT: Record<string, { remarks: string; confirm: string }> = {
|
|
600
|
-
approved: { remarks: "Remarks (the resident sees this)", confirm: "Confirm approval" },
|
|
601
|
+
approved: { remarks: "Remarks - optional (the resident sees this)", confirm: "Confirm approval" },
|
|
601
602
|
rejected: { remarks: "Reason for rejection (the resident sees this)", confirm: "Confirm rejection" },
|
|
602
603
|
resubmission: { remarks: "Reason for resubmission (the resident sees this)", confirm: "Send back to resident" },
|
|
603
604
|
};
|
|
@@ -605,8 +606,8 @@ const remarksLabel = computed(() => REVIEW_TEXT[selectedAction.value]?.remarks ?
|
|
|
605
606
|
const confirmLabel = computed(() => REVIEW_TEXT[selectedAction.value]?.confirm ?? "Confirm");
|
|
606
607
|
const reviewHint = computed(() =>
|
|
607
608
|
selectedAction.value === "approved" && managementUseItems.value.length
|
|
608
|
-
? "Fill in the For Management Use Only box
|
|
609
|
-
: "Choose Approve, Request resubmission or Reject
|
|
609
|
+
? "Fill in the For Management Use Only box, add remarks if you wish, then confirm."
|
|
610
|
+
: "Choose Approve, Request resubmission or Reject. Remarks are needed to reject or send back. Then confirm.",
|
|
610
611
|
);
|
|
611
612
|
|
|
612
613
|
const managementComplete = computed(() => {
|
|
@@ -616,7 +617,7 @@ const managementComplete = computed(() => {
|
|
|
616
617
|
|
|
617
618
|
const canConfirm = computed(() =>
|
|
618
619
|
!!selectedAction.value &&
|
|
619
|
-
adminRemarks.value.trim().length > 0 &&
|
|
620
|
+
(!remarksRequired.value || adminRemarks.value.trim().length > 0) &&
|
|
620
621
|
managementComplete.value
|
|
621
622
|
);
|
|
622
623
|
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
<v-select
|
|
167
167
|
v-model="memberReassignments[member._id]"
|
|
168
168
|
:items="deletionPreview.replacementRoles"
|
|
169
|
-
:item-title="roleLabel"
|
|
169
|
+
:item-title="props.siteId ? sitePickerRoleLabel : roleLabel"
|
|
170
170
|
item-value="_id"
|
|
171
171
|
label="Reassign role"
|
|
172
172
|
density="comfortable"
|
|
@@ -206,7 +206,7 @@
|
|
|
206
206
|
|
|
207
207
|
<script setup lang="ts">
|
|
208
208
|
// Relative import: this layer's `utils/` is not auto-imported into consumers.
|
|
209
|
-
import { roleLabel, safeReturnTo, showSiteField } from "../utils/role";
|
|
209
|
+
import { roleLabel, safeReturnTo, showSiteField, sitePickerRoleLabel } from "../utils/role";
|
|
210
210
|
import { holdsPermission } from "../utils/permission-spellings";
|
|
211
211
|
import {
|
|
212
212
|
catalogueForOrg,
|
|
@@ -320,7 +320,7 @@
|
|
|
320
320
|
|
|
321
321
|
<v-dialog v-model="viewDialog" max-width="514">
|
|
322
322
|
<v-card class="screen-modal">
|
|
323
|
-
<v-card-title>Members ({{ memberDialogCount }})</v-card-title>
|
|
323
|
+
<v-card-title>Members ({{ viewRow?.serviceProviderOrgId ? memberDialogCount : "-" }})</v-card-title>
|
|
324
324
|
|
|
325
325
|
<div class="screen-modal__body sp-members-scroll">
|
|
326
326
|
<v-table class="sp-members-table">
|
|
@@ -336,6 +336,11 @@
|
|
|
336
336
|
Loading...
|
|
337
337
|
</td>
|
|
338
338
|
</tr>
|
|
339
|
+
<tr v-else-if="!viewRow?.serviceProviderOrgId">
|
|
340
|
+
<td colspan="2" class="text-center sp-members-note">
|
|
341
|
+
This provider was added without a linked company account, so its staff cannot be listed.
|
|
342
|
+
</td>
|
|
343
|
+
</tr>
|
|
339
344
|
<tr v-else-if="!serviceProviderMembers.length">
|
|
340
345
|
<td colspan="2" class="text-center sp-members-note">
|
|
341
346
|
No members found.
|
|
@@ -1006,6 +1011,7 @@ const {
|
|
|
1006
1011
|
createServiceProviderInvite,
|
|
1007
1012
|
updateStatus: updateServiceProviderStatus,
|
|
1008
1013
|
invite,
|
|
1014
|
+
getSiteMembers,
|
|
1009
1015
|
} = useServiceProvider();
|
|
1010
1016
|
const { getAll: getAllMembers, getAllByUserId } = useMember();
|
|
1011
1017
|
|
|
@@ -1377,7 +1383,8 @@ function setInviteSiteName(siteId: string) {
|
|
|
1377
1383
|
}
|
|
1378
1384
|
|
|
1379
1385
|
function formatMembersCell(value: unknown): string {
|
|
1380
|
-
|
|
1386
|
+
// null = an older row with no company recorded: unknown, not 0.
|
|
1387
|
+
if (value == null || value === "") return "-";
|
|
1381
1388
|
const n = Number(value);
|
|
1382
1389
|
if (!Number.isFinite(n)) return "0";
|
|
1383
1390
|
return String(n);
|
|
@@ -1522,13 +1529,17 @@ async function openView(row: TableRow) {
|
|
|
1522
1529
|
|
|
1523
1530
|
loadingMembers.value = true;
|
|
1524
1531
|
try {
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
+
// The company's people on THIS site - the same list as Members > Service
|
|
1533
|
+
// Providers. It used to read one person's memberships (`row.userId`),
|
|
1534
|
+
// which a stored provider row does not even carry (owner report 2026-10-06).
|
|
1535
|
+
const data = await getSiteMembers(props.siteId);
|
|
1536
|
+
serviceProviderMembers.value = (data.items ?? [])
|
|
1537
|
+
.filter((member) => member.companyId === row.serviceProviderOrgId && member.status === "active")
|
|
1538
|
+
.map((member) => ({
|
|
1539
|
+
_id: String(member._id),
|
|
1540
|
+
name: member.name || member.email || "-",
|
|
1541
|
+
role: member.role || "-",
|
|
1542
|
+
}));
|
|
1532
1543
|
} catch (error: any) {
|
|
1533
1544
|
showMessage(errorConverter(error), "error");
|
|
1534
1545
|
} finally {
|
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.
|
|
5
|
+
"version": "4.106.0",
|
|
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.",
|
|
@@ -16,7 +16,8 @@ export function inviteRoleOptions(
|
|
|
16
16
|
.filter((role) => role && role._id)
|
|
17
17
|
.map((role) => ({
|
|
18
18
|
_id: String(role._id),
|
|
19
|
-
|
|
19
|
+
// Organisation-wide roles read "Administrator (organisation)" (owner, 2026-10-06).
|
|
20
|
+
title: role.site ? String(role.name ?? "") : `${String(role.name ?? "")} (organisation)`,
|
|
20
21
|
subtitle: role.site ? SITE_ROLE_LABEL : ORG_ROLE_LABEL,
|
|
21
22
|
}));
|
|
22
23
|
}
|
package/utils/role.ts
CHANGED
|
@@ -22,6 +22,19 @@ export function roleLabel(role: { name?: unknown; siteName?: unknown; site?: unk
|
|
|
22
22
|
return role?.site && site ? `${name} · ${site}` : name;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* A site-level role picker's label (owner, 2026-10-06): organisation-wide roles
|
|
27
|
+
* stay offered at a site but read "Administrator (organisation)", so nobody
|
|
28
|
+
* mistakes them for a role of this site. Site roles keep `roleLabel`. Display
|
|
29
|
+
* only - the picker still sends the same `_id`. A row the server did not send
|
|
30
|
+
* (`withCurrentRole`'s placeholder has no `type`) is left plain: we do not know
|
|
31
|
+
* whether it is organisation-wide.
|
|
32
|
+
*/
|
|
33
|
+
export function sitePickerRoleLabel(role: { name?: unknown; siteName?: unknown; site?: unknown; type?: unknown } | null | undefined): string {
|
|
34
|
+
if (!role || role.site || role.type === undefined) return roleLabel(role);
|
|
35
|
+
return `${roleLabel(role)} (organisation)`;
|
|
36
|
+
}
|
|
37
|
+
|
|
25
38
|
/**
|
|
26
39
|
* The Assign Role picker's list, with the member's CURRENT role always in it.
|
|
27
40
|
*
|