Skip to content

Commit 168921c

Browse files
authored
Merge pull request #322 from El-swaggerito/task-1
Task 1
2 parents 8a3e778 + b9967c7 commit 168921c

19 files changed

Lines changed: 1184 additions & 82 deletions

src/app/api/pnl/route.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,7 @@ export async function GET() {
4747
return NextResponse.json(data);
4848
}
4949

50+
<<<<<<< HEAD
51+
=======
5052
// Maintenance: minor update
53+
>>>>>>> upstream/main

src/app/api/upload/route.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,7 @@ export async function POST(request: NextRequest) {
2828
);
2929
}
3030

31+
<<<<<<< HEAD
32+
=======
3133
// Maintenance: minor update
34+
>>>>>>> upstream/main

src/app/page.tsx

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,19 @@ import Icon from "../components/ui/Icon";
4040
* Manages high-level state for wallet connection, active tabs, and invoice data.
4141
*/
4242
export default function Page() {
43+
<<<<<<< HEAD
44+
// --- Component State ---
45+
/** The public Stellar address of the connected user */
46+
const [address, setAddress] = useState("");
47+
/** List of invoices fetched from the backend pipeline */
48+
const [invoices, setInvoices] = useState([]);
49+
/** Loading state for initial data fetch */
50+
=======
4351
const router = useRouter();
4452
const searchParams = useSearchParams();
4553
const { isConnected, walletAddress, isConnecting } = useWalletConnection();
4654
const [invoices, setInvoices] = useState<InvoiceSummary[]>([]);
55+
>>>>>>> upstream/main
4756
const [loading, setLoading] = useState(false);
4857
/** Controls visibility of the Invoice Minting modal */
4958
const [showMintForm, setShowMintForm] = useState(false);
@@ -56,6 +65,16 @@ export default function Page() {
5665
const { toggleWatchlist, isInWatchlist } = useWatchlist();
5766
const riskSocketRef = useRef<RiskSocketClient | null>(null);
5867

68+
<<<<<<< HEAD
69+
// --- Handlers ---
70+
71+
/**
72+
* Triggers the Stellar wallet connection flow.
73+
* Supports multiple providers via the stellar-wallets-kit.
74+
*
75+
* @param {WalletType} walletType - The ID of the wallet provider (e.g., Freighter).
76+
*/
77+
=======
5978
// Initialize filters from URL params
6079
const [filters, setFilters] = useState<InvoiceFilters>(() => ({
6180
minApy: parseFloat(searchParams.get('minApy') || '0'),
@@ -77,18 +96,46 @@ export default function Page() {
7796

7897

7998
// 1. Connect Stellar Wallet (supports Freighter, Albedo, xBull)
99+
>>>>>>> upstream/main
80100
const handleConnectWallet = async (walletType: WalletType) => {
81101
try {
82102
const userInfo = await connectWallet(walletType);
83103
if (userInfo && userInfo.publicKey) {
84104
setAddress(userInfo.publicKey);
105+
<<<<<<< HEAD
106+
console.log("[Dashboard] Wallet connected:", userInfo.publicKey, "Provider:", userInfo.walletType);
107+
}
108+
} catch (e: any) {
109+
console.error("[Dashboard] Connection failed:", e.message);
110+
// In production, this would be a user-friendly toast notification
111+
alert(e.message || "Failed to connect to wallet.");
112+
}
113+
};
114+
115+
/**
116+
* Fetches the latest verified assets from the RWA pipeline.
117+
* Currently points to a local mock API for development.
118+
*/
119+
const fetchInvoices = async () => {
120+
setLoading(true);
121+
try {
122+
// TODO: Replace with environment-aware API base URL
123+
const res = await fetch("http://localhost:3000/invoices");
124+
const data = await res.json();
125+
setInvoices(data);
126+
} catch (e) {
127+
console.warn("[Dashboard] Asset pipeline API not reachable. Check if local server is running.");
128+
} finally {
129+
setLoading(false);
130+
=======
85131
console.log("Wallet connected:", userInfo.publicKey, "Type:", userInfo.walletType);
86132
showSuccess("Wallet connected");
87133
}
88134
} catch (e: unknown) {
89135
const error = e as Error;
90136
console.error("Connection failed:", error.message);
91137
showError(error.message || "Failed to connect to wallet.");
138+
>>>>>>> upstream/main
92139
}
93140
};
94141

@@ -118,6 +165,24 @@ export default function Page() {
118165
};
119166
}, []);
120167

168+
<<<<<<< HEAD
169+
/**
170+
* Debugging utility for testing transaction status notifications.
171+
*/
172+
const handleTestToast = () => {
173+
const toast = useTransactionToast();
174+
toast.loading();
175+
setTimeout(() => toast.success(), 2000);
176+
};
177+
178+
/**
179+
* Callback triggered when a new invoice is successfully submitted for minting.
180+
*
181+
* @param {any} data - The validated invoice metadata.
182+
*/
183+
const handleInvoiceMint = (data: any) => {
184+
console.log("[Dashboard] Mint request received:", data);
185+
=======
121186
useEffect(() => {
122187
if (!walletAddress) {
123188
riskSocketRef.current?.disconnect();
@@ -163,6 +228,7 @@ export default function Page() {
163228

164229
const handleInvoiceMint = (data: Record<string, unknown>) => {
165230
console.log("Invoice data received:", data);
231+
>>>>>>> upstream/main
166232
setShowMintForm(false);
167233
// TODO: Initiate Soroban contract call for minting the NFT
168234
};
@@ -172,7 +238,11 @@ export default function Page() {
172238
/** Tab definitions for the main navigation */
173239
const tabs = [
174240
{ id: "dashboard", label: "Dashboard" },
241+
<<<<<<< HEAD
242+
{ id: "watchlist", label: "Watchlist", icon: <Star size={16} aria-hidden="true" /> },
243+
=======
175244
{ id: "watchlist", label: "Watchlist", icon: <Icon icon={Star} dense /> },
245+
>>>>>>> upstream/main
176246
];
177247

178248

src/components/AddTrustlineButton.tsx

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,90 @@
1+
<<<<<<< HEAD
2+
/**
3+
* Add Trustline Button Component.
4+
* Encapsulates the logic for establishing a Stellar trustline for a specific asset.
5+
* A trustline is mandatory before an account can hold non-native assets.
6+
*/
7+
8+
import React, { useState } from "react";
9+
import { toast } from "react-hot-toast";
10+
import { Plus, Check, Loader2, ShieldCheck, AlertCircle } from "lucide-react";
11+
=======
112
"use client";
213

314
import React, { useState } from "react";
415
import { Plus, Check, Loader2 } from "lucide-react";
16+
>>>>>>> upstream/main
517
import { addTrustline } from "../lib/stellar";
618
import { dismissToast, showError, showLoading, showSuccess } from "../lib/toast";
719
import Button from "./ui/Button";
820
import Icon from "./ui/Icon";
921

22+
/**
23+
* Props for the AddTrustlineButton component.
24+
*/
1025
interface AddTrustlineButtonProps {
26+
/** The 1-12 character asset code (e.g., "USDC") */
1127
assetCode: string;
28+
/** The public Stellar address of the asset issuer */
1229
assetIssuer: string;
1330
}
1431

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

40+
/**
41+
* Initiates the trustline transaction flow.
42+
*/
2243
const handleAddTrustline = async () => {
44+
// Prevent redundant clicks
2345
if (status === "loading" || status === "success") return;
2446

2547
setStatus("loading");
48+
<<<<<<< HEAD
49+
const toastId = toast.loading(`Establishing ${assetCode} trustline...`);
50+
=======
2651
const toastId = showLoading(`Requesting ${assetCode} trustline...`);
52+
>>>>>>> upstream/main
2753

2854
try {
55+
// 1. Trigger the Stellar SDK / Wallet transaction
2956
await addTrustline(assetCode, assetIssuer);
3057

3158
setStatus("success");
59+
<<<<<<< HEAD
60+
toast.success(`${assetCode} Trustline Active`, {
61+
id: toastId,
62+
icon: '🛡️'
63+
});
64+
65+
// 2. Revert to idle after 5 seconds to reset UI
66+
=======
3267
dismissToast(toastId);
3368
showSuccess(`${assetCode} Trustline Established!`);
3469

3570
// Revert to idle after 5 seconds
71+
>>>>>>> upstream/main
3672
setTimeout(() => setStatus("idle"), 5000);
73+
console.log(`[AddTrustline] Successfully added ${assetCode} from ${assetIssuer}`);
3774
} catch (error: any) {
38-
console.error(`[AddTrustline] Error:`, error);
75+
console.error(`[AddTrustline] Failed to add ${assetCode}:`, error);
3976
setStatus("error");
77+
<<<<<<< HEAD
78+
79+
// User-friendly error mapping
80+
const errorMsg = error.message?.toLowerCase().includes("denied")
81+
? "Transaction rejected by user"
82+
: `Network error adding ${assetCode}`;
83+
84+
toast.error(errorMsg, { id: toastId });
85+
86+
// 3. Revert to idle after a short delay to allow retry
87+
=======
4088

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

4997
// Revert to idle after 3 seconds to allow retry
98+
>>>>>>> upstream/main
5099
setTimeout(() => setStatus("idle"), 3000);
51100
}
52101
};
@@ -56,24 +105,57 @@ export default function AddTrustlineButton({ assetCode, assetIssuer }: AddTrustl
56105
variant="secondary"
57106
onClick={handleAddTrustline}
58107
disabled={status === "loading" || status === "success"}
108+
<<<<<<< HEAD
109+
className={`flex items-center gap-2 text-[10px] font-black uppercase tracking-widest py-2 px-4 h-auto transition-all duration-300 border ${
110+
status === "success"
111+
? "bg-emerald-500/10 text-emerald-400 border-emerald-500/30"
112+
: "bg-slate-800/50 text-slate-400 border-slate-700 hover:border-slate-500 hover:text-white"
113+
}`}
114+
aria-label={`Add trustline for ${assetCode}`}
115+
=======
59116
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" : ""
60117
}`}
118+
>>>>>>> upstream/main
61119
>
120+
{/* Dynamic Icon State */}
62121
{status === "loading" ? (
122+
<<<<<<< HEAD
123+
<Loader2 size={12} className="animate-spin text-blue-400" />
124+
) : status === "success" ? (
125+
<ShieldCheck size={12} className="text-emerald-400" />
126+
) : status === "error" ? (
127+
<AlertCircle size={12} className="text-rose-400" />
128+
) : (
129+
<Plus size={12} className="group-hover:rotate-90 transition-transform" />
130+
)}
131+
132+
{/* Dynamic Label State */}
133+
=======
63134
<Icon icon={Loader2} dense className="animate-spin" />
64135
) : status === "success" ? (
65136
<Icon icon={Check} dense />
66137
) : (
67138
<Icon icon={Plus} dense />
68139
)}
69140

141+
>>>>>>> upstream/main
70142
<span>
71-
{status === "loading" ? "Signing..." : status === "success" ? "Trustline Active" : `Add ${assetCode}`}
143+
{status === "loading"
144+
? "Signing..."
145+
: status === "success"
146+
? "Established"
147+
: status === "error"
148+
? "Retry"
149+
: `Add ${assetCode}`
150+
}
72151
</span>
73152
</Button>
74153
);
75154
}
76155

156+
<<<<<<< HEAD
157+
=======
77158
// Inconsequential change for repo health
78159

79160
// Maintenance: minor update
161+
>>>>>>> upstream/main

src/components/Card.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ export default function Card({
5151
</div>
5252
);
5353
}
54+
<<<<<<< HEAD
55+
=======
5456
// Inconsequential change for repo health
5557

5658
// Maintenance: minor update
59+
>>>>>>> upstream/main

0 commit comments

Comments
 (0)