Skip to content

Commit

Permalink
feat: onboarding (#44)
Browse files Browse the repository at this point in the history
* feat: onboarding

* fix: allow deleting storage item

* fix: upgrade packages

* fix: remove button

* fix: use securestorage

* fix: onboarding redirect

* fix: onboarding redirects

* fix: button styles, copy

* fix: secondary button text color

---------

Co-authored-by: Roland Bewick <[email protected]>
  • Loading branch information
reneaaron and rolznz authored Sep 2, 2024
1 parent 90c773f commit e700ca8
Show file tree
Hide file tree
Showing 11 changed files with 155 additions and 62 deletions.
24 changes: 21 additions & 3 deletions app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import "../lib/applyGlobalPolyfills";

import "~/global.css";

import { Theme, ThemeProvider } from "@react-navigation/native";
import { SplashScreen, Stack } from "expo-router";
import {
router,
SplashScreen,
Stack,
useRootNavigationState,
} from "expo-router";
import { StatusBar } from "expo-status-bar";
import * as React from "react";
import { SafeAreaView } from "react-native";
Expand All @@ -16,6 +20,7 @@ import Toast from "react-native-toast-message";
import { toastConfig } from "~/components/ToastConfig";
import * as Font from "expo-font";
import { useInfo } from "~/hooks/useInfo";
import { secureStorage } from "~/lib/secureStorage";

const LIGHT_THEME: Theme = {
dark: false,
Expand All @@ -41,9 +46,22 @@ SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
const { isDarkColorScheme } = useColorScheme();
const [fontsLoaded, setFontsLoaded] = React.useState(false);
const [showOnboarding, setShowOnboarding] = React.useState(false);
useConnectionChecker();

const rootNavigationState = useRootNavigationState();
const hasNavigationState = !!rootNavigationState?.key;

React.useEffect(() => {
const checkOnboardingStatus = async () => {
const hasOnboarded = await secureStorage.getItem("hasOnboarded");
if (!hasOnboarded && hasNavigationState) {
router.replace("/onboarding");
}
};

checkOnboardingStatus();

(async () => {
await Font.loadAsync({
OpenRunde: require("./../assets/fonts/OpenRunde-Regular.otf"),
Expand All @@ -56,7 +74,7 @@ export default function RootLayout() {
})().finally(() => {
SplashScreen.hideAsync();
});
}, []);
}, [hasNavigationState]);

if (!fontsLoaded) {
return null;
Expand Down
5 changes: 5 additions & 0 deletions app/onboarding.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Onboarding } from "../pages/Onboarding";

export default function Page() {
return <Onboarding />;
}
3 changes: 3 additions & 0 deletions components/Icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
Power,
CameraOff,
Palette,
Egg,
} from "lucide-react-native";
import { cssInterop } from "nativewind";

Expand Down Expand Up @@ -81,6 +82,7 @@ interopIcon(Hotel);
interopIcon(Power);
interopIcon(CameraOff);
interopIcon(Palette);
interopIcon(Egg);

export {
AlertCircle,
Expand Down Expand Up @@ -116,4 +118,5 @@ export {
X,
Power,
Palette,
Egg,
};
8 changes: 4 additions & 4 deletions components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const buttonVariants = cva(
size: {
default: "min-h-10 px-4 py-2 native:min-h-12 native:px-5 native:py-3",
sm: "min-h-9 rounded-md px-3",
lg: "min-h-11 rounded-lg px-8 native:min-h-16",
lg: "min-h-11 rounded-2xl px-8 native:min-h-16",
icon: "min-h-10 min-w-10",
},
},
Expand All @@ -42,14 +42,14 @@ const buttonTextVariants = cva(
destructive: "text-destructive-foreground",
outline: "group-active:text-accent-foreground",
secondary:
"text-secondary-foreground group-active:text-secondary-foreground font-medium2",
"text-secondary-foreground group-active:text-secondary-foreground",
ghost: "group-active:text-accent-foreground",
link: "text-primary group-active:underline",
},
size: {
default: "",
default: "font-medium2",
sm: "",
lg: "native:text-2xl",
lg: "native:text-2xl font-bold2",
icon: "",
},
},
Expand Down
2 changes: 1 addition & 1 deletion global.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
--primary: 47 100% 50%;
--primary-foreground: 217 19% 27%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 215 28% 17%;
--secondary-foreground: 217 19% 27%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
Expand Down
9 changes: 9 additions & 0 deletions lib/state/appStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ interface AppState {
addWallet(wallet: Wallet): void;
addAddressBookEntry(entry: AddressBookEntry): void;
reset(): void;
showOnboarding(): void;
}

const walletKeyPrefix = "wallet";
const addressBookEntryKeyPrefix = "addressBookEntry";
const selectedWalletIdKey = "selectedWalletId";
const fiatCurrencyKey = "fiatCurrency";
const hasOnboardedKey = "hasOnboarded";

type Wallet = {
name?: string;
Expand Down Expand Up @@ -176,6 +178,10 @@ export const useAppStore = create<AppState>()((set, get) => {
addressBookEntries: [...currentAddressBookEntries, addressBookEntry],
});
},
showOnboarding() {
// clear onboarding status
secureStorage.removeItem(hasOnboardedKey);
},
reset() {
// clear wallets
for (let i = 0; i < get().wallets.length; i++) {
Expand All @@ -188,6 +194,9 @@ export const useAppStore = create<AppState>()((set, get) => {
// clear selected wallet ID
secureStorage.removeItem(selectedWalletIdKey);

// clear onboarding status
secureStorage.removeItem(hasOnboardedKey);

set({
nwcClient: undefined,
fiatCurrency: undefined,
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"dayjs": "^1.11.10",
"expo": "^51.0.30",
"expo-camera": "^15.0.14",
"expo": "~51.0.31",
"expo-camera": "~15.0.15",
"expo-clipboard": "~6.0.3",
"expo-constants": "~16.0.2",
"expo-font": "^12.0.9",
Expand Down
39 changes: 39 additions & 0 deletions pages/Onboarding.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { openURL } from "expo-linking";
import { Link, Stack, router } from "expo-router";
import React from "react";
import { View } from "react-native";
import { Button } from "~/components/ui/button";
import { Text } from "~/components/ui/text";
import { secureStorage } from "~/lib/secureStorage";

export function Onboarding() {
async function finish() {
secureStorage.setItem("hasOnboarded", "true");
router.replace("/");
}

return (
<View className="flex-1 flex flex-col p-6 gap-3">
<Stack.Screen
options={{
title: "Onboarding",
headerShown: false,
}}
/>
<View className="flex-1 flex items-center justify-center gap-4">
<Text className="font-semibold2 text-4xl text-center text-foreground">Hello there 👋</Text>
<Text className="font-medium2 text-xl text-primary-foreground text-center">
<Text className="font-semibold2 text-xl text-primary-foreground">Alby Go</Text> is a simple mobile wallet interface for your Alby Hub or other lightning nodes and wallets.
</Text>
</View>
<Link href="/" asChild>
<Button size="lg" onPress={finish}>
<Text>Connect Wallet</Text>
</Button>
</Link>
<Button variant="secondary" size="lg" onPress={() => openURL("https://albyhub.com/")}>
<Text>Learn more</Text>
</Button>
</View>
);
}
8 changes: 7 additions & 1 deletion pages/Wildcard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { usePathname } from "expo-router";
import { Stack, usePathname } from "expo-router";
import { View } from "react-native";
import Loading from "~/components/Loading";
import { Text } from "~/components/ui/text";
Expand All @@ -10,6 +10,12 @@ export function Wildcard() {

return (
<View className="flex-1 justify-center items-center flex flex-col gap-3">
<Stack.Screen
options={{
title: "",
header: () => null, // hide header completely
}}
/>
<Loading />
<Text>Loading {pathname}</Text>
</View>
Expand Down
89 changes: 51 additions & 38 deletions pages/settings/Settings.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Link, router } from "expo-router";
import { Alert, Pressable, TouchableOpacity, View } from "react-native";
import { Bitcoin, Palette, Power, Wallet2 } from "~/components/Icons";
import { Bitcoin, Egg, Palette, Power, Wallet2 } from "~/components/Icons";

import { DEFAULT_WALLET_NAME } from "~/lib/constants";
import { useAppStore } from "~/lib/state/appStore";
Expand All @@ -25,9 +25,7 @@ export function Settings() {
<Link href="/settings/wallets" asChild>
<TouchableOpacity className="flex flex-row items-center gap-4">
<Wallet2 className="text-foreground" />
<Text className="font-medium2 text-xl text-foreground">
Wallets
</Text>
<Text className="font-medium2 text-xl text-foreground">Wallets</Text>
<Text className="text-muted-foreground text-xl">
({wallet.name || DEFAULT_WALLET_NAME})
</Text>
Expand All @@ -43,47 +41,63 @@ export function Settings() {
</TouchableOpacity>
</Link>

<TouchableOpacity className="flex flex-row gap-4" onPress={toggleColorScheme}>
<TouchableOpacity
className="flex flex-row gap-4"
onPress={toggleColorScheme}
>
<Palette className="text-foreground" />
<Text className="text-foreground font-medium2 text-xl">
Theme
</Text>
<Text className="text-foreground font-medium2 text-xl">Theme</Text>
<Text className="text-muted-foreground text-xl">
({colorScheme.charAt(0).toUpperCase() + colorScheme.substring(1)})
</Text>
</TouchableOpacity>

{developerMode && (
<View className="mt-5 flex flex-col gap-4">
<Text className="text-muted-foreground uppercase">Developer mode</Text>
<Pressable
className="flex flex-row gap-4"
onPress={() => {
Alert.alert(
"Reset",
"Are you sure you want to reset? You will be signed out of all your wallets. Your connection secrets and address book will be lost.",
[
{
text: "Cancel",
style: "cancel",
},
{
text: "Confirm",
onPress: () => {
router.dismissAll();
useAppStore.getState().reset();
},
},
],
);
}}
>
<Power className="text-destructive" />
<Text className="text-destructive font-medium2 text-xl">
Reset Wallet
<>
<View className="mt-5 flex flex-col gap-6">
<Text className="text-muted-foreground uppercase">
Developer mode
</Text>
</Pressable>
</View>
<Pressable
className="flex flex-row gap-4"
onPress={() => {
router.dismissAll();
useAppStore.getState().showOnboarding();
router.replace("/onboarding");
}}
>
<Egg className="text-primary-foreground" />
<Text className="font-medium2 text-xl">Open Onboarding</Text>
</Pressable>
<Pressable
className="flex flex-row gap-4"
onPress={() => {
Alert.alert(
"Reset",
"Are you sure you want to reset? You will be signed out of all your wallets. Your connection secrets and address book will be lost.",
[
{
text: "Cancel",
style: "cancel",
},
{
text: "Confirm",
onPress: () => {
router.dismissAll();
useAppStore.getState().reset();
},
},
],
);
}}
>
<Power className="text-destructive" />
<Text className="text-destructive font-medium2 text-xl">
Reset Wallet
</Text>
</Pressable>
</View>
</>
)}
<TouchableOpacity
className="flex-1"
Expand All @@ -95,7 +109,6 @@ export function Settings() {
setDeveloperMode(true);
Toast.show({
text1: "You are now a developer",

});
} else if (newCounter > 1 && newCounter < 5) {
Toast.show({
Expand Down
Loading

0 comments on commit e700ca8

Please sign in to comment.