mirror of
https://github.com/selfxyz/self.git
synced 2026-02-19 02:24:25 -05:00
App/use whitelisted addresses for points (#1408)
* feat: enhance PointHistoryList and ProveScreen with disclosure event handling
- Updated PointHistoryList to include loading of disclosure events on refresh.
- Enhanced ProveScreen to set user's points address if not already defined.
- Added endpoint field to ProofHistory and database schema for better tracking.
- Introduced utility functions for fetching whitelisted disclosure addresses and managing disclosure events.
* fix: update navigation flow in PointsNavBar and GratificationScreen
- Changed navigation action in PointsNavBar from `goBack` to `navigate('Home')` for a more direct user experience.
- Updated GratificationScreen to navigate to 'Points' instead of going back, enhancing the flow after user interactions.
- Replaced the ArrowLeft icon with a new X icon for better visual consistency.
This commit is contained in:
committed by
GitHub
parent
87a81a50d5
commit
67eb0d46e4
@@ -31,7 +31,7 @@ export const PointsNavBar = (props: NativeStackHeaderProps) => {
|
||||
color={black}
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
props.navigation.goBack();
|
||||
props.navigation.navigate('Home');
|
||||
}}
|
||||
/>
|
||||
<View flex={1} alignItems="center" justifyContent="center">
|
||||
|
||||
@@ -68,15 +68,15 @@ export const PointHistoryList: React.FC<PointHistoryListProps> = ({
|
||||
}) => {
|
||||
const selfClient = useSelfClient();
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
// Subscribe to events directly from store - component will auto-update when store changes
|
||||
const pointEvents = usePointEventStore(state => state.getAllPointEvents());
|
||||
const isLoading = usePointEventStore(state => state.isLoading);
|
||||
const refreshPoints = usePointEventStore(state => state.refreshPoints);
|
||||
const refreshIncomingPoints = usePointEventStore(
|
||||
state => state.refreshIncomingPoints,
|
||||
);
|
||||
// loadEvents only needs to be called once on mount.
|
||||
// and it is called in Points.ts
|
||||
const loadDisclosureEvents = usePointEventStore(
|
||||
state => state.loadDisclosureEvents,
|
||||
);
|
||||
|
||||
const formatDate = (timestamp: number) => {
|
||||
return new Date(timestamp).toLocaleTimeString([], {
|
||||
@@ -271,14 +271,15 @@ export const PointHistoryList: React.FC<PointHistoryListProps> = ({
|
||||
[],
|
||||
);
|
||||
|
||||
// Pull-to-refresh handler
|
||||
const onRefresh = useCallback(() => {
|
||||
selfClient.trackEvent(PointEvents.REFRESH_HISTORY);
|
||||
setRefreshing(true);
|
||||
Promise.all([refreshPoints(), refreshIncomingPoints()]).finally(() =>
|
||||
setRefreshing(false),
|
||||
);
|
||||
}, [selfClient, refreshPoints, refreshIncomingPoints]);
|
||||
Promise.all([
|
||||
refreshPoints(),
|
||||
refreshIncomingPoints(),
|
||||
loadDisclosureEvents(),
|
||||
]).finally(() => setRefreshing(false));
|
||||
}, [selfClient, refreshPoints, refreshIncomingPoints, loadDisclosureEvents]);
|
||||
|
||||
const keyExtractor = useCallback((item: PointEvent) => item.id, []);
|
||||
|
||||
|
||||
@@ -14,13 +14,13 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { Text, View, YStack } from 'tamagui';
|
||||
import { useNavigation, useRoute } from '@react-navigation/native';
|
||||
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import { X } from '@tamagui/lucide-icons';
|
||||
|
||||
import { DelayedLottieView } from '@selfxyz/mobile-sdk-alpha';
|
||||
import youWinAnimation from '@selfxyz/mobile-sdk-alpha/animations/loading/youWin.json';
|
||||
import { PrimaryButton } from '@selfxyz/mobile-sdk-alpha/components';
|
||||
|
||||
import GratificationBg from '@/images/gratification_bg.svg';
|
||||
import ArrowLeft from '@/images/icons/arrow_left.svg';
|
||||
import LogoWhite from '@/images/icons/logo_white.svg';
|
||||
import type { RootStackParamList } from '@/navigation';
|
||||
import { black, slate700, white } from '@/utils/colors';
|
||||
@@ -46,7 +46,7 @@ const GratificationScreen: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleBackPress = () => {
|
||||
navigation.goBack();
|
||||
navigation.navigate('Points' as never);
|
||||
};
|
||||
|
||||
const handleAnimationFinish = useCallback(() => {
|
||||
@@ -129,7 +129,7 @@ const GratificationScreen: React.FC = () => {
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
>
|
||||
<ArrowLeft width={24} height={24} />
|
||||
<X width={24} height={24} />
|
||||
</View>
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
@@ -8,7 +8,8 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { Linking, StyleSheet, View } from 'react-native';
|
||||
import { SystemBars } from 'react-native-edge-to-edge';
|
||||
import { ScrollView, Spinner } from 'tamagui';
|
||||
import { useIsFocused } from '@react-navigation/native';
|
||||
import { useIsFocused, useNavigation } from '@react-navigation/native';
|
||||
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
|
||||
import { useSelfClient } from '@selfxyz/mobile-sdk-alpha';
|
||||
import loadingAnimation from '@selfxyz/mobile-sdk-alpha/animations/loading/misc.json';
|
||||
@@ -25,6 +26,7 @@ import failAnimation from '@/assets/animations/proof_failed.json';
|
||||
import succesAnimation from '@/assets/animations/proof_success.json';
|
||||
import useHapticNavigation from '@/hooks/useHapticNavigation';
|
||||
import { ExpandableBottomLayout } from '@/layouts/ExpandableBottomLayout';
|
||||
import type { RootStackParamList } from '@/navigation';
|
||||
import { useProofHistoryStore } from '@/stores/proofHistoryStore';
|
||||
import { ProofStatus } from '@/stores/proofTypes';
|
||||
import { black, white } from '@/utils/colors';
|
||||
@@ -33,6 +35,7 @@ import {
|
||||
notificationError,
|
||||
notificationSuccess,
|
||||
} from '@/utils/haptic';
|
||||
import { getWhiteListedDisclosureAddresses } from '@/utils/points/utils';
|
||||
|
||||
const SuccessScreen: React.FC = () => {
|
||||
const selfClient = useSelfClient();
|
||||
@@ -41,6 +44,8 @@ const SuccessScreen: React.FC = () => {
|
||||
const selfApp = useSelfAppStore(state => state.selfApp);
|
||||
const appName = selfApp?.appName;
|
||||
const goHome = useHapticNavigation('Home');
|
||||
const navigation =
|
||||
useNavigation<NativeStackNavigationProp<RootStackParamList>>();
|
||||
|
||||
const { updateProofStatus } = useProofHistoryStore();
|
||||
|
||||
@@ -55,15 +60,28 @@ const SuccessScreen: React.FC = () => {
|
||||
useState<LottieViewProps['source']>(loadingAnimation);
|
||||
const [countdown, setCountdown] = useState<number | null>(null);
|
||||
const [countdownStarted, setCountdownStarted] = useState(false);
|
||||
const [whitelistedPoints, setWhitelistedPoints] = useState<number | null>(
|
||||
null,
|
||||
);
|
||||
const timerRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
const onOkPress = useCallback(() => {
|
||||
const onOkPress = useCallback(async () => {
|
||||
buttonTap();
|
||||
goHome();
|
||||
setTimeout(() => {
|
||||
selfClient.getSelfAppState().cleanSelfApp();
|
||||
}, 2000); // Wait 2 seconds to user coming back to the home screen. If we don't wait the appname will change and user will see it.
|
||||
}, [goHome, selfClient]);
|
||||
|
||||
if (whitelistedPoints !== null) {
|
||||
navigation.navigate('Gratification', {
|
||||
points: whitelistedPoints,
|
||||
});
|
||||
setTimeout(() => {
|
||||
selfClient.getSelfAppState().cleanSelfApp();
|
||||
}, 2000);
|
||||
} else {
|
||||
goHome();
|
||||
setTimeout(() => {
|
||||
selfClient.getSelfAppState().cleanSelfApp();
|
||||
}, 2000);
|
||||
}
|
||||
}, [whitelistedPoints, navigation, goHome, selfClient]);
|
||||
|
||||
function cancelDeeplinkCallbackRedirect() {
|
||||
setCountdown(null);
|
||||
@@ -88,7 +106,28 @@ const SuccessScreen: React.FC = () => {
|
||||
sessionId,
|
||||
appName,
|
||||
});
|
||||
// Start countdown for redirect (only if we are on this screen and haven't started yet)
|
||||
|
||||
if (selfApp?.endpoint && whitelistedPoints === null) {
|
||||
const checkWhitelist = async () => {
|
||||
try {
|
||||
const whitelistedContracts =
|
||||
await getWhiteListedDisclosureAddresses();
|
||||
const endpoint = selfApp.endpoint.toLowerCase();
|
||||
const whitelistedContract = whitelistedContracts.find(
|
||||
c => c.contract_address.toLowerCase() === endpoint,
|
||||
);
|
||||
|
||||
if (whitelistedContract) {
|
||||
setWhitelistedPoints(whitelistedContract.points_per_disclosure);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking whitelist:', error);
|
||||
}
|
||||
};
|
||||
|
||||
checkWhitelist();
|
||||
}
|
||||
|
||||
if (isFocused && !countdownStarted && selfApp?.deeplinkCallback) {
|
||||
if (selfApp?.deeplinkCallback) {
|
||||
try {
|
||||
@@ -133,7 +172,9 @@ const SuccessScreen: React.FC = () => {
|
||||
reason,
|
||||
updateProofStatus,
|
||||
selfApp?.deeplinkCallback,
|
||||
selfApp?.endpoint,
|
||||
countdownStarted,
|
||||
whitelistedPoints,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -44,6 +44,7 @@ import { ProofStatus } from '@/stores/proofTypes';
|
||||
import { black, slate300, white } from '@/utils/colors';
|
||||
import { formatUserId } from '@/utils/formatUserId';
|
||||
import { buttonTap } from '@/utils/haptic';
|
||||
import { getPointsAddress } from '@/utils/points/utils';
|
||||
|
||||
const ProveScreen: React.FC = () => {
|
||||
const selfClient = useSelfClient();
|
||||
@@ -83,11 +84,12 @@ const ProveScreen: React.FC = () => {
|
||||
sessionId: provingStore.uuid!,
|
||||
userId: selectedApp.userId,
|
||||
userIdType: selectedApp.userIdType,
|
||||
endpoint: selectedApp.endpoint,
|
||||
endpointType: selectedApp.endpointType,
|
||||
status: ProofStatus.PENDING,
|
||||
logoBase64: selectedApp.logoBase64,
|
||||
disclosures: JSON.stringify(selectedApp.disclosures),
|
||||
documentId: selectedDocumentId || '', // Fallback to empty if none selected
|
||||
documentId: selectedDocumentId || '',
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -115,6 +117,29 @@ const ProveScreen: React.FC = () => {
|
||||
selectedAppRef.current = selectedApp;
|
||||
}, [selectedApp, isFocused, provingStore, selfClient]);
|
||||
|
||||
// Enhance selfApp with user's points address if not already set
|
||||
useEffect(() => {
|
||||
console.log('useEffect selectedApp', selectedApp);
|
||||
if (!selectedApp || selectedApp.selfDefinedData) {
|
||||
return;
|
||||
}
|
||||
|
||||
const enhanceApp = async () => {
|
||||
const address = await getPointsAddress();
|
||||
|
||||
// Only update if still the same session
|
||||
if (selectedAppRef.current?.sessionId === selectedApp.sessionId) {
|
||||
console.log('enhancing app with points address', address);
|
||||
selfClient.getSelfAppState().setSelfApp({
|
||||
...selectedApp,
|
||||
selfDefinedData: address.toLowerCase(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
enhanceApp();
|
||||
}, [selectedApp, selfClient]);
|
||||
|
||||
const disclosureOptions = useMemo(() => {
|
||||
return (selectedApp?.disclosures as SelfAppDisclosureConfig) || [];
|
||||
}, [selectedApp?.disclosures]);
|
||||
|
||||
@@ -87,6 +87,7 @@ export const database: ProofDB = {
|
||||
sessionId TEXT NOT NULL UNIQUE,
|
||||
userId TEXT NOT NULL,
|
||||
userIdType TEXT NOT NULL,
|
||||
endpoint TEXT,
|
||||
endpointType TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
errorCode TEXT,
|
||||
@@ -108,10 +109,11 @@ export const database: ProofDB = {
|
||||
|
||||
try {
|
||||
const [insertResult] = await db.executeSql(
|
||||
`INSERT OR IGNORE INTO ${TABLE_NAME} (appName, endpointType, status, errorCode, errorReason, timestamp, disclosures, logoBase64, userId, userIdType, sessionId, documentId)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
`INSERT OR IGNORE INTO ${TABLE_NAME} (appName, endpoint, endpointType, status, errorCode, errorReason, timestamp, disclosures, logoBase64, userId, userIdType, sessionId, documentId)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[
|
||||
proof.appName,
|
||||
proof.endpoint || null,
|
||||
proof.endpointType,
|
||||
proof.status,
|
||||
proof.errorCode || null,
|
||||
@@ -133,12 +135,40 @@ export const database: ProofDB = {
|
||||
} catch (error) {
|
||||
if ((error as Error).message.includes('no column named documentId')) {
|
||||
await addDocumentIdColumn();
|
||||
// Then retry the insert (copy the executeSql call here)
|
||||
const [insertResult] = await db.executeSql(
|
||||
`INSERT OR IGNORE INTO ${TABLE_NAME} (appName, endpointType, status, errorCode, errorReason, timestamp, disclosures, logoBase64, userId, userIdType, sessionId, documentId)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
`INSERT OR IGNORE INTO ${TABLE_NAME} (appName, endpoint, endpointType, status, errorCode, errorReason, timestamp, disclosures, logoBase64, userId, userIdType, sessionId, documentId)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[
|
||||
proof.appName,
|
||||
proof.endpoint || null,
|
||||
proof.endpointType,
|
||||
proof.status,
|
||||
proof.errorCode || null,
|
||||
proof.errorReason || null,
|
||||
timestamp,
|
||||
proof.disclosures,
|
||||
proof.logoBase64 || null,
|
||||
proof.userId,
|
||||
proof.userIdType,
|
||||
proof.sessionId,
|
||||
proof.documentId,
|
||||
],
|
||||
);
|
||||
return {
|
||||
id: insertResult.insertId.toString(),
|
||||
timestamp,
|
||||
rowsAffected: insertResult.rowsAffected,
|
||||
};
|
||||
} else if (
|
||||
(error as Error).message.includes('no column named endpoint')
|
||||
) {
|
||||
await addEndpointColumn();
|
||||
const [insertResult] = await db.executeSql(
|
||||
`INSERT OR IGNORE INTO ${TABLE_NAME} (appName, endpoint, endpointType, status, errorCode, errorReason, timestamp, disclosures, logoBase64, userId, userIdType, sessionId, documentId)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[
|
||||
proof.appName,
|
||||
proof.endpoint || null,
|
||||
proof.endpointType,
|
||||
proof.status,
|
||||
proof.errorCode || null,
|
||||
@@ -184,3 +214,8 @@ async function addDocumentIdColumn() {
|
||||
`ALTER TABLE ${TABLE_NAME} ADD COLUMN documentId TEXT NOT NULL DEFAULT ''`,
|
||||
);
|
||||
}
|
||||
|
||||
async function addEndpointColumn() {
|
||||
const db = await openDatabase();
|
||||
await db.executeSql(`ALTER TABLE ${TABLE_NAME} ADD COLUMN endpoint TEXT`);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ interface PointEventState {
|
||||
events: PointEvent[];
|
||||
isLoading: boolean;
|
||||
loadEvents: () => Promise<void>;
|
||||
loadDisclosureEvents: () => Promise<void>;
|
||||
addEvent: (
|
||||
title: string,
|
||||
type: PointEventType,
|
||||
@@ -38,7 +39,6 @@ interface PointEventState {
|
||||
lastUpdated: number | null;
|
||||
promise: Promise<IncomingPoints | null> | null;
|
||||
};
|
||||
// these are the real points that are on chain. each sunday noon UTC they get updated based on incoming points
|
||||
points: number;
|
||||
refreshPoints: () => Promise<void>;
|
||||
fetchIncomingPoints: () => Promise<IncomingPoints | null>;
|
||||
@@ -82,13 +82,11 @@ export const usePointEventStore = create<PointEventState>()((set, get) => ({
|
||||
if (stored) {
|
||||
try {
|
||||
const parsed = JSON.parse(stored);
|
||||
// Validate that parsed data is an array
|
||||
if (!Array.isArray(parsed)) {
|
||||
console.error('Invalid stored events format, expected array');
|
||||
set({ events: [], isLoading: false });
|
||||
return;
|
||||
}
|
||||
// Validate each event has required fields
|
||||
const events: PointEvent[] = parsed.filter((event: unknown) => {
|
||||
if (
|
||||
typeof event === 'object' &&
|
||||
@@ -103,12 +101,9 @@ export const usePointEventStore = create<PointEventState>()((set, get) => ({
|
||||
return false;
|
||||
}) as PointEvent[];
|
||||
set({ events, isLoading: false });
|
||||
// Resume polling for any pending events that were interrupted by app restart
|
||||
// (New events are polled immediately in recordEvents.ts when created)
|
||||
get()
|
||||
.getUnprocessedEvents()
|
||||
.forEach(event => {
|
||||
// Use event.id as job_id (id is the job_id)
|
||||
pollEventProcessingStatus(event.id).then(result => {
|
||||
if (result === 'completed') {
|
||||
get().markEventAsProcessed(event.id);
|
||||
@@ -119,19 +114,36 @@ export const usePointEventStore = create<PointEventState>()((set, get) => ({
|
||||
});
|
||||
} catch (parseError) {
|
||||
console.error('Error parsing stored events:', parseError);
|
||||
// Clear corrupted data
|
||||
await AsyncStorage.removeItem(STORAGE_KEY);
|
||||
set({ events: [], isLoading: false });
|
||||
}
|
||||
} else {
|
||||
set({ isLoading: false });
|
||||
}
|
||||
await get().loadDisclosureEvents();
|
||||
} catch (error) {
|
||||
console.error('Error loading point events:', error);
|
||||
set({ isLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
loadDisclosureEvents: async () => {
|
||||
try {
|
||||
const { getDisclosurePointEvents } = await import(
|
||||
'@/utils/points/getEvents'
|
||||
);
|
||||
const { useProofHistoryStore } = await import(
|
||||
'@/stores/proofHistoryStore'
|
||||
);
|
||||
await useProofHistoryStore.getState().initDatabase();
|
||||
const disclosureEvents = await getDisclosurePointEvents();
|
||||
const existingEvents = get().events.filter(e => e.type !== 'disclosure');
|
||||
set({ events: [...existingEvents, ...disclosureEvents] });
|
||||
} catch (error) {
|
||||
console.error('Error loading disclosure events:', error);
|
||||
}
|
||||
},
|
||||
|
||||
fetchIncomingPoints: async () => {
|
||||
if (get().incomingPoints.promise) {
|
||||
return await get().incomingPoints.promise;
|
||||
|
||||
@@ -174,6 +174,7 @@ export const useProofHistoryStore = create<ProofHistoryState>()((set, get) => {
|
||||
id: row.id.toString(),
|
||||
sessionId: row.sessionId,
|
||||
appName: row.appName,
|
||||
endpoint: row.endpoint,
|
||||
endpointType: row.endpointType,
|
||||
status: row.status,
|
||||
errorCode: row.errorCode,
|
||||
|
||||
@@ -35,6 +35,7 @@ export interface ProofHistory {
|
||||
sessionId: string;
|
||||
userId: string;
|
||||
userIdType: UserIdType;
|
||||
endpoint?: string;
|
||||
endpointType: EndpointType;
|
||||
status: ProofStatus;
|
||||
errorCode?: string;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
|
||||
|
||||
import type { PointEvent, PointEventType } from '@/utils/points/types';
|
||||
import { getWhiteListedDisclosureAddresses } from '@/utils/points/utils';
|
||||
|
||||
/**
|
||||
* Shared helper to get events from store filtered by type.
|
||||
@@ -35,7 +36,49 @@ export const getBackupPointEvents = async (): Promise<PointEvent[]> => {
|
||||
};
|
||||
|
||||
export const getDisclosurePointEvents = async (): Promise<PointEvent[]> => {
|
||||
return getEventsByType('disclosure');
|
||||
try {
|
||||
const [whitelistedContracts, { useProofHistoryStore }] = await Promise.all([
|
||||
getWhiteListedDisclosureAddresses(),
|
||||
import('@/stores/proofHistoryStore'),
|
||||
]);
|
||||
|
||||
if (whitelistedContracts.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const whitelistedMap = new Map(
|
||||
whitelistedContracts.map(c => [
|
||||
c.contract_address.toLowerCase(),
|
||||
c.points_per_disclosure,
|
||||
]),
|
||||
);
|
||||
|
||||
const proofHistory = useProofHistoryStore.getState().proofHistory;
|
||||
const disclosureEvents: PointEvent[] = [];
|
||||
|
||||
for (const proof of proofHistory) {
|
||||
if (proof.status !== 'success' || !proof.endpoint) continue;
|
||||
|
||||
const endpoint = proof.endpoint.toLowerCase();
|
||||
|
||||
if (!whitelistedMap.has(endpoint)) continue;
|
||||
|
||||
const points = whitelistedMap.get(endpoint)!;
|
||||
disclosureEvents.push({
|
||||
id: proof.sessionId,
|
||||
title: `${proof.appName} disclosure`,
|
||||
type: 'disclosure',
|
||||
timestamp: proof.timestamp,
|
||||
points,
|
||||
status: 'completed',
|
||||
});
|
||||
}
|
||||
|
||||
return disclosureEvents;
|
||||
} catch (error) {
|
||||
console.error('Error loading disclosure point events:', error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const getPushNotificationPointEvents = async (): Promise<
|
||||
|
||||
@@ -10,6 +10,12 @@ import { getOrGeneratePointsAddress } from '@/providers/authProvider';
|
||||
import { POINTS_API_BASE_URL } from '@/utils/points/constants';
|
||||
import type { IncomingPoints } from '@/utils/points/types';
|
||||
|
||||
export type WhitelistedContract = {
|
||||
contract_address: string;
|
||||
points_per_disclosure: number;
|
||||
num_disclosures: number;
|
||||
};
|
||||
|
||||
export const formatTimeUntilDate = (targetDate: Date): string => {
|
||||
const now = new Date();
|
||||
const diffMs = targetDate.getTime() - now.getTime();
|
||||
@@ -103,9 +109,23 @@ export const getTotalPoints = async (address: string): Promise<number> => {
|
||||
};
|
||||
|
||||
export const getWhiteListedDisclosureAddresses = async (): Promise<
|
||||
string[]
|
||||
WhitelistedContract[]
|
||||
> => {
|
||||
return [];
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${POINTS_API_BASE_URL}/whitelisted-addresses`,
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data.contracts || [];
|
||||
} catch (error) {
|
||||
console.error('Error fetching whitelisted addresses:', error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const hasUserAnIdentityDocumentRegistered =
|
||||
@@ -146,7 +166,6 @@ export const hasUserDoneThePointsDisclosure = async (): Promise<boolean> => {
|
||||
};
|
||||
|
||||
export const pointsSelfApp = async () => {
|
||||
const userAddress = (await getPointsAddress())?.toLowerCase();
|
||||
const endpoint = '0x829d183faaa675f8f80e8bb25fb1476cd4f7c1f0';
|
||||
const builder = new SelfAppBuilder({
|
||||
appName: '✨ Self Points',
|
||||
@@ -158,7 +177,6 @@ export const pointsSelfApp = async () => {
|
||||
disclosures: {},
|
||||
logoBase64:
|
||||
'https://storage.googleapis.com/self-logo-reverse/Self%20Logomark%20Reverse.png',
|
||||
selfDefinedData: userAddress,
|
||||
header: '',
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user