Skip to content

Commit

Permalink
feat(playstreak-sync): add sync button logic (#22)
Browse files Browse the repository at this point in the history
* feat(playstreak-sync): add sync button logic

* chore: set correct pkg version

* chore: update lock

* chore: prettier
  • Loading branch information
eliobricenov authored Oct 18, 2024
1 parent 648cf4c commit b90372c
Show file tree
Hide file tree
Showing 6 changed files with 366 additions and 228 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperplay/quests-ui",
"version": "0.0.26",
"version": "0.0.27",
"description": "",
"main": "index.js",
"scripts": {
Expand All @@ -25,7 +25,7 @@
"types": "dist/index.d.ts",
"devDependencies": {
"@hyperplay/chains": "^0.3.0",
"@hyperplay/ui": "^1.8.0",
"@hyperplay/ui": "^1.8.4",
"@hyperplay/utils": "^0.2.6",
"@tanstack/query-core": "^5.59.13",
"@tanstack/react-query": "^5.51.23",
Expand Down
466 changes: 260 additions & 206 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions src/components/QuestDetailsWrapper/index.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@
.markdownDescription {
white-space: normal;
}

.syncSuccess {
display: flex;
align-items: center;
gap: var(--space-sm);
}
82 changes: 65 additions & 17 deletions src/components/QuestDetailsWrapper/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React, { useEffect, useState } from 'react'
import {
Images,
Button,
Game,
MarkdownDescription,
QuestDetails,
Expand All @@ -22,10 +24,7 @@ import { mintReward } from '../../helpers/mintReward'
import { resyncExternalTasks as resyncExternalTasksHelper } from '../../helpers/resyncExternalTask'
import useGetUserPlayStreak from '../../hooks/useGetUserPlayStreak'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import {
getPlaystreakArgsFromQuestData,
resetSessionStartedTime
} from '../../helpers/getPlaystreakArgsFromQuestData'
import { getPlaystreakArgsFromQuestData } from '../../helpers/getPlaystreakArgsFromQuestData'
import { useGetRewards } from '../../hooks/useGetRewards'
import { chainMap, parseChainMetadataToViemChain } from '@hyperplay/chains'
import { InfoAlertProps } from '@hyperplay/ui/dist/components/AlertCard'
Expand All @@ -37,6 +36,7 @@ import { injected } from 'wagmi/connectors'
import { TrackEventFn } from '@/types/analytics'
import { TFunction } from 'i18next'
import cn from 'classnames'
import { useHasPendingExternalSync } from '@/hooks/useHasPendingExternalSync'

class ClaimError extends Error {
properties: any
Expand Down Expand Up @@ -70,6 +70,7 @@ export interface QuestDetailsWrapperProps {
rewardId: number,
tokenId?: number
) => Promise<RewardClaimSignature>
getPendingExternalSync: (questId: number) => Promise<boolean>
confirmRewardClaim: (params: ConfirmClaimParams) => Promise<void>
questsWithExternalPlayStreakSync: number[]
syncPlayStreakWithExternalSource: (questId: number) => Promise<unknown>
Expand Down Expand Up @@ -104,7 +105,7 @@ export function QuestDetailsWrapper({
confirmRewardClaim,
resyncExternalTask,
getExternalTaskCredits,
syncPlaySession,
getPendingExternalSync,
logInfo,
openDiscordLink,
getDepositContracts,
Expand All @@ -115,6 +116,7 @@ export function QuestDetailsWrapper({
syncPlayStreakWithExternalSource,
questsWithExternalPlayStreakSync
}: QuestDetailsWrapperProps) {
const [syncSuccess, setSyncSuccess] = useState(false)
const rewardTypeClaimEnabled = flags.rewardTypeClaimEnabled
const {
writeContractAsync,
Expand Down Expand Up @@ -158,6 +160,63 @@ export function QuestDetailsWrapper({
)
const questPlayStreakData = questPlayStreakResult.data.data

const {
data: hasPendingExternalSync,
invalidateQuery: invalidateHasPendingExternalSync
} = useHasPendingExternalSync({
questId: selectedQuestId,
getPendingExternalSync
})

const syncWithExternalSourceMutation = useMutation({
mutationFn: async () => {
if (!selectedQuestId) {
return
}
return syncPlayStreakWithExternalSource(selectedQuestId)
},
onSuccess: async () => {
setSyncSuccess(true)
await questPlayStreakResult.invalidateQuery()
await invalidateHasPendingExternalSync()
setTimeout(() => {
setSyncSuccess(false)
}, 3000)
}
})

let streakRightSection = null

if (
selectedQuestId &&
questsWithExternalPlayStreakSync.includes(selectedQuestId) &&
hasPendingExternalSync
) {
streakRightSection = (
<Button
disabled={syncWithExternalSourceMutation.isPending}
type="secondaryGradient"
onClick={() => syncWithExternalSourceMutation.mutate()}
size="small"
>
{t('quest.playstreak.sync', 'Sync Progress')}
</Button>
)
}

if (syncSuccess) {
streakRightSection = (
<div className={styles.syncSuccess}>
<Images.Checkmark
fill="var(--color-success-500)"
width={18}
height={18}
/>
{t('quest.playstreak.syncSuccess', 'Progress synced')}
</div>
)
}

const resyncMutation = useMutation({
mutationFn: async (rewards: Reward[]) => {
const isConnectedToG7 = await checkG7ConnectionStatus()
Expand Down Expand Up @@ -592,17 +651,7 @@ export function QuestDetailsWrapper({
questMeta,
questPlayStreakData,
useModuleInitTimeForSessionStartTime: isSignedIn,
onSync: async () => {
if (questsWithExternalPlayStreakSync.includes(questMeta.id)) {
await syncPlayStreakWithExternalSource(questMeta.id)
} else {
await syncPlaySession(projectId, 'hyperplay')
resetSessionStartedTime()
logInfo(`Synced play session for quest ${questMeta.id}`)
console.log(`Synced play session for quest ${questMeta.id}`)
}
questPlayStreakResult.invalidateQuery()
}
rightSection: streakRightSection
})
},
rewards: questRewards ?? [],
Expand Down Expand Up @@ -669,7 +718,6 @@ export function QuestDetailsWrapper({
steamAccountLinked: false
},
playStreak: {
onSync: () => console.log('loading...'),
currentStreakInDays: 0,
requiredStreakInDays: 1,
minimumSessionTimeInSeconds: 100,
Expand Down
7 changes: 4 additions & 3 deletions src/helpers/getPlaystreakArgsFromQuestData.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { PlayStreakEligibility } from '@hyperplay/ui'
import { Quest, UserPlayStreak } from '@hyperplay/utils'
import { ReactNode } from 'react'

// this is initialized when the overlay is started for this game
let dateTimeCurrentSessionStartedInMsSinceEpoch = Date.now()
Expand All @@ -8,19 +9,19 @@ export function getPlaystreakArgsFromQuestData({
questMeta,
questPlayStreakData,
useModuleInitTimeForSessionStartTime,
onSync
rightSection
}: {
questMeta: Quest
questPlayStreakData: UserPlayStreak | undefined | null
useModuleInitTimeForSessionStartTime?: boolean
onSync: () => void
rightSection?: ReactNode
}): PlayStreakEligibility {
let sessionStartedTime = undefined
if (useModuleInitTimeForSessionStartTime) {
sessionStartedTime = dateTimeCurrentSessionStartedInMsSinceEpoch
}
return {
onSync,
rightSection,
requiredStreakInDays:
questMeta?.eligibility?.play_streak.required_playstreak_in_days ?? 0,
currentStreakInDays: questPlayStreakData?.current_playstreak_in_days ?? 0,
Expand Down
29 changes: 29 additions & 0 deletions src/hooks/useHasPendingExternalSync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useQueryClient, useQuery } from '@tanstack/react-query'
import { useAccount } from 'wagmi'

export function useHasPendingExternalSync({
questId,
getPendingExternalSync
}: {
questId: number | null
getPendingExternalSync: (questId: number) => Promise<boolean>
}) {
const { address } = useAccount()
const queryClient = useQueryClient()
const queryKey = ['pending-external-sync', questId, address]
const query = useQuery({
queryKey,
queryFn: async () => {
if (!questId) {
return false
}
return getPendingExternalSync(questId)
},
enabled: questId !== undefined
})

return {
...query,
invalidateQuery: async () => queryClient.invalidateQueries({ queryKey })
}
}

0 comments on commit b90372c

Please sign in to comment.