File: /var/www/indoadvisory_new/webapp/src/routes/settings.js
import { Hono } from 'hono';
const settings = new Hono();
// Settings Page
settings.get('/', async (c) => {
try {
const settingsList = await c.env.DB.prepare('SELECT * FROM site_settings ORDER BY setting_key').all();
const user = c.get('user');
// Convert settings array to object for easier access
const settingsObj = {};
settingsList.results.forEach(setting => {
settingsObj[setting.setting_key] = setting.setting_value;
});
return c.html(`
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pengaturan Website - Admin IndoAdvisory</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
</head>
<body class="bg-gray-100">
${adminNavbar(user)}
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div class="mb-8">
<h1 class="text-3xl font-bold text-gray-800">Pengaturan Website</h1>
<p class="text-gray-600 mt-2">Kelola informasi dasar website dan perusahaan</p>
</div>
<form id="settingsForm" action="/admin/settings" method="POST" class="space-y-8">
<!-- Company Information -->
<div class="bg-white rounded-xl shadow-lg p-8">
<h2 class="text-xl font-bold text-gray-800 mb-6">
<i class="fas fa-building mr-2 text-blue-600"></i>
Informasi Perusahaan
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Nama Perusahaan</label>
<input
type="text"
name="company_name"
value="${settingsObj.company_name || 'IndoAdvisory'}"
required
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Email Perusahaan</label>
<input
type="email"
name="company_email"
value="${settingsObj.company_email || 'info@indoadvisory.co.id'}"
required
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Telepon</label>
<input
type="text"
name="company_phone"
value="${settingsObj.company_phone || '+62 21 5794 3210'}"
required
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Website URL</label>
<input
type="url"
name="company_website"
value="${settingsObj.company_website || 'https://indoadvisory.co.id'}"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
</div>
<div class="mt-6">
<label class="block text-sm font-medium text-gray-700 mb-2">Alamat Lengkap</label>
<textarea
name="company_address"
rows="3"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
placeholder="Alamat lengkap perusahaan"
>${settingsObj.company_address || 'Menara Sudirman Lt. 25\\nJl. Jend. Sudirman Kav. 60\\nJakarta Selatan 12190'}</textarea>
</div>
</div>
<!-- Website Settings -->
<div class="bg-white rounded-xl shadow-lg p-8">
<h2 class="text-xl font-bold text-gray-800 mb-6">
<i class="fas fa-globe mr-2 text-blue-600"></i>
Pengaturan Website
</h2>
<div class="space-y-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Judul Website</label>
<input
type="text"
name="site_title"
value="${settingsObj.site_title || 'IndoAdvisory - Penasihat Investasi Terpercaya'}"
required
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Deskripsi Website</label>
<textarea
name="site_description"
rows="3"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
placeholder="Deskripsi singkat tentang perusahaan"
>${settingsObj.site_description || 'Firma konsultan private equity terkemuka di Indonesia'}</textarea>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Bahasa Default</label>
<select
name="default_language"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
<option value="id" ${(settingsObj.default_language || 'id') === 'id' ? 'selected' : ''}>Bahasa Indonesia</option>
<option value="en" ${settingsObj.default_language === 'en' ? 'selected' : ''}>English</option>
</select>
</div>
</div>
</div>
<!-- Hero Section Settings -->
<div class="bg-white rounded-xl shadow-lg p-8">
<h2 class="text-xl font-bold text-gray-800 mb-6">
<i class="fas fa-star mr-2 text-blue-600"></i>
Hero Section
</h2>
<div class="space-y-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Judul Hero (Bahasa Indonesia)</label>
<input
type="text"
name="hero_title_id"
value="${settingsObj.hero_title_id || 'Penasihat Private Equity Terpercaya di Indonesia'}"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Judul Hero (English)</label>
<input
type="text"
name="hero_title_en"
value="${settingsObj.hero_title_en || 'Trusted Private Equity Advisory in Indonesia'}"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Subtitle Hero (Bahasa Indonesia)</label>
<textarea
name="hero_subtitle_id"
rows="3"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>${settingsObj.hero_subtitle_id || 'Kami membantu perusahaan mencapai pertumbuhan berkelanjutan melalui strategi investasi yang tepat, valuasi perusahaan yang akurat, dan persiapan IPO yang komprehensif.'}</textarea>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Subtitle Hero (English)</label>
<textarea
name="hero_subtitle_en"
rows="3"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>${settingsObj.hero_subtitle_en || 'We help companies achieve sustainable growth through strategic investments, accurate company valuations, and comprehensive IPO preparation.'}</textarea>
</div>
</div>
</div>
<!-- Statistics Settings -->
<div class="bg-white rounded-xl shadow-lg p-8">
<h2 class="text-xl font-bold text-gray-800 mb-6">
<i class="fas fa-chart-bar mr-2 text-blue-600"></i>
Statistik Perusahaan
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Total Klien</label>
<input
type="number"
name="stats_clients"
value="${settingsObj.stats_clients || '150'}"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Total Valuasi</label>
<input
type="text"
name="stats_valuation"
value="${settingsObj.stats_valuation || 'Rp 2.5T'}"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">IPO Sukses</label>
<input
type="number"
name="stats_ipos"
value="${settingsObj.stats_ipos || '25'}"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Satisfaction Rate (%)</label>
<input
type="number"
name="stats_satisfaction"
value="${settingsObj.stats_satisfaction || '98'}"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
</div>
</div>
<!-- Portfolio Section Settings -->
<div class="bg-white rounded-xl shadow-lg p-8">
<h2 class="text-xl font-bold text-gray-800 mb-6">
<i class="fas fa-eye mr-2 text-blue-600"></i>
Pengaturan Portfolio & Statistik
</h2>
<div class="space-y-6">
<div class="bg-blue-50 border border-blue-200 rounded-lg p-4">
<div class="flex items-center justify-between">
<div>
<h3 class="font-semibold text-gray-800">Tampilkan Bagian Portfolio</h3>
<p class="text-sm text-gray-600 mt-1">Menampilkan atau menyembunyikan seluruh bagian Portfolio & Prestasi di halaman utama</p>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" name="portfolio_section_enabled" value="1"
${(settingsObj.portfolio_section_enabled || '1') === '1' ? 'checked' : ''}
class="sr-only peer">
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
</label>
</div>
</div>
<div class="bg-green-50 border border-green-200 rounded-lg p-4">
<div class="flex items-center justify-between">
<div>
<h3 class="font-semibold text-gray-800">Tampilkan Statistik Kinerja</h3>
<p class="text-sm text-gray-600 mt-1">Menampilkan atau menyembunyikan grafik dan data statistik dalam bagian portfolio</p>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" name="portfolio_statistics_enabled" value="1"
${(settingsObj.portfolio_statistics_enabled || '1') === '1' ? 'checked' : ''}
class="sr-only peer">
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-green-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-green-600"></div>
</label>
</div>
</div>
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
<h4 class="font-medium text-gray-800 mb-2">
<i class="fas fa-info-circle text-yellow-600 mr-2"></i>
Informasi Pengaturan
</h4>
<ul class="text-sm text-gray-600 space-y-1">
<li>• <strong>Portfolio Section</strong>: Mengontrol visibilitas keseluruhan bagian "Portfolio & Prestasi"</li>
<li>• <strong>Statistik Kinerja</strong>: Mengontrol tampilan grafik dan data statistik di dalam portfolio</li>
<li>• Client showcase (Klien Terkini) akan tetap tampil meskipun statistik dimatikan</li>
<li>• Perubahan akan terlihat langsung di halaman utama setelah disimpan</li>
</ul>
</div>
</div>
</div>
<div class="flex justify-end space-x-4">
<button
type="button"
onclick="window.location.href='/admin/dashboard'"
class="px-6 py-3 text-gray-700 bg-gray-200 rounded-lg hover:bg-gray-300 transition-colors"
>
<i class="fas fa-times mr-2"></i>
Batal
</button>
<button
type="submit"
class="px-8 py-3 bg-blue-600 text-white rounded-lg font-semibold hover:bg-blue-700 transition-colors"
>
<i class="fas fa-save mr-2"></i>
Simpan Pengaturan
</button>
</div>
</form>
</div>
<script>
document.getElementById('settingsForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
const settings = {};
// Handle regular form fields
for (let [key, value] of formData.entries()) {
settings[key] = value;
}
// Handle unchecked checkboxes (they don't appear in formData)
const checkboxes = this.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => {
if (!settings.hasOwnProperty(checkbox.name)) {
settings[checkbox.name] = '0';
}
});
fetch('/admin/settings', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(settings)
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('Pengaturan berhasil disimpan!');
window.location.reload();
} else {
alert('Terjadi kesalahan: ' + data.error);
}
})
.catch(error => {
alert('Terjadi kesalahan: ' + error.message);
});
});
</script>
</body>
</html>
`);
}
catch (error) {
return c.html(`<div>Error: ${error.message}</div>`);
}
});
// Save Settings
settings.post('/', async (c) => {
try {
const settingsData = await c.req.json();
// Update each setting
for (const [key, value] of Object.entries(settingsData)) {
await c.env.DB.prepare(`
INSERT INTO site_settings (setting_key, setting_value, updated_at)
VALUES (?, ?, ?)
ON CONFLICT(setting_key)
DO UPDATE SET setting_value = ?, updated_at = ?
`).bind(key, value, new Date().toISOString(), value, new Date().toISOString()).run();
}
return c.json({ success: true });
}
catch (error) {
return c.json({ error: error.message }, 500);
}
});
// Admin Navbar Component
function adminNavbar(user) {
return `
<nav class="bg-white shadow-lg border-b">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center h-16">
<div class="flex items-center">
<h1 class="text-xl font-bold text-gray-800">
<i class="fas fa-chart-line text-blue-600 mr-2"></i>
IndoAdvisory Admin
</h1>
</div>
<div class="hidden md:flex items-center space-x-6">
<a href="/admin/dashboard" class="text-gray-700 hover:text-blue-600 px-3 py-2 rounded-md text-sm font-medium">
<i class="fas fa-tachometer-alt mr-1"></i>
Dashboard
</a>
<a href="/admin/articles" class="text-gray-700 hover:text-blue-600 px-3 py-2 rounded-md text-sm font-medium">
<i class="fas fa-newspaper mr-1"></i>
Artikel
</a>
<a href="/admin/inquiries" class="text-gray-700 hover:text-blue-600 px-3 py-2 rounded-md text-sm font-medium">
<i class="fas fa-envelope mr-1"></i>
Inquiry
</a>
<a href="/admin/team" class="text-gray-700 hover:text-blue-600 px-3 py-2 rounded-md text-sm font-medium">
<i class="fas fa-users mr-1"></i>
Tim
</a>
<a href="/admin/settings" class="text-blue-600 font-semibold px-3 py-2 rounded-md text-sm font-medium">
<i class="fas fa-cog mr-1"></i>
Settings
</a>
<a href="/" target="_blank" class="text-gray-700 hover:text-blue-600 px-3 py-2 rounded-md text-sm font-medium">
<i class="fas fa-external-link-alt mr-1"></i>
Lihat Website
</a>
</div>
<div class="flex items-center">
<span class="text-gray-700 mr-4">
<i class="fas fa-user mr-1"></i>
${user.name}
</span>
<a href="/admin/logout" class="text-red-600 hover:text-red-700 px-3 py-2 rounded-md text-sm font-medium">
<i class="fas fa-sign-out-alt mr-1"></i>
Logout
</a>
</div>
</div>
</div>
</nav>
`;
}
export default settings;