first commit

Made-with: Cursor
This commit is contained in:
Michaël
2026-02-26 18:33:00 -03:00
commit 3734365463
76 changed files with 14133 additions and 0 deletions

View 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>
);
}