import React, { useState, useEffect } from 'react'; import { BookOpen, Save, Printer, FileText, ChevronRight, Layout, List, CheckSquare, PenTool, Sparkles, Loader2, AlertCircle, Wand2, ChevronLeft, Edit3, User, MapPin, Calendar } from 'lucide-react'; const ModulAjarApp = () => { // Mode: 'form' (input data) atau 'preview' (lihat hasil) const [viewMode, setViewMode] = useState('form'); // State untuk AI Loading const [isGenerating, setIsGenerating] = useState(false); const [loadingText, setLoadingText] = useState(""); const [aiError, setAiError] = useState(null); // State Data Utama (Input Form) const [formData, setFormData] = useState({ // 1. Identitas guru: "Nama Guru Anda", kepalaSekolah: "Nama Kepala Sekolah", kota: "Malang", tanggal: new Date().toLocaleDateString('id-ID', { day: 'numeric', month: 'long', year: 'numeric' }), jenjang: "SMP", kelas: "8", // 2. Struktur Materi mapel: "Informatika", tujuan: "Peserta didik mampu memahami komponen sistem komputer.", kktp: "", // Akan di-generate atau diisi manual jmlPertemuan: 1, jamPerPertemuan: 2, menitPerJam: 40, modelPembelajaran: "Problem Based Learning", // Default metodePembelajaran: ["Diskusi"], // Array karena bisa multiple // 3. Asesmen asesmenDiagnostik: "Tes Tulis", asesmenFormatif: "Ya", asesmenSumatif: "Ya", buatJobsheet: "Buat" }); // State untuk Hasil Generate (Preview Data) const [previewData, setPreviewData] = useState(null); // --- HANDLERS --- const handleInputChange = (e) => { const { name, value } = e.target; setFormData(prev => ({ ...prev, [name]: value })); }; const toggleMetode = (metode) => { setFormData(prev => { const exists = prev.metodePembelajaran.includes(metode); if (exists) { return { ...prev, metodePembelajaran: prev.metodePembelajaran.filter(m => m !== metode) }; } else { return { ...prev, metodePembelajaran: [...prev.metodePembelajaran, metode] }; } }); }; const setSingleSelection = (key, value) => { setFormData(prev => ({ ...prev, [key]: value })); }; // --- GEMINI API HELPERS --- const callGeminiAPI = async (prompt, isJson = false) => { const apiKey = ""; // API Key disuntikkan oleh sistem const model = "gemini-2.5-flash-preview-09-2025"; const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`; const payload = { contents: [{ parts: [{ text: prompt }] }], ...(isJson && { generationConfig: { responseMimeType: "application/json" } }) }; try { const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) throw new Error(`API Error: ${response.status}`); const result = await response.json(); return result.candidates?.[0]?.content?.parts?.[0]?.text; } catch (error) { console.error("Gemini Error:", error); throw error; } }; // --- AI ACTIONS --- // 1. Generate KKTP saja const handleGenerateKKTP = async () => { if (!formData.tujuan) { setAiError("Isi Tujuan Pembelajaran terlebih dahulu!"); return; } setIsGenerating(true); setLoadingText("Sedang menyusun kriteria ketuntasan..."); setAiError(null); const prompt = `Saya guru ${formData.mapel} kelas ${formData.kelas}. Tujuan Pembelajaran: "${formData.tujuan}". Buatkan 3-5 poin Kriteria Ketuntasan Tujuan Pembelajaran (KKTP) yang spesifik dan terukur. Langsung berikan poin-poinnya saja (jangan gunakan markdown bullet, gunakan angka).`; try { const result = await callGeminiAPI(prompt, false); setFormData(prev => ({ ...prev, kktp: result })); } catch (e) { setAiError("Gagal generate KKTP. Coba lagi."); } finally { setIsGenerating(false); } }; // 2. Generate FULL MODUL (The Big Button) const handleGenerateFullModul = async () => { setIsGenerating(true); setLoadingText("Sedang meracik Modul Ajar lengkap (Langkah, Materi, Asesmen)... Mohon tunggu sebentar."); setAiError(null); // Prompt Raksasa const prompt = ` Bertindaklah sebagai Guru Profesional. Buatkan MODUL AJAR LENGKAP dalam format JSON valid berdasarkan data berikut: DATA INPUT: - Guru: ${formData.guru} - Mapel: ${formData.mapel} (Kelas ${formData.kelas} ${formData.jenjang}) - Alokasi: ${formData.jmlPertemuan} Pertemuan (${formData.jamPerPertemuan} JP x ${formData.menitPerJam} Menit) - Tujuan: ${formData.tujuan} - KKTP: ${formData.kktp || "Buatkan KKTP yang relevan"} - Model: ${formData.modelPembelajaran} - Metode: ${formData.metodePembelajaran.join(", ")} - Asesmen Diagnostik: ${formData.asesmenDiagnostik} - Asesmen Formatif/Sumatif: ${formData.asesmenFormatif}/${formData.asesmenSumatif} - Jobsheet: ${formData.buatJobsheet} TUGAS: Output HARUS JSON valid (tanpa markdown \`\`\`json) dengan struktur persis ini: { "informasiUmum": { "strategiAsesmenAwal": "Deskripsi strategi asesmen diagnostik...", "tindakLanjut": { "mahir": "...", "cakap": "...", "butuhBimbingan": "..." }, "profilPancasila": "Daftar dimensi profil pelajar pancasila (poin-poin)" }, "komponenInti": { "pemahamanBermakna": "...", "pertanyaanPemantik": "...", "persiapanPembelajaran": "..." }, "langkahPembelajaran": { "pendahuluan": "Deskripsi kegiatan awal (apersepsi, motivasi, dll)", "inti": "Deskripsi detail kegiatan inti sesuai sintaks model ${formData.modelPembelajaran}", "penutup": "Deskripsi kegiatan penutup (refleksi, doa)" }, "asesmen": { "diagnostik": "Deskripsi instrumen diagnostik", "formatif": "Deskripsi instrumen formatif", "sumatif": "Deskripsi instrumen sumatif" }, "lampiran": { "materiAjar": "Ringkasan materi lengkap (3-4 paragraf)", "lkpd": "Isi/Soal untuk Lembar Kerja Peserta Didik", "rubrik": "Rubrik penilaian detail" } } Gunakan format text biasa. Jika ada poin penting gunakan tanda bintang seperti *kata penting* untuk penekanan. `; try { const resultString = await callGeminiAPI(prompt, true); const resultJSON = JSON.parse(resultString); // Gabungkan data input manual dengan data hasil generate AI untuk Preview setPreviewData({ ...formData, // Data identitas dari form generated: resultJSON // Data isi dari AI }); setViewMode('preview'); // Pindah ke layar preview } catch (e) { console.error(e); setAiError("Gagal membuat modul. Silakan coba klik tombol Generate sekali lagi."); } finally { setIsGenerating(false); } }; // --- RENDERERS --- if (viewMode === 'preview' && previewData) { return (
SMIPDA MALANG - SMP ISLAM PLUS DAARUL HUDA
{aiError}
{parts.map((part, index) => { // Jika cocok dengan pola *...* atau **...** if (part.match(/^\*{1,2}.*\*{1,2}$/)) { const cleanText = part.replace(/\*/g, ''); // Hapus bintang return {cleanText}; } return part; })}
); }); }; const listText = (text) => { if (!text) return null; return (Modul Ajar Pembelajaran - Kurikulum Merdeka
| 1. Identifikasi Awal & Informasi Umum |
{/* Variasi Kuning Kalem pada Sub-Header */}
Profil Pelajar Pancasila{listText(ai.informasiUmum.profilPancasila)}Asesmen Awal (Diagnostik){ai.informasiUmum.strategiAsesmenAwal} Tindak Lanjut:
|
|---|---|
| 2. Desain Pembelajaran (Komponen Inti) |
Tujuan Pembelajaran{data.tujuan} Kriteria Ketuntasan (KKTP){listText(data.kktp)}
Pemahaman Bermakna{ai.komponenInti.pemahamanBermakna} Pertanyaan Pemantik"{ai.komponenInti.pertanyaanPemantik}" Model & MetodeModel: {data.modelPembelajaran} Metode: {data.metodePembelajaran.join(', ')} |
| 3. Langkah Pembelajaran |
A. Pendahuluan{formatText(ai.langkahPembelajaran.pendahuluan)}B. Kegiatan Inti ({data.modelPembelajaran}){formatText(ai.langkahPembelajaran.inti)}C. Penutup{formatText(ai.langkahPembelajaran.penutup)} |
| 4. Rencana Asesmen |
1. Asesmen Diagnostik ({data.asesmenDiagnostik}): {ai.asesmen.diagnostik} {data.asesmenFormatif === 'Ya' && (2. Asesmen Formatif: {ai.asesmen.formatif} )} {data.asesmenSumatif === 'Ya' && (3. Asesmen Sumatif: {ai.asesmen.sumatif} )} |
Mengetahui,
Kepala Sekolah
{data.kepalaSekolah}
{data.kota}, {data.tanggal}
Guru Mata Pelajaran
{data.guru}