Skip to content

Commit

Permalink
improve type checking on web preferences (#5607)
Browse files Browse the repository at this point in the history
  • Loading branch information
walmat authored Apr 9, 2024
1 parent 1f4bfa0 commit 81438be
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 41 deletions.
31 changes: 16 additions & 15 deletions src/hooks/useWebData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,36 +85,38 @@ export default function useWebData() {

const getWebProfile = useCallback(async (address: string) => {
const response = address && (await getPreference('profile', address));
if (!response) {
return null;
}

return response?.profile;
}, []);

const updateWebShowcase = useCallback(
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]
);

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]
);
Expand All @@ -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) {
Expand Down
106 changes: 80 additions & 26 deletions src/model/preferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -10,27 +20,60 @@ export enum PreferenceActionType {
init = 'init',
}

export interface PreferencesResponse {
success: boolean;
reason: string;
data?: Record<string, unknown> | 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<T extends keyof PreferencesDataMap> = {
success: boolean;
data?: T extends keyof PreferencesDataMap ? PreferencesDataMap[T] : never;
reason?: string;
};

export async function setPreference<K extends keyof PreferencesDataMap>(
action: PreferenceActionType,
key: string,
key: K,
address: EthereumAddress,
value?: any | undefined
value?: PayloadMap[K]
): Promise<boolean> {
try {
const signature = await getSignatureForSigningWalletAndCreateSignatureIfNeeded(address);
Expand All @@ -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<PreferencesResponse<K>>(`${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,
Expand All @@ -65,17 +112,24 @@ export async function setPreference(
}
}

export async function getPreference(key: string, address: EthereumAddress): Promise<any | null> {
export async function getPreference<K extends keyof PreferencesDataMap>(
key: K,
address: EthereumAddress
): Promise<PreferencesDataMap[K] | null> {
try {
const response = await preferencesAPI.get(`${PREFS_ENDPOINT}/${key}`, {
const { data } = await preferencesAPI.get<PreferencesResponse<K>>(`${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,
Expand Down

0 comments on commit 81438be

Please sign in to comment.