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' && (
)}
{type == 'dismiss' && (
)}
>
)
}
const styles = StyleSheet.create({
requestDetailsContainer: {
marginBottom: Spacing.Thick24,
},
header: {
...typeScale.titleSmall,
paddingVertical: Spacing.Regular16,
},
description: {
...typeScale.bodySmall,
marginBottom: Spacing.Thick24,
},
requestDetailLabel: {
...typeScale.labelXSmall,
color: Colors.contentSecondary,
marginBottom: 4,
},
requestDetailValue: {
...typeScale.labelSemiBoldSmall,
},
})
export default RequestContent