@@ -58,6 +58,7 @@ type GQLQuestDashboard = {
5858 level : GQLQuestLevel ;
5959 currentStreak : number ;
6060 longestStreak : number ;
61+ hasNewQuestRotations : boolean ;
6162 daily : GQLQuestBucket ;
6263 weekly : GQLQuestBucket ;
6364 milestone : GQLUserQuest [ ] ;
@@ -259,6 +260,30 @@ const getQuestStreaks = async ({
259260 } ;
260261} ;
261262
263+ const getLatestActiveQuestRotationCreatedAt = async ( {
264+ con,
265+ now,
266+ } : {
267+ con : EntityManager ;
268+ now : Date ;
269+ } ) : Promise < Date | null > => {
270+ const result = await con
271+ . getRepository ( QuestRotation )
272+ . createQueryBuilder ( 'rotation' )
273+ . select ( 'MAX(rotation."createdAt")' , 'latestCreatedAt' )
274+ . where ( 'rotation."periodStart" <= :now' , { now } )
275+ . andWhere ( 'rotation."periodEnd" > :now' , { now } )
276+ . getRawOne < { latestCreatedAt : Date | string | null } > ( ) ;
277+
278+ if ( ! result ?. latestCreatedAt ) {
279+ return null ;
280+ }
281+
282+ const latestCreatedAt = new Date ( result . latestCreatedAt ) ;
283+
284+ return Number . isNaN ( latestCreatedAt . getTime ( ) ) ? null : latestCreatedAt ;
285+ } ;
286+
262287const getQuestDashboard = async ( {
263288 con,
264289 userId,
@@ -270,50 +295,86 @@ const getQuestDashboard = async ({
270295 isPlus : boolean ;
271296 now : Date ;
272297} ) : Promise < GQLQuestDashboard > => {
273- const [ profile , dailyQuests , weeklyQuests , milestoneQuests , streaks ] =
274- await Promise . all ( [
275- con . getRepository ( UserQuestProfile ) . findOne ( {
276- where : {
277- userId,
278- } ,
279- } ) ,
280- getCurrentUserQuestsByType ( {
281- con,
282- userId,
283- type : QuestType . Daily ,
284- isPlus,
285- now,
286- } ) ,
287- getCurrentUserQuestsByType ( {
288- con,
289- userId,
290- type : QuestType . Weekly ,
291- isPlus,
292- now,
293- } ) ,
294- getCurrentUserQuestsByType ( {
295- con,
296- userId,
297- type : QuestType . Milestone ,
298- isPlus,
299- now,
300- } ) ,
301- getQuestStreaks ( {
302- con,
298+ const [
299+ profile ,
300+ dailyQuests ,
301+ weeklyQuests ,
302+ milestoneQuests ,
303+ streaks ,
304+ latestActiveQuestRotationCreatedAt ,
305+ ] = await Promise . all ( [
306+ con . getRepository ( UserQuestProfile ) . findOne ( {
307+ where : {
303308 userId,
304- now,
305- } ) ,
306- ] ) ;
309+ } ,
310+ } ) ,
311+ getCurrentUserQuestsByType ( {
312+ con,
313+ userId,
314+ type : QuestType . Daily ,
315+ isPlus,
316+ now,
317+ } ) ,
318+ getCurrentUserQuestsByType ( {
319+ con,
320+ userId,
321+ type : QuestType . Weekly ,
322+ isPlus,
323+ now,
324+ } ) ,
325+ getCurrentUserQuestsByType ( {
326+ con,
327+ userId,
328+ type : QuestType . Milestone ,
329+ isPlus,
330+ now,
331+ } ) ,
332+ getQuestStreaks ( {
333+ con,
334+ userId,
335+ now,
336+ } ) ,
337+ getLatestActiveQuestRotationCreatedAt ( {
338+ con,
339+ now,
340+ } ) ,
341+ ] ) ;
307342
308343 return {
309344 level : getQuestLevelState ( profile ?. totalXp ?? 0 ) ,
310345 ...streaks ,
346+ hasNewQuestRotations :
347+ ! ! latestActiveQuestRotationCreatedAt &&
348+ ( ! profile ?. lastViewedQuestRotationsAt ||
349+ profile . lastViewedQuestRotationsAt <
350+ latestActiveQuestRotationCreatedAt ) ,
311351 daily : toQuestBucket ( dailyQuests ) ,
312352 weekly : toQuestBucket ( weeklyQuests ) ,
313353 milestone : milestoneQuests ,
314354 } ;
315355} ;
316356
357+ const saveQuestRotationsViewedAt = async ( {
358+ con,
359+ userId,
360+ now,
361+ } : {
362+ con : EntityManager ;
363+ userId : string ;
364+ now : Date ;
365+ } ) : Promise < void > => {
366+ await con
367+ . createQueryBuilder ( )
368+ . insert ( )
369+ . into ( UserQuestProfile )
370+ . values ( {
371+ userId,
372+ lastViewedQuestRotationsAt : now ,
373+ } )
374+ . orUpdate ( [ 'lastViewedQuestRotationsAt' ] , [ 'userId' ] )
375+ . execute ( ) ;
376+ } ;
377+
317378const getClaimQuestRewardPayload = async ( {
318379 con,
319380 userId,
@@ -596,6 +657,7 @@ export const typeDefs = /* GraphQL */ `
596657 level: QuestLevel!
597658 currentStreak: Int!
598659 longestStreak: Int!
660+ hasNewQuestRotations: Boolean!
599661 daily: QuestBucket!
600662 weekly: QuestBucket!
601663 milestone: [UserQuest!]!
@@ -633,6 +695,7 @@ export const typeDefs = /* GraphQL */ `
633695
634696 extend type Mutation {
635697 claimQuestReward(userQuestId: ID!): ClaimQuestRewardPayload! @auth
698+ markQuestRotationsViewed: EmptyResponse! @auth
636699 trackQuestEvent(eventType: ClientQuestEventType!): EmptyResponse! @auth
637700 }
638701
@@ -697,6 +760,21 @@ export const resolvers: IResolvers<unknown, BaseContext> = {
697760
698761 return dashboard ;
699762 } ,
763+ markQuestRotationsViewed : async (
764+ _ ,
765+ __ ,
766+ ctx : AuthContext ,
767+ ) : Promise < GQLEmptyResponse > => {
768+ await saveQuestRotationsViewedAt ( {
769+ con : ctx . con . manager ,
770+ userId : ctx . userId ,
771+ now : new Date ( ) ,
772+ } ) ;
773+
774+ return {
775+ _ : true ,
776+ } ;
777+ } ,
700778 trackQuestEvent : async (
701779 _ ,
702780 { eventType } : { eventType : QuestEventType } ,
0 commit comments