Skip to content
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
4 changes: 2 additions & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { Suspense } from "react";
import { NetworkProvider } from "@/contexts/NetworkContext";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Check if NetworkProvider is used within src/app/layout.tsx
cat src/app/layout.tsx

Repository: Trustless-Work/escrow-viewer

Length of output: 1960


🏁 Script executed:

# Search for NetworkProvider usage outside of layout.tsx and NetworkContext definition
rg -n "NetworkProvider" --type ts --type tsx -g '!src/app/layout.tsx' -g '!src/contexts/NetworkContext*'

Repository: Trustless-Work/escrow-viewer

Length of output: 99


🏁 Script executed:

# Search for NetworkProvider usage excluding layout.tsx and NetworkContext definition
rg "NetworkProvider" --type-add 'web:*.{ts,tsx}' -t web -g '!src/app/layout.tsx' -g '!src/contexts/NetworkContext*'

Repository: Trustless-Work/escrow-viewer

Length of output: 54


🏁 Script executed:

# Alternative: simple grep-based search
rg "NetworkProvider" -g '!src/app/layout.tsx' -g '!src/contexts/NetworkContext*'

Repository: Trustless-Work/escrow-viewer

Length of output: 54


Remove the unused NetworkProvider import

NetworkProvider is imported on line 5 but not used anywhere in this file or elsewhere in the codebase. Remove this dead code import.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/layout.tsx` at line 5, Remove the unused import of NetworkProvider
from src/app/layout.tsx: locate the import statement that references
NetworkProvider and delete it (the symbol to remove is NetworkProvider). Ensure
no other references to NetworkProvider remain in this file; run a quick search
for NetworkProvider to confirm it's not used before committing.

import { ThemeProvider } from "next-themes";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

ThemeProvider is imported but never rendered — themes are non-functional

Despite the stated goal of resolving theme hydration by adopting next-themes, ThemeProvider is never placed in the JSX tree. Without it wrapping the app, useTheme() calls in child components will fall back to defaults and theme switching will have no effect. See the proposed fix in the {children} comment above — ThemeProvider should wrap the Suspense block.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/layout.tsx` at line 6, ThemeProvider is imported but not rendered, so
child useTheme() calls won't work; wrap the existing <Suspense> ... {children}
block with <ThemeProvider> (so ThemeProvider is the parent of Suspense and the
app children) and pass any required props (e.g., defaultTheme or attribute) as
needed for your setup; ensure you remove the unused import warning by keeping
the import and placing ThemeProvider around the {children} subtree where
Suspense is mounted so theme context is available to components using
useTheme().


// Work around Node.js experimental localStorage mismatch in dev server
// (prevents Next dev overlay from crashing when localStorage is non-standard)
Expand Down Expand Up @@ -52,13 +53,12 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
<html lang="en">
<html lang="en" suppressHydrationWarning>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

suppressHydrationWarning on <html> fires unconditionally in production

The customBodyProps pattern on <body> (lines 45–48) correctly gates the warning suppression to development only. The new suppressHydrationWarning on <html> has no such guard, so real hydration mismatches on the root element will be silently swallowed in production.

🛡️ Proposed fix — mirror the dev-only guard from customBodyProps
-    <html lang="en" suppressHydrationWarning>
+    <html
+      lang="en"
+      {...(process.env.NODE_ENV === "development"
+        ? { suppressHydrationWarning: true }
+        : {})}
+    >

Alternatively, consolidate both customBodyProps and this new guard into a shared devProps constant.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<html lang="en" suppressHydrationWarning>
<html
lang="en"
{...(process.env.NODE_ENV === "development"
? { suppressHydrationWarning: true }
: {})}
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/layout.tsx` at line 56, The <html> element currently sets
suppressHydrationWarning unconditionally; update layout.tsx to only add
suppressHydrationWarning in development by following the same pattern used for
customBodyProps (i.e., compute dev-only props when process.env.NODE_ENV ===
'development' or a shared isDev flag) and spread those onto <html>, or factor
customBodyProps and the html dev prop into a shared devProps constant and spread
devProps into both <html> and <body> so the suppression is gated to dev only.

<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
{...customBodyProps}
>
<Suspense fallback={<div>Loading...</div>}>
<NetworkProvider>{children}</NetworkProvider>
</Suspense>
Comment on lines 61 to 62
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

{children} is missing — the entire app renders blank

The <Suspense> block has no children. Every page/route's content is silently swallowed; the rendered HTML body will be empty. This is an app-breaking regression introduced when NetworkProvider was removed without preserving the {children} pass-through.

🐛 Proposed fix — restore children and wrap with ThemeProvider
-        <Suspense fallback={<div>Loading...</div>}>
-        </Suspense>
+        <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
+          <Suspense fallback={<div>Loading...</div>}>
+            {children}
+          </Suspense>
+        </ThemeProvider>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Suspense fallback={<div>Loading...</div>}>
<NetworkProvider>{children}</NetworkProvider>
</Suspense>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<Suspense fallback={<div>Loading...</div>}>
{children}
</Suspense>
</ThemeProvider>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/layout.tsx` around lines 61 - 62, The Suspense block in layout.tsx is
empty and swallows all page content; restore the JSX pass-through by placing the
{children} inside the Suspense (i.e., <Suspense
fallback={...}>{children}</Suspense>) so routes render again, and additionally
wrap the children with the ThemeProvider component (e.g.,
<ThemeProvider>{children}</ThemeProvider>) to preserve theming; update the
layout component where Suspense is used to nest ThemeProvider around {children}
(or vice versa per app conventions) and remove the empty Suspense placeholder.

</body>
</html>
Expand Down
68 changes: 11 additions & 57 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,26 @@ import { EXAMPLE_CONTRACT_IDS } from "@/lib/escrow-constants";
import type { NextPage } from "next";
import { useRouter } from "next/navigation";
import { useNetwork } from "@/contexts/NetworkContext";
import { getNetworkConfig } from "@/lib/network-config";

const inter = Inter({ subsets: ["latin"] });

const Home: NextPage = () => {
const router = useRouter();
const { currentNetwork } = useNetwork();
const { currentNetwork, setNetwork } = useNetwork();
const [contractId, setContractId] = useState<string>("");
const [error, setError] = useState<string | null>(null);
const [isSearchFocused, setIsSearchFocused] = useState<boolean>(false);

// Network switching for error recovery
const otherNetwork = currentNetwork === 'testnet' ? 'mainnet' : 'testnet';
const switchNetworkLabel = `Try ${getNetworkConfig(otherNetwork).name}`;
const handleSwitchNetwork = () => {
setNetwork(otherNetwork);
// Clear error when switching networks
setError(null);
};

// Responsive: detect mobile for SearchCard behaviour

const handleNavigate = async () => {
Expand Down Expand Up @@ -53,62 +63,6 @@ const Home: NextPage = () => {
<div className="relative">
<div className="relative bg-white/95 dark:bg-card rounded-3xl p-8 md:p-12 shadow-2xl border border-gray-200/60 dark:border-border">
<section className="flex flex-col-reverse md:flex-row items-center gap-8 md:gap-16">
{/* Left: text */}
<div className="flex-1 flex flex-col items-center md:items-start text-center md:text-left">
<motion.h1
className="text-4xl md:text-5xl font-extrabold text-foreground leading-tight"
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
Escrow Data <span className="text-primary">Viewer</span>
</motion.h1>

<motion.p
className="mt-4 text-lg md:text-xl text-muted-foreground max-w-2xl"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.15, duration: 0.5 }}
>
View detailed information about any escrow contract on the
Stellar blockchain.
</motion.p>

<div className="mt-6 w-full max-w-lg">
{/* Keep the existing search card for discoverability */}
<SearchCard
contractId={contractId}
setContractId={setContractId}
loading={false}
isSearchFocused={isSearchFocused}
setIsSearchFocused={setIsSearchFocused}
handleKeyDown={handleKeyDown}
fetchEscrowData={handleNavigate}
handleUseExample={handleUseExample}
/>

<ErrorDisplay error={error} />
</div>
</div>

{/* Right: image (flexes) */}
<motion.div
className="flex-1 flex justify-center md:justify-end"
initial={{ opacity: 0, scale: 0.98 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: 0.2, duration: 0.6 }}
>
<div className="w-full max-w-md md:max-w-xl flex items-center justify-center">
<Image
src="/logo.png"
alt="Escrow Viewer illustration"
width={350}
height={350}
priority
/>
</div>
</motion.div>
</section>
</div>
</div>
</main>
Expand Down
Loading