-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1231 onboarding numeraire selection2 (#28)
* use numeraire from local storage * save multiple numeraires in local storage * added NumerairesSlice * add ChangeNumeraires service message * numeraires persist * add icons * remove onboardNumeraires * delete prices when numeraire is changed * refactor & fix numeraires update bug * add idb tests * fix chain-id * Update apps/extension/src/shared/components/numeraires-form.tsx Co-authored-by: Jesse Pinho <[email protected]> * Update apps/extension/src/shared/components/numeraires-form.tsx Co-authored-by: Jesse Pinho <[email protected]> * Update apps/extension/src/routes/popup/settings/settings.tsx Co-authored-by: Jesse Pinho <[email protected]> * Update apps/extension/src/routes/page/onboarding/set-numeraire.tsx Co-authored-by: Jesse Pinho <[email protected]> * Update apps/extension/src/routes/page/onboarding/set-numeraire.tsx Co-authored-by: Jesse Pinho <[email protected]> * fix lint * add docs for clearSwapBasedPrices * add chainId comment --------- Co-authored-by: Jesse Pinho <[email protected]>
- Loading branch information
1 parent
236e650
commit 27d8552
Showing
30 changed files
with
343 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
export const NumerairesGradientIcon = () => ( | ||
<svg width='80' height='80' viewBox='0 0 80 80' fill='none' xmlns='http://www.w3.org/2000/svg'> | ||
<defs> | ||
<linearGradient | ||
id='customGradient' | ||
x1='0' | ||
y1='0' | ||
x2='80' | ||
y2='80' | ||
gradientUnits='userSpaceOnUse' | ||
> | ||
<stop stopColor='#8BE4D9' stopOpacity='0.7' /> | ||
<stop offset='0.522217' stopColor='#C8B880' stopOpacity='0.7' /> | ||
<stop offset='1' stopColor='#FF902F' stopOpacity='0.6' /> | ||
</linearGradient> | ||
</defs> | ||
<path | ||
d='M61.3333 6C61.5979 6 61.8333 6.22386 61.8333 6.5V73.5C61.8333 73.7761 61.5979 74 61.3333 74C61.0688 74 60.8333 73.7761 60.8333 73.5V6.5C60.8333 6.22386 61.0688 6 61.3333 6ZM50.3333 18C50.5979 18 50.8333 18.2239 50.8333 18.5V73.5C50.8333 73.7761 50.5979 74 50.3333 74C50.0688 74 49.8333 73.7761 49.8333 73.5V18.5C49.8333 18.2239 50.0688 18 50.3333 18ZM71.3333 18C71.5979 18 71.8333 18.2239 71.8333 18.5V73.5C71.8333 73.7761 71.5979 74 71.3333 74C71.0688 74 70.8333 73.7761 70.8333 73.5V18.5C70.8333 18.2239 71.0688 18 71.3333 18ZM27.3333 21C27.5979 21 27.8333 21.2239 27.8333 21.5V73.5C27.8333 73.7761 27.5979 74 27.3333 74C27.0688 74 26.8333 73.7761 26.8333 73.5V21.5C26.8333 21.2239 27.0688 21 27.3333 21ZM7.33333 26C7.59788 26 7.83333 26.2239 7.83333 26.5V73.5C7.83333 73.7761 7.59788 74 7.33333 74C7.06878 74 6.83333 73.7761 6.83333 73.5V26.5C6.83333 26.2239 7.06878 26 7.33333 26ZM36.3333 26C36.5979 26 36.8333 26.2239 36.8333 26.5V73.5C36.8333 73.7761 36.5979 74 36.3333 74C36.0688 74 35.8333 73.7761 35.8333 73.5V26.5C35.8333 26.2239 36.0688 26 36.3333 26ZM16.3333 36C16.5979 36 16.8333 36.2239 16.8333 36.5V73.5C16.8333 73.7761 16.5979 74 16.3333 74C16.0688 74 15.8333 73.7761 15.8333 73.5V36.5C15.8333 36.2239 16.0688 36 16.3333 36Z' | ||
fill='url(#customGradient)' | ||
fillRule='evenodd' | ||
clipRule='evenodd' | ||
/> | ||
</svg> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export enum ServicesMessage { | ||
ClearCache = 'ClearCache', | ||
ChangeNumeraires = 'ChangeNumeraires', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
apps/extension/src/routes/page/onboarding/set-numeraire.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { Card, CardDescription, CardHeader, CardTitle } from '@penumbra-zone/ui/components/ui/card'; | ||
import { FadeTransition } from '@penumbra-zone/ui/components/ui/fade-transition'; | ||
import { usePageNav } from '../../../utils/navigate'; | ||
import { PagePath } from '../paths'; | ||
import { NumeraireForm } from '../../../shared/components/numeraires-form'; | ||
|
||
export const SetNumerairesPage = () => { | ||
const navigate = usePageNav(); | ||
|
||
const onSuccess = (): void => { | ||
navigate(PagePath.ONBOARDING_SUCCESS); | ||
}; | ||
|
||
return ( | ||
<FadeTransition> | ||
<Card className='w-[400px]' gradient> | ||
<CardHeader> | ||
<CardTitle>In which token denomination would you prefer to price assets?</CardTitle> | ||
<CardDescription> | ||
Prax does not use third-party price providers for privacy reasons. Instead, Prax indexes | ||
asset prices locally by selected denomination. | ||
</CardDescription> | ||
</CardHeader> | ||
<div className='mt-6'> | ||
<NumeraireForm isOnboarding onSuccess={onSuccess} /> | ||
</div> | ||
</Card> | ||
</FadeTransition> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
apps/extension/src/routes/popup/settings/settings-numeraires.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { SettingsScreen } from './settings-screen'; | ||
import { NumerairesGradientIcon } from '../../../icons/numeraires-gradient'; | ||
import { usePopupNav } from '../../../utils/navigate'; | ||
import { PopupPath } from '../paths'; | ||
import { NumeraireForm } from '../../../shared/components/numeraires-form'; | ||
|
||
export const SettingsNumeraires = () => { | ||
const navigate = usePopupNav(); | ||
|
||
const onSuccess = () => { | ||
navigate(PopupPath.INDEX); | ||
}; | ||
return ( | ||
<SettingsScreen title='Price denominations' IconComponent={NumerairesGradientIcon}> | ||
<NumeraireForm onSuccess={onSuccess} /> | ||
</SettingsScreen> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { ChainRegistryClient } from '@penumbra-labs/registry'; | ||
import { AllSlices, useStore } from '../../state'; | ||
import { useChainIdQuery } from '../../hooks/chain-id'; | ||
import { useMemo, useState } from 'react'; | ||
import { ServicesMessage } from '../../message/services'; | ||
import { SelectList } from '@penumbra-zone/ui/components/ui/select-list'; | ||
import { bech32mAssetId } from '@penumbra-zone/bech32m/passet'; | ||
import { getAssetId } from '@penumbra-zone/getters/metadata'; | ||
import { Button } from '@penumbra-zone/ui/components/ui/button'; | ||
import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; | ||
|
||
const getNumeraireFromRegistry = (chainId?: string): Metadata[] => { | ||
if (!chainId) return []; | ||
const registryClient = new ChainRegistryClient(); | ||
const registry = registryClient.get(chainId); | ||
return registry.numeraires.map(n => registry.getMetadata(n)); | ||
}; | ||
|
||
const useNumerairesSelector = (state: AllSlices) => { | ||
return { | ||
selectedNumeraires: state.numeraires.selectedNumeraires, | ||
selectNumeraire: state.numeraires.selectNumeraire, | ||
saveNumeraires: state.numeraires.saveNumeraires, | ||
networkChainId: state.network.chainId, | ||
}; | ||
}; | ||
|
||
export const NumeraireForm = ({ | ||
isOnboarding, | ||
onSuccess, | ||
}: { | ||
isOnboarding?: boolean; | ||
onSuccess: () => void | Promise<void>; | ||
}) => { | ||
const { chainId } = useChainIdQuery(); | ||
const { selectedNumeraires, selectNumeraire, saveNumeraires, networkChainId } = | ||
useStore(useNumerairesSelector); | ||
|
||
// 'chainId' from 'useChainIdQuery' is not available during onboarding, | ||
// this forces you to use two sources to guarantee 'chainId' for both settings and onboarding | ||
const numeraires = useMemo(() => getNumeraireFromRegistry(chainId ?? networkChainId), [chainId]); | ||
|
||
const [loading, setLoading] = useState(false); | ||
|
||
const handleSubmit = () => { | ||
setLoading(true); | ||
void (async function () { | ||
await saveNumeraires(); | ||
await chrome.runtime.sendMessage(ServicesMessage.ChangeNumeraires); | ||
await onSuccess(); | ||
})(); | ||
}; | ||
|
||
return ( | ||
<div className='flex flex-col gap-2'> | ||
<form className='flex flex-col gap-4' onSubmit={handleSubmit}> | ||
<SelectList> | ||
{numeraires.map(metadata => { | ||
// Image default is "" and thus cannot do nullish-coalescing | ||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing | ||
const icon = metadata.images[0]?.png || metadata.images[0]?.svg; | ||
return ( | ||
<SelectList.Option | ||
key={bech32mAssetId(getAssetId(metadata))} | ||
value={getAssetId(metadata).toJsonString()} | ||
label={metadata.symbol} | ||
isSelected={selectedNumeraires.includes(getAssetId(metadata).toJsonString())} | ||
onSelect={() => selectNumeraire(getAssetId(metadata).toJsonString())} | ||
image={ | ||
!!icon && ( | ||
<img | ||
src={icon} | ||
className='size-full object-contain' | ||
alt='rpc endpoint brand image' | ||
/> | ||
) | ||
} | ||
/> | ||
); | ||
})} | ||
|
||
<Button | ||
className='my-5' | ||
key='save-button' | ||
variant='gradient' | ||
type='submit' | ||
disabled={loading} | ||
onClick={handleSubmit} | ||
> | ||
{isOnboarding ? 'Next' : loading ? 'Saving...' : 'Save'} | ||
</Button> | ||
</SelectList> | ||
</form> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { LocalStorageState } from '../storage/types'; | ||
import { AllSlices, SliceCreator } from '.'; | ||
import { ExtensionStorage } from '../storage/base'; | ||
import { Stringified } from '@penumbra-zone/types/jsonified'; | ||
import { AssetId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; | ||
|
||
export interface NumerairesSlice { | ||
selectedNumeraires: Stringified<AssetId>[]; | ||
selectNumeraire: (numeraire: Stringified<AssetId>) => void; | ||
saveNumeraires: () => Promise<void>; | ||
} | ||
|
||
export const createNumerairesSlice = | ||
(local: ExtensionStorage<LocalStorageState>): SliceCreator<NumerairesSlice> => | ||
(set, get) => { | ||
return { | ||
selectedNumeraires: [], | ||
selectNumeraire: (numeraire: Stringified<AssetId>) => { | ||
set(state => { | ||
const index = state.numeraires.selectedNumeraires.indexOf(numeraire); | ||
if (index > -1) { | ||
state.numeraires.selectedNumeraires.splice(index, 1); | ||
} else { | ||
state.numeraires.selectedNumeraires.push(numeraire); | ||
} | ||
}); | ||
}, | ||
saveNumeraires: async () => { | ||
await local.set('numeraires', get().numeraires.selectedNumeraires); | ||
}, | ||
}; | ||
}; | ||
|
||
export const numerairesSelector = (state: AllSlices) => state.numeraires; |
Oops, something went wrong.