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
7 changes: 5 additions & 2 deletions src/components/address/address-breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ const AddressBreadcrumb = ({
};

return (
<nav aria-label="Breadcrumb" className="flex justify-between">
<nav
aria-label="Breadcrumb"
className="flex flex-wrap justify-between gap-2"
>
<ol role="list" className="flex items-center space-x-4">
<li>
<div>
Expand Down Expand Up @@ -147,7 +150,7 @@ const AddressBreadcrumb = ({
</div>
</li>
</ol>
<div className="flex gap-2">
<div className="flex items-center gap-2">
<RefreshButton />
<Settings blocks={blocks} />
</div>
Expand Down
1 change: 1 addition & 0 deletions src/components/address/address-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export default function AddressView({ addresses }: { addresses: string }) {
enableCache: prev.enableCache ?? false,
theme: prev.theme ?? "system",
statsPanelTheme: prev.statsPanelTheme ?? "indigo",
currency: prev.currency ?? "USD",
}),
});
};
Expand Down
54 changes: 38 additions & 16 deletions src/components/address/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { useTheme } from "@/components/theme-provider";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { motion } from "framer-motion";
Expand All @@ -15,16 +22,15 @@ import CsvExportDialog from "@/components/address/csv-export-dialog.tsx";
import { CacheManagementDialog } from "@/components/address/cache-management-dialog";
import { DownloadIcon, DatabaseIcon } from "lucide-react";
import { toast } from "sonner";
import { useAlgoPrice } from "@/hooks/queries/useAlgoPrice";
import AlgorandLogo from "@/components/algorand-logo.tsx";
import { useNavigate, useSearch } from "@tanstack/react-router";
import { CURRENCIES, type Currency } from "@/lib/currencies";

export default function Settings({ blocks }: { blocks: MinimalBlock[] }) {
const { themeSetting, setThemeSetting } = useTheme();
const { price: algoPrice, loading: priceLoading } = useAlgoPrice();
const navigate = useNavigate({ from: "/$addresses" });
const search = useSearch({ from: "/$addresses" });
const statsPanelTheme = search.statsPanelTheme;
const currency = search.currency || "USD";

const changeStatsPanelTheme = (newTheme: "light" | "indigo") => {
navigate({
Expand All @@ -36,6 +42,16 @@ export default function Settings({ blocks }: { blocks: MinimalBlock[] }) {
});
};

const changeCurrency = (newCurrency: Currency) => {
navigate({
search: (prev) => ({
...prev,
currency: newCurrency,
}),
replace: true,
});
};

return (
<DropdownMenu>
<DropdownMenuTrigger className="rounded-md p-2 hover:bg-gray-100 dark:hover:bg-gray-800">
Expand Down Expand Up @@ -227,19 +243,25 @@ export default function Settings({ blocks }: { blocks: MinimalBlock[] }) {
</ToggleGroup>
</div>

{!priceLoading && algoPrice && (
<>
<DropdownMenuSeparator className="dark:bg-gray-700" />
<div className="flex items-center gap-1 px-4 py-2 text-sm text-gray-600 dark:text-gray-300">
<div className="flex items-center">
<span className="mr-1">1</span>
<AlgorandLogo className="h-3.5 w-3.5" />
<span className="ml-1">=</span>
</div>
<span className="font-medium">${algoPrice}</span>
</div>
</>
)}
<DropdownMenuSeparator className="dark:bg-gray-700" />

<DropdownMenuLabel className="dark:text-gray-100">
Currency
</DropdownMenuLabel>
<div className="px-2 py-1.5">
<Select value={currency} onValueChange={changeCurrency}>
<SelectTrigger className="w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
{CURRENCIES.map((curr) => (
<SelectItem key={curr.value} value={curr.value}>
{curr.symbol} {curr.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</DropdownMenuContent>
</DropdownMenu>
);
Expand Down
6 changes: 5 additions & 1 deletion src/components/address/stats/status/status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { AnxietyCard, AnxietyCardSkeleton } from "./anxiety-card";
import { StatusBadgesSkeleton } from "./status-badges-skeleton";
import { CacheBadges } from "./cache-badges";
import { CacheManagementDialog } from "@/components/address/cache-management-dialog";
import { AlgoPriceTicker } from "@/components/algo-price-ticker";

export default function AccountStatus({
address,
Expand Down Expand Up @@ -62,7 +63,10 @@ export default function AccountStatus({
</div>
</div>
</div>
<AnxietyCard account={account} />
<div className="flex flex-col-reverse flex-wrap items-start gap-2 sm:flex-row">
<AnxietyCard account={account} />
<AlgoPriceTicker />
</div>
</div>
</div>
);
Expand Down
30 changes: 20 additions & 10 deletions src/components/algo-amount-display.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import AlgorandLogo from "@/components/algorand-logo.tsx";
import { animate, motion, useMotionValue } from "motion/react";
import { useEffect, useState } from "react";
import { useAlgoPrice } from "@/hooks/queries/useAlgoPrice";
import { useSearch } from "@tanstack/react-router";

export default function AlgoAmountDisplay({
microAlgoAmount,
Expand All @@ -17,6 +18,9 @@ export default function AlgoAmountDisplay({
showUsdValue?: boolean;
hidden?: boolean;
}) {
const search = useSearch({ from: "/$addresses" });
const currency = search.currency || "USD";

// Ensure microAlgoAmount is a BigInt
const algoAmount = new AlgoAmount({
microAlgos:
Expand All @@ -28,7 +32,7 @@ export default function AlgoAmountDisplay({
const value = useMotionValue(0);
const [displayValue, setDisplayValue] = useState("0.000");

const { price: algoPrice } = useAlgoPrice();
const { data: algoPrice } = useAlgoPrice(currency);

useEffect(() => {
const algoValue = Number(algoAmount.algos);
Expand Down Expand Up @@ -58,20 +62,26 @@ export default function AlgoAmountDisplay({
}).format(num);
}

// Format USD value
function formatUsdValue(algoValue: number, price: number): string {
const usdValue = algoValue * price;
// Format currency value
function formatCurrencyValue(
algoValue: number,
price: number,
currencyCode: string,
): string {
const currencyValue = algoValue * price;
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
currency: currencyCode,
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(usdValue);
}).format(currencyValue);
}

const algoValue = Number(algoAmount.algos);
const usdValue =
algoPrice && showUsdValue ? formatUsdValue(algoValue, algoPrice) : null;
const currencyValue =
algoPrice && showUsdValue
? formatCurrencyValue(algoValue, algoPrice, currency)
: null;

return (
<span className={`inline-flex flex-col ${className}`}>
Expand All @@ -86,14 +96,14 @@ export default function AlgoAmountDisplay({
</motion.span>
<AlgorandLogo className="ml-0.5" />
</span>
{showUsdValue && usdValue && (
{showUsdValue && currencyValue && (
<motion.span
initial={{ opacity: 0 }}
animate={{ opacity: 0.6 }}
transition={{ duration: 0.5, delay: 0.2 }}
className="w-fit text-xs"
>
{hidden ? "*****" : usdValue}
{hidden ? "*****" : currencyValue}
</motion.span>
)}
</span>
Expand Down
Loading