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: update settings pages #927

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
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
40 changes: 29 additions & 11 deletions frontend/src/components/MnemonicInputs.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { wordlist } from "@scure/bip39/wordlists/english";
import { useState } from "react";
import PasswordViewAdornment from "src/components/PasswordAdornment";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "src/components/ui/card";
Expand All @@ -12,18 +14,16 @@ type MnemonicInputsProps = {
mnemonic?: string;
setMnemonic?(mnemonic: string): void;
readOnly?: boolean;
description?: string;
};

export default function MnemonicInputs({
mnemonic,
setMnemonic,
readOnly,
children,
description,
}: React.PropsWithChildren<MnemonicInputsProps>) {
const [revealedIndex, setRevealedIndex] = useState<number | undefined>(
undefined
);

const words = mnemonic?.split(" ") || [];
while (words.length < 12) {
words.push("");
Expand All @@ -33,30 +33,37 @@ export default function MnemonicInputs({
words.pop();
}

const [revealedIndex, setRevealedIndex] = useState<number | undefined>(
undefined
);

return (
<>
<Card>
<CardHeader>
<CardTitle>Recovery phrase to your wallet</CardTitle>
<CardTitle className="text-xl text-center">
Wallet Recovery Phrase
</CardTitle>
<CardDescription className="text-muted-foreground text-sm max-w-xs text-right mt-2">
{description}
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-x-8 gap-y-5 justify-center backup sensitive">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-y-5 justify-center backup sensitive">
{words.map((word, i) => {
const isRevealed = revealedIndex === i;
pavanjoshi914 marked this conversation as resolved.
Show resolved Hide resolved
const inputId = `mnemonic-word-${i}`;
return (
<div key={i} className="flex justify-center items-center gap-2">
<span className="text-muted-foreground text-right">
{i + 1}.
</span>
<span className="text-foreground text-right">{i + 1}.</span>
<div className="relative">
<Input
id={inputId}
autoFocus={!readOnly && i === 0}
readOnly={readOnly}
onFocus={() => setRevealedIndex(i)}
onBlur={() => setRevealedIndex(undefined)}
readOnly={readOnly}
className="w-32 text-center"
className="w-32 text-center border-[#E4E4E7] text-muted-foreground"
list={readOnly ? undefined : "wordlist"}
value={isRevealed ? word : word.length ? "•••••" : ""}
onChange={(e) => {
Expand All @@ -71,6 +78,17 @@ export default function MnemonicInputs({
.trim()
);
}}
endAdornment={
<PasswordViewAdornment
isRevealed={isRevealed}
onChange={(passwordView) => {
if (passwordView) {
document.getElementById(inputId)?.focus();
}
}}
iconClass="text-muted-foreground"
/>
}
/>
</div>
</div>
Expand Down
12 changes: 9 additions & 3 deletions frontend/src/components/PasswordAdornment.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { EyeIcon, EyeOffIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { cn } from "src/lib/utils";

type Props = {
onChange: (viewingPassword: boolean) => void;
isRevealed?: boolean;
iconClass?: string;
};

export default function PasswordViewAdornment({ onChange, isRevealed }: Props) {
export default function PasswordViewAdornment({
onChange,
isRevealed,
iconClass,
}: Props) {
const [_isRevealed, setRevealed] = useState(false);

// toggle the button if password view is handled by component itself
Expand All @@ -27,9 +33,9 @@ export default function PasswordViewAdornment({ onChange, isRevealed }: Props) {
}}
>
{_isRevealed ? (
<EyeIcon className="h-5 w-5 text-gray-600" />
<EyeOffIcon className={cn("h-4 w-4", iconClass)} />
) : (
<EyeOffIcon className="h-5 w-5 text-gray-600" />
<EyeIcon className={cn("h-4 w-4", iconClass)} />
)}
</button>
);
Expand Down
7 changes: 4 additions & 3 deletions frontend/src/components/SettingsHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import React from "react";
import { Separator } from "src/components/ui/separator";

type Props = {
title: string;
description: string;
description: string | React.ReactNode;
};

function SettingsHeader({ title, description }: Props) {
return (
<>
<div className="space-y-6">
<div>
<h3 className="text-lg font-medium">{title}</h3>
<p className="text-sm text-muted-foreground">{description}</p>
<h3 className="text-2xl font-medium">{title}</h3>
<p className="text-base text-muted-foreground">{description}</p>
</div>
<Separator />
</div>
Expand Down
1 change: 0 additions & 1 deletion frontend/src/components/SidebarHint.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ function SidebarHint() {
);
}
}

type SidebarHintCardProps = {
title: string;
description: string | ReactElement;
Expand Down
22 changes: 11 additions & 11 deletions frontend/src/components/layouts/SettingsLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { Power } from "lucide-react";
import React, { useState } from "react";
import { NavLink, Outlet, useNavigate } from "react-router-dom";
import AppHeader from "src/components/AppHeader";
import { buttonVariants } from "src/components/ui/button";

import { useInfo } from "src/hooks/useInfo";

import { Power } from "lucide-react";
import {
AlertDialog,
AlertDialogAction,
Expand All @@ -13,12 +17,8 @@ import {
AlertDialogTitle,
AlertDialogTrigger,
} from "src/components/ui/alert-dialog";
import { buttonVariants } from "src/components/ui/button";
import { LoadingButton } from "src/components/ui/loading-button";
import { useToast } from "src/components/ui/use-toast";

import { useInfo } from "src/hooks/useInfo";

import { cn } from "src/lib/utils";
import { request } from "src/utils/request";

Expand Down Expand Up @@ -60,7 +60,7 @@ export default function SettingsLayout() {
<>
<AppHeader
title="Settings"
description="Manage your Alby Hub settings."
description=""
breadcrumb={false}
contentRight={
<AlertDialog>
Expand All @@ -76,11 +76,11 @@ export default function SettingsLayout() {
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
Do you want to turn off Alby Hub?
Do you want to turn off your Alby Hub?
</AlertDialogTitle>
<AlertDialogDescription>
This will turn off your Alby Hub and make your node offline.
You won't be able to send or receive bitcoin until you unlock
You wont be able to send or receive bitcoin until you unlock
it.
</AlertDialogDescription>
</AlertDialogHeader>
Expand All @@ -94,6 +94,7 @@ export default function SettingsLayout() {
</AlertDialog>
}
/>

<div className="flex flex-col space-y-8 lg:flex-row lg:space-x-12 lg:space-y-0">
<aside className="lg:-mx-4 lg:w-1/5">
<nav className="flex flex-wrap lg:flex-col -space-x-1 lg:space-x-0 lg:space-y-1">
Expand All @@ -104,9 +105,8 @@ export default function SettingsLayout() {
<MenuItem to="/settings/change-unlock-password">
Unlock Password
</MenuItem>
{hasMnemonic && <MenuItem to="/settings/backup">Backup</MenuItem>}
{hasNodeBackup && (
<MenuItem to="/settings/node-backup">Migrate Node</MenuItem>
{(hasMnemonic || hasNodeBackup) && (
<MenuItem to="/settings/backup">Backup</MenuItem>
)}
{info?.albyAccountConnected && (
<MenuItem to="/settings/alby-account">Your Alby Account</MenuItem>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const buttonVariants = cva(
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
"border border-destructive text-destructive shadow-sm hover:text-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
Expand Down
30 changes: 20 additions & 10 deletions frontend/src/components/ui/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,33 @@ import * as React from "react";
import { cn } from "src/lib/utils";

export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}
extends React.InputHTMLAttributes<HTMLInputElement> {
endAdornment?: React.ReactNode;
}

const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
({ className, type, endAdornment, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 sm:text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
className
<div className="relative flex items-center w-full">
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-1 pr-10 sm:text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
{endAdornment && (
<span className="absolute right-1 flex items-center">
{endAdornment}
</span>
)}
ref={ref}
{...props}
/>
</div>
);
}
);

Input.displayName = "Input";

export { Input };
9 changes: 8 additions & 1 deletion frontend/src/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,12 @@ import ConnectPeer from "src/screens/peers/ConnectPeer";
import Peers from "src/screens/peers/Peers";
import { AlbyAccount } from "src/screens/settings/AlbyAccount";
import { AutoUnlock } from "src/screens/settings/AutoUnlock";
import Backup from "src/screens/settings/Backup";
import { ChangeUnlockPassword } from "src/screens/settings/ChangeUnlockPassword";
import DebugTools from "src/screens/settings/DebugTools";
import DeveloperSettings from "src/screens/settings/DeveloperSettings";
import Settings from "src/screens/settings/Settings";

import { ImportMnemonic } from "src/screens/setup/ImportMnemonic";
import { RestoreNode } from "src/screens/setup/RestoreNode";
import { SetupAdvanced } from "src/screens/setup/SetupAdvanced";
Expand Down Expand Up @@ -183,9 +185,14 @@ const routes = [
},
{
path: "backup",
element: <BackupMnemonic />,
element: <Backup />,
handle: { crumb: () => "Backup" },
},
{
path: "mnemonic-backup",
element: <BackupMnemonic />,
handle: { crumb: () => "Key Backup" },
},
{
path: "node-backup",
element: <BackupNode />,
Expand Down
Loading
Loading