refactor: remove blur on document when selected + show old view ID data (#1747)

* refactor: remove blur on document when selected

* fix: show original 'view ID data'
This commit is contained in:
Evi Nova
2026-02-14 09:34:08 +10:00
committed by GitHub
parent 3576682e59
commit 3298e13e60
2 changed files with 390 additions and 34 deletions

View File

@@ -2,11 +2,10 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import type { FC } from 'react';
import React, { useCallback } from 'react';
import { Image, Pressable, StyleSheet } from 'react-native';
import React, { type FC, useCallback } from 'react';
import { Dimensions, Image, Pressable, StyleSheet } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import { Text, XStack, YStack } from 'tamagui';
import { Separator, Text, XStack, YStack } from 'tamagui';
import { useNavigation } from '@react-navigation/native';
import type { AadhaarData } from '@selfxyz/common';
@@ -20,11 +19,18 @@ import {
import { WarningTriangleIcon } from '@selfxyz/euclid/dist/components/icons/WarningTriangleIcon';
import { RoundFlag } from '@selfxyz/mobile-sdk-alpha/components';
import {
black,
red600,
slate100,
slate300,
slate400,
slate500,
white,
yellow500,
} from '@selfxyz/mobile-sdk-alpha/constants/colors';
import { dinot, plexMono } from '@selfxyz/mobile-sdk-alpha/constants/fonts';
import AadhaarIcon from '@selfxyz/mobile-sdk-alpha/svgs/icons/aadhaar.svg';
import EPassport from '@selfxyz/mobile-sdk-alpha/svgs/icons/epassport.svg';
import CardBackgroundId1 from '@/assets/images/card_background_id1.png';
import CardBackgroundId2 from '@/assets/images/card_background_id2.png';
@@ -34,14 +40,20 @@ import CardBackgroundId5 from '@/assets/images/card_background_id5.png';
import CardBackgroundId6 from '@/assets/images/card_background_id6.png';
import DevCardLogo from '@/assets/images/dev_card_logo.svg';
import DevCardWave from '@/assets/images/dev_card_wave.svg';
import LogoGray from '@/assets/images/logo_gray.svg';
import SelfLogoPending from '@/assets/images/self_logo_pending.svg';
import WaveOverlay from '@/assets/images/wave_overlay.png';
import { getSecurityLevel } from '@/components/homescreen/cardSecurityBadge';
import { cardStyles } from '@/components/homescreen/cardStyles';
import KycIdCard from '@/components/homescreen/KycIdCard';
import { SvgXml } from '@/components/homescreen/SvgXmlWrapper';
import { useCardDimensions } from '@/hooks/useCardDimensions';
import { getBackgroundIndex } from '@/utils/cardBackgroundSelector';
import { getDocumentAttributes } from '@/utils/documentAttributes';
import {
formatDateFromYYMMDD,
getDocumentAttributes,
getNameAndSurname,
} from '@/utils/documentAttributes';
import { registerModalCallbacks } from '@/utils/modalCallbackRegistry';
const CARD_BACKGROUNDS = [
@@ -282,6 +294,12 @@ const getCountryDemonym = (code: string): string => {
return COUNTRY_DEMONYMS[upperCode] || upperCode;
};
const logoSvg = `<svg width="47" height="46" viewBox="0 0 47 46" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.7814 13.2168C12.7814 12.7057 13.1992 12.2969 13.7214 12.2969H30.0017L42.5676 0H11.2408L0 11.0001V29.0973H12.7814V13.2104V13.2168Z" fill="white"/>
<path d="M34.2186 16.8515V32.3552C34.2186 32.8663 33.8008 33.2751 33.2786 33.2751H17.4357L4.43236 46H35.7592L47 34.9999V16.8579H34.2186V16.8515Z" fill="white"/>
<path d="M28.9703 17.6525H18.0362V28.3539H28.9703V17.6525Z" fill="#00FFB6"/>
</svg>`;
interface IdCardLayoutAttributes {
idDocument: PassportData | AadhaarData | KycData | null;
selected: boolean;
@@ -356,6 +374,331 @@ const IdCardLayout: FC<IdCardLayoutAttributes> = ({
<KycIdCard idDocument={idDocument} selected={selected} hidden={hidden} />
);
}
// When data is revealed (hidden=false), show the white data-view card
if (!hidden && selected) {
const { width: screenWidth } = Dimensions.get('window');
const revealedWidth = screenWidth * 0.95 - 16;
const revealedHeight = revealedWidth * 0.645;
const revealedBorderRadius = revealedWidth * 0.04;
const revealedPadding = revealedWidth * 0.035;
const revealedFontSize = {
large: revealedWidth * 0.045,
small: revealedWidth * 0.028,
xsmall: revealedWidth * 0.022,
};
const imageSize = {
width: revealedWidth * 0.2,
height: revealedWidth * 0.29,
};
const contentLeftOffset = imageSize.width + revealedPadding;
const docAttributes = getDocumentAttributes(idDocument);
const nameData = getNameAndSurname(docAttributes.nameSlice);
return (
<YStack width="100%" alignItems="center" justifyContent="center">
<YStack
width={revealedWidth}
height={revealedHeight}
backgroundColor={white}
borderRadius={revealedBorderRadius}
borderWidth={0.75}
borderColor={'#E0E0E0'}
padding={revealedPadding}
shadowColor={black}
shadowOffset={{ width: 0, height: 2 }}
shadowOpacity={0.1}
shadowRadius={4}
elevation={4}
marginBottom={8}
justifyContent="center"
>
{/* Header Section */}
<XStack>
<XStack alignItems="center">
{isAadhaarDocument(idDocument) ? (
<AadhaarIcon
width={revealedFontSize.large * 3}
height={revealedFontSize.large * 3 * 0.617}
/>
) : (
<EPassport
width={revealedFontSize.large * 3}
height={revealedFontSize.large * 3 * 0.617}
/>
)}
<YStack marginLeft={imageSize.width - revealedFontSize.large * 3}>
<Text
fontWeight="bold"
fontFamily={dinot}
fontSize={revealedFontSize.large * 1.4}
color="black"
>
{isMRZDocument(idDocument) &&
idDocument.documentCategory === 'passport'
? 'Passport'
: isAadhaarDocument(idDocument)
? 'Aadhaar'
: 'ID Card'}
</Text>
<Text
fontSize={revealedFontSize.small}
color={slate400}
fontFamily={dinot}
>
Verified{' '}
{isMRZDocument(idDocument) &&
idDocument.documentCategory === 'passport'
? 'Biometric Passport'
: isAadhaarDocument(idDocument)
? 'Aadhaar Document'
: 'Biometric ID Card'}
</Text>
</YStack>
</XStack>
<XStack flex={1} justifyContent="flex-end">
{idDocument.mock && (
<YStack
marginTop={revealedPadding / 4}
borderWidth={1}
borderColor={slate300}
borderRadius={100}
paddingHorizontal={revealedPadding / 2}
alignSelf="flex-start"
backgroundColor={slate100}
paddingVertical={revealedPadding / 8}
>
<Text
fontSize={revealedFontSize.xsmall}
color={slate400}
fontFamily={dinot}
letterSpacing={revealedFontSize.xsmall * 0.15}
>
DEVELOPER
</Text>
</YStack>
)}
</XStack>
</XStack>
<Separator
backgroundColor={'#E0E0E0'}
height={1}
width={revealedWidth - 1}
marginLeft={-revealedPadding}
marginTop={revealedPadding}
/>
{/* Main Content Section */}
<XStack height="60%" paddingVertical={revealedPadding}>
{/* Person Image Placeholder */}
<YStack
width={imageSize.width}
height={imageSize.height}
backgroundColor="#F5F5F5"
borderRadius={revealedBorderRadius * 0.5}
justifyContent="center"
alignItems="center"
marginRight={revealedPadding}
>
<SvgXml
xml={logoSvg}
width={imageSize.width * 0.6}
height={imageSize.height * 0.6}
/>
</YStack>
{/* ID Attributes Grid */}
<YStack
flex={1}
justifyContent="space-between"
height={imageSize.height}
>
<XStack flex={1} gap={revealedPadding * 0.3}>
<YStack flex={1}>
<IdAttribute
name="TYPE"
value={
isMRZDocument(idDocument) &&
idDocument.documentCategory === 'passport'
? 'PASSPORT'
: isAadhaarDocument(idDocument)
? 'AADHAAR'
: 'ID CARD'
}
/>
</YStack>
<YStack flex={1}>
<IdAttribute
name="CODE"
value={idDocument.mock ? 'SELF DEV' : 'SELF ID'}
/>
</YStack>
<YStack flex={1}>
<IdAttribute
name="DOC NO."
value={docAttributes.passNoSlice}
/>
</YStack>
</XStack>
<XStack flex={1} gap={revealedPadding * 0.3}>
{isAadhaarDocument(idDocument) ? (
<>
<YStack flex={2}>
<IdAttribute
name="NAME"
value={[...nameData.surname, ...nameData.names].join(
' ',
)}
/>
</YStack>
<YStack flex={1}>
<IdAttribute name="SEX" value={docAttributes.sexSlice} />
</YStack>
</>
) : (
<>
<YStack flex={1}>
<IdAttribute
name="SURNAME"
value={nameData.surname.join(' ')}
/>
</YStack>
<YStack flex={1}>
<IdAttribute
name="NAME"
value={nameData.names.join(' ')}
/>
</YStack>
<YStack flex={1}>
<IdAttribute name="SEX" value={docAttributes.sexSlice} />
</YStack>
</>
)}
</XStack>
<XStack flex={1} gap={revealedPadding * 0.3}>
<YStack flex={1}>
<IdAttribute
name="NATIONALITY"
value={docAttributes.nationalitySlice}
/>
</YStack>
<YStack flex={1}>
<IdAttribute
name="DOB"
value={formatDateFromYYMMDD(docAttributes.dobSlice, true)}
/>
</YStack>
<YStack flex={1}>
<IdAttribute
name="EXPIRY DATE"
value={formatDateFromYYMMDD(docAttributes.expiryDateSlice)}
/>
</YStack>
</XStack>
<XStack flex={1} gap={revealedPadding * 0.3}>
<YStack flex={1}>
<IdAttribute
name="AUTHORITY"
value={docAttributes.issuingStateSlice}
/>
</YStack>
<YStack flex={1} />
<YStack flex={1} />
</XStack>
</YStack>
</XStack>
{/* Footer Section - MRZ */}
{isMRZDocument(idDocument) && idDocument.mrz && (
<XStack
alignItems="center"
backgroundColor={slate100}
borderRadius={revealedBorderRadius / 3}
paddingHorizontal={revealedPadding / 2}
paddingVertical={revealedPadding / 4}
>
<XStack width={contentLeftOffset} alignItems="center">
<LogoGray
width={revealedFontSize.large}
height={revealedFontSize.large}
/>
</XStack>
<YStack marginLeft={-revealedPadding / 2}>
{idDocument.documentCategory === 'passport' ? (
<>
<Text
fontSize={revealedFontSize.xsmall}
letterSpacing={revealedFontSize.xsmall * 0.1}
fontFamily={plexMono}
color={slate400}
>
{idDocument.mrz.slice(0, 44)}
</Text>
<Text
fontSize={revealedFontSize.xsmall}
letterSpacing={revealedFontSize.xsmall * 0.1}
fontFamily={plexMono}
color={slate400}
>
{idDocument.mrz.slice(44, 88)}
</Text>
</>
) : (
<>
<Text
fontSize={revealedFontSize.xsmall}
letterSpacing={revealedFontSize.xsmall * 0.44}
fontFamily={plexMono}
color={slate400}
>
{idDocument.mrz.slice(0, 30)}
</Text>
<Text
fontSize={revealedFontSize.xsmall}
letterSpacing={revealedFontSize.xsmall * 0.44}
fontFamily={plexMono}
color={slate400}
>
{idDocument.mrz.slice(30, 60)}
</Text>
<Text
fontSize={revealedFontSize.xsmall}
letterSpacing={revealedFontSize.xsmall * 0.44}
fontFamily={plexMono}
color={slate400}
>
{idDocument.mrz.slice(60, 90)}
</Text>
</>
)}
</YStack>
</XStack>
)}
{/* Footer Section - Empty placeholder for Aadhaar */}
{isAadhaarDocument(idDocument) && (
<XStack
alignItems="center"
backgroundColor={slate100}
borderRadius={revealedBorderRadius / 3}
paddingHorizontal={revealedPadding / 2}
paddingVertical={revealedPadding / 4}
minHeight={revealedFontSize.xsmall * 2.5}
>
<XStack width={contentLeftOffset} alignItems="center">
<LogoGray
width={revealedFontSize.large}
height={revealedFontSize.large}
/>
</XStack>
</XStack>
)}
</YStack>
</YStack>
);
}
const padding = cardWidth * 0.04;
// Get document attributes
@@ -712,4 +1055,33 @@ const styles = StyleSheet.create({
},
});
interface IdAttributeProps {
name: string;
value: string;
}
const IdAttribute: FC<IdAttributeProps> = ({ name, value }) => {
const { width: screenWidth } = Dimensions.get('window');
const attrFontSize = {
label: screenWidth * 0.024,
value: screenWidth * 0.02,
};
return (
<YStack>
<Text
fontWeight="bold"
fontSize={attrFontSize.label}
color={slate500}
fontFamily={dinot}
>
{name}
</Text>
<Text fontSize={attrFontSize.value} color={slate400} fontFamily={dinot}>
{value}
</Text>
</YStack>
);
};
export default IdCardLayout;

View File

@@ -3,10 +3,10 @@
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import React, { useEffect, useState } from 'react';
import LinearGradient from 'react-native-linear-gradient';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { Button, Text, XStack, YStack, ZStack } from 'tamagui';
import { BlurView } from '@react-native-community/blur';
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import { useNavigation } from '@react-navigation/native';
import type { DocumentCatalog, IDDocument } from '@selfxyz/common/utils/types';
import {
@@ -36,18 +36,6 @@ const IdDetailsScreen: React.FC = () => {
const navigation = useNavigation();
const { bottom } = useSafeAreaInsets();
const [isFocused, setIsFocused] = useState(false);
// Added to unmount BlurView when screen loses focus
useFocusEffect(
React.useCallback(() => {
setIsFocused(true);
return () => {
setIsFocused(false);
};
}, []),
);
useEffect(() => {
const loadDocumentAndCatalog = async () => {
const allDocs = await getAllDocuments();
@@ -140,21 +128,17 @@ const IdDetailsScreen: React.FC = () => {
{ListHeader}
<ZStack flex={1}>
<ProofHistoryList documentId={documentId} />
{isFocused && (
<BlurView
style={{
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
height: 100,
}}
blurType="light"
blurAmount={4}
reducedTransparencyFallbackColor={slate50}
pointerEvents="none"
/>
)}
<LinearGradient
colors={['transparent', slate50]}
style={{
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
height: 100,
}}
pointerEvents="none"
/>
<YStack position="absolute" bottom={bottom + 20} left={20} right={20}>
<Button
backgroundColor={isConnected ? slate100 : white}