diff --git a/packages/mobile/app/(tabs)/assets.tsx b/packages/mobile/app/(tabs)/assets.tsx index e625cc7a97..21bcd7c07f 100644 --- a/packages/mobile/app/(tabs)/assets.tsx +++ b/packages/mobile/app/(tabs)/assets.tsx @@ -14,6 +14,7 @@ import { import { SafeAreaView } from "react-native-safe-area-context"; import { SvgUri } from "react-native-svg"; import { create } from "zustand"; +import { createJSONStorage, persist } from "zustand/middleware"; import { ChevronDownIcon } from "~/components/icons/chevron-down"; import { FilterIcon } from "~/components/icons/filter"; @@ -28,13 +29,16 @@ import { } from "~/components/ui/dropdown"; import { Text } from "~/components/ui/text"; import { Colors } from "~/constants/theme-colors"; +import { mmkvStorage } from "~/utils/mmkv"; import { getChangeColor } from "~/utils/price"; import { api, RouterOutputs } from "~/utils/trpc"; const itemSize = 70; const displayOptions = [ - { key: "price", title: "Price (24h)" }, + { key: "price-1h", title: "Price (1h)" }, + { key: "price-24h", title: "Price (24h)" }, + { key: "price-7d", title: "Price (7d)" }, { key: "volume", title: "Volume" }, { key: "market-cap", title: "Market Cap" }, { key: "favorite", title: "Favorite" }, @@ -45,11 +49,19 @@ type DisplayOptionStore = { setDisplayOption: (option: (typeof displayOptions)[number]["key"]) => void; }; -const useDisplayOptionStore = create((set) => ({ - displayOption: displayOptions[0].key, - setDisplayOption: (option: (typeof displayOptions)[number]["key"]) => - set({ displayOption: option }), -})); +const useDisplayOptionStore = create()( + persist( + (set) => ({ + displayOption: displayOptions[1].key, + setDisplayOption: (option: (typeof displayOptions)[number]["key"]) => + set({ displayOption: option }), + }), + { + name: "display-option", + storage: createJSONStorage(() => mmkvStorage), + } + ) +); export default function TabTwoScreen() { const [search, setSearch] = useState(""); @@ -204,7 +216,7 @@ const AssetItem = ({ - {displayOption === "price" && ( + {displayOption.startsWith("price") && ( <> {asset.currentPrice ? ( @@ -216,18 +228,50 @@ const AssetItem = ({ "" )} - - {asset.priceChange24h?.toString()} - + {displayOption === "price-24h" && ( + + {asset.priceChange24h?.toString()} + + )} + + {displayOption === "price-7d" && ( + + {asset.priceChange7d?.toString()} + + )} + + {displayOption === "price-1h" && ( + + {asset.priceChange1h?.toString()} + + )} )} diff --git a/packages/mobile/app/_layout.tsx b/packages/mobile/app/_layout.tsx index bfd2ee42fc..d9cd97cfbf 100644 --- a/packages/mobile/app/_layout.tsx +++ b/packages/mobile/app/_layout.tsx @@ -1,8 +1,7 @@ import { superjson } from "@osmosis-labs/server"; import { localLink } from "@osmosis-labs/trpc"; -import AsyncStorage from "@react-native-async-storage/async-storage"; import { ThemeProvider } from "@react-navigation/native"; -import { createAsyncStoragePersister } from "@tanstack/query-async-storage-persister"; +import { createSyncStoragePersister } from "@tanstack/query-sync-storage-persister"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { persistQueryClient } from "@tanstack/react-query-persist-client"; import { loggerLink } from "@trpc/client"; @@ -15,14 +14,12 @@ import { GestureHandlerRootView } from "react-native-gesture-handler"; import { DefaultTheme } from "~/constants/themes"; import { getMobileAssetListAndChains } from "~/utils/asset-lists"; +import { mmkvStorage } from "~/utils/mmkv"; import { api } from "~/utils/trpc"; import { appRouter } from "~/utils/trpc-routers/root-router"; -const localStoragePersister = createAsyncStoragePersister({ - storage: AsyncStorage, - serialize: (client) => superjson.stringify(client), - deserialize: (cachedString) => superjson.parse(cachedString), -}); +// eslint-disable-next-line @typescript-eslint/no-var-requires +global.Buffer = require("buffer").Buffer; const queryClient = new QueryClient({ defaultOptions: { @@ -32,6 +29,19 @@ const queryClient = new QueryClient({ }, }); +const localStoragePersister = createSyncStoragePersister({ + storage: mmkvStorage, + serialize: (client) => { + try { + return superjson.stringify(client); + } catch (error) { + console.error("Error serializing client", error); + return ""; + } + }, + deserialize: (cachedString) => superjson.parse(cachedString), +}); + persistQueryClient({ queryClient, persister: localStoragePersister, @@ -60,7 +70,6 @@ export default function RootLayout() { (opts.direction === "down" && opts.result instanceof Error), }), (runtime) => { - // initialize the different links for different targets (edge and node) const servers = { local: localLink({ router: appRouter, diff --git a/packages/mobile/app/asset/[id].tsx b/packages/mobile/app/asset/[id].tsx index 245e2d3143..fc3436bbae 100644 --- a/packages/mobile/app/asset/[id].tsx +++ b/packages/mobile/app/asset/[id].tsx @@ -9,15 +9,19 @@ import { TouchableOpacity, View, } from "react-native"; -import { GraphPoint, LineGraph } from "react-native-graph"; import { SafeAreaView } from "react-native-safe-area-context"; +import { + AssetChart, + useAssetChartSelectedPointStore, +} from "~/components/asset-chart"; import { ChevronLeftIcon } from "~/components/icons/chevron-left"; import { SubscriptDecimal } from "~/components/subscript-decimal"; +import { Button } from "~/components/ui/button"; import { Text } from "~/components/ui/text"; import { Colors } from "~/constants/theme-colors"; import { getChangeColor } from "~/utils/price"; -import { api } from "~/utils/trpc"; +import { api, RouterOutputs } from "~/utils/trpc"; const AssetRoute = () => { const { id, coinDenom, coinImageUrl } = useLocalSearchParams<{ @@ -60,72 +64,15 @@ const AssetRoute = () => { - - Trade - +