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
3 changes: 3 additions & 0 deletions src/app/api/pnl/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,7 @@ export async function GET() {
return NextResponse.json(data);
}

<<<<<<< HEAD
=======
// Maintenance: minor update
>>>>>>> upstream/main
3 changes: 3 additions & 0 deletions src/app/api/upload/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,7 @@ export async function POST(request: NextRequest) {
);
}

<<<<<<< HEAD
=======
// Maintenance: minor update
>>>>>>> upstream/main
70 changes: 70 additions & 0 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,19 @@ import Icon from "../components/ui/Icon";
* Manages high-level state for wallet connection, active tabs, and invoice data.
*/
export default function Page() {
<<<<<<< HEAD
// --- Component State ---
/** The public Stellar address of the connected user */
const [address, setAddress] = useState("");
/** List of invoices fetched from the backend pipeline */
const [invoices, setInvoices] = useState([]);
/** Loading state for initial data fetch */
=======
const router = useRouter();
const searchParams = useSearchParams();
const { isConnected, walletAddress, isConnecting } = useWalletConnection();
const [invoices, setInvoices] = useState<InvoiceSummary[]>([]);
>>>>>>> upstream/main
const [loading, setLoading] = useState(false);
/** Controls visibility of the Invoice Minting modal */
const [showMintForm, setShowMintForm] = useState(false);
Expand All @@ -56,6 +65,16 @@ export default function Page() {
const { toggleWatchlist, isInWatchlist } = useWatchlist();
const riskSocketRef = useRef<RiskSocketClient | null>(null);

<<<<<<< HEAD
// --- Handlers ---

/**
* Triggers the Stellar wallet connection flow.
* Supports multiple providers via the stellar-wallets-kit.
*
* @param {WalletType} walletType - The ID of the wallet provider (e.g., Freighter).
*/
=======
// Initialize filters from URL params
const [filters, setFilters] = useState<InvoiceFilters>(() => ({
minApy: parseFloat(searchParams.get('minApy') || '0'),
Expand All @@ -77,18 +96,46 @@ export default function Page() {


// 1. Connect Stellar Wallet (supports Freighter, Albedo, xBull)
>>>>>>> upstream/main
const handleConnectWallet = async (walletType: WalletType) => {
try {
const userInfo = await connectWallet(walletType);
if (userInfo && userInfo.publicKey) {
setAddress(userInfo.publicKey);
<<<<<<< HEAD
console.log("[Dashboard] Wallet connected:", userInfo.publicKey, "Provider:", userInfo.walletType);
}
} catch (e: any) {
console.error("[Dashboard] Connection failed:", e.message);
// In production, this would be a user-friendly toast notification
alert(e.message || "Failed to connect to wallet.");
}
};

/**
* Fetches the latest verified assets from the RWA pipeline.
* Currently points to a local mock API for development.
*/
const fetchInvoices = async () => {
setLoading(true);
try {
// TODO: Replace with environment-aware API base URL
const res = await fetch("http://localhost:3000/invoices");
const data = await res.json();
setInvoices(data);
} catch (e) {
console.warn("[Dashboard] Asset pipeline API not reachable. Check if local server is running.");
} finally {
setLoading(false);
=======
console.log("Wallet connected:", userInfo.publicKey, "Type:", userInfo.walletType);
showSuccess("Wallet connected");
}
} catch (e: unknown) {
const error = e as Error;
console.error("Connection failed:", error.message);
showError(error.message || "Failed to connect to wallet.");
>>>>>>> upstream/main
}
};

Expand Down Expand Up @@ -118,6 +165,24 @@ export default function Page() {
};
}, []);

<<<<<<< HEAD
/**
* Debugging utility for testing transaction status notifications.
*/
const handleTestToast = () => {
const toast = useTransactionToast();
toast.loading();
setTimeout(() => toast.success(), 2000);
};

/**
* Callback triggered when a new invoice is successfully submitted for minting.
*
* @param {any} data - The validated invoice metadata.
*/
const handleInvoiceMint = (data: any) => {
console.log("[Dashboard] Mint request received:", data);
=======
useEffect(() => {
if (!walletAddress) {
riskSocketRef.current?.disconnect();
Expand Down Expand Up @@ -163,6 +228,7 @@ export default function Page() {

const handleInvoiceMint = (data: Record<string, unknown>) => {
console.log("Invoice data received:", data);
>>>>>>> upstream/main
setShowMintForm(false);
// TODO: Initiate Soroban contract call for minting the NFT
};
Expand All @@ -172,7 +238,11 @@ export default function Page() {
/** Tab definitions for the main navigation */
const tabs = [
{ id: "dashboard", label: "Dashboard" },
<<<<<<< HEAD
{ id: "watchlist", label: "Watchlist", icon: <Star size={16} aria-hidden="true" /> },
=======
{ id: "watchlist", label: "Watchlist", icon: <Icon icon={Star} dense /> },
>>>>>>> upstream/main
];


Expand Down
90 changes: 86 additions & 4 deletions src/components/AddTrustlineButton.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,90 @@
<<<<<<< HEAD
/**
* Add Trustline Button Component.
* Encapsulates the logic for establishing a Stellar trustline for a specific asset.
* A trustline is mandatory before an account can hold non-native assets.
*/

import React, { useState } from "react";
import { toast } from "react-hot-toast";
import { Plus, Check, Loader2, ShieldCheck, AlertCircle } from "lucide-react";
=======
"use client";

import React, { useState } from "react";
import { Plus, Check, Loader2 } from "lucide-react";
>>>>>>> upstream/main
import { addTrustline } from "../lib/stellar";
import { dismissToast, showError, showLoading, showSuccess } from "../lib/toast";
import Button from "./ui/Button";
import Icon from "./ui/Icon";

/**
* Props for the AddTrustlineButton component.
*/
interface AddTrustlineButtonProps {
/** The 1-12 character asset code (e.g., "USDC") */
assetCode: string;
/** The public Stellar address of the asset issuer */
assetIssuer: string;
}

/**
* A reusable button that establishes a Trustline for a specific Stellar asset
* using the Freighter wallet extension.
* A specialized button that handles the 'change_trust' operation flow.
*/
export default function AddTrustlineButton({ assetCode, assetIssuer }: AddTrustlineButtonProps) {
// --- Component State ---
/** Current status of the asynchronous trustline operation */
const [status, setStatus] = useState<"idle" | "loading" | "success" | "error">("idle");

/**
* Initiates the trustline transaction flow.
*/
const handleAddTrustline = async () => {
// Prevent redundant clicks
if (status === "loading" || status === "success") return;

setStatus("loading");
<<<<<<< HEAD
const toastId = toast.loading(`Establishing ${assetCode} trustline...`);
=======
const toastId = showLoading(`Requesting ${assetCode} trustline...`);
>>>>>>> upstream/main

try {
// 1. Trigger the Stellar SDK / Wallet transaction
await addTrustline(assetCode, assetIssuer);

setStatus("success");
<<<<<<< HEAD
toast.success(`${assetCode} Trustline Active`, {
id: toastId,
icon: '🛡️'
});

// 2. Revert to idle after 5 seconds to reset UI
=======
dismissToast(toastId);
showSuccess(`${assetCode} Trustline Established!`);

// Revert to idle after 5 seconds
>>>>>>> upstream/main
setTimeout(() => setStatus("idle"), 5000);
console.log(`[AddTrustline] Successfully added ${assetCode} from ${assetIssuer}`);
} catch (error: any) {
console.error(`[AddTrustline] Error:`, error);
console.error(`[AddTrustline] Failed to add ${assetCode}:`, error);
setStatus("error");
<<<<<<< HEAD

// User-friendly error mapping
const errorMsg = error.message?.toLowerCase().includes("denied")
? "Transaction rejected by user"
: `Network error adding ${assetCode}`;

toast.error(errorMsg, { id: toastId });

// 3. Revert to idle after a short delay to allow retry
=======

// Handle rejection vs generic error
const errorMsg = error.message?.includes("denied")
Expand All @@ -47,6 +95,7 @@ export default function AddTrustlineButton({ assetCode, assetIssuer }: AddTrustl
showError(errorMsg);

// Revert to idle after 3 seconds to allow retry
>>>>>>> upstream/main
setTimeout(() => setStatus("idle"), 3000);
}
};
Expand All @@ -56,24 +105,57 @@ export default function AddTrustlineButton({ assetCode, assetIssuer }: AddTrustl
variant="secondary"
onClick={handleAddTrustline}
disabled={status === "loading" || status === "success"}
<<<<<<< HEAD
className={`flex items-center gap-2 text-[10px] font-black uppercase tracking-widest py-2 px-4 h-auto transition-all duration-300 border ${
status === "success"
? "bg-emerald-500/10 text-emerald-400 border-emerald-500/30"
: "bg-slate-800/50 text-slate-400 border-slate-700 hover:border-slate-500 hover:text-white"
}`}
aria-label={`Add trustline for ${assetCode}`}
=======
className={`flex items-center gap-2 text-xs py-1.5 px-3 h-auto transition-all duration-200 ${status === "success" ? "bg-green-600/20 text-green-400 border-green-600/50" : ""
}`}
>>>>>>> upstream/main
>
{/* Dynamic Icon State */}
{status === "loading" ? (
<<<<<<< HEAD
<Loader2 size={12} className="animate-spin text-blue-400" />
) : status === "success" ? (
<ShieldCheck size={12} className="text-emerald-400" />
) : status === "error" ? (
<AlertCircle size={12} className="text-rose-400" />
) : (
<Plus size={12} className="group-hover:rotate-90 transition-transform" />
)}

{/* Dynamic Label State */}
=======
<Icon icon={Loader2} dense className="animate-spin" />
) : status === "success" ? (
<Icon icon={Check} dense />
) : (
<Icon icon={Plus} dense />
)}

>>>>>>> upstream/main
<span>
{status === "loading" ? "Signing..." : status === "success" ? "Trustline Active" : `Add ${assetCode}`}
{status === "loading"
? "Signing..."
: status === "success"
? "Established"
: status === "error"
? "Retry"
: `Add ${assetCode}`
}
</span>
</Button>
);
}

<<<<<<< HEAD
=======
// Inconsequential change for repo health

// Maintenance: minor update
>>>>>>> upstream/main
3 changes: 3 additions & 0 deletions src/components/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ export default function Card({
</div>
);
}
<<<<<<< HEAD
=======
// Inconsequential change for repo health

// Maintenance: minor update
>>>>>>> upstream/main
Loading
Loading