@procivis/one-react-native-components 0.3.132 → 0.3.143

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/lib/commonjs/components/history/history-list-item-icon.js +2 -0
  2. package/lib/commonjs/components/history/history-list-item-icon.js.map +1 -1
  3. package/lib/commonjs/components/proof-request/index.js +1 -12
  4. package/lib/commonjs/components/proof-request/index.js.map +1 -1
  5. package/lib/commonjs/components/proof-request/v2/share-credential-v2-group.js.map +1 -1
  6. package/lib/commonjs/components/proof-request/v2/share-credential-v2.js.map +1 -1
  7. package/lib/commonjs/ui-components/buttons/scan-button.js +122 -27
  8. package/lib/commonjs/ui-components/buttons/scan-button.js.map +1 -1
  9. package/lib/commonjs/ui-components/credential/card/credential-details-card.js +37 -18
  10. package/lib/commonjs/ui-components/credential/card/credential-details-card.js.map +1 -1
  11. package/lib/commonjs/ui-components/credential/credential-attribute-item.js +13 -4
  12. package/lib/commonjs/ui-components/credential/credential-attribute-item.js.map +1 -1
  13. package/lib/commonjs/ui-components/icons/icons.js +36 -2
  14. package/lib/commonjs/ui-components/icons/icons.js.map +1 -1
  15. package/lib/commonjs/ui-components/list/wallet/empty-list.js +2 -1
  16. package/lib/commonjs/ui-components/list/wallet/empty-list.js.map +1 -1
  17. package/lib/commonjs/ui-components/notice/wallet-notice.js +4 -2
  18. package/lib/commonjs/ui-components/notice/wallet-notice.js.map +1 -1
  19. package/lib/commonjs/ui-components/text/expandableTypography.js +64 -0
  20. package/lib/commonjs/ui-components/text/expandableTypography.js.map +1 -0
  21. package/lib/commonjs/ui-components/text/index.js +15 -0
  22. package/lib/commonjs/ui-components/text/index.js.map +1 -1
  23. package/lib/commonjs/utils/hooks/core/credential-schemas.js +24 -1
  24. package/lib/commonjs/utils/hooks/core/credential-schemas.js.map +1 -1
  25. package/lib/commonjs/utils/hooks/core/proofs.js +1 -1
  26. package/lib/commonjs/utils/hooks/core/proofs.js.map +1 -1
  27. package/lib/commonjs/utils/hooks/core/wallet-unit.js +20 -1
  28. package/lib/commonjs/utils/hooks/core/wallet-unit.js.map +1 -1
  29. package/lib/commonjs/utils/parsers/credential-sharing-v2.js +34 -7
  30. package/lib/commonjs/utils/parsers/credential-sharing-v2.js.map +1 -1
  31. package/lib/commonjs/utils/parsers/credential.js +12 -4
  32. package/lib/commonjs/utils/parsers/credential.js.map +1 -1
  33. package/lib/commonjs/utils/parsers/index.js +0 -11
  34. package/lib/commonjs/utils/parsers/index.js.map +1 -1
  35. package/lib/commonjs/utils/parsers/query.js +1 -1
  36. package/lib/commonjs/utils/parsers/query.js.map +1 -1
  37. package/lib/module/components/history/history-list-item-icon.js +2 -0
  38. package/lib/module/components/history/history-list-item-icon.js.map +1 -1
  39. package/lib/module/components/proof-request/index.js +0 -1
  40. package/lib/module/components/proof-request/index.js.map +1 -1
  41. package/lib/module/components/proof-request/v2/share-credential-v2-group.js.map +1 -1
  42. package/lib/module/components/proof-request/v2/share-credential-v2.js.map +1 -1
  43. package/lib/module/ui-components/buttons/scan-button.js +124 -29
  44. package/lib/module/ui-components/buttons/scan-button.js.map +1 -1
  45. package/lib/module/ui-components/credential/card/credential-details-card.js +37 -18
  46. package/lib/module/ui-components/credential/card/credential-details-card.js.map +1 -1
  47. package/lib/module/ui-components/credential/credential-attribute-item.js +13 -4
  48. package/lib/module/ui-components/credential/credential-attribute-item.js.map +1 -1
  49. package/lib/module/ui-components/icons/icons.js +32 -0
  50. package/lib/module/ui-components/icons/icons.js.map +1 -1
  51. package/lib/module/ui-components/list/wallet/empty-list.js +2 -1
  52. package/lib/module/ui-components/list/wallet/empty-list.js.map +1 -1
  53. package/lib/module/ui-components/notice/wallet-notice.js +4 -2
  54. package/lib/module/ui-components/notice/wallet-notice.js.map +1 -1
  55. package/lib/module/ui-components/text/expandableTypography.js +55 -0
  56. package/lib/module/ui-components/text/expandableTypography.js.map +1 -0
  57. package/lib/module/ui-components/text/index.js +2 -1
  58. package/lib/module/ui-components/text/index.js.map +1 -1
  59. package/lib/module/utils/hooks/core/credential-schemas.js +24 -1
  60. package/lib/module/utils/hooks/core/credential-schemas.js.map +1 -1
  61. package/lib/module/utils/hooks/core/proofs.js +1 -1
  62. package/lib/module/utils/hooks/core/proofs.js.map +1 -1
  63. package/lib/module/utils/hooks/core/wallet-unit.js +18 -0
  64. package/lib/module/utils/hooks/core/wallet-unit.js.map +1 -1
  65. package/lib/module/utils/parsers/credential-sharing-v2.js +32 -6
  66. package/lib/module/utils/parsers/credential-sharing-v2.js.map +1 -1
  67. package/lib/module/utils/parsers/credential.js +10 -4
  68. package/lib/module/utils/parsers/credential.js.map +1 -1
  69. package/lib/module/utils/parsers/index.js +0 -1
  70. package/lib/module/utils/parsers/index.js.map +1 -1
  71. package/lib/module/utils/parsers/query.js +1 -1
  72. package/lib/module/utils/parsers/query.js.map +1 -1
  73. package/lib/typescript/components/proof-request/index.d.ts +0 -1
  74. package/lib/typescript/components/proof-request/v2/share-credential-v2-group.d.ts +8 -1
  75. package/lib/typescript/components/proof-request/v2/share-credential-v2.d.ts +1 -1
  76. package/lib/typescript/ui-components/buttons/scan-button.d.ts +9 -3
  77. package/lib/typescript/ui-components/credential/card/credential-details-card.d.ts +3 -0
  78. package/lib/typescript/ui-components/credential/credential-attribute-item.d.ts +3 -0
  79. package/lib/typescript/ui-components/icons/icons.d.ts +2 -0
  80. package/lib/typescript/ui-components/list/wallet/empty-list.d.ts +2 -2
  81. package/lib/typescript/ui-components/text/expandableTypography.d.ts +10 -0
  82. package/lib/typescript/ui-components/text/index.d.ts +2 -1
  83. package/lib/typescript/ui-components/text/typography.d.ts +14 -14
  84. package/lib/typescript/utils/hooks/app-state.d.ts +1 -1
  85. package/lib/typescript/utils/hooks/core/proofs.d.ts +2 -2
  86. package/lib/typescript/utils/hooks/core/wallet-unit.d.ts +5 -1
  87. package/lib/typescript/utils/parsers/credential-sharing-v2.d.ts +10 -2
  88. package/lib/typescript/utils/parsers/credential.d.ts +2 -1
  89. package/lib/typescript/utils/parsers/index.d.ts +0 -1
  90. package/package.json +5 -4
  91. package/src/components/history/history-list-item-icon.tsx +2 -0
  92. package/src/components/proof-request/index.ts +0 -1
  93. package/src/components/proof-request/v2/share-credential-v2-group.tsx +9 -2
  94. package/src/components/proof-request/v2/share-credential-v2.tsx +1 -1
  95. package/src/ui-components/buttons/scan-button.tsx +130 -38
  96. package/src/ui-components/credential/card/credential-details-card.tsx +46 -19
  97. package/src/ui-components/credential/credential-attribute-item.tsx +15 -3
  98. package/src/ui-components/icons/icons.tsx +24 -0
  99. package/src/ui-components/list/wallet/empty-list.tsx +11 -8
  100. package/src/ui-components/notice/wallet-notice.tsx +4 -2
  101. package/src/ui-components/text/expandableTypography.tsx +71 -0
  102. package/src/ui-components/text/index.ts +2 -1
  103. package/src/utils/hooks/core/credential-schemas.ts +23 -1
  104. package/src/utils/hooks/core/proofs.ts +3 -3
  105. package/src/utils/hooks/core/wallet-unit.ts +21 -0
  106. package/src/utils/parsers/credential-sharing-v2.tsx +71 -6
  107. package/src/utils/parsers/credential.ts +14 -3
  108. package/src/utils/parsers/index.ts +0 -1
  109. package/src/utils/parsers/query.ts +0 -1
  110. package/lib/commonjs/components/proof-request/v1/group.js +0 -35
  111. package/lib/commonjs/components/proof-request/v1/group.js.map +0 -1
  112. package/lib/commonjs/components/proof-request/v1/index.js +0 -39
  113. package/lib/commonjs/components/proof-request/v1/index.js.map +0 -1
  114. package/lib/commonjs/components/proof-request/v1/select-credential.js +0 -53
  115. package/lib/commonjs/components/proof-request/v1/select-credential.js.map +0 -1
  116. package/lib/commonjs/components/proof-request/v1/share-credential.js +0 -110
  117. package/lib/commonjs/components/proof-request/v1/share-credential.js.map +0 -1
  118. package/lib/commonjs/utils/parsers/credential-sharing.js +0 -263
  119. package/lib/commonjs/utils/parsers/credential-sharing.js.map +0 -1
  120. package/lib/module/components/proof-request/v1/group.js +0 -27
  121. package/lib/module/components/proof-request/v1/group.js.map +0 -1
  122. package/lib/module/components/proof-request/v1/index.js +0 -4
  123. package/lib/module/components/proof-request/v1/index.js.map +0 -1
  124. package/lib/module/components/proof-request/v1/select-credential.js +0 -44
  125. package/lib/module/components/proof-request/v1/select-credential.js.map +0 -1
  126. package/lib/module/components/proof-request/v1/share-credential.js +0 -101
  127. package/lib/module/components/proof-request/v1/share-credential.js.map +0 -1
  128. package/lib/module/utils/parsers/credential-sharing.js +0 -250
  129. package/lib/module/utils/parsers/credential-sharing.js.map +0 -1
  130. package/lib/typescript/components/proof-request/v1/group.d.ts +0 -2
  131. package/lib/typescript/components/proof-request/v1/index.d.ts +0 -3
  132. package/lib/typescript/components/proof-request/v1/select-credential.d.ts +0 -15
  133. package/lib/typescript/components/proof-request/v1/share-credential.d.ts +0 -27
  134. package/lib/typescript/utils/parsers/credential-sharing.d.ts +0 -20
  135. package/src/components/proof-request/v1/group.tsx +0 -26
  136. package/src/components/proof-request/v1/index.ts +0 -3
  137. package/src/components/proof-request/v1/select-credential.tsx +0 -55
  138. package/src/components/proof-request/v1/share-credential.tsx +0 -159
  139. package/src/utils/parsers/credential-sharing.tsx +0 -404
@@ -1,69 +1,161 @@
1
1
  import React from 'react';
2
- import { Insets, StyleSheet, TouchableOpacityProps, View } from 'react-native';
2
+ import { Insets, StyleProp, StyleSheet, Text, View, ViewStyle } from 'react-native';
3
3
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
4
4
 
5
5
  import { TouchableOpacity, TouchableOpacityRef } from '../accessibility/accessibilityHistoryWrappers';
6
6
  import { useAccessibilityTranslation } from '../accessibility/accessibilityLanguage';
7
7
  import BlurView from '../blur/blur-view';
8
- import { ScanIcon } from '../icons';
8
+ import { IssueIcon, ScanIcon, SignIcon } from '../icons';
9
9
  import { useAppColorScheme } from '../theme';
10
10
 
11
- export type ScanButtonProps = TouchableOpacityProps;
11
+ export type ScanButtonProps = {
12
+ onSignPress?: () => void;
13
+ onIssuePress?: () => void;
14
+ onScanPress: () => void;
15
+ testID?: string;
16
+ style?: StyleProp<ViewStyle>;
17
+ };
12
18
 
13
19
  const hitSlop: Insets = { top: 10, left: 10, bottom: 10, right: 10 };
14
20
 
15
- const ScanButton = React.forwardRef<TouchableOpacityRef, ScanButtonProps>(({ style, ...props }, ref) => {
16
- const t = useAccessibilityTranslation();
17
- const colorScheme = useAppColorScheme();
18
- const insets = useSafeAreaInsets();
21
+ const SCAN_WIDTH = 104;
22
+ const SCAN_HEIGHT = 80;
23
+ const SIDE_WIDTH = 94;
24
+ const SIDE_HEIGHT = 64;
25
+ const OVERLAP = 50;
19
26
 
20
- return (
21
- <TouchableOpacity
22
- accessibilityLabel={t('accessibility.icon.scan')}
23
- accessibilityRole="button"
24
- hitSlop={hitSlop}
25
- ref={ref}
26
- style={[styles.button, { bottom: Math.max(24, insets.bottom) }, style]}
27
- {...props}>
28
- <BlurView blurStyle="soft" style={styles.blurWrapper}>
29
- <View style={[styles.iconWrapper, { backgroundColor: colorScheme.accent }]}>
30
- <ScanIcon color={colorScheme.white} />
27
+ const ScanButton = React.forwardRef<TouchableOpacityRef, ScanButtonProps>(
28
+ ({ style, onSignPress, onIssuePress, onScanPress, testID }, ref) => {
29
+ const t = useAccessibilityTranslation();
30
+ const colorScheme = useAppColorScheme();
31
+ const insets = useSafeAreaInsets();
32
+ const showLeftButton = onSignPress !== undefined;
33
+ const showRightButton = onIssuePress !== undefined;
34
+ const leftButtonOpacity = showLeftButton ? 1 : 0;
35
+ const rightButtonOpacity = showRightButton ? 1 : 0;
36
+
37
+ const bottomOffset = Math.max(24, insets.bottom);
38
+
39
+ return (
40
+ <View style={[styles.wrapper, { bottom: bottomOffset }, style as object]}>
41
+ <View
42
+ pointerEvents={showLeftButton ? 'auto' : 'none'}
43
+ style={[styles.sideButtonContainer, { opacity: leftButtonOpacity }]}>
44
+ <TouchableOpacity
45
+ accessibilityRole="button"
46
+ hitSlop={hitSlop}
47
+ testID={`${testID}.sign`}
48
+ onPress={onSignPress}
49
+ style={styles.sideButton}>
50
+ <View style={[styles.sideInnerLeft, { backgroundColor: colorScheme.white }]}>
51
+ <SignIcon color={colorScheme.black} />
52
+ <Text style={[styles.sideLabel, { color: colorScheme.black }]}>Sign</Text>
53
+ </View>
54
+ </TouchableOpacity>
31
55
  </View>
32
- </BlurView>
33
- </TouchableOpacity>
34
- );
35
- });
56
+
57
+ <TouchableOpacity
58
+ accessibilityLabel={t('accessibility.icon.scan')}
59
+ accessibilityRole="button"
60
+ hitSlop={hitSlop}
61
+ ref={ref}
62
+ style={styles.scanButton}
63
+ testID={`${testID}.scan`}
64
+ onPress={onScanPress}>
65
+ <BlurView blurStyle="soft" style={styles.scanBlurWrapper}>
66
+ <View style={[styles.scanInner, { backgroundColor: colorScheme.accent }]}>
67
+ <ScanIcon color={colorScheme.white} />
68
+ </View>
69
+ </BlurView>
70
+ </TouchableOpacity>
71
+
72
+ <View
73
+ pointerEvents={showRightButton ? 'auto' : 'none'}
74
+ style={[styles.sideButtonContainer, { opacity: rightButtonOpacity }]}>
75
+ <TouchableOpacity
76
+ accessibilityRole="button"
77
+ testID={`${testID}.issue`}
78
+ hitSlop={hitSlop}
79
+ onPress={onIssuePress}
80
+ style={styles.sideButton}>
81
+ <View style={[styles.sideInnerRight, { backgroundColor: colorScheme.white }]}>
82
+ <IssueIcon color={colorScheme.black} />
83
+ <Text style={[styles.sideLabel, { color: colorScheme.black }]}>Issue</Text>
84
+ </View>
85
+ </TouchableOpacity>
86
+ </View>
87
+ </View>
88
+ );
89
+ },
90
+ );
36
91
 
37
92
  ScanButton.displayName = 'ScanButton';
38
93
  export default ScanButton;
39
94
 
40
95
  const styles = StyleSheet.create({
41
- blurWrapper: {
96
+ scanBlurWrapper: {
42
97
  borderRadius: 28,
43
- borderWidth: 0,
44
- height: 80,
98
+ flex: 1,
45
99
  padding: 8,
46
- width: 104,
47
100
  },
48
- button: {
101
+ scanButton: {
49
102
  borderRadius: 28,
50
- borderWidth: 0,
51
- height: 80,
52
- left: '50%',
53
- marginLeft: -52,
54
- position: 'absolute',
103
+ height: SCAN_HEIGHT,
55
104
  shadowColor: '#000000',
56
105
  shadowOffset: { height: 4, width: 0 },
57
- shadowOpacity: 0.2,
106
+ shadowOpacity: 0.25,
58
107
  shadowRadius: 24,
59
- width: 104,
108
+ width: SCAN_WIDTH,
109
+ zIndex: 1,
60
110
  },
61
- iconWrapper: {
111
+ scanInner: {
62
112
  alignItems: 'center',
63
113
  borderRadius: 20,
64
- borderWidth: 0,
65
- height: '100%',
114
+ flex: 1,
66
115
  justifyContent: 'center',
67
- width: '100%',
116
+ },
117
+ sideButton: {
118
+ borderRadius: 24,
119
+ flex: 1,
120
+ },
121
+ sideButtonContainer: {
122
+ height: SIDE_HEIGHT,
123
+ marginHorizontal: -OVERLAP / 2,
124
+ width: SIDE_WIDTH,
125
+ zIndex: 0,
126
+ },
127
+ sideInnerLeft: {
128
+ alignItems: 'center',
129
+ borderBottomLeftRadius: 22,
130
+ borderBottomRightRadius: 0,
131
+ borderTopLeftRadius: 22,
132
+ borderTopRightRadius: 0,
133
+ flex: 1,
134
+ justifyContent: 'center',
135
+ paddingRight: 10,
136
+ },
137
+ sideInnerRight: {
138
+ alignItems: 'center',
139
+ borderBottomLeftRadius: 0,
140
+ borderBottomRightRadius: 22,
141
+ borderTopLeftRadius: 0,
142
+ borderTopRightRadius: 22,
143
+ flex: 1,
144
+ justifyContent: 'center',
145
+ paddingLeft: 10,
146
+ },
147
+ sideLabel: {
148
+ fontSize: 14,
149
+ fontWeight: '500',
150
+ marginTop: 6,
151
+ },
152
+ wrapper: {
153
+ alignItems: 'center',
154
+ flexDirection: 'row',
155
+ height: SCAN_HEIGHT,
156
+ justifyContent: 'center',
157
+ left: 0,
158
+ position: 'absolute',
159
+ right: 0,
68
160
  },
69
161
  });
@@ -18,6 +18,9 @@ export type CredentialDetailsCardProps = ViewProps & {
18
18
  onImagePreview?: (name: string, image: ImageSourcePropType) => void;
19
19
  onAttributeSelected?: (id: string, selected: boolean) => void;
20
20
  showAllButtonLabel?: string;
21
+ showLessButtonLabel?: string;
22
+ moreLabel?: string;
23
+ lessLabel?: string;
21
24
  };
22
25
 
23
26
  const PREVIEW_ATTRIBUTES_COUNT = 3;
@@ -32,7 +35,10 @@ const CredentialDetailsCard: FC<CredentialDetailsCardProps> = ({
32
35
  onImagePreview,
33
36
  onAttributeSelected,
34
37
  style,
35
- showAllButtonLabel,
38
+ showAllButtonLabel = 'Show all',
39
+ showLessButtonLabel = 'Show less',
40
+ moreLabel = 'More',
41
+ lessLabel = 'Less',
36
42
  testID,
37
43
  ...viewProps
38
44
  }) => {
@@ -43,15 +49,14 @@ const CredentialDetailsCard: FC<CredentialDetailsCardProps> = ({
43
49
  const [allAttributesRendered, setAllAttributesRendered] = useState<boolean>(
44
50
  (attributes && attributes.length <= PREVIEW_ATTRIBUTES_COUNT) || !showAllButtonLabel,
45
51
  );
46
-
47
52
  const CaretIcon = expanded ? UpIcon : DownIcon;
48
-
49
53
  const cardHeight = Math.ceil(card.width / CredentialCardRatio);
50
54
  const currentHeight = useSharedValue<number | undefined>(undefined);
51
55
  const [animatedHeightSet, setAnimatedHeightSet] = useState(false);
52
-
53
56
  const previewAttributes = attributes ? attributes.slice(0, PREVIEW_ATTRIBUTES_COUNT) : [];
54
57
  const extraAttributes = useMemo(() => (attributes ? attributes.slice(PREVIEW_ATTRIBUTES_COUNT) : []), [attributes]);
58
+ const showSeeAllButton = extraAttributes.length > 0;
59
+ const isExpanded = allAttributesRendered;
55
60
 
56
61
  useEffect(() => {
57
62
  if (extraAttributes.length === 0) {
@@ -72,9 +77,9 @@ const CredentialDetailsCard: FC<CredentialDetailsCardProps> = ({
72
77
  return;
73
78
  }
74
79
 
75
- const buttonViewHeight = !extraAttributes || allAttributesRendered ? 0 : SEE_ALL_BUTTON_HEIGHT;
80
+ const buttonViewHeight = showSeeAllButton ? SEE_ALL_BUTTON_HEIGHT : 0;
76
81
  const additionalAttributesHeight = fullAttributesHeight ?? 0;
77
- const additionalHeight = allAttributesRendered ? additionalAttributesHeight : buttonViewHeight;
82
+ const additionalHeight = allAttributesRendered ? additionalAttributesHeight + buttonViewHeight : buttonViewHeight;
78
83
  const fullHeight = previewAttributesHeight + additionalHeight;
79
84
 
80
85
  setAnimatedHeightSet(true);
@@ -103,6 +108,7 @@ const CredentialDetailsCard: FC<CredentialDetailsCardProps> = ({
103
108
  fullAttributesHeight,
104
109
  previewAttributes.length,
105
110
  previewAttributesHeight,
111
+ showSeeAllButton,
106
112
  ]);
107
113
 
108
114
  const animatedStyle = useAnimatedStyle(() => {
@@ -160,41 +166,54 @@ const CredentialDetailsCard: FC<CredentialDetailsCardProps> = ({
160
166
  <View onLayout={onPreviewAttrContentLayout} style={styles.previewAttributesWrapper}>
161
167
  {previewAttributes.map((attribute, idx) => (
162
168
  <CredentialAttributeItem
169
+ moreLabel={moreLabel}
170
+ lessLabel={lessLabel}
163
171
  key={attribute.id}
164
- last={!footerView && !extraAttributes.length && idx === previewAttributes.length - 1}
172
+ last={!footerView && !showSeeAllButton && idx === previewAttributes.length - 1}
165
173
  testID={concatTestID(testID, 'attribute', idx.toString())}
166
174
  onImagePreview={onImagePreview}
167
175
  onPress={onAttributeSelected}
176
+ isExpanded={isExpanded}
168
177
  {...attribute}
169
178
  />
170
179
  ))}
171
180
  </View>
172
- {!allAttributesRendered && extraAttributes.length > 0 && (
173
- <View style={styles.buttonWrapper}>
174
- <Button
175
- onPress={() => setAllAttributesRendered(true)}
176
- type={ButtonType.Secondary}
177
- testID={concatTestID(testID, 'showAllAttributesButton')}
178
- title={showAllButtonLabel!}
179
- />
180
- </View>
181
- )}
181
+
182
182
  {renderExtraAttributes && (
183
183
  <View
184
- style={[styles.allAttributesWrapper, footerView && styles.allAttributesWrapperWithFooter]}
184
+ style={[
185
+ styles.allAttributesWrapper,
186
+ footerView && styles.allAttributesWrapperWithFooter,
187
+ showSeeAllButton && styles.allAttributesWrapperWithButton,
188
+ !allAttributesRendered && styles.hidden,
189
+ ]}
185
190
  onLayout={onFullAttrContentLayout}>
186
191
  {extraAttributes.map((attribute, index, { length }) => (
187
192
  <CredentialAttributeItem
193
+ moreLabel={moreLabel}
194
+ lessLabel={lessLabel}
188
195
  key={attribute.id}
189
- last={!footerView && index === length - 1}
196
+ last={!footerView && !showSeeAllButton && index === length - 1}
190
197
  testID={concatTestID(testID, 'attribute', index.toString())}
191
198
  onImagePreview={onImagePreview}
192
199
  onPress={onAttributeSelected}
200
+ isExpanded={isExpanded}
193
201
  {...attribute}
194
202
  />
195
203
  ))}
196
204
  </View>
197
205
  )}
206
+
207
+ {showSeeAllButton && (
208
+ <View style={styles.buttonWrapper}>
209
+ <Button
210
+ onPress={() => setAllAttributesRendered((prev) => !prev)}
211
+ type={ButtonType.Secondary}
212
+ testID={concatTestID(testID, 'showAllAttributesButton')}
213
+ title={isExpanded ? showLessButtonLabel : showAllButtonLabel}
214
+ />
215
+ </View>
216
+ )}
198
217
  </View>
199
218
  </View>
200
219
  )}
@@ -209,6 +228,9 @@ const styles = StyleSheet.create({
209
228
  paddingHorizontal: 4,
210
229
  width: '100%',
211
230
  },
231
+ allAttributesWrapperWithButton: {
232
+ paddingBottom: 0,
233
+ },
212
234
  allAttributesWrapperWithFooter: {
213
235
  paddingBottom: 0,
214
236
  },
@@ -218,8 +240,10 @@ const styles = StyleSheet.create({
218
240
  },
219
241
  buttonWrapper: {
220
242
  height: SEE_ALL_BUTTON_HEIGHT,
243
+ justifyContent: 'flex-end',
221
244
  paddingBottom: 12,
222
245
  paddingHorizontal: 4,
246
+ paddingTop: 0,
223
247
  width: '100%',
224
248
  },
225
249
  card: {
@@ -234,6 +258,9 @@ const styles = StyleSheet.create({
234
258
  footer: {
235
259
  marginTop: 12,
236
260
  },
261
+ hidden: {
262
+ display: 'none',
263
+ },
237
264
  previewAttributesWrapper: {
238
265
  paddingHorizontal: 4,
239
266
  width: '100%',
@@ -4,6 +4,7 @@ import { Image, ImageSourcePropType, StyleProp, StyleSheet, View, ViewStyle } fr
4
4
  import { colorWithAlphaComponent } from '../../utils/color';
5
5
  import { concatTestID } from '../../utils/testID';
6
6
  import { TouchableHighlight, TouchableOpacity } from '../accessibility/accessibilityHistoryWrappers';
7
+ import ExpandableTypography from '../text/expandableTypography';
7
8
  import Typography from '../text/typography';
8
9
  import { useAppColorScheme } from '../theme/color-scheme-context';
9
10
 
@@ -109,6 +110,9 @@ export type CredentialAttributeItemProps = CredentialAttribute & {
109
110
  onImagePreview?: (name: string, image: ImageSourcePropType) => void;
110
111
  onPress?: (id: string, selected: boolean) => void;
111
112
  style?: StyleProp<ViewStyle>;
113
+ isExpanded?: boolean;
114
+ moreLabel?: string;
115
+ lessLabel?: string;
112
116
  };
113
117
 
114
118
  const CredentialAttributeItem: FC<CredentialAttributeItemProps> = ({
@@ -129,6 +133,9 @@ const CredentialAttributeItem: FC<CredentialAttributeItemProps> = ({
129
133
  value,
130
134
  values,
131
135
  valueErrorColor,
136
+ isExpanded,
137
+ moreLabel,
138
+ lessLabel,
132
139
  }) => {
133
140
  const colorScheme = useAppColorScheme();
134
141
 
@@ -214,14 +221,18 @@ const CredentialAttributeItem: FC<CredentialAttributeItemProps> = ({
214
221
  </TouchableOpacity>
215
222
  )}
216
223
  {value && (
217
- <Typography
224
+ <ExpandableTypography
218
225
  color={valueErrorColor ? colorScheme.error : colorScheme.text}
219
- numberOfLines={10}
226
+ numberOfLines={3}
227
+ ellipsizeMode="tail"
220
228
  preset="s"
229
+ hideExpandButton={!isExpanded && !listValue && !nested}
221
230
  style={listValue ? styles.listValue : undefined}
231
+ moreLabel={moreLabel}
232
+ lessLabel={lessLabel}
222
233
  testID={concatTestID(testID, 'value')}>
223
234
  {value}
224
- </Typography>
235
+ </ExpandableTypography>
225
236
  )}
226
237
  {isObject &&
227
238
  attributes.map((attribute, index, { length }) => (
@@ -263,6 +274,7 @@ const styles = StyleSheet.create({
263
274
  attributeItem: {
264
275
  flex: 1,
265
276
  paddingLeft: 8,
277
+ paddingRight: 8,
266
278
  },
267
279
  attributeItemContainer: {
268
280
  marginTop: 2,
@@ -17,6 +17,30 @@ export const ScanIcon: FC<SvgProps> = ({ color, ...props }) => {
17
17
  );
18
18
  };
19
19
 
20
+ // https://www.figma.com/design/52qDYWUMjXAGre1dcnz5bz/Procivis-One-Wallet?node-id=621-19281&t=mV98iCutPWAC5Nb4-0
21
+ export const IssueIcon: FC<SvgProps> = ({ color, ...props }) => {
22
+ return (
23
+ <Svg width={24} height={24} viewBox="0 0 24 24" fill="none" {...props}>
24
+ <Path
25
+ d="M4.188 13.34V5.27c0-.965.239-1.692.715-2.18.482-.49 1.203-.734 2.161-.734h4.407c.347 0 .65.025.91.075.265.043.51.13.732.26.223.123.452.306.687.547l5.112 5.204c.247.254.433.495.556.724.13.223.217.47.26.742.043.272.065.61.065 1.011v8.424c0 .965-.241 1.689-.724 2.171-.476.489-1.193.733-2.152.733h-6.8c.136-.229.253-.47.352-.724.1-.247.18-.504.241-.77h6.133c.482 0 .844-.123 1.085-.37.248-.248.371-.604.371-1.068v-8.33h-5.288c-.581 0-1.017-.146-1.308-.437-.29-.29-.436-.726-.436-1.308V3.85H7.14c-.483 0-.848.127-1.095.38-.241.254-.362.61-.362 1.067v8.044a8.606 8.606 0 00-.38-.028 3.812 3.812 0 00-.752 0 7.826 7.826 0 00-.362.028zm8.48-4.276c0 .186.037.318.111.399.08.08.214.12.4.12h4.833l-5.344-5.445v4.926zM4.94 24a4.51 4.51 0 01-1.818-.37 4.698 4.698 0 01-1.503-1.012 4.828 4.828 0 01-1.02-1.503 4.533 4.533 0 01-.372-1.827c0-.65.124-1.256.371-1.819a4.828 4.828 0 011.02-1.503c.434-.439.935-.779 1.504-1.02a4.51 4.51 0 011.818-.371c.65 0 1.259.123 1.828.37.569.242 1.07.58 1.503 1.012.432.433.77.934 1.01 1.503.248.569.372 1.178.372 1.828 0 .643-.124 1.249-.371 1.818a4.751 4.751 0 01-1.03 1.503 4.828 4.828 0 01-1.503 1.02 4.488 4.488 0 01-1.81.371zm0-1.762c.173 0 .31-.053.408-.158a.552.552 0 00.158-.408v-1.819h1.818a.552.552 0 00.408-.157.533.533 0 00.158-.408.533.533 0 00-.158-.409.552.552 0 00-.408-.157H5.506v-1.819a.552.552 0 00-.158-.408.534.534 0 00-.408-.158.564.564 0 00-.418.158.572.572 0 00-.148.408v1.819H2.556a.552.552 0 00-.409.157.533.533 0 00-.157.409c0 .173.052.309.157.408a.552.552 0 00.409.157h1.818v1.819c0 .167.05.303.148.408a.564.564 0 00.418.158z"
26
+ fill={color}
27
+ />
28
+ </Svg>
29
+ );
30
+ };
31
+
32
+ // https://www.figma.com/design/52qDYWUMjXAGre1dcnz5bz/Procivis-One-Wallet?node-id=621-19281&t=RS4pnpOH4RNYzd8j-0
33
+ export const SignIcon: FC<SvgProps> = ({ color, ...props }) => {
34
+ return (
35
+ <Svg width={27} height={24} viewBox="0 0 27 24" fill="none" {...props}>
36
+ <Path
37
+ d="M8.807 22.913c-.827 0-1.442-.228-1.846-.686-.404-.45-.607-1.03-.607-1.74 0-.662.167-1.388.501-2.18.34-.79.818-1.576 1.433-2.355a12.083 12.083 0 012.197-2.136 11.226 11.226 0 012.84-1.564 9.352 9.352 0 013.322-.589c.568 0 1.019.132 1.353.396.34.257.51.606.51 1.046 0 .234-.033.465-.097.694a13.12 13.12 0 01-.193.615 1.384 1.384 0 00-.097.43c0 .1.044.15.132.15.123 0 .308-.1.554-.299.252-.199.539-.445.86-.738.329-.299.675-.595 1.038-.888a7.33 7.33 0 011.081-.747c.363-.199.697-.299 1.002-.299.352 0 .61.1.774.3.163.193.275.436.334.729.064.287.11.577.14.87.03.287.08.53.15.73.07.193.202.29.395.29a.815.815 0 00.43-.124.774.774 0 01.431-.131c.17 0 .305.058.405.175a.62.62 0 01.158.431.635.635 0 01-.106.36.841.841 0 01-.255.264c-.181.117-.38.202-.597.255-.217.053-.416.079-.598.079-.44 0-.773-.09-1.002-.273a1.52 1.52 0 01-.483-.685 4.234 4.234 0 01-.194-.817 7.551 7.551 0 00-.114-.686c-.04-.188-.126-.281-.255-.281-.146 0-.342.102-.588.307-.247.205-.528.46-.844.765-.317.299-.657.6-1.02.905-.363.305-.732.56-1.107.765-.37.205-.733.308-1.09.308-.322 0-.592-.094-.809-.282-.216-.193-.325-.457-.325-.79 0-.253.032-.493.097-.721l.21-.677c.071-.229.106-.472.106-.73 0-.24-.16-.36-.483-.36-1.02 0-1.978.17-2.874.51a9.486 9.486 0 00-2.435 1.327 10.996 10.996 0 00-1.88 1.793 8.956 8.956 0 00-1.214 1.916c-.28.633-.421 1.195-.421 1.687 0 .399.1.721.298.967.205.252.519.378.94.378.645 0 1.243-.237 1.794-.712.55-.468 1.031-1.122 1.441-1.96.41-.832.727-1.796.95-2.891.228-1.096.342-2.268.342-3.516 0-1.043-.102-2.021-.307-2.935-.205-.92-.501-1.729-.888-2.426-.387-.698-.853-1.245-1.398-1.644a3.023 3.023 0 00-1.828-.597c-.504 0-.958.134-1.362.404-.398.27-.715.633-.95 1.09a3.34 3.34 0 00-.35 1.547c0 .884.178 1.702.535 2.452A8.048 8.048 0 008.314 12.4a11.734 11.734 0 001.758 1.53c.61.421 1.166.756 1.67 1.002a.652.652 0 01.281.246.555.555 0 01.088.298c0 .153-.058.29-.176.414a.596.596 0 01-.439.175.738.738 0 01-.334-.079 13.678 13.678 0 01-1.828-1.046 12.83 12.83 0 01-1.661-1.37c-.516-.51-.97-1.061-1.362-1.653a8.333 8.333 0 01-.915-1.898 6.543 6.543 0 01-.333-2.083c0-.82.175-1.56.527-2.215A4.198 4.198 0 017.03 4.148a3.658 3.658 0 012.04-.588c.878 0 1.67.231 2.372.694.71.463 1.316 1.104 1.82 1.925.504.814.89 1.763 1.16 2.847.27 1.079.404 2.236.404 3.472 0 1.459-.143 2.818-.43 4.078-.282 1.26-.689 2.364-1.222 3.314-.527.949-1.16 1.69-1.899 2.223a4.12 4.12 0 01-2.47.8zM.703 19.696a.684.684 0 01-.5-.21.7.7 0 01-.203-.502.7.7 0 01.202-.5.7.7 0 01.501-.203H25.7a.7.7 0 01.501.202c.14.141.211.308.211.501 0 .194-.07.36-.21.501a.684.684 0 01-.502.211H.703zM.457 16.27a.556.556 0 01-.176-.405c0-.152.059-.287.176-.404l3.006-2.988a.54.54 0 01.395-.167.51.51 0 01.405.167.537.537 0 01.175.404.528.528 0 01-.175.396l-3.006 2.997a.583.583 0 01-.404.175.528.528 0 01-.396-.175zm3.006 0L.457 13.272a.528.528 0 01-.176-.396c0-.158.059-.293.176-.404a.528.528 0 01.396-.176c.158 0 .293.059.404.176l3.006 2.988a.556.556 0 010 .809.537.537 0 01-.405.175.528.528 0 01-.395-.175z"
38
+ fill={color}
39
+ />
40
+ </Svg>
41
+ );
42
+ };
43
+
20
44
  // https://www.figma.com/file/52qDYWUMjXAGre1dcnz5bz/Procivis-One-Wallet?type=design&node-id=415-10316&mode=design&t=5mm9J3ttJ4bbt2N3-4
21
45
  export const HistoryIcon: FC<SvgProps> = ({ color, ...props }) => {
22
46
  return (
@@ -9,8 +9,8 @@ import { Typography } from '../../text';
9
9
  import { useAppColorScheme } from '../../theme';
10
10
 
11
11
  type WalletEmptyListProps = {
12
- onScanPress: () => void;
13
- scanButtonTitle: string;
12
+ onScanPress?: () => void;
13
+ scanButtonTitle?: string;
14
14
  subtitle: string;
15
15
  testID: string;
16
16
  title: string;
@@ -19,6 +19,7 @@ type WalletEmptyListProps = {
19
19
  const WalletEmptyList: FC<WalletEmptyListProps> = ({ onScanPress, scanButtonTitle, subtitle, testID, title }) => {
20
20
  const safeAreaInsets = useSafeAreaInsets();
21
21
  const colorScheme = useAppColorScheme();
22
+ const showButton = Boolean(onScanPress && scanButtonTitle);
22
23
 
23
24
  return (
24
25
  <View style={styles.empty}>
@@ -38,12 +39,14 @@ const WalletEmptyList: FC<WalletEmptyListProps> = ({ onScanPress, scanButtonTitl
38
39
  {subtitle}
39
40
  </Typography>
40
41
  <NoCredentialsIcon style={styles.emptyIcon} />
41
- <Button
42
- onPress={onScanPress}
43
- style={[styles.emptyButton, { bottom: Math.max(24, safeAreaInsets.bottom) }]}
44
- testID={concatTestID(testID, 'scanQrCode')}
45
- title={scanButtonTitle}
46
- />
42
+ {showButton && (
43
+ <Button
44
+ onPress={onScanPress}
45
+ style={[styles.emptyButton, { bottom: Math.max(24, safeAreaInsets.bottom) }]}
46
+ testID={concatTestID(testID, 'scanQrCode')}
47
+ title={scanButtonTitle!}
48
+ />
49
+ )}
47
50
  </View>
48
51
  );
49
52
  };
@@ -45,10 +45,12 @@ const WalletNotice: FunctionComponent<WalletNoticeProps> = ({ accessory, icon, s
45
45
  }, [accessory]);
46
46
 
47
47
  return (
48
- <View style={[styles.noticeContainer, style]}>
48
+ <View style={[styles.noticeContainer, style]} testID={testID}>
49
49
  <View style={styles.title}>
50
50
  {iconView}
51
- <Typography color={colorScheme.white}>{text}</Typography>
51
+ <Typography color={colorScheme.white} testID={concatTestID(testID, 'label')}>
52
+ {text}
53
+ </Typography>
52
54
  {accessoryView}
53
55
  </View>
54
56
  {onClose && (
@@ -0,0 +1,71 @@
1
+ import React, { useCallback, useState } from 'react';
2
+ import { StyleSheet, View } from 'react-native';
3
+
4
+ import { concatTestID } from '../../utils';
5
+ import { Button, ButtonType } from '../buttons';
6
+ import { useAppColorScheme } from '../theme/color-scheme-context';
7
+ import Typography, { TypographyProps } from './typography';
8
+
9
+ const testID = 'expandableTypography';
10
+
11
+ export type ExpandableTypographyProps = TypographyProps & {
12
+ numberOfLines?: number;
13
+ hideExpandButton?: boolean;
14
+ moreLabel?: string;
15
+ lessLabel?: string;
16
+ };
17
+
18
+ const ExpandableTypography: React.FC<ExpandableTypographyProps> = ({
19
+ numberOfLines = 3,
20
+ hideExpandButton,
21
+ moreLabel = 'More',
22
+ lessLabel = 'Less',
23
+ style,
24
+ ...props
25
+ }) => {
26
+ const colorScheme = useAppColorScheme();
27
+ const [expanded, setExpanded] = useState(false);
28
+ const [isTruncated, setIsTruncated] = useState(false);
29
+
30
+ const handlePress = useCallback(() => {
31
+ setExpanded((prev) => !prev);
32
+ }, []);
33
+
34
+ return (
35
+ <View style={[style]}>
36
+ <Typography
37
+ {...props}
38
+ numberOfLines={undefined}
39
+ style={[styles.hiddenTypography]}
40
+ onTextLayout={(e) => {
41
+ setIsTruncated(e.nativeEvent.lines.length > numberOfLines);
42
+ }}
43
+ />
44
+ <Typography {...props} numberOfLines={expanded ? undefined : numberOfLines} />
45
+ {(isTruncated || expanded) && !hideExpandButton && (
46
+ <Button
47
+ onPress={handlePress}
48
+ type={ButtonType.Secondary}
49
+ style={[
50
+ styles.button,
51
+ {
52
+ backgroundColor: colorScheme.background,
53
+ },
54
+ ]}
55
+ testID={concatTestID(testID, 'showMore')}
56
+ title={expanded ? lessLabel : moreLabel}
57
+ />
58
+ )}
59
+ </View>
60
+ );
61
+ };
62
+
63
+ const styles = StyleSheet.create({
64
+ button: {
65
+ marginTop: 10,
66
+ paddingVertical: 12,
67
+ },
68
+ hiddenTypography: { opacity: 0, position: 'absolute', zIndex: -1 },
69
+ });
70
+
71
+ export default ExpandableTypography;
@@ -1,4 +1,5 @@
1
+ import ExpandableTypography, { ExpandableTypographyProps } from './expandableTypography';
1
2
  import type { TypographyProps } from './typography';
2
3
  import Typography from './typography';
3
4
 
4
- export { Typography, TypographyProps };
5
+ export { ExpandableTypography, ExpandableTypographyProps, Typography, TypographyProps };
@@ -43,7 +43,7 @@ export const useCredentialSchemaPreview = (url: string) => {
43
43
  if (!response.ok) {
44
44
  throw response.originalError;
45
45
  }
46
- return response.data as ImportCredentialSchemaRequestSchema;
46
+ return prepareImportCredentialSchema(response.data);
47
47
  }),
48
48
  {
49
49
  keepPreviousData: true,
@@ -51,6 +51,28 @@ export const useCredentialSchemaPreview = (url: string) => {
51
51
  );
52
52
  };
53
53
 
54
+ const prepareImportCredentialSchema = (data: unknown): ImportCredentialSchemaRequestSchema => {
55
+ if (!data || typeof data !== 'object') {
56
+ throw Error('Invalid credential schema data');
57
+ }
58
+
59
+ if ('formats' in data) {
60
+ // v2 schema: just return
61
+ return data as ImportCredentialSchemaRequestSchema;
62
+ }
63
+
64
+ // v1 schema: convert format
65
+ const schema = data as Record<string, any>;
66
+ const format = schema.format;
67
+ const schemaId = schema.schemaId;
68
+ const revocationMethod = schema.revocationMethod;
69
+ return {
70
+ ...schema,
71
+ formats: [{ format, schemaId }],
72
+ allowRevocation: Boolean(revocationMethod),
73
+ } as unknown as ImportCredentialSchemaRequestSchema;
74
+ };
75
+
54
76
  export const useCredentialSchemaAccept = () => {
55
77
  const queryClient = useQueryClient();
56
78
  const { core, organisationId } = useONECore();
@@ -6,7 +6,7 @@ import {
6
6
  HistoryErrorMetadata,
7
7
  IdentifierListQuery,
8
8
  OneError,
9
- PresentationSubmitCredentialRequest,
9
+ PresentationSubmitV2CredentialRequest,
10
10
  ProofListQuery,
11
11
  ProofSchemaDetail,
12
12
  ProofState,
@@ -102,9 +102,9 @@ export const useProofAccept = () => {
102
102
  interactionId,
103
103
  credentials,
104
104
  }: {
105
- credentials: Record<string, PresentationSubmitCredentialRequest[]>;
105
+ credentials: Record<string, PresentationSubmitV2CredentialRequest[]>;
106
106
  interactionId: string;
107
- }) => core.holderSubmitProof(interactionId, credentials),
107
+ }) => core.holderSubmitProofV2(interactionId, credentials),
108
108
  {
109
109
  onError: async (err) => {
110
110
  reportException(err, 'Proof submission failure');