feat(typescript): add core infrastructure modules
- Add centralized API type definitions (types/api.d.ts) - Interfaces for all API responses matching Go handler JSON - Snake_case field names matching actual API responses - Source file references in comments for verification - Add API client module (api.ts) - Procedural get/post/put/delete functions - Automatic auth header injection - Exported to window for cross-module access - Add DOM utilities (dom.ts) - escapeHtml for safe HTML rendering - querySelector wrappers with null checks - Element creation helpers - Add event delegation helpers (events.ts) - Reusable event delegation pattern - Data attribute selectors for dynamic content - Add localStorage wrapper (storage.ts) - Type-safe token management - Theme persistence helpers
This commit is contained in:
+101
@@ -0,0 +1,101 @@
|
||||
function getAuthHeader(): string {
|
||||
const token = localStorage.getItem('token');
|
||||
return token ? `Bearer ${token}` : '';
|
||||
}
|
||||
|
||||
async function apiGet(url: string): Promise<Response> {
|
||||
return fetch(`/api${url}`, {
|
||||
headers: {
|
||||
'Authorization': getAuthHeader(),
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function apiPost(url: string, data?: unknown): Promise<Response> {
|
||||
return fetch(`/api${url}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': getAuthHeader(),
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: data ? JSON.stringify(data) : undefined
|
||||
});
|
||||
}
|
||||
|
||||
async function apiPut(url: string, data?: unknown): Promise<Response> {
|
||||
return fetch(`/api${url}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Authorization': getAuthHeader(),
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: data ? JSON.stringify(data) : undefined
|
||||
});
|
||||
}
|
||||
|
||||
async function apiDelete(url: string): Promise<Response> {
|
||||
return fetch(`/api${url}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Authorization': getAuthHeader()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function apiPatch(url: string, data?: unknown): Promise<Response> {
|
||||
return fetch(`/api${url}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Authorization': getAuthHeader(),
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: data ? JSON.stringify(data) : undefined
|
||||
});
|
||||
}
|
||||
|
||||
async function handleResponse<T>(response: Response): Promise<T> {
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ error: 'Unknown error' }));
|
||||
throw new Error(errorData.error || `HTTP ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async function handleVoidResponse(response: Response): Promise<void> {
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ error: 'Unknown error' }));
|
||||
throw new Error(errorData.error || `HTTP ${response.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
function handleError(error: unknown, context: string): void {
|
||||
console.error(`${context}:`, error);
|
||||
const message = error instanceof Error ? error.message : 'An unexpected error occurred';
|
||||
if ((window as any).showToast?.error) {
|
||||
(window as any).showToast.error(message);
|
||||
}
|
||||
}
|
||||
|
||||
(window as any).api = {
|
||||
get: apiGet,
|
||||
post: apiPost,
|
||||
put: apiPut,
|
||||
delete: apiDelete,
|
||||
patch: apiPatch,
|
||||
handleResponse,
|
||||
handleVoidResponse,
|
||||
handleError
|
||||
};
|
||||
|
||||
export {
|
||||
getAuthHeader,
|
||||
apiGet,
|
||||
apiPost,
|
||||
apiPut,
|
||||
apiDelete,
|
||||
apiPatch,
|
||||
handleResponse,
|
||||
handleVoidResponse,
|
||||
handleError
|
||||
};
|
||||
Reference in New Issue
Block a user