Files
grateful-journal/src/lib/api.ts
2026-03-31 10:23:49 +05:30

206 lines
4.3 KiB
TypeScript

/**
* API Service Layer
* Handles all communication with the backend API
*/
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8001/api'
type ApiOptions = {
method?: 'GET' | 'POST' | 'PUT' | 'DELETE'
body?: unknown
token?: string | null
}
async function apiCall<T>(
endpoint: string,
options: ApiOptions = {}
): Promise<T> {
const { method = 'GET', body, token } = options
const headers: HeadersInit = {
'Content-Type': 'application/json',
}
if (token) {
headers['Authorization'] = `Bearer ${token}`
}
const config: RequestInit = {
method,
headers,
credentials: 'include',
}
if (body) {
config.body = JSON.stringify(body)
}
const response = await fetch(`${API_BASE_URL}${endpoint}`, config)
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.detail || `API error: ${response.statusText}`)
}
return response.json() as Promise<T>
}
// ============================================
// USER ENDPOINTS
// ============================================
export async function registerUser(
userData: {
email: string
displayName?: string
photoURL?: string
},
token: string
) {
return apiCall('/users/register', {
method: 'POST',
body: userData,
token,
})
}
export async function getUserByEmail(email: string, token: string) {
return apiCall(`/users/by-email/${email}`, { token })
}
export async function updateUserProfile(
userId: string,
updates: { displayName?: string; photoURL?: string; theme?: string; tutorial?: boolean },
token: string
) {
return apiCall(`/users/${userId}`, {
method: 'PUT',
body: updates,
token,
})
}
export async function deleteUser(userId: string, token: string) {
return apiCall<{ message: string; user_deleted: number; entries_deleted: number }>(
`/users/${userId}`,
{
method: 'DELETE',
token,
}
)
}
// ============================================
// ENTRY ENDPOINTS
// ============================================
export interface EncryptionMetadata {
encrypted: boolean
ciphertext?: string // Base64-encoded encrypted content
nonce?: string // Base64-encoded nonce
algorithm?: string // e.g., "XSalsa20-Poly1305"
}
export interface JournalEntryCreate {
title?: string // Optional if encrypted
content?: string // Optional if encrypted
mood?: string
tags?: string[]
isPublic?: boolean
encryption?: EncryptionMetadata
}
export interface JournalEntry extends JournalEntryCreate {
id: string
userId: string
createdAt: string
updatedAt: string
entryDate?: string
encryption?: EncryptionMetadata
}
export async function createEntry(
userId: string,
entryData: JournalEntryCreate,
token: string
) {
return apiCall<{ id: string; message: string }>(
`/entries/${userId}`,
{
method: 'POST',
body: entryData,
token,
}
)
}
export async function getUserEntries(
userId: string,
token: string,
limit = 50,
skip = 0
) {
return apiCall<{ entries: JournalEntry[]; total: number }>(
`/entries/${userId}?limit=${limit}&skip=${skip}`,
{ token }
)
}
export async function getEntry(
userId: string,
entryId: string,
token: string
) {
return apiCall<JournalEntry>(`/entries/${userId}/${entryId}`, {
token,
})
}
export async function updateEntry(
userId: string,
entryId: string,
updates: Partial<JournalEntryCreate>,
token: string
) {
return apiCall(`/entries/${userId}/${entryId}`, {
method: 'PUT',
body: updates,
token,
})
}
export async function deleteEntry(
userId: string,
entryId: string,
token: string
) {
return apiCall(`/entries/${userId}/${entryId}`, {
method: 'DELETE',
token,
})
}
export async function getEntriesByDate(
userId: string,
startDate: string,
endDate: string,
token: string
) {
return apiCall<JournalEntry[]>(
`/entries/${userId}/date-range?startDate=${startDate}&endDate=${endDate}`,
{ token }
)
}
// ============================================
// TIMEZONE CONVERSION ENDPOINTS
// ============================================
export async function convertUTCToIST(utcTimestamp: string) {
return apiCall<{ utc: string; ist: string }>(
`/entries/convert-timestamp/utc-to-ist`,
{
method: 'POST',
body: { timestamp: utcTimestamp },
}
)
}