Skip to content

Generator Perangkat Pembelajaran #3938

Description

@khususai763-ai

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>
);

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions