@lyxa.ai/marketing 1.0.53 → 1.0.55

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 (170) hide show
  1. package/dist/lib/index.d.ts +679 -28
  2. package/dist/lib/index.d.ts.map +1 -1
  3. package/dist/lib/index.js +2 -2
  4. package/dist/lib/index.js.map +1 -1
  5. package/dist/lib/modules/coupon/routers/coupon.router.d.ts +651 -0
  6. package/dist/lib/modules/coupon/routers/coupon.router.d.ts.map +1 -1
  7. package/dist/lib/modules/coupon/routers/coupon.router.js +8 -1
  8. package/dist/lib/modules/coupon/routers/coupon.router.js.map +1 -1
  9. package/dist/lib/modules/coupon/services/coupon.service.d.ts +8 -1
  10. package/dist/lib/modules/coupon/services/coupon.service.d.ts.map +1 -1
  11. package/dist/lib/modules/coupon/services/coupon.service.js +234 -27
  12. package/dist/lib/modules/coupon/services/coupon.service.js.map +1 -1
  13. package/dist/lib/modules/coupon/services/custom-coupon.service.d.ts +5 -0
  14. package/dist/lib/modules/coupon/services/custom-coupon.service.d.ts.map +1 -1
  15. package/dist/lib/modules/coupon/services/helper.service.d.ts +5 -0
  16. package/dist/lib/modules/coupon/services/helper.service.d.ts.map +1 -1
  17. package/dist/lib/modules/coupon/services/individual-store-coupon.service.d.ts +5 -0
  18. package/dist/lib/modules/coupon/services/individual-store-coupon.service.d.ts.map +1 -1
  19. package/dist/lib/modules/coupon/services/patterns/repository/CouponMetricsRepository.d.ts +1 -0
  20. package/dist/lib/modules/coupon/services/patterns/repository/CouponMetricsRepository.d.ts.map +1 -1
  21. package/dist/lib/modules/coupon/services/patterns/repository/CouponMetricsRepository.js +27 -9
  22. package/dist/lib/modules/coupon/services/patterns/repository/CouponMetricsRepository.js.map +1 -1
  23. package/dist/lib/modules/coupon/services/shops-categories-coupon.service.d.ts +5 -0
  24. package/dist/lib/modules/coupon/services/shops-categories-coupon.service.d.ts.map +1 -1
  25. package/dist/lib/modules/coupon/validations/all-coupons.validation.d.ts +293 -1125
  26. package/dist/lib/modules/coupon/validations/all-coupons.validation.d.ts.map +1 -1
  27. package/dist/lib/modules/coupon/validations/all-coupons.validation.js +2 -16
  28. package/dist/lib/modules/coupon/validations/all-coupons.validation.js.map +1 -1
  29. package/dist/lib/modules/coupon/validations/coupon.validation.d.ts +44 -0
  30. package/dist/lib/modules/coupon/validations/coupon.validation.d.ts.map +1 -1
  31. package/dist/lib/modules/coupon/validations/coupon.validation.js +16 -1
  32. package/dist/lib/modules/coupon/validations/coupon.validation.js.map +1 -1
  33. package/dist/lib/modules/coupon/validations/create-coupon.validation.d.ts.map +1 -1
  34. package/dist/lib/modules/coupon/validations/create-coupon.validation.js +4 -1
  35. package/dist/lib/modules/coupon/validations/create-coupon.validation.js.map +1 -1
  36. package/dist/lib/modules/coupon/validations/index.d.ts +1 -0
  37. package/dist/lib/modules/coupon/validations/index.d.ts.map +1 -1
  38. package/dist/lib/modules/coupon/validations/index.js +1 -0
  39. package/dist/lib/modules/coupon/validations/index.js.map +1 -1
  40. package/dist/lib/modules/limited-time-offer/campaign/campaign.router.d.ts +8 -8
  41. package/dist/lib/modules/limited-time-offer/campaign/limited-time-offer-campaign.validation.d.ts +34 -34
  42. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.validation.d.ts +9 -1
  43. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.validation.d.ts.map +1 -1
  44. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.validation.js +26 -3
  45. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.validation.js.map +1 -1
  46. package/dist/lib/modules/limited-time-offer/limited-time-offer.router.d.ts +28 -28
  47. package/dist/lib/modules/limited-time-offer/limited-time-offer.service.d.ts +1 -0
  48. package/dist/lib/modules/limited-time-offer/limited-time-offer.service.d.ts.map +1 -1
  49. package/dist/lib/modules/limited-time-offer/limited-time-offer.service.js +6 -0
  50. package/dist/lib/modules/limited-time-offer/limited-time-offer.service.js.map +1 -1
  51. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.builder.d.ts +13 -0
  52. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.builder.d.ts.map +1 -0
  53. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.builder.js +22 -0
  54. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.builder.js.map +1 -0
  55. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.constants.d.ts +20 -0
  56. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.constants.d.ts.map +1 -0
  57. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.constants.js +26 -0
  58. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.constants.js.map +1 -0
  59. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.service.d.ts +8 -0
  60. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.service.d.ts.map +1 -0
  61. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.service.js +60 -0
  62. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.service.js.map +1 -0
  63. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.type.d.ts +5 -0
  64. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.type.d.ts.map +1 -0
  65. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.type.js +3 -0
  66. package/dist/lib/modules/limited-time-offer/notification/limited-time-offer-notification.type.js.map +1 -0
  67. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.builder.js +1 -1
  68. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.builder.js.map +1 -1
  69. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.repository.d.ts +1 -0
  70. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.repository.d.ts.map +1 -1
  71. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.repository.js +8 -1
  72. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.repository.js.map +1 -1
  73. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.router.d.ts +20 -20
  74. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.validation.d.ts +82 -82
  75. package/dist/lib/modules/limited-time-offer/participant/services/limited-time-offer-participant.service.d.ts +2 -1
  76. package/dist/lib/modules/limited-time-offer/participant/services/limited-time-offer-participant.service.d.ts.map +1 -1
  77. package/dist/lib/modules/limited-time-offer/participant/services/limited-time-offer-participant.service.js +12 -5
  78. package/dist/lib/modules/limited-time-offer/participant/services/limited-time-offer-participant.service.js.map +1 -1
  79. package/dist/lib/modules/marketing/services/marketing.service.d.ts +1 -0
  80. package/dist/lib/modules/marketing/services/marketing.service.d.ts.map +1 -1
  81. package/dist/lib/modules/marketing/services/marketing.service.js +9 -0
  82. package/dist/lib/modules/marketing/services/marketing.service.js.map +1 -1
  83. package/dist/lib/modules/tournament/match/events/evaluate-predictions.consumer.js +1 -1
  84. package/dist/lib/modules/tournament/match/events/evaluate-predictions.consumer.js.map +1 -1
  85. package/dist/lib/modules/tournament/notification/__tests__/notification.service.spec.d.ts +2 -0
  86. package/dist/lib/modules/tournament/notification/__tests__/notification.service.spec.d.ts.map +1 -0
  87. package/dist/lib/modules/tournament/notification/__tests__/notification.service.spec.js +266 -0
  88. package/dist/lib/modules/tournament/notification/__tests__/notification.service.spec.js.map +1 -0
  89. package/dist/lib/modules/tournament/notification/notification.service.d.ts +14 -3
  90. package/dist/lib/modules/tournament/notification/notification.service.d.ts.map +1 -1
  91. package/dist/lib/modules/tournament/notification/notification.service.js +89 -31
  92. package/dist/lib/modules/tournament/notification/notification.service.js.map +1 -1
  93. package/dist/lib/modules/tournament/participant/participant.repository.d.ts +1 -0
  94. package/dist/lib/modules/tournament/participant/participant.repository.d.ts.map +1 -1
  95. package/dist/lib/modules/tournament/participant/participant.repository.js +9 -0
  96. package/dist/lib/modules/tournament/participant/participant.repository.js.map +1 -1
  97. package/dist/lib/modules/tournament/participant/participant.service.d.ts +1 -0
  98. package/dist/lib/modules/tournament/participant/participant.service.d.ts.map +1 -1
  99. package/dist/lib/modules/tournament/participant/participant.service.js +6 -0
  100. package/dist/lib/modules/tournament/participant/participant.service.js.map +1 -1
  101. package/dist/lib/modules/tournament/reward/reward.builder.d.ts.map +1 -1
  102. package/dist/lib/modules/tournament/reward/reward.builder.js +3 -3
  103. package/dist/lib/modules/tournament/reward/reward.builder.js.map +1 -1
  104. package/dist/lib/modules/tournament/reward/reward.types.d.ts +1 -0
  105. package/dist/lib/modules/tournament/reward/reward.types.d.ts.map +1 -1
  106. package/dist/lib/modules/tournament/reward/reward.types.js.map +1 -1
  107. package/dist/lib/modules/tournament/schedule/schedule.service.d.ts +7 -0
  108. package/dist/lib/modules/tournament/schedule/schedule.service.d.ts.map +1 -1
  109. package/dist/lib/modules/tournament/schedule/schedule.service.js +52 -19
  110. package/dist/lib/modules/tournament/schedule/schedule.service.js.map +1 -1
  111. package/dist/lib/utility/utils.js +2 -2
  112. package/dist/lib/utility/utils.js.map +1 -1
  113. package/dist/types/index.d.ts +679 -28
  114. package/dist/types/index.d.ts.map +1 -1
  115. package/dist/types/modules/coupon/routers/coupon.router.d.ts +651 -0
  116. package/dist/types/modules/coupon/routers/coupon.router.d.ts.map +1 -1
  117. package/dist/types/modules/coupon/services/coupon.service.d.ts +8 -1
  118. package/dist/types/modules/coupon/services/coupon.service.d.ts.map +1 -1
  119. package/dist/types/modules/coupon/services/custom-coupon.service.d.ts +5 -0
  120. package/dist/types/modules/coupon/services/custom-coupon.service.d.ts.map +1 -1
  121. package/dist/types/modules/coupon/services/helper.service.d.ts +5 -0
  122. package/dist/types/modules/coupon/services/helper.service.d.ts.map +1 -1
  123. package/dist/types/modules/coupon/services/individual-store-coupon.service.d.ts +5 -0
  124. package/dist/types/modules/coupon/services/individual-store-coupon.service.d.ts.map +1 -1
  125. package/dist/types/modules/coupon/services/patterns/repository/CouponMetricsRepository.d.ts +1 -0
  126. package/dist/types/modules/coupon/services/patterns/repository/CouponMetricsRepository.d.ts.map +1 -1
  127. package/dist/types/modules/coupon/services/shops-categories-coupon.service.d.ts +5 -0
  128. package/dist/types/modules/coupon/services/shops-categories-coupon.service.d.ts.map +1 -1
  129. package/dist/types/modules/coupon/validations/all-coupons.validation.d.ts +293 -1125
  130. package/dist/types/modules/coupon/validations/all-coupons.validation.d.ts.map +1 -1
  131. package/dist/types/modules/coupon/validations/coupon.validation.d.ts +44 -0
  132. package/dist/types/modules/coupon/validations/coupon.validation.d.ts.map +1 -1
  133. package/dist/types/modules/coupon/validations/create-coupon.validation.d.ts.map +1 -1
  134. package/dist/types/modules/coupon/validations/index.d.ts +1 -0
  135. package/dist/types/modules/coupon/validations/index.d.ts.map +1 -1
  136. package/dist/types/modules/limited-time-offer/campaign/campaign.router.d.ts +8 -8
  137. package/dist/types/modules/limited-time-offer/campaign/limited-time-offer-campaign.validation.d.ts +34 -34
  138. package/dist/types/modules/limited-time-offer/config/limited-time-offer-config.validation.d.ts +9 -1
  139. package/dist/types/modules/limited-time-offer/config/limited-time-offer-config.validation.d.ts.map +1 -1
  140. package/dist/types/modules/limited-time-offer/limited-time-offer.router.d.ts +28 -28
  141. package/dist/types/modules/limited-time-offer/limited-time-offer.service.d.ts +1 -0
  142. package/dist/types/modules/limited-time-offer/limited-time-offer.service.d.ts.map +1 -1
  143. package/dist/types/modules/limited-time-offer/notification/limited-time-offer-notification.builder.d.ts +13 -0
  144. package/dist/types/modules/limited-time-offer/notification/limited-time-offer-notification.builder.d.ts.map +1 -0
  145. package/dist/types/modules/limited-time-offer/notification/limited-time-offer-notification.constants.d.ts +20 -0
  146. package/dist/types/modules/limited-time-offer/notification/limited-time-offer-notification.constants.d.ts.map +1 -0
  147. package/dist/types/modules/limited-time-offer/notification/limited-time-offer-notification.service.d.ts +8 -0
  148. package/dist/types/modules/limited-time-offer/notification/limited-time-offer-notification.service.d.ts.map +1 -0
  149. package/dist/types/modules/limited-time-offer/notification/limited-time-offer-notification.type.d.ts +5 -0
  150. package/dist/types/modules/limited-time-offer/notification/limited-time-offer-notification.type.d.ts.map +1 -0
  151. package/dist/types/modules/limited-time-offer/participant/limited-time-offer-participant.repository.d.ts +1 -0
  152. package/dist/types/modules/limited-time-offer/participant/limited-time-offer-participant.repository.d.ts.map +1 -1
  153. package/dist/types/modules/limited-time-offer/participant/limited-time-offer-participant.router.d.ts +20 -20
  154. package/dist/types/modules/limited-time-offer/participant/limited-time-offer-participant.validation.d.ts +82 -82
  155. package/dist/types/modules/limited-time-offer/participant/services/limited-time-offer-participant.service.d.ts +2 -1
  156. package/dist/types/modules/limited-time-offer/participant/services/limited-time-offer-participant.service.d.ts.map +1 -1
  157. package/dist/types/modules/marketing/services/marketing.service.d.ts +1 -0
  158. package/dist/types/modules/marketing/services/marketing.service.d.ts.map +1 -1
  159. package/dist/types/modules/tournament/notification/notification.service.d.ts +14 -3
  160. package/dist/types/modules/tournament/notification/notification.service.d.ts.map +1 -1
  161. package/dist/types/modules/tournament/participant/participant.repository.d.ts +1 -0
  162. package/dist/types/modules/tournament/participant/participant.repository.d.ts.map +1 -1
  163. package/dist/types/modules/tournament/participant/participant.service.d.ts +1 -0
  164. package/dist/types/modules/tournament/participant/participant.service.d.ts.map +1 -1
  165. package/dist/types/modules/tournament/reward/reward.builder.d.ts.map +1 -1
  166. package/dist/types/modules/tournament/reward/reward.types.d.ts +1 -0
  167. package/dist/types/modules/tournament/reward/reward.types.d.ts.map +1 -1
  168. package/dist/types/modules/tournament/schedule/schedule.service.d.ts +7 -0
  169. package/dist/types/modules/tournament/schedule/schedule.service.d.ts.map +1 -1
  170. package/package.json +3 -3
@@ -1,15 +1,26 @@
1
1
  import { mongoose } from '@typegoose/typegoose';
2
2
  import { TournamentNotificationTag, TournamentScheduledNotificationTarget } from '@lyxa.ai/core/dist/utilities/enum';
3
- import { NotificationMessage } from '@lyxa.ai/core/dist/libraries/mongo/models';
3
+ import { NotificationMessage, TournamentMatch } from '@lyxa.ai/core/dist/libraries/mongo/models';
4
+ import { TournamentDocument } from '../config/config.types';
4
5
  import { NotificationObject } from './notification.config';
6
+ export interface ScheduledReminderContext {
7
+ type: TournamentNotificationTag;
8
+ target: TournamentScheduledNotificationTarget;
9
+ templates: Map<TournamentNotificationTag, NotificationMessage>;
10
+ tournament: TournamentDocument;
11
+ match: TournamentMatch;
12
+ }
5
13
  export declare class TournamentNotificationService {
6
14
  private participantService;
7
15
  constructor();
8
16
  private getTemplate;
9
- private hasNotPredicted;
10
17
  notifyGlobal(notification: NotificationObject): Promise<void>;
11
18
  notifyUsers(notification: NotificationObject, userIds: mongoose.Types.ObjectId[]): Promise<void>;
12
- dispatchScheduledJob(type: TournamentNotificationTag, target: TournamentScheduledNotificationTarget, templates: Map<TournamentNotificationTag, NotificationMessage>, tournamentId: mongoose.Types.ObjectId, teamIds: mongoose.Types.ObjectId[], matchId: mongoose.Types.ObjectId, matchStartTime: Date, deepLinkRoute?: string): Promise<void>;
19
+ dispatchScheduledReminder(ctx: ScheduledReminderContext): Promise<void>;
20
+ private resolveReminderRecipients;
21
+ private buildBaseMessage;
22
+ private buildTargetedMessage;
23
+ private withTeamNames;
13
24
  }
14
25
  export declare const tournamentNotificationService: TournamentNotificationService;
15
26
  //# sourceMappingURL=notification.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"notification.service.d.ts","sourceRoot":"/","sources":["modules/tournament/notification/notification.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAG9C,OAAO,EAGH,yBAAyB,EACzB,qCAAqC,EACxC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAC,mBAAmB,EAAC,MAAM,2CAA2C,CAAC;AAG9E,OAAO,EAAC,kBAAkB,EAAC,MAAM,uBAAuB,CAAC;AAEzD,qBACa,6BAA6B;IACtC,OAAO,CAAC,kBAAkB,CAAqB;;IAM/C,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,eAAe;IAIV,YAAY,CAAC,YAAY,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB7D,WAAW,CAAC,YAAY,EAAE,kBAAkB,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBhG,oBAAoB,CAC7B,IAAI,EAAE,yBAAyB,EAC/B,MAAM,EAAE,qCAAqC,EAC7C,SAAS,EAAE,GAAG,CAAC,yBAAyB,EAAE,mBAAmB,CAAC,EAC9D,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,EAClC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAChC,cAAc,EAAE,IAAI,EACpB,aAAa,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC;CAqBnB;AAED,eAAO,MAAM,6BAA6B,+BAA+C,CAAC"}
1
+ {"version":3,"file":"notification.service.d.ts","sourceRoot":"/","sources":["modules/tournament/notification/notification.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAI9C,OAAO,EAGH,yBAAyB,EACzB,qCAAqC,EACxC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAC,mBAAmB,EAAE,eAAe,EAAC,MAAM,2CAA2C,CAAC;AAG/F,OAAO,EAAC,kBAAkB,EAAC,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAC,kBAAkB,EAAC,MAAM,uBAAuB,CAAC;AAEzD,MAAM,WAAW,wBAAwB;IACrC,IAAI,EAAE,yBAAyB,CAAC;IAChC,MAAM,EAAE,qCAAqC,CAAC;IAC9C,SAAS,EAAE,GAAG,CAAC,yBAAyB,EAAE,mBAAmB,CAAC,CAAC;IAC/D,UAAU,EAAE,kBAAkB,CAAC;IAC/B,KAAK,EAAE,eAAe,CAAC;CAC1B;AAED,qBACa,6BAA6B;IACtC,OAAO,CAAC,kBAAkB,CAAqB;;IAM/C,OAAO,CAAC,WAAW;IAMN,YAAY,CAAC,YAAY,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB7D,WAAW,CAAC,YAAY,EAAE,kBAAkB,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA6DhG,yBAAyB,CAAC,GAAG,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;IAYpF,OAAO,CAAC,yBAAyB;IAcjC,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,aAAa;CAKxB;AAED,eAAO,MAAM,6BAA6B,+BAA+C,CAAC"}
@@ -44,6 +44,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
44
44
  Object.defineProperty(exports, "__esModule", { value: true });
45
45
  exports.tournamentNotificationService = exports.TournamentNotificationService = void 0;
46
46
  const typedi_1 = __importStar(require("typedi"));
47
+ const core_1 = require("@lyxa.ai/core");
47
48
  const event_1 = require("@lyxa.ai/core/dist/libraries/event");
48
49
  const notification_1 = require("@lyxa.ai/core/dist/libraries/notification");
49
50
  const enum_1 = require("@lyxa.ai/core/dist/utilities/enum");
@@ -59,9 +60,6 @@ let TournamentNotificationService = class TournamentNotificationService {
59
60
  throw new Error(`No notification template for tag: ${tag}`);
60
61
  return t;
61
62
  }
62
- hasNotPredicted(participant, matchId) {
63
- return !participant.predictions.some(p => p.matchId.toString() === matchId.toString());
64
- }
65
63
  async notifyGlobal(notification) {
66
64
  await (0, event_1.publishEvent)(new notification_1.NotificationGlobalEvent({
67
65
  title: notification.title,
@@ -77,37 +75,97 @@ let TournamentNotificationService = class TournamentNotificationService {
77
75
  }));
78
76
  }
79
77
  async notifyUsers(notification, userIds) {
80
- await Promise.all(userIds.map(recipientId => (0, event_1.publishEvent)(new notification_1.NotificationEvent({
81
- title: notification.title,
82
- body: notification.body,
83
- data: {
84
- saveNotification: true,
85
- accountType: enum_1.NotificationAccountType.USER,
86
- recipientId,
87
- isGlobal: false,
88
- isClickable: true,
89
- clickType: enum_1.ClickType.CLICKABLE_TOURNAMENT,
90
- ...notification,
91
- },
92
- }))));
78
+ const logger = (0, core_1.getLibraries)().getLoggerKit();
79
+ try {
80
+ await Promise.all(userIds.map(recipientId => (0, event_1.publishEvent)(new notification_1.NotificationEvent({
81
+ title: notification.title,
82
+ body: notification.body,
83
+ data: {
84
+ saveNotification: true,
85
+ accountType: enum_1.NotificationAccountType.USER,
86
+ recipientId,
87
+ isGlobal: false,
88
+ isClickable: true,
89
+ clickType: enum_1.ClickType.CLICKABLE_TOURNAMENT,
90
+ ...notification,
91
+ },
92
+ }))));
93
+ logger.info('Tournament user notifications dispatched', {
94
+ tag: 'notification.queue.tournament',
95
+ data: {
96
+ payload: {
97
+ saveNotification: true,
98
+ accountType: enum_1.NotificationAccountType.USER,
99
+ userIds,
100
+ isGlobal: false,
101
+ isClickable: true,
102
+ clickType: enum_1.ClickType.CLICKABLE_TOURNAMENT,
103
+ ...notification,
104
+ },
105
+ tournamentId: notification.tournamentId,
106
+ type: notification.tournamentNotificationType,
107
+ recipientCount: userIds.length,
108
+ },
109
+ });
110
+ }
111
+ catch (error) {
112
+ logger.error('Failed to dispatch tournament user notifications', error, {
113
+ tag: 'notification.queue.tournament',
114
+ data: {
115
+ tournamentId: notification.tournamentId,
116
+ type: notification.tournamentNotificationType,
117
+ recipientCount: userIds.length,
118
+ payload: {
119
+ saveNotification: true,
120
+ accountType: enum_1.NotificationAccountType.USER,
121
+ userIds,
122
+ isGlobal: false,
123
+ isClickable: true,
124
+ clickType: enum_1.ClickType.CLICKABLE_TOURNAMENT,
125
+ ...notification,
126
+ },
127
+ },
128
+ });
129
+ }
93
130
  }
94
- async dispatchScheduledJob(type, target, templates, tournamentId, teamIds, matchId, matchStartTime, deepLinkRoute) {
95
- const { title, body } = this.getTemplate(templates, type);
96
- if (target === enum_1.TournamentScheduledNotificationTarget.GLOBAL) {
97
- await this.notifyGlobal({ title, body, tournamentNotificationType: type, tournamentId: tournamentId.toString(), deepLinkRoute });
131
+ async dispatchScheduledReminder(ctx) {
132
+ if (ctx.target === enum_1.TournamentScheduledNotificationTarget.GLOBAL) {
133
+ await this.notifyGlobal(this.buildBaseMessage(ctx));
134
+ return;
98
135
  }
99
- else {
100
- const unpredicted = await this.participantService.getUnpredicted(tournamentId, teamIds, matchId);
101
- await this.notifyUsers({
102
- title,
103
- body,
104
- tournamentNotificationType: type,
105
- predictionExpiryTime: matchStartTime,
106
- matchId: matchId.toString(),
107
- tournamentId: tournamentId.toString(),
108
- deepLinkRoute,
109
- }, unpredicted.map(p => p.userId));
136
+ const recipients = await this.resolveReminderRecipients(ctx);
137
+ if (!recipients.length)
138
+ return;
139
+ await this.notifyUsers(this.buildTargetedMessage(ctx), recipients.map(p => p.userId));
140
+ }
141
+ resolveReminderRecipients(ctx) {
142
+ const { tournament, match, type } = ctx;
143
+ if (type === enum_1.TournamentNotificationTag.PREDICTION_REMINDER_1_HOUR) {
144
+ return this.participantService.getPredicted(tournament._id, match._id);
110
145
  }
146
+ return this.participantService.getUnpredicted(tournament._id, [match.team1.teamId, match.team2.teamId], match._id);
147
+ }
148
+ buildBaseMessage(ctx) {
149
+ const { title, body } = this.getTemplate(ctx.templates, ctx.type);
150
+ return {
151
+ title: this.withTeamNames(title, ctx.match),
152
+ body: this.withTeamNames(body, ctx.match),
153
+ tournamentNotificationType: ctx.type,
154
+ tournamentId: ctx.tournament._id.toString(),
155
+ deepLinkRoute: ctx.tournament.deepLinkRoute,
156
+ };
157
+ }
158
+ buildTargetedMessage(ctx) {
159
+ return {
160
+ ...this.buildBaseMessage(ctx),
161
+ matchId: ctx.match._id.toString(),
162
+ predictionExpiryTime: ctx.match.startingDate,
163
+ };
164
+ }
165
+ withTeamNames(text, match) {
166
+ return text
167
+ .replace(/{team1}/g, match.team1.name)
168
+ .replace(/{team2}/g, match.team2.name);
111
169
  }
112
170
  };
113
171
  exports.TournamentNotificationService = TournamentNotificationService;
@@ -1 +1 @@
1
- {"version":3,"file":"notification.service.js","sourceRoot":"/","sources":["modules/tournament/notification/notification.service.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, {Service} from 'typedi';\nimport {mongoose} from '@typegoose/typegoose';\nimport {publishEvent} from '@lyxa.ai/core/dist/libraries/event';\nimport {NotificationEvent, NotificationGlobalEvent} from '@lyxa.ai/core/dist/libraries/notification';\nimport {\n ClickType,\n NotificationAccountType,\n TournamentNotificationTag,\n TournamentScheduledNotificationTarget\n} from '@lyxa.ai/core/dist/utilities/enum';\nimport {NotificationMessage} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport {ParticipantService} from '../participant/participant.service';\nimport {TournamentParticipantOutputDTO} from '../participant/participant.validation';\nimport {NotificationObject} from './notification.config';\n\n@Service()\nexport class TournamentNotificationService {\n private participantService: ParticipantService;\n\n constructor() {\n this.participantService = Container.get(ParticipantService);\n }\n\n private getTemplate(templates: Map<string, NotificationMessage>, tag: string): NotificationMessage {\n const t = templates.get(tag);\n if (!t) throw new Error(`No notification template for tag: ${tag}`);\n return t;\n }\n\n private hasNotPredicted(participant: TournamentParticipantOutputDTO, matchId: mongoose.Types.ObjectId): boolean {\n return !participant.predictions.some(p => p.matchId.toString() === matchId.toString());\n }\n\n public async notifyGlobal(notification: NotificationObject): Promise<void> {\n await publishEvent(\n new NotificationGlobalEvent({\n title: notification.title,\n body: notification.body,\n data: {\n saveNotification: true,\n accountType: NotificationAccountType.USER,\n isGlobal: true,\n isClickable: true,\n clickType: ClickType.CLICKABLE_TOURNAMENT,\n ...notification,\n },\n })\n );\n }\n\n public async notifyUsers(notification: NotificationObject, userIds: mongoose.Types.ObjectId[]): Promise<void> {\n await Promise.all(\n userIds.map(recipientId =>\n publishEvent(\n new NotificationEvent({\n title: notification.title,\n body: notification.body,\n data: {\n saveNotification: true,\n accountType: NotificationAccountType.USER,\n recipientId,\n isGlobal: false,\n isClickable: true,\n clickType: ClickType.CLICKABLE_TOURNAMENT,\n ...notification,\n },\n })\n )\n )\n );\n }\n\n public async dispatchScheduledJob(\n type: TournamentNotificationTag,\n target: TournamentScheduledNotificationTarget,\n templates: Map<TournamentNotificationTag, NotificationMessage>,\n tournamentId: mongoose.Types.ObjectId,\n teamIds: mongoose.Types.ObjectId[],\n matchId: mongoose.Types.ObjectId,\n matchStartTime: Date,\n deepLinkRoute?: string\n ): Promise<void> {\n const {title, body} = this.getTemplate(templates, type);\n\n if (target === TournamentScheduledNotificationTarget.GLOBAL) {\n await this.notifyGlobal({title, body, tournamentNotificationType: type, tournamentId: tournamentId.toString(), deepLinkRoute});\n } else {\n const unpredicted = await this.participantService.getUnpredicted(tournamentId, teamIds, matchId);\n await this.notifyUsers(\n {\n title,\n body,\n tournamentNotificationType: type,\n predictionExpiryTime: matchStartTime,\n matchId: matchId.toString(),\n tournamentId: tournamentId.toString(),\n deepLinkRoute,\n },\n unpredicted.map(p => p.userId)\n );\n }\n }\n}\n\nexport const tournamentNotificationService = Container.get(TournamentNotificationService);\n"]}
1
+ {"version":3,"file":"notification.service.js","sourceRoot":"/","sources":["modules/tournament/notification/notification.service.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, {Service} from 'typedi';\nimport {mongoose} from '@typegoose/typegoose';\nimport {getLibraries} from '@lyxa.ai/core';\nimport {publishEvent} from '@lyxa.ai/core/dist/libraries/event';\nimport {NotificationEvent, NotificationGlobalEvent} from '@lyxa.ai/core/dist/libraries/notification';\nimport {\n ClickType,\n NotificationAccountType,\n TournamentNotificationTag,\n TournamentScheduledNotificationTarget\n} from '@lyxa.ai/core/dist/utilities/enum';\nimport {NotificationMessage, TournamentMatch} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport {ParticipantService} from '../participant/participant.service';\nimport {TournamentParticipantOutputDTO} from '../participant/participant.validation';\nimport {TournamentDocument} from '../config/config.types';\nimport {NotificationObject} from './notification.config';\n\nexport interface ScheduledReminderContext {\n type: TournamentNotificationTag;\n target: TournamentScheduledNotificationTarget;\n templates: Map<TournamentNotificationTag, NotificationMessage>;\n tournament: TournamentDocument;\n match: TournamentMatch;\n}\n\n@Service()\nexport class TournamentNotificationService {\n private participantService: ParticipantService;\n\n constructor() {\n this.participantService = Container.get(ParticipantService);\n }\n\n private getTemplate(templates: Map<string, NotificationMessage>, tag: string): NotificationMessage {\n const t = templates.get(tag);\n if (!t) throw new Error(`No notification template for tag: ${tag}`);\n return t;\n }\n\n public async notifyGlobal(notification: NotificationObject): Promise<void> {\n await publishEvent(\n new NotificationGlobalEvent({\n title: notification.title,\n body: notification.body,\n data: {\n saveNotification: true,\n accountType: NotificationAccountType.USER,\n isGlobal: true,\n isClickable: true,\n clickType: ClickType.CLICKABLE_TOURNAMENT,\n ...notification,\n },\n })\n );\n }\n\n public async notifyUsers(notification: NotificationObject, userIds: mongoose.Types.ObjectId[]): Promise<void> {\n const logger = getLibraries().getLoggerKit();\n try {\n await Promise.all(\n userIds.map(recipientId =>\n publishEvent(\n new NotificationEvent({\n title: notification.title,\n body: notification.body,\n data: {\n saveNotification: true,\n accountType: NotificationAccountType.USER,\n recipientId,\n isGlobal: false,\n isClickable: true,\n clickType: ClickType.CLICKABLE_TOURNAMENT,\n ...notification,\n },\n })\n )\n )\n );\n\n logger.info('Tournament user notifications dispatched', {\n tag: 'notification.queue.tournament',\n data: {\n payload: {\n saveNotification: true,\n accountType: NotificationAccountType.USER,\n userIds,\n isGlobal: false,\n isClickable: true,\n clickType: ClickType.CLICKABLE_TOURNAMENT,\n ...notification,\n },\n tournamentId: notification.tournamentId,\n type: notification.tournamentNotificationType,\n recipientCount: userIds.length,\n },\n });\n } catch (error) {\n logger.error('Failed to dispatch tournament user notifications', error, {\n tag: 'notification.queue.tournament',\n data: {\n tournamentId: notification.tournamentId,\n type: notification.tournamentNotificationType,\n recipientCount: userIds.length,\n payload: {\n saveNotification: true,\n accountType: NotificationAccountType.USER,\n userIds,\n isGlobal: false,\n isClickable: true,\n clickType: ClickType.CLICKABLE_TOURNAMENT,\n ...notification,\n },\n },\n });\n }\n }\n\n public async dispatchScheduledReminder(ctx: ScheduledReminderContext): Promise<void> {\n if (ctx.target === TournamentScheduledNotificationTarget.GLOBAL) {\n await this.notifyGlobal(this.buildBaseMessage(ctx));\n return;\n }\n\n const recipients = await this.resolveReminderRecipients(ctx);\n if (!recipients.length) return;\n\n await this.notifyUsers(this.buildTargetedMessage(ctx), recipients.map(p => p.userId));\n }\n\n private resolveReminderRecipients(ctx: ScheduledReminderContext): Promise<TournamentParticipantOutputDTO[]> {\n const {tournament, match, type} = ctx;\n\n if (type === TournamentNotificationTag.PREDICTION_REMINDER_1_HOUR) {\n return this.participantService.getPredicted(tournament._id, match._id);\n }\n\n return this.participantService.getUnpredicted(\n tournament._id,\n [match.team1.teamId, match.team2.teamId],\n match._id\n );\n }\n\n private buildBaseMessage(ctx: ScheduledReminderContext): NotificationObject {\n const {title, body} = this.getTemplate(ctx.templates, ctx.type);\n return {\n title: this.withTeamNames(title, ctx.match),\n body: this.withTeamNames(body, ctx.match),\n tournamentNotificationType: ctx.type,\n tournamentId: ctx.tournament._id.toString(),\n deepLinkRoute: ctx.tournament.deepLinkRoute,\n };\n }\n\n private buildTargetedMessage(ctx: ScheduledReminderContext): NotificationObject {\n return {\n ...this.buildBaseMessage(ctx),\n matchId: ctx.match._id.toString(),\n predictionExpiryTime: ctx.match.startingDate,\n };\n }\n\n private withTeamNames(text: string, match: TournamentMatch): string {\n return text\n .replace(/{team1}/g, match.team1.name)\n .replace(/{team2}/g, match.team2.name);\n }\n}\n\nexport const tournamentNotificationService = Container.get(TournamentNotificationService);\n"]}
@@ -11,6 +11,7 @@ export declare class TournamentParticipantRepository {
11
11
  updateToJoined(userId: mongoose.Types.ObjectId, tournamentId: mongoose.Types.ObjectId, teamId: mongoose.Types.ObjectId): Promise<TournamentParticipantOutputDTO | null>;
12
12
  createIfAbsent(userId: mongoose.Types.ObjectId, tournamentId: mongoose.Types.ObjectId, status: string): Promise<void>;
13
13
  findByTournamentWithoutPrediction(tournamentId: mongoose.Types.ObjectId, teamIds: mongoose.Types.ObjectId[], matchId: mongoose.Types.ObjectId): Promise<TournamentParticipantOutputDTO[]>;
14
+ findByTournamentWithPrediction(tournamentId: mongoose.Types.ObjectId, matchId: mongoose.Types.ObjectId): Promise<TournamentParticipantOutputDTO[]>;
14
15
  }
15
16
  export declare const tournamentParticipantRepository: TournamentParticipantRepository;
16
17
  //# sourceMappingURL=participant.repository.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"participant.repository.d.ts","sourceRoot":"/","sources":["modules/tournament/participant/participant.repository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAC;AAE1E,qBACa,+BAA+B;IACxC,OAAO,CAAC,gBAAgB,CAAoC;;IAMtD,yBAAyB,CAC3B,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAC/B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACtC,OAAO,CAAC,OAAO,CAAC;IAIb,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,8BAA8B,CAAC;IAK9D,uBAAuB,CACzB,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAC/B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACtC,OAAO,CAAC,8BAA8B,GAAG,IAAI,CAAC;IAI3C,gBAAgB,CAAC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,8BAA8B,EAAE,CAAC;IAIlG,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,8BAA8B,GAAG,IAAI,CAAC;IAO3F,cAAc,CAChB,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAC/B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAChC,OAAO,CAAC,8BAA8B,GAAG,IAAI,CAAC;IAM3C,cAAc,CAChB,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAC/B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,MAAM,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAQH,iCAAiC,CAC1C,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,EAClC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACjC,OAAO,CAAC,8BAA8B,EAAE,CAAC;CAW/C;AAED,eAAO,MAAM,+BAA+B,iCAAiD,CAAC"}
1
+ {"version":3,"file":"participant.repository.d.ts","sourceRoot":"/","sources":["modules/tournament/participant/participant.repository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAC;AAE1E,qBACa,+BAA+B;IACxC,OAAO,CAAC,gBAAgB,CAAoC;;IAMtD,yBAAyB,CAC3B,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAC/B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACtC,OAAO,CAAC,OAAO,CAAC;IAIb,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,8BAA8B,CAAC;IAK9D,uBAAuB,CACzB,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAC/B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACtC,OAAO,CAAC,8BAA8B,GAAG,IAAI,CAAC;IAI3C,gBAAgB,CAAC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,8BAA8B,EAAE,CAAC;IAIlG,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,8BAA8B,GAAG,IAAI,CAAC;IAO3F,cAAc,CAChB,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAC/B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAChC,OAAO,CAAC,8BAA8B,GAAG,IAAI,CAAC;IAM3C,cAAc,CAChB,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAC/B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,MAAM,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAQH,iCAAiC,CAC1C,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,EAClC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACjC,OAAO,CAAC,8BAA8B,EAAE,CAAC;IAW/B,8BAA8B,CACvC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACjC,OAAO,CAAC,8BAA8B,EAAE,CAAC;CAU/C;AAED,eAAO,MAAM,+BAA+B,iCAAiD,CAAC"}
@@ -87,6 +87,15 @@ let TournamentParticipantRepository = class TournamentParticipantRepository {
87
87
  .lean()
88
88
  .exec();
89
89
  }
90
+ async findByTournamentWithPrediction(tournamentId, matchId) {
91
+ return this.participantModel
92
+ .find({
93
+ tournamentId,
94
+ 'predictions.matchId': matchId,
95
+ })
96
+ .lean()
97
+ .exec();
98
+ }
90
99
  };
91
100
  exports.TournamentParticipantRepository = TournamentParticipantRepository;
92
101
  exports.TournamentParticipantRepository = TournamentParticipantRepository = __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"participant.repository.js","sourceRoot":"/","sources":["modules/tournament/participant/participant.repository.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAA4C;AAE5C,sEAAuF;AAIhF,IAAM,+BAA+B,GAArC,MAAM,+BAA+B;IAChC,gBAAgB,CAAoC;IAE5D;QACI,IAAI,CAAC,gBAAgB,GAAG,mCAA0B,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,yBAAyB,CAC3B,MAA+B,EAC/B,YAAqC;QAErC,OAAO,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACtB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtD,OAAO,GAAG,CAAC,QAAQ,EAA+C,CAAC;IACvE,CAAC;IAED,KAAK,CAAC,uBAAuB,CACzB,MAA+B,EAC/B,YAAqC;QAErC,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,IAAI,EAAoD,CAAC;IAC5H,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,YAAqC;QACxD,OAAO,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,IAAI,EAA+C,CAAC;IAC5G,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,MAA+B;QAC5C,OAAO,IAAI,CAAC,gBAAgB;aACvB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;aACnB,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC;aACvB,IAAI,EAAoD,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,cAAc,CAChB,MAA+B,EAC/B,YAAqC,EACrC,MAA+B;QAE/B,OAAO,IAAI,CAAC,gBAAgB;aACvB,gBAAgB,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;aACjG,IAAI,EAAoD,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,cAAc,CAChB,MAA+B,EAC/B,YAAqC,EACrC,MAAc;QAEd,MAAM,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,CACxC,EAAE,MAAM,EAAE,YAAY,EAAE,EACxB,EAAE,YAAY,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EACnE,EAAE,MAAM,EAAE,IAAI,EAAE,CACnB,CAAC;IACN,CAAC;IAEM,KAAK,CAAC,iCAAiC,CAC1C,YAAqC,EACrC,OAAkC,EAClC,OAAgC;QAEhC,OAAO,IAAI,CAAC,gBAAgB;aACvB,IAAI,CAAC;YACF,YAAY;YACZ,MAAM,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE;YACxB,qBAAqB,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE;SAC1C,CAAC;aACD,IAAI,EAAE;aACN,IAAI,EAA+C,CAAC;IAC7D,CAAC;CAEJ,CAAA;AA1EY,0EAA+B;0CAA/B,+BAA+B;IAD3C,IAAA,gBAAO,GAAE;;GACG,+BAA+B,CA0E3C;AAEY,QAAA,+BAA+B,GAAG,gBAAS,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC","sourcesContent":["import Container, { Service } from 'typedi';\nimport { mongoose } from '@typegoose/typegoose';\nimport { TournamentParticipantModel } from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport { TournamentParticipantOutputDTO } from './participant.validation';\n\n@Service()\nexport class TournamentParticipantRepository {\n private participantModel: typeof TournamentParticipantModel;\n\n constructor() {\n this.participantModel = TournamentParticipantModel;\n }\n\n async existsByUserAndTournament(\n userId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId\n ): Promise<boolean> {\n return !!(await this.participantModel.exists({ userId, tournamentId }));\n }\n\n async create(input: object): Promise<TournamentParticipantOutputDTO> {\n const doc = await this.participantModel.create(input);\n return doc.toObject() as unknown as TournamentParticipantOutputDTO;\n }\n\n async findByUserAndTournament(\n userId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId\n ): Promise<TournamentParticipantOutputDTO | null> {\n return this.participantModel.findOne({ userId, tournamentId }).lean() as Promise<TournamentParticipantOutputDTO | null>;\n }\n\n async findByTournament(tournamentId: mongoose.Types.ObjectId): Promise<TournamentParticipantOutputDTO[]> {\n return this.participantModel.find({ tournamentId }).lean() as Promise<TournamentParticipantOutputDTO[]>;\n }\n\n async findByUser(userId: mongoose.Types.ObjectId): Promise<TournamentParticipantOutputDTO | null> {\n return this.participantModel\n .findOne({ userId })\n .sort({ createdAt: -1 })\n .lean() as Promise<TournamentParticipantOutputDTO | null>;\n }\n\n async updateToJoined(\n userId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId,\n teamId: mongoose.Types.ObjectId\n ): Promise<TournamentParticipantOutputDTO | null> {\n return this.participantModel\n .findOneAndUpdate({ userId, tournamentId }, { $set: { status: 'joined', teamId } }, { new: true })\n .lean() as Promise<TournamentParticipantOutputDTO | null>;\n }\n\n async createIfAbsent(\n userId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId,\n status: string\n ): Promise<void> {\n await this.participantModel.findOneAndUpdate(\n { userId, tournamentId },\n { $setOnInsert: { userId, tournamentId, predictions: [], status } },\n { upsert: true }\n );\n }\n\n public async findByTournamentWithoutPrediction(\n tournamentId: mongoose.Types.ObjectId,\n teamIds: mongoose.Types.ObjectId[],\n matchId: mongoose.Types.ObjectId\n ): Promise<TournamentParticipantOutputDTO[]> {\n return this.participantModel\n .find({\n tournamentId,\n teamId: { $in: teamIds },\n 'predictions.matchId': { $ne: matchId },\n })\n .lean()\n .exec() as Promise<TournamentParticipantOutputDTO[]>;\n }\n\n}\n\nexport const tournamentParticipantRepository = Container.get(TournamentParticipantRepository);\n"]}
1
+ {"version":3,"file":"participant.repository.js","sourceRoot":"/","sources":["modules/tournament/participant/participant.repository.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, { Service } from 'typedi';\nimport { mongoose } from '@typegoose/typegoose';\nimport { TournamentParticipantModel } from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport { TournamentParticipantOutputDTO } from './participant.validation';\n\n@Service()\nexport class TournamentParticipantRepository {\n private participantModel: typeof TournamentParticipantModel;\n\n constructor() {\n this.participantModel = TournamentParticipantModel;\n }\n\n async existsByUserAndTournament(\n userId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId\n ): Promise<boolean> {\n return !!(await this.participantModel.exists({ userId, tournamentId }));\n }\n\n async create(input: object): Promise<TournamentParticipantOutputDTO> {\n const doc = await this.participantModel.create(input);\n return doc.toObject() as unknown as TournamentParticipantOutputDTO;\n }\n\n async findByUserAndTournament(\n userId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId\n ): Promise<TournamentParticipantOutputDTO | null> {\n return this.participantModel.findOne({ userId, tournamentId }).lean() as Promise<TournamentParticipantOutputDTO | null>;\n }\n\n async findByTournament(tournamentId: mongoose.Types.ObjectId): Promise<TournamentParticipantOutputDTO[]> {\n return this.participantModel.find({ tournamentId }).lean() as Promise<TournamentParticipantOutputDTO[]>;\n }\n\n async findByUser(userId: mongoose.Types.ObjectId): Promise<TournamentParticipantOutputDTO | null> {\n return this.participantModel\n .findOne({ userId })\n .sort({ createdAt: -1 })\n .lean() as Promise<TournamentParticipantOutputDTO | null>;\n }\n\n async updateToJoined(\n userId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId,\n teamId: mongoose.Types.ObjectId\n ): Promise<TournamentParticipantOutputDTO | null> {\n return this.participantModel\n .findOneAndUpdate({ userId, tournamentId }, { $set: { status: 'joined', teamId } }, { new: true })\n .lean() as Promise<TournamentParticipantOutputDTO | null>;\n }\n\n async createIfAbsent(\n userId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId,\n status: string\n ): Promise<void> {\n await this.participantModel.findOneAndUpdate(\n { userId, tournamentId },\n { $setOnInsert: { userId, tournamentId, predictions: [], status } },\n { upsert: true }\n );\n }\n\n public async findByTournamentWithoutPrediction(\n tournamentId: mongoose.Types.ObjectId,\n teamIds: mongoose.Types.ObjectId[],\n matchId: mongoose.Types.ObjectId\n ): Promise<TournamentParticipantOutputDTO[]> {\n return this.participantModel\n .find({\n tournamentId,\n teamId: { $in: teamIds },\n 'predictions.matchId': { $ne: matchId },\n })\n .lean()\n .exec() as Promise<TournamentParticipantOutputDTO[]>;\n }\n\n public async findByTournamentWithPrediction(\n tournamentId: mongoose.Types.ObjectId,\n matchId: mongoose.Types.ObjectId\n ): Promise<TournamentParticipantOutputDTO[]> {\n return this.participantModel\n .find({\n tournamentId,\n 'predictions.matchId': matchId,\n })\n .lean()\n .exec() as Promise<TournamentParticipantOutputDTO[]>;\n }\n\n}\n\nexport const tournamentParticipantRepository = Container.get(TournamentParticipantRepository);\n"]}
@@ -10,6 +10,7 @@ export declare class ParticipantService {
10
10
  getByUserAndTournament(userId: mongoose.Types.ObjectId, tournamentId: mongoose.Types.ObjectId): Promise<TournamentParticipantOutputDTO>;
11
11
  getAll(tournamentId: mongoose.Types.ObjectId): Promise<TournamentParticipantOutputDTO[]>;
12
12
  getUnpredicted(tournamentId: mongoose.Types.ObjectId, teamIds: mongoose.Types.ObjectId[], matchId: mongoose.Types.ObjectId): Promise<TournamentParticipantOutputDTO[]>;
13
+ getPredicted(tournamentId: mongoose.Types.ObjectId, matchId: mongoose.Types.ObjectId): Promise<TournamentParticipantOutputDTO[]>;
13
14
  }
14
15
  export declare const participantService: ParticipantService;
15
16
  //# sourceMappingURL=participant.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"participant.service.d.ts","sourceRoot":"/","sources":["modules/tournament/participant/participant.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAG9C,OAAO,EACH,sBAAsB,EACtB,0BAA0B,EAC1B,8BAA8B,EACjC,MAAM,0BAA0B,CAAC;AAOlC,qBACa,kBAAkB;IAC3B,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,eAAe,CAA4B;;IAOnD,OAAO,CAAC,gBAAgB;IAKX,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,8BAA8B,CAAC;IAuB7G,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3F,sBAAsB,CAC/B,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAC/B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACtC,OAAO,CAAC,8BAA8B,CAAC;IAM7B,MAAM,CAAC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,8BAA8B,EAAE,CAAC;IAMxF,cAAc,CACvB,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,EAClC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACjC,OAAO,CAAC,8BAA8B,EAAE,CAAC;CAM/C;AAED,eAAO,MAAM,kBAAkB,oBAAoC,CAAC"}
1
+ {"version":3,"file":"participant.service.d.ts","sourceRoot":"/","sources":["modules/tournament/participant/participant.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAG9C,OAAO,EACH,sBAAsB,EACtB,0BAA0B,EAC1B,8BAA8B,EACjC,MAAM,0BAA0B,CAAC;AAOlC,qBACa,kBAAkB;IAC3B,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,eAAe,CAA4B;;IAOnD,OAAO,CAAC,gBAAgB;IAKX,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,8BAA8B,CAAC;IAuB7G,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3F,sBAAsB,CAC/B,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAC/B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACtC,OAAO,CAAC,8BAA8B,CAAC;IAM7B,MAAM,CAAC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,8BAA8B,EAAE,CAAC;IAMxF,cAAc,CACvB,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,EAClC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACjC,OAAO,CAAC,8BAA8B,EAAE,CAAC;IAM/B,YAAY,CACrB,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACjC,OAAO,CAAC,8BAA8B,EAAE,CAAC;CAM/C;AAED,eAAO,MAAM,kBAAkB,oBAAoC,CAAC"}
@@ -105,6 +105,12 @@ let ParticipantService = class ParticipantService {
105
105
  throw (0, error_common_1.notFoundError)('Tournament not found');
106
106
  return this.repository.findByTournamentWithoutPrediction(tournamentId, teamIds, matchId);
107
107
  }
108
+ async getPredicted(tournamentId, matchId) {
109
+ const tournament = await this.matchRepository.findById(tournamentId);
110
+ if (!tournament)
111
+ throw (0, error_common_1.notFoundError)('Tournament not found');
112
+ return this.repository.findByTournamentWithPrediction(tournamentId, matchId);
113
+ }
108
114
  };
109
115
  exports.ParticipantService = ParticipantService;
110
116
  exports.ParticipantService = ParticipantService = __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"participant.service.js","sourceRoot":"/","sources":["modules/tournament/participant/participant.service.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, {Service} from 'typedi';\nimport {TRPCError} from '@trpc/server';\nimport {mongoose} from '@typegoose/typegoose';\nimport {badRequestError, conflictError, notFoundError} from '@lyxa.ai/core/dist/utilities/error-common';\nimport {TournamentParticipantRepository} from './participant.repository';\nimport {\n JoinTournamentInputDTO,\n MarkSeenTournamentInputDTO,\n TournamentParticipantOutputDTO,\n} from './participant.validation';\nimport {TournamentMatchRepository} from '../match/match.repository';\nimport {Tournament as TournamentType} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport {ensureCampaignActive} from '../tournament.utils';\nimport {ParticipantBuilder} from './participant.builder';\nimport {TournamentParticipantStatus} from '@lyxa.ai/core/dist/utilities/enum';\n\n@Service()\nexport class ParticipantService {\n private repository: TournamentParticipantRepository;\n private matchRepository: TournamentMatchRepository;\n\n constructor() {\n this.repository = Container.get(TournamentParticipantRepository);\n this.matchRepository = Container.get(TournamentMatchRepository);\n }\n\n private ensureTeamExists(tournament: TournamentType, teamId: mongoose.Types.ObjectId) {\n const exists = tournament.teams.some(team => team._id.toString() === teamId.toString());\n if (!exists) throw badRequestError('Selected team does not exist in this tournament');\n }\n\n public async join(userId: mongoose.Types.ObjectId, input: JoinTournamentInputDTO): Promise<TournamentParticipantOutputDTO> {\n const tournament = await this.matchRepository.findById(input.tournamentId);\n if (!tournament) throw notFoundError('Tournament not found');\n\n ensureCampaignActive(tournament);\n this.ensureTeamExists(tournament, input.teamId);\n\n const existing = await this.repository.findByUserAndTournament(userId, input.tournamentId);\n if (existing?.status === TournamentParticipantStatus.JOINED) throw conflictError('You have already joined this tournament');\n\n if (existing) {\n const updated = await this.repository.updateToJoined(userId, input.tournamentId, input.teamId);\n if (!updated) throw new TRPCError({code: 'INTERNAL_SERVER_ERROR', message: 'Failed to join tournament'});\n return updated;\n }\n\n const result = await this.repository.create(\n ParticipantBuilder.buildNewParticipant(userId, input.tournamentId, input.teamId)\n );\n\n return result;\n }\n\n public async markSeen(userId: mongoose.Types.ObjectId, input: MarkSeenTournamentInputDTO): Promise<void> {\n const exists = await this.matchRepository.findById(input.tournamentId);\n if (!exists) throw notFoundError('Tournament not found');\n\n await this.repository.createIfAbsent(userId, input.tournamentId, TournamentParticipantStatus.SEEN);\n }\n\n public async getByUserAndTournament(\n userId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId\n ): Promise<TournamentParticipantOutputDTO> {\n const participant = await this.repository.findByUserAndTournament(userId, tournamentId);\n if (!participant) throw notFoundError('You have not joined this tournament');\n return participant;\n }\n\n public async getAll(tournamentId: mongoose.Types.ObjectId): Promise<TournamentParticipantOutputDTO[]> {\n const tournament = await this.matchRepository.findById(tournamentId);\n if (!tournament) throw notFoundError('Tournament not found');\n return this.repository.findByTournament(tournamentId);\n }\n\n public async getUnpredicted(\n tournamentId: mongoose.Types.ObjectId,\n teamIds: mongoose.Types.ObjectId[],\n matchId: mongoose.Types.ObjectId\n ): Promise<TournamentParticipantOutputDTO[]> {\n const tournament = await this.matchRepository.findById(tournamentId);\n if (!tournament) throw notFoundError('Tournament not found');\n return this.repository.findByTournamentWithoutPrediction(tournamentId, teamIds, matchId);\n }\n\n}\n\nexport const participantService = Container.get(ParticipantService);\n"]}
1
+ {"version":3,"file":"participant.service.js","sourceRoot":"/","sources":["modules/tournament/participant/participant.service.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, {Service} from 'typedi';\nimport {TRPCError} from '@trpc/server';\nimport {mongoose} from '@typegoose/typegoose';\nimport {badRequestError, conflictError, notFoundError} from '@lyxa.ai/core/dist/utilities/error-common';\nimport {TournamentParticipantRepository} from './participant.repository';\nimport {\n JoinTournamentInputDTO,\n MarkSeenTournamentInputDTO,\n TournamentParticipantOutputDTO,\n} from './participant.validation';\nimport {TournamentMatchRepository} from '../match/match.repository';\nimport {Tournament as TournamentType} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport {ensureCampaignActive} from '../tournament.utils';\nimport {ParticipantBuilder} from './participant.builder';\nimport {TournamentParticipantStatus} from '@lyxa.ai/core/dist/utilities/enum';\n\n@Service()\nexport class ParticipantService {\n private repository: TournamentParticipantRepository;\n private matchRepository: TournamentMatchRepository;\n\n constructor() {\n this.repository = Container.get(TournamentParticipantRepository);\n this.matchRepository = Container.get(TournamentMatchRepository);\n }\n\n private ensureTeamExists(tournament: TournamentType, teamId: mongoose.Types.ObjectId) {\n const exists = tournament.teams.some(team => team._id.toString() === teamId.toString());\n if (!exists) throw badRequestError('Selected team does not exist in this tournament');\n }\n\n public async join(userId: mongoose.Types.ObjectId, input: JoinTournamentInputDTO): Promise<TournamentParticipantOutputDTO> {\n const tournament = await this.matchRepository.findById(input.tournamentId);\n if (!tournament) throw notFoundError('Tournament not found');\n\n ensureCampaignActive(tournament);\n this.ensureTeamExists(tournament, input.teamId);\n\n const existing = await this.repository.findByUserAndTournament(userId, input.tournamentId);\n if (existing?.status === TournamentParticipantStatus.JOINED) throw conflictError('You have already joined this tournament');\n\n if (existing) {\n const updated = await this.repository.updateToJoined(userId, input.tournamentId, input.teamId);\n if (!updated) throw new TRPCError({code: 'INTERNAL_SERVER_ERROR', message: 'Failed to join tournament'});\n return updated;\n }\n\n const result = await this.repository.create(\n ParticipantBuilder.buildNewParticipant(userId, input.tournamentId, input.teamId)\n );\n\n return result;\n }\n\n public async markSeen(userId: mongoose.Types.ObjectId, input: MarkSeenTournamentInputDTO): Promise<void> {\n const exists = await this.matchRepository.findById(input.tournamentId);\n if (!exists) throw notFoundError('Tournament not found');\n\n await this.repository.createIfAbsent(userId, input.tournamentId, TournamentParticipantStatus.SEEN);\n }\n\n public async getByUserAndTournament(\n userId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId\n ): Promise<TournamentParticipantOutputDTO> {\n const participant = await this.repository.findByUserAndTournament(userId, tournamentId);\n if (!participant) throw notFoundError('You have not joined this tournament');\n return participant;\n }\n\n public async getAll(tournamentId: mongoose.Types.ObjectId): Promise<TournamentParticipantOutputDTO[]> {\n const tournament = await this.matchRepository.findById(tournamentId);\n if (!tournament) throw notFoundError('Tournament not found');\n return this.repository.findByTournament(tournamentId);\n }\n\n public async getUnpredicted(\n tournamentId: mongoose.Types.ObjectId,\n teamIds: mongoose.Types.ObjectId[],\n matchId: mongoose.Types.ObjectId\n ): Promise<TournamentParticipantOutputDTO[]> {\n const tournament = await this.matchRepository.findById(tournamentId);\n if (!tournament) throw notFoundError('Tournament not found');\n return this.repository.findByTournamentWithoutPrediction(tournamentId, teamIds, matchId);\n }\n\n public async getPredicted(\n tournamentId: mongoose.Types.ObjectId,\n matchId: mongoose.Types.ObjectId\n ): Promise<TournamentParticipantOutputDTO[]> {\n const tournament = await this.matchRepository.findById(tournamentId);\n if (!tournament) throw notFoundError('Tournament not found');\n return this.repository.findByTournamentWithPrediction(tournamentId, matchId);\n }\n\n}\n\nexport const participantService = Container.get(ParticipantService);\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"reward.builder.d.ts","sourceRoot":"/","sources":["modules/tournament/reward/reward.builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EAAC,kBAAkB,EAAE,mBAAmB,EAAE,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAEtF,OAAO,EAAC,6BAA6B,EAAC,MAAM,+DAA+D,CAAC;AAe5G,qBAAa,aAAa;IACtB,MAAM,CAAC,wBAAwB,CAC3B,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAChC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,EACpC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,kBAAkB,GAC3B,aAAa;IAUhB,MAAM,CAAC,gBAAgB,CACnB,OAAO,EAAE,mBAAmB,EAC5B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAG,GACnC,6BAA6B;IAWhC,OAAO,CAAC,MAAM,CAAC,kBAAkB;CAqBpC"}
1
+ {"version":3,"file":"reward.builder.d.ts","sourceRoot":"/","sources":["modules/tournament/reward/reward.builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EAAC,kBAAkB,EAAE,mBAAmB,EAAE,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAEtF,OAAO,EAAC,6BAA6B,EAAC,MAAM,+DAA+D,CAAC;AAc5G,qBAAa,aAAa;IACtB,MAAM,CAAC,wBAAwB,CAC3B,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAChC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,EACpC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,kBAAkB,GAC3B,aAAa;IAUhB,MAAM,CAAC,gBAAgB,CACnB,OAAO,EAAE,mBAAmB,EAC5B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAG,GACnC,6BAA6B;IAWhC,OAAO,CAAC,MAAM,CAAC,kBAAkB;CAsBpC"}
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RewardBuilder = void 0;
4
4
  const enum_1 = require("@lyxa.ai/core/dist/utilities/enum");
5
5
  const tournament_utils_1 = require("../tournament.utils");
6
- const FWC_MIN_ORDER_VALUE = 5;
7
6
  const FWC_ORDER_LIMIT_PER_USER = 1;
8
7
  const FWC_COUPON_DURATION_MONTHS = 1;
9
8
  const FWC_ELIGIBLE_ITEM_TYPES = [
@@ -44,14 +43,15 @@ class RewardBuilder {
44
43
  valueType: enum_1.ValueType.PERCENTAGE,
45
44
  value: config.percentage,
46
45
  maxDiscountLimit: config.maxDiscountPerOrder,
46
+ isMaxDiscountLimitEnabled: true,
47
47
  couponNamePrefix: config.couponNamePrefix,
48
48
  duration: { start: now, end: expiresAt },
49
49
  isSpendLimitEnabled: false,
50
50
  spendLimit: null,
51
51
  isOrderLimitPerUserEnabled: true,
52
52
  orderLimitPerUser: FWC_ORDER_LIMIT_PER_USER,
53
- isMinOrderValueEnabled: true,
54
- minOrderValue: FWC_MIN_ORDER_VALUE,
53
+ isMinOrderValueEnabled: false,
54
+ minOrderValue: 0,
55
55
  itemTypes: FWC_ELIGIBLE_ITEM_TYPES,
56
56
  };
57
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"reward.builder.js","sourceRoot":"/","sources":["modules/tournament/reward/reward.builder.ts"],"names":[],"mappings":";;;AACA,4DAAkF;AAElF,0DAA2C;AAG3C,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAC9B,MAAM,wBAAwB,GAAG,CAAC,CAAC;AACnC,MAAM,0BAA0B,GAAG,CAAC,CAAC;AACrC,MAAM,uBAAuB,GAAe;IACxC,eAAQ,CAAC,IAAI;IACb,eAAQ,CAAC,OAAO;IAChB,eAAQ,CAAC,QAAQ;IACjB,eAAQ,CAAC,MAAM;IACf,eAAQ,CAAC,MAAM;IACf,eAAQ,CAAC,GAAG;IACZ,eAAQ,CAAC,cAAc;CAC1B,CAAC;AAEF,MAAa,aAAa;IACtB,MAAM,CAAC,wBAAwB,CAC3B,OAAgC,EAChC,YAAqC,EACrC,SAAoC,EACpC,WAAmB,EACnB,MAA0B;QAE1B,OAAO;YACH,OAAO,EAAE,SAAS;YAClB,YAAY;YACZ,OAAO;YACP,WAAW;YACX,OAAO,EAAE,aAAa,CAAC,kBAAkB,CAAC,MAAM,CAAC;SACpD,CAAC;IACN,CAAC;IAED,MAAM,CAAC,gBAAgB,CACnB,OAA4B,EAC5B,IAAY,EACZ,MAAkC;QAElC,MAAM,EAAC,gBAAgB,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAC,GAAG,OAAO,CAAC;QACtD,OAAO;YACH,GAAG,IAAI;YACP,IAAI;YACJ,KAAK,EAAE,MAAM;YACb,KAAK,EAAE,EAAE;YACT,OAAO,EAAE,EAAE;SAC8B,CAAC;IAClD,CAAC;IAEO,MAAM,CAAC,kBAAkB,CAAC,MAA0B;QACxD,MAAM,GAAG,GAAG,IAAA,yBAAM,GAAE,CAAC;QACrB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QAChC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,0BAA0B,CAAC,CAAC;QAEtE,OAAO;YACH,UAAU,EAAE,iBAAU,CAAC,eAAe;YACtC,SAAS,EAAE,gBAAS,CAAC,UAAU;YAC/B,KAAK,EAAE,MAAM,CAAC,UAAU;YACxB,gBAAgB,EAAE,MAAM,CAAC,mBAAmB;YAC5C,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;YACzC,QAAQ,EAAE,EAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAC;YACtC,mBAAmB,EAAE,KAAK;YAC1B,UAAU,EAAE,IAAI;YAChB,0BAA0B,EAAE,IAAI;YAChC,iBAAiB,EAAE,wBAAwB;YAC3C,sBAAsB,EAAE,IAAI;YAC5B,aAAa,EAAE,mBAAmB;YAClC,SAAS,EAAE,uBAAuB;SACrC,CAAC;IACN,CAAC;CACJ;AArDD,sCAqDC","sourcesContent":["import {mongoose} from '@typegoose/typegoose';\nimport {CouponType, ItemType, ValueType} from '@lyxa.ai/core/dist/utilities/enum';\nimport {CouponRewardConfig, CouponRewardPayload, RewardContext} from './reward.types';\nimport {utcNow} from '../tournament.utils';\nimport {CreateIndividualUserCouponDTO} from '@modules/coupon/validations/individual-user-coupon.validation';\n\nconst FWC_MIN_ORDER_VALUE = 5;\nconst FWC_ORDER_LIMIT_PER_USER = 1;\nconst FWC_COUPON_DURATION_MONTHS = 1;\nconst FWC_ELIGIBLE_ITEM_TYPES: ItemType[] = [\n ItemType.FOOD,\n ItemType.GROCERY,\n ItemType.PHARMACY,\n ItemType.COFFEE,\n ItemType.FLOWER,\n ItemType.PET,\n ItemType.HEALTHY_CORNER,\n];\n\nexport class RewardBuilder {\n static buildCouponRewardContext(\n matchId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId,\n winnerIds: mongoose.Types.ObjectId[],\n matchNumber: number,\n config: CouponRewardConfig\n ): RewardContext {\n return {\n userIds: winnerIds,\n tournamentId,\n matchId,\n matchNumber,\n payload: RewardBuilder.buildCouponPayload(config),\n };\n }\n\n static buildCouponInput(\n payload: CouponRewardPayload,\n code: string,\n userId: mongoose.Types.ObjectId []\n ): CreateIndividualUserCouponDTO {\n const {couponNamePrefix: _ignored, ...rest} = payload;\n return {\n ...rest,\n code,\n users: userId,\n shops: [],\n vendors: [],\n } as unknown as CreateIndividualUserCouponDTO;\n }\n\n private static buildCouponPayload(config: CouponRewardConfig): CouponRewardPayload {\n const now = utcNow();\n const expiresAt = new Date(now);\n expiresAt.setMonth(expiresAt.getMonth() + FWC_COUPON_DURATION_MONTHS);\n\n return {\n couponType: CouponType.INDIVIDUAL_USER,\n valueType: ValueType.PERCENTAGE,\n value: config.percentage,\n maxDiscountLimit: config.maxDiscountPerOrder,\n couponNamePrefix: config.couponNamePrefix,\n duration: {start: now, end: expiresAt},\n isSpendLimitEnabled: false,\n spendLimit: null,\n isOrderLimitPerUserEnabled: true,\n orderLimitPerUser: FWC_ORDER_LIMIT_PER_USER,\n isMinOrderValueEnabled: true,\n minOrderValue: FWC_MIN_ORDER_VALUE,\n itemTypes: FWC_ELIGIBLE_ITEM_TYPES,\n };\n }\n}\n"]}
1
+ {"version":3,"file":"reward.builder.js","sourceRoot":"/","sources":["modules/tournament/reward/reward.builder.ts"],"names":[],"mappings":";;;AACA,4DAAkF;AAElF,0DAA2C;AAG3C,MAAM,wBAAwB,GAAG,CAAC,CAAC;AACnC,MAAM,0BAA0B,GAAG,CAAC,CAAC;AACrC,MAAM,uBAAuB,GAAe;IACxC,eAAQ,CAAC,IAAI;IACb,eAAQ,CAAC,OAAO;IAChB,eAAQ,CAAC,QAAQ;IACjB,eAAQ,CAAC,MAAM;IACf,eAAQ,CAAC,MAAM;IACf,eAAQ,CAAC,GAAG;IACZ,eAAQ,CAAC,cAAc;CAC1B,CAAC;AAEF,MAAa,aAAa;IACtB,MAAM,CAAC,wBAAwB,CAC3B,OAAgC,EAChC,YAAqC,EACrC,SAAoC,EACpC,WAAmB,EACnB,MAA0B;QAE1B,OAAO;YACH,OAAO,EAAE,SAAS;YAClB,YAAY;YACZ,OAAO;YACP,WAAW;YACX,OAAO,EAAE,aAAa,CAAC,kBAAkB,CAAC,MAAM,CAAC;SACpD,CAAC;IACN,CAAC;IAED,MAAM,CAAC,gBAAgB,CACnB,OAA4B,EAC5B,IAAY,EACZ,MAAkC;QAElC,MAAM,EAAC,gBAAgB,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAC,GAAG,OAAO,CAAC;QACtD,OAAO;YACH,GAAG,IAAI;YACP,IAAI;YACJ,KAAK,EAAE,MAAM;YACb,KAAK,EAAE,EAAE;YACT,OAAO,EAAE,EAAE;SAC8B,CAAC;IAClD,CAAC;IAEO,MAAM,CAAC,kBAAkB,CAAC,MAA0B;QACxD,MAAM,GAAG,GAAG,IAAA,yBAAM,GAAE,CAAC;QACrB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QAChC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,0BAA0B,CAAC,CAAC;QAEtE,OAAO;YACH,UAAU,EAAE,iBAAU,CAAC,eAAe;YACtC,SAAS,EAAE,gBAAS,CAAC,UAAU;YAC/B,KAAK,EAAE,MAAM,CAAC,UAAU;YACxB,gBAAgB,EAAE,MAAM,CAAC,mBAAmB;YAC5C,yBAAyB,EAAE,IAAI;YAC/B,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;YACzC,QAAQ,EAAE,EAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAC;YACtC,mBAAmB,EAAE,KAAK;YAC1B,UAAU,EAAE,IAAI;YAChB,0BAA0B,EAAE,IAAI;YAChC,iBAAiB,EAAE,wBAAwB;YAC3C,sBAAsB,EAAE,KAAK;YAC7B,aAAa,EAAE,CAAC;YAChB,SAAS,EAAE,uBAAuB;SACrC,CAAC;IACN,CAAC;CACJ;AAtDD,sCAsDC","sourcesContent":["import {mongoose} from '@typegoose/typegoose';\nimport {CouponType, ItemType, ValueType} from '@lyxa.ai/core/dist/utilities/enum';\nimport {CouponRewardConfig, CouponRewardPayload, RewardContext} from './reward.types';\nimport {utcNow} from '../tournament.utils';\nimport {CreateIndividualUserCouponDTO} from '@modules/coupon/validations/individual-user-coupon.validation';\n\nconst FWC_ORDER_LIMIT_PER_USER = 1;\nconst FWC_COUPON_DURATION_MONTHS = 1;\nconst FWC_ELIGIBLE_ITEM_TYPES: ItemType[] = [\n ItemType.FOOD,\n ItemType.GROCERY,\n ItemType.PHARMACY,\n ItemType.COFFEE,\n ItemType.FLOWER,\n ItemType.PET,\n ItemType.HEALTHY_CORNER,\n];\n\nexport class RewardBuilder {\n static buildCouponRewardContext(\n matchId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId,\n winnerIds: mongoose.Types.ObjectId[],\n matchNumber: number,\n config: CouponRewardConfig\n ): RewardContext {\n return {\n userIds: winnerIds,\n tournamentId,\n matchId,\n matchNumber,\n payload: RewardBuilder.buildCouponPayload(config),\n };\n }\n\n static buildCouponInput(\n payload: CouponRewardPayload,\n code: string,\n userId: mongoose.Types.ObjectId []\n ): CreateIndividualUserCouponDTO {\n const {couponNamePrefix: _ignored, ...rest} = payload;\n return {\n ...rest,\n code,\n users: userId,\n shops: [],\n vendors: [],\n } as unknown as CreateIndividualUserCouponDTO;\n }\n\n private static buildCouponPayload(config: CouponRewardConfig): CouponRewardPayload {\n const now = utcNow();\n const expiresAt = new Date(now);\n expiresAt.setMonth(expiresAt.getMonth() + FWC_COUPON_DURATION_MONTHS);\n\n return {\n couponType: CouponType.INDIVIDUAL_USER,\n valueType: ValueType.PERCENTAGE,\n value: config.percentage,\n maxDiscountLimit: config.maxDiscountPerOrder,\n isMaxDiscountLimitEnabled: true,\n couponNamePrefix: config.couponNamePrefix,\n duration: {start: now, end: expiresAt},\n isSpendLimitEnabled: false,\n spendLimit: null,\n isOrderLimitPerUserEnabled: true,\n orderLimitPerUser: FWC_ORDER_LIMIT_PER_USER,\n isMinOrderValueEnabled: false,\n minOrderValue: 0,\n itemTypes: FWC_ELIGIBLE_ITEM_TYPES,\n };\n }\n}\n"]}
@@ -26,6 +26,7 @@ export interface CouponRewardPayload {
26
26
  isMinOrderValueEnabled: boolean;
27
27
  minOrderValue: number;
28
28
  itemTypes: ItemType[];
29
+ isMaxDiscountLimitEnabled: boolean;
29
30
  }
30
31
  export type CouponRewardResult = {
31
32
  code: string;
@@ -1 +1 @@
1
- {"version":3,"file":"reward.types.d.ts","sourceRoot":"/","sources":["modules/tournament/reward/reward.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAC,MAAM,mCAAmC,CAAC;AAElF,oBAAY,UAAU;IAClB,MAAM,WAAW;CACpB;AAED,MAAM,WAAW,kBAAkB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACjC,KAAK,EAAE,IAAI,CAAC;IACZ,GAAG,EAAE,IAAI,CAAC;CACb;AAED,MAAM,WAAW,mBAAmB;IAChC,UAAU,EAAE,UAAU,CAAC,eAAe,CAAC;IACvC,SAAS,EAAE,SAAS,CAAC,UAAU,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,0BAA0B,EAAE,OAAO,CAAC;IACpC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sBAAsB,EAAE,OAAO,CAAC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,QAAQ,EAAE,CAAC;CACzB;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC;CAChC,CAAC;AAEF,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,mBAAmB;IAClD,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;IACnC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC;IACtC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,CAAC,CAAC;CACd"}
1
+ {"version":3,"file":"reward.types.d.ts","sourceRoot":"/","sources":["modules/tournament/reward/reward.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAC,MAAM,mCAAmC,CAAC;AAElF,oBAAY,UAAU;IAClB,MAAM,WAAW;CACpB;AAED,MAAM,WAAW,kBAAkB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACjC,KAAK,EAAE,IAAI,CAAC;IACZ,GAAG,EAAE,IAAI,CAAC;CACb;AAED,MAAM,WAAW,mBAAmB;IAChC,UAAU,EAAE,UAAU,CAAC,eAAe,CAAC;IACvC,SAAS,EAAE,SAAS,CAAC,UAAU,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,0BAA0B,EAAE,OAAO,CAAC;IACpC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sBAAsB,EAAE,OAAO,CAAC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,yBAAyB,EAAE,OAAO,CAAA;CACrC;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC;CAChC,CAAC;AAEF,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,mBAAmB;IAClD,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;IACnC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC;IACtC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,CAAC,CAAC;CACd"}
@@ -1 +1 @@
1
- {"version":3,"file":"reward.types.js","sourceRoot":"/","sources":["modules/tournament/reward/reward.types.ts"],"names":[],"mappings":";;;AAGA,IAAY,UAEX;AAFD,WAAY,UAAU;IAClB,+BAAiB,CAAA;AACrB,CAAC,EAFW,UAAU,0BAAV,UAAU,QAErB","sourcesContent":["import {mongoose} from '@typegoose/typegoose';\nimport {CouponType, ItemType, ValueType} from '@lyxa.ai/core/dist/utilities/enum';\n\nexport enum RewardType {\n COUPON = 'coupon',\n}\n\nexport interface CouponRewardConfig {\n percentage: number;\n maxDiscountPerOrder: number;\n couponNamePrefix: string;\n}\n\nexport interface CouponRewardDuration {\n start: Date;\n end: Date;\n}\n\nexport interface CouponRewardPayload {\n couponType: CouponType.INDIVIDUAL_USER;\n valueType: ValueType.PERCENTAGE;\n value: number;\n maxDiscountLimit: number;\n couponNamePrefix: string;\n duration: CouponRewardDuration;\n isSpendLimitEnabled: boolean;\n spendLimit: number | null;\n isOrderLimitPerUserEnabled: boolean;\n orderLimitPerUser: number;\n isMinOrderValueEnabled: boolean;\n minOrderValue: number;\n itemTypes: ItemType[];\n}\n\nexport type CouponRewardResult = {\n code: string;\n duration: CouponRewardDuration;\n couponOfferLabel: string;\n couponValidityLabel: string;\n _id: mongoose.Types.ObjectId;\n};\n\nexport interface RewardContext<P = CouponRewardPayload> {\n userIds: mongoose.Types.ObjectId[];\n tournamentId: mongoose.Types.ObjectId;\n matchId: mongoose.Types.ObjectId;\n matchNumber: number;\n payload: P;\n}\n"]}
1
+ {"version":3,"file":"reward.types.js","sourceRoot":"/","sources":["modules/tournament/reward/reward.types.ts"],"names":[],"mappings":";;;AAGA,IAAY,UAEX;AAFD,WAAY,UAAU;IAClB,+BAAiB,CAAA;AACrB,CAAC,EAFW,UAAU,0BAAV,UAAU,QAErB","sourcesContent":["import {mongoose} from '@typegoose/typegoose';\nimport {CouponType, ItemType, ValueType} from '@lyxa.ai/core/dist/utilities/enum';\n\nexport enum RewardType {\n COUPON = 'coupon',\n}\n\nexport interface CouponRewardConfig {\n percentage: number;\n maxDiscountPerOrder: number;\n couponNamePrefix: string;\n}\n\nexport interface CouponRewardDuration {\n start: Date;\n end: Date;\n}\n\nexport interface CouponRewardPayload {\n couponType: CouponType.INDIVIDUAL_USER;\n valueType: ValueType.PERCENTAGE;\n value: number;\n maxDiscountLimit: number;\n couponNamePrefix: string;\n duration: CouponRewardDuration;\n isSpendLimitEnabled: boolean;\n spendLimit: number | null;\n isOrderLimitPerUserEnabled: boolean;\n orderLimitPerUser: number;\n isMinOrderValueEnabled: boolean;\n minOrderValue: number;\n itemTypes: ItemType[];\n isMaxDiscountLimitEnabled: boolean\n}\n\nexport type CouponRewardResult = {\n code: string;\n duration: CouponRewardDuration;\n couponOfferLabel: string;\n couponValidityLabel: string;\n _id: mongoose.Types.ObjectId;\n};\n\nexport interface RewardContext<P = CouponRewardPayload> {\n userIds: mongoose.Types.ObjectId[];\n tournamentId: mongoose.Types.ObjectId;\n matchId: mongoose.Types.ObjectId;\n matchNumber: number;\n payload: P;\n}\n"]}
@@ -7,7 +7,14 @@ export declare class ScheduleService {
7
7
  private userModel;
8
8
  constructor();
9
9
  private dispatchTournamentActivationNotification;
10
+ private static readonly REMINDER_TYPES;
10
11
  dispatchPending(): Promise<void>;
12
+ private dispatchDueReminders;
13
+ private dispatchReminder;
14
+ private isDue;
15
+ private alreadySent;
16
+ private canSendNow;
17
+ private isCompanyOpen;
11
18
  }
12
19
  export declare const scheduleDispatchService: ScheduleService;
13
20
  //# sourceMappingURL=schedule.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schedule.service.d.ts","sourceRoot":"/","sources":["modules/tournament/schedule/schedule.service.ts"],"names":[],"mappings":"AAYA,qBACa,eAAe;IAC3B,OAAO,CAAC,gBAAgB,CAA6B;IACrD,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,qBAAqB,CAAkC;IAC/D,OAAO,CAAC,kBAAkB,CAAiC;IAC3D,OAAO,CAAC,mBAAmB,CAAgC;IAC3D,OAAO,CAAC,SAAS,CAA2C;;YA0D9C,wCAAwC;IAuBzC,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;CA4C7C;AAED,eAAO,MAAM,uBAAuB,iBAAiC,CAAC"}
1
+ {"version":3,"file":"schedule.service.d.ts","sourceRoot":"/","sources":["modules/tournament/schedule/schedule.service.ts"],"names":[],"mappings":"AAoBA,qBACa,eAAe;IAC3B,OAAO,CAAC,gBAAgB,CAA6B;IACrD,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,qBAAqB,CAAkC;IAC/D,OAAO,CAAC,kBAAkB,CAAiC;IAC3D,OAAO,CAAC,mBAAmB,CAAgC;IAC3D,OAAO,CAAC,SAAS,CAA2C;;YA0D9C,wCAAwC;IAuBtD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAInC;IAEU,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;YAU/B,oBAAoB;YAapB,gBAAgB;IAuB9B,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,WAAW;YAOL,UAAU;YAKV,aAAa;CAM3B;AAED,eAAO,MAAM,uBAAuB,iBAAiC,CAAC"}
@@ -41,17 +41,21 @@ var __importStar = (this && this.__importStar) || (function () {
41
41
  var __metadata = (this && this.__metadata) || function (k, v) {
42
42
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
43
43
  };
44
+ var ScheduleService_1;
44
45
  Object.defineProperty(exports, "__esModule", { value: true });
45
46
  exports.scheduleDispatchService = exports.ScheduleService = void 0;
46
47
  const typedi_1 = __importStar(require("typedi"));
48
+ const core_1 = require("@lyxa.ai/core");
47
49
  const models_1 = require("@lyxa.ai/core/dist/libraries/mongo/models");
48
50
  const enum_1 = require("@lyxa.ai/core/dist/utilities/enum");
51
+ const workHourSetting_1 = require("@lyxa.ai/core/dist/utilities/workHourSetting");
49
52
  const config_repository_1 = require("../config/config.repository");
50
53
  const match_repository_1 = require("../match/match.repository");
51
54
  const participant_repository_1 = require("../participant/participant.repository");
52
55
  const notification_template_repository_1 = require("../notification/notification-template.repository");
53
56
  const notification_service_1 = require("../notification/notification.service");
54
57
  let ScheduleService = class ScheduleService {
58
+ static { ScheduleService_1 = this; }
55
59
  configRepository;
56
60
  matchRepository;
57
61
  participantRepository;
@@ -82,33 +86,62 @@ let ScheduleService = class ScheduleService {
82
86
  });
83
87
  await this.configRepository.setNotificationFlag(tournament._id, enum_1.TournamentNotificationTag.TOURNAMENT_ACTIVATION);
84
88
  }
89
+ static REMINDER_TYPES = new Set([
90
+ enum_1.TournamentNotificationTag.PREDICTION_REMINDER_15_MINUTES,
91
+ enum_1.TournamentNotificationTag.PREDICTION_REMINDER_3_HOURS,
92
+ enum_1.TournamentNotificationTag.PREDICTION_REMINDER_1_HOUR,
93
+ ]);
85
94
  async dispatchPending() {
86
95
  const tournament = await this.configRepository.findActiveFull();
87
96
  if (!tournament)
88
97
  return;
89
- const tournamentId = tournament._id;
90
- const templates = await this.templateRepository.findTemplates(tournamentId);
91
- const now = Date.now();
98
+ const templates = await this.templateRepository.findTemplates(tournament._id);
92
99
  await this.dispatchTournamentActivationNotification(tournament, templates);
93
- await Promise.all(tournament.matches.map(match => Promise.all(tournament.scheduledNotifications.map(async ({ type, durationMins, target }) => {
94
- if (![
95
- enum_1.TournamentNotificationTag.PREDICTION_REMINDER_15_MINUTES,
96
- enum_1.TournamentNotificationTag.PREDICTION_REMINDER_3_HOURS,
97
- ].includes(type))
98
- return;
99
- const notificationTime = new Date(match.startingDate).getTime() - durationMins * 60 * 1000;
100
- const flags = match.notificationFlags;
101
- if (now < notificationTime)
102
- return;
103
- if (flags?.[type] === true)
104
- return;
105
- await this.notificationService.dispatchScheduledJob(type, target, templates, tournamentId, [match.team1.teamId, match.team2.teamId], match._id, match.startingDate, tournament.deepLinkRoute);
106
- await this.matchRepository.setNotificationFlag(tournamentId, match._id, type);
107
- }))));
100
+ await this.dispatchDueReminders(tournament, templates);
101
+ }
102
+ async dispatchDueReminders(tournament, templates) {
103
+ await Promise.all(tournament.matches.flatMap(match => tournament.scheduledNotifications.map(scheduled => this.dispatchReminder(tournament, match, scheduled, templates))));
104
+ }
105
+ async dispatchReminder(tournament, match, scheduled, templates) {
106
+ const { type, target, durationMins } = scheduled;
107
+ if (!ScheduleService_1.REMINDER_TYPES.has(type))
108
+ return;
109
+ if (this.alreadySent(match, type))
110
+ return;
111
+ if (!this.isDue(match, durationMins))
112
+ return;
113
+ if (await this.canSendNow(type))
114
+ await this.notificationService.dispatchScheduledReminder({
115
+ tournament,
116
+ match,
117
+ templates,
118
+ type,
119
+ target
120
+ });
121
+ await this.matchRepository.setNotificationFlag(tournament._id, match._id, type);
122
+ }
123
+ isDue(match, durationMins) {
124
+ const notificationTime = new Date(match.startingDate).getTime() - durationMins * 60 * 1000;
125
+ return Date.now() >= notificationTime;
126
+ }
127
+ alreadySent(match, type) {
128
+ const flags = match.notificationFlags;
129
+ return flags?.[type] === true;
130
+ }
131
+ async canSendNow(type) {
132
+ if (type !== enum_1.TournamentNotificationTag.PREDICTION_REMINDER_1_HOUR)
133
+ return true;
134
+ return this.isCompanyOpen();
135
+ }
136
+ async isCompanyOpen() {
137
+ const settings = (await (0, core_1.getLibraries)().getCachedSettingsService().getSettings());
138
+ if (!settings?.workHourSetting)
139
+ return false;
140
+ return (0, workHourSetting_1.isLyxaOpen)(settings.workHourSetting);
108
141
  }
109
142
  };
110
143
  exports.ScheduleService = ScheduleService;
111
- exports.ScheduleService = ScheduleService = __decorate([
144
+ exports.ScheduleService = ScheduleService = ScheduleService_1 = __decorate([
112
145
  (0, typedi_1.Service)(),
113
146
  __metadata("design:paramtypes", [])
114
147
  ], ScheduleService);