Skip to content

Commit

Permalink
feat: choose app currency
Browse files Browse the repository at this point in the history
  • Loading branch information
vojtechsimetka committed Oct 28, 2023
1 parent 7b7ebdb commit 18f006c
Show file tree
Hide file tree
Showing 18 changed files with 170 additions and 38 deletions.
2 changes: 2 additions & 0 deletions src/lib/adapters/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export function getFromLocalStorage<T extends JSONdecoded>(
throw new Error(`Error getting from local storage: invalid data. ${parseData.error.issues}`)
}

console.log('Retrieved', key, parseData.data)

return parseData.data
}

Expand Down
5 changes: 3 additions & 2 deletions src/lib/adapters/waku/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ import type {
import { walletStore } from '$lib/stores/wallet'
import { SafeWaku } from './safe-waku'
import type { TokenAmount } from '$lib/objects/schemas'
import { DEFAULT_FIAT_SYMBOL, exchangeStore } from '$lib/stores/exchangeRates'
import { exchangeStore } from '$lib/stores/exchangeRates'
import { preferences } from '$lib/stores/preferences'
import { balanceStore } from '$lib/stores/balances'
import type { ContentTopic } from './waku'
import { installedObjectStore } from '$lib/stores/installed-objects'
Expand Down Expand Up @@ -167,7 +168,7 @@ async function executeOnDataMessage(
users: users,
profile: myProfile,
exchangeRates: get(exchangeStore).exchange,
fiatSymbol: DEFAULT_FIAT_SYMBOL,
fiatSymbol: get(preferences).fiatSymbol,
tokens: get(balanceStore).balances,
}
await descriptor.onMessage(dataMessage, args)
Expand Down
14 changes: 14 additions & 0 deletions src/lib/components/icons/settings-adjust.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script lang="ts">
export let size = 20
</script>

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width={size} height={size}>
<path
d="M30,8h-4.1c-0.5-2.3-2.5-4-4.9-4s-4.4,1.7-4.9,4H2v2h14.1c0.5,2.3,2.5,4,4.9,4s4.4-1.7,4.9-4H30V8z M21,12c-1.7,0-3-1.3-3-3
s1.3-3,3-3s3,1.3,3,3S22.7,12,21,12z"
/>
<path
d="M2,24h4.1c0.5,2.3,2.5,4,4.9,4s4.4-1.7,4.9-4H30v-2H15.9c-0.5-2.3-2.5-4-4.9-4s-4.4,1.7-4.9,4H2V24z M11,20c1.7,0,3,1.3,3,3
s-1.3,3-3,3s-3-1.3-3-3S9.3,20,11,20z"
/>
</svg>
7 changes: 4 additions & 3 deletions src/lib/objects/chat.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
import { goto } from '$app/navigation'
import routes from '$lib/routes'
import { chats } from '$lib/stores/chat'
import { DEFAULT_FIAT_SYMBOL, exchangeStore } from '$lib/stores/exchangeRates'
import { defaultBlockchainNetwork } from '$lib/adapters/transaction'
import { exchangeStore } from '$lib/stores/exchangeRates'
import { errorStore } from '$lib/stores/error'
import { preferences } from '$lib/stores/preferences'
import { defaultBlockchainNetwork } from '$lib/adapters/transaction'
export let message: DataMessage
export let users: User[]
Expand Down Expand Up @@ -62,7 +63,7 @@
users,
tokens,
exchangeRates: $exchangeStore.exchange,
fiatSymbol: DEFAULT_FIAT_SYMBOL,
fiatSymbol: $preferences.fiatSymbol,
store,
viewParams: [],
chatName,
Expand Down
5 changes: 3 additions & 2 deletions src/lib/objects/external/iframe.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
import { onDestroy } from 'svelte'
import adapters from '$lib/adapters'
import { walletStore } from '$lib/stores/wallet'
import { DEFAULT_FIAT_SYMBOL, exchangeStore } from '$lib/stores/exchangeRates'
import { exchangeStore } from '$lib/stores/exchangeRates'
import { preferences } from '$lib/stores/preferences'
import { defaultBlockchainNetwork } from '$lib/adapters/transaction'
// TODO: This needs escaping for the CSP
Expand Down Expand Up @@ -110,7 +111,7 @@
users,
tokens,
exchangeRates: $exchangeStore.exchange,
fiatSymbol: DEFAULT_FIAT_SYMBOL,
fiatSymbol: $preferences.fiatSymbol,
},
context: {
view,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/objects/payggy/views/choose-amount.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
export let token: TokenAmount
export let tokens: TokenAmount[]
export let fiatRates: Map<string, ExchangeRateRecord>
export let fiatSymbol: string | undefined
export let fiatSymbol: string
export let onViewChange: (view: string) => void
export let exitObject: () => void
Expand Down
2 changes: 1 addition & 1 deletion src/lib/objects/payggy/views/confirm-send.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
export let amount: string
export let token: TokenAmount
export let fiatRates: Map<string, ExchangeRateRecord>
export let fiatSymbol: string | undefined
export let fiatSymbol: string
export let estimateTransaction: (to: string, token: TokenAmount) => Promise<TokenAmount>
export let sendTransaction: (to: string, token: TokenAmount, fee: TokenAmount) => Promise<string>
Expand Down
2 changes: 1 addition & 1 deletion src/lib/objects/payggy/views/details.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
export let profile: User
export let status: string
export let fiatRates: Map<string, ExchangeRateRecord>
export let fiatSymbol: string | undefined
export let fiatSymbol: string
export let exitObject: () => void
$: sender = users.find((u) => u.address === transaction.from)
Expand Down
2 changes: 1 addition & 1 deletion src/lib/objects/split/views/settle-now.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
export let tokens: TokenAmount[]
export let token: Token
export let fiatRates: Map<string, ExchangeRateRecord>
export let fiatSymbol: string | undefined
export let fiatSymbol: string
export let getContract: GetContract
export let exitObject: () => void
Expand Down
5 changes: 3 additions & 2 deletions src/lib/objects/ui.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
import Loading from '$lib/components/loading.svelte'
import type { HDNodeWallet } from 'ethers/lib.commonjs'
import type { TokenAmount } from './schemas'
import { DEFAULT_FIAT_SYMBOL, exchangeStore } from '$lib/stores/exchangeRates'
import { exchangeStore } from '$lib/stores/exchangeRates'
import { defaultBlockchainNetwork } from '$lib/adapters/transaction'
import { errorStore } from '$lib/stores/error'
import { preferences } from '$lib/stores/preferences'
export let objectId: string
export let instanceId: string
Expand Down Expand Up @@ -84,7 +85,7 @@
view,
viewParams,
exchangeRates: $exchangeStore.exchange,
fiatSymbol: DEFAULT_FIAT_SYMBOL,
fiatSymbol: $preferences.fiatSymbol,
...wakuObjectAdapter,
}
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default {
IDENTITY_ACCOUNT: '/identity/account',
IDENTITY_BACKUP: '/identity/backup',
IDENTITY_CHAT: '/identity/chat',
IDENTITY_PREFERENCES: '/identity/preferences',
CHAT: (id: string) => `/chat/${id}`,
INVITE: (address: string) => `/invite/${address}`,
OBJECTS: (id: string) => `/chat/${id}/object/new`,
Expand Down
11 changes: 4 additions & 7 deletions src/lib/stores/exchangeRates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@ import { writable, get } from 'svelte/store'
import type { Writable } from 'svelte/store'
import { z } from 'zod'
import { defaultBlockchainNetwork } from '$lib/adapters/transaction'
import { fiatSymbolList } from './preferences'

function createSchema(tokens: string[]) {
function createSchema(tokens: readonly string[]) {
const schemas: Record<string, z.ZodNumber> = {}
for (const token of tokens) {
schemas[token] = z.number()
}
return z.object(schemas)
}

// TODO: with centralised endpoint, we can add more fiat currencies
const fiatList = ['DAI', 'EUR', 'USD', 'CZK']

const resSchema = createSchema(fiatList)
const resSchema = createSchema(fiatSymbolList)
type ExchangeRates = z.infer<typeof resSchema>

export interface ExchangeRateRecord {
Expand All @@ -34,7 +32,7 @@ interface BalanceRateStore extends Writable<ExchangeRateState> {
}

async function fetchTokenPrice(symbol: string): Promise<ExchangeRates> {
const endpoint = `https://min-api.cryptocompare.com/data/price?fsym=${symbol}&tsyms=${fiatList.join(
const endpoint = `https://min-api.cryptocompare.com/data/price?fsym=${symbol}&tsyms=${fiatSymbolList.join(
',',
)}&extraParams=0f8e116726ca17f20d95cd93fb85c7740c3bdb86719a58164ca28ed10df3320c`
const response = await fetch(endpoint)
Expand Down Expand Up @@ -108,4 +106,3 @@ function createExchangeStore(): BalanceRateStore {
}

export const exchangeStore = createExchangeStore()
export const DEFAULT_FIAT_SYMBOL = fiatList[1] // TODO: we could set this in user preferences as originally designed
35 changes: 35 additions & 0 deletions src/lib/stores/preferences.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { getFromLocalStorage, saveToLocalStorage } from '$lib/adapters/utils'
import { writable, type Writable } from 'svelte/store'
import { z } from 'zod'

export const fiatSymbolList = ['DAI', 'EUR', 'USD', 'CZK'] as const
const fiatSymbolSchema = z.enum(fiatSymbolList)
export type FiatSymbol = z.infer<typeof fiatSymbolSchema>

interface Preferences {
fiatSymbol: FiatSymbol
}

interface PreferenceStore extends Writable<Preferences> {
setFiatSymbol: (newFiatSymbol: FiatSymbol) => void
}

function createPreferenceStore(): PreferenceStore {
let fiatSymbol: FiatSymbol = 'DAI'
try {
fiatSymbol = getFromLocalStorage<FiatSymbol>('fiat', fiatSymbolSchema) ?? fiatSymbol
} catch (error) {
// this is fine
}
const store = writable<Preferences>({ fiatSymbol })

return {
...store,
setFiatSymbol: (newFiatSymbol: FiatSymbol) => {
saveToLocalStorage('fiat', newFiatSymbol)
store.update((theme) => ({ ...theme, fiatSymbol: newFiatSymbol }))
},
}
}

export const preferences = createPreferenceStore()
44 changes: 30 additions & 14 deletions src/lib/utils/fiat.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,57 @@
import type { ExchangeRateRecord } from '$lib/stores/exchangeRates'
import { isValidNumber } from '$lib/utils'

interface FiatAmount {
symbol?: string
amount?: number
symbol: string
amount: number
error?: Error
refreshing: boolean
}

function calculateFiatAmount(
fiatRates: Map<string, ExchangeRateRecord>,
fiatSymbol?: string,
tokenAmount?: string,
tokenSymbol?: string,
fiatSymbol: string,
tokenAmount: number,
tokenSymbol: string,
): FiatAmount {
if (!fiatSymbol || !tokenAmount || !tokenSymbol) return { symbol: fiatSymbol, refreshing: false }
const exchangeRate = fiatRates.get(tokenSymbol)
const rate = exchangeRate?.rates[fiatSymbol]
let amount: number | undefined = undefined

if (rate !== undefined) amount = Number(tokenAmount) * rate
if (rate === undefined)
return {
symbol: fiatSymbol,
amount: 0,
refreshing: Boolean(exchangeRate?.refreshing),
error: new Error(`No exchange rate for ${tokenSymbol} to ${fiatSymbol}`),
}

return {
symbol: fiatSymbol,
amount,
amount: tokenAmount * rate,
refreshing: Boolean(exchangeRate?.refreshing),
error: exchangeRate?.error,
}
}

export function getFiatAmountText(
fiatRates: Map<string, ExchangeRateRecord>,
fiatSymbol?: string,
tokenAmount?: string,
tokenSymbol?: string,
fiatSymbol: string,
tokenAmount: string,
tokenSymbol: string,
): string {
const fiatAmount = calculateFiatAmount(fiatRates, fiatSymbol, tokenAmount, tokenSymbol)
if (tokenAmount === '') {
const fiatAmount = calculateFiatAmount(fiatRates, fiatSymbol, 1, tokenSymbol)
if (fiatAmount.amount !== undefined)
return `1 ${tokenSymbol}${fiatAmount.amount.toFixed(2)} ${fiatSymbol}`
if (fiatAmount.refreshing) return `Getting exchange rate`
return `Failed to load ${fiatSymbol} amount`
}

if (!isValidNumber(tokenAmount)) return 'Please enter a valid number'
const amount = Number(tokenAmount)
if (isNaN(amount)) return 'Please enter a valid number'
const fiatAmount = calculateFiatAmount(fiatRates, fiatSymbol, amount, tokenSymbol)
if (fiatAmount.amount !== undefined) return `≈${fiatAmount.amount.toFixed(2)} ${fiatSymbol}`
else if (fiatAmount.refreshing) return `Getting exchange rate`
if (fiatAmount.refreshing) return `Getting exchange rate`
return `Failed to load ${fiatSymbol} amount`
}
6 changes: 6 additions & 0 deletions src/lib/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@
export function genRandomHex(size: number) {
return [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join('')
}

const regex = /^[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?$/

export function isValidNumber(input: string): boolean {
return regex.test(input)
}
15 changes: 14 additions & 1 deletion src/routes/identity/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import Renew from '$lib/components/icons/renew.svelte'
import Wallet from '$lib/components/icons/wallet.svelte'
import SettingsView from '$lib/components/icons/settings-view.svelte'
import SettingsAdjust from '$lib/components/icons/settings-adjust.svelte'
import Logout from '$lib/components/icons/logout.svelte'
import DocumentSigned from '$lib/components/icons/document-signed.svelte'
Expand Down Expand Up @@ -132,7 +133,7 @@
</div>
</Container>
</ButtonBlock>
<ButtonBlock borderTop borderBottom on:click={() => goto(routes.IDENTITY_CHAT)}>
<ButtonBlock borderTop on:click={() => goto(routes.IDENTITY_CHAT)}>
<Container direction="row" justify="space-between" align="center" alignItems="center">
<div class="icon">
<SettingsView size={20} /> Chat appearance
Expand All @@ -144,6 +145,18 @@
</div>
</Container>
</ButtonBlock>
<ButtonBlock borderTop borderBottom on:click={() => goto(routes.IDENTITY_PREFERENCES)}>
<Container direction="row" justify="space-between" align="center" alignItems="center">
<div class="icon">
<SettingsAdjust size={20} /> Preferences
</div>
<div>
<Button variant="icon">
<ChevronRight />
</Button>
</div>
</Container>
</ButtonBlock>
<Container align="center" gap={12} padX={24} padY={24}>
<p>
If you disconnect or need to recover access to your identity you will need your recovery
Expand Down
9 changes: 6 additions & 3 deletions src/routes/identity/account/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
import { fetchBalances } from '$lib/adapters/balance'
import AuthenticatedOnly from '$lib/components/authenticated-only.svelte'
import Layout from '$lib/components/layout.svelte'
import { exchangeStore, DEFAULT_FIAT_SYMBOL } from '$lib/stores/exchangeRates'
import { exchangeStore } from '$lib/stores/exchangeRates'
import { preferences } from '$lib/stores/preferences'
import Loading from '$lib/components/loading.svelte'
let copied = false
Expand Down Expand Up @@ -85,8 +86,10 @@
amount={balance.amount}
decimals={balance.decimals}
image={balance.image}
fiatSymbol={DEFAULT_FIAT_SYMBOL}
fiatExchange={$exchangeStore.exchange.get(balance.symbol)?.rates[DEFAULT_FIAT_SYMBOL]}
fiatSymbol={$preferences.fiatSymbol}
fiatExchange={$exchangeStore.exchange.get(balance.symbol)?.rates[
$preferences.fiatSymbol
]}
/>
{/each}
</div>
Expand Down
Loading

0 comments on commit 18f006c

Please sign in to comment.