Skip to content

Commit 1ef66a4

Browse files
feat: set invoice to "processing" status after being paid. (#133)
Co-authored-by: MantisClone <[email protected]>
1 parent 72ad639 commit 1ef66a4

File tree

4 files changed

+87
-8
lines changed

4 files changed

+87
-8
lines changed

.env.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ NEXT_PUBLIC_API_TERMS_CONDITIONS="https://request.network/api-terms"
1212

1313
FEE_PERCENTAGE_FOR_PAYMENT=""
1414
FEE_ADDRESS_FOR_PAYMENT=""
15+
REDIS_URL=redis://localhost:7379
1516

1617
# Optional
1718
# NEXT_PUBLIC_GTM_ID=""
1819
# NEXT_PUBLIC_CRYPTO_TO_FIAT_TRUSTED_ORIGINS=""
19-
20+
INVOICE_PROCESSING_TTL=""

src/components/payment-section.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ export function PaymentSection({ serverInvoice }: PaymentSectionProps) {
142142
const { mutateAsync: payRequest } = api.invoice.payRequest.useMutation();
143143
const { mutateAsync: sendPaymentIntent } =
144144
api.invoice.sendPaymentIntent.useMutation();
145+
const { mutateAsync: setInvoiceAsProcessing } =
146+
api.invoice.setInvoiceAsProcessing.useMutation();
147+
145148
const {
146149
data: paymentRoutesData,
147150
refetch,
@@ -375,6 +378,18 @@ export function PaymentSection({ serverInvoice }: PaymentSectionProps) {
375378
} else {
376379
await handleDirectPayments(paymentData, signer);
377380
}
381+
382+
try {
383+
await setInvoiceAsProcessing({
384+
id: invoice.id,
385+
});
386+
} catch (statusError) {
387+
console.error("Status update failed:", statusError);
388+
toast("Payment Successful", {
389+
description:
390+
"Payment confirmed but status update failed. Please refresh.",
391+
});
392+
}
378393
} catch (error) {
379394
console.error("Error : ", error);
380395
toast("Payment Failed", {
@@ -468,7 +483,7 @@ export function PaymentSection({ serverInvoice }: PaymentSectionProps) {
468483
</div>
469484

470485
{/* Payment Steps */}
471-
{paymentStatus !== "paid" && (
486+
{paymentStatus === "pending" && (
472487
<div className="space-y-8">
473488
{/* Step indicators */}
474489
<div className="flex justify-center">
@@ -652,11 +667,7 @@ export function PaymentSection({ serverInvoice }: PaymentSectionProps) {
652667
<Button
653668
onClick={handlePayment}
654669
className="w-full bg-black hover:bg-zinc-800 text-white"
655-
disabled={
656-
paymentProgress !== "idle" ||
657-
!hasRoutes ||
658-
paymentStatus === "processing"
659-
}
670+
disabled={paymentProgress !== "idle" || !hasRoutes}
660671
>
661672
{!hasRoutes ? (
662673
"No payment routes available"

src/lib/redis/index.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import Redis from "ioredis";
2+
3+
let redis: Redis | null = null;
4+
5+
export function getRedis(): Redis {
6+
if (!redis) {
7+
redis = new Redis(process.env.REDIS_URL || "redis://localhost:6379", {
8+
lazyConnect: true,
9+
});
10+
11+
redis.on("error", (err) => {
12+
console.error("Redis connection error:", err);
13+
});
14+
}
15+
16+
return redis;
17+
}

src/server/routers/invoice.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { apiClient } from "@/lib/axios";
22
import { toTRPCError } from "@/lib/errors";
3+
import { getRedis } from "@/lib/redis";
34
import { invoiceFormSchema } from "@/lib/schemas/invoice";
45
import {
56
type PaymentDetailsPayers,
@@ -280,7 +281,24 @@ export const invoiceRouter = router({
280281
});
281282
}
282283

283-
return invoice;
284+
try {
285+
const redis = getRedis();
286+
const isProcessing = await redis.get(`processing:${invoice.id}`);
287+
288+
return {
289+
...invoice,
290+
status:
291+
isProcessing && invoice.status === "pending"
292+
? "processing"
293+
: invoice.status,
294+
};
295+
} catch (error) {
296+
console.warn(
297+
"[invoice.getById] Redis unavailable, falling back to DB status",
298+
error,
299+
);
300+
return invoice;
301+
}
284302
}),
285303
payRequest: publicProcedure
286304
.input(
@@ -462,4 +480,36 @@ export const invoiceRouter = router({
462480

463481
return response.data;
464482
}),
483+
setInvoiceAsProcessing: publicProcedure
484+
.input(
485+
z.object({
486+
id: z.string().ulid(),
487+
}),
488+
)
489+
.mutation(async ({ ctx, input }) => {
490+
const { db } = ctx;
491+
492+
try {
493+
const invoice = await db.query.requestTable.findFirst({
494+
where: (requestTable, { eq }) => eq(requestTable.id, input.id),
495+
});
496+
497+
if (!invoice) {
498+
throw new TRPCError({
499+
code: "NOT_FOUND",
500+
message: "Invoice not found",
501+
});
502+
}
503+
504+
const redis = getRedis();
505+
506+
await redis.setex(
507+
`processing:${invoice.id}`,
508+
Number(process.env.INVOICE_PROCESSING_TTL) || 60,
509+
"true",
510+
);
511+
} catch (error) {
512+
throw toTRPCError(error);
513+
}
514+
}),
465515
});

0 commit comments

Comments
 (0)