- Add tailwind.config.ts with proper content paths and theme config - Add postcss.config.js for Tailwind and autoprefixer processing - Downgrade tailwindcss to v3.4.17 and add missing PostCSS dependencies - Update Dockerfile to clarify build process - Fix UI styling issues in Docker environment
243 lines
9.4 KiB
TypeScript
243 lines
9.4 KiB
TypeScript
"use client"
|
||
import React, { useState, useEffect } from 'react'
|
||
|
||
export default function DeveloperSettings() {
|
||
const [settings, setSettings] = useState({
|
||
environment: 'production',
|
||
debugMode: false,
|
||
logLevel: 'info',
|
||
apiTimeout: 30000,
|
||
maxRetries: 3,
|
||
customEndpoint: ''
|
||
})
|
||
const [message, setMessage] = useState('')
|
||
const [loading, setLoading] = useState(false)
|
||
|
||
useEffect(() => {
|
||
// Load settings from localStorage
|
||
const saved = localStorage.getItem('devSettings')
|
||
if (saved) {
|
||
try {
|
||
setSettings(JSON.parse(saved))
|
||
} catch (e) {
|
||
console.error('Failed to parse saved settings:', e)
|
||
}
|
||
}
|
||
}, [])
|
||
|
||
const handleSettingChange = (key: string, value: any) => {
|
||
setSettings(prev => ({
|
||
...prev,
|
||
[key]: value
|
||
}))
|
||
}
|
||
|
||
const handleSave = async () => {
|
||
setLoading(true)
|
||
setMessage('')
|
||
|
||
try {
|
||
// Save to localStorage
|
||
localStorage.setItem('devSettings', JSON.stringify(settings))
|
||
|
||
// Optionally send to API
|
||
const response = await fetch('/api/developer-settings', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(settings)
|
||
})
|
||
|
||
if (response.ok) {
|
||
setMessage('Settings saved successfully!')
|
||
} else {
|
||
setMessage('Settings saved locally (API unavailable)')
|
||
}
|
||
} catch (error) {
|
||
setMessage('Settings saved locally (API error)')
|
||
}
|
||
|
||
setLoading(false)
|
||
setTimeout(() => setMessage(''), 3000)
|
||
}
|
||
|
||
const handleReset = () => {
|
||
const defaultSettings = {
|
||
environment: 'production',
|
||
debugMode: false,
|
||
logLevel: 'info',
|
||
apiTimeout: 30000,
|
||
maxRetries: 3,
|
||
customEndpoint: ''
|
||
}
|
||
setSettings(defaultSettings)
|
||
localStorage.removeItem('devSettings')
|
||
setMessage('Settings reset to defaults')
|
||
setTimeout(() => setMessage(''), 3000)
|
||
}
|
||
|
||
return (
|
||
<div className="card card-gradient">
|
||
<div className="flex items-center justify-between mb-6">
|
||
<h2 className="text-lg font-bold text-white flex items-center">
|
||
<span className="w-8 h-8 bg-gradient-to-br from-indigo-400 to-purple-600 rounded-lg flex items-center justify-center mr-3">
|
||
⚙️
|
||
</span>
|
||
Developer Settings
|
||
</h2>
|
||
<div className="flex items-center space-x-2 text-sm text-gray-400">
|
||
<div className="w-2 h-2 bg-indigo-400 rounded-full"></div>
|
||
<span>Advanced</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-6">
|
||
{/* Environment Selection */}
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-300 mb-2">Environment</label>
|
||
<select
|
||
className="w-full px-3 py-2 bg-gray-800/50 border border-gray-700 rounded-lg text-white focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 transition-all"
|
||
value={settings.environment}
|
||
onChange={e => handleSettingChange('environment', e.target.value)}
|
||
>
|
||
<option value="development">Development</option>
|
||
<option value="staging">Staging</option>
|
||
<option value="production">Production</option>
|
||
</select>
|
||
</div>
|
||
|
||
{/* Debug Mode Toggle */}
|
||
<div className="flex items-center justify-between p-4 bg-gray-800/30 rounded-lg border border-gray-700">
|
||
<div>
|
||
<h3 className="text-sm font-semibold text-white">Debug Mode</h3>
|
||
<p className="text-xs text-gray-400 mt-1">Enable detailed logging and debugging features</p>
|
||
</div>
|
||
<label className="relative inline-flex items-center cursor-pointer">
|
||
<input
|
||
type="checkbox"
|
||
checked={settings.debugMode}
|
||
onChange={e => handleSettingChange('debugMode', e.target.checked)}
|
||
className="sr-only peer"
|
||
/>
|
||
<div className="w-11 h-6 bg-gray-600 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-indigo-300/20 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:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-indigo-600"></div>
|
||
</label>
|
||
</div>
|
||
|
||
{/* Log Level */}
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-300 mb-2">Log Level</label>
|
||
<select
|
||
className="w-full px-3 py-2 bg-gray-800/50 border border-gray-700 rounded-lg text-white focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 transition-all"
|
||
value={settings.logLevel}
|
||
onChange={e => handleSettingChange('logLevel', e.target.value)}
|
||
>
|
||
<option value="error">Error</option>
|
||
<option value="warn">Warning</option>
|
||
<option value="info">Info</option>
|
||
<option value="debug">Debug</option>
|
||
<option value="trace">Trace</option>
|
||
</select>
|
||
</div>
|
||
|
||
{/* API Settings */}
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-300 mb-2">API Timeout (ms)</label>
|
||
<input
|
||
type="number"
|
||
className="w-full px-3 py-2 bg-gray-800/50 border border-gray-700 rounded-lg text-white placeholder-gray-500 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 transition-all"
|
||
value={settings.apiTimeout}
|
||
onChange={e => handleSettingChange('apiTimeout', parseInt(e.target.value) || 30000)}
|
||
min="1000"
|
||
max="300000"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-300 mb-2">Max Retries</label>
|
||
<input
|
||
type="number"
|
||
className="w-full px-3 py-2 bg-gray-800/50 border border-gray-700 rounded-lg text-white placeholder-gray-500 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 transition-all"
|
||
value={settings.maxRetries}
|
||
onChange={e => handleSettingChange('maxRetries', parseInt(e.target.value) || 3)}
|
||
min="0"
|
||
max="10"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Custom Endpoint */}
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-300 mb-2">Custom API Endpoint</label>
|
||
<input
|
||
type="url"
|
||
className="w-full px-3 py-2 bg-gray-800/50 border border-gray-700 rounded-lg text-white placeholder-gray-500 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 transition-all"
|
||
placeholder="https://api.example.com"
|
||
value={settings.customEndpoint}
|
||
onChange={e => handleSettingChange('customEndpoint', e.target.value)}
|
||
/>
|
||
</div>
|
||
|
||
{/* Status Message */}
|
||
{message && (
|
||
<div className={`p-3 rounded-lg text-sm ${
|
||
message.includes('successfully') || message.includes('saved locally')
|
||
? 'bg-green-500/10 border border-green-500/30 text-green-400'
|
||
: message.includes('reset')
|
||
? 'bg-blue-500/10 border border-blue-500/30 text-blue-400'
|
||
: 'bg-yellow-500/10 border border-yellow-500/30 text-yellow-400'
|
||
}`}>
|
||
{message}
|
||
</div>
|
||
)}
|
||
|
||
{/* Action Buttons */}
|
||
<div className="grid grid-cols-2 gap-3 pt-4 border-t border-gray-700">
|
||
<button
|
||
onClick={handleSave}
|
||
disabled={loading}
|
||
className={`py-3 px-4 rounded-lg font-semibold transition-all duration-300 ${
|
||
loading
|
||
? 'bg-gray-700 text-gray-400 cursor-not-allowed'
|
||
: 'btn-primary transform hover:scale-105 active:scale-95'
|
||
}`}
|
||
>
|
||
{loading ? (
|
||
<div className="flex items-center justify-center space-x-2">
|
||
<div className="spinner"></div>
|
||
<span>Saving...</span>
|
||
</div>
|
||
) : (
|
||
'Save Settings'
|
||
)}
|
||
</button>
|
||
|
||
<button
|
||
onClick={handleReset}
|
||
disabled={loading}
|
||
className="btn-secondary py-3 px-4 transform hover:scale-105 active:scale-95"
|
||
>
|
||
Reset to Defaults
|
||
</button>
|
||
</div>
|
||
|
||
{/* Current Settings Summary */}
|
||
<div className="p-3 bg-gray-800/20 rounded-lg border border-gray-700">
|
||
<h4 className="text-xs font-semibold text-gray-400 mb-2">Current Configuration</h4>
|
||
<div className="grid grid-cols-2 gap-2 text-xs">
|
||
<div className="text-gray-500">Environment:</div>
|
||
<div className="text-gray-300 capitalize">{settings.environment}</div>
|
||
<div className="text-gray-500">Debug:</div>
|
||
<div className={settings.debugMode ? 'text-green-400' : 'text-red-400'}>
|
||
{settings.debugMode ? 'Enabled' : 'Disabled'}
|
||
</div>
|
||
<div className="text-gray-500">Log Level:</div>
|
||
<div className="text-gray-300 capitalize">{settings.logLevel}</div>
|
||
<div className="text-gray-500">Timeout:</div>
|
||
<div className="text-gray-300">{settings.apiTimeout}ms</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|