Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
f43a22c
add document selector test screen
transphorm Jan 6, 2026
bbe4aa5
clean up mock docs
transphorm Jan 6, 2026
4ad10e6
update selection options
transphorm Jan 7, 2026
1e3386f
Merge branch 'dev' into justin/self-1754-proving-screen-selective-dis…
transphorm Jan 7, 2026
a63f3ad
Merge branch 'dev' into justin/self-1754-proving-screen-selective-dis…
transphorm Jan 7, 2026
d28cf5a
Add DocumentSelectorForProving screen and route proof flows through i…
transphorm Jan 8, 2026
a6d4548
remove not accepted state
transphorm Jan 8, 2026
191acca
save wip design
transphorm Jan 8, 2026
3e7d6c6
formatting
transphorm Jan 8, 2026
b5ef1fd
update design
transphorm Jan 8, 2026
4b45e2a
update layout
transphorm Jan 8, 2026
a54374a
Update proving flow tests (#1559)
transphorm Jan 8, 2026
99d200e
Refactor ProveScreen to ProofRequestCard layout and preserve scroll p…
transphorm Jan 8, 2026
edac83b
wip fix tests
transphorm Jan 8, 2026
8ea959d
fix tests
transphorm Jan 8, 2026
bacd36b
formatting
transphorm Jan 8, 2026
69e7523
agent feedback
transphorm Jan 8, 2026
fccb65c
fix tests
transphorm Jan 8, 2026
128b4fa
Merge branch 'dev' into justin/self-1754-proving-screen-selective-dis…
transphorm Jan 8, 2026
e54ba03
save wip
transphorm Jan 8, 2026
e7f8411
remove text
transphorm Jan 8, 2026
2324023
fix types
transphorm Jan 8, 2026
69c65e3
save working header update
transphorm Jan 8, 2026
0fadd1f
no transition
transphorm Jan 8, 2026
5fd9c5f
cache document load for proving flow
transphorm Jan 8, 2026
75d1c7d
save fixes
transphorm Jan 8, 2026
f8b3c65
small fixes
transphorm Jan 9, 2026
7f6d809
match disclosure text
transphorm Jan 9, 2026
cddd454
design updates
transphorm Jan 9, 2026
9128ca0
fix approve flow
transphorm Jan 9, 2026
256fcd8
fix document type flash
transphorm Jan 9, 2026
a472865
add min height so text doesn't jump
transphorm Jan 9, 2026
9c37e85
update lock
transphorm Jan 9, 2026
1cc7951
formatting
transphorm Jan 9, 2026
0d4da72
save refactor wip
transphorm Jan 9, 2026
6cd9d7a
don't enable euclid yet
transphorm Jan 9, 2026
5cf025a
fix tests
transphorm Jan 9, 2026
921c60e
fix staleness check
transphorm Jan 9, 2026
e559aca
fix select box description
transphorm Jan 9, 2026
c387940
remove id selector screen
transphorm Jan 9, 2026
e03508d
vertically center
transphorm Jan 9, 2026
97698a0
button updates
transphorm Jan 9, 2026
0953717
Remove proving document cache (#1567)
transphorm Jan 9, 2026
be9452f
Merge branch 'dev' into justin/self-1754-proving-screen-selective-dis…
transphorm Jan 9, 2026
2526ac2
formatting
transphorm Jan 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ jest.mock('react-native', () => {
ScrollView: 'ScrollView',
TouchableOpacity: 'TouchableOpacity',
TouchableHighlight: 'TouchableHighlight',
Pressable: 'Pressable',
Image: 'Image',
ActivityIndicator: 'ActivityIndicator',
SafeAreaView: 'SafeAreaView',
Expand Down
126 changes: 126 additions & 0 deletions app/src/components/documents/IDSelectorItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// 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 { Pressable } from 'react-native';
import { Separator, Text, View, XStack, YStack } from 'tamagui';
import { Check, Circle } from '@tamagui/lucide-icons';

import {
black,
slate300,
slate500,
} from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { dinot } from '@selfxyz/mobile-sdk-alpha/constants/fonts';

export interface IDSelectorItemProps {
documentName: string;
state: IDSelectorState;
onPress?: () => void;
disabled?: boolean;
testID?: string;
}

export type IDSelectorState =
| 'active'
| 'verified'
| 'not_accepted'
| 'expired';

const green500 = '#22C55E';
const red500 = '#EF4444';

function getSubtitleText(state: IDSelectorState): string {
switch (state) {
case 'active':
return 'Currently active';
case 'verified':
return 'Verified ID';
case 'not_accepted':
return 'Not accepted';
case 'expired':
return 'Expired';
}
}

function getSubtitleColor(state: IDSelectorState): string {
switch (state) {
case 'active':
return green500;
case 'verified':
return slate500;
case 'not_accepted':
return slate500;
case 'expired':
return red500;
}
}

function isDisabledState(state: IDSelectorState): boolean {
return state === 'not_accepted' || state === 'expired';
}

export const IDSelectorItem: React.FC<IDSelectorItemProps> = ({
documentName,
state,
onPress,
disabled,
testID,
}) => {
const isDisabled = disabled || isDisabledState(state);
const isActive = state === 'active';
const subtitleText = getSubtitleText(state);
const subtitleColor = getSubtitleColor(state);
const textColor = isDisabled ? slate500 : black;

return (
<>
<Pressable
onPress={isDisabled ? undefined : onPress}
disabled={isDisabled}
testID={testID}
>
<XStack
paddingVertical={16}
paddingHorizontal={8}
alignItems="center"
gap={12}
opacity={isDisabled ? 0.6 : 1}
>
{/* Radio button indicator */}
<View
width={24}
height={24}
borderRadius={12}
borderWidth={isActive ? 0 : 2}
borderColor={slate300}
backgroundColor={isActive ? green500 : 'transparent'}
alignItems="center"
justifyContent="center"
>
{isActive && <Check size={16} color="white" strokeWidth={3} />}
{!isActive && !isDisabled && (
<Circle size={20} color={slate300} strokeWidth={0} />
)}
</View>

{/* Document info */}
<YStack flex={1} gap={2}>
<Text
fontFamily={dinot}
fontSize={16}
fontWeight="500"
color={textColor}
>
{documentName}
</Text>
<Text fontFamily={dinot} fontSize={14} color={subtitleColor}>
{subtitleText}
</Text>
</YStack>
</XStack>
</Pressable>
<Separator borderColor={slate300} />
</>
);
};
170 changes: 170 additions & 0 deletions app/src/components/documents/IDSelectorSheet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// 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 {
Button,
ScrollView,
Separator,
Sheet,
Text,
XStack,
YStack,
} from 'tamagui';
import { X } from '@tamagui/lucide-icons';

import {
black,
blue600,
slate300,
slate500,
white,
} from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { dinot } from '@selfxyz/mobile-sdk-alpha/constants/fonts';

import type { IDSelectorState } from '@/components/documents/IDSelectorItem';
import { IDSelectorItem } from '@/components/documents/IDSelectorItem';

export interface IDSelectorDocument {
id: string;
name: string;
state: IDSelectorState;
}

export interface IDSelectorSheetProps {
open: boolean;
onOpenChange: (open: boolean) => void;
documents: IDSelectorDocument[];
selectedId?: string;
onSelect: (documentId: string) => void;
onDismiss: () => void;
onApprove: () => void;
testID?: string;
}

export const IDSelectorSheet: React.FC<IDSelectorSheetProps> = ({
open,
onOpenChange,
documents,
selectedId,
onSelect,
onDismiss,
onApprove,
testID = 'id-selector-sheet',
}) => {
return (
<Sheet
modal
open={open}
onOpenChange={onOpenChange}
snapPoints={[55]}
animation="medium"
dismissOnSnapToBottom
>
<Sheet.Overlay
backgroundColor="rgba(0, 0, 0, 0.5)"
animation="lazy"
enterStyle={{ opacity: 0 }}
exitStyle={{ opacity: 0 }}
/>
<Sheet.Frame
backgroundColor={white}
borderTopLeftRadius="$9"
borderTopRightRadius="$9"
testID={testID}
>
<YStack padding="$4" flex={1}>
{/* Header */}
<XStack
alignItems="center"
justifyContent="space-between"
marginBottom="$4"
>
<Text
fontSize={20}
fontFamily={dinot}
fontWeight="600"
color={black}
>
Select an ID
</Text>
<XStack
onPress={onDismiss}
padding="$2"
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
testID={`${testID}-close-button`}
>
<X color={slate500} size={24} />
</XStack>
</XStack>

<Separator borderColor={slate300} marginBottom="$2" />

{/* Document List */}
<ScrollView
flex={1}
showsVerticalScrollIndicator={false}
testID={`${testID}-list`}
>
{documents.map(doc => {
const isSelected = doc.id === selectedId;
const itemState: IDSelectorState = isSelected
? 'active'
: doc.state;

return (
<IDSelectorItem
key={doc.id}
documentName={doc.name}
state={itemState}
onPress={() => onSelect(doc.id)}
testID={`${testID}-item-${doc.id}`}
/>
);
})}
</ScrollView>

{/* Footer Buttons */}
<XStack gap={12} marginTop="$4" paddingBottom="$2">
<Button
flex={1}
backgroundColor={white}
borderWidth={1}
borderColor={slate300}
borderRadius={8}
paddingVertical={16}
onPress={onDismiss}
testID={`${testID}-dismiss-button`}
>
<Text
fontFamily={dinot}
fontSize={16}
fontWeight="500"
color={black}
>
Dismiss
</Text>
</Button>
<Button
flex={1}
backgroundColor={blue600}
borderRadius={8}
paddingVertical={16}
onPress={onApprove}
testID={`${testID}-approve-button`}
>
<Text
fontFamily={dinot}
fontSize={16}
fontWeight="500"
color={white}
>
Approve
</Text>
</Button>
</XStack>
</YStack>
</Sheet.Frame>
</Sheet>
);
};
15 changes: 15 additions & 0 deletions app/src/components/documents/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// 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.

export type {
IDSelectorDocument,
IDSelectorSheetProps,
} from '@/components/documents/IDSelectorSheet';

export type {
IDSelectorItemProps,
IDSelectorState,
} from '@/components/documents/IDSelectorItem';
export { IDSelectorItem } from '@/components/documents/IDSelectorItem';
export { IDSelectorSheet } from '@/components/documents/IDSelectorSheet';
8 changes: 8 additions & 0 deletions app/src/navigation/devTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import DevHapticFeedbackScreen from '@/screens/dev/DevHapticFeedbackScreen';
import DevLoadingScreen from '@/screens/dev/DevLoadingScreen';
import DevPrivateKeyScreen from '@/screens/dev/DevPrivateKeyScreen';
import DevSettingsScreen from '@/screens/dev/DevSettingsScreen';
import IDSelectorTestScreen from '@/screens/dev/IDSelectorTestScreen';

const devHeaderOptions: NativeStackNavigationOptions = {
headerStyle: {
Expand Down Expand Up @@ -80,6 +81,13 @@ const devScreens = {
title: 'Dev Loading Screen',
} as NativeStackNavigationOptions,
},
IDSelectorTest: {
screen: IDSelectorTestScreen,
options: {
...devHeaderOptions,
title: 'ID Selector Test',
} as NativeStackNavigationOptions,
},
};

export default devScreens;
Loading
Loading