SELF-908: Add shared WebView screen (#1288)

* feat: add shared webview screen

* get react web view working

* fix default

* fix footer

* fix nav header

* android layout looks good

* fix initial screen

* add webview types

* fix types and clean error message

* remove share logic

* cr feedback and tests

* fix tests

* fix tests
This commit is contained in:
Justin Hernandez
2025-10-16 21:27:16 -07:00
committed by GitHub
parent c45853d081
commit 62aea03bd5
14 changed files with 810 additions and 27 deletions

View File

@@ -0,0 +1,88 @@
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import React from 'react';
import { StyleSheet, Text } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { ExternalLink, X } from '@tamagui/lucide-icons';
import { Button, XStack } from '@selfxyz/mobile-sdk-alpha/components';
import { black } from '@/utils/colors';
import { dinot } from '@/utils/fonts';
import { buttonTap } from '@/utils/haptic';
export interface WebViewNavBarProps {
title?: string;
onBackPress: () => void;
onOpenExternalPress?: () => void;
isOpenExternalDisabled?: boolean;
}
export const WebViewNavBar: React.FC<WebViewNavBarProps> = ({
title,
onBackPress,
onOpenExternalPress,
isOpenExternalDisabled,
}) => {
const insets = useSafeAreaInsets();
return (
<XStack
paddingHorizontal={20}
paddingVertical={10}
paddingTop={insets.top + 10}
gap={14}
alignItems="center"
backgroundColor="white"
>
{/* Left: Close Button */}
<Button
unstyled
hitSlop={{ top: 20, bottom: 20, left: 20, right: 10 }}
icon={<X size={24} color={black} />}
onPress={() => {
buttonTap();
onBackPress();
}}
/>
{/* Center: Title */}
<XStack flex={1} alignItems="center" justifyContent="center">
<Text style={styles.title} numberOfLines={1}>
{title?.toUpperCase() || 'PAGE TITLE'}
</Text>
</XStack>
{/* Right: Open External Button */}
<Button
unstyled
disabled={isOpenExternalDisabled}
hitSlop={{ top: 20, bottom: 20, left: 10, right: 20 }}
icon={
<ExternalLink
size={24}
color={isOpenExternalDisabled ? black : black}
opacity={isOpenExternalDisabled ? 0.3 : 1}
/>
}
onPress={() => {
buttonTap();
onOpenExternalPress?.();
}}
/>
</XStack>
);
};
const styles = StyleSheet.create({
title: {
fontFamily: dinot,
fontSize: 15,
color: black,
letterSpacing: 0.6,
textAlign: 'center',
textTransform: 'uppercase',
},
});

View File

@@ -0,0 +1,86 @@
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import React from 'react';
import { ArrowLeft, ArrowRight, RotateCcw } from '@tamagui/lucide-icons';
import { Button, XStack, YStack } from '@selfxyz/mobile-sdk-alpha/components';
import { black, slate50, slate400 } from '@/utils/colors';
import { buttonTap } from '@/utils/haptic';
export interface WebViewFooterProps {
canGoBack: boolean;
canGoForward: boolean;
onGoBack: () => void;
onGoForward: () => void;
onReload: () => void;
onOpenInBrowser: () => void;
}
const iconSize = 22;
const buttonSize = 36;
export const WebViewFooter: React.FC<WebViewFooterProps> = ({
canGoBack,
canGoForward,
onGoBack,
onGoForward,
onReload,
onOpenInBrowser: _onOpenInBrowser,
}) => {
const renderIconButton = (
key: string,
icon: React.ReactNode,
onPress: () => void,
disabled?: boolean,
) => (
<Button
key={key}
size="$4"
unstyled
disabled={disabled}
onPress={() => {
buttonTap();
onPress();
}}
backgroundColor={slate50}
borderRadius={buttonSize / 2}
width={buttonSize}
height={buttonSize}
alignItems="center"
justifyContent="center"
opacity={disabled ? 0.5 : 1}
>
{icon}
</Button>
);
return (
<YStack gap={12} paddingVertical={12} width="100%">
<XStack justifyContent="space-between" alignItems="center" width="100%">
{renderIconButton(
'back',
<ArrowLeft size={iconSize} color={canGoBack ? black : slate400} />,
onGoBack,
!canGoBack,
)}
{renderIconButton(
'reload',
<RotateCcw size={iconSize} color={black} />,
onReload,
)}
{renderIconButton(
'forward',
<ArrowRight
size={iconSize}
color={canGoForward ? black : slate400}
/>,
onGoForward,
!canGoForward,
)}
</XStack>
</YStack>
);
};