mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 18:28:15 +00:00
96 lines
3.0 KiB
TypeScript
96 lines
3.0 KiB
TypeScript
const API_URL = import.meta.env.VITE_API_URL ?? 'http://localhost:4100';
|
|
|
|
class AuthError extends Error {
|
|
constructor(message = 'Authentication required') {
|
|
super(message);
|
|
this.name = 'AuthError';
|
|
}
|
|
}
|
|
|
|
const getStoredToken = (): string | null => localStorage.getItem('helix_access_token');
|
|
const getRefreshToken = (): string | null => localStorage.getItem('helix_refresh_token');
|
|
|
|
const storeTokens = (accessToken: string, refreshToken: string) => {
|
|
localStorage.setItem('helix_access_token', accessToken);
|
|
localStorage.setItem('helix_refresh_token', refreshToken);
|
|
};
|
|
|
|
const clearTokens = () => {
|
|
localStorage.removeItem('helix_access_token');
|
|
localStorage.removeItem('helix_refresh_token');
|
|
};
|
|
|
|
export const apiClient = {
|
|
async login(email: string, password: string): Promise<{
|
|
accessToken: string;
|
|
refreshToken: string;
|
|
user?: {
|
|
id?: string;
|
|
email?: string;
|
|
firstName?: string;
|
|
lastName?: string;
|
|
avatarUrl?: string;
|
|
role?: string;
|
|
platformRoles?: string[];
|
|
};
|
|
}> {
|
|
const response = await fetch(`${API_URL}/auth/login`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ email, password }),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const data = await response.json().catch(() => ({}));
|
|
throw new Error(data.message ?? 'Login failed');
|
|
}
|
|
|
|
const data = await response.json();
|
|
storeTokens(data.accessToken, data.refreshToken);
|
|
return data;
|
|
},
|
|
|
|
async graphql<T>(query: string, variables?: Record<string, unknown>): Promise<T> {
|
|
const token = getStoredToken();
|
|
if (!token) throw new AuthError();
|
|
|
|
const response = await fetch(`${API_URL}/graphql`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Bearer ${token}`,
|
|
},
|
|
body: JSON.stringify({ query, variables }),
|
|
});
|
|
|
|
if (response.status === 401) {
|
|
clearTokens();
|
|
throw new AuthError();
|
|
}
|
|
|
|
const json = await response.json();
|
|
if (json.errors) {
|
|
console.error('GraphQL errors:', json.errors);
|
|
throw new Error(json.errors[0]?.message ?? 'GraphQL error');
|
|
}
|
|
|
|
return json.data;
|
|
},
|
|
|
|
async healthCheck(): Promise<{ status: string; platform: { reachable: boolean } }> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/health`, { signal: AbortSignal.timeout(3000) });
|
|
if (!response.ok) return { status: 'down', platform: { reachable: false } };
|
|
return response.json();
|
|
} catch {
|
|
return { status: 'down', platform: { reachable: false } };
|
|
}
|
|
},
|
|
|
|
getStoredToken,
|
|
getRefreshToken,
|
|
storeTokens,
|
|
clearTokens,
|
|
isAuthenticated: () => !!getStoredToken(),
|
|
};
|