This commit is contained in:
86
components/CreditButton.tsx
Normal file
86
components/CreditButton.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
type ActionType = 'GENERATE_MASTER' | 'GENERATE_VARIANT' | 'GENERATE_MOCKUP' | 'GENERATE_PROMPT';
|
||||
|
||||
const DEFAULT_CREDITS: Record<ActionType, number> = {
|
||||
GENERATE_PROMPT: 1,
|
||||
GENERATE_MASTER: 10,
|
||||
GENERATE_VARIANT: 5,
|
||||
GENERATE_MOCKUP: 2
|
||||
};
|
||||
|
||||
// Global pricing cache to avoid fetching every button render
|
||||
let pricingCache: any = null;
|
||||
|
||||
interface CreditButtonProps {
|
||||
action?: ActionType;
|
||||
cost?: number; // Direct cost override (for backward compatibility)
|
||||
onClick: () => void;
|
||||
disabled?: boolean;
|
||||
className?: string; // Additional classes for styling
|
||||
children?: React.ReactNode; // Custom text if needed (e.g. "Generate")
|
||||
hideCost?: boolean;
|
||||
}
|
||||
|
||||
export const CreditButton: React.FC<CreditButtonProps> = ({
|
||||
action,
|
||||
cost: directCost,
|
||||
onClick,
|
||||
disabled = false,
|
||||
className = "",
|
||||
children,
|
||||
hideCost = false
|
||||
}) => {
|
||||
const [price, setPrice] = useState<number>(directCost ?? (action ? DEFAULT_CREDITS[action] : 0));
|
||||
|
||||
useEffect(() => {
|
||||
// If directCost is provided, use it directly
|
||||
if (directCost !== undefined) {
|
||||
setPrice(directCost);
|
||||
return;
|
||||
}
|
||||
|
||||
// If no action, skip fetching
|
||||
if (!action) return;
|
||||
|
||||
const fetchPrices = async () => {
|
||||
// Use cache if exists
|
||||
if (pricingCache && pricingCache[`PRICE_${action}`]) {
|
||||
setPrice(Number(pricingCache[`PRICE_${action}`]));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('http://localhost:3001/api/config/prices');
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
pricingCache = data;
|
||||
const dynamicPrice = data[`PRICE_${action}`];
|
||||
if (dynamicPrice) {
|
||||
setPrice(Number(dynamicPrice));
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn("Failed to fetch dynamic prices", err);
|
||||
}
|
||||
};
|
||||
|
||||
fetchPrices();
|
||||
}, [action, directCost]);
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
className={`flex items-center justify-center gap-2 group ${className}`}
|
||||
>
|
||||
{children || <span>Generate</span>}
|
||||
{!hideCost && (
|
||||
<span className="bg-white/20 px-2 py-0.5 rounded text-xs font-mono font-bold opacity-90 group-hover:bg-white/30 transition-colors">
|
||||
{price} 🪙
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user