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: new ui home screen and receive screen #2983

Merged
merged 16 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from 12 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
6 changes: 3 additions & 3 deletions src/app/components/IconLinkCard/IconLinkCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ export function IconLinkCard({
}: IconLinkCardProps) {
return (
<div
className="shadow rounded-md p-4 bg-white dark:bg-surface-01dp hover:bg-gray-50 dark:hover:bg-surface-02dp text-gray-800 dark:text-neutral-200 cursor-pointer flex flex-row items-center gap-3"
className="border border-gray-300 dark:border-neutral-800 rounded-xl p-4 bg-white dark:bg-surface-01dp hover:bg-gray-50 dark:hover:bg-surface-02dp text-gray-800 dark:text-neutral-200 cursor-pointer flex flex-row items-center gap-3"
onClick={onClick}
>
<div className="flex-shrink-0 flex justify-center md:px-3">{icon}</div>
<div className="flex-grow">
<div className="flex-grow space-y-0.5">
<div className="font-medium leading-5 text-sm md:text-base">
{title}
</div>
<div className="text-gray-600 dark:text-neutral-400 text-xs leading-4 md:text-sm">
{description}
</div>
</div>
<div className="flex-shrink-0 flex justify-end ">
<div className="flex-shrink-0 flex justify-end text-gray-400 dark:text-neutral-500 ">
<CaretRightIcon className="w-8" />
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/app/screens/Accounts/BackupMnemonic/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ function BackupMnemonic() {
fetchData();
}, [fetchData]);

// TODO: set isMnemonicBackupDone, once new ui for screen is merged
return loading ? (
<div className="flex justify-center mt-5">
<Loading />
Expand Down
5 changes: 4 additions & 1 deletion src/app/screens/Accounts/GenerateMnemonic/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ function GenerateMnemonic() {
}

await api.setMnemonic(id, mnemonic);
await api.editAccount(id, { useMnemonicForLnurlAuth: true });
await api.editAccount(id, {
useMnemonicForLnurlAuth: true,
isMnemonicBackupDone: true,
});

toast.success(t("saved"));
// go to account settings
Expand Down
106 changes: 104 additions & 2 deletions src/app/screens/Home/DefaultView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,26 @@ import { ArrowRightIcon } from "@bitcoin-design/bitcoin-icons-react/filled";
import Button from "@components/Button";
import Loading from "@components/Loading";
import TransactionsTable from "@components/TransactionsTable";
import {
PopiconsArrowDownLine,
PopiconsBulbLine,
PopiconsDownloadLine,
PopiconsKeyLine,
} from "@popicons/react";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import { FC, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import BalanceBox from "~/app/components/BalanceBox";
import Hyperlink from "~/app/components/Hyperlink";
import { IconLinkCard } from "~/app/components/IconLinkCard/IconLinkCard";
import SkeletonLoader from "~/app/components/SkeletonLoader";
import toast from "~/app/components/Toast";
import { useAccount } from "~/app/context/AccountContext";
import { useTransactions } from "~/app/hooks/useTransactions";
import { PublisherLnData } from "~/app/screens/Home/PublisherLnData";
import api from "~/common/lib/api";
import api, { GetAccountRes } from "~/common/lib/api";
import msg from "~/common/lib/msg";
import utils from "~/common/lib/utils";
import type { Battery } from "~/types";
Expand All @@ -40,6 +47,7 @@ const DefaultView: FC<Props> = (props) => {
const lightningAddress = account?.lightningAddress || "";

const [isBlockedUrl, setIsBlockedUrl] = useState<boolean>(false);
const [currentAccount, setCurrentAccount] = useState<GetAccountRes>();

const { transactions, isLoadingTransactions, loadTransactions } =
useTransactions();
Expand All @@ -62,6 +70,18 @@ const DefaultView: FC<Props> = (props) => {
}
}, [props.currentUrl]);

useEffect(() => {
(async () => {
try {
const account = await api.getAccount();
setCurrentAccount(account);
} catch (e) {
console.error(e);
if (e instanceof Error) toast.error(`Error: ${e.message}`);
}
})();
}, []);

const unblock = async () => {
try {
if (props.currentUrl?.host) {
Expand All @@ -88,6 +108,10 @@ const DefaultView: FC<Props> = (props) => {
}
}

function openOptions(path: string) {
utils.openPage(`options.html#/${path}`);
}

return (
<div className="w-full max-w-screen-sm h-full mx-auto overflow-y-auto no-scrollbar">
{props.renderPublisherWidget && !!props.lnDataFromCurrentTab?.length && (
Expand Down Expand Up @@ -164,10 +188,88 @@ const DefaultView: FC<Props> = (props) => {

{!isLoading && (
<div>
<div className="flex flex-col gap-2 md:gap-3">
{transactions.length == 0 && (
<IconLinkCard
title={t("default_view.actions.get_started.title")}
description={t(
"default_view.actions.get_started.description"
)}
icon={
<PopiconsBulbLine className="w-8 h-8 text-gray-400 dark:text-neutral-500" />
}
onClick={() => {
utils.openUrl(
"https://guides.getalby.com/user-guide/v/alby-account-and-browser-extension/"
);
}}
/>
)}

{!(
currentAccount?.hasMnemonic &&
currentAccount?.isMnemonicBackupDone
) && (
<IconLinkCard
title={t("default_view.actions.backup_masterkey.title")}
description={t(
"default_view.actions.backup_masterkey.description"
)}
icon={
<PopiconsKeyLine className="w-8 h-8 text-gray-400 dark:text-neutral-500" />
}
onClick={async () => {
if (currentAccount?.hasMnemonic) {
openOptions(
`accounts/${currentAccount?.id}/secret-key/backup`
);
} else {
openOptions(
`accounts/${currentAccount?.id}/secret-key/new`
);
}
}}
/>
)}

{transactions.length == 0 && (
<IconLinkCard
title={t("default_view.actions.receive_bitcoin.title")}
description={t(
"default_view.actions.receive_bitcoin.description"
)}
icon={
<PopiconsArrowDownLine className="w-8 h-8 text-gray-400 dark:text-neutral-500" />
}
onClick={() => {
navigate("/receive");
}}
/>
)}

{!(
currentAccount?.hasMnemonic &&
currentAccount?.isMnemonicBackupDone
pavanjoshi914 marked this conversation as resolved.
Show resolved Hide resolved
) && (
<IconLinkCard
title={t("default_view.actions.import_masterkey.title")}
description={t(
"default_view.actions.import_masterkey.description"
)}
icon={
<PopiconsDownloadLine className="w-8 h-8 text-gray-400 dark:text-neutral-500" />
}
onClick={async () => {
openOptions(
`accounts/${currentAccount?.id}/secret-key/import`
);
}}
/>
)}
</div>
<TransactionsTable
transactions={transactions}
loading={isLoading}
noResultMsg={t("default_view.no_transactions")}
/>

{!isLoading && transactions.length > 0 && (
Expand Down
17 changes: 11 additions & 6 deletions src/app/screens/Receive/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {
BitcoinCircleIcon,
BitcoinIcon,
CaretLeftIcon,
CopyIcon,
LightningIcon,
} from "@bitcoin-design/bitcoin-icons-react/outline";
import Container from "@components/Container";
import Header from "@components/Header";
import IconButton from "@components/IconButton";
import { PopiconsBoltLine, PopiconsWithdrawalLine } from "@popicons/react";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
Expand All @@ -15,7 +15,6 @@ import QRCode from "~/app/components/QRCode";
import SkeletonLoader from "~/app/components/SkeletonLoader";
import toast from "~/app/components/Toast";
import { useAccount } from "~/app/context/AccountContext";
import RedeemIcon from "~/app/icons/RedeemIcon";
import { isAlbyLNDHubAccount, isAlbyOAuthAccount } from "~/app/utils";
import api from "~/common/lib/api";
import { IconLinkCard } from "../../components/IconLinkCard/IconLinkCard";
Expand Down Expand Up @@ -123,7 +122,9 @@ function Receive() {
<IconLinkCard
title={t("actions.invoice.title")}
description={t("actions.invoice.description")}
icon={<LightningIcon className="w-8" />}
icon={
<PopiconsBoltLine className="w-8 h-8 text-gray-400 dark:text-neutral-500" />
}
onClick={() => {
navigate("/receive/invoice");
}}
Expand All @@ -132,7 +133,9 @@ function Receive() {
<IconLinkCard
title={t("actions.bitcoin_address.title")}
description={t("actions.bitcoin_address.description")}
icon={<BitcoinCircleIcon className="w-8" />}
icon={
<BitcoinIcon className="w-8 h-8 text-gray-400 dark:text-neutral-500" />
}
onClick={() => {
navigate("/onChainReceive");
}}
Expand All @@ -141,7 +144,9 @@ function Receive() {
<IconLinkCard
title={t("actions.redeem.title")}
description={t("actions.redeem.description")}
icon={<RedeemIcon className="w-8" />}
icon={
<PopiconsWithdrawalLine className="w-8 h-8 text-gray-400 dark:text-neutral-500" />
}
onClick={() => {
navigate("/lnurlRedeem");
}}
Expand Down
1 change: 1 addition & 0 deletions src/common/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export interface GetAccountRes extends Pick<Account, "id" | "name"> {
liquidEnabled: boolean;
nostrEnabled: boolean;
hasMnemonic: boolean;
isMnemonicBackupDone: boolean;
hasImportedNostrKey: boolean;
bitcoinNetwork: BitcoinNetworkType;
useMnemonicForLnurlAuth: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const mockState = {
mnemonic: btcFixture.mnemonic,
bitcoinNetwork: "regtest",
useMnemonicForLnurlAuth: true,
isMnemonicBackupDone: true,
},
"1e1e8ea6-493e-480b-9855-303d37506e97": {
config: "config-123-456",
Expand Down Expand Up @@ -65,6 +66,7 @@ describe("account info", () => {
hasImportedNostrKey: true,
bitcoinNetwork: "bitcoin",
useMnemonicForLnurlAuth: false,
isMnemonicBackupDone: false,
};

expect(await getAccount(message)).toStrictEqual({
Expand Down Expand Up @@ -92,6 +94,7 @@ describe("account info", () => {
hasImportedNostrKey: true,
bitcoinNetwork: "regtest",
useMnemonicForLnurlAuth: true,
isMnemonicBackupDone: true,
};

expect(await getAccount(message)).toStrictEqual({
Expand Down
1 change: 1 addition & 0 deletions src/extension/background-script/actions/accounts/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const add = async (message: MessageAccountAdd) => {
...newAccount,
id: accountId,
name,
isMnemonicBackupDone: false,
};

const mnemonic = await generateMnemonic({
Expand Down
5 changes: 5 additions & 0 deletions src/extension/background-script/actions/accounts/edit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ const edit = async (message: MessageAccountEdit) => {
message.args.useMnemonicForLnurlAuth;
}

if (message.args.isMnemonicBackupDone !== undefined) {
accounts[accountId].isMnemonicBackupDone =
message.args.isMnemonicBackupDone;
}

state.setState({ accounts });
// make sure we immediately persist the updated accounts
await state.getState().saveToStorage();
Expand Down
4 changes: 4 additions & 0 deletions src/extension/background-script/actions/accounts/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ const get = async (message: MessageAccountGet) => {
liquidEnabled: !!account.mnemonic,
nostrEnabled: !!account.nostrPrivateKey,
hasMnemonic: !!account.mnemonic,
// for existing accounts consider mnemonic backup already done
isMnemonicBackupDone: account.isMnemonicBackupDone
? account.isMnemonicBackupDone
: true,
// Note: undefined (default for new accounts) it is also considered imported
hasImportedNostrKey: account.hasImportedNostrKey !== false,
bitcoinNetwork: account.bitcoinNetwork || "bitcoin",
Expand Down
21 changes: 20 additions & 1 deletion src/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,26 @@
"is_blocked_hint": "Alby is currently disabled on {{host}}",
"block_removed": "Enabled {{host}}. Please reload the website.",
"no_transactions": "No transactions for this account yet.",
"see_all": "See all"
"see_all": "See all",
"actions": {
"get_started": {
"title": "Get Started With Alby Extension",
"description": "New to Alby Extension? Check out our guides, videos, and explanations"
},
"backup_masterkey": {
"title": "Back up your Master Key",
"description": "Learn what Master Key is, how it’s used for Nostr and make sure to back up"
},

"receive_bitcoin": {
"title": "Receive bitcoin",
"description": "Get bitcoin to your lightning address, a lightning invoice or bitcoin address."
},
"import_masterkey": {
"title": "Import your Master Key",
"description": "If you already have a Master Key, you can import it using recovery phrase"
}
}
}
},
"accounts": {
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface Account {
mnemonic?: string | null;
hasImportedNostrKey?: boolean;
bitcoinNetwork?: BitcoinNetworkType;
isMnemonicBackupDone?: boolean;
useMnemonicForLnurlAuth?: boolean;
avatarUrl?: string;
}
Expand Down Expand Up @@ -231,6 +232,7 @@ export interface MessageAccountEdit extends MessageDefault {
name?: Account["name"];
bitcoinNetwork?: BitcoinNetworkType;
useMnemonicForLnurlAuth?: boolean;
isMnemonicBackupDone?: boolean;
};
action: "editAccount";
}
Expand Down
Loading