-
Notifications
You must be signed in to change notification settings - Fork 2
feat: creating recurring payments and set up webhook for payments #83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat/19-manage-recurring-payments
Are you sure you want to change the base?
feat: creating recurring payments and set up webhook for payments #83
Conversation
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThe changes introduce full-stack support for recurring payments, including new schemas, database fields, and API procedures. A two-step React UI for creating recurring payments is added, along with form validation and wallet integration. The backend supports recurring payment creation, signature submission, and payment tracking. Batch and direct payment forms are refactored for schema consistency and a reusable security notice component is introduced. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as CreateRecurringPayment
participant Form as CreateRecurringPaymentForm
participant Wallet
participant Server
participant DB
User->>UI: Open recurring payment creation page
UI->>Wallet: Check wallet connection
alt Not connected
UI->>User: Prompt to connect wallet
User->>Wallet: Connect wallet
end
UI->>Form: Render recurring payment form
User->>Form: Fill form and submit
Form->>Wallet: Request transaction approval
Wallet-->>Form: Transaction confirmed
Form->>Wallet: Request permit signature
Wallet-->>Form: Signature provided
Form->>Server: Submit recurring payment data
Server->>DB: Insert new recurring payment record
DB-->>Server: Success
Server-->>Form: Return new recurring payment
Form->>Server: Submit permit signature
Server->>DB: Update recurring payment with signature
DB-->>Server: Success
Server-->>Form: Confirm recurring payment setup
Form->>User: Show success and redirect
sequenceDiagram
participant Webhook
participant Server
participant DB
Webhook->>Server: POST "payment.confirmed" event
alt Recurring payment (recurringPayment.id present)
Server->>DB: Find recurring payment by externalPaymentId
DB-->>Server: Return recurring payment
Server->>DB: Append payment to payments array, update count
DB-->>Server: Success
else Non-recurring payment
Server->>DB: Update request status to "crypto_paid" or "paid"
DB-->>Server: Success
end
Server-->>Webhook: Respond
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
a072029
to
229b3f2
Compare
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (6)
src/lib/constants/currencies.ts (1)
72-79
: Consider reusing existing constants to avoid duplication.The implementation is correct and follows established patterns. However, these currencies already exist in
TESTNET_CURRENCIES
. Consider derivingRECURRING_PAYMENT_CURRENCIES
from the existing array to maintain single source of truth:-export const RECURRING_PAYMENT_CURRENCIES = [ - "FAU-sepolia", - "fUSDC-sepolia", - "fUSDT-sepolia", -] as const; +export const RECURRING_PAYMENT_CURRENCIES = [ + TESTNET_CURRENCIES[1], // "FAU-sepolia" + TESTNET_CURRENCIES[2], // "fUSDC-sepolia" + TESTNET_CURRENCIES[3], // "fUSDT-sepolia" +] as const;Or filter from TESTNET_CURRENCIES to make the relationship explicit.
src/components/payment-secured-using-request.tsx (1)
1-13
: LGTM: Well-designed reusable component.This component effectively consolidates security notices into a reusable UI element. The styling is consistent and the message is clear. Consider adding an ARIA label for better accessibility:
-<div className="p-4 bg-green-50 border border-green-200 rounded-lg mt-4"> +<div className="p-4 bg-green-50 border border-green-200 rounded-lg mt-4" role="complementary" aria-label="Security information">src/server/routers/payment.ts (1)
75-107
: Consider adding input validation for the signature format.The new
submitRecurringSignature
procedure has good authentication and error handling, but consider adding validation for the permit signature format to catch malformed signatures early.permitSignature: z.string().min(1, "Permit signature is required"), + permitSignature: z.string() + .min(1, "Permit signature is required") + .regex(/^0x[0-9a-fA-F]{130}$/, "Invalid signature format"),src/components/create-recurring-payment/blocks/create-recurring-payment-form.tsx (2)
41-48
: Consider extracting schema derivation for better maintainability.The inline schema derivation for
recurringPaymentFormSchema
could be moved to a separate file or constant to improve readability and reusability.Create a new file
src/lib/schemas/recurring-payment-form.ts
:import { paymentApiSchema } from "@/lib/schemas/payment"; const recurrenceFields = paymentApiSchema.shape.recurrence .unwrap() .omit({ payer: true }).shape; export const recurringPaymentFormSchema = paymentApiSchema .omit({ recurrence: true, paymentCurrency: true }) .extend(recurrenceFields);
80-174
: Consider breaking down the large onSubmit function.The
onSubmit
function is quite large and handles multiple concerns. Consider extracting separate functions for payment creation, transaction approval, and signature submission to improve readability and testability.Extract functions like:
createPaymentAndApproval()
handleTransactionApproval()
handlePermitSigning()
src/lib/schemas/payment.ts (1)
18-35
: Consider simplifying date validation logic.The current date validation logic is complex and might have edge cases around timezone handling. Consider using a simpler approach that's more readable and timezone-safe.
- .refine( - (date) => { - const today = new Date(); - return ( - date.getFullYear() > today.getFullYear() || - (date.getFullYear() === today.getFullYear() && - (date.getMonth() > today.getMonth() || - (date.getMonth() === today.getMonth() && - date.getDate() >= today.getDate()))) - ); - }, - { - message: "Start date cannot be in the past", - }, - ) + .refine( + (date) => { + const today = new Date(); + today.setHours(0, 0, 0, 0); + const inputDate = new Date(date); + inputDate.setHours(0, 0, 0, 0); + return inputDate >= today; + }, + { + message: "Start date cannot be in the past", + }, + )
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
src/app/api/webhook/route.ts
(3 hunks)src/app/payouts/recurring/create/page.tsx
(1 hunks)src/components/batch-payout.tsx
(2 hunks)src/components/create-recurring-payment.tsx
(0 hunks)src/components/create-recurring-payment/blocks/create-recurring-payment-form.tsx
(1 hunks)src/components/create-recurring-payment/create-recurring-payment.tsx
(1 hunks)src/components/direct-payout.tsx
(4 hunks)src/components/payment-secured-using-request.tsx
(1 hunks)src/components/view-recurring-payments/blocks/completed-payments.tsx
(2 hunks)src/lib/constants/currencies.ts
(1 hunks)src/lib/schemas/payment.ts
(2 hunks)src/lib/schemas/recurring-payment.ts
(1 hunks)src/server/db/schema.ts
(1 hunks)src/server/routers/payment.ts
(4 hunks)src/server/routers/recurring-payment.ts
(2 hunks)
💤 Files with no reviewable changes (1)
- src/components/create-recurring-payment.tsx
🔇 Additional comments (16)
src/server/db/schema.ts (1)
220-220
: LGTM: Well-structured schema addition.The
externalPaymentId
field addition follows proper Drizzle ORM patterns and supports the recurring payment integration with external payment systems. The non-nullable constraint ensures data integrity.src/components/view-recurring-payments/blocks/completed-payments.tsx (1)
31-43
: LGTM: Improved transaction display logic.The conditional rendering appropriately handles cases where
requestScanUrl
might not be available. UsingShortAddress
component for transaction hash display provides consistent UX and maintains the existing link behavior when scan URLs are present.src/app/payouts/recurring/create/page.tsx (1)
1-1
: ```shell
#!/bin/bashVerify that the component file exists and that it exports CreateRecurringPayment
file="src/components/create-recurring-payment/create-recurring-payment.tsx"
if [ -f "$file" ]; then
echo "Found: $file"
rg "export (default )?(function|const|class) CreateRecurringPayment" "$file" -A3 || echo "No matching export found in $file"
else
echo "File not found: $file"
fi</details> <details> <summary>src/lib/schemas/recurring-payment.ts (1)</summary> `1-31`: **LGTM! Well-structured schema with proper validation.** The schema design effectively flattens recurrence fields to the top level while maintaining proper validation. The use of `unwrap()` to extract nested schema fields is a clean approach for form handling. </details> <details> <summary>src/components/direct-payout.tsx (2)</summary> `47-56`: **LGTM! Clean schema refactoring approach.** The refactoring properly creates a component-specific schema by omitting the recurrence field from the base API schema. This maintains separation of concerns while reusing validation logic. --- `380-380`: **Good use of reusable component.** Replacing the hardcoded security notice with the `PaymentSecuredUsingRequest` component improves maintainability and consistency across payment forms. </details> <details> <summary>src/server/routers/recurring-payment.ts (1)</summary> `22-56`: **LGTM! Proper implementation with good security practices.** The mutation procedure follows good patterns: - Proper authentication checks - Input validation using the schema - Appropriate database field mappings - Clean error handling The field mappings look correct, converting numbers to strings where needed for database storage. </details> <details> <summary>src/components/batch-payout.tsx (2)</summary> `66-73`: **LGTM! Appropriate batch validation schema.** The local schema properly validates an array of payout items with sensible constraints (1-10 payments). Using the base `payoutSchema` ensures consistency with other payment forms. --- `569-569`: **Good consistency with reusable component.** Using the same `PaymentSecuredUsingRequest` component maintains UI consistency across all payment forms. </details> <details> <summary>src/components/create-recurring-payment/create-recurring-payment.tsx (1)</summary> `1-128`: **LGTM! Well-structured component with proper state management.** The component follows excellent React patterns: - Clean state management for the two-step flow - Proper integration with wallet hooks - Conditional rendering with good UX (loading states) - Consistent styling with other payment components The step indicator provides clear visual feedback to users about their progress. </details> <details> <summary>src/app/api/webhook/route.ts (2)</summary> `39-74`: **LGTM! Well-structured function with proper error handling.** The `addPaymentToRecurringPayment` function correctly uses database transactions and handles the case where no recurring payment is found. The array spread operation ensures immutability when adding new payments. --- `110-122`: **Good conditional logic for handling recurring payments.** The webhook handler correctly differentiates between recurring and regular payments using the presence of `body.recurringPayment?.id`. This maintains backward compatibility while adding new functionality. </details> <details> <summary>src/server/routers/payment.ts (2)</summary> `2-2`: **Good schema naming update for consistency.** The import changes from `*FormSchema` to `*ApiSchema` better reflect the actual usage of these schemas in API endpoints. --- `28-28`: **Proper handling of optional recurrence field.** Using nullish coalescing (`??`) with `undefined` ensures the field is only included when present, maintaining clean API payloads. </details> <details> <summary>src/lib/schemas/payment.ts (2)</summary> `6-6`: **Good schema naming consistency.** The rename from `paymentFormSchema` to `paymentApiSchema` better reflects its usage in API endpoints rather than just forms. --- `72-74`: **Good use of refinement for mutual exclusion.** The refinement ensuring either `payouts` or `requestIds` is provided is a clean approach to handle the either/or validation requirement. </details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
src/components/create-recurring-payment/blocks/create-recurring-payment-form.tsx
Outdated
Show resolved
Hide resolved
src/components/create-recurring-payment/blocks/create-recurring-payment-form.tsx
Show resolved
Hide resolved
src/components/create-recurring-payment/blocks/create-recurring-payment-form.tsx
Outdated
Show resolved
Hide resolved
f597f1f
to
5d5c58e
Compare
5d5c58e
to
258eaea
Compare
Implemented a form for users to create recurring payments via easy invoice.
Changes
Added
Reworked
Testing
Prerequisites
/payouts/recurring/create
and verify that it loads appkit and then shows up the form3.Immediately try to submit the form and verify that validation happens
/payouts/recurring
after it's createdView transaction
should take you to request scan.Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Chores