00Boobs00 commited on
Commit
3e87704
·
verified ·
1 Parent(s): 37e516b

Upload components/PocketBase.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. components/PocketBase.js +125 -0
components/PocketBase.js ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState, useEffect } from 'react';
2
+ import { Database, Plus, Trash2, RefreshCw } from 'lucide-react';
3
+
4
+ export default function PocketBase() {
5
+ const [items, setItems] = useState([]);
6
+ const [newItem, setNewItem] = useState('');
7
+ const [loading, setLoading] = useState(false);
8
+ const [actionLoading, setActionLoading] = useState(false);
9
+
10
+ const fetchItems = async () => {
11
+ setLoading(true);
12
+ try {
13
+ const res = await fetch('/api/pocketbase');
14
+ const data = await res.json();
15
+ setItems(data.items || []);
16
+ } catch (error) {
17
+ console.error('Failed to fetch items');
18
+ } finally {
19
+ setLoading(false);
20
+ }
21
+ };
22
+
23
+ useEffect(() => {
24
+ fetchItems();
25
+ }, []);
26
+
27
+ const addItem = async () => {
28
+ if (!newItem.trim()) return;
29
+ setActionLoading(true);
30
+ try {
31
+ const res = await fetch('/api/pocketbase', {
32
+ method: 'POST',
33
+ headers: { 'Content-Type': 'application/json' },
34
+ body: JSON.stringify({ name: newItem }),
35
+ });
36
+ if (res.ok) {
37
+ setNewItem('');
38
+ fetchItems();
39
+ }
40
+ } catch (error) {
41
+ console.error('Failed to add item');
42
+ } finally {
43
+ setActionLoading(false);
44
+ }
45
+ };
46
+
47
+ const deleteItem = async (id) => {
48
+ setActionLoading(true);
49
+ try {
50
+ const res = await fetch('/api/pocketbase', {
51
+ method: 'DELETE',
52
+ headers: { 'Content-Type': 'application/json' },
53
+ body: JSON.stringify({ id }),
54
+ });
55
+ if (res.ok) {
56
+ fetchItems();
57
+ }
58
+ } catch (error) {
59
+ console.error('Failed to delete item');
60
+ } finally {
61
+ setActionLoading(false);
62
+ }
63
+ };
64
+
65
+ return (
66
+ <div className="bg-slate-800 rounded-xl p-6 shadow-xl border border-slate-700">
67
+ <div className="flex items-center justify-between mb-4">
68
+ <div className="flex items-center gap-2">
69
+ <Database className="w-5 h-5 text-emerald-500" />
70
+ <h2 className="text-lg font-semibold text-white">PocketBase Manager</h2>
71
+ </div>
72
+ <button
73
+ onClick={fetchItems}
74
+ disabled={loading}
75
+ className="text-slate-400 hover:text-white transition-colors p-1 rounded-md hover:bg-slate-700"
76
+ title="Refresh"
77
+ >
78
+ <RefreshCw className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />
79
+ </button>
80
+ </div>
81
+
82
+ <div className="flex gap-2 mb-6">
83
+ <input
84
+ type="text"
85
+ value={newItem}
86
+ onChange={(e) => setNewItem(e.target.value)}
87
+ onKeyDown={(e) => e.key === 'Enter' && addItem()}
88
+ placeholder="Add new record..."
89
+ 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"
90
+ />
91
+ <button
92
+ onClick={addItem}
93
+ disabled={actionLoading}
94
+ 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"
95
+ >
96
+ <Plus className="w-5 h-5" />
97
+ </button>
98
+ </div>
99
+
100
+ <div className="space-y-2 max-h-64 overflow-y-auto pr-2">
101
+ {loading ? (
102
+ <p className="text-slate-500 text-sm text-center py-4">Loading records...</p>
103
+ ) : items.length === 0 ? (
104
+ <p className="text-slate-500 text-sm text-center py-4">No records found</p>
105
+ ) : (
106
+ items.map((item) => (
107
+ <div
108
+ key={item.id}
109
+ className="flex items-center justify-between bg-slate-900 p-3 rounded-lg border border-slate-700 group hover:border-slate-500 transition-colors"
110
+ >
111
+ <span className="text-slate-300 truncate mr-2">{item.name || item.id}</span>
112
+ <button
113
+ onClick={() => deleteItem(item.id)}
114
+ className="text-red-400 opacity-0 group-hover:opacity-100 transition-opacity hover:text-red-300 p-1 hover:bg-red-900/30 rounded"
115
+ title="Delete"
116
+ >
117
+ <Trash2 className="w-4 h-4" />
118
+ </button>
119
+ </div>
120
+ ))
121
+ )}
122
+ </div>
123
+ </div>
124
+ );
125
+ }