@7365admin1/core 3.7.0 → 3.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.
package/dist/index.mjs CHANGED
@@ -11889,9 +11889,7 @@ function useVerificationService() {
11889
11889
  ...metadata,
11890
11890
  app
11891
11891
  },
11892
- expireAt: new Date(
11893
- Date.now() + 72 * 60 * 60 * 1e3
11894
- ).toISOString(),
11892
+ expireAt: new Date(Date.now() + 72 * 60 * 60 * 1e3).toISOString(),
11895
11893
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
11896
11894
  };
11897
11895
  const createdId = await add(value);
@@ -11910,10 +11908,7 @@ function useVerificationService() {
11910
11908
  hasPestControl: app === "pest_control_services",
11911
11909
  hasPoolMaintenance: app === "pool_maintenance_services"
11912
11910
  },
11913
- filePath: getDirectory(
11914
- __dirname,
11915
- "./public/handlebars/user-invite"
11916
- )
11911
+ filePath: getDirectory(__dirname, "./public/handlebars/user-invite")
11917
11912
  });
11918
11913
  await mailer.sendMail({
11919
11914
  to: email,
@@ -12056,7 +12051,15 @@ function useVerificationService() {
12056
12051
  throw error2;
12057
12052
  }
12058
12053
  }
12059
- async function createSimpleServiceProviderInvite({ email, app, name, role, orgId, siteId, siteName }) {
12054
+ async function createSimpleServiceProviderInvite({
12055
+ email,
12056
+ app,
12057
+ name,
12058
+ role,
12059
+ orgId,
12060
+ siteId,
12061
+ siteName
12062
+ }) {
12060
12063
  const schema2 = Joi11.object({
12061
12064
  email: Joi11.string().email().lowercase().required(),
12062
12065
  app: Joi11.string().allow("", null),
@@ -12098,7 +12101,10 @@ function useVerificationService() {
12098
12101
  };
12099
12102
  try {
12100
12103
  const id = await _add(value);
12101
- const filePath = getDirectory(__dirname, `./public/handlebars/${value.type}`);
12104
+ const filePath = getDirectory(
12105
+ __dirname,
12106
+ `./public/handlebars/${value.type}`
12107
+ );
12102
12108
  const link = `${APP_MAIN}/verify/${value.type}/${id}`;
12103
12109
  const emailContent = compileHandlebar({
12104
12110
  context: {
@@ -21025,6 +21031,15 @@ async function convertObjectIdUtil(id) {
21025
21031
  return Promise.reject("Invalid ID conversion to ObjectId");
21026
21032
  }
21027
21033
  }
21034
+ async function convertObjectIdUtil2(id, fieldName) {
21035
+ try {
21036
+ if (!id)
21037
+ throw new Error(`Invalid ID conversion to ObjectId of ${fieldName}.`);
21038
+ return new ObjectId40(id);
21039
+ } catch (_) {
21040
+ throw new Error(`Invalid ID conversion to ObjectId of ${fieldName}.`);
21041
+ }
21042
+ }
21028
21043
 
21029
21044
  // src/repositories/visitor-transaction.repo.ts
21030
21045
  import moment from "moment-timezone";
@@ -22827,6 +22842,38 @@ function useVehicleRepo() {
22827
22842
  throw error;
22828
22843
  }
22829
22844
  }
22845
+ async function getBlocklistedVehicleByPlateNumber(plateNumber, site) {
22846
+ if (!plateNumber) {
22847
+ throw new BadRequestError69("Plate number is required");
22848
+ }
22849
+ const baseQuery = {
22850
+ type: "blocklist" /* BLOCKLIST */,
22851
+ plateNumber,
22852
+ ...site && {
22853
+ site: typeof site === "string" ? new ObjectId43(site) : site
22854
+ }
22855
+ };
22856
+ try {
22857
+ const pipeline = [
22858
+ { $match: baseQuery },
22859
+ {
22860
+ $addFields: {
22861
+ latestDate: { $max: ["$createdAt", "$updatedAt"] }
22862
+ }
22863
+ },
22864
+ { $sort: { latestDate: -1 } },
22865
+ {
22866
+ $project: {
22867
+ latestDate: 0
22868
+ }
22869
+ }
22870
+ ];
22871
+ const [result] = await collection.aggregate(pipeline).toArray();
22872
+ return result;
22873
+ } catch (error) {
22874
+ throw error;
22875
+ }
22876
+ }
22830
22877
  return {
22831
22878
  createIndex,
22832
22879
  createTextIndex,
@@ -22845,7 +22892,8 @@ function useVehicleRepo() {
22845
22892
  bulkUpsertVehicles,
22846
22893
  getSpecificVehicleById,
22847
22894
  getBlocklistedVehicles,
22848
- getVehicleBySiteAndPlateNumber
22895
+ getVehicleBySiteAndPlateNumber,
22896
+ getBlocklistedVehicleByPlateNumber
22849
22897
  };
22850
22898
  }
22851
22899
 
@@ -33279,6 +33327,241 @@ var KeyRepo = class {
33279
33327
  return Promise.reject("Failed to delete key");
33280
33328
  }
33281
33329
  }
33330
+ static async getById2(id) {
33331
+ return this.collection().aggregate([
33332
+ { $match: { _id: new ObjectId61(id) } },
33333
+ {
33334
+ $lookup: {
33335
+ from: "qr-code-templates",
33336
+ localField: "template",
33337
+ foreignField: "_id",
33338
+ as: "QRTemplateInfo"
33339
+ }
33340
+ },
33341
+ {
33342
+ $unwind: {
33343
+ path: "$QRTemplateInfo",
33344
+ preserveNullAndEmptyArrays: true
33345
+ }
33346
+ },
33347
+ {
33348
+ $addFields: {
33349
+ prefixPass: { $toUpper: "$QRTemplateInfo.prefixPass" },
33350
+ prefixKey: { $toUpper: "$QRTemplateInfo.prefixKey" },
33351
+ templateName: "$QRTemplateInfo.name"
33352
+ }
33353
+ },
33354
+ {
33355
+ $addFields: {
33356
+ prefixAndName: {
33357
+ $cond: {
33358
+ if: { $or: [{ $not: "$prefixPass" }, { $not: "$prefixKey" }] },
33359
+ then: "$name",
33360
+ else: {
33361
+ $cond: {
33362
+ if: { $eq: ["$passType", "pass-key"] },
33363
+ then: { $concat: ["$prefixKey", "$name"] },
33364
+ else: { $concat: ["$prefixPass", "$name"] }
33365
+ }
33366
+ }
33367
+ }
33368
+ }
33369
+ }
33370
+ }
33371
+ ]).toArray().then((results) => results.length ? results[0] : null);
33372
+ }
33373
+ static async checkPassKeyAvailability(visitorPass, passKeys) {
33374
+ if (Array.isArray(visitorPass) && visitorPass.length > 0) {
33375
+ for (let i = 0; i < visitorPass.length; i++) {
33376
+ let pass = await convertObjectIdUtil2(visitorPass[i].keyId, "Pass ID");
33377
+ const getPass = await this.getById2(pass);
33378
+ if (!getPass)
33379
+ throw new Error("Pass not found");
33380
+ if (getPass?.status && getPass?.status.toLowerCase() != "Available".toLowerCase())
33381
+ throw new Error(`Pass ${getPass?.prefixAndName} is ${getPass?.status}`);
33382
+ }
33383
+ }
33384
+ if (Array.isArray(passKeys) && passKeys.length > 0) {
33385
+ for (let i = 0; i < passKeys.length; i++) {
33386
+ let key = await convertObjectIdUtil2(passKeys[i].keyId, "Key ID");
33387
+ const getPass = await this.getById2(key);
33388
+ if (!getPass)
33389
+ throw new Error(`Key not found`);
33390
+ if (getPass?.status && getPass?.status.toLowerCase() != "Available".toLowerCase())
33391
+ throw new Error(`Pass ${getPass?.prefixAndName} is ${getPass?.status}`);
33392
+ }
33393
+ }
33394
+ }
33395
+ };
33396
+
33397
+ // src/services/notification.service.ts
33398
+ import { sendExpoPushNotifications } from "iservice365-expo-notifications";
33399
+
33400
+ // src/repositories/push-token.repository.ts
33401
+ var PushTokenRepo = class {
33402
+ static collection() {
33403
+ return getDB().collection("push_tokens");
33404
+ }
33405
+ static async createIndexes() {
33406
+ await Promise.all([
33407
+ this.collection().createIndex({ token: 1 }, { unique: true }),
33408
+ this.collection().createIndex({ userId: 1, platform: 1 }),
33409
+ this.collection().createIndex({ siteId: 1 })
33410
+ ]);
33411
+ }
33412
+ static async upsert(userId, token, platform, siteId, projectId, appSlug) {
33413
+ const now = /* @__PURE__ */ new Date();
33414
+ const p = platform;
33415
+ const existing = await this.collection().findOne({ token });
33416
+ if (existing) {
33417
+ await this.collection().updateOne(
33418
+ { token },
33419
+ {
33420
+ $set: {
33421
+ userId,
33422
+ platform: p,
33423
+ siteId,
33424
+ projectId,
33425
+ appSlug,
33426
+ updatedAt: now
33427
+ }
33428
+ }
33429
+ );
33430
+ return;
33431
+ }
33432
+ await this.collection().deleteMany({ userId, platform: p });
33433
+ await this.collection().insertOne({
33434
+ userId,
33435
+ siteId,
33436
+ token,
33437
+ platform: p,
33438
+ projectId,
33439
+ appSlug,
33440
+ createdAt: now,
33441
+ updatedAt: now
33442
+ });
33443
+ }
33444
+ static async remove(token) {
33445
+ await this.collection().deleteMany({ token });
33446
+ }
33447
+ static async findTokensByUserIds(userIds, appSlug) {
33448
+ const docs = await this.collection().find({ userId: { $in: userIds }, appSlug: { $eq: appSlug } }).toArray();
33449
+ return docs.map((d) => d.token);
33450
+ }
33451
+ };
33452
+
33453
+ // src/services/notification.service.ts
33454
+ function toStringArray(recipient) {
33455
+ const arr = Array.isArray(recipient) ? recipient : [recipient];
33456
+ return arr.map((r) => r.toString());
33457
+ }
33458
+ async function send(userIds, title, body, data, isForMAMobileApp = false, appSlug) {
33459
+ try {
33460
+ let tokens = [];
33461
+ if (isForMAMobileApp) {
33462
+ tokens = await PushTokenRepo.findTokensByUserIds(userIds, appSlug);
33463
+ } else {
33464
+ tokens = await PushTokenRepo.findTokensByUserIds(userIds);
33465
+ }
33466
+ if (!tokens.length)
33467
+ return;
33468
+ for (const token of tokens) {
33469
+ await sendExpoPushNotifications([token], { title, body, data });
33470
+ }
33471
+ } catch (error) {
33472
+ console.warn("[NotificationService]", error);
33473
+ }
33474
+ }
33475
+ var NotificationService = class {
33476
+ static async bulletinBoardCreated(payload) {
33477
+ await send(
33478
+ toStringArray(payload.to),
33479
+ "Bulletin Board",
33480
+ `There is new ${payload.status} bulletin board.`,
33481
+ {
33482
+ bulletinId: payload.bulletinId.toString(),
33483
+ status: payload.status,
33484
+ module: "feedback",
33485
+ screen: "/(user)/bulletinInfo",
33486
+ params: {
33487
+ id: payload.bulletinId.toString()
33488
+ }
33489
+ },
33490
+ false,
33491
+ "iservice365-resident-mobile-app"
33492
+ );
33493
+ }
33494
+ static async prelovedMarketplacePostCreation(payload) {
33495
+ await send(
33496
+ toStringArray(payload.to),
33497
+ "Preloved Marketplace",
33498
+ `New preloved marketplace post added.`,
33499
+ {
33500
+ prelovedId: payload.prelovedId.toString(),
33501
+ status: payload.status,
33502
+ module: "prelovedMarketplace",
33503
+ screen: "/(user)/(marketplace)/prelovedPostInfo",
33504
+ params: {
33505
+ id: payload.prelovedId.toString()
33506
+ }
33507
+ },
33508
+ false,
33509
+ "iservice365-resident-mobile-app"
33510
+ );
33511
+ }
33512
+ static async bulletinBoardCreatedForMA(payload) {
33513
+ await send(
33514
+ toStringArray(payload.to),
33515
+ "Bulletin Board",
33516
+ `There is new ${payload.status} bulletin board.`,
33517
+ {
33518
+ bulletinId: payload.bulletinId.toString(),
33519
+ status: payload.status,
33520
+ module: "feedback",
33521
+ screen: "/(user)/(bulletin-board)",
33522
+ params: {
33523
+ id: payload.bulletinId.toString()
33524
+ }
33525
+ },
33526
+ true,
33527
+ "iservice365-ma-mobile-app"
33528
+ );
33529
+ }
33530
+ static async eventCreatedForMA(payload) {
33531
+ await send(
33532
+ toStringArray(payload.to),
33533
+ "Event",
33534
+ `There is new ${payload.status} event.`,
33535
+ {
33536
+ eventId: payload.eventId.toString(),
33537
+ status: payload.status,
33538
+ module: "event",
33539
+ screen: "/(user)/(events)",
33540
+ params: {
33541
+ id: payload.eventId.toString()
33542
+ }
33543
+ },
33544
+ true,
33545
+ "iservice365-ma-mobile-app"
33546
+ );
33547
+ }
33548
+ static async invitedVisitorCheckOutForMa(payload) {
33549
+ await send(
33550
+ toStringArray(payload.to),
33551
+ "Invited Visitor Check Out",
33552
+ `The invited visitor ${payload.name}, has been checked out.`,
33553
+ {
33554
+ visitorTransactionId: payload._id.toString(),
33555
+ module: "visitors",
33556
+ screen: "/(user)/visitor-management",
33557
+ params: {
33558
+ id: payload._id.toString()
33559
+ }
33560
+ },
33561
+ true,
33562
+ "iservice365-ma-mobile-app"
33563
+ );
33564
+ }
33282
33565
  };
33283
33566
 
33284
33567
  // src/services/visitor-transaction.service.ts
@@ -33315,8 +33598,11 @@ function useVisitorTransactionService() {
33315
33598
  } = useDahuaService();
33316
33599
  const { getAllSites: _getAllSites } = useSiteRepo();
33317
33600
  const { getByUserId: _getByUserId } = usePersonRepo();
33318
- const { add: addVehicle } = useVehicleRepo();
33601
+ const {
33602
+ getBlocklistedVehicleByPlateNumber: _getBlocklistedVehicleByPlateNumber
33603
+ } = useVehicleRepo();
33319
33604
  const { getById: _getUnitById } = useBuildingUnitRepo();
33605
+ const { getUsersBySiteId } = useMemberRepo();
33320
33606
  function extractKeyId(item) {
33321
33607
  if (!item)
33322
33608
  return null;
@@ -33393,6 +33679,13 @@ function useVisitorTransactionService() {
33393
33679
  const start = value.checkIn ? new Date(value.checkIn) : /* @__PURE__ */ new Date();
33394
33680
  try {
33395
33681
  session?.startTransaction();
33682
+ if (value.plateNumber) {
33683
+ const result2 = await _getBlocklistedVehicleByPlateNumber(
33684
+ value.plateNumber
33685
+ );
33686
+ if (result2)
33687
+ throw new BadRequestError100("Plate number is blocklisted");
33688
+ }
33396
33689
  let camera;
33397
33690
  if (value.site && value.plateNumber) {
33398
33691
  try {
@@ -33458,6 +33751,10 @@ function useVisitorTransactionService() {
33458
33751
  for (let i = 0; i < value.members.length; i += chunkSize) {
33459
33752
  const chunk = value.members.slice(i, i + chunkSize);
33460
33753
  for (const member of chunk) {
33754
+ await KeyRepo.checkPassKeyAvailability(
33755
+ member.visitorPass,
33756
+ member.passKeys
33757
+ );
33461
33758
  if (member.visitorPass && Array.isArray(member.visitorPass) && member.visitorPass.length > 0) {
33462
33759
  for (const vp of member.visitorPass) {
33463
33760
  try {
@@ -33544,6 +33841,7 @@ function useVisitorTransactionService() {
33544
33841
  if (found === 1)
33545
33842
  throw new BadRequestError100("This plate number is blocklisted");
33546
33843
  }
33844
+ await KeyRepo.checkPassKeyAvailability(value.visitorPass, value.passKeys);
33547
33845
  if (value.visitorPass && Array.isArray(value.visitorPass) && value.visitorPass.length > 0 && value.visitorPass) {
33548
33846
  for (const vp of value.visitorPass) {
33549
33847
  try {
@@ -33591,7 +33889,9 @@ function useVisitorTransactionService() {
33591
33889
  password,
33592
33890
  plateNumber: value?.plateNumber
33593
33891
  });
33594
- logger80.info(`Barrier command sent successfully to ${host}`, { response: openBarrier });
33892
+ logger80.info(`Barrier command sent successfully to ${host}`, {
33893
+ response: openBarrier
33894
+ });
33595
33895
  } catch (error) {
33596
33896
  logger80.error(
33597
33897
  `Failed to open barrier at host ${host}. Critical system error:`,
@@ -33731,7 +34031,9 @@ function useVisitorTransactionService() {
33731
34031
  password,
33732
34032
  plateNumber: value?.plateNumber
33733
34033
  });
33734
- logger80.info(`Barrier command sent successfully to ${host}`, { response: openBarrier });
34034
+ logger80.info(`Barrier command sent successfully to ${host}`, {
34035
+ response: openBarrier
34036
+ });
33735
34037
  } catch (error) {
33736
34038
  logger80.error(
33737
34039
  `Failed to open barrier at host ${host}. Critical system error:`,
@@ -33741,6 +34043,28 @@ function useVisitorTransactionService() {
33741
34043
  }
33742
34044
  }
33743
34045
  console.log("Open barrier response:", openBarrier);
34046
+ const visitorTransaction = await _getVisitorTransactionById(
34047
+ id.toString()
34048
+ );
34049
+ if (!visitorTransaction) {
34050
+ throw new Error("Visitor transaction not found.");
34051
+ }
34052
+ if (value.checkOut && visitorTransaction.type === "guest" /* GUEST */) {
34053
+ const users = await getUsersBySiteId({
34054
+ status: "active",
34055
+ siteId: visitorTransaction.site.toString()
34056
+ });
34057
+ if (users?.length > 0) {
34058
+ const userIds = Array.from(
34059
+ new Set(users.map((item) => item.user.toString()))
34060
+ );
34061
+ NotificationService.invitedVisitorCheckOutForMa({
34062
+ to: userIds,
34063
+ name: visitorTransaction.name,
34064
+ _id: id.toString()
34065
+ });
34066
+ }
34067
+ }
33744
34068
  await session?.commitTransaction();
33745
34069
  return "Successfully updated visitor transaction.";
33746
34070
  } catch (error) {
@@ -33944,7 +34268,12 @@ function useVisitorTransactionController() {
33944
34268
  return;
33945
34269
  } catch (error) {
33946
34270
  logger81.log({ level: "error", message: error.message });
33947
- next(error);
34271
+ console.log("error", error);
34272
+ if (error?.message) {
34273
+ next(new BadRequestError101(error?.message));
34274
+ } else {
34275
+ next(error);
34276
+ }
33948
34277
  return;
33949
34278
  }
33950
34279
  }
@@ -40899,120 +41228,6 @@ function useBulletinBoardRepo() {
40899
41228
  // src/services/bulletin-board.service.ts
40900
41229
  import { useAtlas as useAtlas68, NotFoundError as NotFoundError30 } from "@7365admin1/node-server-utils";
40901
41230
  import { ObjectId as ObjectId85 } from "mongodb";
40902
-
40903
- // src/services/notification.service.ts
40904
- import { sendExpoPushNotifications } from "iservice365-expo-notifications";
40905
-
40906
- // src/repositories/push-token.repository.ts
40907
- var PushTokenRepo = class {
40908
- static collection() {
40909
- return getDB().collection("push_tokens");
40910
- }
40911
- static async createIndexes() {
40912
- await Promise.all([
40913
- this.collection().createIndex({ token: 1 }, { unique: true }),
40914
- this.collection().createIndex({ userId: 1, platform: 1 }),
40915
- this.collection().createIndex({ siteId: 1 })
40916
- ]);
40917
- }
40918
- static async upsert(userId, token, platform, siteId, projectId, appSlug) {
40919
- const now = /* @__PURE__ */ new Date();
40920
- const p = platform;
40921
- const existing = await this.collection().findOne({ token });
40922
- if (existing) {
40923
- await this.collection().updateOne(
40924
- { token },
40925
- {
40926
- $set: {
40927
- userId,
40928
- platform: p,
40929
- siteId,
40930
- projectId,
40931
- appSlug,
40932
- updatedAt: now
40933
- }
40934
- }
40935
- );
40936
- return;
40937
- }
40938
- await this.collection().deleteMany({ userId, platform: p });
40939
- await this.collection().insertOne({
40940
- userId,
40941
- siteId,
40942
- token,
40943
- platform: p,
40944
- projectId,
40945
- appSlug,
40946
- createdAt: now,
40947
- updatedAt: now
40948
- });
40949
- }
40950
- static async remove(token) {
40951
- await this.collection().deleteMany({ token });
40952
- }
40953
- static async findTokensByUserIds(userIds, appSlug) {
40954
- const docs = await this.collection().find({ userId: { $in: userIds }, appSlug: { $eq: appSlug } }).toArray();
40955
- return docs.map((d) => d.token);
40956
- }
40957
- };
40958
-
40959
- // src/services/notification.service.ts
40960
- function toStringArray(recipient) {
40961
- const arr = Array.isArray(recipient) ? recipient : [recipient];
40962
- return arr.map((r) => r.toString());
40963
- }
40964
- async function send(userIds, title, body, data, appSlug) {
40965
- try {
40966
- const tokens = Array.from(
40967
- new Set(await PushTokenRepo.findTokensByUserIds(userIds, appSlug))
40968
- );
40969
- if (!tokens.length)
40970
- return;
40971
- for (const token of tokens) {
40972
- await sendExpoPushNotifications([token], { title, body, data });
40973
- }
40974
- } catch (error) {
40975
- console.warn("[NotificationService]", error);
40976
- }
40977
- }
40978
- var NotificationService = class {
40979
- static async bulletinBoardCreated(payload) {
40980
- await send(
40981
- toStringArray(payload.to),
40982
- "Bulletin Board",
40983
- `There is new ${payload.status} bulletin board.`,
40984
- {
40985
- bulletinId: payload.bulletinId.toString(),
40986
- status: payload.status,
40987
- module: "feedback",
40988
- screen: "/(user)/bulletinInfo",
40989
- params: {
40990
- id: payload.bulletinId.toString()
40991
- }
40992
- },
40993
- "iservice365-resident-mobile-app"
40994
- );
40995
- }
40996
- static async prelovedMarketplacePostCreation(payload) {
40997
- await send(
40998
- toStringArray(payload.to),
40999
- "Preloved Marketplace",
41000
- `New preloved marketplace post added.`,
41001
- {
41002
- prelovedId: payload.prelovedId.toString(),
41003
- status: payload.status,
41004
- module: "prelovedMarketplace",
41005
- screen: "/(user)/(marketplace)/prelovedPostInfo",
41006
- params: {
41007
- id: payload.prelovedId.toString()
41008
- }
41009
- },
41010
- "iservice365-resident-mobile-app"
41011
- );
41012
- }
41013
- };
41014
-
41015
- // src/services/bulletin-board.service.ts
41016
41231
  function useBulletinBoardService() {
41017
41232
  const {
41018
41233
  add: _add,
@@ -41079,6 +41294,12 @@ function useBulletinBoardService() {
41079
41294
  status: bulletinBoardStatus
41080
41295
  });
41081
41296
  }
41297
+ NotificationService.bulletinBoardCreatedForMA({
41298
+ to: userIds,
41299
+ bulletinId: bulletinBoardId,
41300
+ subject: "Bulletin Board",
41301
+ status: bulletinBoardStatus
41302
+ });
41082
41303
  }
41083
41304
  await session?.commitTransaction();
41084
41305
  return "Successfully added bulletin board.";
@@ -43041,11 +43262,27 @@ function useEventManagementService() {
43041
43262
  updateEventManagementById: _updateEventManagementById,
43042
43263
  processCompletedEvents: _processCompletedEvents
43043
43264
  } = useEventManagementRepo();
43265
+ const { getUsersBySiteId } = useMemberRepo();
43044
43266
  async function add(value) {
43045
43267
  const session = useAtlas74.getClient()?.startSession();
43046
43268
  try {
43047
43269
  session?.startTransaction();
43048
- await _add(value, session);
43270
+ const response = await _add(value, session);
43271
+ console.log("response", response);
43272
+ const users = await getUsersBySiteId({
43273
+ status: "active",
43274
+ siteId: value.site
43275
+ });
43276
+ if (users?.length > 0) {
43277
+ const userIds = Array.from(
43278
+ new Set(users.map((item) => item.user.toString()))
43279
+ );
43280
+ NotificationService.eventCreatedForMA({
43281
+ to: userIds,
43282
+ eventId: response,
43283
+ status: value.status
43284
+ });
43285
+ }
43049
43286
  await session?.commitTransaction();
43050
43287
  return "Successfully added event.";
43051
43288
  } catch (error) {
@@ -56552,73 +56789,6 @@ var Period = /* @__PURE__ */ ((Period2) => {
56552
56789
  Period2["THIS_MONTH"] = "thisMonth";
56553
56790
  return Period2;
56554
56791
  })(Period || {});
56555
- function getPeriodRangeWithPrevious(period) {
56556
- const now = /* @__PURE__ */ new Date();
56557
- let currentStart = /* @__PURE__ */ new Date();
56558
- let currentEnd = /* @__PURE__ */ new Date();
56559
- let previousStart = /* @__PURE__ */ new Date();
56560
- let previousEnd = /* @__PURE__ */ new Date();
56561
- if (period === "today" /* TODAY */) {
56562
- currentStart.setHours(0, 0, 0, 0);
56563
- currentEnd.setHours(23, 59, 59, 999);
56564
- previousStart = new Date(currentStart);
56565
- previousStart.setDate(previousStart.getDate() - 1);
56566
- previousEnd = new Date(currentEnd);
56567
- previousEnd.setDate(previousEnd.getDate() - 1);
56568
- } else if (period === "thisWeek" /* THIS_WEEK */) {
56569
- const day = now.getDay();
56570
- const diffToMonday = day === 0 ? -6 : 1 - day;
56571
- currentStart = new Date(now);
56572
- currentStart.setDate(now.getDate() + diffToMonday);
56573
- currentStart.setHours(0, 0, 0, 0);
56574
- currentEnd = new Date(currentStart);
56575
- currentEnd.setDate(currentStart.getDate() + 6);
56576
- currentEnd.setHours(23, 59, 59, 999);
56577
- previousStart = new Date(currentStart);
56578
- previousStart.setDate(previousStart.getDate() - 7);
56579
- previousEnd = new Date(currentEnd);
56580
- previousEnd.setDate(previousEnd.getDate() - 7);
56581
- } else if (period === "thisMonth" /* THIS_MONTH */) {
56582
- currentStart = new Date(now.getFullYear(), now.getMonth(), 1);
56583
- currentEnd = new Date(
56584
- now.getFullYear(),
56585
- now.getMonth() + 1,
56586
- 0,
56587
- 23,
56588
- 59,
56589
- 59,
56590
- 999
56591
- );
56592
- previousStart = new Date(now.getFullYear(), now.getMonth() - 1, 1);
56593
- previousEnd = new Date(
56594
- now.getFullYear(),
56595
- now.getMonth(),
56596
- 0,
56597
- 23,
56598
- 59,
56599
- 59,
56600
- 999
56601
- );
56602
- } else {
56603
- throw new BadRequestError182("Invalid period.");
56604
- }
56605
- return {
56606
- current: {
56607
- start: currentStart.toISOString(),
56608
- end: currentEnd.toISOString()
56609
- },
56610
- previous: {
56611
- start: previousStart.toISOString(),
56612
- end: previousEnd.toISOString()
56613
- }
56614
- };
56615
- }
56616
- function calculatePercentage(current, previous) {
56617
- if (previous === 0) {
56618
- return current === 0 ? 0 : 100;
56619
- }
56620
- return Number(((current - previous) / previous * 100).toFixed(2));
56621
- }
56622
56792
  function useNewDashboardRepo() {
56623
56793
  const db = useAtlas100.getDb();
56624
56794
  if (!db) {
@@ -57127,7 +57297,8 @@ function useNewDashboardRepo() {
57127
57297
  currentlyOnSiteCount,
57128
57298
  facilityReport,
57129
57299
  yesterdayFacilityReport,
57130
- todayFacilityReport
57300
+ todayFacilityReport,
57301
+ workOrderStatusReport
57131
57302
  ] = await Promise.all([
57132
57303
  workOrderCollection.aggregate([
57133
57304
  {
@@ -57317,6 +57488,20 @@ function useNewDashboardRepo() {
57317
57488
  }
57318
57489
  },
57319
57490
  { $count: "count" }
57491
+ ]).toArray(),
57492
+ workOrderCollection.aggregate([
57493
+ {
57494
+ $match: {
57495
+ site: { $in: [siteIdObj, siteId] },
57496
+ createdAt: periodRange
57497
+ }
57498
+ },
57499
+ {
57500
+ $group: {
57501
+ _id: "$status",
57502
+ count: { $sum: 1 }
57503
+ }
57504
+ }
57320
57505
  ]).toArray()
57321
57506
  ]);
57322
57507
  const wFacet = workOrderReport[0] ?? { total: [], inProgress: [] };
@@ -57325,6 +57510,23 @@ function useNewDashboardRepo() {
57325
57510
  ongoing: [],
57326
57511
  waitingApproval: []
57327
57512
  };
57513
+ const workOrderStatus = {
57514
+ pending: 0,
57515
+ inProgress: 0,
57516
+ completed: 0
57517
+ };
57518
+ for (const item of workOrderStatusReport || []) {
57519
+ const rawStatus = String(item._id || "").toLowerCase().trim();
57520
+ if (rawStatus === "to-do" || rawStatus === "for-review") {
57521
+ workOrderStatus.pending += item.count || 0;
57522
+ } else if (rawStatus === "in-progress") {
57523
+ workOrderStatus.inProgress += item.count || 0;
57524
+ } else if (rawStatus === "completed") {
57525
+ workOrderStatus.completed += item.count || 0;
57526
+ } else {
57527
+ workOrderStatus.pending += item.count || 0;
57528
+ }
57529
+ }
57328
57530
  const data = {
57329
57531
  openWorkOrder: {
57330
57532
  count: wFacet.total[0]?.count ?? 0,
@@ -57359,6 +57561,7 @@ function useNewDashboardRepo() {
57359
57561
  yesterdayFacilityReport[0]?.count ?? 0
57360
57562
  )
57361
57563
  },
57564
+ workOrderStatus,
57362
57565
  upcomingEvents,
57363
57566
  todayReminders,
57364
57567
  todayAttentions
@@ -66058,7 +66261,8 @@ var schemaUpdateChatPreloved = Joi141.object({
66058
66261
  reactions: Joi141.string().optional().allow("", null)
66059
66262
  });
66060
66263
  var schemaChatPreloved = Joi141.object({
66061
- channelId: Joi141.string().hex().length(24).required(),
66264
+ channelId: Joi141.string().hex().length(24).optional().allow("", null),
66265
+ receiverId: Joi141.string().hex().length(24).optional().allow("", null),
66062
66266
  senderId: Joi141.string().hex().length(24).required(),
66063
66267
  postId: Joi141.string().hex().length(24).optional().allow("", null),
66064
66268
  message: schemaMessage.required(),
@@ -66105,7 +66309,7 @@ function MChatPreloved(value) {
66105
66309
  }
66106
66310
  return {
66107
66311
  _id: new ObjectId145(),
66108
- channelId: value.channelId ?? "",
66312
+ channelId: value.channelId ?? null,
66109
66313
  senderId: value.senderId ?? "",
66110
66314
  postId: value.postId ?? null,
66111
66315
  message: {
@@ -66344,7 +66548,130 @@ function useChannelPrelovedRepo() {
66344
66548
  throw error;
66345
66549
  }
66346
66550
  }
66347
- return { add, getByParticipants, getChannelMessages };
66551
+ async function getChatLists(currentUserId, page = 1, limit = 10, search) {
66552
+ const normalizedPage = page > 0 ? page - 1 : 0;
66553
+ const normalizedLimit = limit || 10;
66554
+ const _currentUserId = new ObjectId148(currentUserId);
66555
+ const escapedSearch = search ? search.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") : null;
66556
+ const pipeline = [
66557
+ {
66558
+ $match: {
66559
+ $or: [{ receiverId: _currentUserId }, { senderId: _currentUserId }]
66560
+ }
66561
+ },
66562
+ {
66563
+ $lookup: {
66564
+ from: "users",
66565
+ localField: "senderId",
66566
+ foreignField: "_id",
66567
+ pipeline: [
66568
+ {
66569
+ $project: {
66570
+ name: 1,
66571
+ profile: 1,
66572
+ type: 1
66573
+ }
66574
+ }
66575
+ ],
66576
+ as: "senderId"
66577
+ }
66578
+ },
66579
+ { $unwind: { path: "$senderId", preserveNullAndEmptyArrays: true } },
66580
+ {
66581
+ $lookup: {
66582
+ from: "post-preloved",
66583
+ localField: "postId",
66584
+ foreignField: "_id",
66585
+ pipeline: [
66586
+ {
66587
+ $project: {
66588
+ title: 1,
66589
+ description: 1,
66590
+ attachments: 1,
66591
+ price: 1,
66592
+ status: 1,
66593
+ createdBy: 1,
66594
+ reserverId: 1
66595
+ }
66596
+ }
66597
+ ],
66598
+ as: "postDetails"
66599
+ }
66600
+ },
66601
+ { $unwind: { path: "$postDetails", preserveNullAndEmptyArrays: true } },
66602
+ ...escapedSearch ? [
66603
+ {
66604
+ $match: {
66605
+ $or: [
66606
+ {
66607
+ "senderId.name": {
66608
+ $regex: new RegExp(escapedSearch, "i")
66609
+ }
66610
+ },
66611
+ {
66612
+ "postDetails.title": {
66613
+ $regex: new RegExp(escapedSearch, "i")
66614
+ }
66615
+ }
66616
+ ]
66617
+ }
66618
+ }
66619
+ ] : [],
66620
+ {
66621
+ $lookup: {
66622
+ from: "chat-preloved",
66623
+ localField: "_id",
66624
+ foreignField: "channelId",
66625
+ pipeline: [
66626
+ { $match: { deletedAt: null } },
66627
+ { $sort: { createdAt: -1 } },
66628
+ { $limit: 1 }
66629
+ ],
66630
+ as: "latestChat"
66631
+ }
66632
+ },
66633
+ { $unwind: { path: "$latestChat", preserveNullAndEmptyArrays: true } },
66634
+ { $addFields: { lastMessageDate: "$latestChat.createdAt" } },
66635
+ {
66636
+ $lookup: {
66637
+ from: "bid-preloved",
66638
+ localField: "postId",
66639
+ foreignField: "postId",
66640
+ pipeline: [
66641
+ { $sort: { createdAt: -1 } },
66642
+ { $limit: 1 },
66643
+ { $project: { price: 1, message: 1, status: 1, type: 1 } }
66644
+ ],
66645
+ as: "latestBidDetails"
66646
+ }
66647
+ },
66648
+ {
66649
+ $unwind: {
66650
+ path: "$latestBidDetails",
66651
+ preserveNullAndEmptyArrays: true
66652
+ }
66653
+ },
66654
+ { $sort: { lastMessageDate: -1 } },
66655
+ {
66656
+ $facet: {
66657
+ totalCount: [{ $count: "count" }],
66658
+ items: [
66659
+ { $skip: normalizedPage * normalizedLimit },
66660
+ { $limit: normalizedLimit }
66661
+ ]
66662
+ }
66663
+ }
66664
+ ];
66665
+ try {
66666
+ const result = await collection.aggregate(pipeline).toArray();
66667
+ const totalCount = result[0].totalCount[0]?.count ?? 0;
66668
+ const items = result[0].items;
66669
+ return paginate63(items, normalizedPage, normalizedLimit, totalCount);
66670
+ } catch (error) {
66671
+ throw error;
66672
+ }
66673
+ }
66674
+ return { add, getByParticipants, getChatLists, getChannelMessages };
66348
66675
  }
66349
66676
 
66350
66677
  // src/services/chat-preloved.service.ts
@@ -66462,7 +66789,12 @@ function useChatPrelovedController() {
66462
66789
  import { BadRequestError as BadRequestError223, logger as logger193 } from "@7365admin1/node-server-utils";
66463
66790
  import Joi144 from "joi";
66464
66791
  function useChannelPrelovedController() {
66465
- const { add: _add, getChannelMessages: _getChannelMessages } = useChannelPrelovedRepo();
66792
+ const {
66793
+ add: _add,
66794
+ getByParticipants: _getByParticipants,
66795
+ getChatLists: _getChatLists,
66796
+ getChannelMessages: _getChannelMessages
66797
+ } = useChannelPrelovedRepo();
66466
66798
  async function add(req, res, next) {
66467
66799
  const { error, value } = schemaChannelPreloved.validate(req.body, {
66468
66800
  abortEarly: false
@@ -66499,9 +66831,7 @@ function useChannelPrelovedController() {
66499
66831
  next(new BadRequestError223(paramError.message));
66500
66832
  return;
66501
66833
  }
66502
- const { error: queryError, value: query } = querySchema.validate(
66503
- req.query
66504
- );
66834
+ const { error: queryError, value: query } = querySchema.validate(req.query);
66505
66835
  if (queryError) {
66506
66836
  logger193.log({ level: "error", message: queryError.message });
66507
66837
  next(new BadRequestError223(queryError.message));
@@ -66521,7 +66851,57 @@ function useChannelPrelovedController() {
66521
66851
  next(error);
66522
66852
  }
66523
66853
  }
66524
- return { add, getChannelMessages };
66854
+ async function getChannel(req, res, next) {
66855
+ const querySchema = Joi144.object({
66856
+ postId: Joi144.string().hex().length(24).required(),
66857
+ receiverId: Joi144.string().hex().length(24).required(),
66858
+ senderId: Joi144.string().hex().length(24).required()
66859
+ });
66860
+ const { error, value } = querySchema.validate(req.query);
66861
+ if (error) {
66862
+ logger193.log({ level: "error", message: error.message });
66863
+ next(new BadRequestError223(error.message));
66864
+ return;
66865
+ }
66866
+ try {
66867
+ const data = await _getByParticipants(
66868
+ value.senderId,
66869
+ value.receiverId,
66870
+ value.postId
66871
+ );
66872
+ res.status(200).json(data);
66873
+ } catch (error2) {
66874
+ logger193.log({ level: "error", message: error2.message });
66875
+ next(error2);
66876
+ }
66877
+ }
66878
+ async function getChatLists(req, res, next) {
66879
+ const querySchema = Joi144.object({
66880
+ currentUserId: Joi144.string().hex().length(24).required(),
66881
+ page: Joi144.number().integer().min(1).default(1),
66882
+ limit: Joi144.number().integer().min(1).max(100).default(10),
66883
+ search: Joi144.string().optional().allow("", null)
66884
+ });
66885
+ const { error, value } = querySchema.validate(req.query);
66886
+ if (error) {
66887
+ logger193.log({ level: "error", message: error.message });
66888
+ next(new BadRequestError223(error.message));
66889
+ return;
66890
+ }
66891
+ try {
66892
+ const data = await _getChatLists(
66893
+ value.currentUserId,
66894
+ value.page,
66895
+ value.limit,
66896
+ value.search || void 0
66897
+ );
66898
+ res.status(200).json(data);
66899
+ } catch (error2) {
66900
+ logger193.log({ level: "error", message: error2.message });
66901
+ next(error2);
66902
+ }
66903
+ }
66904
+ return { add, getChannel, getChatLists, getChannelMessages };
66525
66905
  }
66526
66906
 
66527
66907
  // src/models/online-forms-v2.model.ts
@@ -66754,7 +67134,23 @@ function useFormEntryRepo() {
66754
67134
  { $match: query },
66755
67135
  { $sort: sort },
66756
67136
  { $skip: page * limit },
66757
- { $limit: limit }
67137
+ { $limit: limit },
67138
+ {
67139
+ $lookup: {
67140
+ from: "users",
67141
+ localField: "userId",
67142
+ foreignField: "_id",
67143
+ as: "user",
67144
+ pipeline: [{ $project: { name: 1 } }]
67145
+ }
67146
+ },
67147
+ { $unwind: { path: "$user", preserveNullAndEmptyArrays: true } },
67148
+ {
67149
+ $addFields: {
67150
+ name: { $ifNull: ["$user.name", "$name"] }
67151
+ }
67152
+ },
67153
+ { $project: { user: 0 } }
66758
67154
  ]).toArray();
66759
67155
  const length = await collection.countDocuments(query);
66760
67156
  const data = paginate64(items, page, limit, length);
@@ -67524,7 +67920,6 @@ export {
67524
67920
  building_units_namespace_collection,
67525
67921
  buildings_namespace_collection,
67526
67922
  bulletin_boards_namespace_collection,
67527
- calculatePercentage,
67528
67923
  chatSchema,
67529
67924
  createManpowerRemarksDaily,
67530
67925
  customerSchema,
@@ -67535,7 +67930,6 @@ export {
67535
67930
  feedbacks2_namespace_collection,
67536
67931
  feedbacks_namespace_collection,
67537
67932
  formatDahuaDate,
67538
- getPeriodRangeWithPrevious,
67539
67933
  guests_namespace_collection,
67540
67934
  incidentReportLog,
67541
67935
  incidents_namespace_collection,