ranger-app/src/components/TextGenerationCard.tsx
2025-01-09 12:32:34 -05:00

132 lines
4.1 KiB
TypeScript

'use client'
import React, { useState } from 'react'
interface TextGenerationCardProps {
title: string
description: string
tokenCost: number
isWalletConnected: boolean
onGenerate: (prompt: string) => Promise<{ textResponse?: string, error?: string }>
}
interface GenerationState {
loading: boolean
processing: boolean
textResponse: string | null
error: string | null
}
const TextGenerationCard: React.FC<TextGenerationCardProps> = ({
title,
description,
tokenCost,
isWalletConnected,
onGenerate
}) => {
const [inputText, setInputText] = useState<string>('')
const [generationState, setGenerationState] = useState<GenerationState>({
loading: false,
processing: false,
textResponse: null,
error: null,
})
const handleGenerate = async (): Promise<void> => {
if (!inputText || !isWalletConnected) return
setGenerationState({
...generationState,
loading: true,
error: null,
})
try {
const result = await onGenerate(inputText)
if (result.error) {
setGenerationState({
...generationState,
loading: false,
error: result.error,
})
return
}
if (result.textResponse) {
setGenerationState({
loading: false,
processing: false,
textResponse: result.textResponse,
error: null,
})
} else {
throw new Error('No response received')
}
} catch (error) {
setGenerationState({
...generationState,
loading: false,
error: error instanceof Error ? error.message : 'Generation failed',
})
}
}
return (
<div className="w-full bg-gray-800/50 backdrop-blur-lg rounded-2xl shadow-xl border border-gray-700/50 mb-8">
<div className="p-6">
<div className="mb-4">
<h2 className="text-2xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-green-400 to-emerald-600">
{title}
</h2>
<p className="text-gray-400 mt-2">{description}</p>
<div className="mt-2 inline-block px-3 py-1 bg-green-500/20 rounded-full text-green-300 text-sm">
Cost: {tokenCost} MTM
</div>
</div>
<div className="space-y-4">
<textarea
value={inputText}
onChange={(e) => setInputText(e.target.value)}
placeholder="Enter your question here..."
disabled={!isWalletConnected}
className="w-full bg-gray-900/50 text-gray-100 border border-gray-700 rounded-xl p-4
placeholder-gray-500 focus:border-green-500 focus:ring-2 focus:ring-green-500/20
focus:outline-none min-h-[120px] transition-all duration-200
disabled:opacity-50 disabled:cursor-not-allowed"
rows={4}
/>
<button
onClick={handleGenerate}
disabled={!isWalletConnected || generationState.loading || !inputText}
className="w-full bg-gradient-to-r from-green-500 to-emerald-500 hover:from-green-600
hover:to-emerald-600 text-white font-semibold py-4 px-6 rounded-xl
transition-all duration-200 shadow-lg hover:shadow-green-500/25
disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:shadow-none"
>
{generationState.loading ? 'Processing...' : `Pay ${tokenCost} MTM & Generate`}
</button>
</div>
{generationState.error && (
<div className="mt-4 bg-red-900/20 border border-red-500/20 text-red-400 px-4 py-3 rounded-xl text-center">
{generationState.error}
</div>
)}
{generationState.textResponse && (
<div className="mt-6 bg-gray-900/50 rounded-xl p-6 border border-gray-700">
<h3 className="text-lg font-semibold text-green-400 mb-3">Response:</h3>
<div className="text-gray-300 whitespace-pre-wrap">
{generationState.textResponse}
</div>
</div>
)}
</div>
</div>
)
}
export default TextGenerationCard