00Boobs00's picture
Upload components/PocketBase.js with huggingface_hub
c187f58 verified
import { useState, useEffect } from 'react';
import { Database, Plus, Trash2, RefreshCw } from 'lucide-react';
export default function PocketBase() {
const [items, setItems] = useState([]);
const [newItem, setNewItem] = useState('');
const [loading, setLoading] = useState(false);
const [actionLoading, setActionLoading] = useState(false);
const fetchItems = async () => {
setLoading(true);
try {
const res = await fetch('/api/pocketbase');
const data = await res.json();
setItems(data.items || []);
} catch (error) {
console.error('Failed to fetch items');
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchItems();
}, []);
const addItem = async () => {
if (!newItem.trim()) return;
setActionLoading(true);
try {
const res = await fetch('/api/pocketbase', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: newItem }),
});
if (res.ok) {
setNewItem('');
fetchItems();
}
} catch (error) {
console.error('Failed to add item');
} finally {
setActionLoading(false);
}
};
const deleteItem = async (id) => {
setActionLoading(true);
try {
const res = await fetch('/api/pocketbase', {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id }),
});
if (res.ok) {
fetchItems();
}
} catch (error) {
console.error('Failed to delete item');
} finally {
setActionLoading(false);
}
};
return (
<div className="bg-slate-800 rounded-xl p-6 shadow-xl border border-slate-700">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-2">
<Database className="w-5 h-5 text-emerald-500" />
<h2 className="text-lg font-semibold text-white">PocketBase Manager</h2>
</div>
<button
onClick={fetchItems}
disabled={loading}
className="text-slate-400 hover:text-white transition-colors p-1 rounded-md hover:bg-slate-700"
title="Refresh"
>
<RefreshCw className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />
</button>
</div>
<div className="flex gap-2 mb-6">
<input
type="text"
value={newItem}
onChange={(e) => setNewItem(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && addItem()}
placeholder="Add new record..."
className="flex-1 bg-slate-900 border border-slate-600 rounded-lg px-4 py-2 text-white placeholder-slate-500 focus:ring-2 focus:ring-emerald-500 focus:border-transparent outline-none"
/>
<button
onClick={addItem}
disabled={actionLoading}
className="bg-emerald-600 hover:bg-emerald-500 text-white px-4 py-2 rounded-lg transition-colors disabled:opacity-50 flex items-center justify-center"
>
<Plus className="w-5 h-5" />
</button>
</div>
<div className="space-y-2 max-h-64 overflow-y-auto pr-2">
{loading ? (
<p className="text-slate-500 text-sm text-center py-4">Loading records...</p>
) : items.length === 0 ? (
<p className="text-slate-500 text-sm text-center py-4">No records found</p>
) : (
items.map((item) => (
<div
key={item.id}
className="flex items-center justify-between bg-slate-900 p-3 rounded-lg border border-slate-700 group hover:border-slate-500 transition-colors"
>
<span className="text-slate-300 truncate mr-2">{item.name || item.id}</span>
<button
onClick={() => deleteItem(item.id)}
className="text-red-400 opacity-0 group-hover:opacity-100 transition-opacity hover:text-red-300 p-1 hover:bg-red-900/30 rounded"
title="Delete"
>
<Trash2 className="w-4 h-4" />
</button>
</div>
))
)}
</div>
</div>
);
}