diff --git a/src/hooks/useWebData.ts b/src/hooks/useWebData.ts index f00bbd06d93..daa5a80b5ad 100644 --- a/src/hooks/useWebData.ts +++ b/src/hooks/useWebData.ts @@ -85,6 +85,10 @@ export default function useWebData() { const getWebProfile = useCallback(async (address: string) => { const response = address && (await getPreference('profile', address)); + if (!response) { + return null; + } + return response?.profile; }, []); @@ -92,14 +96,13 @@ export default function useWebData() { async (assetIds: any) => { if (!webDataEnabled) return; const response = await getPreference('showcase', accountAddress); - // If the showcase is populated, just updated it - if (response?.ids?.length > 0) { - setPreference(PreferenceActionType.update, 'showcase', accountAddress, assetIds); - } else { - // Initialize showcase and profiles + if (!response || !response.showcase.ids.length) { await initWebData(assetIds); logger.log('showcase initialized!'); + return; } + + setPreference(PreferenceActionType.update, 'showcase', accountAddress, assetIds); }, [accountAddress, initWebData, webDataEnabled] ); @@ -107,14 +110,13 @@ export default function useWebData() { const updateWebHidden = useCallback( async (assetIds: any) => { const response = await getPreference('hidden', accountAddress); - // If the showcase is populated, just updated it - if (response?.ids?.length > 0) { - setPreference(PreferenceActionType.update, 'hidden', accountAddress, assetIds); - } else { + if (!response || !response.hidden.ids.length) { await setPreference(PreferenceActionType.init, 'hidden', accountAddress, assetIds); - logger.log('hidden initialized!'); + return; } + + setPreference(PreferenceActionType.update, 'hidden', accountAddress, assetIds); }, [accountAddress] ); @@ -126,14 +128,13 @@ export default function useWebData() { // If webdata is enabled if (webDataEnabled) { const response = await getPreference('showcase', accountAddress); - // If the showcase is populated, nothing to do - if (response?.ids?.length > 0) { - logger.log('showcase already initialized. skipping'); - } else { - // Initialize + if (!response || !response.showcase.ids.length) { await initWebData(showcaseTokens); logger.log('showcase initialized!'); + return; } + + logger.log('showcase already initialized. skipping'); } } } catch (e) { diff --git a/src/model/preferences.ts b/src/model/preferences.ts index 92311f9e053..226424912e2 100644 --- a/src/model/preferences.ts +++ b/src/model/preferences.ts @@ -2,6 +2,16 @@ import { RainbowFetchClient } from '../rainbow-fetch'; import { EthereumAddress } from '@/entities'; import { getSignatureForSigningWalletAndCreateSignatureIfNeeded, signWithSigningWallet } from '@/helpers/signingWallet'; import { logger } from '@/logger'; +import { Address } from 'viem'; + +export const PREFS_ENDPOINT = 'https://api.rainbow.me'; +const preferencesAPI = new RainbowFetchClient({ + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + timeout: 30000, // 30 secs +}); export enum PreferenceActionType { update = 'update', @@ -10,27 +20,60 @@ export enum PreferenceActionType { init = 'init', } -export interface PreferencesResponse { - success: boolean; - reason: string; - data?: Record | undefined; +export enum PreferenceKeys { + showcase = 'showcase', + profile = 'profile', } -export const PREFS_ENDPOINT = 'https://api.rainbow.me'; +type TokenContract = Address; +type TokenId = string; -const preferencesAPI = new RainbowFetchClient({ - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - }, - timeout: 30000, // 30 secs -}); +type TokenContractWithId = `${TokenContract}_${TokenId}`; + +type HiddenPreferencesData = { + hidden: { + ids: []; + }; +}; + +type ShowcasePreferencesData = { + showcase: { + ids: TokenContractWithId[]; + }; +}; + +type Profile = { + accountColor: string; + accountSymbol: string | null; +}; + +type ProfilePreferencesData = { + profile: Profile; +}; + +type PreferencesDataMap = { + showcase: ShowcasePreferencesData; + profile: ProfilePreferencesData; + hidden: HiddenPreferencesData; +}; + +type PayloadMap = { + showcase: string[]; + profile: Profile; + hidden: string[]; +}; -export async function setPreference( +type PreferencesResponse = { + success: boolean; + data?: T extends keyof PreferencesDataMap ? PreferencesDataMap[T] : never; + reason?: string; +}; + +export async function setPreference( action: PreferenceActionType, - key: string, + key: K, address: EthereumAddress, - value?: any | undefined + value?: PayloadMap[K] ): Promise { try { const signature = await getSignatureForSigningWalletAndCreateSignatureIfNeeded(address); @@ -46,17 +89,21 @@ export async function setPreference( const message = JSON.stringify(objToSign); const signature2 = await signWithSigningWallet(message); logger.debug('☁️ SENDING ', { message }); - const response = await preferencesAPI.post(`${PREFS_ENDPOINT}/${key}`, { + const { data } = await preferencesAPI.post>(`${PREFS_ENDPOINT}/${key}`, { message, signature, signature2, }); - const responseData: PreferencesResponse = response.data as PreferencesResponse; logger.debug('☁️ RESPONSE', { - reason: responseData?.reason, - success: responseData?.success, + reason: data?.reason, + success: data?.success, }); - return responseData?.success; + + if (!data.data) { + throw new Error('Failed to set preference'); + } + + return data?.success; } catch (e) { logger.warn(`Preferences API failed to set preference`, { preferenceKey: key, @@ -65,17 +112,24 @@ export async function setPreference( } } -export async function getPreference(key: string, address: EthereumAddress): Promise { +export async function getPreference( + key: K, + address: EthereumAddress +): Promise { try { - const response = await preferencesAPI.get(`${PREFS_ENDPOINT}/${key}`, { + const { data } = await preferencesAPI.get>(`${PREFS_ENDPOINT}/${key}`, { params: { address }, }); - const responseData: PreferencesResponse = response.data as PreferencesResponse; logger.debug('☁️ RESPONSE', { - reason: responseData?.reason, - success: responseData?.success, + reason: data?.reason, + success: data?.success, }); - return responseData?.data || null; + + if (!data.data) { + return null; + } + + return data.data; } catch (e) { logger.warn(`Preferences API failed to get preference`, { preferenceKey: key,