@7365admin1/core 3.78.0 → 3.79.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/dist/index.mjs CHANGED
@@ -4401,6 +4401,20 @@ async function resolveStaffRole(userId) {
4401
4401
  const role = await db2.collection("roles").findOne({ _id: new ObjectId14(member.role.toString()), ...LIVE_ROLE });
4402
4402
  return role?.type === "admin" ? role : null;
4403
4403
  }
4404
+ async function listStaffUserIds() {
4405
+ const db2 = useAtlas8.getDb();
4406
+ if (!db2)
4407
+ return [];
4408
+ const members = await db2.collection("members").find({ type: "admin", status: { $ne: "deleted" } }, { projection: { user: 1, role: 1 } }).toArray();
4409
+ const roleIds = members.map((m) => m.role?.toString?.() ?? "").filter((r) => r && ObjectId14.isValid(r)).map((r) => new ObjectId14(r));
4410
+ if (!roleIds.length)
4411
+ return [];
4412
+ const staffRoles = new Set(
4413
+ (await db2.collection("roles").find({ _id: { $in: roleIds }, type: "admin", ...LIVE_ROLE }, { projection: { _id: 1 } }).toArray()).map((r) => r._id.toString())
4414
+ );
4415
+ const ids2 = members.filter((m) => staffRoles.has(m.role?.toString?.() ?? "")).map((m) => m.user?.toString?.() ?? "").filter((id) => id && ObjectId14.isValid(id));
4416
+ return Array.from(new Set(ids2));
4417
+ }
4404
4418
  async function isSuperAdmin(userId) {
4405
4419
  return await resolveStaffRole(userId) !== null;
4406
4420
  }
@@ -8396,6 +8410,7 @@ var NotificationModule = /* @__PURE__ */ ((NotificationModule2) => {
8396
8410
  NotificationModule2["EMERGENCY_CONTACT"] = "emergencyContact";
8397
8411
  NotificationModule2["VIRTUAL_PATROL"] = "virtualPatrol";
8398
8412
  NotificationModule2["CAMERA_FAULT"] = "cameraFault";
8413
+ NotificationModule2["PLATFORM"] = "platform";
8399
8414
  NotificationModule2["OTHER"] = "other";
8400
8415
  return NotificationModule2;
8401
8416
  })(NotificationModule || {});
@@ -8818,6 +8833,17 @@ var NOTIFICATION_CHANNEL_LABELS = {
8818
8833
  var ORG_MARKETPLACE_VENDOR_FIELD = "isMarketplaceVendor";
8819
8834
  var NO_EMAIL_RECIPIENT = "This system does not email anyone about this \u2014 the alert only reaches you in the app and on your phone.";
8820
8835
  var NOTIFICATION_CATEGORIES = [
8836
+ {
8837
+ key: "platform",
8838
+ label: "Seven365 platform",
8839
+ description: "When a new client is created, or an invited client owner accepts and their account goes live. Seven365 staff only.",
8840
+ channels: { inApp: true, push: true, email: false },
8841
+ channelNote: { email: NO_EMAIL_RECIPIENT },
8842
+ // Staff hold `*`; the flag below is what decides, not a resource.
8843
+ permissionResources: [],
8844
+ staffOnly: true,
8845
+ rendered: true
8846
+ },
8821
8847
  {
8822
8848
  key: "feedback",
8823
8849
  label: "Feedback",
@@ -9039,6 +9065,8 @@ function categoriesForPermissions(params) {
9039
9065
  return NOTIFICATION_CATEGORIES.filter((category) => {
9040
9066
  if (!category.rendered)
9041
9067
  return false;
9068
+ if (category.staffOnly)
9069
+ return params.isStaff === true;
9042
9070
  if (wildcard)
9043
9071
  return true;
9044
9072
  if (params.isResident && category.residentDefault)
@@ -10258,7 +10286,61 @@ async function sendSafetyAlert(params) {
10258
10286
  );
10259
10287
  return userIds.length;
10260
10288
  }
10289
+ async function staffRecipients() {
10290
+ try {
10291
+ return await listStaffUserIds();
10292
+ } catch (error) {
10293
+ console.warn("[NotificationService] staff lookup", error);
10294
+ return [];
10295
+ }
10296
+ }
10261
10297
  var NotificationService = class {
10298
+ /**
10299
+ * Seven365's own staff, told about the platform's client lifecycle.
10300
+ *
10301
+ * Nothing in the estate addressed Seven365 staff before this: their bell was
10302
+ * empty by construction (owner, 2026-09-21). Both senders resolve the staff
10303
+ * list themselves — a caller cannot address the platform by accident — and
10304
+ * both are quiet when there are no staff accounts.
10305
+ *
10306
+ * No `appSlug`: staff work on the web, and the web feed asks for everything
10307
+ * addressed to the person. The category is `platform`, whose switch only
10308
+ * staff are shown.
10309
+ */
10310
+ static async clientCreated(payload) {
10311
+ const staff = await staffRecipients();
10312
+ if (!staff.length)
10313
+ return;
10314
+ const what = [payload.orgName, payload.nature].filter(Boolean).join(" \u2014 ");
10315
+ await send(
10316
+ staff,
10317
+ "New client created",
10318
+ `${what} is now on iService365.`,
10319
+ {
10320
+ module: "platform",
10321
+ screen: "",
10322
+ params: { id: payload.orgId.toString() }
10323
+ },
10324
+ false,
10325
+ void 0,
10326
+ "platform"
10327
+ );
10328
+ }
10329
+ static async clientInvitationAccepted(payload) {
10330
+ const staff = await staffRecipients();
10331
+ if (!staff.length)
10332
+ return;
10333
+ const who = payload.orgName ? `${payload.email} (${payload.orgName})` : payload.email;
10334
+ await send(
10335
+ staff,
10336
+ "Invitation accepted",
10337
+ `${who} accepted their invitation and can sign in.`,
10338
+ { module: "platform", screen: "" },
10339
+ false,
10340
+ void 0,
10341
+ "platform"
10342
+ );
10343
+ }
10262
10344
  static async bulletinBoardCreated(payload) {
10263
10345
  await send(
10264
10346
  toStringArray(payload.to),
@@ -24186,6 +24268,11 @@ function useVerificationController() {
24186
24268
  return;
24187
24269
  }
24188
24270
  const result = await _updateStatusById(id, status);
24271
+ void NotificationService.clientInvitationAccepted({
24272
+ email: verification.email,
24273
+ invitationType: verification.type,
24274
+ orgName: verification?.metadata?.organizationName
24275
+ });
24189
24276
  res.json({ message: result });
24190
24277
  return;
24191
24278
  } catch (error2) {
@@ -25587,6 +25674,12 @@ function useOrgController() {
25587
25674
  const createdBy = await requireConsolePermission(req, "organizations");
25588
25675
  const org = await _add({ ...req.body, createdBy });
25589
25676
  await seedDefaultRoles(org, req.body.nature);
25677
+ void NotificationService.clientCreated({
25678
+ orgId: org,
25679
+ orgName: req.body.name,
25680
+ nature: req.body.nature,
25681
+ createdBy
25682
+ });
25590
25683
  res.status(201).json({ message: "Successfully created organization." });
25591
25684
  return;
25592
25685
  } catch (error2) {
@@ -91461,7 +91554,9 @@ function useNotificationPreferenceService() {
91461
91554
  return categoriesForPermissions({
91462
91555
  permissions,
91463
91556
  isResident,
91464
- isMarketplaceVendor: await belongsToMarketplaceVendor(db2, members)
91557
+ isMarketplaceVendor: await belongsToMarketplaceVendor(db2, members),
91558
+ // The staff switch is never opened by a role permission — see `staffOnly`.
91559
+ isStaff: await isSuperAdmin(userId)
91465
91560
  });
91466
91561
  }
91467
91562
  async function getForUser(userId) {
@@ -92116,6 +92211,7 @@ export {
92116
92211
  isSuperAdmin,
92117
92212
  isTermsCurrent,
92118
92213
  isValidTimezone,
92214
+ listStaffUserIds,
92119
92215
  manpowerDesignationsSchema,
92120
92216
  manpowerEvents,
92121
92217
  manpowerMonitoringSchema,