Skip to content

Commit f0ca805

Browse files
authored
Merge pull request #191 from MeshJS/feature/UX-info-page
Feature/ux info page
2 parents bc00729 + 83e55ef commit f0ca805

File tree

31 files changed

+959
-768
lines changed

31 files changed

+959
-768
lines changed

src/components/common/card-content.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@ export default function CardUI({
1616
cardClassName?: string;
1717
headerDom?: ReactNode;
1818
}) {
19+
// Make title larger for wallet info card (col-span-2)
20+
const isLargeTitle = cardClassName?.includes('col-span-2');
21+
1922
return (
2023
<Card className={`w-full max-w-4xl ${cardClassName}`}>
2124
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
22-
<CardTitle className="text-xl font-medium">{title}</CardTitle>
25+
<CardTitle className={isLargeTitle ? "text-2xl sm:text-3xl font-semibold" : "text-xl font-medium"}>{title}</CardTitle>
2326
{headerDom && headerDom}
2427
{icon && (
2528
<>
@@ -33,7 +36,7 @@ export default function CardUI({
3336
</>
3437
)}
3538
</CardHeader>
36-
<CardContent className="overflow-y-auto max-h-[calc(100vh-200px)]">
39+
<CardContent>
3740
<div className="mt-1 flex flex-col gap-2">
3841
{description && (
3942
<p className="text-sm text-muted-foreground">{description}</p>

src/components/common/discordIcon.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
export default function DiscordIcon() {
1+
interface DiscordIconProps {
2+
className?: string;
3+
}
4+
5+
export default function DiscordIcon({ className }: DiscordIconProps) {
26
return (
37
<svg
48
xmlns="http://www.w3.org/2000/svg"
59
width="16"
610
height="16"
711
fill="currentColor"
812
viewBox="0 0 16 16"
13+
className={className}
914
>
1015
<path d="M13.545 2.907a13.2 13.2 0 0 0-3.257-1.011.05.05 0 0 0-.052.025c-.141.25-.297.577-.406.833a12.2 12.2 0 0 0-3.658 0 8 8 0 0 0-.412-.833.05.05 0 0 0-.052-.025c-1.125.194-2.22.534-3.257 1.011a.04.04 0 0 0-.021.018C.356 6.024-.213 9.047.066 12.032q.003.022.021.037a13.3 13.3 0 0 0 3.995 2.02.05.05 0 0 0 .056-.019q.463-.63.818-1.329a.05.05 0 0 0-.01-.059l-.018-.011a9 9 0 0 1-1.248-.595.05.05 0 0 1-.02-.066l.015-.019q.127-.095.248-.195a.05.05 0 0 1 .051-.007c2.619 1.196 5.454 1.196 8.041 0a.05.05 0 0 1 .053.007q.121.1.248.195a.05.05 0 0 1-.004.085 8 8 0 0 1-1.249.594.05.05 0 0 0-.03.03.05.05 0 0 0 .003.041c.24.465.515.909.817 1.329a.05.05 0 0 0 .056.019 13.2 13.2 0 0 0 4.001-2.02.05.05 0 0 0 .021-.037c.334-3.451-.559-6.449-2.366-9.106a.03.03 0 0 0-.02-.019m-8.198 7.307c-.789 0-1.438-.724-1.438-1.612s.637-1.613 1.438-1.613c.807 0 1.45.73 1.438 1.613 0 .888-.637 1.612-1.438 1.612m5.316 0c-.788 0-1.438-.724-1.438-1.612s.637-1.613 1.438-1.613c.807 0 1.451.73 1.438 1.613 0 .888-.631 1.612-1.438 1.612" />
1116
</svg>

src/components/common/overall-layout/layout.tsx

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -371,19 +371,35 @@ export default function RootLayout({
371371
// Don't refetch here - let the natural query refetch handle it if needed
372372
}, []);
373373

374-
const handleAuthModalAuthorized = useCallback(() => {
374+
const handleAuthModalAuthorized = useCallback(async () => {
375375
setShowAuthModal(false);
376376
setCheckingSession(false);
377377
setHasCheckedSession(true); // Mark as checked so we don't check again
378378
// Show loading skeleton for smooth transition
379379
setShowPostAuthLoading(true);
380-
// Refetch session after authorization to update state (but don't show modal again)
381-
void refetchWalletSession();
380+
381+
// Wait a moment for the cookie to be set by the browser, then refetch session
382+
await new Promise(resolve => setTimeout(resolve, 200));
383+
384+
// Refetch session to update state
385+
await refetchWalletSession();
386+
387+
// Invalidate wallet queries so they refetch with the new session
388+
// Use a small delay to ensure cookie is available on subsequent requests
389+
setTimeout(() => {
390+
const userAddressForInvalidation = userAddress || address;
391+
if (userAddressForInvalidation) {
392+
void ctx.wallet.getUserWallets.invalidate({ address: userAddressForInvalidation });
393+
void ctx.wallet.getUserNewWallets.invalidate({ address: userAddressForInvalidation });
394+
void ctx.wallet.getUserNewWalletsNotOwner.invalidate({ address: userAddressForInvalidation });
395+
}
396+
}, 300);
397+
382398
// Hide loading after a brief delay to allow data to load
383399
setTimeout(() => {
384400
setShowPostAuthLoading(false);
385-
}, 1000);
386-
}, [refetchWalletSession]);
401+
}, 1500);
402+
}, [refetchWalletSession, ctx.wallet, userAddress, address]);
387403

388404
// Memoize computed route values
389405
const isWalletPath = useMemo(() => router.pathname.includes("/wallets/[wallet]"), [router.pathname]);

src/components/common/overall-layout/mobile-wrappers/wallet-data-loader-wrapper.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,9 @@ export default function WalletDataLoaderWrapper({
160160
}
161161

162162
function dRepIds() {
163-
// Use multisig wallet DRep ID if available, otherwise fallback to appWallet
164-
const dRepId = multisigWallet?.getKeysByRole(3) ? multisigWallet?.getDRepId() : appWallet?.dRepId;
163+
// Use multisig wallet DRep ID if available (it handles no DRep keys by using payment script),
164+
// otherwise fallback to appWallet (for legacy wallets without multisigWallet)
165+
const dRepId = multisigWallet ? multisigWallet.getDRepId() : appWallet?.dRepId;
165166
if (!dRepId) return null;
166167
return getDRepIds(dRepId);
167168
}

src/components/multisig/proxy/ProxyOverview.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { memo, useState, useEffect } from "react";
2+
import { truncateTokenSymbol } from "@/utils/strings";
23
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
34
import { Badge } from "@/components/ui/badge";
45
import { Button } from "@/components/ui/button";
@@ -270,7 +271,7 @@ const ProxyCard = memo(function ProxyCard({
270271
<div className="text-sm space-y-1">
271272
{displayBalance.map((asset: any, index: number) => (
272273
<div key={index} className="flex justify-between">
273-
<span>{asset.unit === "lovelace" ? "ADA" : asset.unit}:</span>
274+
<span>{asset.unit === "lovelace" ? "ADA" : truncateTokenSymbol(asset.unit)}:</span>
274275
<span className="font-mono">
275276
{asset.unit === "lovelace"
276277
? `${(parseFloat(asset.quantity) / 1000000).toFixed(6)} ADA`

src/components/multisig/proxy/ProxySpend.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { memo } from "react";
2+
import { truncateTokenSymbol } from "@/utils/strings";
23
import { Button } from "@/components/ui/button";
34
import { Input } from "@/components/ui/input";
45
import { Label } from "@/components/ui/label";
@@ -139,7 +140,7 @@ const ProxySpend = memo(function ProxySpend({
139140
<div key={index} className="flex items-center justify-between p-3 border rounded-lg bg-muted/50">
140141
<div className="flex items-center gap-2">
141142
<Badge variant="secondary">
142-
{asset.unit === "lovelace" ? "ADA" : asset.unit}
143+
{asset.unit === "lovelace" ? "ADA" : truncateTokenSymbol(asset.unit)}
143144
</Badge>
144145
<span className="font-mono text-sm">
145146
{asset.unit === "lovelace"

src/components/pages/homepage/wallets/index.tsx

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ import { getFirstAndLast } from "@/utils/strings";
99
import { api } from "@/utils/api";
1010
import { useUserStore } from "@/lib/zustand/user";
1111
import { useSiteStore } from "@/lib/zustand/site";
12-
import { buildMultisigWallet } from "@/utils/common";
12+
import { buildMultisigWallet, getWalletType } from "@/utils/common";
1313
import { addressToNetwork } from "@/utils/multisigSDK";
1414

1515
import { Button } from "@/components/ui/button";
16+
import { Badge } from "@/components/ui/badge";
17+
import { Archive } from "lucide-react";
1618
import PageHeader from "@/components/common/page-header";
1719
import CardUI from "@/components/common/card-content";
1820
import RowLabelInfo from "@/components/common/row-label-info";
@@ -29,10 +31,21 @@ export default function PageWallets() {
2931
const [showArchived, setShowArchived] = useState(false);
3032
const userAddress = useUserStore((state) => state.userAddress);
3133

34+
// Check wallet session authorization before enabling queries
35+
const { data: walletSession } = api.auth.getWalletSession.useQuery(
36+
{ address: userAddress ?? "" },
37+
{
38+
enabled: !!userAddress && userAddress.length > 0,
39+
refetchOnWindowFocus: false,
40+
},
41+
);
42+
const isAuthorized = walletSession?.authorized ?? false;
43+
3244
const { data: newPendingWallets, isLoading: isLoadingNewWallets } = api.wallet.getUserNewWallets.useQuery(
3345
{ address: userAddress! },
3446
{
35-
enabled: userAddress !== undefined,
47+
// Only enable query when user is authorized (prevents 403 errors)
48+
enabled: userAddress !== undefined && isAuthorized,
3649
retry: (failureCount, error) => {
3750
// Don't retry on authorization errors (403)
3851
if (error && typeof error === "object") {
@@ -60,15 +73,24 @@ export default function PageWallets() {
6073
api.wallet.getUserNewWalletsNotOwner.useQuery(
6174
{ address: userAddress! },
6275
{
63-
enabled: userAddress !== undefined,
76+
// Only enable query when user is authorized (prevents 403 errors)
77+
enabled: userAddress !== undefined && isAuthorized,
6478
retry: (failureCount, error) => {
6579
// Don't retry on authorization errors (403)
6680
if (error && typeof error === "object") {
67-
const err = error as { code?: string; message?: string; data?: { code?: string } };
81+
const err = error as {
82+
code?: string;
83+
message?: string;
84+
data?: { code?: string; httpStatus?: number };
85+
shape?: { code?: string; message?: string };
86+
};
87+
const errorMessage = err.message || err.shape?.message || "";
6888
const isAuthError =
6989
err.code === "FORBIDDEN" ||
7090
err.data?.code === "FORBIDDEN" ||
71-
err.message?.includes("Address mismatch");
91+
err.data?.httpStatus === 403 ||
92+
err.shape?.code === "FORBIDDEN" ||
93+
errorMessage.includes("Address mismatch");
7294
if (isAuthError) return false;
7395
}
7496
return failureCount < 1;
@@ -216,6 +238,11 @@ function CardWallet({
216238
walletId: wallet.id,
217239
});
218240

241+
// Check wallet type for badge display using centralized detection
242+
const walletType = getWalletType(wallet);
243+
const isSummonWallet = walletType === 'summon';
244+
const isLegacyWallet = walletType === 'legacy';
245+
219246
// Rebuild the multisig wallet to get the correct canonical address for display
220247
// This ensures we show the correct address even if wallet.address was built incorrectly
221248
const displayAddress = useMemo(() => {
@@ -240,6 +267,17 @@ function CardWallet({
240267
title={`${wallet.name}${wallet.isArchived ? " (Archived)" : ""}`}
241268
description={wallet.description}
242269
cardClassName=""
270+
headerDom={
271+
isSummonWallet ? (
272+
<Badge
273+
variant="outline"
274+
className="text-xs bg-orange-600/10 border-orange-600/30 text-orange-700 dark:text-orange-400"
275+
>
276+
<Archive className="h-3 w-3 mr-1" />
277+
Summon
278+
</Badge>
279+
) : undefined
280+
}
243281
>
244282
<WalletBalance balance={balance} loadingState={loadingState} />
245283
<RowLabelInfo

src/components/pages/homepage/wallets/new-wallet-flow/ready/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { api } from "@/utils/api";
66
import { useToast } from "@/hooks/use-toast";
77
import { useUserStore } from "@/lib/zustand/user";
88
import { useSiteStore } from "@/lib/zustand/site";
9-
import { buildWallet } from "@/hooks/common";
9+
import { buildWallet } from "@/utils/common";
1010

1111
import PageHeader from "@/components/common/page-header";
1212
import {

src/components/pages/wallet/governance/ballot/ballot.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,6 @@ export default function BallotCard({
285285
const proxy = proxies.find((p: any) => p.id === selectedProxyId);
286286
if (!proxy) throw new Error("Proxy not found");
287287

288-
if (!multisigWallet) throw new Error("Multisig Wallet could not be built.");
289288
const meshTxBuilder = getTxBuilder(network);
290289
const proxyContract = new MeshProxyContract(
291290
{
@@ -314,7 +313,12 @@ export default function BallotCard({
314313
});
315314

316315
// Vote using proxy
317-
const txBuilder = await proxyContract.voteProxyDrep(votes, utxos, multisigWallet?.getScript().address);
316+
// Use multisig wallet address if available, otherwise fallback to appWallet (for legacy wallets)
317+
const proxyAddress = multisigWallet?.getScript().address || appWallet?.address;
318+
if (!proxyAddress) {
319+
throw new Error("Wallet address not found");
320+
}
321+
const txBuilder = await proxyContract.voteProxyDrep(votes, utxos, proxyAddress);
318322

319323
await newTransaction({
320324
txBuilder: txBuilder,
@@ -401,8 +405,9 @@ export default function BallotCard({
401405

402406
setLoading(true);
403407
try {
404-
if (!multisigWallet) throw new Error("Multisig Wallet could not be built.");
405-
const dRepId = multisigWallet?.getKeysByRole(3) ? multisigWallet?.getDRepId() : appWallet?.dRepId;
408+
// Use multisig wallet DRep ID if available (it handles no DRep keys by using payment script),
409+
// otherwise fallback to appWallet (for legacy wallets without multisigWallet)
410+
const dRepId = multisigWallet ? multisigWallet.getDRepId() : appWallet?.dRepId;
406411
if (!dRepId) {
407412
setAlert("DRep not found");
408413
toast({

src/components/pages/wallet/governance/card-info.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ export default function CardInfo({ appWallet, manualUtxos }: { appWallet: Wallet
5656
} | null>(null);
5757

5858
// Get DRep info for standard mode
59-
const currentDrepId = multisigWallet?.getKeysByRole(3) ? multisigWallet?.getDRepId() : appWallet?.dRepId;
59+
// Use multisig wallet DRep ID if available (it handles no DRep keys by using payment script),
60+
// otherwise fallback to appWallet (for legacy wallets without multisigWallet)
61+
const currentDrepId = multisigWallet ? multisigWallet.getDRepId() : appWallet?.dRepId;
6062
const currentDrepInfo = drepInfo;
6163

6264

0 commit comments

Comments
 (0)