Files
PinPoint-Golf/src/services/api.ts
T

169 lines
4.6 KiB
TypeScript

import { User, AuthResponse, PublicGolferStats, CommunityComparisonData } from '../types/auth';
import { Round, TrackingSettings, Course } from '../types/golf';
const AUTH_TOKEN_KEY = 'pinpoint_auth_token_v1';
export function getStoredToken(): string | null {
return localStorage.getItem(AUTH_TOKEN_KEY);
}
export function setStoredToken(token: string | null): void {
if (token) {
localStorage.setItem(AUTH_TOKEN_KEY, token);
} else {
localStorage.removeItem(AUTH_TOKEN_KEY);
}
}
async function request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
const token = getStoredToken();
const headers: Record<string, string> = {
'Content-Type': 'application/json',
...(options.headers as Record<string, string>),
};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const response = await fetch(endpoint, {
...options,
headers,
});
if (!response.ok) {
let errorMsg = `Request failed: ${response.statusText}`;
try {
const errorJson = await response.json();
if (errorJson && errorJson.error) {
errorMsg = errorJson.error;
}
} catch {
// Ignore json parse error
}
throw new Error(errorMsg);
}
return response.json();
}
export const authApi = {
async register(data: {
email: string;
username: string;
password: string;
name?: string;
handicapIndex?: number;
homeClub?: string;
isPublic?: boolean;
}): Promise<AuthResponse & { settings: TrackingSettings }> {
return request<AuthResponse & { settings: TrackingSettings }>('/api/auth/register', {
method: 'POST',
body: JSON.stringify(data),
});
},
async login(identifier: string, password: string): Promise<AuthResponse & { settings: TrackingSettings }> {
return request<AuthResponse & { settings: TrackingSettings }>('/api/auth/login', {
method: 'POST',
body: JSON.stringify({ identifier, password }),
});
},
async getMe(): Promise<{ user: User; settings: TrackingSettings }> {
return request<{ user: User; settings: TrackingSettings }>('/api/auth/me');
},
async updateProfile(updates: Partial<User>): Promise<{ user: User }> {
return request<{ user: User }>('/api/auth/profile', {
method: 'PUT',
body: JSON.stringify(updates),
});
},
async ssoLogin(data: {
provider: string;
email?: string;
username?: string;
name?: string;
avatarUrl?: string;
authentikServerUrl?: string;
}): Promise<AuthResponse & { settings: TrackingSettings }> {
return request<AuthResponse & { settings: TrackingSettings }>('/api/auth/oauth/sso-login', {
method: 'POST',
body: JSON.stringify(data),
});
},
async getProviders(): Promise<{
providers: Array<{
id: string;
name: string;
icon: string;
isConfigured: boolean;
issuerUrl?: string;
authUrlEndpoint: string;
}>;
}> {
return request('/api/auth/oauth/providers');
},
async getSettings(): Promise<TrackingSettings> {
return request<TrackingSettings>('/api/auth/settings');
},
async updateSettings(settings: TrackingSettings): Promise<TrackingSettings> {
return request<TrackingSettings>('/api/auth/settings', {
method: 'PUT',
body: JSON.stringify(settings),
});
},
};
export const roundsApi = {
async getRounds(): Promise<Round[]> {
return request<Round[]>('/api/rounds');
},
async saveRound(round: Round): Promise<Round> {
return request<Round>('/api/rounds', {
method: 'POST',
body: JSON.stringify(round),
});
},
async syncBatch(rounds: Round[]): Promise<{ count: number; rounds: Round[] }> {
return request<{ count: number; rounds: Round[] }>('/api/rounds/sync-batch', {
method: 'POST',
body: JSON.stringify({ rounds }),
});
},
async deleteRound(id: string): Promise<{ success: boolean }> {
return request<{ success: boolean }>(`/api/rounds/${id}`, {
method: 'DELETE',
});
},
async getCustomCourses(): Promise<Course[]> {
return request<Course[]>('/api/rounds/courses/custom');
},
async saveCustomCourse(course: Course): Promise<Course> {
return request<Course>('/api/rounds/courses/custom', {
method: 'POST',
body: JSON.stringify(course),
});
},
};
export const communityApi = {
async getLeaderboard(): Promise<{ totalCount: number; golfers: PublicGolferStats[] }> {
return request<{ totalCount: number; golfers: PublicGolferStats[] }>('/api/community/leaderboard');
},
async getComparison(): Promise<CommunityComparisonData> {
return request<CommunityComparisonData>('/api/community/compare');
},
};