Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: simplify wallet renaming flow #233

Merged
merged 1 commit into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/Icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
PopiconsClipboardTextSolid as PasteIcon,
PopiconsReloadLine as RefreshIcon,
PopiconsReloadSolid as ResetIcon,
PopiconsSettingsMinimalLine as SettingsIcon,
PopiconsSettingsMinimalSolid as SettingsIcon,
PopiconsShareSolid as ShareIcon,
PopiconsLogoutSolid as SignOutIcon,
PopiconsLoopSolid as SwapIcon,
Expand Down
37 changes: 21 additions & 16 deletions lib/state/appStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ interface AppState {
setUnlocked: (unlocked: boolean) => void;
setTheme: (theme: Theme) => void;
setOnboarded: (isOnboarded: boolean) => void;
getNWCClient: (walletId: number) => NWCClient | undefined;
setNWCClient: (nwcClient: NWCClient | undefined) => void;
updateCurrentWallet(wallet: Partial<Wallet>): void;
removeCurrentWallet(): void;
updateWallet(wallet: Partial<Wallet>, walletId?: number): void;
removeWallet(walletId?: number): void;
setFiatCurrency(fiatCurrency: string): void;
setSelectedWalletId(walletId: number): void;
setSecurityEnabled(securityEnabled: boolean): void;
Expand Down Expand Up @@ -89,25 +90,22 @@ function loadAddressBookEntries(): AddressBookEntry[] {
}

export const useAppStore = create<AppState>()((set, get) => {
const updateCurrentWallet = (walletUpdate: Partial<Wallet>) => {
const selectedWalletId = get().selectedWalletId;
const updateWallet = (walletUpdate: Partial<Wallet>, walletId?: number) => {
walletId = walletId ?? get().selectedWalletId;
const wallets = [...get().wallets];

const wallet: Wallet = {
...(wallets[selectedWalletId] || {}),
...(wallets[walletId] || {}),
...walletUpdate,
};
secureStorage.setItem(
getWalletKey(selectedWalletId),
JSON.stringify(wallet),
);
wallets[selectedWalletId] = wallet;
secureStorage.setItem(getWalletKey(walletId), JSON.stringify(wallet));
wallets[walletId] = wallet;
set({
wallets,
});
};

const removeCurrentWallet = () => {
const removeWallet = (walletId?: number) => {
const wallets = [...get().wallets];
if (wallets.length <= 1) {
// set to initial wallet status
Expand All @@ -123,9 +121,10 @@ export const useAppStore = create<AppState>()((set, get) => {
return;
}
const selectedWalletId = get().selectedWalletId;
walletId = walletId ?? selectedWalletId;

// move existing wallets down one
for (let i = selectedWalletId; i < wallets.length - 1; i++) {
for (let i = walletId; i < wallets.length - 1; i++) {
const nextWallet = secureStorage.getItem(getWalletKey(i + 1));
if (!nextWallet) {
throw new Error("Next wallet not found");
Expand All @@ -135,9 +134,14 @@ export const useAppStore = create<AppState>()((set, get) => {

secureStorage.removeItem(getWalletKey(wallets.length - 1));

get().setSelectedWalletId(0);
if (walletId === selectedWalletId) {
get().setSelectedWalletId(0);
} else if (walletId < selectedWalletId) {
rolznz marked this conversation as resolved.
Show resolved Hide resolved
get().setSelectedWalletId(selectedWalletId - 1);
}

set({
wallets: wallets.filter((_, i) => i !== selectedWalletId),
wallets: wallets.filter((_, i) => i !== walletId),
});
};

Expand Down Expand Up @@ -181,9 +185,10 @@ export const useAppStore = create<AppState>()((set, get) => {
theme,
isOnboarded: secureStorage.getItem(hasOnboardedKey) === "true",
selectedWalletId: initialSelectedWalletId,
updateCurrentWallet,
removeCurrentWallet,
updateWallet,
removeWallet,
removeAddressBookEntry,
getNWCClient,
setUnlocked: (unlocked) => {
set({ unlocked });
},
Expand Down
6 changes: 3 additions & 3 deletions pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export function Home() {
right={() => (
<Link href="/settings" asChild>
<TouchableOpacity>
<SettingsIcon className="text-foreground" />
<SettingsIcon className="text-muted-foreground" />
</TouchableOpacity>
</Link>
)}
Expand All @@ -93,7 +93,7 @@ export function Home() {
onPress={switchBalanceState}
className="w-full flex flex-col items-center justify-center gap-4"
>
{wallets.length && (
{wallets.length > 1 && (
<TouchableOpacity
onPress={() => {
router.push("/settings/wallets");
Expand Down Expand Up @@ -149,7 +149,7 @@ export function Home() {
</View>
</ScrollView>
<View className="flex items-center justify-center">
<Link href="/transactions" asChild>
<Link href="/transactions">
<ChevronUpIcon
className="text-muted-foreground"
width={32}
Expand Down
28 changes: 13 additions & 15 deletions pages/settings/Wallets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,19 @@ export function Wallets() {
{item.item.name || DEFAULT_WALLET_NAME}
</Text>
</View>
{active && (
<Link
href={`/settings/wallets/${selectedWalletId}`}
className="absolute right-4"
asChild
>
<TouchableOpacity>
<SettingsIcon
className="text-foreground"
width={18}
height={18}
/>
</TouchableOpacity>
</Link>
)}
<Link
href={`/settings/wallets/${item.index}`}
className="absolute right-4"
asChild
>
<TouchableOpacity>
<SettingsIcon
className="text-muted-foreground"
width={18}
height={18}
/>
</TouchableOpacity>
</Link>
</TouchableOpacity>
);
}}
Expand Down
27 changes: 12 additions & 15 deletions pages/settings/wallets/EditWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Link, router } from "expo-router";
import * as Clipboard from "expo-clipboard";
import { Link, router, useLocalSearchParams } from "expo-router";
import { Pressable, Alert as RNAlert, View } from "react-native";
import Toast from "react-native-toast-message";

import * as Clipboard from "expo-clipboard";
import Alert from "~/components/Alert";
import {
ExportIcon,
Expand All @@ -22,47 +21,45 @@ import { DEFAULT_WALLET_NAME, REQUIRED_CAPABILITIES } from "~/lib/constants";
import { useAppStore } from "~/lib/state/appStore";

export function EditWallet() {
const selectedWalletId = useAppStore((store) => store.selectedWalletId);
const { id } = useLocalSearchParams() as { id: string };
const wallets = useAppStore((store) => store.wallets);

let walletId = parseInt(id);

return (
<View className="flex-1 flex flex-col p-4 gap-4">
<Screen title="Edit Wallet" />
{/* TODO: Do not allow notifications to be toggled without notifications capability */}
{!REQUIRED_CAPABILITIES.every((capability) =>
(wallets[selectedWalletId].nwcCapabilities || []).includes(capability),
(wallets[walletId]?.nwcCapabilities || []).includes(capability),
) && (
<Alert
type="warn"
title="This wallet might not work as expected"
description={`Missing capabilities: ${REQUIRED_CAPABILITIES.filter(
(capability) =>
!(wallets[selectedWalletId].nwcCapabilities || []).includes(
capability,
),
!(wallets[walletId]?.nwcCapabilities || []).includes(capability),
).join(", ")}`}
icon={TriangleAlertIcon}
className="mb-0"
/>
)}
<Link href={`/settings/wallets/${selectedWalletId}/name`} asChild>
<Link href={`/settings/wallets/${walletId}/name`} asChild>
<Pressable>
<Card className="w-full">
<CardContent className="flex flex-row items-center gap-4">
<WalletIcon className="text-muted-foreground" />
<View className="flex flex-1 flex-col">
<CardTitle>Wallet Name</CardTitle>
<CardDescription>
{wallets[selectedWalletId].name || DEFAULT_WALLET_NAME}
{wallets[walletId]?.name || DEFAULT_WALLET_NAME}
</CardDescription>
</View>
</CardContent>
</Card>
</Pressable>
</Link>
<Link
href={`/settings/wallets/${selectedWalletId}/lightning-address`}
asChild
>
<Link href={`/settings/wallets/${walletId}/lightning-address`} asChild>
<Pressable>
<Card className="w-full">
<CardContent className="flex flex-row items-center gap-4">
Expand Down Expand Up @@ -134,7 +131,7 @@ export function EditWallet() {
{
text: "Confirm",
onPress: () => {
useAppStore.getState().removeCurrentWallet();
useAppStore.getState().removeWallet(walletId);
if (wallets.length !== 1) {
router.back();
}
Expand Down
13 changes: 7 additions & 6 deletions pages/settings/wallets/LightningAddress.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { LightningAddress } from "@getalby/lightning-tools";
import { router } from "expo-router";
import { router, useLocalSearchParams } from "expo-router";
import React from "react";
import { View } from "react-native";
import Toast from "react-native-toast-message";
Expand All @@ -13,19 +13,20 @@ import { errorToast } from "~/lib/errorToast";
import { useAppStore } from "~/lib/state/appStore";

export function SetLightningAddress() {
const selectedWalletId = useAppStore((store) => store.selectedWalletId);
const { id } = useLocalSearchParams() as { id: string };
const walletId = parseInt(id);
const wallets = useAppStore((store) => store.wallets);
const [lightningAddress, setLightningAddress] = React.useState("");
React.useEffect(() => {
setLightningAddress(wallets[selectedWalletId].lightningAddress || "");
}, [wallets, selectedWalletId]);
setLightningAddress(wallets[walletId].lightningAddress || "");
}, [wallets, walletId]);
const [isLoading, setLoading] = React.useState(false);

const updateLightningAddress = async () => {
setLoading(true);
try {
if (lightningAddress) {
const nwcClient = useAppStore.getState().nwcClient;
const nwcClient = useAppStore.getState().getNWCClient(walletId);
if (!nwcClient) {
throw new Error("NWC client not connected");
}
Expand Down Expand Up @@ -53,7 +54,7 @@ export function SetLightningAddress() {
}
}

useAppStore.getState().updateCurrentWallet({ lightningAddress });
useAppStore.getState().updateWallet({ lightningAddress }, walletId);
Toast.show({
type: "success",
text1: "Lightning address updated",
Expand Down
16 changes: 10 additions & 6 deletions pages/settings/wallets/RenameWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { router } from "expo-router";
import { router, useLocalSearchParams } from "expo-router";
import React from "react";
import { View } from "react-native";
import Toast from "react-native-toast-message";
Expand All @@ -11,10 +11,11 @@ import { DEFAULT_WALLET_NAME } from "~/lib/constants";
import { useAppStore } from "~/lib/state/appStore";

export function RenameWallet() {
const selectedWalletId = useAppStore((store) => store.selectedWalletId);
const { id } = useLocalSearchParams() as { id: string };
const walletId = parseInt(id);
const wallets = useAppStore((store) => store.wallets);
const [walletName, setWalletName] = React.useState(
wallets[selectedWalletId].name || "",
wallets[walletId].name || "",
);
return (
<DismissableKeyboardView>
Expand All @@ -35,9 +36,12 @@ export function RenameWallet() {
<Button
size="lg"
onPress={() => {
useAppStore.getState().updateCurrentWallet({
name: walletName,
});
useAppStore.getState().updateWallet(
{
name: walletName,
},
walletId,
);
Toast.show({
type: "success",
text1: "Wallet name updated",
Expand Down
Loading