Files
AITrader/app/routes/settings.tsx
T

62 lines
1.9 KiB
TypeScript

import type { LoaderFunction } from '@remix-run/node';
import { json } from '@remix-run/node';
import React, { useEffect, useState } from 'react';
import { requireAdmin } from '~/lib/auth.server';
import { settingsService } from '~/lib/settings.server';
export const loader: LoaderFunction = async ({ request }) => {
await requireAdmin(request);
await settingsService.init?.();
const entries: any[] = [];
// @ts-ignore
for (const key of (settingsService as any).cache.keys()) {
entries.push({ key, value: await settingsService.get(key) });
}
return json({ entries });
};
export default function SettingsPage() {
const [items, setItems] = useState<Array<{ key: string; value: any }>>([]);
useEffect(() => {
fetch('/api/admin/settings')
.then(r => r.json())
.then(j => setItems(j));
}, []);
async function save(key: string, value: any) {
await fetch(`/api/admin/settings/${encodeURIComponent(key)}`, {
method: 'PUT',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ value }),
});
setItems(s => s.map(i => (i.key === key ? { ...i, value } : i)));
}
return (
<div className="p-6">
<h1 className="text-2xl font-bold mb-4">Settings</h1>
<ul>
{items.map(it => (
<li key={it.key} className="mb-3">
<div className="flex items-center gap-4">
<div className="font-medium">{it.key}</div>
<textarea
className="border p-2 w-2/3"
defaultValue={JSON.stringify(it.value, null, 2)}
onBlur={e => {
try {
const v = JSON.parse(e.currentTarget.value);
save(it.key, v);
} catch (err) {
alert('Invalid JSON');
}
}}
/>
</div>
</li>
))}
</ul>
</div>
);
}