feat: add admin contracts and arsenal pages

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
achmad
2026-05-29 17:05:09 +07:00
parent 3f7bda10eb
commit f14e6b91f3
4 changed files with 109 additions and 0 deletions
+57
View File
@@ -0,0 +1,57 @@
'use client';
import { useEffect, useState } from 'react';
export default function ArsenalPage() {
const [data, setData] = useState<any>({});
useEffect(() => {
fetch('/api/admin/arsenal').then(r => r.json()).then(setData);
}, []);
return (
<div>
<h1 className="text-2xl font-bold mb-4">Arsenal</h1>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="bg-gray-800 rounded-lg p-4">
<h2 className="text-lg font-semibold mb-3">Inventory ({data.inventory?.length || 0})</h2>
<div className="max-h-96 overflow-y-auto text-sm space-y-1">
{data.inventory?.map((i: any, idx: number) => (
<div key={idx} className="text-gray-300 p-1 border-b border-gray-700 last:border-0">
<span className="text-amber-300">{i.item_name}</span>
<span className="text-gray-500 ml-2">[{i.quality}]</span>
<div className="text-xs text-gray-500">{i.steam_id}</div>
</div>
))}
{!data.inventory?.length && <p className="text-gray-500 text-sm">None</p>}
</div>
</div>
<div className="bg-gray-800 rounded-lg p-4">
<h2 className="text-lg font-semibold mb-3">Loadouts ({data.loadouts?.length || 0})</h2>
<div className="max-h-96 overflow-y-auto text-sm space-y-1">
{data.loadouts?.map((l: any, idx: number) => (
<div key={idx} className="text-gray-300 p-1 border-b border-gray-700">
<span className="font-mono text-xs">{l.steam_id}</span>
<span className="text-amber-300 ml-2">{l.hero_name}</span>
<div className="text-xs text-gray-500">{l.loadout}</div>
</div>
))}
{!data.loadouts?.length && <p className="text-gray-500 text-sm">None</p>}
</div>
</div>
<div className="bg-gray-800 rounded-lg p-4">
<h2 className="text-lg font-semibold mb-3">Active Listings ({data.listings?.length || 0})</h2>
<div className="max-h-96 overflow-y-auto text-sm space-y-1">
{data.listings?.map((l: any, idx: number) => (
<div key={idx} className="text-gray-300 p-1 border-b border-gray-700">
<span className="text-amber-300">{l.item_name}</span>
<span className="text-gray-500 ml-2">{l.price_free} free</span>
<div className="text-xs text-gray-500">{l.steam_id}</div>
</div>
))}
{!data.listings?.length && <p className="text-gray-500 text-sm">None</p>}
</div>
</div>
</div>
</div>
);
}
+34
View File
@@ -0,0 +1,34 @@
'use client';
import { useEffect, useState } from 'react';
export default function ContractsPage() {
const [contracts, setContracts] = useState<any[]>([]);
useEffect(() => {
fetch('/api/admin/contracts').then(r => r.json()).then(setContracts);
}, []);
return (
<div>
<h1 className="text-2xl font-bold mb-4">Death Sentence Contracts</h1>
<div className="bg-gray-800 rounded-lg">
<table className="w-full text-left text-sm">
<thead>
<tr className="border-b border-gray-700 text-gray-400">
<th className="p-3">Steam ID</th><th className="p-3">Contract Data</th><th className="p-3">Updated</th>
</tr>
</thead>
<tbody>
{contracts.map((c: any) => (
<tr key={c.steam_id} className="border-b border-gray-700">
<td className="p-3 font-mono text-xs">{c.steam_id}</td>
<td className="p-3 text-xs max-w-md truncate">{c.contracts}</td>
<td className="p-3 text-xs text-gray-500">{c.updated_at}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
@@ -0,0 +1,10 @@
import { NextResponse } from 'next/server';
import { getDb } from '@/lib/db';
export async function GET() {
const db = getDb();
const inventory = db.prepare('SELECT * FROM arsenal_inventory ORDER BY steam_id').all();
const loadouts = db.prepare('SELECT * FROM arsenal_loadouts ORDER BY steam_id').all();
const listings = db.prepare("SELECT * FROM arsenal_market_listings WHERE status = 'active' ORDER BY created_at DESC").all();
return NextResponse.json({ inventory, loadouts, listings });
}
@@ -0,0 +1,8 @@
import { NextResponse } from 'next/server';
import { getDb } from '@/lib/db';
export async function GET() {
const db = getDb();
const contracts = db.prepare('SELECT * FROM death_sentence_contracts').all();
return NextResponse.json(contracts);
}