feat: enhance credit management with transaction store and UI updates

- Added a new transaction store to manage refresh triggers for credit-related components.
- Updated CreditPackages and StripePaymentForm components to utilize the transaction store for refreshing UI after credit purchases.
- Modified .gitignore to include certificates.
- Introduced a new script in package.json for running the development server with HTTPS support.
This commit is contained in:
javayhu 2025-07-05 23:59:30 +08:00
parent 13bee49f90
commit e933844479
5 changed files with 26 additions and 7 deletions

2
.gitignore vendored
View File

@ -30,6 +30,8 @@ yarn-debug.log*
yarn-error.log* yarn-error.log*
.pnpm-debug.log* .pnpm-debug.log*
certificates
# env files (can opt-in for committing if needed) # env files (can opt-in for committing if needed)
.env* .env*

View File

@ -4,6 +4,7 @@
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
"dev-https": "next dev --experimental-https",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"postinstall": "fumadocs-mdx", "postinstall": "fumadocs-mdx",

View File

@ -8,6 +8,7 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/u
import { CREDIT_PACKAGES } from '@/lib/constants'; import { CREDIT_PACKAGES } from '@/lib/constants';
import { formatPrice } from '@/lib/formatter'; import { formatPrice } from '@/lib/formatter';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { useTransactionStore } from '@/stores/transaction-store';
import { CircleCheckBigIcon, CoinsIcon, Loader2Icon } from 'lucide-react'; import { CircleCheckBigIcon, CoinsIcon, Loader2Icon } from 'lucide-react';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { toast } from 'sonner'; import { toast } from 'sonner';
@ -28,6 +29,8 @@ export function CreditPackages() {
clientSecret: null, clientSecret: null,
}); });
const { refreshTrigger } = useTransactionStore();
const fetchCredits = async () => { const fetchCredits = async () => {
try { try {
setLoadingCredits(true); setLoadingCredits(true);
@ -48,9 +51,10 @@ export function CreditPackages() {
} }
}; };
// Initial fetch and listen for transaction updates
useEffect(() => { useEffect(() => {
fetchCredits(); fetchCredits();
}, []); }, [refreshTrigger]);
const handlePurchase = async (packageId: string) => { const handlePurchase = async (packageId: string) => {
try { try {
@ -82,11 +86,6 @@ export function CreditPackages() {
packageId: null, packageId: null,
clientSecret: null, clientSecret: null,
}); });
// Refresh credit balance without page reload
fetchCredits();
// Show success toast
toast.success('Your credits have been added to your account'); toast.success('Your credits have been added to your account');
}; };

View File

@ -4,6 +4,7 @@ import { confirmCreditPayment } from '@/actions/credits.action';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { formatPrice } from '@/lib/formatter'; import { formatPrice } from '@/lib/formatter';
import { useTransactionStore } from '@/stores/transaction-store';
import { import {
Elements, Elements,
PaymentElement, PaymentElement,
@ -82,6 +83,7 @@ function PaymentForm({
const stripe = useStripe(); const stripe = useStripe();
const elements = useElements(); const elements = useElements();
const [processing, setProcessing] = useState(false); const [processing, setProcessing] = useState(false);
const { triggerRefresh } = useTransactionStore();
const handleSubmit = async (event: React.FormEvent) => { const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault(); event.preventDefault();
@ -115,6 +117,10 @@ 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.`); toast.success(`${packageInfo.credits} credits have been added to your account.`);
// Trigger refresh for transaction-dependent UI components
triggerRefresh();
onPaymentSuccess(); onPaymentSuccess();
} else { } else {
console.error('PaymentForm, payment error:', result?.data?.error); console.error('PaymentForm, payment error:', result?.data?.error);

View File

@ -0,0 +1,11 @@
import { create } from "zustand";
interface TransactionStore {
refreshTrigger: number;
triggerRefresh: () => void;
}
export const useTransactionStore = create<TransactionStore>((set) => ({
refreshTrigger: 0,
triggerRefresh: () => set((state) => ({ refreshTrigger: state.refreshTrigger + 1 })),
}));