feat: replace API token field with login flow

New auth.ts service: login() POSTs to /api/auth/token with handle +
password, stores instanceUrl/handle/apiToken in AsyncStorage, password
never persisted. logout() clears all credentials. loadAuthState()
returns stored credentials or null.

Settings screen now shows a login form (URL + handle + password) when
not connected, and a connected state card with Disconnect button when
logged in. km notifications toggle auto-saves without a separate Save
button.
This commit is contained in:
Davide Scaini
2026-06-03 09:43:52 +02:00
parent 9d82084fa1
commit 6e47ced264
2 changed files with 174 additions and 32 deletions
+64
View File
@@ -0,0 +1,64 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
interface LoginResult {
ok: boolean;
displayName?: string;
error?: string;
}
export async function login(
instanceUrl: string,
handle: string,
password: string,
): Promise<LoginResult> {
const url = instanceUrl.replace(/\/$/, '') + '/api/auth/token';
try {
const resp = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ handle, password }),
});
if (!resp.ok) {
const text = await resp.text().catch(() => '');
return { ok: false, error: text || `HTTP ${resp.status}` };
}
const data = await resp.json();
if (!data.token) return { ok: false, error: 'No token in response' };
await Promise.all([
AsyncStorage.setItem('instanceUrl', instanceUrl.trim()),
AsyncStorage.setItem('handle', handle.trim()),
AsyncStorage.setItem('apiToken', data.token),
]);
return { ok: true, displayName: data.display_name };
} catch (e: any) {
return { ok: false, error: e?.message ?? 'Connection failed' };
}
}
export async function logout(): Promise<void> {
await Promise.all([
AsyncStorage.removeItem('instanceUrl'),
AsyncStorage.removeItem('handle'),
AsyncStorage.removeItem('apiToken'),
]);
}
export interface AuthState {
instanceUrl: string;
handle: string;
apiToken: string;
}
export async function loadAuthState(): Promise<AuthState | null> {
const [instanceUrl, handle, apiToken] = await Promise.all([
AsyncStorage.getItem('instanceUrl'),
AsyncStorage.getItem('handle'),
AsyncStorage.getItem('apiToken'),
]);
if (!instanceUrl || !apiToken) return null;
return { instanceUrl, handle: handle ?? '', apiToken };
}