Skip to content

Commit 855207f

Browse files
committed
fix(settings): validate GitHub PAT before saving
1 parent 4243735 commit 855207f

1 file changed

Lines changed: 45 additions & 8 deletions

File tree

src/pages/SettingsPage.jsx

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,44 @@ export default function SettingsPage() {
1212
const [cleared, setCleared] = useState(false)
1313
const [isRefreshing, setIsRefreshing] = useState(false)
1414
const [refreshError, setRefreshError] = useState(false)
15-
const handleSave = () => {
16-
savePat(draft.trim())
17-
setSaved(true)
18-
setTimeout(() => setSaved(false), 2000)
15+
const [isValidating, setIsValidating] = useState(false)
16+
const [tokenError, setTokenError] = useState('')
17+
18+
const handleSave = async () => {
19+
const token = draft.trim();
20+
if (!token) return;
21+
22+
setIsValidating(true);
23+
setTokenError('');
24+
25+
try {
26+
const response = await fetch('https://api.github.com/rate_limit', {
27+
headers: {
28+
Accept: 'application/vnd.github.v3+json',
29+
Authorization: `token ${token}`
30+
}
31+
});
32+
33+
if (!response.ok) {
34+
setTokenError('Invalid Personal Access Token');
35+
setIsValidating(false);
36+
return;
37+
}
38+
39+
savePat(token);
40+
setSaved(true);
41+
setTimeout(() => setSaved(false), 2000);
42+
} catch (err) {
43+
setTokenError('Network error verifying token');
44+
} finally {
45+
setIsValidating(false);
46+
}
1947
}
2048

2149
const handleDelete = () => {
2250
savePat('')
2351
setDraft('')
52+
setTokenError('')
2453
}
2554

2655
const handleClear = async () => {
@@ -131,7 +160,10 @@ export default function SettingsPage() {
131160
<input
132161
type={show ? 'text' : 'password'}
133162
value={draft}
134-
onChange={e => setDraft(e.target.value)}
163+
onChange={e => {
164+
setDraft(e.target.value)
165+
setTokenError('')
166+
}}
135167
placeholder="ghp_xxxxxxxxxxxxxxxxxxxx"
136168
style={{ ...C.input, flex: 1 }}
137169
onKeyDown={e => e.key === 'Enter' && handleSave()}
@@ -143,17 +175,22 @@ export default function SettingsPage() {
143175
{show ? <FiEyeOff size={14} /> : <FiEye size={14} />}
144176
</button>
145177
</div>
178+
{tokenError && (
179+
<div style={{ color: 'var(--red)', fontSize: 13, marginBottom: 10, marginTop: -2 }}>
180+
{tokenError}
181+
</div>
182+
)}
146183
<div style={{ display: 'flex', gap: 8 }}>
147184
<button
148185
onClick={handleSave}
149-
disabled={!draft.trim()}
186+
disabled={!draft.trim() || isValidating}
150187
style={{ ...C.btn('primary'), display: 'flex', alignItems: 'center', gap: 5, fontSize: 13 }}
151188
>
152-
<FiSave size={13} /> {saved ? 'Saved' : 'Save'}
189+
<FiSave size={13} /> {isValidating ? 'Validating...' : saved ? 'Saved' : 'Save'}
153190
</button>
154191
<button
155192
onClick={handleDelete}
156-
disabled={!draft.trim()}
193+
disabled={!draft.trim() || isValidating}
157194
style={{ ...C.btn('danger'), display: 'flex', alignItems: 'center', gap: 5, fontSize: 13 }}
158195
>
159196
<FiTrash2 size={13} /> Delete

0 commit comments

Comments
 (0)