1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
'use client';
import { useState, useEffect } from 'react';
import { TwitterBookmark } from '../lib/bookmark-models';
import { BookmarkStorageService } from '../lib/bookmark-storage';
import { BookmarkList } from './bookmark-list';
export function BookmarkFetcher() {
const [bookmarks, setBookmarks] = useState<TwitterBookmark[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [username, setUsername] = useState('');
const [authToken, setAuthToken] = useState('');
// Load existing bookmarks on mount
useEffect(() => {
const existingBookmarks = BookmarkStorageService.getBookmarks();
setBookmarks(existingBookmarks);
}, []);
const handleFetchBookmarks = async () => {
if (!username || !authToken) {
setError('Please enter your Twitter username and auth token');
return;
}
setLoading(true);
setError(null);
try {
// Simple fetch to our API endpoint
const response = await fetch('/api/sync-bookmarks', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, authToken }),
});
const result = await response.json();
if (!result.success) {
throw new Error(result.error || 'Failed to fetch bookmarks');
}
// Load the newly saved bookmarks
const updatedBookmarks = BookmarkStorageService.getBookmarks();
setBookmarks(updatedBookmarks);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to fetch bookmarks');
} finally {
setLoading(false);
}
};
const handleClearBookmarks = () => {
BookmarkStorageService.clearAll();
setBookmarks([]);
};
return (
<div className="space-y-6">
{/* Input fields */}
<div className="bg-white border border-gray-200 rounded-lg p-6">
<h2 className="text-xl font-semibold mb-4">Twitter Credentials</h2>
<div className="space-y-4">
<div>
<label htmlFor="username" className="block text-sm font-medium text-gray-700 mb-1">
Twitter Username
</label>
<input
id="username"
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="your_twitter_username"
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
<div>
<label htmlFor="authToken" className="block text-sm font-medium text-gray-700 mb-1">
Auth Token
</label>
<input
id="authToken"
type="password"
value={authToken}
onChange={(e) => setAuthToken(e.target.value)}
placeholder="your_auth_token"
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
</div>
</div>
{/* Action buttons */}
<div className="flex gap-4">
<button
onClick={handleFetchBookmarks}
disabled={loading}
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:bg-blue-300 disabled:cursor-not-allowed font-medium"
>
{loading ? (
<>
<svg className="animate-spin -ml-1 mr-3 h-5 w-5 text-white inline" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Fetching...
</>
) : (
'Fetch Twitter Bookmarks'
)}
</button>
{bookmarks.length > 0 && (
<button
onClick={handleClearBookmarks}
className="px-6 py-3 bg-red-600 text-white rounded-lg hover:bg-red-700 font-medium"
>
Clear All
</button>
)}
</div>
{/* Error message */}
{error && (
<div className="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg">
{error}
</div>
)}
{/* Bookmark list */}
<div className="bg-white border border-gray-200 rounded-lg p-6">
<h2 className="text-xl font-semibold mb-4">Your Bookmarks</h2>
<BookmarkList bookmarks={bookmarks} />
</div>
</div>
);
}
|