From 75083b32e4dd7f2e1f84b948966875c66ee0aa95 Mon Sep 17 00:00:00 2001 From: javayhu Date: Sun, 6 Jul 2025 00:15:07 +0800 Subject: [PATCH] refactor: reorganize credit-related imports and enhance user feedback - Updated import paths for credit-related actions and functions to improve module organization. - Removed redundant refresh trigger declaration in CreditPackages component. - Simplified success toast message in CreditPackages and PaymentForm components for clarity. - Introduced a new credits.ts file to centralize credit management logic and improve maintainability. --- src/actions/credits.action.ts | 2 +- .../settings/credits/credit-packages.tsx | 5 +- .../settings/credits/stripe-payment-form.tsx | 4 +- src/credits/README.md | 163 ++++++++++++++++++ src/{lib => credits}/credits.ts | 2 +- src/payment/provider/stripe.ts | 2 +- 6 files changed, 170 insertions(+), 8 deletions(-) create mode 100644 src/credits/README.md rename src/{lib => credits}/credits.ts (99%) diff --git a/src/actions/credits.action.ts b/src/actions/credits.action.ts index 2c89842..2be7e67 100644 --- a/src/actions/credits.action.ts +++ b/src/actions/credits.action.ts @@ -6,7 +6,7 @@ import { addRegisterGiftCredits, consumeCredits, getUserCredits, -} from '@/lib/credits'; +} from '@/credits/credits'; import { getSession } from '@/lib/server'; import { confirmPaymentIntent, createPaymentIntent } from '@/payment'; import { createSafeActionClient } from 'next-safe-action'; diff --git a/src/components/settings/credits/credit-packages.tsx b/src/components/settings/credits/credit-packages.tsx index a71fdfc..09e6efd 100644 --- a/src/components/settings/credits/credit-packages.tsx +++ b/src/components/settings/credits/credit-packages.tsx @@ -19,6 +19,7 @@ export function CreditPackages() { const [loadingCredits, setLoadingCredits] = useState(true); const [loadingPackage, setLoadingPackage] = useState(null); const [credits, setCredits] = useState(null); + const { refreshTrigger } = useTransactionStore(); const [paymentDialog, setPaymentDialog] = useState<{ isOpen: boolean; packageId: string | null; @@ -29,8 +30,6 @@ export function CreditPackages() { clientSecret: null, }); - const { refreshTrigger } = useTransactionStore(); - const fetchCredits = async () => { try { setLoadingCredits(true); @@ -86,7 +85,7 @@ export function CreditPackages() { packageId: null, clientSecret: null, }); - toast.success('Your credits have been added to your account'); + toast.success('Credits have been added to your account'); }; const handlePaymentCancel = () => { diff --git a/src/components/settings/credits/stripe-payment-form.tsx b/src/components/settings/credits/stripe-payment-form.tsx index f7bb42c..6fea790 100644 --- a/src/components/settings/credits/stripe-payment-form.tsx +++ b/src/components/settings/credits/stripe-payment-form.tsx @@ -116,12 +116,12 @@ function PaymentForm({ if (result?.data?.success) { console.log('PaymentForm, payment success'); - toast.success(`${packageInfo.credits} credits have been added to your account.`); - // Trigger refresh for transaction-dependent UI components triggerRefresh(); + // Show success toast onPaymentSuccess(); + // toast.success(`${packageInfo.credits} credits have been added to your account.`); } else { console.error('PaymentForm, payment error:', result?.data?.error); throw new Error( result?.data?.error || 'Failed to confirm payment' ); diff --git a/src/credits/README.md b/src/credits/README.md new file mode 100644 index 0000000..aa96bb5 --- /dev/null +++ b/src/credits/README.md @@ -0,0 +1,163 @@ +# Credit Management System Implementation + +## Overview + +This document describes the credit management system implementation for the mksaas-template project, which allows users to purchase credits using Stripe payments. + +## Features Implemented + +### 1. Credit Packages +- Defined credit packages with different tiers (Basic, Standard, Premium, Enterprise) +- Each package includes credits amount, price, and description +- Popular package highlighting + +### 2. Payment Integration +- Stripe PaymentIntent integration for credit purchases +- Secure payment processing with webhook verification +- Automatic credit addition upon successful payment + +### 3. UI Components +- Credit balance display with refresh functionality +- Credit packages selection interface +- Stripe payment form integration +- Modern, responsive design + +### 4. Database Integration +- Credit transaction recording +- User credit balance management +- Proper error handling and validation + +## Files Created/Modified + +### Core Components +- `src/components/dashboard/credit-packages.tsx` - Main credit packages interface +- `src/components/dashboard/credit-balance.tsx` - Credit balance display +- `src/components/dashboard/stripe-payment-form.tsx` - Stripe payment integration + +### Actions & API +- `src/actions/credits.action.ts` - Credit-related server actions +- `src/app/api/webhooks/stripe/route.ts` - Stripe webhook handler +- `src/payment/index.ts` - Payment provider interface (updated) +- `src/payment/types.ts` - Payment types (updated) + +### Configuration +- `src/lib/constants.ts` - Credit packages configuration +- `env.example` - Environment variables template + +### Pages +- `src/app/[locale]/(protected)/settings/credits/page.tsx` - Credits management page + +## Environment Variables Required + +Add these to your `.env.local` file: + +```env +# Stripe Configuration +NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY="pk_test_..." +STRIPE_SECRET_KEY="sk_test_..." +STRIPE_WEBHOOK_SECRET="whsec_..." +``` + +## Setup Instructions + +### 1. Stripe Configuration +1. Create a Stripe account at https://dashboard.stripe.com +2. Get your API keys from the Stripe dashboard +3. Set up a webhook endpoint pointing to `/api/webhooks/stripe` +4. Copy the webhook secret and add it to your environment variables + +### 2. Database Setup +Make sure your database schema includes the required credit tables as defined in `src/db/schema.ts`. + +### 3. Environment Variables +Copy the required environment variables from `env.example` to your `.env.local` file and fill in the values. + +## Usage + +### For Users +1. Navigate to `/settings/credits` +2. View current credit balance +3. Select a credit package +4. Complete payment using Stripe +5. Credits are automatically added to account + +### For Developers +```typescript +// Get user credits +const result = await getCreditsAction(); + +// Create payment intent +const paymentIntent = await createCreditPaymentIntent({ + packageId: 'standard' +}); + +// Add credits manually +await addCredits({ + userId: 'user-id', + amount: 100, + type: 'PURCHASE', + description: 'Credit purchase' +}); +``` + +## Credit Packages Configuration + +Edit `src/lib/constants.ts` to modify available credit packages: + +```typescript +export const CREDIT_PACKAGES = [ + { + id: 'basic', + credits: 100, + price: 9.99, + popular: false, + description: 'Perfect for getting started', + }, + // ... more packages +]; +``` + +## Webhook Events + +The system handles these Stripe webhook events: +- `payment_intent.succeeded` - Adds credits to user account upon successful payment + +## Security Features + +1. **Webhook Verification**: All webhook requests are verified using Stripe signatures +2. **Payment Validation**: Amount and package validation before processing +3. **User Authentication**: All credit operations require authenticated users +4. **Metadata Validation**: Payment metadata is validated before processing + +## Error Handling + +The system includes comprehensive error handling for: +- Invalid payment attempts +- Network failures +- Database errors +- Authentication issues +- Webhook verification failures + +## Testing + +To test the credit purchase flow: +1. Use Stripe test cards (e.g., `4242424242424242`) +2. Monitor webhook events in Stripe dashboard +3. Check credit balance updates in the application + +## Integration Notes + +This implementation: +- Uses Next.js server actions for secure server-side operations +- Integrates with existing Drizzle ORM schema +- Follows the existing payment provider pattern +- Maintains consistency with the existing codebase architecture + +## Future Enhancements + +Potential improvements: +- Credit transaction history display +- Credit expiration management +- Bulk credit operations +- Credit usage analytics +- Subscription-based credit allocation diff --git a/src/lib/credits.ts b/src/credits/credits.ts similarity index 99% rename from src/lib/credits.ts rename to src/credits/credits.ts index 530e844..9506e7f 100644 --- a/src/lib/credits.ts +++ b/src/credits/credits.ts @@ -8,7 +8,7 @@ import { CREDIT_TRANSACTION_TYPE, FREE_MONTHLY_CREDITS, REGISTER_GIFT_CREDITS, -} from './constants'; +} from '../lib/constants'; /** * Get user's current credit balance diff --git a/src/payment/provider/stripe.ts b/src/payment/provider/stripe.ts index 1981476..0e8b6bd 100644 --- a/src/payment/provider/stripe.ts +++ b/src/payment/provider/stripe.ts @@ -7,7 +7,7 @@ import { findPriceInPlan, } from '@/lib/price-plan'; import { sendNotification } from '@/notification/notification'; -import { addCredits } from '@/lib/credits'; +import { addCredits } from '@/credits/credits'; import { CREDIT_TRANSACTION_TYPE } from '@/lib/constants'; import { desc, eq } from 'drizzle-orm'; import { Stripe } from 'stripe';