diff --git a/package-lock.json b/package-lock.json
index 40d6bfa..b480f8a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,7 @@
"@testing-library/user-event": "^13.5.0",
"react": "^19.1.1",
"react-dom": "^19.1.1",
+ "react-router-dom": "^7.7.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
@@ -12866,6 +12867,53 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.7.1.tgz",
+ "integrity": "sha512-jVKHXoWRIsD/qS6lvGveckwb862EekvapdHJN/cGmzw40KnJH5gg53ujOJ4qX6EKIK9LSBfFed/xiQ5yeXNrUA==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.7.1.tgz",
+ "integrity": "sha512-bavdk2BA5r3MYalGKZ01u8PGuDBloQmzpBZVhDLrOOv1N943Wq6dcM9GhB3x8b7AbqPMEezauv4PeGkAJfy7FQ==",
+ "license": "MIT",
+ "dependencies": {
+ "react-router": "7.7.1"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
+ "node_modules/react-router/node_modules/cookie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+ "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/react-scripts": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
@@ -13703,6 +13751,12 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
+ "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
+ "license": "MIT"
+ },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
diff --git a/package.json b/package.json
index fdfb489..225d615 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
"@testing-library/user-event": "^13.5.0",
"react": "^19.1.1",
"react-dom": "^19.1.1",
+ "react-router-dom": "^7.7.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
diff --git a/src/App copy.js b/src/App copy.js
new file mode 100644
index 0000000..c1cba04
--- /dev/null
+++ b/src/App copy.js
@@ -0,0 +1,767 @@
+import React, { useState, useEffect, useRef } from 'react';
+import './index.css'; // Pastikan untuk mengimpor file CSS Anda
+
+function App() {
+ // State untuk mengontrol tampilan: 'landing' atau 'dashboard'
+ const [view, setView] = useState('landing');
+ // State untuk modal login/register
+ const [isAuthModalOpen, setAuthModalOpen] = useState(false);
+ const [authForm, setAuthForm] = useState('login'); // 'login' atau 'register'
+ // State untuk bagian aktif di dashboard
+ const [activeDashboardSection, setActiveDashboardSection] = useState('chatbot');
+
+ // State untuk fungsionalitas Chatbot
+ const [messages, setMessages] = useState([
+ { sender: 'bot', text: 'Halo! Ada yang bisa saya bantu hari ini?' }
+ ]);
+ const [chatInput, setChatInput] = useState('');
+ const [isChatLoading, setChatLoading] = useState(false);
+ const chatMessagesEndRef = useRef(null);
+
+ // State untuk fungsionalitas Image Generation
+ const [imagePrompt, setImagePrompt] = useState('');
+ const [generatedImageUrl, setGeneratedImageUrl] = useState('');
+ const [isImageLoading, setImageLoading] = useState(false);
+
+ // State untuk koneksi media sosial di profil
+ const [socialConnections, setSocialConnections] = useState({
+ twitter: false,
+ instagram: false,
+ });
+
+ // Fungsi untuk scroll otomatis ke pesan terbaru
+ const scrollToBottom = () => {
+ chatMessagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
+ };
+
+ useEffect(() => {
+ if (view === 'dashboard' && activeDashboardSection === 'chatbot') {
+ scrollToBottom();
+ }
+ }, [messages, view, activeDashboardSection]);
+
+
+ // --- Fungsi Handler ---
+
+ const showDashboard = () => {
+ setAuthModalOpen(false);
+ setView('dashboard');
+ };
+
+ const showLanding = () => {
+ setView('landing');
+ };
+
+ const handleLogin = (e) => {
+ e.preventDefault();
+ // Logika login simulasi
+ const email = e.target.loginEmail.value;
+ const password = e.target.loginPassword.value;
+ if (email === "user@example.com" && password === "password123") {
+ alert("Login berhasil!");
+ showDashboard();
+ } else {
+ alert("Email atau kata sandi salah.");
+ }
+ };
+
+ const handleRegister = (e) => {
+ e.preventDefault();
+ // Logika registrasi simulasi
+ const password = e.target.registerPassword.value;
+ const confirmPassword = e.target.confirmPassword.value;
+ if (password !== confirmPassword) {
+ alert("Kata sandi tidak cocok.");
+ return;
+ }
+ alert("Registrasi berhasil! Silakan masuk.");
+ setAuthForm('login');
+ };
+
+ const handleSendMessage = async () => {
+ const userMessage = chatInput.trim();
+ if (userMessage === "") return;
+
+ // Tambahkan pesan pengguna ke state
+ setMessages(prev => [...prev, { sender: 'user', text: userMessage }]);
+ setChatInput('');
+ setChatLoading(true);
+
+ // Simulasi panggilan API ke Gemini
+ setTimeout(() => {
+ // Ini adalah respons palsu. Ganti dengan panggilan fetch API asli Anda.
+ const botResponse = `Ini adalah respons AI untuk: "${userMessage}". Dalam aplikasi nyata, ini akan datang dari API.`;
+ setMessages(prev => [...prev, { sender: 'bot', text: botResponse }]);
+ setChatLoading(false);
+ }, 1500);
+ };
+
+ const handleGenerateImage = async () => {
+ if (imagePrompt.trim() === "") {
+ alert("Mohon masukkan deskripsi gambar.");
+ return;
+ }
+ setImageLoading(true);
+ setGeneratedImageUrl('');
+
+ // Simulasi panggilan API pembuatan gambar
+ setTimeout(() => {
+ // Ganti URL ini dengan hasil dari API Anda
+ const mockImageUrl = `https://placehold.co/512x512/142F32/E5FFCC?text=Hasil:+${encodeURIComponent(imagePrompt.substring(0, 20))}`;
+ setGeneratedImageUrl(mockImageUrl);
+ setImageLoading(false);
+ }, 2000);
+ };
+
+ const handleConnectSocial = (platform) => {
+ setSocialConnections(prev => ({
+ ...prev,
+ [platform]: !prev[platform]
+ }));
+ };
+
+ const handleLogout = () => {
+ // Logika logout
+ showLanding();
+ alert("Anda telah berhasil keluar.");
+ };
+
+ // --- Komponen-Komponen Kecil ---
+
+ const Header = () => (
+
+
+
+
Maragen
+
+
+ Beranda
+ Tentang
+ Layanan
+ Kontak
+
+ setAuthModalOpen(true)} className="button-sign-up px-6 py-2 rounded-lg font-semibold hidden md:block">
+ Daftar
+
+
+
+
+
+ );
+
+ const LandingPage = () => (
+
+ {/* Hero Section */}
+
+
+
+ Masa Depan Otomatisasi dengan Teknologi Terbaru
+
+
+ Ahli teknologi untuk meningkatkan bisnis Anda. Mari bawa bisnis Anda lebih jauh.
+
+
+ setAuthModalOpen(true)}
+ className="button-primary px-8 py-4 text-lg sm:text-xl font-semibold rounded-lg focus:outline-none focus:ring-4 focus:ring-blue-300 focus:ring-opacity-50"
+ >
+ Mulai Sekarang
+
+
+ Coba Demo
+
+
+
+
+
+
+
+
+ 5.0
+ dari 80+ ulasan
+
+
+
+ {/* Stat Cards Grid */}
+
+
+
+
+
+
+
+
+
Klien & Mitra Terhormat Kami
+
+
+
+
+
Total Proyek ↑126 bulan ini
+
+
+
+
+
Tahun Layanan Khusus
+
+
+
+
+ {/* Bottom Section (Layanan Otomatisasi) */}
+
+
+
+ Layanan Otomatisasi yang Efisien dan Terintegrasi
+
+
+ Sederhanakan operasi Anda dengan layanan berkualitas dan berorientasi efisiensi.
+
+
+
+
+
+
+
+
+
Alur Kerja Otomatis
+
+ Detail tentang proses otomatisasi, kemampuan integrasi, dan jenis alur kerja yang didukung.
+
+
+
+
+
+
+
+
Kustomisasi Solusi
+
+ Pembuatan solusi otomatisasi khusus dengan opsi desain dan kustomisasi.
+
+
+
+
+
+
+
+
Pemantauan & Analisis
+
+ Prosedur dan sistem untuk memastikan kualitas output otomatisasi yang tinggi.
+
+
+
+
+
+
+ {/* Key Benefits Section */}
+
+
+
+ Total Proyek
+ ↑56%
+
+
+
+ Selesai
+ 10%
+
+
+
+ Sedang Berjalan
+ 13%
+
+
+
+ Ditolak
+ 11%
+
+
+
+
+
+
Peningkatan ↑126 bulan ini
+
+
+
+
+
+ Manfaat Utama Sistem Kami untuk Efisiensi Bisnis Anda
+
+
+ Sistem kami meningkatkan produktivitas, mengurangi biaya, dan mendorong pertumbuhan bisnis.
+
+
+
+
+
+
+
Meningkatkan Kualitas dengan Teknologi
+
+ Dengan teknologi canggih, kami membantu Anda mencapai kualitas produk terbaik. Pelajari bagaimana kami dapat meningkatkan standar Anda.
+
+
+
+
+
+
+
Optimasi Proses Produksi
+
+ Meningkatkan efisiensi dan produktivitas pabrik dengan solusi inovatif kami. Lihat bagaimana teknologi terbaru dapat memaksimalkan output Anda.
+
+
+
+
+
+
+
Produksi Berbasis AI
+
+ Manfaatkan kekuatan AI untuk mengubah proses manufaktur Anda, mencapai hasil yang lebih cepat dan efektif.
+
+
+
+
+
+
+
+ {/* Tailored Plans Section */}
+
+
+
+ Paket yang Disesuaikan untuk Skala Bisnis Anda
+
+
+ Harga fleksibel untuk setiap ukuran bisnis.
+
+
+
+
+
+
Starter
+
+ Paket ini menawarkan fitur dasar yang Anda butuhkan untuk memulai.
+
+
+ $39
+ / bulan
+
+
+ Mulai Sekarang
+
+
+
Produksi hingga 10.000 unit per bulan
+
Dukungan teknis 24/7
+
Akses ke dasbor produksi
+
Pengaturan awal
+
+
+
+
+
Enterprise
+
+ Paket ini menyediakan akses penuh ke semua fitur premium.
+
+
+ $99
+ / bulan
+
+
+ Mulai Sekarang
+
+
+
Unit produksi tak terbatas
+
Manajer akun khusus
+
Solusi manufaktur yang disesuaikan
+
Optimalisasi produksi prediktif
+
+
+
+
+
+ {/* Seamless Integrations Section */}
+
+
+
+ Memberdayakan Perusahaan Top dengan Integrasi Tanpa Batas
+
+
+ Rasakan koneksi tanpa batas dengan solusi inovatif kami, dirancang untuk berintegrasi dengan mudah dengan sistem Anda yang ada, meningkatkan produktivitas, dan mendorong bisnis Anda menuju kesuksesan yang lebih besar.
+
+
+ Bekerja Bersama Kami
+
+
+
+
+
+ {/* From Idea to Production Section */}
+
+
+
+ Dari Ide ke Produksi dalam Hitungan Hari
+
+
+ Percepat produksi Anda dengan teknologi kami. Kurangi waktu henti dan optimalkan biaya. Dapatkan penawaran spesial sekarang!
+
+
+ Bekerja Bersama Kami
+
+
+
+
+
+
+ );
+
+ const Footer = () => (
+
+ );
+
+ const AuthModal = () => (
+
+ );
+
+ const Dashboard = () => {
+ const sidebarItems = [
+ { id: 'chatbot', icon: 'fa-comments', label: 'Chatbot' },
+ { id: 'imageGen', icon: 'fa-image', label: 'Buat Gambar' },
+ { id: 'scheduling', icon: 'fa-calendar-alt', label: 'Penjadwalan' },
+ { id: 'monitoring', icon: 'fa-chart-line', label: 'Pemantauan Konten' },
+ { id: 'notifications', icon: 'fa-bell', label: 'Notifikasi' },
+ { id: 'profile', icon: 'fa-user-circle', label: 'Pengaturan Profil' },
+ ];
+
+ return (
+
+ {/* Sidebar */}
+
+
+ {/* Main Content */}
+
+ {activeDashboardSection === 'chatbot' && (
+
+ Chatbot AI
+ Ajukan pertanyaan atau mulai percakapan dengan AI kami.
+
+
+ {messages.map((msg, index) => (
+
+ {msg.text}
+
+ ))}
+
+
+ {isChatLoading &&
Mengetik...
}
+
+ setChatInput(e.target.value)}
+ onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
+ autoFocus
+ />
+ Kirim
+
+
+
+ )}
+ {activeDashboardSection === 'imageGen' && (
+
+ Buat Gambar AI
+ Masukkan deskripsi untuk membuat gambar.
+
+
setImagePrompt(e.target.value)}
+ />
+
+ {isImageLoading ? 'Membuat...' : 'Buat Gambar'}
+
+ {isImageLoading &&
Membuat gambar...
}
+ {generatedImageUrl && (
+
+
+
+ Jadwalkan
+ Posting Langsung
+
+
+ )}
+
+
+ )}
+ {activeDashboardSection === 'scheduling' && (
+
+ Penjadwalan Konten
+ Kelola konten yang akan dipublikasikan di masa mendatang.
+
+
+
+ Postingan Blog: "Masa Depan Otomatisasi"
+ 2025-08-15 10:00 AM
+
+
+ Gambar AI: "Pemandangan Kota Futuristik"
+ 2025-08-18 02:30 PM
+
+
+
+ Tambah Jadwal Baru
+
+ )}
+ {activeDashboardSection === 'monitoring' && (
+
+ Pemantauan & Analisis Tren
+ Pantau kinerja konten Anda dan temukan tren viral berikutnya.
+
+
+
Kinerja Konten Saya
+
+
+
Total Penayangan
+
1.2M
+
↑15% bulan ini
+
+
+
Total Suka
+
89K
+
↑12% bulan ini
+
+
+
Pengikut Baru
+
5,210
+
↑8% bulan ini
+
+
+
+
+
+
Konten yang Sedang Tren
+
+ {/* Konten tren akan diisi oleh data dari API */}
+
Fitur ini sedang dalam pengembangan.
+
+
+
+ )}
+ {activeDashboardSection === 'notifications' && (
+
+ Notifikasi
+ Pembaruan terkini tentang akun dan konten Anda.
+
+ {/* Notifikasi akan diisi oleh data dari API */}
+ Postingan Anda "Masa Depan Otomatisasi" telah dijadwalkan.
+ Selamat! Anda mendapatkan 50 pengikut baru minggu ini.
+
+
+ )}
+ {activeDashboardSection === 'profile' && (
+
+ Pengaturan Profil
+ Kelola informasi akun dan koneksi media sosial Anda.
+
+
+ Nama Pengguna
+
+
+
+ Email
+
+
+
+
Autentikasi Media Sosial
+
+
+
+
+
Twitter
+
+ {socialConnections.twitter ? 'Terhubung' : 'Belum Terhubung'}
+
+
+
+
handleConnectSocial('twitter')} className="button-primary py-2 px-4 rounded-lg text-sm">
+ {socialConnections.twitter ? 'Putuskan' : 'Hubungkan'}
+
+
+
+
+
+
+
Instagram
+
+ {socialConnections.instagram ? 'Terhubung' : 'Belum Terhubung'}
+
+
+
+
handleConnectSocial('instagram')} className="button-primary py-2 px-4 rounded-lg text-sm">
+ {socialConnections.instagram ? 'Putuskan' : 'Hubungkan'}
+
+
+
+
+ Simpan Perubahan
+
+ Keluar
+
+
+
+
+ )}
+
+
+ );
+ };
+
+
+ return (
+ <>
+
+ {view === 'landing' && }
+ {view === 'dashboard' && }
+ {isAuthModalOpen && }
+ >
+ );
+}
+
+export default App;
\ No newline at end of file
diff --git a/src/App.js b/src/App.js
index c1cba04..2181c94 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,766 +1,17 @@
-import React, { useState, useEffect, useRef } from 'react';
-import './index.css'; // Pastikan untuk mengimpor file CSS Anda
+import { Routes, Route } from 'react-router-dom';
+import LoginPage from './pages/LoginPage';
+import OrganizationPage from './pages/OrganizationPage';
+import DashboardPage from './pages/DashboardPage';
+import InputDataPage from './pages/InputDataPage';
function App() {
- // State untuk mengontrol tampilan: 'landing' atau 'dashboard'
- const [view, setView] = useState('landing');
- // State untuk modal login/register
- const [isAuthModalOpen, setAuthModalOpen] = useState(false);
- const [authForm, setAuthForm] = useState('login'); // 'login' atau 'register'
- // State untuk bagian aktif di dashboard
- const [activeDashboardSection, setActiveDashboardSection] = useState('chatbot');
-
- // State untuk fungsionalitas Chatbot
- const [messages, setMessages] = useState([
- { sender: 'bot', text: 'Halo! Ada yang bisa saya bantu hari ini?' }
- ]);
- const [chatInput, setChatInput] = useState('');
- const [isChatLoading, setChatLoading] = useState(false);
- const chatMessagesEndRef = useRef(null);
-
- // State untuk fungsionalitas Image Generation
- const [imagePrompt, setImagePrompt] = useState('');
- const [generatedImageUrl, setGeneratedImageUrl] = useState('');
- const [isImageLoading, setImageLoading] = useState(false);
-
- // State untuk koneksi media sosial di profil
- const [socialConnections, setSocialConnections] = useState({
- twitter: false,
- instagram: false,
- });
-
- // Fungsi untuk scroll otomatis ke pesan terbaru
- const scrollToBottom = () => {
- chatMessagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
- };
-
- useEffect(() => {
- if (view === 'dashboard' && activeDashboardSection === 'chatbot') {
- scrollToBottom();
- }
- }, [messages, view, activeDashboardSection]);
-
-
- // --- Fungsi Handler ---
-
- const showDashboard = () => {
- setAuthModalOpen(false);
- setView('dashboard');
- };
-
- const showLanding = () => {
- setView('landing');
- };
-
- const handleLogin = (e) => {
- e.preventDefault();
- // Logika login simulasi
- const email = e.target.loginEmail.value;
- const password = e.target.loginPassword.value;
- if (email === "user@example.com" && password === "password123") {
- alert("Login berhasil!");
- showDashboard();
- } else {
- alert("Email atau kata sandi salah.");
- }
- };
-
- const handleRegister = (e) => {
- e.preventDefault();
- // Logika registrasi simulasi
- const password = e.target.registerPassword.value;
- const confirmPassword = e.target.confirmPassword.value;
- if (password !== confirmPassword) {
- alert("Kata sandi tidak cocok.");
- return;
- }
- alert("Registrasi berhasil! Silakan masuk.");
- setAuthForm('login');
- };
-
- const handleSendMessage = async () => {
- const userMessage = chatInput.trim();
- if (userMessage === "") return;
-
- // Tambahkan pesan pengguna ke state
- setMessages(prev => [...prev, { sender: 'user', text: userMessage }]);
- setChatInput('');
- setChatLoading(true);
-
- // Simulasi panggilan API ke Gemini
- setTimeout(() => {
- // Ini adalah respons palsu. Ganti dengan panggilan fetch API asli Anda.
- const botResponse = `Ini adalah respons AI untuk: "${userMessage}". Dalam aplikasi nyata, ini akan datang dari API.`;
- setMessages(prev => [...prev, { sender: 'bot', text: botResponse }]);
- setChatLoading(false);
- }, 1500);
- };
-
- const handleGenerateImage = async () => {
- if (imagePrompt.trim() === "") {
- alert("Mohon masukkan deskripsi gambar.");
- return;
- }
- setImageLoading(true);
- setGeneratedImageUrl('');
-
- // Simulasi panggilan API pembuatan gambar
- setTimeout(() => {
- // Ganti URL ini dengan hasil dari API Anda
- const mockImageUrl = `https://placehold.co/512x512/142F32/E5FFCC?text=Hasil:+${encodeURIComponent(imagePrompt.substring(0, 20))}`;
- setGeneratedImageUrl(mockImageUrl);
- setImageLoading(false);
- }, 2000);
- };
-
- const handleConnectSocial = (platform) => {
- setSocialConnections(prev => ({
- ...prev,
- [platform]: !prev[platform]
- }));
- };
-
- const handleLogout = () => {
- // Logika logout
- showLanding();
- alert("Anda telah berhasil keluar.");
- };
-
- // --- Komponen-Komponen Kecil ---
-
- const Header = () => (
-
-
-
-
Maragen
-
-
- Beranda
- Tentang
- Layanan
- Kontak
-
- setAuthModalOpen(true)} className="button-sign-up px-6 py-2 rounded-lg font-semibold hidden md:block">
- Daftar
-
-
-
-
-
- );
-
- const LandingPage = () => (
-
- {/* Hero Section */}
-
-
-
- Masa Depan Otomatisasi dengan Teknologi Terbaru
-
-
- Ahli teknologi untuk meningkatkan bisnis Anda. Mari bawa bisnis Anda lebih jauh.
-
-
- setAuthModalOpen(true)}
- className="button-primary px-8 py-4 text-lg sm:text-xl font-semibold rounded-lg focus:outline-none focus:ring-4 focus:ring-blue-300 focus:ring-opacity-50"
- >
- Mulai Sekarang
-
-
- Coba Demo
-
-
-
-
-
-
-
-
- 5.0
- dari 80+ ulasan
-
-
-
- {/* Stat Cards Grid */}
-
-
-
-
-
-
-
-
-
Klien & Mitra Terhormat Kami
-
-
-
-
-
Total Proyek ↑126 bulan ini
-
-
-
-
-
Tahun Layanan Khusus
-
-
-
-
- {/* Bottom Section (Layanan Otomatisasi) */}
-
-
-
- Layanan Otomatisasi yang Efisien dan Terintegrasi
-
-
- Sederhanakan operasi Anda dengan layanan berkualitas dan berorientasi efisiensi.
-
-
-
-
-
-
-
-
-
Alur Kerja Otomatis
-
- Detail tentang proses otomatisasi, kemampuan integrasi, dan jenis alur kerja yang didukung.
-
-
-
-
-
-
-
-
Kustomisasi Solusi
-
- Pembuatan solusi otomatisasi khusus dengan opsi desain dan kustomisasi.
-
-
-
-
-
-
-
-
Pemantauan & Analisis
-
- Prosedur dan sistem untuk memastikan kualitas output otomatisasi yang tinggi.
-
-
-
-
-
-
- {/* Key Benefits Section */}
-
-
-
- Total Proyek
- ↑56%
-
-
-
- Selesai
- 10%
-
-
-
- Sedang Berjalan
- 13%
-
-
-
- Ditolak
- 11%
-
-
-
-
-
-
Peningkatan ↑126 bulan ini
-
-
-
-
-
- Manfaat Utama Sistem Kami untuk Efisiensi Bisnis Anda
-
-
- Sistem kami meningkatkan produktivitas, mengurangi biaya, dan mendorong pertumbuhan bisnis.
-
-
-
-
-
-
-
Meningkatkan Kualitas dengan Teknologi
-
- Dengan teknologi canggih, kami membantu Anda mencapai kualitas produk terbaik. Pelajari bagaimana kami dapat meningkatkan standar Anda.
-
-
-
-
-
-
-
Optimasi Proses Produksi
-
- Meningkatkan efisiensi dan produktivitas pabrik dengan solusi inovatif kami. Lihat bagaimana teknologi terbaru dapat memaksimalkan output Anda.
-
-
-
-
-
-
-
Produksi Berbasis AI
-
- Manfaatkan kekuatan AI untuk mengubah proses manufaktur Anda, mencapai hasil yang lebih cepat dan efektif.
-
-
-
-
-
-
-
- {/* Tailored Plans Section */}
-
-
-
- Paket yang Disesuaikan untuk Skala Bisnis Anda
-
-
- Harga fleksibel untuk setiap ukuran bisnis.
-
-
-
-
-
-
Starter
-
- Paket ini menawarkan fitur dasar yang Anda butuhkan untuk memulai.
-
-
- $39
- / bulan
-
-
- Mulai Sekarang
-
-
-
Produksi hingga 10.000 unit per bulan
-
Dukungan teknis 24/7
-
Akses ke dasbor produksi
-
Pengaturan awal
-
-
-
-
-
Enterprise
-
- Paket ini menyediakan akses penuh ke semua fitur premium.
-
-
- $99
- / bulan
-
-
- Mulai Sekarang
-
-
-
Unit produksi tak terbatas
-
Manajer akun khusus
-
Solusi manufaktur yang disesuaikan
-
Optimalisasi produksi prediktif
-
-
-
-
-
- {/* Seamless Integrations Section */}
-
-
-
- Memberdayakan Perusahaan Top dengan Integrasi Tanpa Batas
-
-
- Rasakan koneksi tanpa batas dengan solusi inovatif kami, dirancang untuk berintegrasi dengan mudah dengan sistem Anda yang ada, meningkatkan produktivitas, dan mendorong bisnis Anda menuju kesuksesan yang lebih besar.
-
-
- Bekerja Bersama Kami
-
-
-
-
-
- {/* From Idea to Production Section */}
-
-
-
- Dari Ide ke Produksi dalam Hitungan Hari
-
-
- Percepat produksi Anda dengan teknologi kami. Kurangi waktu henti dan optimalkan biaya. Dapatkan penawaran spesial sekarang!
-
-
- Bekerja Bersama Kami
-
-
-
-
-
-
- );
-
- const Footer = () => (
-
- );
-
- const AuthModal = () => (
-
- );
-
- const Dashboard = () => {
- const sidebarItems = [
- { id: 'chatbot', icon: 'fa-comments', label: 'Chatbot' },
- { id: 'imageGen', icon: 'fa-image', label: 'Buat Gambar' },
- { id: 'scheduling', icon: 'fa-calendar-alt', label: 'Penjadwalan' },
- { id: 'monitoring', icon: 'fa-chart-line', label: 'Pemantauan Konten' },
- { id: 'notifications', icon: 'fa-bell', label: 'Notifikasi' },
- { id: 'profile', icon: 'fa-user-circle', label: 'Pengaturan Profil' },
- ];
-
- return (
-
- {/* Sidebar */}
-
-
- {/* Main Content */}
-
- {activeDashboardSection === 'chatbot' && (
-
- Chatbot AI
- Ajukan pertanyaan atau mulai percakapan dengan AI kami.
-
-
- {messages.map((msg, index) => (
-
- {msg.text}
-
- ))}
-
-
- {isChatLoading &&
Mengetik...
}
-
- setChatInput(e.target.value)}
- onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
- autoFocus
- />
- Kirim
-
-
-
- )}
- {activeDashboardSection === 'imageGen' && (
-
- Buat Gambar AI
- Masukkan deskripsi untuk membuat gambar.
-
-
setImagePrompt(e.target.value)}
- />
-
- {isImageLoading ? 'Membuat...' : 'Buat Gambar'}
-
- {isImageLoading &&
Membuat gambar...
}
- {generatedImageUrl && (
-
-
-
- Jadwalkan
- Posting Langsung
-
-
- )}
-
-
- )}
- {activeDashboardSection === 'scheduling' && (
-
- Penjadwalan Konten
- Kelola konten yang akan dipublikasikan di masa mendatang.
-
-
-
- Postingan Blog: "Masa Depan Otomatisasi"
- 2025-08-15 10:00 AM
-
-
- Gambar AI: "Pemandangan Kota Futuristik"
- 2025-08-18 02:30 PM
-
-
-
- Tambah Jadwal Baru
-
- )}
- {activeDashboardSection === 'monitoring' && (
-
- Pemantauan & Analisis Tren
- Pantau kinerja konten Anda dan temukan tren viral berikutnya.
-
-
-
Kinerja Konten Saya
-
-
-
Total Penayangan
-
1.2M
-
↑15% bulan ini
-
-
-
Total Suka
-
89K
-
↑12% bulan ini
-
-
-
Pengikut Baru
-
5,210
-
↑8% bulan ini
-
-
-
-
-
-
Konten yang Sedang Tren
-
- {/* Konten tren akan diisi oleh data dari API */}
-
Fitur ini sedang dalam pengembangan.
-
-
-
- )}
- {activeDashboardSection === 'notifications' && (
-
- Notifikasi
- Pembaruan terkini tentang akun dan konten Anda.
-
- {/* Notifikasi akan diisi oleh data dari API */}
- Postingan Anda "Masa Depan Otomatisasi" telah dijadwalkan.
- Selamat! Anda mendapatkan 50 pengikut baru minggu ini.
-
-
- )}
- {activeDashboardSection === 'profile' && (
-
- Pengaturan Profil
- Kelola informasi akun dan koneksi media sosial Anda.
-
-
- Nama Pengguna
-
-
-
- Email
-
-
-
-
Autentikasi Media Sosial
-
-
-
-
-
Twitter
-
- {socialConnections.twitter ? 'Terhubung' : 'Belum Terhubung'}
-
-
-
-
handleConnectSocial('twitter')} className="button-primary py-2 px-4 rounded-lg text-sm">
- {socialConnections.twitter ? 'Putuskan' : 'Hubungkan'}
-
-
-
-
-
-
-
Instagram
-
- {socialConnections.instagram ? 'Terhubung' : 'Belum Terhubung'}
-
-
-
-
handleConnectSocial('instagram')} className="button-primary py-2 px-4 rounded-lg text-sm">
- {socialConnections.instagram ? 'Putuskan' : 'Hubungkan'}
-
-
-
-
- Simpan Perubahan
-
- Keluar
-
-
-
-
- )}
-
-
- );
- };
-
-
return (
- <>
-
- {view === 'landing' && }
- {view === 'dashboard' && }
- {isAuthModalOpen && }
- >
+
+ } />
+ } />
+ } />
+ } />
+
);
}
diff --git a/src/components/AddDocumentModal.js b/src/components/AddDocumentModal.js
new file mode 100644
index 0000000..028650e
--- /dev/null
+++ b/src/components/AddDocumentModal.js
@@ -0,0 +1,136 @@
+import { useState } from 'react';
+
+// --- ICONS (no changes) ---
+const CloseIcon = () => ( );
+const PlusIcon = () => ( );
+const TrashIcon = () => ( );
+
+// --- Objek Templates (no changes) ---
+const templates = {
+ 'KTP':{icon:'👤',fields:[{name:'NIK',type:'Number'},{name:'Nama',type:'Text'},{name:'Jenis Kelamin',type:'Selection',options:[{value:'Laki-laki'},{value:'Perempuan'}]},{name:'Tempat Lahir',type:'Text'},{name:'Tanggal Lahir',type:'Date'},]},
+ 'KK':{icon:'👨👩👧👦',fields:[{name:'Nomor KK',type:'Number'},{name:'Nama Kepala Keluarga',type:'Text'},{name:'Alamat',type:'Text'},{name:'RT/RW',type:'Text'},{name:'Desa/Kelurahan',type:'Text'},{name:'Kecamatan',type:'Text'},{name:'Kabupaten/Kota',type:'Text'},{name:'Provinsi',type:'Text'},{name:'Tanggal Dikeluarkan',type:'Date'},]},
+ 'Akta Kelahiran':{icon:'📜',fields:[{name:'Nomor Akta',type:'Text'},{name:'Nama Lengkap',type:'Text'},{name:'Jenis Kelamin',type:'Selection',options:[{value:'Laki-laki'},{value:'Perempuan'}]},{name:'Tempat Lahir',type:'Text'},{name:'Tanggal Lahir',type:'Date'},{name:'Nama Ayah',type:'Text'},{name:'Nama Ibu',type:'Text'},]},
+ 'Custom':{icon:'⚙️',fields:[]}
+};
+const templateNames = Object.keys(templates);
+
+export default function AddDocumentModal({ isOpen, onClose }) {
+ // --- State and handlers (no changes) ---
+ const [selectedTemplate, setSelectedTemplate] = useState(null);
+ const [docTypeName, setDocTypeName] = useState('');
+ const [fields, setFields] = useState([]);
+ const handleSelectTemplate = (templateName) => {
+ setSelectedTemplate(templateName);
+ const templateData = templates[templateName];
+ setDocTypeName(templateName === 'Custom' ? '' : templateName);
+ if (templateData.fields && templateData.fields.length > 0) {
+ const newFields = templateData.fields.map(field => ({
+ id: Date.now() + Math.random(),
+ name: field.name,
+ type: field.type,
+ options: field.options ? field.options.map(opt => ({ id: Date.now() + Math.random(), value: opt.value })) : []
+ }));
+ setFields(newFields);
+ } else {
+ setFields([{ id: Date.now(), name: '', type: 'Text', options: [] }]);
+ }
+ };
+ const handleAddField = () => {setFields([...fields, { id: Date.now(), name: '', type: 'Text', options: [] }]);};
+ const handleRemoveField = (id) => {setFields(fields.filter(field => field.id !== id));};
+ const handleFieldChange = (id, event) => {const { name, value } = event.target; setFields(fields.map(field => field.id === id ? { ...field, [name]: value } : field));};
+ const handleAddOption = (fieldId) => {setFields(fields.map(field =>field.id === fieldId? { ...field, options: [...field.options, { id: Date.now(), value: '' }] }: field));};
+ const handleOptionChange = (fieldId, optionId, event) => {const { value } = event.target;setFields(fields.map(field =>field.id === fieldId? { ...field, options: field.options.map(opt => opt.id === optionId ? { ...opt, value } : opt) }: field));};
+ const handleRemoveOption = (fieldId, optionId) => {setFields(fields.map(field =>field.id === fieldId? { ...field, options: field.options.filter(opt => opt.id !== optionId) }: field));};
+ const handleSave = () => {
+ const newDocumentType = {
+ template: selectedTemplate,
+ name: docTypeName,
+ fields: fields.map(({ id, name, type, options }) => ({
+ name,
+ type,
+ ...(type === 'Selection' && { options: options.map(opt => opt.value) })
+ }))
+ };
+ console.log("Menyimpan data JSON:", JSON.stringify(newDocumentType, null, 2));
+ onClose();
+ setSelectedTemplate(null);
+ };
+
+ if (!isOpen) return null;
+
+ return (
+
+
+
{setSelectedTemplate(null); onClose();}} className="absolute top-4 right-4 text-gray-500 hover:text-gray-800">
+
Tambah Jenis Dokumen Baru
+
+ {!selectedTemplate &&
+
+
Pilih Template
+
+ {templateNames.map(name => (
+
handleSelectTemplate(name)} className={`p-4 border-2 rounded-xl text-center cursor-pointer transition-all duration-200 ${selectedTemplate === name ? 'border-yellow-400 ring-2 ring-yellow-200' : 'border-gray-200 hover:border-blue-500'}`}>
+
{templates[name].icon}
+
{name}
+
+ ))}
+
+
+ }
+
+ {selectedTemplate && (
+
+
+ Nama Tipe Dokumen
+ setDocTypeName(e.target.value)} placeholder="Contoh: KTP, KK, Ijazah, dll" className="w-full mt-2 p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 transition"/>
+
+
+
Ekspektasi data
+
+ {fields.map((field) => (
+ // PERUBAHAN: Menambahkan class `relative` dan `pt-4` pada container field
+
+
+ {/* PERUBAHAN: Tombol hapus dipindah ke sini dan diubah gayanya */}
+
handleRemoveField(field.id)}
+ className="absolute top-1 right-1 w-7 h-7 bg-red-500 text-white rounded-full hover:bg-red-600 flex items-center justify-center border-2 border-white"
+ >
+
+
+
+
+ handleFieldChange(field.id, e)} className="flex-grow p-3 border border-gray-300 rounded-lg"/>
+ handleFieldChange(field.id, e)} className="p-3 border border-gray-300 rounded-lg bg-white w-full sm:w-auto">
+ Text Number Date Selection
+
+ {/* Tombol hapus yang lama sudah dihapus dari sini */}
+
+ {field.type === 'Selection' && (
+
+
+ {field.options.map(option => (
+
+ handleOptionChange(field.id, option.id, e)} className="flex-grow p-2 text-sm border border-gray-200 rounded-md"/>
+ handleRemoveOption(field.id, option.id)} className="flex-shrink-0 w-7 h-7 bg-gray-200 text-gray-600 rounded hover:bg-red-200 hover:text-red-700 flex items-center justify-center text-xs">X
+
+ ))}
+
+
handleAddOption(field.id)} className="mt-2 text-sm text-blue-600 font-semibold hover:underline">+ Tambah Ekspektasi Pilihan
+
+ )}
+
+ ))}
+
+
Tambah Field
+
+
+ Tambah
+ {setSelectedTemplate(null); onClose();}} className="py-2 px-6 bg-gray-100 text-gray-700 font-semibold rounded-lg hover:bg-gray-200">Batal
+
+
+ )}
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/LandingPage.js b/src/components/LandingPage.js
new file mode 100644
index 0000000..11155c5
--- /dev/null
+++ b/src/components/LandingPage.js
@@ -0,0 +1,29 @@
+import { Link } from 'react-router-dom';
+
+const DocumentIcon = () => (
+
+
+
+);
+
+export default function LoginPage() {
+ return (
+
+
+
+
SOLID DATA
+
Kelola data dokumen Anda dengan mudah
+
+ Masuk
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index d563c0f..f332564 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,17 +1,13 @@
-import React from 'react';
-import ReactDOM from 'react-dom/client';
-import './index.css';
-import App from './App';
-import reportWebVitals from './reportWebVitals';
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import App from './App.js'
+import './index.css'
+import { BrowserRouter } from 'react-router-dom'
-const root = ReactDOM.createRoot(document.getElementById('root'));
-root.render(
+ReactDOM.createRoot(document.getElementById('root')).render(
-
-
-);
-
-// If you want to start measuring performance in your app, pass a function
-// to log results (for example: reportWebVitals(console.log))
-// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
-reportWebVitals();
+
+
+
+ ,
+)
\ No newline at end of file
diff --git a/src/pages/DashboardPage.js b/src/pages/DashboardPage.js
new file mode 100644
index 0000000..5b518de
--- /dev/null
+++ b/src/pages/DashboardPage.js
@@ -0,0 +1,64 @@
+import { useState } from 'react';
+import { Link } from 'react-router-dom';
+import AddDocumentModal from '../components/AddDocumentModal'; // Kita akan buat ini
+
+// Data dummy
+const documentTypes = [
+ { name: 'Akta Kelahiran', count: 0 },
+ { name: 'Ijazah', count: 0 },
+ { name: 'KK', count: 0 },
+ { name: 'KTP', count: 6 },
+ { name: 'Polinema', count: 3 },
+ { name: 'Sampul Buku', count: 1 },
+];
+
+const StatCard = ({ title, value }) => (
+
+);
+
+export default function DashboardPage() {
+ const [isModalOpen, setIsModalOpen] = useState(false);
+
+ return (
+
+
+ {/* Statistik */}
+
+
+
+
+
+
+ {/* Daftar Jenis Dokumen */}
+
+
+
Daftar Jenis Dokumen
+ setIsModalOpen(true)}
+ className="bg-blue-600 text-white font-semibold py-2 px-4 rounded-lg hover:bg-blue-700 transition-colors"
+ >
+ + Tambah Jenis
+
+
+
+ {documentTypes.map((doc, index) => (
+
+
{index + 1}
+
+
{doc.name}
+
{doc.count} data tersedia
+
+ {/* Arrow Icon */}
+
+ ))}
+
+
+
+
+
setIsModalOpen(false)} />
+
+ );
+}
\ No newline at end of file
diff --git a/src/pages/InputDataPage.js b/src/pages/InputDataPage.js
new file mode 100644
index 0000000..ba4288c
--- /dev/null
+++ b/src/pages/InputDataPage.js
@@ -0,0 +1,152 @@
+import { useState, useRef } from 'react';
+import { useParams, Link } from 'react-router-dom';
+
+// Ikon (tidak ada perubahan)
+const BackIcon = () => ( );
+const UploadIcon = () => ( );
+const CameraIcon = () => ( );
+const ImageIcon = () => ( );
+const TrashIcon = () => ( );
+
+
+export default function InputDataPage() {
+ const { docType } = useParams();
+ const [filesToUpload, setFilesToUpload] = useState([]);
+ const [isUploading, setIsUploading] = useState(false);
+ const fileInputRef = useRef(null);
+ const cameraInputRef = useRef(null);
+ const [isDragging, setIsDragging] = useState(false);
+
+ // --- PERUBAHAN: State baru untuk progress upload ---
+ const [uploadProgress, setUploadProgress] = useState(0);
+
+ const handleFiles = (newFiles) => {
+ const imageFiles = Array.from(newFiles).filter(file => file.type.startsWith('image/'));
+ setFilesToUpload(prevFiles => {
+ const uniqueNewFiles = imageFiles.filter(newFile =>
+ !prevFiles.some(existingFile => existingFile.name === newFile.name && existingFile.size === newFile.size)
+ );
+ return [...prevFiles, ...uniqueNewFiles];
+ });
+ };
+
+ const removeFile = (index) => {
+ setFilesToUpload(prevFiles => prevFiles.filter((_, i) => i !== index));
+ };
+
+ // --- PERUBAHAN: Fungsi handleUpload diubah total ---
+ const handleUpload = async () => {
+ if (filesToUpload.length === 0) return;
+
+ setIsUploading(true);
+ setUploadProgress(0);
+
+ const totalFiles = filesToUpload.length;
+ const successfulUploads = [];
+ const failedUploads = [];
+
+ for (let i = 0; i < totalFiles; i++) {
+ const file = filesToUpload[i];
+ setUploadProgress(i + 1); // Update progress sebelum upload
+
+ const formData = new FormData();
+ formData.append('document', file); // Kirim satu file
+
+ try {
+ console.log(`Mengupload file ${i + 1}/${totalFiles}: ${file.name}`);
+ const response = await fetch('https://api.kedaimaster.com/scan-documents', {
+ method: 'POST',
+ body: formData,
+ });
+
+ if (!response.ok) {
+ // Lemparkan error agar ditangkap oleh catch block
+ throw new Error(`Gagal mengupload ${file.name}`);
+ }
+
+ const resultJson = await response.json();
+ successfulUploads.push({ file: file.name, result: resultJson });
+ console.log(`Sukses mengupload ${file.name}:`, resultJson);
+
+ } catch (error) {
+ failedUploads.push(file.name);
+ console.error(`Error saat mengupload ${file.name}:`, error);
+ }
+ }
+
+ setIsUploading(false);
+ setUploadProgress(0);
+
+ // Beri ringkasan hasil upload
+ alert(`Selesai! Berhasil: ${successfulUploads.length}, Gagal: ${failedUploads.length}`);
+
+ // Reset daftar file setelah semua proses selesai
+ setFilesToUpload([]);
+ };
+
+ return (
+
+
+
+ Input Data untuk {docType.replace('-', ' ')}
+
+
+
+
+
+
setIsDragging(true)}
+ onDragLeave={() => setIsDragging(false)}
+ onDragOver={(e) => e.preventDefault()}
+ onDrop={(e) => { e.preventDefault(); setIsDragging(false); handleFiles(e.dataTransfer.files); }}
+ >
+
handleFiles(e.target.files)}/>
+
handleFiles(e.target.files)}/>
+
Upload Dokumen
+
Pilih file atau ambil gambar dari kamera.
+
+ fileInputRef.current.click()} className="w-full flex items-center justify-center bg-blue-600 text-white font-semibold py-3 px-4 rounded-lg hover:bg-blue-700 transition-colors"> Upload File
+ cameraInputRef.current.click()} className="w-full flex items-center justify-center bg-white text-gray-700 font-semibold py-3 px-4 rounded-lg border border-gray-300 hover:bg-gray-100 transition-colors"> Ambil Gambar
+
+
Atau, seret & lepas file di area ini.
+
+
+
+
Pratinjau
+ {filesToUpload.length > 0 ? (
+
+ {filesToUpload.map((file, index) => (
+
+
+
+ removeFile(index)} className="text-white p-2 bg-red-500 rounded-full hover:bg-red-600">
+
+
+ ))}
+
+ ) : (
+
+
+
Pratinjau gambar akan muncul di sini.
+
+ )}
+
+
+
+ {filesToUpload.length > 0 && (
+
+
+ {/* --- PERUBAHAN: Teks tombol dinamis dengan progress --- */}
+ {isUploading
+ ? `Mengupload file ${uploadProgress} dari ${filesToUpload.length}...`
+ : `Upload ${filesToUpload.length} Gambar & Scan Data`
+ }
+
+
+ )}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/pages/LoginPage.js b/src/pages/LoginPage.js
new file mode 100644
index 0000000..11155c5
--- /dev/null
+++ b/src/pages/LoginPage.js
@@ -0,0 +1,29 @@
+import { Link } from 'react-router-dom';
+
+const DocumentIcon = () => (
+
+
+
+);
+
+export default function LoginPage() {
+ return (
+
+
+
+
SOLID DATA
+
Kelola data dokumen Anda dengan mudah
+
+ Masuk
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/pages/OrganizationPage.js b/src/pages/OrganizationPage.js
new file mode 100644
index 0000000..51fa27e
--- /dev/null
+++ b/src/pages/OrganizationPage.js
@@ -0,0 +1,44 @@
+import { Link } from 'react-router-dom';
+
+const OrgIcon = () => (
+
+);
+
+const ArrowIcon = () => (
+
+);
+
+const organizations = [
+ { name: 'psi', id: 'BLWR-XDU-QRUV' },
+ { name: 'managemen', id: 'NFTJ-POX-ZYOB' },
+ { name: 'solid', id: 'TCKQ-ZNF-UFTW' },
+];
+
+export default function OrganizationPage() {
+ return (
+
+
+
Pilih Organisasi
+
Silakan pilih organisasi yang ingin Anda kelola.
+
+ {organizations.map((org) => (
+
+
+
+
+
{org.name}
+
ID: {org.id}
+
+
+
+
+ ))}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/pages/browser.html b/src/pages/browser.html
new file mode 100644
index 0000000..bd89d9e
--- /dev/null
+++ b/src/pages/browser.html
@@ -0,0 +1,19 @@
+
+
+
+ Bypass Situs
+
+
+
+ 🔓 Akses Situs Lain dari File Lokal
+
+ Tips: Kalau tidak bisa dibuka, coba salin link-nya lalu tempel di tab baru.
+
+