import React, { useState, useEffect } from 'react';
import {
GraduationCap, User, Crown, Settings2, FileText,
Lock, CheckCircle, Download, Copy, Bot,
Check, X, RefreshCw, Layers, FileSignature, ListOrdered
} from 'lucide-react';
type EducationalLevel = 'SD' | 'SMP' | 'SMA' | 'SMK';
interface FormData {
tingkat: EducationalLevel | '';
jurusan: string;
mapel: string;
kelas: string;
semester: string;
topik: string;
wantsSilabus: boolean;
wantsLKPD: boolean;
wantsSoal: boolean;
}
const VALID_TOKENS = ['PRO-8538-UNIX1', 'PRO-8538-DEV99', 'EDUGEN-FULL-2026'];
const WA_NUMBER = "6282182098538";
export default function EduGenApp() {
const [isPro, setIsPro] = useState(false);
const [usageCount, setUsageCount] = useState(0);
const [isGenerating, setIsGenerating] = useState(false);
const [showUpgradeModal, setShowUpgradeModal] = useState(false);
const [tokenInput, setTokenInput] = useState('');
const [tokenMessage, setTokenMessage] = useState({ text: '', type: '' });
const [generatedResult, setGeneratedResult] = useState<string | null>(null);
const [isCopied, setIsCopied] = useState(false);
const [isExporting, setIsExporting] = useState(false);
const [formData, setFormData] = useState<FormData>({
tingkat: '',
jurusan: '',
mapel: '',
kelas: '',
semester: 'Ganjil',
topik: '',
wantsSilabus: false,
wantsLKPD: false,
wantsSoal: false,
});
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
const handleCheckboxChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, checked } = e.target;
if (!isPro) {
setShowUpgradeModal(true);
return;
}
setFormData(prev => ({ ...prev, [name]: checked }));
};
const handleProFeatureClick = (e: React.MouseEvent) => {
if (!isPro) {
e.preventDefault();
setShowUpgradeModal(true);
}
};
const verifyToken = () => {
const token = tokenInput.trim().toUpperCase();
if (!token) {
setTokenMessage({ text: "Token tidak boleh kosong!", type: "error" });
return;
}
if (VALID_TOKENS.includes(token)) {
setIsPro(true);
setTokenMessage({ text: "Token Valid! Akun Anda telah diupgrade ke PRO Full Stack.", type: "success" });
setTimeout(() => {
setShowUpgradeModal(false);
setTokenMessage({ text: '', type: '' });
}, 2000);
} else {
setTokenMessage({ text: "Token tidak valid. Silakan hubungi admin via WA.", type: "error" });
}
};
const handleGenerate = (e: React.FormEvent) => {
e.preventDefault();
// Validasi Limit Reguler
if (!isPro && usageCount >= 1) {
setShowUpgradeModal(true);
return;
}
setIsGenerating(true);
setGeneratedResult(null);
// Simulasi request AI (misal via fetch ke server Remix/Next)
setTimeout(() => {
const result = generateMockResponse(formData);
setGeneratedResult(result);
setIsGenerating(false);
if (!isPro) setUsageCount(prev => prev + 1);
}, 2500);
};
const generateMockResponse = (data: FormData): string => {
const isKejuruan = (data.tingkat === 'SMK' || data.tingkat === 'SMA') && data.jurusan;
const targetSiswa = isKejuruan ? `${data.tingkat} Jurusan ${data.jurusan}` : data.tingkat;
let html = `
<div class="mb-6 border-b pb-4">
<h2 class="text-2xl font-bold text-center uppercase mb-1">Modul Ajar Kurikulum Merdeka</h2>
<p class="text-center text-gray-600 font-medium">${data.mapel} | Kelas ${data.kelas} | Semester ${data.semester}</p>
</div>
<div class="space-y-6">
<section>
<h3 class="text-lg font-bold text-blue-800 bg-blue-50 p-2 rounded-md border-l-4 border-blue-600 mb-3 flex items-center"><Layers class="w-5 h-5 mr-2"/> A. Informasi Umum</h3>
<div class="grid grid-cols-3 gap-2 text-sm border border-gray-200 rounded p-3 bg-white">
<div class="font-semibold text-gray-600">Satuan Pendidikan</div><div class="col-span-2">${targetSiswa}</div>
<div class="font-semibold text-gray-600">Mata Pelajaran</div><div class="col-span-2">${data.mapel}</div>
<div class="font-semibold text-gray-600">Topik Materi</div><div class="col-span-2 font-bold text-gray-800">${data.topik}</div>
</div>
</section>
<section>
<h3 class="text-lg font-bold text-blue-800 bg-blue-50 p-2 rounded-md border-l-4 border-blue-600 mb-3">B. Capaian & Tujuan</h3>
<div class="pl-2">
<p class="text-sm mb-2 text-gray-700">Peserta didik mampu memahami dan mengaplikasikan konsep dasar terkait <strong>${data.topik}</strong> dalam kehidupan sehari-hari ${isKejuruan ? 'serta pada industri ' + data.jurusan : ''}.</p>
<h4 class="font-semibold text-sm mt-3 mb-1">Tujuan Pembelajaran:</h4>
<ul class="list-decimal pl-5 text-sm text-gray-700 space-y-1">
<li>Peserta didik dapat menjelaskan ruang lingkup ${data.topik}.</li>
<li>Peserta didik mampu mengidentifikasi dan memecahkan studi kasus sederhana.</li>
</ul>
</div>
</section>
<section>
<h3 class="text-lg font-bold text-blue-800 bg-blue-50 p-2 rounded-md border-l-4 border-blue-600 mb-3">C. Kegiatan Pembelajaran</h3>
<div class="space-y-3 pl-2">
<div class="border-l-2 border-green-500 pl-3">
<h4 class="font-bold text-sm text-green-700">Pendahuluan (15 Menit)</h4>
<p class="text-xs text-gray-600">Apersepsi dan pemantik motivasi mengenai relevansi ${data.topik}.</p>
</div>
<div class="border-l-2 border-yellow-500 pl-3">
<h4 class="font-bold text-sm text-yellow-700">Inti (60 Menit) - Problem Based Learning</h4>
<p class="text-xs text-gray-600">Siswa berdiskusi kelompok memecahkan permasalahan nyata yang diberikan guru mengenai ${data.topik}, disusul dengan presentasi.</p>
</div>
<div class="border-l-2 border-red-500 pl-3">
<h4 class="font-bold text-sm text-red-700">Penutup (15 Menit)</h4>
<p class="text-xs text-gray-600">Refleksi, kesimpulan bersama, dan asesmen formatif singkat.</p>
</div>
</div>
</section>
</div>
`;
if (isPro) {
if (data.wantsSilabus) {
html += `
<div class="mt-8 pt-6 border-t-2 border-dashed border-purple-200">
<h3 class="text-lg font-bold text-purple-800 mb-3 flex items-center"><FileText class="w-5 h-5 mr-2"/> Silabus (ATP) Mini</h3>
<p class="text-xs text-purple-600 mb-2 italic">Pro Feature Unlocked</p>
<table class="w-full text-xs border border-gray-200 text-left">
<thead class="bg-purple-50"><tr><th class="p-2 border">Minggu</th><th class="p-2 border">Materi</th><th class="p-2 border">Asesmen</th></tr></thead>
<tbody>
<tr><td class="p-2 border">1</td><td class="p-2 border">Pengantar ${data.topik}</td><td class="p-2 border">Formatif Lisan</td></tr>
<tr><td class="p-2 border">2</td><td class="p-2 border">Analisis Kasus ${data.topik}</td><td class="p-2 border">Unjuk Kerja / Presentasi</td></tr>
</tbody>
</table>
</div>`;
}
if (data.wantsLKPD) {
html += `
<div class="mt-8 pt-6 border-t-2 border-dashed border-teal-200">
<h3 class="text-lg font-bold text-teal-800 mb-3 flex items-center"><FileSignature class="w-5 h-5 mr-2"/> Lembar Kerja (LKPD)</h3>
<div class="bg-teal-50 border border-teal-100 p-4 rounded text-sm">
<p class="font-bold mb-2">Nama Kelompok: _______________</p>
<p class="mb-4">Diskusikan dengan kelompok: Jelaskan strategi terbaik untuk mengimplementasikan ${data.topik} berdasarkan studi literatur!</p>
<div class="h-20 border-2 border-dashed border-teal-300 bg-white"></div>
</div>
</div>`;
}
if (data.wantsSoal) {
html += `
<div class="mt-8 pt-6 border-t-2 border-dashed border-rose-200">
<h3 class="text-lg font-bold text-rose-800 mb-3 flex items-center"><ListOrdered class="w-5 h-5 mr-2"/> Bank Soal (HOTS)</h3>
<div class="space-y-3 text-sm">
<div class="p-3 bg-gray-50 border rounded">
<p class="font-semibold">Soal Esai Analisis (C4):</p>
<p class="mt-1">Bandingkan dua pendekatan berbeda dalam menyelesaikan masalah terkait ${data.topik} ${isKejuruan ? 'di lingkungan industri ' + data.jurusan : ''}. Pendekatan mana yang lebih efisien dan mengapa?</p>
</div>
</div>
</div>`;
}
}
return html;
};
const handleCopy = () => {
if (!generatedResult) return;
// Buat temporary div untuk mengambil teks saja tanpa HTML tags
const tempDiv = document.createElement("div");
tempDiv.innerHTML = generatedResult;
const textToCopy = tempDiv.innerText || tempDiv.textContent;
navigator.clipboard.writeText(textToCopy || "").then(() => {
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
});
};
const handleExport = () => {
if (!isPro) {
setShowUpgradeModal(true);
return;
}
setIsExporting(true);
// Simulasi ekspor file
setTimeout(() => {
setIsExporting(false);
}, 1500);
};
return (
<div className="min-h-screen bg-slate-50 text-slate-800 font-sans flex flex-col">
{/* Navbar */}
<header className="bg-gradient-to-r from-blue-700 to-indigo-800 text-white shadow-md sticky top-0 z-40">
<div className="max-w-7xl mx-auto px-4 py-4 flex justify-between items-center">
<div className="flex items-center gap-2">
<GraduationCap className="w-8 h-8 text-blue-200" />
<h1 className="text-2xl font-bold tracking-tight">EduGen AI</h1>
</div>
<div className="flex items-center gap-3">
{isPro ? (
<span className="flex items-center bg-amber-400 text-amber-900 px-3 py-1 rounded-full text-sm font-bold shadow-sm">
<Crown className="w-4 h-4 mr-1.5" /> PRO Member
</span>
) : (
<>
<span className="hidden sm:flex items-center bg-slate-100 text-slate-700 px-3 py-1 rounded-full text-sm font-medium">
<User className="w-4 h-4 mr-1.5" /> Reguler
</span>
<button
onClick={() => setShowUpgradeModal(true)}
className="bg-amber-400 hover:bg-amber-300 text-amber-900 px-4 py-1.5 rounded-md text-sm font-bold shadow-sm transition-colors flex items-center"
>
<Crown className="w-4 h-4 mr-1.5" /> Upgrade
</button>
</>
)}
</div>
</div>
</header>
{/* Main Content */}
<main className="flex-grow max-w-7xl mx-auto w-full px-4 py-8 grid grid-cols-1 lg:grid-cols-12 gap-8">
{/* Panel Konfigurasi (Kiri) */}
<aside className="lg:col-span-4 space-y-6">
<div className="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden">
<div className="bg-slate-50 px-5 py-4 border-b border-slate-200 flex items-center">
<Settings2 className="w-5 h-5 text-blue-600 mr-2" />
<h2 className="font-semibold text-slate-800 text-lg">Konfigurasi AI</h2>
</div>
<form onSubmit={handleGenerate} className="p-5 space-y-4">
<div>
<label className="block text-sm font-medium text-slate-700 mb-1">Tingkat Pendidikan</label>
<select
name="tingkat" required
value={formData.tingkat} onChange={handleInputChange}
className="w-full border-slate-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 p-2.5 border bg-white text-sm"
>
<option value="" disabled>Pilih Tingkat</option>
<option value="SD">SD</option>
<option value="SMP">SMP</option>
<option value="SMA">SMA</option>
<option value="SMK">SMK</option>
</select>
</div>
{(formData.tingkat === 'SMA' || formData.tingkat === 'SMK') && (
<div className="animate-in fade-in slide-in-from-top-2 duration-300">
<label className="block text-sm font-medium text-slate-700 mb-1">Jurusan / Peminatan</label>
<input
type="text" name="jurusan" required
value={formData.jurusan} onChange={handleInputChange}
placeholder="Mis: Rekayasa Perangkat Lunak..."
className="w-full border-slate-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 p-2.5 border text-sm"
/>
</div>
)}
<div>
<label className="block text-sm font-medium text-slate-700 mb-1">Mata Pelajaran</label>
<input
type="text" name="mapel" required
value={formData.mapel} onChange={handleInputChange}
placeholder="Mis: Matematika, Pemrograman..."
className="w-full border-slate-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 p-2.5 border text-sm"
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-slate-700 mb-1">Kelas</label>
<input
type="text" name="kelas" required
value={formData.kelas} onChange={handleInputChange}
placeholder="Mis: X"
className="w-full border-slate-300 rounded-md shadow-sm p-2.5 border text-sm"
/>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-1">Semester</label>
<select
name="semester" required
value={formData.semester} onChange={handleInputChange}
className="w-full border-slate-300 rounded-md shadow-sm p-2.5 border bg-white text-sm"
>
<option value="Ganjil">Ganjil</option>
<option value="Genap">Genap</option>
</select>
</div>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-1">Topik Utama</label>
<textarea
name="topik" required rows={2}
value={formData.topik} onChange={handleInputChange}
placeholder="Deskripsikan spesifik materi yang diajarkan..."
className="w-full border-slate-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 p-2.5 border text-sm resize-none"
/>
</div>
{/* Pilihan Fitur Pro */}
<div className="pt-2 border-t border-slate-100">
<label className="block text-sm font-semibold text-slate-800 mb-3">Jenis Output</label>
<div className="space-y-2.5">
<label className="flex items-center text-sm text-slate-700">
<input type="checkbox" checked disabled className="rounded text-blue-600 focus:ring-blue-500 h-4 w-4 mr-2" />
Modul Ajar / RPP Dasar
</label>
{[
{ name: 'wantsSilabus', label: 'Silabus / ATP' },
{ name: 'wantsLKPD', label: 'Lembar Kerja (LKPD)' },
{ name: 'wantsSoal', label: 'Bank Soal Evaluasi' }
].map((feat) => (
<div key={feat.name} onClick={handleProFeatureClick} className={`flex items-center text-sm ${!isPro ? 'cursor-pointer opacity-70' : 'cursor-pointer'}`}>
<input
type="checkbox"
name={feat.name}
checked={formData[feat.name as keyof FormData] as boolean}
onChange={handleCheckboxChange}
disabled={!isPro}
className={`rounded text-blue-600 h-4 w-4 mr-2 ${!isPro ? 'pointer-events-none' : ''}`}
/>
<span className="flex-grow">{feat.label}</span>
{!isPro && <Lock className="w-3.5 h-3.5 text-amber-500 ml-1" />}
</div>
))}
</div>
</div>
<button
type="submit"
disabled={isGenerating}
className="w-full mt-4 bg-blue-600 hover:bg-blue-700 disabled:bg-blue-400 text-white font-semibold py-3 px-4 rounded-md shadow-sm transition flex justify-center items-center"
>
{isGenerating ? (
<><RefreshCw className="w-5 h-5 mr-2 animate-spin" /> Merancang...</>
) : (
<><Bot className="w-5 h-5 mr-2" /> Generate AI</>
)}
</button>
{!isPro && (
<p className="text-xs text-center text-slate-500 mt-2">
Batas Reguler: {usageCount}/1 per hari
</p>
)}
</form>
</div>
</aside>
{/* Panel Hasil (Kanan) */}
<section className="lg:col-span-8 flex flex-col h-full">
<div className="bg-white rounded-xl shadow-sm border border-slate-200 flex-grow flex flex-col overflow-hidden min-h-[600px]">
<div className="bg-slate-50 px-5 py-3 border-b border-slate-200 flex justify-between items-center">
<h2 className="font-semibold text-slate-800 text-lg flex items-center">
<FileText className="w-5 h-5 text-emerald-600 mr-2" />
Hasil Dokumen
</h2>
{generatedResult && (
<div className="flex gap-2">
<button
onClick={handleCopy}
className="flex items-center gap-1.5 px-3 py-1.5 bg-white border border-slate-300 text-slate-700 hover:bg-slate-50 rounded text-sm transition"
>
{isCopied ? <Check className="w-4 h-4 text-emerald-500" /> : <Copy className="w-4 h-4" />}
{isCopied ? 'Tersalin' : 'Copy Teks'}
</button>
<button
onClick={handleExport}
className={`flex items-center gap-1.5 px-3 py-1.5 text-white rounded text-sm transition ${isPro ? 'bg-blue-600 hover:bg-blue-700' : 'bg-slate-500 hover:bg-slate-600'}`}
>
{isExporting ? <RefreshCw className="w-4 h-4 animate-spin" /> : <Download className="w-4 h-4" />}
Ekspor {!isPro && <Lock className="w-3 h-3 ml-0.5"/>}
</button>
</div>
)}
</div>
<div className="p-6 overflow-y-auto flex-grow bg-white">
{isGenerating ? (
<div className="h-full flex flex-col items-center justify-center text-center space-y-4">
<div className="w-12 h-12 border-4 border-blue-100 border-t-blue-600 rounded-full animate-spin"></div>
<p className="text-blue-600 font-medium animate-pulse">AI sedang merancang kurikulum dan materi...</p>
</div>
) : generatedResult ? (
<div
className="prose max-w-none text-slate-800"
dangerouslySetInnerHTML={{ __html: generatedResult }}
/>
) : (
<div className="h-full flex flex-col items-center justify-center text-slate-400">
<Bot className="w-16 h-16 mb-4 opacity-50" />
<p className="text-lg font-medium text-slate-500">Belum ada dokumen</p>
<p className="text-sm mt-1">Isi form di sebelah kiri dan klik Generate AI</p>
</div>
)}
</div>
</div>
</section>
</main>
{}
{showUpgradeModal && (
<div className="fixed inset-0 bg-slate-900/60 backdrop-blur-sm z-50 flex items-center justify-center p-4">
<div className="bg-white rounded-2xl shadow-2xl max-w-md w-full overflow-hidden animate-in zoom-in-95 duration-200">
<div className="bg-gradient-to-br from-amber-400 to-amber-600 p-6 text-center relative">
<button
onClick={() => {
setShowUpgradeModal(false);
setTokenMessage({ text: '', type: '' });
}}
className="absolute top-4 right-4 text-white/80 hover:text-white"
>
<X className="w-6 h-6" />
</button>
<Crown className="w-12 h-12 text-white mx-auto mb-2 drop-shadow-md" />
<h2 className="text-2xl font-bold text-white">Upgrade ke PRO</h2>
<p className="text-amber-100 text-sm mt-1">Buka akses Full Stack Generator</p>
</div>
<div className="p-6">
<div className="space-y-3 mb-6">
{[
'Buat Silabus, LKPD, & Bank Soal',
'Tanpa limit generasi harian',
'Fitur Ekspor Teks/Dokumen'
].map((fitur, i) => (
<div key={i} className="flex items-center text-slate-700 text-sm">
<CheckCircle className="w-5 h-5 text-emerald-500 mr-3 flex-shrink-0" />
{fitur}
</div>
))}
</div>
<div className="bg-amber-50 border border-amber-200 rounded-lg p-4 mb-6">
<p className="text-center text-xs text-slate-600 mb-2">Dapatkan Token Akses PRO dengan menghubungi Admin:</p>
<a
href={`https://wa.me/${WA_NUMBER}?text=Halo%20Admin,%20saya%20ingin%20upgrade%20EduGen%20ke%20versi%20PRO%20Full%20Stack.`}
target="_blank" rel="noopener noreferrer"
className="flex justify-center items-center w-full bg-emerald-500 hover:bg-emerald-600 text-white font-bold py-2.5 px-4 rounded-md transition shadow-sm text-sm"
>
<svg className="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z"/></svg>
0821-8209-8538
</a>
</div>
<div className="border-t border-slate-100 pt-4">
<label className="block text-xs font-semibold text-slate-700 mb-1.5">Sudah punya Token Unix?</label>
<div className="flex gap-2">
<input
type="text"
value={tokenInput}
onChange={(e) => setTokenInput(e.target.value)}
placeholder="Masukkan Token..."
className="flex-grow border-slate-300 rounded-md p-2 border text-sm uppercase font-mono bg-slate-50 focus:bg-white focus:ring-blue-500 focus:border-blue-500 outline-none"
/>
<button
onClick={verifyToken}
className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md font-medium text-sm transition"
>
Verifikasi
</button>
</div>
{tokenMessage.text && (
<p className={`text-xs mt-2 font-medium ${tokenMessage.type === 'error' ? 'text-red-500' : 'text-emerald-600'}`}>
{tokenMessage.text}
</p>
)}
</div>
</div>
</div>
</div>
)}
</div>
);
}
import React, { useState, useEffect } from 'react';
import {
GraduationCap, User, Crown, Settings2, FileText,
Lock, CheckCircle, Download, Copy, Bot,
Check, X, RefreshCw, Layers, FileSignature, ListOrdered
} from 'lucide-react';
type EducationalLevel = 'SD' | 'SMP' | 'SMA' | 'SMK';
interface FormData {
tingkat: EducationalLevel | '';
jurusan: string;
mapel: string;
kelas: string;
semester: string;
topik: string;
wantsSilabus: boolean;
wantsLKPD: boolean;
wantsSoal: boolean;
}
const VALID_TOKENS = ['PRO-8538-UNIX1', 'PRO-8538-DEV99', 'EDUGEN-FULL-2026'];
const WA_NUMBER = "6282182098538";
export default function EduGenApp() {
const [isPro, setIsPro] = useState(false);
const [usageCount, setUsageCount] = useState(0);
const [isGenerating, setIsGenerating] = useState(false);
const [showUpgradeModal, setShowUpgradeModal] = useState(false);
const [tokenInput, setTokenInput] = useState('');
const [tokenMessage, setTokenMessage] = useState({ text: '', type: '' });
const [generatedResult, setGeneratedResult] = useState<string | null>(null);
const [isCopied, setIsCopied] = useState(false);
const [isExporting, setIsExporting] = useState(false);
}