abbashkyt-creator 7d8ce0e322 V0.1
2026-03-14 04:02:22 +03:00

175 lines
8.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import { useEffect, useState } from 'react'
import { fetchConfig, saveConfig } from '@/lib/api/config'
import { testTelegram, downloadBackup, restoreBackup } from '@/lib/api/system'
import { useSettingsStore } from '@/store/settingsStore'
const Field = ({
label, k, cfg, onChange, type = 'text', mono = false,
}: {
label: string; k: string; cfg: Record<string, string>;
onChange: (k: string, v: string) => void; type?: string; mono?: boolean
}) => (
<div className="flex items-center gap-4">
<label className="text-xs text-g-faint w-52 shrink-0 leading-snug">{label}</label>
<input
type={type}
value={cfg[k] ?? ''}
onChange={(e) => onChange(k, e.target.value)}
className={`g-input h-8 text-sm flex-1 ${mono ? 'font-mono' : ''}`}
/>
</div>
)
const Section = ({ title, children }: { title: string; children: React.ReactNode }) => (
<div className="g-card overflow-hidden">
<div className="px-5 py-3 border-b border-g-border/50">
<h2 className="text-xs font-semibold uppercase tracking-widest text-g-faint">{title}</h2>
</div>
<div className="p-5 space-y-3.5">
{children}
</div>
</div>
)
export default function SettingsPage() {
const { config, loaded, setConfig, updateKey } = useSettingsStore()
const [saving, setSaving] = useState(false)
const [msg, setMsg] = useState('')
useEffect(() => {
if (!loaded) fetchConfig().then(setConfig).catch(() => setConfig({}))
}, [loaded, setConfig])
const save = async () => {
setSaving(true)
try { await saveConfig(config); setMsg('Saved.') }
catch { setMsg('Save failed.') }
setSaving(false)
setTimeout(() => setMsg(''), 3000)
}
const handleRestore = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0]
if (!file) return
if (!confirm('Restore this backup? Current data will be replaced.')) return
try { await restoreBackup(file); setMsg('Restored. Restart engine.') }
catch { setMsg('Restore failed.') }
}
if (!loaded) return (
<div className="flex items-center gap-2 text-xs text-g-faint">
<span className="w-1.5 h-1.5 rounded-full bg-g-faint animate-pulse" />
Loading settings
</div>
)
return (
<div className="space-y-6 max-w-2xl">
<div>
<h1 className="g-page-title">Settings</h1>
<p className="g-page-sub">Engine and alert configuration</p>
</div>
<Section title="Telegram">
<Field label="Bot token" k="telegram_token" cfg={config} onChange={updateKey} mono />
<Field label="Chat ID" k="telegram_chat_id" cfg={config} onChange={updateKey} mono />
<button onClick={async () => {
try { await testTelegram(); setMsg('Telegram OK!') }
catch { setMsg('Telegram failed.') }
}} className="g-btn text-xs">
Send test message
</button>
</Section>
<Section title="Engine">
<Field label="Scrape interval (s)" k="timer" cfg={config} onChange={updateKey} type="number" />
<Field label="Browser" k="browser_choice" cfg={config} onChange={updateKey} />
<Field label="Humanize level" k="humanize_level" cfg={config} onChange={updateKey} />
<Field label="Show browser (true/false)" k="show_browser" cfg={config} onChange={updateKey} />
<Field label="Incognito mode" k="incognito_mode" cfg={config} onChange={updateKey} />
<Field label="Delay launch (s)" k="delay_launch" cfg={config} onChange={updateKey} type="number" />
<Field label="Delay post-search (s)" k="delay_post_search" cfg={config} onChange={updateKey} type="number" />
<Field label="Scrape window enabled" k="scrape_window_enabled" cfg={config} onChange={updateKey} />
<Field label="Window start hour (023)" k="scrape_start_hour" cfg={config} onChange={updateKey} type="number" />
<Field label="Window end hour (023)" k="scrape_end_hour" cfg={config} onChange={updateKey} type="number" />
<Field label="Boost interval (min)" k="boost_interval_mins" cfg={config} onChange={updateKey} type="number" />
</Section>
<Section title="Alerts">
<Field label="Alert channels (telegram,discord,email)" k="alert_channels" cfg={config} onChange={updateKey} />
<Field label="Discord webhook" k="discord_webhook" cfg={config} onChange={updateKey} />
<Field label="Gmail address" k="gmail_address" cfg={config} onChange={updateKey} />
<Field label="Gmail app password" k="gmail_app_password" cfg={config} onChange={updateKey} type="password" mono />
<Field label="Email to" k="email_to" cfg={config} onChange={updateKey} />
<Field label="Closing alerts (true/false)" k="closing_alert_enabled" cfg={config} onChange={updateKey} />
<Field label="Alert schedule (min, e.g. 60,30,10)" k="closing_alert_schedule" cfg={config} onChange={updateKey} />
</Section>
<Section title="Currency">
<Field label="Display currency (blank = raw)" k="display_currency" cfg={config} onChange={updateKey} />
</Section>
<Section title="Proxy">
<Field label="Proxy enabled (true/false)" k="proxy_enabled" cfg={config} onChange={updateKey} />
<div className="flex items-start gap-4">
<label className="text-xs text-g-faint w-52 shrink-0 pt-1.5">Proxy list</label>
<textarea
value={config['proxy_list'] ?? ''}
onChange={(e) => updateKey('proxy_list', e.target.value)}
rows={3}
placeholder={"http://proxy1:8080\nsocks5://proxy2:1080"}
className="g-input text-sm font-mono resize-none flex-1"
/>
</div>
</Section>
<Section title="CAPTCHA">
<Field label="Solver (2captcha / capsolver)" k="captcha_solver" cfg={config} onChange={updateKey} />
<Field label="API key" k="captcha_api_key" cfg={config} onChange={updateKey} type="password" mono />
</Section>
<Section title="AI Filter">
<Field label="AI enabled (true/false)" k="ai_filter_enabled" cfg={config} onChange={updateKey} />
<Field label="AI provider (groq/ollama)" k="ai_provider" cfg={config} onChange={updateKey} />
<Field label="AI model" k="ai_model" cfg={config} onChange={updateKey} mono />
<Field label="Groq API key" k="ai_api_key" cfg={config} onChange={updateKey} type="password" mono />
<Field label="Ollama URL" k="ai_base_url" cfg={config} onChange={updateKey} />
<Field label="AI debug (true/false)" k="ai_debug" cfg={config} onChange={updateKey} />
<Field label="Auto-adapt (true/false)" k="auto_adapt_enabled" cfg={config} onChange={updateKey} />
</Section>
<Section title="Database">
<Field label="DB URL (blank = SQLite)" k="db_url" cfg={config} onChange={updateKey} mono />
<Field label="Auto-disable after N failures (0 = never)" k="site_auto_disable_after" cfg={config} onChange={updateKey} type="number" />
</Section>
<Section title="Backup & Restore">
<div className="flex gap-2">
<button onClick={downloadBackup} className="g-btn text-xs">Download backup</button>
<label className="g-btn text-xs cursor-pointer">
Restore backup
<input type="file" accept=".db" onChange={handleRestore} className="hidden" />
</label>
</div>
</Section>
{/* Save bar */}
<div className="flex gap-3 items-center pt-2">
<button
onClick={save}
disabled={saving}
className="g-btn-primary text-sm px-5 disabled:opacity-50"
>
{saving ? 'Saving…' : 'Save settings'}
</button>
{msg && (
<span className={`text-xs ${msg.includes('fail') || msg.includes('fail') ? 'text-g-red' : 'text-g-green'}`}>
{msg}
</span>
)}
</div>
</div>
)
}