Skip to content

Commit

Permalink
feature(mobile): Battery refunds dApp (#879)
Browse files Browse the repository at this point in the history
* feature(mobile): Battery refunds dApp

* bump(mobile): 4.6.0

* fix(mobile): disable Navbar
  • Loading branch information
voloshinskii authored May 24, 2024
1 parent c0b9579 commit dce544a
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 19 deletions.
2 changes: 2 additions & 0 deletions packages/mobile/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export type AppConfigVars = {

batteryHost: string;
batteryTestnetHost: string;
batteryRefundEndpoint: string;
batteryMeanFees: string;
batteryReservedAmount: string;
batteryMaxInputAmount: string;
Expand Down Expand Up @@ -109,6 +110,7 @@ const defaultConfig: Partial<AppConfigVars> = {

batteryHost: 'https://battery.tonkeeper.com',
batteryTestnetHost: 'https://testnet-battery.tonkeeper.com',
batteryRefundEndpoint: 'https://battery-refund-app.vercel.app',
batteryMeanFees: '0.0055',
batteryReservedAmount: '0.3',
batteryMaxInputAmount: '3',
Expand Down
55 changes: 46 additions & 9 deletions packages/mobile/src/core/DAppBrowser/DAppBrowser.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useDeeplinking } from '$libs/deeplinking';
import { openDAppsSearch } from '$navigation';
import { getCorrectUrl, getSearchQuery, getUrlWithoutTonProxy, isIOS } from '$utils';
import { getCorrectUrl, getSearchQuery, getUrlWithoutTonProxy } from '$utils';
import React, { FC, memo, useCallback, useState } from 'react';
import { Linking, StatusBar, useWindowDimensions } from 'react-native';
import { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
Expand All @@ -16,10 +16,12 @@ import { useDAppBridge } from './hooks/useDAppBridge';
import { useWallet } from '@tonkeeper/shared/hooks';
import { Address } from '@tonkeeper/shared/Address';
import { config } from '$config';
import { Screen, isAndroid, useTheme } from '@tonkeeper/uikit';
import { Screen, useTheme } from '@tonkeeper/uikit';

export interface DAppBrowserProps {
url: string;
persistentQueryParams?: string;
disableSearchBar?: boolean;
}

const TONKEEPER_UTM = 'utm_source=tonkeeper';
Expand All @@ -30,12 +32,31 @@ const addUtmToUrl = (url: string) => {
return `${url}${startChar}${TONKEEPER_UTM}`;
};

const addPersistentQueryParamsIfNeeded = (
url: string,
persistentQueryParams?: string,
) => {
if (!persistentQueryParams) {
return url;
}
const startChar = url.includes('?') ? '&' : '?';

return `${url}${startChar}${persistentQueryParams}`;
};

const removeQueryParamsFromUrl = (url: string, params?: string) => {
if (!params) {
return url;
}
return url.replace(new RegExp(`[?|&]${params}`), '');
};

const removeUtmFromUrl = (url: string) => {
return url.replace(new RegExp(`[?|&]${TONKEEPER_UTM}`), '');
return removeQueryParamsFromUrl(url, TONKEEPER_UTM);
};

const DAppBrowserComponent: FC<DAppBrowserProps> = (props) => {
const { url: initialUrl } = props;
const { url: initialUrl, persistentQueryParams } = props;

const wallet = useWallet();
const walletAddress = wallet
Expand All @@ -49,7 +70,9 @@ const DAppBrowserComponent: FC<DAppBrowserProps> = (props) => {

const [currentUrl, setCurrentUrl] = useState(getCorrectUrl(initialUrl));

const [webViewSource, setWebViewSource] = useState({ uri: addUtmToUrl(currentUrl) });
const [webViewSource, setWebViewSource] = useState({
uri: addPersistentQueryParamsIfNeeded(addUtmToUrl(currentUrl), persistentQueryParams),
});

const app = useAppInfo(walletAddress, currentUrl);

Expand Down Expand Up @@ -86,18 +109,31 @@ const DAppBrowserComponent: FC<DAppBrowserProps> = (props) => {
progress.value = withTiming(e.nativeEvent.progress);

setTitle(e.nativeEvent.title);
setCurrentUrl(getUrlWithoutTonProxy(removeUtmFromUrl(e.nativeEvent.url)));
setCurrentUrl(
getUrlWithoutTonProxy(
removeQueryParamsFromUrl(
removeUtmFromUrl(e.nativeEvent.url),
persistentQueryParams,
),
),
);
},
[progress],
[persistentQueryParams, progress],
);

const handleNavigationStateChange = useCallback((e: WebViewNavigation) => {
setCanGoBack(e.canGoBack);
}, []);

const openUrl = useCallback(
(url: string) => setWebViewSource({ uri: addUtmToUrl(getCorrectUrl(url)) }),
[],
(url: string) =>
setWebViewSource({
uri: addPersistentQueryParamsIfNeeded(
addUtmToUrl(getCorrectUrl(url)),
persistentQueryParams,
),
}),
[persistentQueryParams],
);

const handleOpenExternalLink = useCallback(
Expand Down Expand Up @@ -150,6 +186,7 @@ const DAppBrowserComponent: FC<DAppBrowserProps> = (props) => {
<Screen alternateBackground>
<StatusBar barStyle={theme.isDark ? 'light-content' : 'dark-content'} />
<BrowserNavBar
disableSearchBar={props.disableSearchBar}
title={app?.name || title}
url={currentUrl}
isNotificationsEnabled={notificationsEnabled}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ interface Props {
onRefreshPress: () => void;
disconnect: () => Promise<void>;
unsubscribeFromNotifications: () => Promise<void>;
disableSearchBar?: boolean;
}

const BrowserNavBarComponent: FC<Props> = (props) => {
Expand Down Expand Up @@ -147,7 +148,7 @@ const BrowserNavBarComponent: FC<Props> = (props) => {
</S.BackButtonTouchable>
) : null}
</S.LeftContainer>
<S.MiddleContainer onPress={onTitlePress}>
<S.MiddleContainer disabled={props.disableSearchBar} onPress={onTitlePress}>
<S.Title>{title || '...'}</S.Title>
{isConnected ? (
<S.SubTitleRow>
Expand Down
8 changes: 6 additions & 2 deletions packages/mobile/src/navigation/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,12 @@ export function openDAppsSearch(
navigate(AppStackRouteNames.DAppsSearch, { initialQuery, onOpenUrl });
}

export function openDAppBrowser(url: string) {
const params = { url };
export function openDAppBrowser(
url: string,
persistentQueryParams?: string,
disableSearchBar?: boolean,
) {
const params = { url, persistentQueryParams, disableSearchBar };
if (getCurrentRoute()?.name === AppStackRouteNames.DAppsSearch) {
replace(AppStackRouteNames.DAppBrowser, params);
} else {
Expand Down
48 changes: 41 additions & 7 deletions packages/shared/components/RefillBattery/RestorePurchases.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { t } from '../../i18n';
import { getPendingPurchasesIOS, finishTransaction } from 'react-native-iap';
import { Platform } from 'react-native';
import { tk } from '@tonkeeper/mobile/src/wallet';
import { openDAppBrowser } from '@tonkeeper/mobile/src/navigation';
import { config } from '@tonkeeper/mobile/src/config';

export const RestorePurchases = memo(() => {
const handleRestorePurchases = useCallback(async () => {
Expand Down Expand Up @@ -45,19 +47,51 @@ export const RestorePurchases = memo(() => {
}
}, []);

const openRefundsDApp = useCallback(() => {
openDAppBrowser(
config.get('batteryRefundEndpoint'),
`token=${encodeURIComponent(tk.wallet.tonProof.tonProofToken)}` +
`&testnet=${tk.wallet.isTestnet}`,
true,
);
}, []);

return (
<Text style={styles.text.static} type="body2" textAlign="center" color="textTertiary">
{t('battery.packages.disclaimer')}{' '}
<>
<Text
style={styles.text.static}
type="body2"
textAlign="center"
color="textTertiary"
>
{t('battery.packages.disclaimer')}{' '}
<Text
onPress={handleRestorePurchases}
type="body2"
textAlign="center"
color="textSecondary"
>
{t('battery.packages.restore')}
</Text>
.
</Text>
<Text
onPress={handleRestorePurchases}
style={styles.text.static}
type="body2"
textAlign="center"
color="textSecondary"
color="textTertiary"
>
{t('battery.packages.restore')}
<Text
onPress={openRefundsDApp}
type="body2"
textAlign="center"
color="textSecondary"
>
{t('battery.packages.refund')}
</Text>
.
</Text>
.
</Text>
</>
);
});

Expand Down
1 change: 1 addition & 0 deletions packages/shared/i18n/locales/tonkeeper/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@
},
"disclaimer": "One charge covers the average transaction fee. Some transactions may cost more.",
"restore": "Restore Purchases",
"refund": "Request a refund",
"buy": "Buy",
"ok": "OK",
"refilled": "Your battery is charged"
Expand Down
1 change: 1 addition & 0 deletions packages/shared/i18n/locales/tonkeeper/ru-RU.json
Original file line number Diff line number Diff line change
Expand Up @@ -1201,6 +1201,7 @@
},
"disclaimer": "Один заряд покрывает среднюю комиссию за транзакцию. Некоторые транзакции могут стоить дороже.",
"restore": "Восстановить покупки",
"refund": "Запросить возврат",
"ok": "OK",
"refilled": "Ваша батарейка заряжена"
}
Expand Down

0 comments on commit dce544a

Please sign in to comment.