feat: add ConsumeCreditCard component for credit consumption
This commit is contained in:
parent
4160305a67
commit
c7a1ec69bb
@ -633,9 +633,9 @@
|
||||
"types": {
|
||||
"MONTHLY_REFRESH": "Monthly Refresh",
|
||||
"REGISTER_GIFT": "Register Gift",
|
||||
"PURCHASE": "Purchase",
|
||||
"USAGE": "Usage",
|
||||
"EXPIRE": "Expire",
|
||||
"PURCHASE": "Purchased Credits",
|
||||
"USAGE": "Consumed Credits",
|
||||
"EXPIRE": "Expired Credits",
|
||||
"SUBSCRIPTION_RENEWAL": "Subscription Renewal",
|
||||
"LIFETIME_MONTHLY": "Lifetime Monthly"
|
||||
},
|
||||
|
51
src/ai/text/components/consume-credit-card.tsx
Normal file
51
src/ai/text/components/consume-credit-card.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
'use client';
|
||||
|
||||
import { CreditsBalanceButton } from '@/components/layout/credits-balance-button';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useCredits } from '@/hooks/use-credits';
|
||||
import { CoinsIcon } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
const CONSUME_CREDITS = 50;
|
||||
|
||||
export function ConsumeCreditCard() {
|
||||
const { consumeCredits, hasEnoughCredits, isLoading } = useCredits();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleConsume = async () => {
|
||||
if (!hasEnoughCredits(CONSUME_CREDITS)) {
|
||||
toast.error('Insufficient credits, please buy more credits.');
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
const success = await consumeCredits(
|
||||
CONSUME_CREDITS,
|
||||
`AI Text Credit Consumption (${CONSUME_CREDITS} credits)`
|
||||
);
|
||||
setLoading(false);
|
||||
if (success) {
|
||||
toast.success(`${CONSUME_CREDITS} credits have been consumed.`);
|
||||
} else {
|
||||
toast.error('Failed to consume credits, please try again later.');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-8 p-4 border rounded-lg">
|
||||
<div className="w-full flex flex-row items-center justify-end">
|
||||
<CreditsBalanceButton />
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleConsume}
|
||||
disabled={isLoading || loading}
|
||||
className="w-full cursor-pointer"
|
||||
>
|
||||
<CoinsIcon className="size-4" />
|
||||
<span>Consume {CONSUME_CREDITS} credits</span>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
import { ConsumeCreditCard } from '@/ai/text/components/consume-credit-card';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { constructMetadata } from '@/lib/metadata';
|
||||
import { getUrlWithLocale } from '@/lib/urls/urls';
|
||||
@ -28,7 +29,7 @@ export default async function AITextPage() {
|
||||
<div className="max-w-4xl mx-auto space-y-8">
|
||||
{/* about section */}
|
||||
<div className="relative max-w-(--breakpoint-md) mx-auto mb-24 mt-8 md:mt-16">
|
||||
<div className="mx-auto flex flex-col justify-between">
|
||||
<div className="mx-auto flex flex-col justify-between gap-8">
|
||||
<div className="flex flex-row items-center gap-8">
|
||||
{/* avatar and name */}
|
||||
<div className="flex items-center gap-8">
|
||||
@ -48,6 +49,9 @@ export default async function AITextPage() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* simulate consume credits */}
|
||||
<ConsumeCreditCard />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -223,17 +223,6 @@ export function CreditTransactionsTable({
|
||||
}
|
||||
};
|
||||
|
||||
// Get transaction type badge variant
|
||||
const getTransactionTypeBadgeVariant = (type: string) => {
|
||||
switch (type) {
|
||||
case CREDIT_TRANSACTION_TYPE.USAGE:
|
||||
case CREDIT_TRANSACTION_TYPE.EXPIRE:
|
||||
return 'destructive' as const;
|
||||
default:
|
||||
return 'outline' as const;
|
||||
}
|
||||
};
|
||||
|
||||
// Get transaction type display name
|
||||
const getTransactionTypeDisplayName = (type: string) => {
|
||||
switch (type) {
|
||||
@ -268,8 +257,8 @@ export function CreditTransactionsTable({
|
||||
return (
|
||||
<div className="flex items-center gap-2 pl-3">
|
||||
<Badge
|
||||
variant={getTransactionTypeBadgeVariant(transaction.type)}
|
||||
className="cursor-pointer hover:bg-accent transition-colors"
|
||||
variant="outline"
|
||||
className="hover:bg-accent transition-colors"
|
||||
>
|
||||
{getTransactionTypeIcon(transaction.type)}
|
||||
{getTransactionTypeDisplayName(transaction.type)}
|
||||
|
@ -70,17 +70,6 @@ export function CreditDetailViewer({ transaction }: CreditDetailViewerProps) {
|
||||
}
|
||||
};
|
||||
|
||||
// Get transaction type badge variant
|
||||
const getTransactionTypeBadgeVariant = (type: string) => {
|
||||
switch (type) {
|
||||
case CREDIT_TRANSACTION_TYPE.USAGE:
|
||||
case CREDIT_TRANSACTION_TYPE.EXPIRE:
|
||||
return 'destructive' as const;
|
||||
default:
|
||||
return 'outline' as const;
|
||||
}
|
||||
};
|
||||
|
||||
// Get transaction type display name
|
||||
const getTransactionTypeDisplayName = (type: string) => {
|
||||
switch (type) {
|
||||
@ -131,8 +120,8 @@ export function CreditDetailViewer({ transaction }: CreditDetailViewerProps) {
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Transaction Type Badge */}
|
||||
<Badge
|
||||
variant={getTransactionTypeBadgeVariant(transaction.type)}
|
||||
className="px-2 py-1"
|
||||
variant="outline"
|
||||
className="hover:bg-accent transition-colors"
|
||||
>
|
||||
{getTransactionTypeIcon(transaction.type)}
|
||||
{getTransactionTypeDisplayName(transaction.type)}
|
||||
|
Loading…
Reference in New Issue
Block a user