mirror of
https://github.com/selfxyz/self.git
synced 2026-01-09 22:58:20 -05:00
save refactor wip
This commit is contained in:
62
app/src/hooks/useSelfAppData.ts
Normal file
62
app/src/hooks/useSelfAppData.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
// 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 { useMemo } from 'react';
|
||||
|
||||
import type { SelfApp } from '@selfxyz/common';
|
||||
import type { SelfAppDisclosureConfig } from '@selfxyz/common/utils/appType';
|
||||
import { formatEndpoint } from '@selfxyz/common/utils/scope';
|
||||
|
||||
import { getDisclosureItems } from '@/utils/disclosureUtils';
|
||||
import { formatUserId } from '@/utils/formatUserId';
|
||||
|
||||
/**
|
||||
* Hook that extracts and transforms SelfApp data for use in UI components.
|
||||
* Returns memoized values for logo source, URL, formatted user ID, and disclosure items.
|
||||
*/
|
||||
export function useSelfAppData(selfApp: SelfApp | null) {
|
||||
const logoSource = useMemo(() => {
|
||||
if (!selfApp?.logoBase64) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if the logo is already a URL
|
||||
if (
|
||||
selfApp.logoBase64.startsWith('http://') ||
|
||||
selfApp.logoBase64.startsWith('https://')
|
||||
) {
|
||||
return { uri: selfApp.logoBase64 };
|
||||
}
|
||||
|
||||
// Otherwise handle as base64
|
||||
const base64String = selfApp.logoBase64.startsWith('data:image')
|
||||
? selfApp.logoBase64
|
||||
: `data:image/png;base64,${selfApp.logoBase64}`;
|
||||
return { uri: base64String };
|
||||
}, [selfApp?.logoBase64]);
|
||||
|
||||
const url = useMemo(() => {
|
||||
if (!selfApp?.endpoint) {
|
||||
return null;
|
||||
}
|
||||
return formatEndpoint(selfApp.endpoint);
|
||||
}, [selfApp?.endpoint]);
|
||||
|
||||
const formattedUserId = useMemo(
|
||||
() => formatUserId(selfApp?.userId, selfApp?.userIdType),
|
||||
[selfApp?.userId, selfApp?.userIdType],
|
||||
);
|
||||
|
||||
const disclosureItems = useMemo(() => {
|
||||
const disclosures = (selfApp?.disclosures as SelfAppDisclosureConfig) || {};
|
||||
return getDisclosureItems(disclosures);
|
||||
}, [selfApp?.disclosures]);
|
||||
|
||||
return {
|
||||
logoSource,
|
||||
url,
|
||||
formattedUserId,
|
||||
disclosureItems,
|
||||
};
|
||||
}
|
||||
29
app/src/hooks/useSelfAppStalenessCheck.ts
Normal file
29
app/src/hooks/useSelfAppStalenessCheck.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
// 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 { useCallback } from 'react';
|
||||
import { useFocusEffect } from '@react-navigation/native';
|
||||
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
|
||||
import type { SelfApp } from '@selfxyz/common';
|
||||
|
||||
import type { RootStackParamList } from '@/navigation';
|
||||
|
||||
/**
|
||||
* Hook that checks if SelfApp data is stale (missing or empty disclosures)
|
||||
* and navigates to Home screen if stale data is detected.
|
||||
*/
|
||||
export function useSelfAppStalenessCheck(
|
||||
selfApp: SelfApp | null,
|
||||
disclosureItems: Array<{ key: string; text: string }>,
|
||||
navigation: NativeStackNavigationProp<RootStackParamList>,
|
||||
) {
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
if (!selfApp || disclosureItems.length === 0) {
|
||||
navigation.navigate({ name: 'Home', params: {} });
|
||||
}
|
||||
}, [selfApp, disclosureItems.length, navigation]),
|
||||
);
|
||||
}
|
||||
@@ -21,8 +21,6 @@ import {
|
||||
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
|
||||
import { commonNames } from '@selfxyz/common/constants/countries';
|
||||
import type { SelfAppDisclosureConfig } from '@selfxyz/common/utils/appType';
|
||||
import { formatEndpoint } from '@selfxyz/common/utils/scope';
|
||||
import type {
|
||||
DocumentCatalog,
|
||||
DocumentMetadata,
|
||||
@@ -47,11 +45,12 @@ import {
|
||||
truncateAddress,
|
||||
WalletAddressModal,
|
||||
} from '@/components/proof-request';
|
||||
import { useSelfAppData } from '@/hooks/useSelfAppData';
|
||||
import { useSelfAppStalenessCheck } from '@/hooks/useSelfAppStalenessCheck';
|
||||
import type { RootStackParamList } from '@/navigation';
|
||||
import { usePassport } from '@/providers/passportDataProvider';
|
||||
import { useDocumentCacheStore } from '@/stores/documentCacheStore';
|
||||
import { getDisclosureItems } from '@/utils/disclosureUtils';
|
||||
import { formatUserId } from '@/utils/formatUserId';
|
||||
import { getDocumentTypeName } from '@/utils/documentUtils';
|
||||
|
||||
/**
|
||||
* Converts a 3-letter country code to its full country name
|
||||
@@ -99,22 +98,6 @@ function getDocumentDisplayName(
|
||||
return isMock ? `Developer ${metadata.documentType}` : metadata.documentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the document type display name for the proof request message.
|
||||
*/
|
||||
function getDocumentTypeName(category: string | undefined): string {
|
||||
switch (category) {
|
||||
case 'passport':
|
||||
return 'Passport';
|
||||
case 'id_card':
|
||||
return 'ID Card';
|
||||
case 'aadhaar':
|
||||
return 'Aadhaar';
|
||||
default:
|
||||
return 'Document';
|
||||
}
|
||||
}
|
||||
|
||||
function determineDocumentState(
|
||||
metadata: DocumentMetadata,
|
||||
documentData: IDDocument | undefined,
|
||||
@@ -146,6 +129,13 @@ const DocumentSelectorForProvingScreen: React.FC = () => {
|
||||
usePassport();
|
||||
const { getCache, setCache, isValid } = useDocumentCacheStore();
|
||||
|
||||
// Extract SelfApp data using hook
|
||||
const { logoSource, url, formattedUserId, disclosureItems } =
|
||||
useSelfAppData(selfApp);
|
||||
|
||||
// Check for stale data and navigate to Home if needed
|
||||
useSelfAppStalenessCheck(selfApp, disclosureItems, navigation);
|
||||
|
||||
const [documentCatalog, setDocumentCatalog] = useState<DocumentCatalog>({
|
||||
documents: [],
|
||||
});
|
||||
@@ -163,47 +153,6 @@ const DocumentSelectorForProvingScreen: React.FC = () => {
|
||||
const abortControllerRef = useRef<AbortController | null>(null);
|
||||
const scrollOffsetRef = useRef(0);
|
||||
|
||||
// Memoized values from selfApp
|
||||
const logoSource = useMemo(() => {
|
||||
if (!selfApp?.logoBase64) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
selfApp.logoBase64.startsWith('http://') ||
|
||||
selfApp.logoBase64.startsWith('https://')
|
||||
) {
|
||||
return { uri: selfApp.logoBase64 };
|
||||
}
|
||||
|
||||
const base64String = selfApp.logoBase64.startsWith('data:image')
|
||||
? selfApp.logoBase64
|
||||
: `data:image/png;base64,${selfApp.logoBase64}`;
|
||||
return { uri: base64String };
|
||||
}, [selfApp?.logoBase64]);
|
||||
|
||||
const url = useMemo(() => {
|
||||
if (!selfApp?.endpoint) {
|
||||
return null;
|
||||
}
|
||||
return formatEndpoint(selfApp.endpoint);
|
||||
}, [selfApp?.endpoint]);
|
||||
|
||||
const disclosures = useMemo(
|
||||
() => (selfApp?.disclosures as SelfAppDisclosureConfig) || {},
|
||||
[selfApp?.disclosures],
|
||||
);
|
||||
|
||||
const disclosureItems = useMemo(
|
||||
() => getDisclosureItems(disclosures),
|
||||
[disclosures],
|
||||
);
|
||||
|
||||
const formattedUserId = useMemo(
|
||||
() => formatUserId(selfApp?.userId, selfApp?.userIdType),
|
||||
[selfApp?.userId, selfApp?.userIdType],
|
||||
);
|
||||
|
||||
const pickInitialDocument = useCallback(
|
||||
(
|
||||
catalog: DocumentCatalog,
|
||||
|
||||
@@ -26,8 +26,6 @@ import {
|
||||
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
|
||||
import { isMRZDocument } from '@selfxyz/common';
|
||||
import type { SelfAppDisclosureConfig } from '@selfxyz/common/utils/appType';
|
||||
import { formatEndpoint } from '@selfxyz/common/utils/scope';
|
||||
import { loadSelectedDocument, useSelfClient } from '@selfxyz/mobile-sdk-alpha';
|
||||
import { ProofEvents } from '@selfxyz/mobile-sdk-alpha/constants/analytics';
|
||||
|
||||
@@ -40,6 +38,8 @@ import {
|
||||
truncateAddress,
|
||||
WalletAddressModal,
|
||||
} from '@/components/proof-request';
|
||||
import { useSelfAppData } from '@/hooks/useSelfAppData';
|
||||
import { useSelfAppStalenessCheck } from '@/hooks/useSelfAppStalenessCheck';
|
||||
import { buttonTap } from '@/integrations/haptics';
|
||||
import type { RootStackParamList } from '@/navigation';
|
||||
import {
|
||||
@@ -53,35 +53,33 @@ import {
|
||||
import { useDocumentCacheStore } from '@/stores/documentCacheStore';
|
||||
import { useProofHistoryStore } from '@/stores/proofHistoryStore';
|
||||
import { ProofStatus } from '@/stores/proofTypes';
|
||||
import { getDisclosureItems } from '@/utils/disclosureUtils';
|
||||
import {
|
||||
checkDocumentExpiration,
|
||||
getDocumentAttributes,
|
||||
} from '@/utils/documentAttributes';
|
||||
import { formatUserId } from '@/utils/formatUserId';
|
||||
|
||||
function getDocumentTypeName(category: string | undefined): string {
|
||||
switch (category) {
|
||||
case 'passport':
|
||||
return 'Passport';
|
||||
case 'id_card':
|
||||
return 'ID Card';
|
||||
case 'aadhaar':
|
||||
return 'Aadhaar';
|
||||
default:
|
||||
return 'Document';
|
||||
}
|
||||
}
|
||||
import { getDocumentTypeName } from '@/utils/documentUtils';
|
||||
|
||||
const ProveScreen: React.FC = () => {
|
||||
const selfClient = useSelfClient();
|
||||
const { trackEvent } = selfClient;
|
||||
const { navigate } =
|
||||
const navigation =
|
||||
useNavigation<NativeStackNavigationProp<RootStackParamList>>();
|
||||
const { navigate } = navigation;
|
||||
const route = useRoute<RouteProp<RootStackParamList, 'Prove'>>();
|
||||
const isFocused = useIsFocused();
|
||||
const { useProvingStore, useSelfAppStore } = selfClient;
|
||||
const selectedApp = useSelfAppStore(state => state.selfApp);
|
||||
|
||||
// Extract SelfApp data using hook
|
||||
const { logoSource, url, formattedUserId, disclosureItems } =
|
||||
useSelfAppData(selectedApp);
|
||||
|
||||
// Check for stale data and navigate to Home if needed
|
||||
useSelfAppStalenessCheck(
|
||||
selectedApp,
|
||||
disclosureItems,
|
||||
navigation as NativeStackNavigationProp<RootStackParamList>,
|
||||
);
|
||||
const selectedAppRef = useRef<typeof selectedApp>(null);
|
||||
const processedSessionsRef = useRef<Set<string>>(new Set());
|
||||
|
||||
@@ -255,47 +253,6 @@ const ProveScreen: React.FC = () => {
|
||||
enhanceApp();
|
||||
}, [selectedApp, selfClient]);
|
||||
|
||||
const disclosureItems = useMemo(
|
||||
() =>
|
||||
getDisclosureItems(
|
||||
(selectedApp?.disclosures as SelfAppDisclosureConfig) || {},
|
||||
),
|
||||
[selectedApp?.disclosures],
|
||||
);
|
||||
|
||||
// Format the logo source based on whether it's a URL or base64 string
|
||||
const logoSource = useMemo(() => {
|
||||
if (!selectedApp?.logoBase64) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if the logo is already a URL
|
||||
if (
|
||||
selectedApp.logoBase64.startsWith('http://') ||
|
||||
selectedApp.logoBase64.startsWith('https://')
|
||||
) {
|
||||
return { uri: selectedApp.logoBase64 };
|
||||
}
|
||||
|
||||
// Otherwise handle as base64 as before
|
||||
const base64String = selectedApp.logoBase64.startsWith('data:image')
|
||||
? selectedApp.logoBase64
|
||||
: `data:image/png;base64,${selectedApp.logoBase64}`;
|
||||
return { uri: base64String };
|
||||
}, [selectedApp?.logoBase64]);
|
||||
|
||||
const url = useMemo(() => {
|
||||
if (!selectedApp?.endpoint) {
|
||||
return null;
|
||||
}
|
||||
return formatEndpoint(selectedApp.endpoint);
|
||||
}, [selectedApp?.endpoint]);
|
||||
|
||||
const formattedUserId = useMemo(
|
||||
() => formatUserId(selectedApp?.userId, selectedApp?.userIdType),
|
||||
[selectedApp?.userId, selectedApp?.userIdType],
|
||||
);
|
||||
|
||||
function onVerify() {
|
||||
provingStore.setUserConfirmed(selfClient);
|
||||
buttonTap();
|
||||
|
||||
@@ -20,22 +20,7 @@ import type { RootStackParamList } from '@/navigation';
|
||||
import { usePassport } from '@/providers/passportDataProvider';
|
||||
import { useDocumentCacheStore } from '@/stores/documentCacheStore';
|
||||
import { useSettingStore } from '@/stores/settingStore';
|
||||
|
||||
/**
|
||||
* Gets the document type display name for the proof request message.
|
||||
*/
|
||||
function getDocumentTypeName(category: string | undefined): string {
|
||||
switch (category) {
|
||||
case 'passport':
|
||||
return 'Passport';
|
||||
case 'id_card':
|
||||
return 'ID Card';
|
||||
case 'aadhaar':
|
||||
return 'Aadhaar';
|
||||
default:
|
||||
return 'Document';
|
||||
}
|
||||
}
|
||||
import { getDocumentTypeName } from '@/utils/documentUtils';
|
||||
|
||||
/**
|
||||
* Router screen for the proving flow that decides whether to skip the document selector.
|
||||
|
||||
19
app/src/utils/documentUtils.ts
Normal file
19
app/src/utils/documentUtils.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
// 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.
|
||||
|
||||
/**
|
||||
* Gets the document type display name for the proof request message.
|
||||
*/
|
||||
export function getDocumentTypeName(category: string | undefined): string {
|
||||
switch (category) {
|
||||
case 'passport':
|
||||
return 'Passport';
|
||||
case 'id_card':
|
||||
return 'ID Card';
|
||||
case 'aadhaar':
|
||||
return 'Aadhaar';
|
||||
default:
|
||||
return 'Document';
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,9 @@ export { extraYPadding, normalizeBorderWidth } from '@/utils/styleUtils';
|
||||
// JSON utilities
|
||||
export { formatUserId } from '@/utils/formatUserId';
|
||||
|
||||
// Document utilities
|
||||
export { getDocumentTypeName } from '@/utils/documentUtils';
|
||||
|
||||
export {
|
||||
getModalCallbacks,
|
||||
registerModalCallbacks,
|
||||
|
||||
Reference in New Issue
Block a user