770 lines
31 KiB
TypeScript
770 lines
31 KiB
TypeScript
import { ActionFunctionArgs, json, LoaderFunctionArgs } from "@remix-run/node"
|
|
import { Form, useActionData, useLoaderData } from "@remix-run/react"
|
|
import { useState } from "react"
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card"
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs"
|
|
import { Button } from "~/components/ui/button"
|
|
import { Input } from "~/components/ui/input"
|
|
import { Label } from "~/components/ui/label"
|
|
import { Textarea } from "~/components/ui/textarea"
|
|
import { Switch } from "~/components/ui/switch"
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/components/ui/select"
|
|
import { Badge } from "~/components/ui/badge"
|
|
import { Separator } from "~/components/ui/separator"
|
|
import { Alert, AlertDescription } from "~/components/ui/alert"
|
|
import {
|
|
Settings,
|
|
Users,
|
|
Bell,
|
|
Shield,
|
|
Database,
|
|
Mail,
|
|
Globe,
|
|
Palette,
|
|
Save,
|
|
Upload,
|
|
Download,
|
|
RefreshCw,
|
|
CheckCircle,
|
|
AlertTriangle,
|
|
Info
|
|
} from "lucide-react"
|
|
|
|
export async function loader({ request }: LoaderFunctionArgs) {
|
|
// Mock data - ganti dengan data dari database
|
|
const settings = {
|
|
// Pengaturan Umum
|
|
appName: "EcoWaste Manager",
|
|
appDescription: "Sistem Pengelolaan Sampah Terpadu untuk Lingkungan yang Lebih Bersih",
|
|
companyName: "PT. Lingkungan Hijau Indonesia",
|
|
companyAddress: "Jl. Sudirman No. 123, Jakarta Pusat 10220",
|
|
companyPhone: "+62 21 1234567",
|
|
companyEmail: "info@ecowaste.com",
|
|
timezone: "Asia/Jakarta",
|
|
language: "id",
|
|
|
|
// Pengaturan Sistem
|
|
maintenanceMode: false,
|
|
registrationEnabled: true,
|
|
maxFileSize: "10",
|
|
sessionTimeout: "60",
|
|
backupFrequency: "daily",
|
|
|
|
// Pengaturan Email
|
|
smtpHost: "smtp.gmail.com",
|
|
smtpPort: "587",
|
|
smtpUser: "noreply@ecowaste.com",
|
|
smtpPassword: "",
|
|
emailFrom: "EcoWaste System <noreply@ecowaste.com>",
|
|
|
|
// Pengaturan Notifikasi
|
|
emailNotifications: true,
|
|
pushNotifications: false,
|
|
smsNotifications: false,
|
|
notifyNewUser: true,
|
|
notifyLowStock: true,
|
|
notifySystemAlert: true,
|
|
|
|
// Statistik
|
|
totalUsers: 245,
|
|
totalWaste: "1,250 kg",
|
|
lastBackup: "2 jam yang lalu",
|
|
systemUptime: "99.9%"
|
|
}
|
|
|
|
return json({ settings })
|
|
}
|
|
|
|
export async function action({ request }: ActionFunctionArgs) {
|
|
const formData = await request.formData()
|
|
const intent = formData.get("intent")
|
|
|
|
try {
|
|
switch (intent) {
|
|
case "general":
|
|
// Save general settings
|
|
console.log("Saving general settings...")
|
|
break
|
|
case "system":
|
|
// Save system settings
|
|
console.log("Saving system settings...")
|
|
break
|
|
case "email":
|
|
// Save email settings
|
|
console.log("Saving email settings...")
|
|
break
|
|
case "notifications":
|
|
// Save notification settings
|
|
console.log("Saving notification settings...")
|
|
break
|
|
case "backup":
|
|
// Trigger backup
|
|
console.log("Creating backup...")
|
|
break
|
|
case "test-email":
|
|
// Test email configuration
|
|
console.log("Testing email...")
|
|
break
|
|
}
|
|
|
|
return json({ success: true, message: "Pengaturan berhasil disimpan!" })
|
|
} catch (error) {
|
|
return json({ success: false, message: "Gagal menyimpan pengaturan." }, { status: 400 })
|
|
}
|
|
}
|
|
|
|
export default function Pengaturan() {
|
|
const { settings } = useLoaderData<typeof loader>()
|
|
const actionData = useActionData<typeof action>()
|
|
const [activeTab, setActiveTab] = useState("overview")
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div>
|
|
<h1 className="text-3xl font-bold tracking-tight">Pengaturan</h1>
|
|
<p className="text-muted-foreground">
|
|
Kelola pengaturan dan konfigurasi sistem pengelolaan sampah
|
|
</p>
|
|
</div>
|
|
|
|
{actionData && (
|
|
<Alert className={actionData.success ? "border-green-500" : "border-red-500"}>
|
|
<Info className="h-4 w-4" />
|
|
<AlertDescription>{actionData.message}</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
|
|
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-4">
|
|
<TabsList className="grid w-full grid-cols-5">
|
|
<TabsTrigger value="overview" className="flex items-center gap-2">
|
|
<Settings className="h-4 w-4" />
|
|
Overview
|
|
</TabsTrigger>
|
|
<TabsTrigger value="general" className="flex items-center gap-2">
|
|
<Globe className="h-4 w-4" />
|
|
Umum
|
|
</TabsTrigger>
|
|
<TabsTrigger value="system" className="flex items-center gap-2">
|
|
<Database className="h-4 w-4" />
|
|
Sistem
|
|
</TabsTrigger>
|
|
<TabsTrigger value="notifications" className="flex items-center gap-2">
|
|
<Bell className="h-4 w-4" />
|
|
Notifikasi
|
|
</TabsTrigger>
|
|
<TabsTrigger value="backup" className="flex items-center gap-2">
|
|
<Shield className="h-4 w-4" />
|
|
Backup
|
|
</TabsTrigger>
|
|
</TabsList>
|
|
|
|
{/* Overview Tab */}
|
|
<TabsContent value="overview" className="space-y-4">
|
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Total Pengguna</CardTitle>
|
|
<Users className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{settings.totalUsers}</div>
|
|
<p className="text-xs text-muted-foreground">+5 dari bulan lalu</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Total Sampah</CardTitle>
|
|
<Database className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{settings.totalWaste}</div>
|
|
<p className="text-xs text-muted-foreground">Bulan ini</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">System Uptime</CardTitle>
|
|
<CheckCircle className="h-4 w-4 text-green-500" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{settings.systemUptime}</div>
|
|
<p className="text-xs text-muted-foreground">30 hari terakhir</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Last Backup</CardTitle>
|
|
<Shield className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold text-green-600">✓</div>
|
|
<p className="text-xs text-muted-foreground">{settings.lastBackup}</p>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Status Sistem</CardTitle>
|
|
<CardDescription>Kondisi sistem saat ini</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-3">
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-sm">Database</span>
|
|
<Badge className="bg-green-100 text-green-800">Online</Badge>
|
|
</div>
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-sm">Email Service</span>
|
|
<Badge className="bg-green-100 text-green-800">Connected</Badge>
|
|
</div>
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-sm">Storage</span>
|
|
<Badge className="bg-yellow-100 text-yellow-800">75% Used</Badge>
|
|
</div>
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-sm">Cache</span>
|
|
<Badge className="bg-green-100 text-green-800">Active</Badge>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Aktivitas Terbaru</CardTitle>
|
|
<CardDescription>Log aktivitas sistem</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-3">
|
|
<div className="text-sm">
|
|
<div className="flex justify-between">
|
|
<span>Backup otomatis selesai</span>
|
|
<span className="text-muted-foreground">2 jam lalu</span>
|
|
</div>
|
|
</div>
|
|
<div className="text-sm">
|
|
<div className="flex justify-between">
|
|
<span>User baru terdaftar</span>
|
|
<span className="text-muted-foreground">4 jam lalu</span>
|
|
</div>
|
|
</div>
|
|
<div className="text-sm">
|
|
<div className="flex justify-between">
|
|
<span>Cache dibersihkan</span>
|
|
<span className="text-muted-foreground">1 hari lalu</span>
|
|
</div>
|
|
</div>
|
|
<div className="text-sm">
|
|
<div className="flex justify-between">
|
|
<span>Database dioptimasi</span>
|
|
<span className="text-muted-foreground">2 hari lalu</span>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</TabsContent>
|
|
|
|
{/* General Settings Tab */}
|
|
<TabsContent value="general" className="space-y-4">
|
|
<Form method="post">
|
|
<input type="hidden" name="intent" value="general" />
|
|
|
|
<div className="grid gap-6">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Informasi Aplikasi</CardTitle>
|
|
<CardDescription>
|
|
Pengaturan dasar aplikasi dan identitas perusahaan
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="appName">Nama Aplikasi</Label>
|
|
<Input
|
|
id="appName"
|
|
name="appName"
|
|
defaultValue={settings.appName}
|
|
placeholder="Nama aplikasi Anda"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="companyName">Nama Perusahaan</Label>
|
|
<Input
|
|
id="companyName"
|
|
name="companyName"
|
|
defaultValue={settings.companyName}
|
|
placeholder="Nama perusahaan"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="appDescription">Deskripsi Aplikasi</Label>
|
|
<Textarea
|
|
id="appDescription"
|
|
name="appDescription"
|
|
defaultValue={settings.appDescription}
|
|
placeholder="Deskripsi singkat aplikasi"
|
|
rows={3}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="companyAddress">Alamat Perusahaan</Label>
|
|
<Textarea
|
|
id="companyAddress"
|
|
name="companyAddress"
|
|
defaultValue={settings.companyAddress}
|
|
placeholder="Alamat lengkap perusahaan"
|
|
rows={2}
|
|
/>
|
|
</div>
|
|
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="companyPhone">Telepon</Label>
|
|
<Input
|
|
id="companyPhone"
|
|
name="companyPhone"
|
|
defaultValue={settings.companyPhone}
|
|
placeholder="+62 21 xxxxxx"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="companyEmail">Email</Label>
|
|
<Input
|
|
id="companyEmail"
|
|
name="companyEmail"
|
|
type="email"
|
|
defaultValue={settings.companyEmail}
|
|
placeholder="info@company.com"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Pengaturan Regional</CardTitle>
|
|
<CardDescription>
|
|
Zona waktu dan bahasa aplikasi
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="timezone">Zona Waktu</Label>
|
|
<Select name="timezone" defaultValue={settings.timezone}>
|
|
<SelectTrigger>
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="Asia/Jakarta">Asia/Jakarta (WIB)</SelectItem>
|
|
<SelectItem value="Asia/Makassar">Asia/Makassar (WITA)</SelectItem>
|
|
<SelectItem value="Asia/Jayapura">Asia/Jayapura (WIT)</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="language">Bahasa</Label>
|
|
<Select name="language" defaultValue={settings.language}>
|
|
<SelectTrigger>
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="id">Bahasa Indonesia</SelectItem>
|
|
<SelectItem value="en">English</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<div className="flex justify-end">
|
|
<Button type="submit" className="flex items-center gap-2">
|
|
<Save className="h-4 w-4" />
|
|
Simpan Pengaturan
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</Form>
|
|
</TabsContent>
|
|
|
|
{/* System Settings Tab */}
|
|
<TabsContent value="system" className="space-y-4">
|
|
<Form method="post">
|
|
<input type="hidden" name="intent" value="system" />
|
|
|
|
<div className="grid gap-6">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Pengaturan Sistem</CardTitle>
|
|
<CardDescription>
|
|
Konfigurasi sistem dan keamanan
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-0.5">
|
|
<Label className="text-base">Mode Maintenance</Label>
|
|
<div className="text-sm text-muted-foreground">
|
|
Nonaktifkan akses pengguna untuk maintenance
|
|
</div>
|
|
</div>
|
|
<Switch
|
|
name="maintenanceMode"
|
|
defaultChecked={settings.maintenanceMode}
|
|
/>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-0.5">
|
|
<Label className="text-base">Registrasi Pengguna Baru</Label>
|
|
<div className="text-sm text-muted-foreground">
|
|
Izinkan pendaftaran pengguna baru
|
|
</div>
|
|
</div>
|
|
<Switch
|
|
name="registrationEnabled"
|
|
defaultChecked={settings.registrationEnabled}
|
|
/>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="maxFileSize">Ukuran File Maksimal (MB)</Label>
|
|
<Input
|
|
id="maxFileSize"
|
|
name="maxFileSize"
|
|
type="number"
|
|
defaultValue={settings.maxFileSize}
|
|
min="1"
|
|
max="100"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="sessionTimeout">Session Timeout (menit)</Label>
|
|
<Input
|
|
id="sessionTimeout"
|
|
name="sessionTimeout"
|
|
type="number"
|
|
defaultValue={settings.sessionTimeout}
|
|
min="15"
|
|
max="480"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Tindakan Sistem</CardTitle>
|
|
<CardDescription>
|
|
Aksi pemeliharaan dan optimasi sistem
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex flex-wrap gap-3">
|
|
<Button variant="outline" type="button">
|
|
<RefreshCw className="h-4 w-4 mr-2" />
|
|
Clear Cache
|
|
</Button>
|
|
<Button variant="outline" type="button">
|
|
<Database className="h-4 w-4 mr-2" />
|
|
Optimize Database
|
|
</Button>
|
|
<Button variant="outline" type="button">
|
|
<Download className="h-4 w-4 mr-2" />
|
|
Export Logs
|
|
</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<div className="flex justify-end">
|
|
<Button type="submit" className="flex items-center gap-2">
|
|
<Save className="h-4 w-4" />
|
|
Simpan Pengaturan
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</Form>
|
|
</TabsContent>
|
|
|
|
{/* Notifications Tab */}
|
|
<TabsContent value="notifications" className="space-y-4">
|
|
<Form method="post">
|
|
<input type="hidden" name="intent" value="notifications" />
|
|
|
|
<div className="grid gap-6">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Email Configuration</CardTitle>
|
|
<CardDescription>
|
|
Pengaturan server email untuk notifikasi
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="smtpHost">SMTP Host</Label>
|
|
<Input
|
|
id="smtpHost"
|
|
name="smtpHost"
|
|
defaultValue={settings.smtpHost}
|
|
placeholder="smtp.gmail.com"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="smtpPort">SMTP Port</Label>
|
|
<Input
|
|
id="smtpPort"
|
|
name="smtpPort"
|
|
defaultValue={settings.smtpPort}
|
|
placeholder="587"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="smtpUser">SMTP Username</Label>
|
|
<Input
|
|
id="smtpUser"
|
|
name="smtpUser"
|
|
defaultValue={settings.smtpUser}
|
|
placeholder="username@gmail.com"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="smtpPassword">SMTP Password</Label>
|
|
<Input
|
|
id="smtpPassword"
|
|
name="smtpPassword"
|
|
type="password"
|
|
defaultValue={settings.smtpPassword}
|
|
placeholder="••••••••"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="emailFrom">Email Pengirim</Label>
|
|
<Input
|
|
id="emailFrom"
|
|
name="emailFrom"
|
|
defaultValue={settings.emailFrom}
|
|
placeholder="EcoWaste System <noreply@ecowaste.com>"
|
|
/>
|
|
</div>
|
|
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
onClick={() => {
|
|
// Test email function
|
|
const form = new FormData()
|
|
form.append("intent", "test-email")
|
|
fetch("", { method: "POST", body: form })
|
|
}}
|
|
>
|
|
<Mail className="h-4 w-4 mr-2" />
|
|
Test Email
|
|
</Button>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Pengaturan Notifikasi</CardTitle>
|
|
<CardDescription>
|
|
Atur jenis notifikasi yang akan dikirim
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-0.5">
|
|
<Label className="text-base">Email Notifications</Label>
|
|
<div className="text-sm text-muted-foreground">
|
|
Kirim notifikasi melalui email
|
|
</div>
|
|
</div>
|
|
<Switch
|
|
name="emailNotifications"
|
|
defaultChecked={settings.emailNotifications}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-0.5">
|
|
<Label className="text-base">Notifikasi Pengguna Baru</Label>
|
|
<div className="text-sm text-muted-foreground">
|
|
Notifikasi saat ada pengguna baru mendaftar
|
|
</div>
|
|
</div>
|
|
<Switch
|
|
name="notifyNewUser"
|
|
defaultChecked={settings.notifyNewUser}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-0.5">
|
|
<Label className="text-base">Alert Sistem</Label>
|
|
<div className="text-sm text-muted-foreground">
|
|
Notifikasi untuk masalah sistem dan error
|
|
</div>
|
|
</div>
|
|
<Switch
|
|
name="notifySystemAlert"
|
|
defaultChecked={settings.notifySystemAlert}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<div className="flex justify-end">
|
|
<Button type="submit" className="flex items-center gap-2">
|
|
<Save className="h-4 w-4" />
|
|
Simpan Pengaturan
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</Form>
|
|
</TabsContent>
|
|
|
|
{/* Backup Tab */}
|
|
<TabsContent value="backup" className="space-y-4">
|
|
<div className="grid gap-6">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Backup & Restore</CardTitle>
|
|
<CardDescription>
|
|
Kelola backup data dan pemulihan sistem
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="grid gap-4 md:grid-cols-3">
|
|
<div className="text-center p-4 border rounded-lg">
|
|
<Database className="h-8 w-8 mx-auto mb-2 text-muted-foreground" />
|
|
<div className="text-sm font-medium">Database</div>
|
|
<div className="text-xs text-muted-foreground">245 MB</div>
|
|
</div>
|
|
<div className="text-center p-4 border rounded-lg">
|
|
<Upload className="h-8 w-8 mx-auto mb-2 text-muted-foreground" />
|
|
<div className="text-sm font-medium">Files</div>
|
|
<div className="text-xs text-muted-foreground">1.2 GB</div>
|
|
</div>
|
|
<div className="text-center p-4 border rounded-lg">
|
|
<Settings className="h-8 w-8 mx-auto mb-2 text-muted-foreground" />
|
|
<div className="text-sm font-medium">Settings</div>
|
|
<div className="text-xs text-muted-foreground">2 KB</div>
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-4">
|
|
<h4 className="text-sm font-medium">Backup Otomatis</h4>
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="backupFrequency">Frekuensi Backup</Label>
|
|
<Select name="backupFrequency" defaultValue={settings.backupFrequency}>
|
|
<SelectTrigger>
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="daily">Harian</SelectItem>
|
|
<SelectItem value="weekly">Mingguan</SelectItem>
|
|
<SelectItem value="monthly">Bulanan</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="flex flex-wrap gap-3">
|
|
<Form method="post" style={{ display: 'inline' }}>
|
|
<input type="hidden" name="intent" value="backup" />
|
|
<Button type="submit" className="flex items-center gap-2">
|
|
<Database className="h-4 w-4" />
|
|
Backup Sekarang
|
|
</Button>
|
|
</Form>
|
|
|
|
<Button variant="outline">
|
|
<Download className="h-4 w-4 mr-2" />
|
|
Download Backup
|
|
</Button>
|
|
|
|
<Button variant="outline">
|
|
<Upload className="h-4 w-4 mr-2" />
|
|
Restore Backup
|
|
</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Riwayat Backup</CardTitle>
|
|
<CardDescription>
|
|
Daftar backup yang tersedia
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-3">
|
|
{[
|
|
{ date: "2024-01-15 14:30", size: "1.4 GB", status: "success" },
|
|
{ date: "2024-01-14 14:30", size: "1.3 GB", status: "success" },
|
|
{ date: "2024-01-13 14:30", size: "1.3 GB", status: "success" },
|
|
{ date: "2024-01-12 14:30", size: "1.2 GB", status: "failed" },
|
|
].map((backup, index) => (
|
|
<div key={index} className="flex items-center justify-between py-2 border-b last:border-0">
|
|
<div className="flex items-center space-x-3">
|
|
<div className={`h-2 w-2 rounded-full ${backup.status === 'success' ? 'bg-green-500' : 'bg-red-500'}`} />
|
|
<div>
|
|
<div className="text-sm font-medium">{backup.date}</div>
|
|
<div className="text-xs text-muted-foreground">{backup.size}</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex space-x-2">
|
|
<Button size="sm" variant="outline">
|
|
<Download className="h-3 w-3" />
|
|
</Button>
|
|
<Button size="sm" variant="outline">
|
|
<RefreshCw className="h-3 w-3" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</TabsContent>
|
|
</Tabs>
|
|
</div>
|
|
)
|
|
} |