Skip to content

Commit 7aaceb7

Browse files
authored
Fix/invoice wallet select v2 (#487)
* fix(invoice): auto-select worker's coinpay wallet when poster creates invoice Fixes #478. When the poster initiates an invoice on behalf of the worker, the frontend no longer forces the poster to select a CoinPay receiving wallet (which they wouldn't have access to). The backend API now automatically falls back to selecting the worker's CoinPay wallet matching the gig's payment coin. * fix(invoice): isWorker prop and fuzzy matching * fix(invoice): correct fuzzy match to use raw gig.payment_coin base
1 parent 1518a5e commit 7aaceb7

2 files changed

Lines changed: 46 additions & 21 deletions

File tree

src/app/api/gigs/[id]/invoice/route.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -335,16 +335,6 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
335335
);
336336
}
337337

338-
const selectedCurrency = preferredCoinToPaymentCurrency(payment_currency || null);
339-
const selectedAddress = merchant_wallet_address?.trim() || "";
340-
341-
if (!selectedCurrency || !selectedAddress) {
342-
return NextResponse.json(
343-
{ error: "Select a CoinPay receiving wallet before sending the invoice" },
344-
{ status: 400 }
345-
);
346-
}
347-
348338
const workerCoinpayToken = await getConnectedCoinpayAccessToken(workerId);
349339
if (!workerCoinpayToken) {
350340
return NextResponse.json(
@@ -375,6 +365,28 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
375365
);
376366
}
377367

368+
let selectedCurrency = preferredCoinToPaymentCurrency(payment_currency || null);
369+
let selectedAddress = merchant_wallet_address?.trim() || "";
370+
371+
if (!selectedCurrency || !selectedAddress) {
372+
const baseCoin = (gig.payment_coin || "").trim().toLowerCase();
373+
const gigCoin = preferredCoinToPaymentCurrency(gig.payment_coin || null);
374+
const preferred = workerWallets.find((w) => {
375+
const wc = w.currency.toLowerCase();
376+
return wc === gigCoin?.toLowerCase() || (baseCoin && (wc === baseCoin || wc.startsWith(`${baseCoin}_`)));
377+
}) || workerWallets[0];
378+
379+
if (preferred) {
380+
selectedCurrency = preferred.currency;
381+
selectedAddress = preferred.address;
382+
} else {
383+
return NextResponse.json(
384+
{ error: "Select a CoinPay receiving wallet before sending the invoice" },
385+
{ status: 400 }
386+
);
387+
}
388+
}
389+
378390
const selectedWallet = findCoinpayGlobalWallet(
379391
workerWallets,
380392
selectedCurrency,

src/components/gigs/InvoiceButton.tsx

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -234,12 +234,19 @@ export function InvoiceButton({
234234

235235
setIsCreating(true);
236236
setError(null);
237-
const selectedWallet =
238-
wallets.find((wallet) => walletKey(wallet) === selectedWalletKey) || null;
239-
if (!selectedWallet) {
240-
setError("Select a CoinPay receiving wallet");
241-
setIsCreating(false);
242-
return;
237+
let selectedWalletCurrency: string | undefined;
238+
let selectedWalletAddress: string | undefined;
239+
240+
if (isWorker) {
241+
const selectedWallet =
242+
wallets.find((wallet) => walletKey(wallet) === selectedWalletKey) || null;
243+
if (!selectedWallet) {
244+
setError("Select a CoinPay receiving wallet");
245+
setIsCreating(false);
246+
return;
247+
}
248+
selectedWalletCurrency = selectedWallet.currency;
249+
selectedWalletAddress = selectedWallet.address;
243250
}
244251

245252
try {
@@ -251,8 +258,8 @@ export function InvoiceButton({
251258
items: lineItems,
252259
amount: total,
253260
currency: "USD",
254-
payment_currency: selectedWallet.currency,
255-
merchant_wallet_address: selectedWallet.address,
261+
payment_currency: selectedWalletCurrency,
262+
merchant_wallet_address: selectedWalletAddress,
256263
notes: notes || undefined,
257264
due_date: dueDate || undefined,
258265
pr_links: prLinks.length > 0 ? prLinks : undefined,
@@ -545,6 +552,7 @@ export function InvoiceButton({
545552

546553
{isWorker && showForm && (
547554
<InvoiceForm
555+
isWorker={isWorker}
548556
isSats={isSats}
549557
capAmount={capAmount}
550558
items={items}
@@ -580,6 +588,7 @@ export function InvoiceButton({
580588
if (showForm) {
581589
return (
582590
<InvoiceForm
591+
isWorker={isWorker}
583592
isSats={isSats}
584593
capAmount={capAmount}
585594
items={items}
@@ -630,6 +639,7 @@ export function InvoiceButton({
630639
type LineItem = { description: string; quantity: string; unit_price: string; link: string };
631640

632641
function InvoiceForm({
642+
isWorker,
633643
isSats,
634644
capAmount,
635645
items,
@@ -652,6 +662,7 @@ function InvoiceForm({
652662
onSubmit,
653663
onCancel,
654664
}: {
665+
isWorker: boolean;
655666
isSats: boolean;
656667
capAmount: number | null;
657668
items: LineItem[];
@@ -844,7 +855,8 @@ function InvoiceForm({
844855
/>
845856
</div>
846857

847-
<div className="space-y-2 rounded-md border border-border bg-background p-3">
858+
{isWorker && (
859+
<div className="space-y-2 rounded-md border border-border bg-background p-3">
848860
<div className="flex items-center justify-between gap-3">
849861
<label className="text-xs font-medium text-muted-foreground">
850862
CoinPay receiving wallet
@@ -906,14 +918,15 @@ function InvoiceForm({
906918
)}
907919
</div>
908920
)}
909-
</div>
921+
</div>
922+
)}
910923

911924
{error && <p className="text-sm text-destructive">{error}</p>}
912925

913926
<div className="flex gap-2">
914927
<Button
915928
onClick={onSubmit}
916-
disabled={isCreating || total <= 0 || overCap || !hasWallets}
929+
disabled={isCreating || total <= 0 || overCap || (isWorker && !hasWallets)}
917930
className="flex-1"
918931
size="sm"
919932
>

0 commit comments

Comments
 (0)