Skip to content

Commit

Permalink
Merge branch 'koni/dev/issue-194' into mythical-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
saltict committed Dec 20, 2024
2 parents 5acd1b3 + b875a63 commit fff6705
Show file tree
Hide file tree
Showing 15 changed files with 700 additions and 175 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,35 @@
// SPDX-License-Identifier: Apache-2.0

import { EmptyListContent } from '@subwallet/extension-koni-ui/components/Mythical';
import { BookaSdk } from '@subwallet/extension-koni-ui/connector/booka/sdk';
import { Reward } from '@subwallet/extension-koni-ui/connector/booka/types';
import { ThemeProps } from '@subwallet/extension-koni-ui/types';
import React, { useMemo } from 'react';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import styled from 'styled-components';

import { RewardHistoryItem, RewardHistoryItemType } from './RewardHistoryItem';
import { RewardHistoryItem } from './RewardHistoryItem';

type Props = ThemeProps;
const apiSDK = BookaSdk.instance;

const Component = ({ className }: Props): React.ReactElement => {
const { t } = useTranslation();
const [rewardHistories, setRewardHistories] = useState<Reward[]>(apiSDK.getRewardHistoryList());

const items: RewardHistoryItemType[] = useMemo(() => {
return [
] as RewardHistoryItemType[];
useEffect(() => {
const unsub = apiSDK.subscribeRewardList().subscribe((rewards) => {
setRewardHistories(rewards);
});

return () => {
unsub.unsubscribe();
};
}, []);

return (
<div className={className}>
{items.length > 0
{rewardHistories.length > 0
? (
<>
<div className='__area-label'>
Expand All @@ -30,11 +39,11 @@ const Component = ({ className }: Props): React.ReactElement => {

<div className='__list-container'>
{
items.map((item) => (
rewardHistories.map((item) => (
<RewardHistoryItem
{...item}
className={'reward-history-item'}
key={item.ordinal}
key={item.airdrop_record_id}
reward={item}
/>
))
}
Expand Down Expand Up @@ -68,6 +77,12 @@ export const RewardHistoryArea = styled(Component)<ThemeProps>(({ theme: { exten
marginBottom: 12
},

'.__list-container': {
display: 'flex',
flexDirection: 'column',
gap: 3
},

'.empty-list-content': {
paddingBottom: 103,
paddingTop: 56
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,74 @@
// Copyright 2019-2022 @subwallet/extension-ui authors & contributors
// SPDX-License-Identifier: Apache-2.0

import { getRewardStatus } from '@subwallet/extension-koni-ui/connector/booka/sdk';
import { Reward, RewardStatus } from '@subwallet/extension-koni-ui/connector/booka/types';
import { ThemeProps } from '@subwallet/extension-koni-ui/types';
import { toDisplayNumber } from '@subwallet/extension-koni-ui/utils';
import React from 'react';
import { customFormatDate, preloadImages, toDisplayNumber } from '@subwallet/extension-koni-ui/utils';
import { Icon } from '@subwallet/react-ui';
import CN from 'classnames';
import { Check, ClockCounterClockwise, SpinnerGap } from 'phosphor-react';
import React, { useEffect, useMemo } from 'react';
import styled from 'styled-components';

export type RewardHistoryItemType = {
ordinal: number;
name: string,
date: string,
tokenValue: string,
type Props = ThemeProps & {
reward: Reward;
};

type Props = ThemeProps & RewardHistoryItemType;
const RewardHistoryStatusItem = {
[RewardStatus.EXPIRED]: {
icon: ClockCounterClockwise,
isShowStatus: true,
value: 'EXPIRED',
color: '#FF596B'
},

[RewardStatus.SUCCESS]: {
icon: Check,
isShowStatus: false,
value: 'SUCCESS',
color: '#28C89F'
},

[RewardStatus.PENDING]: {
icon: SpinnerGap,
isShowStatus: true,
value: 'PENDING',
color: '#C4FD38'
}
};

const Component = ({ className, reward }: Props): React.ReactElement => {
const status = useMemo(() => RewardHistoryStatusItem[getRewardStatus(reward.status)], [reward.status]);

useEffect(() => {
preloadImages([
'/images/mythical/reward-history-background-item.png'
]);
}, []);

const Component = ({ className, date,
name,
ordinal,
tokenValue }: Props): React.ReactElement => {
return (
<div className={className}>
<div className='__item-inner'>
<div className='__item-left-part __ordinal'>{ordinal}</div>
<div className='__item-center-part __name'>{name}</div>
<div className='__item-left-part __ordinal'>
<Icon
className={CN(`-${reward.status}`)}
customSize={'16px'}
iconColor={status.color}
phosphorIcon={status.icon}
weight={'fill'}
/>
</div>
<div className='__item-center-part __name'>{reward.campaign_name}</div>
<div className='__item-right-part'>
<div className='__date'>{date}</div>
{
status.isShowStatus
? <div className={CN('__status-label', `-${status.value.toLowerCase()}`)}>{status.value}</div>
: <div className={CN('__status-label')}>{customFormatDate(reward?.completeDate || 0, '#MMM# #DD#', 'en')}</div>
}
<div className='__token-value-wrapper'>
<span className='__token-value'>+{toDisplayNumber(tokenValue)}&nbsp;</span>
<span className='__token-symbol'>MYTH</span>
<span className='__token-value'>+{toDisplayNumber(reward.token)}&nbsp;</span>
<span className='__token-symbol'>{'MYTH'}</span>
</div>
</div>
</div>
Expand All @@ -50,7 +90,10 @@ export const RewardHistoryItem = styled(Component)<ThemeProps>(({ theme: { exten
position: 'relative',
zIndex: 2,
paddingTop: 6,
paddingBottom: 10
paddingBottom: 10,
backgroundImage: 'url(/images/mythical/reward-history-background-item.png)',
backgroundPosition: 'center center',
backgroundSize: '100% 100%'
},

'.__ordinal': {
Expand Down Expand Up @@ -88,7 +131,7 @@ export const RewardHistoryItem = styled(Component)<ThemeProps>(({ theme: { exten
textAlign: 'right'
},

'.__date': {
'.__status-label': {
fontFamily: extendToken.fontBarlowCondensed,
fontSize: '12px',
fontStyle: 'normal',
Expand Down Expand Up @@ -141,6 +184,18 @@ export const RewardHistoryItem = styled(Component)<ThemeProps>(({ theme: { exten
backgroundImage: 'linear-gradient(75deg, rgba(54, 53, 53, 0.32) 25.94%, rgba(25, 25, 25, 0.32) 63.11%)',
backdropFilter: 'blur(16px)'
}
},

'.-success': {
color: '#28C89F'
},

'.-pending': {
color: '#C4FD38'
},

'.-expired': {
color: '#FF596B'
}
};
});
26 changes: 22 additions & 4 deletions packages/extension-koni-ui/src/Popup/Home/MyProfile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,28 @@ const Component = ({ className }: Props): React.ReactElement => {
/>
{isLinkedMyth
? (
mythicalWallet?.address && <>
<WalletInfoArea className={'wallet-info-area'} />
<RewardHistoryArea className={'reward-history-area'} />
</>
mythicalWallet?.address
? <>
<WalletInfoArea className={'wallet-info-area'} />
<RewardHistoryArea className={'reward-history-area'} />
</>
: <>
<div className={'empty-list-wrapper'}>
<EmptyListContent
className={'empty-rewards-content'}
content={t('Connect your Mythical account to NFL Rivals app\n' +
'and create a wallet address to view rewards')}
title={t('oops! no rewards yet ')}
/>
<MythButton
className={'__link-now-button'}
isLoading={loading}
onClick={openAppStoreLink}
>
{t('CONNECT NOW')}
</MythButton>
</div>
</>
)
: (
<>
Expand Down
92 changes: 89 additions & 3 deletions packages/extension-koni-ui/src/Popup/Home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@
import { CampaignBanner } from '@subwallet/extension-base/background/KoniTypes';
import { CampaignBannerModal, Layout } from '@subwallet/extension-koni-ui/components';
import { LayoutBaseProps } from '@subwallet/extension-koni-ui/components/Layout/base/Base';
import { AlertModal, MythicalAlertRewardModal } from '@subwallet/extension-koni-ui/components/Modal';
import { MaintenanceInfo, MetadataHandler } from '@subwallet/extension-koni-ui/connector/booka/metadata';
import { BookaSdk } from '@subwallet/extension-koni-ui/connector/booka/sdk';
import { Reward, RewardStatus } from '@subwallet/extension-koni-ui/connector/booka/types';
import { MYTHICAL_ALERT_LINKING_TO_REWARDS_MODAL, MYTHICAL_ALERT_REWARD_MODAL } from '@subwallet/extension-koni-ui/constants';
import { AuthenticationMythContext } from '@subwallet/extension-koni-ui/contexts/AuthenticationMythProvider';
import { HomeContext } from '@subwallet/extension-koni-ui/contexts/screen/HomeContext';
import { useAccountBalance, useGetBannerByScreen, useGetChainSlugsByAccountType, useTokenGroup } from '@subwallet/extension-koni-ui/hooks';
import { ThemeProps } from '@subwallet/extension-koni-ui/types';
import { noop } from '@subwallet/extension-koni-ui/utils';
import { ModalContext } from '@subwallet/react-ui';
import CN from 'classnames';
import React, { useEffect, useMemo, useState } from 'react';
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Outlet } from 'react-router';
import { useNavigate } from 'react-router-dom';
import styled from 'styled-components';
Expand All @@ -20,22 +27,86 @@ type Props = ThemeProps;
export const GlobalSearchTokenModalId = 'globalSearchToken';
const apiSDK = BookaSdk.instance;
const metadataHandler = MetadataHandler.instance;
const alertLinkingToRewardModal = MYTHICAL_ALERT_LINKING_TO_REWARDS_MODAL;
const alertRewardModal = MYTHICAL_ALERT_REWARD_MODAL;

function Component ({ className = '' }: Props): React.ReactElement<Props> {
const chainsByAccountType = useGetChainSlugsByAccountType();
const tokenGroupStructure = useTokenGroup(chainsByAccountType);
const { t } = useTranslation();
const accountBalance = useAccountBalance(tokenGroupStructure.tokenGroupMap);
const [containerClass, setContainerClass] = useState<string | undefined>();

const { activeModal, inactiveModal } = useContext(ModalContext);
const banners = useGetBannerByScreen('home');

// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
const firstBanner = useMemo((): CampaignBanner | undefined => banners[0], [banners]);

const { checkAlreadyLinked, isLinkedMyth, onLogin } = useContext(AuthenticationMythContext);
const [backgroundStyle, setBackgroundStyle] = useState<LayoutBaseProps['backgroundStyle'] | undefined>();
const [rewardsEligible, setRewardsEligible] = useState<Reward[]>([]);
const [hasSuccessReward, setHasSuccessReward] = useState<boolean>(false);
const [hasFullPendingReward, setHasFullPendingReward] = useState<boolean>(false);
const navigate = useNavigate();

const alertLinkingToRewardModalProps = useMemo(() => {
const totalTokenOfPendingReward = rewardsEligible.reduce((acc, reward) => {
if (reward.status !== RewardStatus.SUCCESS) {
acc += reward.token;
}

return acc;
}, 0);

return {
title: t(`you’re eligible for ${totalTokenOfPendingReward} myth`),
content: t(`Link your Mythical account now to receive ${totalTokenOfPendingReward} MYTH. Make sure to connect to NFL Rivals app first and create a wallet address to receive rewards`),
okButton: {
text: 'Link account',
onClick: () => {
apiSDK.updateRewardHistory(true).catch(console.error);
inactiveModal(alertLinkingToRewardModal);

if (isLinkedMyth) {
navigate('/home/my-profile');
} else {
onLogin();
}
}
},
cancelButton: {
text: 'Cancel',
onClick: noop
},
onCancel: () => {
inactiveModal(alertLinkingToRewardModal);
apiSDK.updateRewardHistory(true).catch(console.error);
}
};
}, [inactiveModal, isLinkedMyth, navigate, onLogin, rewardsEligible, t]);

const handleAlertReward = useCallback(async (rewardList: Reward[]) => {
if (rewardList.length > 0) {
const isHasRewardIsDistributed = rewardList.find((reward) => reward.status === RewardStatus.SUCCESS);

if (isHasRewardIsDistributed) {
setHasSuccessReward(true);
activeModal(alertRewardModal);

return;
}

const isAlreadyLinked = await checkAlreadyLinked();

if (isAlreadyLinked) {
return;
}

setHasFullPendingReward(true);
activeModal(alertLinkingToRewardModal);
}
}, [activeModal, checkAlreadyLinked]);

useEffect(() => {
const handleMaintenance = (info: MaintenanceInfo) => {
if (info.isMaintenance) {
Expand All @@ -59,6 +130,16 @@ function Component ({ className = '' }: Props): React.ReactElement<Props> {
};
}, [navigate]);

useEffect(() => {
apiSDK.getRewardListIsNotChecked().then((res) => {
setRewardsEligible(res);
}).catch(console.error);
}, []);

useEffect(() => {
handleAlertReward(rewardsEligible).catch(console.error);
}, [handleAlertReward, rewardsEligible]);

return (
<>
<HomeContext.Provider value={{
Expand All @@ -76,6 +157,11 @@ function Component ({ className = '' }: Props): React.ReactElement<Props> {
</Layout.Home>
</HomeContext.Provider>
{firstBanner && <CampaignBannerModal banner={firstBanner} />}
{hasSuccessReward && <MythicalAlertRewardModal rewardsEligible={rewardsEligible} />}
{hasFullPendingReward && <AlertModal
modalId={alertLinkingToRewardModal}
{...alertLinkingToRewardModalProps}
/>}
</>
);
}
Expand Down
Loading

0 comments on commit fff6705

Please sign in to comment.