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.
This commit is contained in:
parent
e933844479
commit
75083b32e4
@ -6,7 +6,7 @@ import {
|
|||||||
addRegisterGiftCredits,
|
addRegisterGiftCredits,
|
||||||
consumeCredits,
|
consumeCredits,
|
||||||
getUserCredits,
|
getUserCredits,
|
||||||
} from '@/lib/credits';
|
} from '@/credits/credits';
|
||||||
import { getSession } from '@/lib/server';
|
import { getSession } from '@/lib/server';
|
||||||
import { confirmPaymentIntent, createPaymentIntent } from '@/payment';
|
import { confirmPaymentIntent, createPaymentIntent } from '@/payment';
|
||||||
import { createSafeActionClient } from 'next-safe-action';
|
import { createSafeActionClient } from 'next-safe-action';
|
||||||
|
@ -19,6 +19,7 @@ export function CreditPackages() {
|
|||||||
const [loadingCredits, setLoadingCredits] = useState(true);
|
const [loadingCredits, setLoadingCredits] = useState(true);
|
||||||
const [loadingPackage, setLoadingPackage] = useState<string | null>(null);
|
const [loadingPackage, setLoadingPackage] = useState<string | null>(null);
|
||||||
const [credits, setCredits] = useState<number | null>(null);
|
const [credits, setCredits] = useState<number | null>(null);
|
||||||
|
const { refreshTrigger } = useTransactionStore();
|
||||||
const [paymentDialog, setPaymentDialog] = useState<{
|
const [paymentDialog, setPaymentDialog] = useState<{
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
packageId: string | null;
|
packageId: string | null;
|
||||||
@ -29,8 +30,6 @@ export function CreditPackages() {
|
|||||||
clientSecret: null,
|
clientSecret: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { refreshTrigger } = useTransactionStore();
|
|
||||||
|
|
||||||
const fetchCredits = async () => {
|
const fetchCredits = async () => {
|
||||||
try {
|
try {
|
||||||
setLoadingCredits(true);
|
setLoadingCredits(true);
|
||||||
@ -86,7 +85,7 @@ export function CreditPackages() {
|
|||||||
packageId: null,
|
packageId: null,
|
||||||
clientSecret: null,
|
clientSecret: null,
|
||||||
});
|
});
|
||||||
toast.success('Your credits have been added to your account');
|
toast.success('Credits have been added to your account');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePaymentCancel = () => {
|
const handlePaymentCancel = () => {
|
||||||
|
@ -116,12 +116,12 @@ function PaymentForm({
|
|||||||
|
|
||||||
if (result?.data?.success) {
|
if (result?.data?.success) {
|
||||||
console.log('PaymentForm, payment success');
|
console.log('PaymentForm, payment success');
|
||||||
toast.success(`${packageInfo.credits} credits have been added to your account.`);
|
|
||||||
|
|
||||||
// Trigger refresh for transaction-dependent UI components
|
// Trigger refresh for transaction-dependent UI components
|
||||||
triggerRefresh();
|
triggerRefresh();
|
||||||
|
|
||||||
|
// Show success toast
|
||||||
onPaymentSuccess();
|
onPaymentSuccess();
|
||||||
|
// toast.success(`${packageInfo.credits} credits have been added to your account.`);
|
||||||
} else {
|
} else {
|
||||||
console.error('PaymentForm, payment error:', result?.data?.error);
|
console.error('PaymentForm, payment error:', result?.data?.error);
|
||||||
throw new Error( result?.data?.error || 'Failed to confirm payment' );
|
throw new Error( result?.data?.error || 'Failed to confirm payment' );
|
||||||
|
163
src/credits/README.md
Normal file
163
src/credits/README.md
Normal file
@ -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
|
@ -8,7 +8,7 @@ import {
|
|||||||
CREDIT_TRANSACTION_TYPE,
|
CREDIT_TRANSACTION_TYPE,
|
||||||
FREE_MONTHLY_CREDITS,
|
FREE_MONTHLY_CREDITS,
|
||||||
REGISTER_GIFT_CREDITS,
|
REGISTER_GIFT_CREDITS,
|
||||||
} from './constants';
|
} from '../lib/constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user's current credit balance
|
* Get user's current credit balance
|
@ -7,7 +7,7 @@ import {
|
|||||||
findPriceInPlan,
|
findPriceInPlan,
|
||||||
} from '@/lib/price-plan';
|
} from '@/lib/price-plan';
|
||||||
import { sendNotification } from '@/notification/notification';
|
import { sendNotification } from '@/notification/notification';
|
||||||
import { addCredits } from '@/lib/credits';
|
import { addCredits } from '@/credits/credits';
|
||||||
import { CREDIT_TRANSACTION_TYPE } from '@/lib/constants';
|
import { CREDIT_TRANSACTION_TYPE } from '@/lib/constants';
|
||||||
import { desc, eq } from 'drizzle-orm';
|
import { desc, eq } from 'drizzle-orm';
|
||||||
import { Stripe } from 'stripe';
|
import { Stripe } from 'stripe';
|
||||||
|
Loading…
Reference in New Issue
Block a user