Skip to content

Commit 9c5375e

Browse files
authored
[UI/UX] Add completed quests tab (#1124)
* add completed tab logic to overlay * run yarn allow-scripts auto * fix codecheck * refactor to use hp/quests-ui, independent queries for useGetQuestStates * update to latests quests-ui * only query quest states if signed in * fix quest log loader * update quests ui * update quests ui * fix codecheck * move types, update to some * run yarn
1 parent 8d860f4 commit 9c5375e

File tree

12 files changed

+140
-163
lines changed

12 files changed

+140
-163
lines changed

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@
169169
"@fortawesome/react-fontawesome": "^0.2.2",
170170
"@hyperplay/chains": "^0.3.0",
171171
"@hyperplay/check-disk-space": "^3.5.2",
172-
"@hyperplay/quests-ui": "^0.0.28",
172+
"@hyperplay/quests-ui": "^0.0.38",
173173
"@hyperplay/ui": "^1.8.9",
174174
"@hyperplay/utils": "^0.3.4",
175175
"@mantine/carousel": "^7.12.0",
@@ -401,7 +401,8 @@
401401
"classic-level": false,
402402
"i18next-parser>esbuild": false,
403403
"wagmi>@wagmi/connectors>@metamask/sdk>@metamask/sdk-communication-layer>utf-8-validate": true,
404-
"@hyperplay/providers>@metamask/sdk>@metamask/sdk-communication-layer>utf-8-validate": true
404+
"@hyperplay/providers>@metamask/sdk>@metamask/sdk-communication-layer>utf-8-validate": true,
405+
"@hyperplay/overlay>electron": false
405406
}
406407
}
407408
}

src/common/types.ts

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
import { Channel, ContractMetadata } from '@valist/sdk/dist/typesApi'
1313
import { IconDefinition } from '@fortawesome/free-solid-svg-icons'
1414
import { DropdownItemType } from '@hyperplay/ui'
15+
export type { Quest } from '@hyperplay/utils'
1516

1617
export type {
1718
Listing as HyperPlayRelease,
@@ -932,30 +933,6 @@ export interface Reward {
932933
numClaimsLeft: string
933934
}
934935

935-
export interface Quest {
936-
id: number
937-
project_id: string
938-
name: string
939-
type: 'REPUTATIONAL-AIRDROP' | 'PLAYSTREAK'
940-
status: string
941-
description: string
942-
rewards?: Reward[]
943-
/* eslint-disable-next-line */
944-
deposit_contracts: any[]
945-
eligibility?: {
946-
completion_threshold?: number
947-
steam_games: { id: string }[]
948-
play_streak: {
949-
required_playstreak_in_days: number
950-
minimum_session_time_in_seconds: number
951-
}
952-
}
953-
quest_external_game: null | {
954-
runner: Runner
955-
store_redirect_url: string
956-
}
957-
}
958-
959936
export interface RewardClaimSignature {
960937
signature: `0x${string}`
961938
nonce: string
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.questLog {
22
margin: 0 var(--space-sm) 0 0;
3-
min-width: 280px;
3+
min-width: 320px;
44
max-width: 400px;
55
}

src/frontend/components/UI/QuestsViewer/components/QuestLogWrapper/index.tsx

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import {
77
} from '@hyperplay/ui'
88
import styles from './index.module.scss'
99
import { useTranslation } from 'react-i18next'
10-
import { Quest } from 'common/types'
1110
import useGetG7UserCredits from 'frontend/hooks/useGetG7UserCredits'
1211
import useGetPointsBalancesForProject from 'frontend/hooks/useGetPointsBalances'
1312
import useGetQuests from 'frontend/hooks/useGetQuests'
13+
import { useGetQuestStates } from 'frontend/hooks/useGetQuestStates'
1414

1515
export interface QuestLogWrapperProps {
1616
questsResults: ReturnType<typeof useGetQuests>
@@ -31,6 +31,27 @@ export function QuestLogWrapper({
3131
const pointsBalancesQuery = useGetPointsBalancesForProject(appName)
3232
const pointsBalances = pointsBalancesQuery?.data?.data
3333
const { t } = useTranslation()
34+
const { questIdToQuestStateMap, isPending: isGetQuestStatesPending } =
35+
useGetQuestStates({
36+
quests
37+
})
38+
39+
const questsUi =
40+
quests?.map((quest) => {
41+
const questUi_i: QuestLogInfo = {
42+
questType: quest.type,
43+
title: quest.name,
44+
state: Object.hasOwn(questIdToQuestStateMap, quest.id)
45+
? questIdToQuestStateMap[quest.id]
46+
: 'ACTIVE',
47+
onClick: () => {
48+
setSelectedQuestId(quest.id)
49+
},
50+
selected: selectedQuestId === quest.id,
51+
id: quest.id
52+
}
53+
return questUi_i
54+
}) ?? []
3455

3556
const i18n: QuestLogTranslations = {
3657
quests: t('quest.quests', 'Quests'),
@@ -68,38 +89,19 @@ export function QuestLogWrapper({
6889
}
6990

7091
let questLog = null
71-
if (Array.isArray(quests)) {
72-
const questsUi = quests.map((val: Quest) => {
73-
const questUi_i: QuestLogInfo = {
74-
questType: val.type,
75-
title: val.name,
76-
state: 'ACTIVE',
77-
onClick: () => {
78-
setSelectedQuestId(val.id)
79-
},
80-
selected: selectedQuestId === val.id,
81-
id: val.id
82-
}
83-
return questUi_i
84-
})
85-
questLog = (
86-
<QuestLog
87-
quests={questsUi}
88-
className={styles.questLog}
89-
i18n={i18n}
90-
pointsProps={pointsBalanceProps}
91-
/>
92-
)
93-
} else if (questsResults?.data.isLoading || questsResults?.data.isFetching) {
94-
questLog = (
95-
<QuestLog
96-
quests={[]}
97-
className={styles.questLog}
98-
loading={true}
99-
i18n={i18n}
100-
/>
101-
)
102-
}
92+
const isLoading =
93+
questsResults?.data.isLoading ||
94+
questsResults?.data.isFetching ||
95+
isGetQuestStatesPending
96+
questLog = (
97+
<QuestLog
98+
quests={questsUi ?? []}
99+
className={styles.questLog}
100+
i18n={i18n}
101+
pointsProps={pointsBalanceProps}
102+
loading={isLoading}
103+
/>
104+
)
103105

104106
if (!quests?.length) {
105107
return null

src/frontend/components/UI/QuestsViewer/index.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@ import styles from './index.module.scss'
33
import { QuestLogWrapper } from './components/QuestLogWrapper'
44
import { Alert } from '@hyperplay/ui'
55
import { useTranslation } from 'react-i18next'
6-
import { QuestDetailsWrapper } from '@hyperplay/quests-ui'
6+
import { QuestDetailsWrapper, useGetUserPlayStreak } from '@hyperplay/quests-ui'
77
import { useFlags } from 'launchdarkly-react-client-sdk'
88
import authState from 'frontend/state/authState'
99
import useAuthSession from 'frontend/hooks/useAuthSession'
1010
import '@hyperplay/quests-ui/style.css'
1111
import { Reward } from 'common/types'
1212
import useGetQuests from 'frontend/hooks/useGetQuests'
13-
import useGetUserPlayStreak from 'frontend/hooks/useGetUserPlayStreak'
1413
import { useSyncPlayStreakWithExternalSource } from 'frontend/hooks/useSyncPlayStreakWithExternalSource'
1514
import { useAccount } from 'wagmi'
1615

@@ -29,7 +28,10 @@ export function QuestsViewer({ projectId: appName }: QuestsViewerProps) {
2928
const initialQuestId = quests?.[0]?.id ?? null
3029
const visibleQuestId = selectedQuestId ?? initialQuestId
3130
const sessionEmail = data?.linkedAccounts.get('email')
32-
const { invalidateQuery } = useGetUserPlayStreak(visibleQuestId)
31+
const { invalidateQuery } = useGetUserPlayStreak(
32+
visibleQuestId,
33+
window.api.getUserPlayStreak
34+
)
3335

3436
const getPendingExternalSync = useCallback(async () => {
3537
if (!address || !visibleQuestId || !isSignedIn) return false
@@ -123,7 +125,6 @@ export function QuestsViewer({ projectId: appName }: QuestsViewerProps) {
123125
getQuestRewardSignature={window.api.getQuestRewardSignature}
124126
confirmRewardClaim={window.api.confirmRewardClaim}
125127
getExternalTaskCredits={window.api.getExternalTaskCredits}
126-
syncPlaySession={window.api.syncPlaySession}
127128
getDepositContracts={window.api.getDepositContracts}
128129
openSignInModal={authState.openSignInModal}
129130
resyncExternalTask={async (rewardId: string) => {

src/frontend/hooks/useGetQuest.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import {
2+
getPlaystreakQuestStatus,
3+
getUserPlaystreakQueryOptions,
4+
getQuestQueryOptions
5+
} from '@hyperplay/quests-ui'
6+
import { QuestLogInfo } from '@hyperplay/ui'
7+
import { Quest } from '@hyperplay/utils'
8+
import { useQueries } from '@tanstack/react-query'
9+
import useAuthSession from './useAuthSession'
10+
11+
export interface UseGetQuestLogInfosProps {
12+
quests?: Quest[] | null
13+
}
14+
15+
type getQuestQueryOptionsType = ReturnType<typeof getQuestQueryOptions>
16+
type getUserPlaystreakQueryOptionsType = ReturnType<
17+
typeof getUserPlaystreakQueryOptions
18+
>
19+
export function useGetQuestStates({ quests }: UseGetQuestLogInfosProps) {
20+
const { isSignedIn } = useAuthSession()
21+
let getQuestQueries: getQuestQueryOptionsType[] = []
22+
if (isSignedIn) {
23+
getQuestQueries =
24+
quests?.map((quest) =>
25+
getQuestQueryOptions(quest.id, window.api.getQuest)
26+
) ?? []
27+
}
28+
const getQuestQuery = useQueries({
29+
queries: getQuestQueries
30+
})
31+
32+
let getUserPlaystreakQueries: getUserPlaystreakQueryOptionsType[] = []
33+
if (isSignedIn) {
34+
getUserPlaystreakQueries =
35+
quests?.map((quest) =>
36+
getUserPlaystreakQueryOptions(quest.id, window.api.getUserPlayStreak)
37+
) ?? []
38+
}
39+
const getUserPlaystreakQuery = useQueries({
40+
queries: getUserPlaystreakQueries
41+
})
42+
43+
const questMap: Record<number, Quest> = {}
44+
getQuestQuery
45+
.filter((val) => !!val.data)
46+
.forEach((val) => {
47+
if (!val.data) {
48+
return
49+
}
50+
questMap[val.data.id] = val.data
51+
})
52+
53+
const questIdToQuestStateMap: Record<number, QuestLogInfo['state']> = {}
54+
55+
getUserPlaystreakQuery.forEach((val) => {
56+
if (!val.data || !Object.hasOwn(questMap, val.data.questId)) {
57+
return
58+
}
59+
const questId = val.data.questId
60+
const questData = questMap[questId]
61+
return (questIdToQuestStateMap[questId] = getPlaystreakQuestStatus(
62+
questData,
63+
val.data.userPlayStreak
64+
))
65+
})
66+
67+
const allQueries = [...getQuestQuery, ...getUserPlaystreakQuery]
68+
69+
return {
70+
isPending: allQueries.some((val) => val.status === 'pending'),
71+
isLoading: allQueries.some((val) => val.isLoading || val.isFetching),
72+
questIdToQuestStateMap
73+
}
74+
}

src/frontend/hooks/useGetRewards.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { useQuery, useQueryClient } from '@tanstack/react-query'
2-
import useGetQuest from './useGetQuest'
32
import { getDecimalNumberFromAmount } from '@hyperplay/utils'
43
import { getRewardCategory } from 'frontend/helpers/getRewardCategory'
54
import { useTranslation } from 'react-i18next'
65
import { QuestReward } from '@hyperplay/ui'
6+
import { useGetQuest } from '@hyperplay/quests-ui'
77

88
export function useGetRewards(questId: number | null) {
9-
const questResult = useGetQuest(questId)
9+
const questResult = useGetQuest(questId, window.api.getQuest)
1010
const questMeta = questResult.data.data
1111

1212
const queryClient = useQueryClient()

src/frontend/hooks/useGetUserPlayStreak.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.

src/frontend/hooks/useSyncInterval.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)