Files
etf-oglasi/frontend/services/api.tsx
T
2026-06-03 19:13:56 +02:00

158 lines
3.9 KiB
TypeScript

const BASE_URL = process.env.EXPO_PUBLIC_API_URL; // TODO change this
export type NotificationType = 'PUSH_NOTIFICATION' | 'NO_NOTIFICATION';
function authHeader(token?: string) {
return token ? { Authorization: `Bearer ${token}` } : {};
}
async function request<T>(
method: string,
path: string,
token?: string,
body?: object,
params?: Record<string, any>,
): Promise<T> {
const url = new URL(`${BASE_URL}${path}`);
if (params) {
Object.entries(params).forEach(([k, v]) => {
if (v !== undefined && v !== null) url.searchParams.set(k, String(v));
});
}
const res = await fetch(url.toString(), {
method,
// @ts-ignore
headers: { "Content-Type": "application/json", ...authHeader(token) },
...(body ? { body: JSON.stringify(body) } : {}),
});
if (!res.ok) {
const errorText = await res.text().catch(() => `HTTP ${res.status}`);
console.log('Failed URL:', res.url);
console.log('Status:', res.status);
console.log('Response:', errorText);
throw new Error(errorText);
}
return res.json();
}
export function get<T>(path: string, token?: string, params?: Record<string, any>) {
return request<T>("GET", path, token, undefined, params);
}
export function post<T>(path: string, body: object, token?: string) {
return request<T>("POST", path, token, body);
}
export function put<T>(
path: string,
body?: object,
token?: string
) {
return request<T>("PUT", path, token, body);
}
export function del<T>(path: string, token?: string) {
return request<T>("DELETE", path, token);
}
export type Subject = {
id: string;
name: string;
};
export type JwtResponse = {
token: string;
email: string;
userId: string;
message: string;
};
export type UserDTO = {
id: string;
email: string;
subjectSet: Subject[];
notificationType: NotificationType;
};
export type UserUpdateDTO = {
email: string;
newEmail?: string;
password?: string;
subjectSet: { id: string }[]; // pass existing subscriptions so they aren't wiped
};
export type Entry = {
id: string;
title: string;
timePublished: string;
groupName: string;
infoEntry: string;
paragraph: string;
filepath?: string;
subject: Subject;
};
export type SpringPage<T> = {
content: T[];
totalPages: number;
last: boolean;
number: number;
};
export type LoginPayload = { email: string; password: string };
export type RegisterPayload = { email: string; password: string; name?: string };
export const authApi = {
login: (p: LoginPayload) => post<JwtResponse>("/login", p),
register: (p: RegisterPayload) => post<UserDTO>("/register", p),
getUser: (token: string) =>
get<UserDTO>("/users/me", token),
updateUser: (body: UserUpdateDTO, token: string) =>
request<UserDTO>("PUT", "/users/me", token, body),
deleteUser: (token: string) =>
del<void>("/users/me", token),
};
export const userApi = {
updateNotificationType: (
type: 'PUSH_NOTIFICATION' | 'NO_NOTIFICATION',
token: string
) => post<void>('/users/me/notification-type', { notificationType: type }, token),
};
export const subjectsApi = {
getAll: (token?: string) => get<Subject[]>("/subjects", token),
};
export const subscriptionsApi = {
subscribe: (subjectId: string, token: string) =>
put<UserDTO>(
`/users/me/subjects/${subjectId}`,
{},
token
),
unsubscribe: (subjectId: string, token: string) =>
del<UserDTO>(
`/users/me/subjects/${subjectId}`,
token
),
};
export const entriesApi = {
getEntries: (params: { subjectId?: string; groupName?: string; page?: number }) =>
get<SpringPage<Entry>>("/entries", undefined, params),
getEntry: (id: string) => get<Entry>(`/entries/${id}`),
};