diff --git a/packages/extension-koni-ui/src/Popup/Home/Airdrop/AirdropDetail/index.tsx b/packages/extension-koni-ui/src/Popup/Home/Airdrop/AirdropDetail/index.tsx index 809860df12..3fa2a1506a 100644 --- a/packages/extension-koni-ui/src/Popup/Home/Airdrop/AirdropDetail/index.tsx +++ b/packages/extension-koni-ui/src/Popup/Home/Airdrop/AirdropDetail/index.tsx @@ -1,12 +1,13 @@ // Copyright 2019-2022 @subwallet/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 +import DefaultLogosMap from '@subwallet/extension-koni-ui/assets/logo'; import { Layout, LoadingScreen, TabGroup } from '@subwallet/extension-koni-ui/components'; import { TabGroupItemType } from '@subwallet/extension-koni-ui/components/Common/TabGroup'; import { BookaSdk } from '@subwallet/extension-koni-ui/connector/booka/sdk'; -import { AirdropCampaign } from '@subwallet/extension-koni-ui/connector/booka/types'; -import { TelegramConnector } from '@subwallet/extension-koni-ui/connector/telegram'; import { AirdropCampaign, AirdropEligibility, AirdropRaffle, AirdropRewardHistoryLog } from '@subwallet/extension-koni-ui/connector/booka/types'; +import { TelegramConnector } from '@subwallet/extension-koni-ui/connector/telegram'; +import useNotification from '@subwallet/extension-koni-ui/hooks/common/useNotification'; import useTranslation from '@subwallet/extension-koni-ui/hooks/common/useTranslation'; import { AirdropDetailAbout } from '@subwallet/extension-koni-ui/Popup/Home/Airdrop/AirdropDetail/About'; import { AirdropDetailCondition } from '@subwallet/extension-koni-ui/Popup/Home/Airdrop/AirdropDetail/Condition'; @@ -20,8 +21,7 @@ import { Alarm, ArrowCircleRight, CheckCircle, ShareNetwork } from 'phosphor-rea import React, { Context, useCallback, useContext, useEffect, useMemo, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import styled, { ThemeContext } from 'styled-components'; -import useNotification from '@subwallet/extension-koni-ui/hooks/common/useNotification'; -import DefaultLogosMap from '@subwallet/extension-koni-ui/assets/logo'; + type WrapperProps = ThemeProps; type Props = ThemeProps & { currentAirdrop: AirdropCampaign; @@ -41,7 +41,7 @@ const enum buttonTypeConst { RAFFLE = 2, INELIGIBLE = 3, END_CAMPAIGN = 4 -}; +} const enum AirdropCampaignProcess { RAFFLE = 'RAFFLE', @@ -104,6 +104,7 @@ const Component: React.FC = ({ className, currentAirdrop }: Props) => { const fetchEligibility = useCallback(async () => { try { const data = await apiSDK.subscribeCheckEligibility(currentAirdrop.airdrop_campaign_id) as unknown as AirdropEligibility; + if (data) { setEligibility(data); currentAirdrop.eligibilityIds = data.eligibilityIds; @@ -115,7 +116,8 @@ const Component: React.FC = ({ className, currentAirdrop }: Props) => { const fetchHistory = useCallback(async () => { try { - const data = await apiSDK.subscribeAirdropHistory(currentAirdrop.airdrop_campaign_id) as unknown as AirdropRewardHistoryLog; + const data = await apiSDK.subscribeAirdropHistory(currentAirdrop.airdrop_campaign_id) as AirdropRewardHistoryLog; + if (data) { setAirdropHistory(data); } @@ -179,20 +181,18 @@ const Component: React.FC = ({ className, currentAirdrop }: Props) => { } else { return buttonTypeConst.INELIGIBLE; } - })(); - const onRaffle = useCallback(async () => { try { - const result = await apiSDK.subscribeAirdropRaffle(currentAirdrop.airdrop_campaign_id) as unknown as AirdropRaffle; + const result = await apiSDK.subscribeAirdropRaffle(currentAirdrop.airdrop_campaign_id) as AirdropRaffle; + setRaffle(result); showLoadingRaffle(true); setTimeout(() => { showLoadingRaffle(false); activeModal(rewardModalId); - },3000); - + }, 3000); } catch (error) { setRaffle(null); console.log('error', error); @@ -205,8 +205,10 @@ const Component: React.FC = ({ className, currentAirdrop }: Props) => { const onClaim = useCallback(async (airdrop_record_id?: number) => { setIsLoading(true); + try { let airdropRecordLogId; + if (raffle) { airdropRecordLogId = raffle.airdropRecordLogId; } else if (airdrop_record_id !== undefined) { @@ -214,6 +216,7 @@ const Component: React.FC = ({ className, currentAirdrop }: Props) => { } else { throw new Error('No airdrop record ID available'); } + await apiSDK.subscribeAirdropClaim(airdropRecordLogId); notify({ @@ -233,95 +236,95 @@ const Component: React.FC = ({ className, currentAirdrop }: Props) => { setIsLoading(false); setClaim(false); } - }, [raffle,notify, inactiveModal]); + }, [raffle, notify, inactiveModal]); const onClaimLater = useCallback(() => { inactiveModal(rewardModalId); }, [inactiveModal]); - const renderButton = () => { return ( <> - {eligibility ? ( - <> - {buttonType === buttonTypeConst.INELIGIBLE && ( - - )} - {buttonType === buttonTypeConst.END_CAMPAIGN && ( - - )} - {buttonType === buttonTypeConst.ELIGIBLE && ( - - )} - {buttonType === buttonTypeConst.RAFFLE && ( - - )} - - ) : ( - - )} + {eligibility + ? ( + <> + {buttonType === buttonTypeConst.INELIGIBLE && ( + + )} + {buttonType === buttonTypeConst.END_CAMPAIGN && ( + + )} + {buttonType === buttonTypeConst.ELIGIBLE && ( + + )} + {buttonType === buttonTypeConst.RAFFLE && ( + + )} + + ) + : ( + + )} ); }; - return ( = ({ className, currentAirdrop }: Props) => { { selectedTab === TabType.HISTORY && ( ) @@ -378,15 +381,18 @@ const Component: React.FC = ({ className, currentAirdrop }: Props) => { {loadingRaffle && ( - Loading... + Loading... ) } diff --git a/packages/extension-koni-ui/src/connector/booka/sdk.ts b/packages/extension-koni-ui/src/connector/booka/sdk.ts index cfa03514ef..ed197118fa 100644 --- a/packages/extension-koni-ui/src/connector/booka/sdk.ts +++ b/packages/extension-koni-ui/src/connector/booka/sdk.ts @@ -7,10 +7,10 @@ import { AccountRankType, AirdropCampaign, AirdropEligibility, BookaAccount, Ene import { TelegramConnector } from '@subwallet/extension-koni-ui/connector/telegram'; import { signRaw } from '@subwallet/extension-koni-ui/messaging'; import { InGameItem } from '@subwallet/extension-koni-ui/Popup/Home/Games/types'; +import { populateTemplateString } from '@subwallet/extension-koni-ui/utils'; import { calculateStartAndEnd, formatDateFully } from '@subwallet/extension-koni-ui/utils/date'; import fetch from 'cross-fetch'; import { BehaviorSubject } from 'rxjs'; -import { populateTemplateString } from '@subwallet/extension-koni-ui/utils'; export const GAME_API_HOST = process.env.GAME_API_HOST || 'https://game-api.anhmtv.xyz'; export const TELEGRAM_WEBAPP_LINK = process.env.TELEGRAM_WEBAPP_LINK || 'Playnation_bot/app'; @@ -47,8 +47,7 @@ export class BookaSdk { private checkEligibility = new BehaviorSubject([]); isEnabled = new BehaviorSubject(true); - - constructor() { + constructor () { storage.getItem('cache-version').then((version) => { if (cacheVersion === version) { storage.getItems(Object.values(CACHE_KEYS)).then(([account, taskCategory, tasks, game, energyConfig, rankInfoMap]) => { @@ -121,67 +120,67 @@ export class BookaSdk { }).catch(console.error); } - public get waitForSync() { + public get waitForSync () { return this.syncHandler.promise; } - public get account() { + public get account () { return this.accountSubject.value; } - public get energyConfig() { + public get energyConfig () { return this.energyConfigSubject.value; } - public get taskList() { + public get taskList () { return this.taskListSubject.value; } - public get taskCategoryList() { + public get taskCategoryList () { return this.taskCategoryListSubject.value; } - public get gameList() { + public get gameList () { return this.gameListSubject.value; } - public get gameItemMap() { + public get gameItemMap () { return this.gameItemMapSubject.value; } - public get gameItemInGameList() { + public get gameItemInGameList () { return this.gameItemInGame.value; } - public get gameInventoryItemList() { + public get gameInventoryItemList () { return this.gameInventoryItemListSubject.value; } - public get gameInventoryItemInGameList() { + public get gameInventoryItemInGameList () { return this.gameInventoryItemInGame.value; } - public get leaderBoard() { + public get leaderBoard () { return this.leaderBoardSubject.value; } - public get referralList() { + public get referralList () { return this.referralListSubject.value; } - public get currentGamePlay() { + public get currentGamePlay () { return this.currentGamePlaySubject.value; } - public get rankInfoMap() { + public get rankInfoMap () { return this.rankInfoSubject.value; } - public get airdropCampaignList() { + public get airdropCampaignList () { return this.airdropCampaignSubject.value; } - private getRequestHeader() { + private getRequestHeader () { const header: Record = { 'Content-Type': 'application/json' }; @@ -193,7 +192,7 @@ export class BookaSdk { return header; } - private async getRequest(url: string) { + private async getRequest (url: string) { const request = await fetch(url, { method: 'GET', headers: this.getRequestHeader() @@ -206,7 +205,7 @@ export class BookaSdk { } } - private async postRequest(url: string, body: any) { + private async postRequest (url: string, body: any) { const response = await fetch(url, { method: 'POST', headers: this.getRequestHeader(), @@ -222,7 +221,7 @@ export class BookaSdk { return await response.json() as T; } - private async reloadAccount() { + private async reloadAccount () { const account = this.account; const newAccountData = await this.getRequest>(`${GAME_API_HOST}/api/account/get-attribute`); @@ -236,11 +235,11 @@ export class BookaSdk { storage.setItem(CACHE_KEYS.account, JSON.stringify(account)).catch(console.error); } - subscribeAccount() { + subscribeAccount () { return this.accountSubject; } - async fetchEnergyConfig() { + async fetchEnergyConfig () { const energyConfig = await this.getRequest(`${GAME_API_HOST}/api/shop/get-config-buy-energy`); if (energyConfig) { @@ -249,11 +248,11 @@ export class BookaSdk { } } - subscribeEnergyConfig() { + subscribeEnergyConfig () { return this.energyConfigSubject; } - async fetchGameList() { + async fetchGameList () { const gameList = await this.getRequest(`${GAME_API_HOST}/api/game/fetch`); if (gameList) { @@ -262,11 +261,11 @@ export class BookaSdk { } } - subscribeGameList() { + subscribeGameList () { return this.gameListSubject; } - async fetchTaskCategoryList() { + async fetchTaskCategoryList () { await this.waitForSync; const taskCategoryList = await this.getRequest(`${GAME_API_HOST}/api/task-category/fetch`); @@ -276,11 +275,11 @@ export class BookaSdk { } } - subscribeTaskCategoryList() { + subscribeTaskCategoryList () { return this.taskCategoryListSubject; } - async fetchTaskList() { + async fetchTaskList () { await this.waitForSync; const taskList = await this.getRequest(`${GAME_API_HOST}/api/task/history`); @@ -290,11 +289,11 @@ export class BookaSdk { } } - subscribeTaskList() { + subscribeTaskList () { return this.taskListSubject; } - async completeTask(taskHistoryId: number | undefined) { + async completeTask (taskHistoryId: number | undefined) { const taskHistoryCheck = await this.postRequest<{ completed: boolean }>(`${GAME_API_HOST}/api/task/check-complete-task`, { taskHistoryId: taskHistoryId }); if (taskHistoryCheck && taskHistoryCheck.completed) { @@ -306,7 +305,7 @@ export class BookaSdk { return false; } - async finishTask(taskId: number, extrinsicHash: string, network: string) { + async finishTask (taskId: number, extrinsicHash: string, network: string) { await this.postRequest(`${GAME_API_HOST}/api/task/submit`, { taskId, extrinsicHash, network }); await this.fetchTaskCategoryList(); @@ -316,7 +315,7 @@ export class BookaSdk { await this.reloadAccount(); } - getInviteURL(): string { + getInviteURL (): string { return `https://t.me/${TELEGRAM_WEBAPP_LINK}?startapp=${this.account?.info.inviteCode || 'booka'}`; } @@ -343,8 +342,7 @@ export class BookaSdk { const start = formatDateFully(new Date(startDate)); const end = formatDateFully(new Date(endDate)); const leaderBoard = await this.postRequest(`${GAME_API_HOST}/api/game/leader-board`, - { - startDate: start, + { startDate: start, endDate: end, gameId: gameId, limit: 1 }); @@ -370,13 +368,13 @@ export class BookaSdk { } } - subscribeReferralList() { + subscribeReferralList () { this.fetchReferalList().catch(console.error); return this.referralListSubject; } - async sync(address: string) { + async sync (address: string) { const userInfo = telegramConnector.userInfo; const message = `Login as ${userInfo?.username || 'booka'}`; const signature = await this.requestSignature(address, message); @@ -400,7 +398,8 @@ export class BookaSdk { }; try { - const account = await this.postRequest(`${GAME_API_HOST}/api/account/sync`, syncData) + const account = await this.postRequest(`${GAME_API_HOST}/api/account/sync`, syncData); + if (account) { this.accountSubject.next(account); storage.setItem(CACHE_KEYS.account, JSON.stringify(account)).catch(console.error); @@ -422,14 +421,16 @@ export class BookaSdk { await Promise.all([this.fetchGameList(), this.fetchTaskList(), this.fetchAirdropCampaign()]); } } catch (error: any) { - if(error.message === 'ACCOUNT_BANNED') { + if (error.message === 'ACCOUNT_BANNED') { this.isEnabled.next(false); this.syncHandler.reject(error.message); } + throw error; } -} - async requestSignature(address: string, message: string): Promise { + } + + async requestSignature (address: string, message: string): Promise { const loginMessage = await storage.getItem('loginMessage'); let loginMap: Record = {}; @@ -456,7 +457,7 @@ export class BookaSdk { return result.signature; } - async playGame(gameId: number, energyUsed: number): Promise { + async playGame (gameId: number, energyUsed: number): Promise { await this.waitForSync; const gamePlay = await this.postRequest(`${GAME_API_HOST}/api/game/new-game`, { gameId @@ -479,7 +480,7 @@ export class BookaSdk { return gamePlay; } - async submitGame(gamePlayId: number, point: number, signature: string) { + async submitGame (gamePlayId: number, point: number, signature: string) { await this.postRequest(`${GAME_API_HOST}/api/game/submit`, { gamePlayId: gamePlayId, point: point, @@ -493,7 +494,7 @@ export class BookaSdk { // --- shop - async fetchGameItemMap() { + async fetchGameItemMap () { await this.waitForSync; const gameItemMap = await this.postRequest>(`${GAME_API_HOST}/api/shop/list-items`, {}); @@ -503,11 +504,11 @@ export class BookaSdk { } } - subscribeGameItemMap() { + subscribeGameItemMap () { return this.gameItemMapSubject; } - async fetchGameInventoryItemList() { + async fetchGameInventoryItemList () { await this.waitForSync; const inventoryResponse = await this.getRequest<{ success: boolean; inventory: GameInventoryItem[], inventoryInGame: GameInventoryItem['inventoryInGame'] }>(`${GAME_API_HOST}/api/shop/get-inventory`); @@ -521,11 +522,11 @@ export class BookaSdk { } } - subscribeGameInventoryItemList() { + subscribeGameInventoryItemList () { return this.gameInventoryItemListSubject; } - async buyItem(gameItemId: number, quantity = 1) { + async buyItem (gameItemId: number, quantity = 1) { await this.postRequest(`${GAME_API_HOST}/api/shop/buy-item`, { gameItemId, quantity }); await this.fetchGameInventoryItemList(); @@ -535,7 +536,7 @@ export class BookaSdk { await this.reloadAccount(); } - async useInventoryItem(gameItemId: number) { + async useInventoryItem (gameItemId: number) { await this.postRequest(`${GAME_API_HOST}/api/shop/use-inventory-item`, { gameItemId }); await this.fetchGameInventoryItemList(); @@ -545,13 +546,13 @@ export class BookaSdk { await this.reloadAccount(); } - async buyEnergy() { + async buyEnergy () { await this.postRequest(`${GAME_API_HOST}/api/shop/buy-energy`, {}); await this.reloadAccount(); } - async fetchGameItemInGameList() { + async fetchGameItemInGameList () { const gameItem = await this.getRequest<{ success: boolean, items: any }>(`${GAME_API_HOST}/api/shop/get-item-in-game`); if (gameItem) { @@ -562,7 +563,7 @@ export class BookaSdk { } // --- shop - async fetchLeaderboard(startDate?: string, endDate?: string, gameId?: number, limit?: number, type = 'all') { + async fetchLeaderboard (startDate?: string, endDate?: string, gameId?: number, limit?: number, type = 'all') { await this.waitForSync; const leaderBoard = await this.postRequest(`${GAME_API_HOST}/api/game/leader-board`, { startDate, @@ -577,13 +578,13 @@ export class BookaSdk { } } - subscribeLeaderboard(startDate?: string, endDate?: string, gameId?: number, limit?: number, type = 'all') { + subscribeLeaderboard (startDate?: string, endDate?: string, gameId?: number, limit?: number, type = 'all') { this.fetchLeaderboard(startDate, endDate, gameId, limit, type).catch(console.error); return this.leaderBoardSubject; } - async fetchRankInfoMap() { + async fetchRankInfoMap () { const rankMap = { iron: { minPoint: 0, @@ -636,13 +637,13 @@ export class BookaSdk { return Promise.resolve(); } - subscribeRankInfoMap() { + subscribeRankInfoMap () { this.fetchRankInfoMap().catch(console.log); return this.rankInfoSubject; } - async signResult(gamePlayId: string, gameToken: string, score: number): Promise { + async signResult (gamePlayId: string, gameToken: string, score: number): Promise { if (this.account) { // Implement later return await this.requestSignature(this.account?.info.address, `${gamePlayId}|${gameToken}|${score}`); @@ -651,7 +652,7 @@ export class BookaSdk { } } - async fetchAirdropCampaign() { + async fetchAirdropCampaign () { const airdropCampaignResponse = await this.getRequest(`${GAME_API_HOST}/api/airdrop/list-airdrop-campaign`); if (airdropCampaignResponse) { @@ -659,7 +660,7 @@ export class BookaSdk { } } - async fetchCheckEligibility(campaignId: number): Promise { + async fetchCheckEligibility (campaignId: number): Promise { try { const response = await this.postRequest(`${GAME_API_HOST}/api/airdrop/check-eligibility`, { campaign_id: campaignId }); @@ -674,10 +675,12 @@ export class BookaSdk { } } - async fetchClaimAirdrop(airdrop_log_id: number) { + async fetchClaimAirdrop (airdrop_log_id: number) { try { - const claim = await this.postRequest(`${GAME_API_HOST}/api/airdrop/claim`, { airdrop_log_id: airdrop_log_id }); + const claim = await this.postRequest(`${GAME_API_HOST}/api/airdrop/claim`, { airdrop_log_id: airdrop_log_id }); + await this.fetchAirdropCampaign(); + return claim; } catch (error) { console.error('Error in claimAirdrop:', error); @@ -686,10 +689,12 @@ export class BookaSdk { } // airdrop raffle - async fetchRaffleAirdrop(campaignId: number) { + async fetchRaffleAirdrop (campaignId: number) { try { const raffle = await this.postRequest(`${GAME_API_HOST}/api/airdrop/raffle`, { campaign_id: campaignId }); + await this.fetchAirdropCampaign(); + return raffle; } catch (error) { console.error('Error in raffleAirdrop:', error); @@ -698,7 +703,7 @@ export class BookaSdk { } // airdrop history - async fetchAirdropHistory(campaignId:number) { + async fetchAirdropHistory (campaignId: number) { try { return await this.postRequest(`${GAME_API_HOST}/api/airdrop/history`, { campaign_id: campaignId }); } catch (error) { @@ -707,30 +712,30 @@ export class BookaSdk { } } - subscribeAirdropCampaign() { + subscribeAirdropCampaign () { return this.airdropCampaignSubject; } - subscribeCheckEligibility(campaignId:number) { + subscribeCheckEligibility (campaignId: number) { return this.fetchCheckEligibility(campaignId); } - subscribeAirdropRaffle(campaignId: number) { + subscribeAirdropRaffle (campaignId: number) { return this.fetchRaffleAirdrop(campaignId); } - subscribeAirdropClaim(airdrop_log_id: number) { + subscribeAirdropClaim (airdrop_log_id: number) { return this.fetchClaimAirdrop(airdrop_log_id); } - subscribeAirdropHistory(campaignId: number) { + subscribeAirdropHistory (campaignId: number) { return this.fetchAirdropHistory(campaignId); } // Singleton private static _instance: BookaSdk; - public static get instance() { + public static get instance () { if (!this._instance) { this._instance = new BookaSdk(); } @@ -738,4 +743,3 @@ export class BookaSdk { return this._instance; } } -