import { IClientMeta } from '@walletconnect/legacy-types' import { CoreTypes } from '@walletconnect/types' import React, { ReactElement, useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { StyleSheet, Text, View } from 'react-native' import Button, { BtnSizes, BtnTypes } from 'src/components/Button' import { activeDappSelector } from 'src/dapps/selectors' import { useSelector } from 'src/redux/hooks' import Colors from 'src/styles/colors' import { typeScale } from 'src/styles/fonts' import { Spacing } from 'src/styles/styles' import Logos from 'src/walletConnect/screens/Logos' export interface RequestDetail { label: string value: ReactElement | string | null } interface BaseProps { dappName: string dappUrl?: string dappImageUrl?: string title: string description: string | null requestDetails?: RequestDetail[] testId: string children?: React.ReactNode buttonText?: string | null buttonLoading?: boolean } interface ConfirmProps extends BaseProps { type: 'confirm' onAccept(): void onDeny(): void } interface DismissProps extends BaseProps { type: 'dismiss' onDismiss(): void } type Props = ConfirmProps | DismissProps export const useDappMetadata = (metadata?: IClientMeta | CoreTypes.Metadata | null) => { const activeDapp = useSelector(activeDappSelector) if (!metadata) { // should never happen return { url: '', dappName: '', dappImageUrl: '', } } const { url, name, icons } = metadata let dappOrigin = '' let dappHostname = '' try { const dappUrl = new URL(url) dappHostname = dappUrl.hostname dappOrigin = dappUrl.origin } catch { // do nothing if an invalid url is received, use fallback values } // create a display name in case the WC request contains an empty string const dappName = name || (!!activeDapp && new URL(activeDapp.dappUrl).origin === dappOrigin ? activeDapp.name : dappHostname) const dappImageUrl = icons[0] ?? `${url}/favicon.ico` return { url, dappName, dappImageUrl, } } function RequestContent(props: Props) { const { type, dappName, dappImageUrl, title, description, requestDetails, testId, children, buttonText, buttonLoading, } = props const { t } = useTranslation() const [isPressed, setIsPressed] = useState(false) const isPressedRef = useRef(false) const showButtonLoading = buttonLoading || isPressed const onPress = () => { setIsPressed(true) } useEffect(() => { isPressedRef.current = isPressed if (isPressed) { switch (props.type) { case 'confirm': props.onAccept() break case 'dismiss': props.onDismiss() break default: break } } }, [isPressed]) useEffect(() => { // This makes sure that the onDeny/onDismiss callback is called when the component is unmounted return () => { if (!isPressedRef.current) { switch (props.type) { case 'confirm': props.onDeny() break case 'dismiss': props.onDismiss() break default: break } } } }, []) return ( <> {title} {!!description && {description}} {requestDetails && ( {requestDetails.map(({ label, value }, index) => value ? ( 0 ? { marginTop: Spacing.Regular16 } : undefined, ]} > {label} {React.isValidElement(value) ? ( value ) : ( {value} )} ) : null )} )} {children} {type == 'confirm' && (