'use client'; import * as React from 'react'; import { useState, useEffect } from 'react'; import { AdminService } from '@/lib/api/services/admin'; import { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter, } from '@/components/ui/card'; 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 { Alert, AlertDescription } from '@/components/ui/alert'; import { AlertCircle, Save, RefreshCw, Eye, EyeOff } from 'lucide-react'; import { toast } from 'sonner'; interface SettingsData { name?: string; description?: string; npub?: string; nsec?: string; upstream_api_key?: string; http_url?: string; onion_url?: string; cashu_mints?: string[]; [key: string]: unknown; } interface PasswordData { current_password: string; new_password: string; confirm_password: string; } export function AdminSettings() { const [settings, setSettings] = useState({}); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [error, setError] = useState(''); const [showSecrets, setShowSecrets] = useState(false); const [newMint, setNewMint] = useState(''); const [passwordData, setPasswordData] = useState({ current_password: '', new_password: '', confirm_password: '', }); const [passwordError, setPasswordError] = useState(''); const [passwordSaving, setPasswordSaving] = useState(false); useEffect(() => { loadSettings(); }, []); const loadSettings = async () => { try { setLoading(true); setError(''); const data = await AdminService.getSettings(); setSettings(data as SettingsData); } catch (err) { const message = err instanceof Error ? err.message : 'Failed to load settings'; setError(message); toast.error(message); } finally { setLoading(false); } }; const handleSave = async () => { try { setSaving(true); setError(''); const updatedData = await AdminService.updateSettings(settings); setSettings(updatedData as SettingsData); toast.success('Settings saved successfully'); } catch (err) { const message = err instanceof Error ? err.message : 'Failed to save settings'; setError(message); toast.error(message); } finally { setSaving(false); } }; const handlePasswordUpdate = async () => { try { setPasswordSaving(true); setPasswordError(''); if (passwordData.new_password !== passwordData.confirm_password) { setPasswordError('New passwords do not match'); return; } if (passwordData.new_password.length < 6) { setPasswordError('New password must be at least 6 characters'); return; } const { apiClient } = await import('@/lib/api/client'); await apiClient.patch('/admin/api/password', { current_password: passwordData.current_password, new_password: passwordData.new_password, }); setPasswordData({ current_password: '', new_password: '', confirm_password: '', }); toast.success('Password updated successfully'); } catch (err) { const message = err instanceof Error ? err.message : 'Failed to update password'; setPasswordError(message); toast.error(message); } finally { setPasswordSaving(false); } }; const handleInputChange = (field: string, value: string | boolean) => { setSettings((prev) => ({ ...prev, [field]: value, })); }; const addMint = () => { if (newMint.trim()) { setSettings((prev) => ({ ...prev, cashu_mints: [...(prev.cashu_mints || []), newMint.trim()], })); setNewMint(''); } }; const removeMint = (index: number) => { setSettings((prev) => ({ ...prev, cashu_mints: prev.cashu_mints?.filter((_, i) => i !== index) || [], })); }; const renderSecretField = ( field: string, label: string, placeholder?: string ) => { const value = (settings[field] as string) || ''; const displayValue = showSecrets ? value : value ? '••••••••' : ''; return (
handleInputChange(field, e.target.value)} placeholder={placeholder} className='flex-1' />
); }; if (loading) { return (
Loading settings...
); } return ( <>

Admin Settings

Configure your Routstr node settings

{error && ( {error} )}
{/* Basic Information */} Basic Information Configure the basic node information and branding
handleInputChange('name', e.target.value)} placeholder='ARoutstrNode' />