Files
self/app/src/components/proof-request/ProofRequestCard.tsx
Justin Hernandez 850e3b98f9 SELF-1754: Implement selective disclosure on Proving Screen (#1549)
* add document selector test screen

* clean up mock docs

* update selection options

* Add DocumentSelectorForProving screen and route proof flows through it (#1555)

* Add document selector to proving flow

* fix formatting

* improvements

* redirect user to document not found screen when no documents

* option flow tweaks and tests

* wip tweaks

* fix scrollview bottom padding (#1556)

* tighten up selection text

* create inerstitial

* save wip

* remove not accepted state

* save wip design

* formatting

* update design

* update layout

* Update proving flow tests (#1559)

* Refactor ProveScreen to ProofRequestCard layout and preserve scroll position (#1560)

* Refactor prove screen layout

* fix: amount of hooks rendered needs to be the same for all variants

* long URL ellipsis

* keep titles consistent

* lint

---------

Co-authored-by: Leszek Stachowski <leszek.stachowski@self.xyz>

* wip fix tests

* fix tests

* formatting

* agent feedback

* fix tests

* save wip

* remove text

* fix types

* save working header update

* no transition

* cache document load for proving flow

* save fixes

* small fixes

* match disclosure text

* design updates

* fix approve flow

* fix document type flash

* add min height so text doesn't jump

* update lock

* formatting

* save refactor wip

* don't enable euclid yet

* fix tests

* fix staleness check

* fix select box description

* remove id selector screen

* vertically center

* button updates

* Remove proving document cache (#1567)

* formatting

---------

Co-authored-by: Leszek Stachowski <leszek.stachowski@self.xyz>
2026-01-09 13:56:10 -08:00

139 lines
4.0 KiB
TypeScript

// 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, { useMemo } from 'react';
import type {
ImageSourcePropType,
LayoutChangeEvent,
NativeScrollEvent,
NativeSyntheticEvent,
ScrollView as ScrollViewType,
} from 'react-native';
import { ScrollView } from 'react-native';
import { Text, View } from 'tamagui';
import { dinot } from '@selfxyz/mobile-sdk-alpha/constants/fonts';
import {
proofRequestColors,
proofRequestSpacing,
} from '@/components/proof-request/designTokens';
import {
formatTimestamp,
ProofMetadataBar,
} from '@/components/proof-request/ProofMetadataBar';
import { ProofRequestHeader } from '@/components/proof-request/ProofRequestHeader';
export interface ProofRequestCardProps {
logoSource: ImageSourcePropType | null;
appName: string;
appUrl: string | null;
documentType?: string;
timestamp?: Date;
children?: React.ReactNode;
testID?: string;
onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
scrollViewRef?: React.RefObject<ScrollViewType>;
onContentSizeChange?: (width: number, height: number) => void;
onLayout?: (event: LayoutChangeEvent) => void;
initialScrollOffset?: number;
}
/**
* Main card container for proof request screens.
* Combines header, metadata bar, and content section.
* Matches Figma design 15234:9267.
*/
export const ProofRequestCard: React.FC<ProofRequestCardProps> = ({
logoSource,
appName,
appUrl,
documentType = '',
timestamp,
children,
testID = 'proof-request-card',
onScroll,
scrollViewRef,
onContentSizeChange,
onLayout,
initialScrollOffset,
}) => {
// Create default timestamp once and reuse it to avoid unnecessary re-renders
const defaultTimestamp = useMemo(() => new Date(), []);
const effectiveTimestamp = timestamp ?? defaultTimestamp;
// Build request message with highlighted app name and document type
const requestMessage = (
<>
<Text color={proofRequestColors.white} fontFamily={dinot}>
{appName}
</Text>
<Text color={proofRequestColors.slate400} fontFamily={dinot}>
{
' is requesting access to the following information from your verified '
}
</Text>
<Text color={proofRequestColors.white} fontFamily={dinot}>
{documentType}
</Text>
<Text color={proofRequestColors.slate400} fontFamily={dinot}>
.
</Text>
</>
);
return (
<View flex={1} paddingVertical={20} paddingHorizontal={20} testID={testID}>
<View
borderRadius={proofRequestSpacing.borderRadius}
borderWidth={1}
borderColor={proofRequestColors.slate200}
overflow="hidden"
flex={1}
>
{/* Black Header */}
<ProofRequestHeader
logoSource={logoSource}
appName={appName}
appUrl={appUrl}
requestMessage={requestMessage}
testID={`${testID}-header`}
/>
{/* Metadata Bar */}
<ProofMetadataBar
timestamp={formatTimestamp(effectiveTimestamp)}
testID={`${testID}-metadata`}
/>
{/* White Content Area */}
<View
flex={1}
backgroundColor={proofRequestColors.slate100}
padding={proofRequestSpacing.cardPadding}
borderBottomLeftRadius={proofRequestSpacing.borderRadius}
borderBottomRightRadius={proofRequestSpacing.borderRadius}
>
<ScrollView
ref={scrollViewRef}
showsVerticalScrollIndicator={true}
contentContainerStyle={{ flexGrow: 1 }}
onScroll={onScroll}
scrollEventThrottle={16}
onContentSizeChange={onContentSizeChange}
onLayout={onLayout}
contentOffset={
typeof initialScrollOffset === 'number'
? { x: 0, y: initialScrollOffset }
: undefined
}
>
{children}
</ScrollView>
</View>
</View>
</View>
);
};