@lyxa.ai/marketing 1.0.54 → 1.0.56

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 (104) hide show
  1. package/dist/lib/index.d.ts +1289 -0
  2. package/dist/lib/index.d.ts.map +1 -1
  3. package/dist/lib/index.js +1 -1
  4. package/dist/lib/index.js.map +1 -1
  5. package/dist/lib/modules/coupon/routers/coupon.router.d.ts +1289 -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 +14 -0
  8. package/dist/lib/modules/coupon/routers/coupon.router.js.map +1 -1
  9. package/dist/lib/modules/coupon/services/coupon.service.d.ts +30 -2
  10. package/dist/lib/modules/coupon/services/coupon.service.d.ts.map +1 -1
  11. package/dist/lib/modules/coupon/services/coupon.service.js +34 -1
  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 +2 -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 +77 -7
  22. package/dist/lib/modules/coupon/services/patterns/repository/CouponMetricsRepository.js.map +1 -1
  23. package/dist/lib/modules/coupon/services/patterns/repository/CouponRepository.d.ts +17 -0
  24. package/dist/lib/modules/coupon/services/patterns/repository/CouponRepository.d.ts.map +1 -1
  25. package/dist/lib/modules/coupon/services/patterns/repository/CouponRepository.js +135 -0
  26. package/dist/lib/modules/coupon/services/patterns/repository/CouponRepository.js.map +1 -1
  27. package/dist/lib/modules/coupon/services/shops-categories-coupon.service.d.ts +5 -0
  28. package/dist/lib/modules/coupon/services/shops-categories-coupon.service.d.ts.map +1 -1
  29. package/dist/lib/modules/coupon/validations/coupon.validation.d.ts +76 -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 +27 -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/limited-time-offer/config/limited-time-offer-config.validation.d.ts +9 -1
  37. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.validation.d.ts.map +1 -1
  38. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.validation.js +26 -3
  39. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.validation.js.map +1 -1
  40. package/dist/lib/modules/tournament/match/events/evaluate-predictions.consumer.js +1 -1
  41. package/dist/lib/modules/tournament/match/events/evaluate-predictions.consumer.js.map +1 -1
  42. package/dist/lib/modules/tournament/notification/__tests__/notification.service.spec.d.ts +2 -0
  43. package/dist/lib/modules/tournament/notification/__tests__/notification.service.spec.d.ts.map +1 -0
  44. package/dist/lib/modules/tournament/notification/__tests__/notification.service.spec.js +266 -0
  45. package/dist/lib/modules/tournament/notification/__tests__/notification.service.spec.js.map +1 -0
  46. package/dist/lib/modules/tournament/notification/notification.service.d.ts +14 -3
  47. package/dist/lib/modules/tournament/notification/notification.service.d.ts.map +1 -1
  48. package/dist/lib/modules/tournament/notification/notification.service.js +89 -31
  49. package/dist/lib/modules/tournament/notification/notification.service.js.map +1 -1
  50. package/dist/lib/modules/tournament/participant/participant.repository.d.ts +1 -0
  51. package/dist/lib/modules/tournament/participant/participant.repository.d.ts.map +1 -1
  52. package/dist/lib/modules/tournament/participant/participant.repository.js +9 -0
  53. package/dist/lib/modules/tournament/participant/participant.repository.js.map +1 -1
  54. package/dist/lib/modules/tournament/participant/participant.service.d.ts +1 -0
  55. package/dist/lib/modules/tournament/participant/participant.service.d.ts.map +1 -1
  56. package/dist/lib/modules/tournament/participant/participant.service.js +6 -0
  57. package/dist/lib/modules/tournament/participant/participant.service.js.map +1 -1
  58. package/dist/lib/modules/tournament/reward/reward.builder.d.ts.map +1 -1
  59. package/dist/lib/modules/tournament/reward/reward.builder.js +3 -3
  60. package/dist/lib/modules/tournament/reward/reward.builder.js.map +1 -1
  61. package/dist/lib/modules/tournament/reward/reward.types.d.ts +1 -0
  62. package/dist/lib/modules/tournament/reward/reward.types.d.ts.map +1 -1
  63. package/dist/lib/modules/tournament/reward/reward.types.js.map +1 -1
  64. package/dist/lib/modules/tournament/schedule/schedule.service.d.ts +7 -0
  65. package/dist/lib/modules/tournament/schedule/schedule.service.d.ts.map +1 -1
  66. package/dist/lib/modules/tournament/schedule/schedule.service.js +52 -19
  67. package/dist/lib/modules/tournament/schedule/schedule.service.js.map +1 -1
  68. package/dist/lib/utility/utils.js +2 -2
  69. package/dist/lib/utility/utils.js.map +1 -1
  70. package/dist/types/index.d.ts +1289 -0
  71. package/dist/types/index.d.ts.map +1 -1
  72. package/dist/types/modules/coupon/routers/coupon.router.d.ts +1289 -0
  73. package/dist/types/modules/coupon/routers/coupon.router.d.ts.map +1 -1
  74. package/dist/types/modules/coupon/services/coupon.service.d.ts +30 -2
  75. package/dist/types/modules/coupon/services/coupon.service.d.ts.map +1 -1
  76. package/dist/types/modules/coupon/services/custom-coupon.service.d.ts +5 -0
  77. package/dist/types/modules/coupon/services/custom-coupon.service.d.ts.map +1 -1
  78. package/dist/types/modules/coupon/services/helper.service.d.ts +5 -0
  79. package/dist/types/modules/coupon/services/helper.service.d.ts.map +1 -1
  80. package/dist/types/modules/coupon/services/individual-store-coupon.service.d.ts +5 -0
  81. package/dist/types/modules/coupon/services/individual-store-coupon.service.d.ts.map +1 -1
  82. package/dist/types/modules/coupon/services/patterns/repository/CouponMetricsRepository.d.ts +2 -0
  83. package/dist/types/modules/coupon/services/patterns/repository/CouponMetricsRepository.d.ts.map +1 -1
  84. package/dist/types/modules/coupon/services/patterns/repository/CouponRepository.d.ts +17 -0
  85. package/dist/types/modules/coupon/services/patterns/repository/CouponRepository.d.ts.map +1 -1
  86. package/dist/types/modules/coupon/services/shops-categories-coupon.service.d.ts +5 -0
  87. package/dist/types/modules/coupon/services/shops-categories-coupon.service.d.ts.map +1 -1
  88. package/dist/types/modules/coupon/validations/coupon.validation.d.ts +76 -0
  89. package/dist/types/modules/coupon/validations/coupon.validation.d.ts.map +1 -1
  90. package/dist/types/modules/coupon/validations/create-coupon.validation.d.ts.map +1 -1
  91. package/dist/types/modules/limited-time-offer/config/limited-time-offer-config.validation.d.ts +9 -1
  92. package/dist/types/modules/limited-time-offer/config/limited-time-offer-config.validation.d.ts.map +1 -1
  93. package/dist/types/modules/tournament/notification/notification.service.d.ts +14 -3
  94. package/dist/types/modules/tournament/notification/notification.service.d.ts.map +1 -1
  95. package/dist/types/modules/tournament/participant/participant.repository.d.ts +1 -0
  96. package/dist/types/modules/tournament/participant/participant.repository.d.ts.map +1 -1
  97. package/dist/types/modules/tournament/participant/participant.service.d.ts +1 -0
  98. package/dist/types/modules/tournament/participant/participant.service.d.ts.map +1 -1
  99. package/dist/types/modules/tournament/reward/reward.builder.d.ts.map +1 -1
  100. package/dist/types/modules/tournament/reward/reward.types.d.ts +1 -0
  101. package/dist/types/modules/tournament/reward/reward.types.d.ts.map +1 -1
  102. package/dist/types/modules/tournament/schedule/schedule.service.d.ts +7 -0
  103. package/dist/types/modules/tournament/schedule/schedule.service.d.ts.map +1 -1
  104. package/package.json +2 -2
@@ -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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAA0C;AAE1C,wCAA2C;AAC3C,8DAAgE;AAChE,4EAAqG;AACrG,4DAK2C;AAE3C,4EAAsE;AAc/D,IAAM,6BAA6B,GAAnC,MAAM,6BAA6B;IAC9B,kBAAkB,CAAqB;IAE/C;QACI,IAAI,CAAC,kBAAkB,GAAG,gBAAS,CAAC,GAAG,CAAC,wCAAkB,CAAC,CAAC;IAChE,CAAC;IAEO,WAAW,CAAC,SAA2C,EAAE,GAAW;QACxE,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,GAAG,EAAE,CAAC,CAAC;QACpE,OAAO,CAAC,CAAC;IACb,CAAC;IAEM,KAAK,CAAC,YAAY,CAAC,YAAgC;QACtD,MAAM,IAAA,oBAAY,EACd,IAAI,sCAAuB,CAAC;YACxB,KAAK,EAAE,YAAY,CAAC,KAAK;YACzB,IAAI,EAAE,YAAY,CAAC,IAAI;YACvB,IAAI,EAAE;gBACF,gBAAgB,EAAE,IAAI;gBACtB,WAAW,EAAE,8BAAuB,CAAC,IAAI;gBACzC,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,IAAI;gBACjB,SAAS,EAAE,gBAAS,CAAC,oBAAoB;gBACzC,GAAG,YAAY;aAClB;SACJ,CAAC,CACL,CAAC;IACN,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,YAAgC,EAAE,OAAkC;QACzF,MAAM,MAAM,GAAG,IAAA,mBAAY,GAAE,CAAC,YAAY,EAAE,CAAC;QAC7C,IAAI,CAAC;YACD,MAAM,OAAO,CAAC,GAAG,CACb,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CACtB,IAAA,oBAAY,EACR,IAAI,gCAAiB,CAAC;gBAClB,KAAK,EAAE,YAAY,CAAC,KAAK;gBACzB,IAAI,EAAE,YAAY,CAAC,IAAI;gBACvB,IAAI,EAAE;oBACF,gBAAgB,EAAE,IAAI;oBACtB,WAAW,EAAE,8BAAuB,CAAC,IAAI;oBACzC,WAAW;oBACX,QAAQ,EAAE,KAAK;oBACf,WAAW,EAAE,IAAI;oBACjB,SAAS,EAAE,gBAAS,CAAC,oBAAoB;oBACzC,GAAG,YAAY;iBAClB;aACJ,CAAC,CACL,CACJ,CACJ,CAAC;YAEF,MAAM,CAAC,IAAI,CAAC,0CAA0C,EAAE;gBACpD,GAAG,EAAE,+BAA+B;gBACpC,IAAI,EAAE;oBACF,OAAO,EAAE;wBACL,gBAAgB,EAAE,IAAI;wBACtB,WAAW,EAAE,8BAAuB,CAAC,IAAI;wBACzC,OAAO;wBACP,QAAQ,EAAE,KAAK;wBACf,WAAW,EAAE,IAAI;wBACjB,SAAS,EAAE,gBAAS,CAAC,oBAAoB;wBACzC,GAAG,YAAY;qBAClB;oBACD,YAAY,EAAE,YAAY,CAAC,YAAY;oBACvC,IAAI,EAAE,YAAY,CAAC,0BAA0B;oBAC7C,cAAc,EAAE,OAAO,CAAC,MAAM;iBACjC;aACJ,CAAC,CAAC;QACP,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,kDAAkD,EAAE,KAAK,EAAE;gBACpE,GAAG,EAAE,+BAA+B;gBACpC,IAAI,EAAE;oBACF,YAAY,EAAE,YAAY,CAAC,YAAY;oBACvC,IAAI,EAAE,YAAY,CAAC,0BAA0B;oBAC7C,cAAc,EAAE,OAAO,CAAC,MAAM;oBAC9B,OAAO,EAAE;wBACL,gBAAgB,EAAE,IAAI;wBACtB,WAAW,EAAE,8BAAuB,CAAC,IAAI;wBACzC,OAAO;wBACP,QAAQ,EAAE,KAAK;wBACf,WAAW,EAAE,IAAI;wBACjB,SAAS,EAAE,gBAAS,CAAC,oBAAoB;wBACzC,GAAG,YAAY;qBAClB;iBACJ;aACJ,CAAC,CAAC;QACP,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,yBAAyB,CAAC,GAA6B;QAChE,IAAI,GAAG,CAAC,MAAM,KAAK,4CAAqC,CAAC,MAAM,EAAE,CAAC;YAC9D,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC;YACpD,OAAO;QACX,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI,CAAC,UAAU,CAAC,MAAM;YAAE,OAAO;QAE/B,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1F,CAAC;IAEO,yBAAyB,CAAC,GAA6B;QAC3D,MAAM,EAAC,UAAU,EAAE,KAAK,EAAE,IAAI,EAAC,GAAG,GAAG,CAAC;QAEtC,IAAI,IAAI,KAAK,gCAAyB,CAAC,0BAA0B,EAAE,CAAC;YAChE,OAAO,IAAI,CAAC,kBAAkB,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3E,CAAC;QAED,OAAO,IAAI,CAAC,kBAAkB,CAAC,cAAc,CACzC,UAAU,CAAC,GAAG,EACd,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,EACxC,KAAK,CAAC,GAAG,CACZ,CAAC;IACN,CAAC;IAEO,gBAAgB,CAAC,GAA6B;QAClD,MAAM,EAAC,KAAK,EAAE,IAAI,EAAC,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAChE,OAAO;YACH,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC;YAC3C,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC;YACzC,0BAA0B,EAAE,GAAG,CAAC,IAAI;YACpC,YAAY,EAAE,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE;YAC3C,aAAa,EAAE,GAAG,CAAC,UAAU,CAAC,aAAa;SAC9C,CAAC;IACN,CAAC;IAEO,oBAAoB,CAAC,GAA6B;QACtD,OAAO;YACH,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC;YAC7B,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE;YACjC,oBAAoB,EAAE,GAAG,CAAC,KAAK,CAAC,YAAY;SAC/C,CAAC;IACN,CAAC;IAEO,aAAa,CAAC,IAAY,EAAE,KAAsB;QACtD,OAAO,IAAI;aACN,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;aACrC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/C,CAAC;CACJ,CAAA;AA7IY,sEAA6B;wCAA7B,6BAA6B;IADzC,IAAA,gBAAO,GAAE;;GACG,6BAA6B,CA6IzC;AAEY,QAAA,6BAA6B,GAAG,gBAAS,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC","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);
@@ -1 +1 @@
1
- {"version":3,"file":"schedule.service.js","sourceRoot":"/","sources":["modules/tournament/schedule/schedule.service.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, { Service } from 'typedi';\nimport { mongoose } from '@typegoose/typegoose';\nimport { SoftDeleteModel } from '@lyxa.ai/core/dist/libraries/mongo/plugins/soft-delete-plugin';\nimport { NotificationMessage, User, UserModel } from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport { TournamentNotificationTag } from '@lyxa.ai/core/dist/utilities/enum';\nimport { TournamentConfigRepository } from '../config/config.repository';\nimport { TournamentMatchRepository } from '../match/match.repository';\nimport { TournamentParticipantRepository } from '../participant/participant.repository';\nimport { NotificationTemplateRepository } from '../notification/notification-template.repository';\nimport { TournamentNotificationService } from '../notification/notification.service';\nimport { TournamentDocument } from '../config/config.types';\n\n@Service()\nexport class ScheduleService {\n\tprivate configRepository: TournamentConfigRepository;\n\tprivate matchRepository: TournamentMatchRepository;\n\tprivate participantRepository: TournamentParticipantRepository;\n\tprivate templateRepository: NotificationTemplateRepository;\n\tprivate notificationService: TournamentNotificationService;\n\tprivate userModel: typeof UserModel & SoftDeleteModel<User>;\n\n\tconstructor() {\n\t\tthis.configRepository = Container.get(TournamentConfigRepository);\n\t\tthis.matchRepository = Container.get(TournamentMatchRepository);\n\t\tthis.participantRepository = Container.get(TournamentParticipantRepository);\n\t\tthis.templateRepository = Container.get(NotificationTemplateRepository);\n\t\tthis.notificationService = Container.get(TournamentNotificationService);\n\t\tthis.userModel = UserModel as typeof UserModel & SoftDeleteModel<User>;\n\t}\n\n\t// NOTE: there is a huge possibility we will not use this feature, left it out in case they want it back\n\t//\n\t// public async dispatchPreTournamentReminders(): Promise<void> {\n\t// \tconst tournaments = await this.configRepository.findPendingReminderTournaments();\n\t// \tif (!tournaments.length) return;\n\t//\n\t// \tawait Promise.all(\n\t// \t\ttournaments.map(async tournament => {\n\t// \t\t\tconst templates = await this.templateRepository.findTemplates(tournament._id);\n\t// \t\t\tconst reminderTemplate = templates.get(TournamentNotificationTag.TEAM_SELECTION_REMINDER_1_DAY);\n\t// \t\t\tif (!reminderTemplate) return;\n\t//\n\t// \t\t\tconst participants = await this.participantRepository.findByTournament(tournament._id);\n\t// \t\t\tconst usersWithTeam = participants\n\t// \t\t\t\t.filter(participant => participant.teamId)\n\t// \t\t\t\t.map(participant => participant.userId);\n\t// \t\t\tconst recipients = await this.userModel\n\t// \t\t\t\t.find({ _id: { $nin: usersWithTeam } })\n\t// \t\t\t\t.select('_id')\n\t// \t\t\t\t.lean();\n\t//\n\t// \t\t\tif (!recipients.length) {\n\t// \t\t\t\tawait this.configRepository.setNotificationFlag(\n\t// \t\t\t\t\ttournament._id,\n\t// \t\t\t\t\tTournamentNotificationTag.TEAM_SELECTION_REMINDER_1_DAY\n\t// \t\t\t\t);\n\t// \t\t\t\treturn;\n\t// \t\t\t}\n\t//\n\t// \t\t\tawait this.notificationService.notifyUsers(\n\t// \t\t\t\t{\n\t// \t\t\t\t\ttitle: reminderTemplate.title,\n\t// \t\t\t\t\tbody: reminderTemplate.body,\n\t// \t\t\t\t\ttournamentNotificationType: TournamentNotificationTag.TEAM_SELECTION_REMINDER_1_DAY,\n\t// \t\t\t\t\ttournamentId: tournament._id.toString(),\n\t// \t\t\t\t\tdeepLinkRoute: tournament.deepLinkRoute,\n\t// \t\t\t\t},\n\t// \t\t\t\trecipients.map(user => user._id as mongoose.Types.ObjectId)\n\t// \t\t\t);\n\t// \t\t\tawait this.configRepository.setNotificationFlag(\n\t// \t\t\t\ttournament._id,\n\t// \t\t\t\tTournamentNotificationTag.TEAM_SELECTION_REMINDER_1_DAY\n\t// \t\t\t);\n\t// \t\t})\n\t// \t);\n\t// }\n\n\tprivate async dispatchTournamentActivationNotification(\n\t\ttournament: TournamentDocument,\n\t\ttemplates: Map<TournamentNotificationTag, NotificationMessage>\n\t): Promise<void> {\n\t\tconst flags = new Map(Object.entries(tournament.notificationFlags || {}) as Array<[TournamentNotificationTag, boolean]>);\n\t\tif (flags.get(TournamentNotificationTag.TOURNAMENT_ACTIVATION) === true) return;\n\n\t\tconst template = templates.get(TournamentNotificationTag.TOURNAMENT_ACTIVATION);\n\t\tif (!template) return;\n\n\t\tawait this.notificationService.notifyGlobal({\n\t\t\ttitle: template.title,\n\t\t\tbody: template.body,\n\t\t\ttournamentNotificationType: TournamentNotificationTag.TOURNAMENT_ACTIVATION,\n\t\t\ttournamentId: tournament._id.toString(),\n\t\t\tdeepLinkRoute: tournament.deepLinkRoute,\n\t\t});\n\t\tawait this.configRepository.setNotificationFlag(\n\t\t\ttournament._id,\n\t\t\tTournamentNotificationTag.TOURNAMENT_ACTIVATION\n\t\t);\n\t}\n\n\tpublic async dispatchPending(): Promise<void> {\n\t\tconst tournament = await this.configRepository.findActiveFull();\n\t\tif (!tournament) return;\n\n\t\tconst tournamentId = tournament._id;\n\t\tconst templates = await this.templateRepository.findTemplates(tournamentId);\n\t\tconst now = Date.now();\n\n\t\tawait this.dispatchTournamentActivationNotification(tournament, templates);\n\n\t\tawait Promise.all(\n\t\t\ttournament.matches.map(match =>\n\t\t\t\tPromise.all(\n\t\t\t\t\ttournament.scheduledNotifications.map(async ({ type, durationMins, target }) => {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t![\n\t\t\t\t\t\t\t\tTournamentNotificationTag.PREDICTION_REMINDER_15_MINUTES,\n\t\t\t\t\t\t\t\tTournamentNotificationTag.PREDICTION_REMINDER_3_HOURS,\n\t\t\t\t\t\t\t].includes(type)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\tconst notificationTime = new Date(match.startingDate).getTime() - durationMins * 60 * 1000;\n\t\t\t\t\t\tconst flags = match.notificationFlags as unknown as Record<string, boolean> | undefined;\n\n\t\t\t\t\t\tif (now < notificationTime) return;\n\t\t\t\t\t\tif (flags?.[type] === true) return;\n\n\t\t\t\t\t\tawait this.notificationService.dispatchScheduledJob(\n\t\t\t\t\t\t\ttype,\n\t\t\t\t\t\t\ttarget,\n\t\t\t\t\t\t\ttemplates,\n\t\t\t\t\t\t\ttournamentId,\n\t\t\t\t\t\t\t[match.team1.teamId, match.team2.teamId],\n\t\t\t\t\t\t\tmatch._id,\n match.startingDate,\n\t\t\t\t\t\t\ttournament.deepLinkRoute,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tawait this.matchRepository.setNotificationFlag(tournamentId, match._id, type);\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\t}\n}\n\nexport const scheduleDispatchService = Container.get(ScheduleService);\n"]}
1
+ {"version":3,"file":"schedule.service.js","sourceRoot":"/","sources":["modules/tournament/schedule/schedule.service.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, {Service} from 'typedi';\nimport {getLibraries} from '@lyxa.ai/core';\nimport {SoftDeleteModel} from '@lyxa.ai/core/dist/libraries/mongo/plugins/soft-delete-plugin';\nimport {\n\tNotificationMessage,\n\tScheduledNotificationConfig,\n\tSetting,\n\tTournamentMatch,\n\tUser,\n\tUserModel,\n} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport {TournamentNotificationTag} from '@lyxa.ai/core/dist/utilities/enum';\nimport {isLyxaOpen} from '@lyxa.ai/core/dist/utilities/workHourSetting';\nimport {TournamentConfigRepository} from '../config/config.repository';\nimport {TournamentMatchRepository} from '../match/match.repository';\nimport {TournamentParticipantRepository} from '../participant/participant.repository';\nimport {NotificationTemplateRepository} from '../notification/notification-template.repository';\nimport {TournamentNotificationService} from '../notification/notification.service';\nimport {TournamentDocument} from '../config/config.types';\n\n@Service()\nexport class ScheduleService {\n\tprivate configRepository: TournamentConfigRepository;\n\tprivate matchRepository: TournamentMatchRepository;\n\tprivate participantRepository: TournamentParticipantRepository;\n\tprivate templateRepository: NotificationTemplateRepository;\n\tprivate notificationService: TournamentNotificationService;\n\tprivate userModel: typeof UserModel & SoftDeleteModel<User>;\n\n\tconstructor() {\n\t\tthis.configRepository = Container.get(TournamentConfigRepository);\n\t\tthis.matchRepository = Container.get(TournamentMatchRepository);\n\t\tthis.participantRepository = Container.get(TournamentParticipantRepository);\n\t\tthis.templateRepository = Container.get(NotificationTemplateRepository);\n\t\tthis.notificationService = Container.get(TournamentNotificationService);\n\t\tthis.userModel = UserModel as typeof UserModel & SoftDeleteModel<User>;\n\t}\n\n\t// NOTE: there is a huge possibility we will not use this feature, left it out in case they want it back\n\t//\n\t// public async dispatchPreTournamentReminders(): Promise<void> {\n\t// \tconst tournaments = await this.configRepository.findPendingReminderTournaments();\n\t// \tif (!tournaments.length) return;\n\t//\n\t// \tawait Promise.all(\n\t// \t\ttournaments.map(async tournament => {\n\t// \t\t\tconst templates = await this.templateRepository.findTemplates(tournament._id);\n\t// \t\t\tconst reminderTemplate = templates.get(TournamentNotificationTag.TEAM_SELECTION_REMINDER_1_DAY);\n\t// \t\t\tif (!reminderTemplate) return;\n\t//\n\t// \t\t\tconst participants = await this.participantRepository.findByTournament(tournament._id);\n\t// \t\t\tconst usersWithTeam = participants\n\t// \t\t\t\t.filter(participant => participant.teamId)\n\t// \t\t\t\t.map(participant => participant.userId);\n\t// \t\t\tconst recipients = await this.userModel\n\t// \t\t\t\t.find({ _id: { $nin: usersWithTeam } })\n\t// \t\t\t\t.select('_id')\n\t// \t\t\t\t.lean();\n\t//\n\t// \t\t\tif (!recipients.length) {\n\t// \t\t\t\tawait this.configRepository.setNotificationFlag(\n\t// \t\t\t\t\ttournament._id,\n\t// \t\t\t\t\tTournamentNotificationTag.TEAM_SELECTION_REMINDER_1_DAY\n\t// \t\t\t\t);\n\t// \t\t\t\treturn;\n\t// \t\t\t}\n\t//\n\t// \t\t\tawait this.notificationService.notifyUsers(\n\t// \t\t\t\t{\n\t// \t\t\t\t\ttitle: reminderTemplate.title,\n\t// \t\t\t\t\tbody: reminderTemplate.body,\n\t// \t\t\t\t\ttournamentNotificationType: TournamentNotificationTag.TEAM_SELECTION_REMINDER_1_DAY,\n\t// \t\t\t\t\ttournamentId: tournament._id.toString(),\n\t// \t\t\t\t\tdeepLinkRoute: tournament.deepLinkRoute,\n\t// \t\t\t\t},\n\t// \t\t\t\trecipients.map(user => user._id as mongoose.Types.ObjectId)\n\t// \t\t\t);\n\t// \t\t\tawait this.configRepository.setNotificationFlag(\n\t// \t\t\t\ttournament._id,\n\t// \t\t\t\tTournamentNotificationTag.TEAM_SELECTION_REMINDER_1_DAY\n\t// \t\t\t);\n\t// \t\t})\n\t// \t);\n\t// }\n\n\tprivate async dispatchTournamentActivationNotification(\n\t\ttournament: TournamentDocument,\n\t\ttemplates: Map<TournamentNotificationTag, NotificationMessage>\n\t): Promise<void> {\n\t\tconst flags = new Map(Object.entries(tournament.notificationFlags || {}) as Array<[TournamentNotificationTag, boolean]>);\n\t\tif (flags.get(TournamentNotificationTag.TOURNAMENT_ACTIVATION) === true) return;\n\n\t\tconst template = templates.get(TournamentNotificationTag.TOURNAMENT_ACTIVATION);\n\t\tif (!template) return;\n\n\t\tawait this.notificationService.notifyGlobal({\n\t\t\ttitle: template.title,\n\t\t\tbody: template.body,\n\t\t\ttournamentNotificationType: TournamentNotificationTag.TOURNAMENT_ACTIVATION,\n\t\t\ttournamentId: tournament._id.toString(),\n\t\t\tdeepLinkRoute: tournament.deepLinkRoute,\n\t\t});\n\t\tawait this.configRepository.setNotificationFlag(\n\t\t\ttournament._id,\n\t\t\tTournamentNotificationTag.TOURNAMENT_ACTIVATION\n\t\t);\n\t}\n\n\tprivate static readonly REMINDER_TYPES: ReadonlySet<TournamentNotificationTag> = new Set([\n\t\tTournamentNotificationTag.PREDICTION_REMINDER_15_MINUTES,\n\t\tTournamentNotificationTag.PREDICTION_REMINDER_3_HOURS,\n\t\tTournamentNotificationTag.PREDICTION_REMINDER_1_HOUR,\n\t]);\n\n\tpublic async dispatchPending(): Promise<void> {\n\t\tconst tournament = await this.configRepository.findActiveFull();\n\t\tif (!tournament) return;\n\n\t\tconst templates = await this.templateRepository.findTemplates(tournament._id);\n\n\t\tawait this.dispatchTournamentActivationNotification(tournament, templates);\n\t\tawait this.dispatchDueReminders(tournament, templates);\n\t}\n\n\tprivate async dispatchDueReminders(\n\t\ttournament: TournamentDocument,\n\t\ttemplates: Map<TournamentNotificationTag, NotificationMessage>\n\t): Promise<void> {\n\t\tawait Promise.all(\n\t\t\ttournament.matches.flatMap(match =>\n\t\t\t\ttournament.scheduledNotifications.map(scheduled =>\n\t\t\t\t\tthis.dispatchReminder(tournament, match, scheduled, templates)\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\t}\n\n\tprivate async dispatchReminder(\n\t\ttournament: TournamentDocument,\n\t\tmatch: TournamentMatch,\n\t\tscheduled: ScheduledNotificationConfig,\n\t\ttemplates: Map<TournamentNotificationTag, NotificationMessage>\n\t): Promise<void> {\n\t\tconst {type, target, durationMins} = scheduled;\n\n\t\tif (!ScheduleService.REMINDER_TYPES.has(type)) return;\n\t\tif (this.alreadySent(match, type)) return;\n\t\tif (!this.isDue(match, durationMins)) return;\n\n\t\tif (await this.canSendNow(type)) await this.notificationService.dispatchScheduledReminder({\n\t\t\ttournament,\n\t\t\tmatch,\n\t\t\ttemplates,\n\t\t\ttype,\n\t\t\ttarget\n\t\t});\n\n\t\tawait this.matchRepository.setNotificationFlag(tournament._id, match._id, type);\n\t}\n\n\tprivate isDue(match: TournamentMatch, durationMins: number): boolean {\n\t\tconst notificationTime = new Date(match.startingDate).getTime() - durationMins * 60 * 1000;\n\t\treturn Date.now() >= notificationTime;\n\t}\n\n\tprivate alreadySent(match: TournamentMatch, type: TournamentNotificationTag): boolean {\n\t\tconst flags = match.notificationFlags as unknown as Record<string, boolean> | undefined;\n\t\treturn flags?.[type] === true;\n\t}\n\n\t// The 1-hour reminder targets users who already predicted, so it's only worth sending while Lyxa\n\t// is open. Every other reminder can go out at any time.\n\tprivate async canSendNow(type: TournamentNotificationTag): Promise<boolean> {\n\t\tif (type !== TournamentNotificationTag.PREDICTION_REMINDER_1_HOUR) return true;\n\t\treturn this.isCompanyOpen();\n\t}\n\n\tprivate async isCompanyOpen(): Promise<boolean> {\n\t\tconst settings = (await getLibraries().getCachedSettingsService().getSettings()) as Setting | null;\n\t\t// Without configured working hours we can't confirm we're open, so hold the reminder for a later run.\n\t\tif (!settings?.workHourSetting) return false;\n\t\treturn isLyxaOpen(settings.workHourSetting);\n\t}\n}\n\nexport const scheduleDispatchService = Container.get(ScheduleService);\n"]}
@@ -10,8 +10,8 @@ function fillMissingPeriods(results, startDate, endDate, type, defaultFields) {
10
10
  resultMap.set(item.date, item);
11
11
  }
12
12
  const fieldKeys = Object.keys(defaultFields);
13
- const unit = type === enum_1.GraphType.MONTHLY ? 'month' : 'day';
14
- const dateFormat = type === enum_1.GraphType.MONTHLY ? 'YYYY-MM' : 'YYYY-MM-DD';
13
+ const unit = type === enum_1.GraphType.YEARLY ? 'year' : type === enum_1.GraphType.MONTHLY ? 'month' : 'day';
14
+ const dateFormat = type === enum_1.GraphType.YEARLY ? 'YYYY' : type === enum_1.GraphType.MONTHLY ? 'YYYY-MM' : 'YYYY-MM-DD';
15
15
  let current = (0, dayjs_1.dayjs)(startDate).startOf(unit);
16
16
  const end = (0, dayjs_1.dayjs)(endDate).startOf(unit);
17
17
  while (current.isBefore(end) || current.isSame(end)) {