SELF-1754: polish for document selection for proving flow (#1570)

* change spinner color

* fix disclosure scroll feedback

* fix type error

* fix button scrolling logic

* make the connected wallet static

* fix hold to verify button feedback timing

* formatting

* clean up tex
This commit is contained in:
Justin Hernandez
2026-01-09 23:52:36 -08:00
committed by GitHub
parent e1d06b5b13
commit 3ce1f26898
9 changed files with 184 additions and 90 deletions

View File

@@ -14,6 +14,7 @@ export interface BottomVerifyBarProps {
onVerify: () => void;
selectedAppSessionId: string | undefined | null;
hasScrolledToBottom: boolean;
isScrollable: boolean;
isReadyToProve: boolean;
isDocumentExpired: boolean;
testID?: string;
@@ -23,6 +24,7 @@ export const BottomVerifyBar: React.FC<BottomVerifyBarProps> = ({
onVerify,
selectedAppSessionId,
hasScrolledToBottom,
isScrollable,
isReadyToProve,
isDocumentExpired,
testID = 'bottom-verify-bar',
@@ -41,6 +43,7 @@ export const BottomVerifyBar: React.FC<BottomVerifyBarProps> = ({
onVerify={onVerify}
selectedAppSessionId={selectedAppSessionId}
hasScrolledToBottom={hasScrolledToBottom}
isScrollable={isScrollable}
isReadyToProve={isReadyToProve}
isDocumentExpired={isDocumentExpired}
/>

View File

@@ -32,6 +32,7 @@ export interface ProofRequestCardProps {
documentType?: string;
timestamp?: Date;
children?: React.ReactNode;
connectedWalletBadge?: React.ReactNode;
testID?: string;
onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
scrollViewRef?: React.RefObject<ScrollViewType>;
@@ -52,6 +53,7 @@ export const ProofRequestCard: React.FC<ProofRequestCardProps> = ({
documentType = '',
timestamp,
children,
connectedWalletBadge,
testID = 'proof-request-card',
onScroll,
scrollViewRef,
@@ -111,26 +113,47 @@ export const ProofRequestCard: React.FC<ProofRequestCardProps> = ({
<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
{/* Connected Wallet Badge - Fixed position under metadata bar */}
{connectedWalletBadge && (
<View
paddingHorizontal={proofRequestSpacing.cardPadding}
paddingTop={proofRequestSpacing.cardPadding}
paddingBottom={0}
>
{connectedWalletBadge}
</View>
)}
{/* Scrollable Content */}
<View
flex={1}
padding={proofRequestSpacing.cardPadding}
paddingTop={
connectedWalletBadge
? proofRequestSpacing.itemPadding
: proofRequestSpacing.cardPadding
}
>
{children}
</ScrollView>
<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>
</View>

View File

@@ -30,7 +30,7 @@ import {
isDocumentValidForProving,
useSelfClient,
} from '@selfxyz/mobile-sdk-alpha';
import { blue600, white } from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { black, white } from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { dinot } from '@selfxyz/mobile-sdk-alpha/constants/fonts';
import type { IDSelectorState } from '@/components/documents';
@@ -341,7 +341,7 @@ const DocumentSelectorForProvingScreen: React.FC = () => {
justifyContent="center"
testID="document-selector-loading-container"
>
<ActivityIndicator color={blue600} size="large" />
<ActivityIndicator color={black} size="large" />
</View>
);
}
@@ -418,25 +418,25 @@ const DocumentSelectorForProvingScreen: React.FC = () => {
appName={selfApp?.appName || 'Self'}
appUrl={url}
documentType={selectedDocumentType}
connectedWalletBadge={
formattedUserId ? (
<ConnectedWalletBadge
address={
selfApp?.userIdType === 'hex'
? truncateAddress(selfApp?.userId || '')
: formattedUserId
}
userIdType={selfApp?.userIdType}
onToggle={() => setWalletModalOpen(true)}
testID="document-selector-wallet-badge"
/>
) : undefined
}
onScroll={handleScroll}
testID="document-selector-card"
>
{/* Connected Wallet Badge */}
{formattedUserId && (
<ConnectedWalletBadge
address={
selfApp?.userIdType === 'hex'
? truncateAddress(selfApp?.userId || '')
: formattedUserId
}
userIdType={selfApp?.userIdType}
onToggle={() => setWalletModalOpen(true)}
testID="document-selector-wallet-badge"
/>
)}
{/* Disclosure Items */}
<YStack marginTop={formattedUserId ? 16 : 0}>
<YStack marginTop={0}>
{disclosureItems.map((item, index) => (
<DisclosureItem
key={item.key}

View File

@@ -93,9 +93,14 @@ const ProveScreen: React.FC = () => {
const scrollViewRef = useRef<ScrollViewType>(null);
const isContentShorterThanScrollView = useMemo(
() => scrollViewContentHeight <= scrollViewHeight,
() => scrollViewContentHeight <= scrollViewHeight + 50,
[scrollViewContentHeight, scrollViewHeight],
);
const isScrollable = useMemo(
() => !isContentShorterThanScrollView && hasLayoutMeasurements,
[isContentShorterThanScrollView, hasLayoutMeasurements],
);
const provingStore = useProvingStore();
const currentState = useProvingStore(state => state.currentState);
const isReadyToProve = currentState === 'ready_to_prove';
@@ -255,7 +260,7 @@ const ProveScreen: React.FC = () => {
}
const { layoutMeasurement, contentOffset, contentSize } =
event.nativeEvent;
const paddingToBottom = 10;
const paddingToBottom = 50;
const isCloseToBottom =
layoutMeasurement.height + contentOffset.y >=
contentSize.height - paddingToBottom;
@@ -287,7 +292,7 @@ const ProveScreen: React.FC = () => {
// If we now have both measurements and content fits on screen, enable button immediately
if (contentHeight > 0 && scrollViewHeight > 0) {
setHasLayoutMeasurements(true);
if (contentHeight <= scrollViewHeight) {
if (contentHeight <= scrollViewHeight + 50) {
setHasScrolledToBottom(true);
}
}
@@ -302,7 +307,7 @@ const ProveScreen: React.FC = () => {
// If we now have both measurements and content fits on screen, enable button immediately
if (layoutHeight > 0 && scrollViewContentHeight > 0) {
setHasLayoutMeasurements(true);
if (scrollViewContentHeight <= layoutHeight) {
if (scrollViewContentHeight <= layoutHeight + 50) {
setHasScrolledToBottom(true);
}
}
@@ -317,6 +322,20 @@ const ProveScreen: React.FC = () => {
appName={selectedApp?.appName || 'Self'}
appUrl={url}
documentType={documentType}
connectedWalletBadge={
formattedUserId ? (
<ConnectedWalletBadge
address={
selectedApp?.userIdType === 'hex'
? truncateAddress(selectedApp?.userId || '')
: formattedUserId
}
userIdType={selectedApp?.userIdType}
onToggle={() => setWalletModalOpen(true)}
testID="prove-screen-wallet-badge"
/>
) : undefined
}
onScroll={handleScroll}
scrollViewRef={scrollViewRef}
onContentSizeChange={handleContentSizeChange}
@@ -324,20 +343,8 @@ const ProveScreen: React.FC = () => {
initialScrollOffset={route.params?.scrollOffset}
testID="prove-screen-card"
>
{formattedUserId && (
<ConnectedWalletBadge
address={
selectedApp?.userIdType === 'hex'
? truncateAddress(selectedApp?.userId || '')
: formattedUserId
}
userIdType={selectedApp?.userIdType}
onToggle={() => setWalletModalOpen(true)}
testID="prove-screen-wallet-badge"
/>
)}
<YStack marginTop={formattedUserId ? 16 : 0}>
{/* Disclosure Items */}
<YStack marginTop={0}>
{disclosureItems.map((item, index) => (
<DisclosureItem
key={item.key}
@@ -354,6 +361,7 @@ const ProveScreen: React.FC = () => {
onVerify={onVerify}
selectedAppSessionId={selectedApp?.sessionId}
hasScrolledToBottom={hasScrolledToBottom}
isScrollable={isScrollable}
isReadyToProve={isReadyToProve}
isDocumentExpired={isDocumentExpired}
testID="prove-screen-verify-bar"

View File

@@ -12,7 +12,7 @@ import {
isDocumentValidForProving,
pickBestDocumentToSelect,
} from '@selfxyz/mobile-sdk-alpha';
import { blue600 } from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { black } from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { dinot } from '@selfxyz/mobile-sdk-alpha/constants/fonts';
import { proofRequestColors } from '@/components/proof-request';
@@ -195,7 +195,7 @@ const ProvingScreenRouter: React.FC = () => {
</View>
) : (
<>
<ActivityIndicator color={blue600} size="large" />
<ActivityIndicator color={black} size="large" />
</>
)}
</View>

View File

@@ -127,8 +127,9 @@ export const database: ProofDB = {
proof.documentId,
],
);
// Handle case where INSERT OR IGNORE skips insertion due to duplicate sessionId
return {
id: insertResult.insertId.toString(),
id: insertResult.insertId ? insertResult.insertId.toString() : '0',
timestamp,
rowsAffected: insertResult.rowsAffected,
};
@@ -154,8 +155,9 @@ export const database: ProofDB = {
proof.documentId,
],
);
// Handle case where INSERT OR IGNORE skips insertion due to duplicate sessionId
return {
id: insertResult.insertId.toString(),
id: insertResult.insertId ? insertResult.insertId.toString() : '0',
timestamp,
rowsAffected: insertResult.rowsAffected,
};
@@ -182,8 +184,9 @@ export const database: ProofDB = {
proof.documentId,
],
);
// Handle case where INSERT OR IGNORE skips insertion due to duplicate sessionId
return {
id: insertResult.insertId.toString(),
id: insertResult.insertId ? insertResult.insertId.toString() : '0',
timestamp,
rowsAffected: insertResult.rowsAffected,
};