first commit
Made-with: Cursor
This commit is contained in:
86
frontend/src/components/DepositSection.tsx
Normal file
86
frontend/src/components/DepositSection.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import QRCode from "qrcode";
|
||||
import { getDeposit, postRedeemCashu, type DepositInfo } from "../api";
|
||||
import { useToast } from "../contexts/ToastContext";
|
||||
|
||||
export function DepositSection() {
|
||||
const [deposit, setDeposit] = useState<DepositInfo | null>(null);
|
||||
const [qrDataUrl, setQrDataUrl] = useState<string | null>(null);
|
||||
const [cashuToken, setCashuToken] = useState("");
|
||||
const [cashuLoading, setCashuLoading] = useState(false);
|
||||
const { showToast } = useToast();
|
||||
|
||||
useEffect(() => {
|
||||
getDeposit().then((d) => {
|
||||
setDeposit(d);
|
||||
const qrContent = d.lightningAddress || d.lnurlp;
|
||||
if (qrContent) QRCode.toDataURL(qrContent, { width: 180 }).then(setQrDataUrl);
|
||||
}).catch(() => setDeposit(null));
|
||||
}, []);
|
||||
|
||||
const copyAddress = () => {
|
||||
if (!deposit?.lightningAddress) return;
|
||||
navigator.clipboard.writeText(deposit.lightningAddress);
|
||||
showToast("Copied");
|
||||
};
|
||||
|
||||
const handleRedeemCashu = async () => {
|
||||
const token = cashuToken.trim();
|
||||
if (!token || !token.toLowerCase().startsWith("cashu")) {
|
||||
showToast("Enter a valid Cashu token (cashuA... or cashuB...)");
|
||||
return;
|
||||
}
|
||||
setCashuLoading(true);
|
||||
try {
|
||||
const result = await postRedeemCashu(token);
|
||||
setCashuToken("");
|
||||
const amount = result.amount ?? result.netAmount ?? result.invoiceAmount;
|
||||
showToast(amount != null ? `Redeemed ${amount} sats to faucet!` : "Cashu token redeemed to faucet.");
|
||||
} catch (e) {
|
||||
showToast(e instanceof Error ? e.message : "Redeem failed");
|
||||
} finally {
|
||||
setCashuLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (!deposit) return null;
|
||||
if (!deposit.lightningAddress && !deposit.lnurlp) return null;
|
||||
|
||||
return (
|
||||
<div className="deposit-box">
|
||||
<h3>Fund the faucet</h3>
|
||||
{deposit.lightningAddress && (
|
||||
<div className="copy-row">
|
||||
<input type="text" readOnly value={deposit.lightningAddress} />
|
||||
<button type="button" onClick={copyAddress}>
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{qrDataUrl && (
|
||||
<div className="qr-wrap">
|
||||
<img src={qrDataUrl} alt="Deposit QR" width={180} height={180} />
|
||||
</div>
|
||||
)}
|
||||
<div className="cashu-redeem">
|
||||
<label className="cashu-redeem-label">Redeem Cashu token to faucet</label>
|
||||
<textarea
|
||||
className="cashu-redeem-input"
|
||||
placeholder="Paste Cashu token (cashuA... or cashuB...)"
|
||||
value={cashuToken}
|
||||
onChange={(e) => setCashuToken(e.target.value)}
|
||||
rows={2}
|
||||
disabled={cashuLoading}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="cashu-redeem-btn"
|
||||
onClick={handleRedeemCashu}
|
||||
disabled={cashuLoading || !cashuToken.trim()}
|
||||
>
|
||||
{cashuLoading ? "Redeeming…" : "Redeem to faucet"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user