Skip to content
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
35 changes: 29 additions & 6 deletions client/src/_components/settings/backup-account-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,31 @@ import { AlertTriangle, Copy, Download } from "lucide-react";
import { useState } from "react";
import { toast } from "sonner";

export function BackupAccountModal() {
interface BackupAccountModalProps {
open?: boolean;
onOpenChange?: (open: boolean) => void;
onBackupSuccess?: () => void;
trigger?: React.ReactNode;
}

export function BackupAccountModal({
open: controlledOpen,
onOpenChange: controlledOnOpenChange,
onBackupSuccess,
trigger,
}: BackupAccountModalProps = {}) {
const { getMnemonic } = useAuth();

const [isOpen, setIsOpen] = useState(false);
const [internalOpen, setInternalOpen] = useState(false);
const [confirmExport, setConfirmExport] = useState(false);

// Support both controlled and uncontrolled modes
const isControlled = controlledOpen !== undefined;
const isOpen = isControlled ? controlledOpen : internalOpen;
const setIsOpen = isControlled
? (open: boolean) => controlledOnOpenChange?.(open)
: setInternalOpen;

function waitForWindowFocus(): Promise<void> {
return new Promise((resolve) => {
// If window is already focused, resolve immediately
Expand Down Expand Up @@ -56,6 +75,7 @@ export function BackupAccountModal() {

await copyToClipboard(exportData);
toast.success("Account backup copied to clipboard!");
onBackupSuccess?.();
setIsOpen(false);
resetForm();
} catch (error) {
Expand All @@ -77,6 +97,7 @@ export function BackupAccountModal() {

downloadAsJson(exportData);
toast.success("Account backup downloaded!");
onBackupSuccess?.();
setIsOpen(false);
resetForm();
} catch (error) {
Expand All @@ -98,9 +119,11 @@ export function BackupAccountModal() {
}}
>
<DialogTrigger asChild>
<Button variant="outline" className="">
Back Up Account
</Button>
{trigger || (
<Button variant="outline" className="">
Back Up Account
</Button>
)}
</DialogTrigger>
<DialogContent className="sm:max-w-md">
<DialogHeader>
Expand All @@ -117,7 +140,7 @@ export function BackupAccountModal() {
</p>
<p className="text-xs text-muted-foreground">
Anyone with access to this backup can control all of your
account. Keep it secure.
assets. Keep it secure.
</p>
</div>
</div>
Expand Down
50 changes: 50 additions & 0 deletions client/src/_components/status/experimental-banner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { BackupAccountModal } from "@/_components/settings/backup-account-modal";
import { useAuth } from "@/_providers/auth-provider";
import { AlertTriangle } from "lucide-react";
import { useEffect, useState } from "react";

const BACKUP_STORAGE_KEY = "commbank-account-backed-up";

export function ExperimentalBanner() {
const { isSignedIn } = useAuth();
const [hasBackedUp, setHasBackedUp] = useState(true); // Default to true to prevent flash

useEffect(() => {
const backed = localStorage.getItem(BACKUP_STORAGE_KEY);
setHasBackedUp(backed === "true");
}, []);

const handleBackupSuccess = () => {
localStorage.setItem(BACKUP_STORAGE_KEY, "true");
setHasBackedUp(true);
};

// Don't show if not signed in or already backed up
if (!isSignedIn || hasBackedUp) {
return null;
}

return (
<div className="w-full mb-6 rounded-lg border border-yellow-500/50 bg-yellow-500/10 p-4">
<div className="flex items-start gap-3">
<AlertTriangle className="h-5 w-5 text-yellow-500 shrink-0 mt-0.5" />
<div className="space-y-1 flex-1 text-left">
<p className="text-base font-medium text-yellow-500">
commbank.eth is experimental
</p>
<p className="text-sm text-muted-foreground">
Please practise caution and{" "}
<BackupAccountModal
onBackupSuccess={handleBackupSuccess}
trigger={
<button className="underline text-yellow-500 hover:text-yellow-400 font-medium cursor-pointer">
backup your account secret
</button>
}
/>
</p>
</div>
</div>
</div>
);
}
4 changes: 2 additions & 2 deletions client/src/lib/gas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ export async function getAdjustedGasPrice(
return parseUnits("2", "gwei");
}

// Add 20% buffer to handle base fee increases between estimation and inclusion
return (basePrice * 120n) / 100n;
// Add 50% buffer to handle base fee increases between estimation and inclusion
return (basePrice * 150n) / 100n;
}
3 changes: 3 additions & 0 deletions client/src/pages/account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import { BalanceCard } from "@/_components/account/balance-card";
import { Transactions } from "@/_components/account/transactions";
import PageContainer from "@/_providers/page-container";
import { PAGE_METADATA } from "@/_constants/seo-config";
import { ExperimentalBanner } from "@/_components/status/experimental-banner";

export default function AccountPage() {
return (
<PageContainer {...PAGE_METADATA.account}>
<div className="container max-w-4xl space-y-6">
<ExperimentalBanner />

<BalanceCard />

{/* Navigation Buttons */}
Expand Down