391 lines
12 KiB
TypeScript

import axios from 'axios';
import type { LoginRequest, RegisterRequest, AuthResponse, User, Language, TranslationGroup } from '../types';
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000';
// Helper function to get full API URL for resources like images
export const getApiUrl = (path: string) => {
return `${API_URL}${path.startsWith('/') ? path : '/' + path}`;
};
const api = axios.create({
baseURL: API_URL,
headers: {
'Content-Type': 'application/json',
},
});
// Add auth token to requests
api.interceptors.request.use((config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// Handle 401 responses (token expired/invalid)
api.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
// Token is invalid or expired, logout user
localStorage.removeItem('token');
localStorage.removeItem('lastVisitedPath');
sessionStorage.removeItem('routeRestored');
// Dispatch event to notify AuthContext
window.dispatchEvent(new CustomEvent('sessionExpired'));
}
return Promise.reject(error);
}
);
export const authAPI = {
login: async (data: LoginRequest): Promise<AuthResponse> => {
const response = await api.post('/auth/login', data);
return response.data;
},
register: async (data: RegisterRequest): Promise<User> => {
const response = await api.post('/auth/register', data);
return response.data;
},
getCurrentUser: async (): Promise<User> => {
const response = await api.get('/auth/me');
return response.data;
},
updateProfile: async (data: { email?: string; full_name?: string; password?: string; theme?: string }): Promise<User> => {
const response = await api.put('/auth/me', data);
return response.data;
},
uploadProfilePicture: async (file: File): Promise<User> => {
const formData = new FormData();
formData.append('file', file);
const response = await api.post('/auth/me/profile-picture', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return response.data;
},
};
export const departmentsAPI = {
getAll: async () => {
const response = await api.get('/departments/');
return response.data;
},
getMy: async () => {
const response = await api.get('/departments/my');
return response.data;
},
create: async (data: { name: string; description?: string }) => {
const response = await api.post('/departments/', data);
return response.data;
},
};
export const channelsAPI = {
getMy: async () => {
const response = await api.get('/channels/');
return response.data;
},
getByDepartment: async (departmentId: number) => {
const response = await api.get(`/channels/department/${departmentId}`);
return response.data;
},
create: async (data: { name: string; description?: string; department_id: number }) => {
const response = await api.post('/channels/', data);
return response.data;
},
delete: async (channelId: number) => {
const response = await api.delete(`/channels/${channelId}`);
return response.data;
},
};
export const messagesAPI = {
getChannelMessages: async (channelId: number, limit = 50, offset = 0) => {
const response = await api.get(`/messages/channel/${channelId}`, {
params: { limit, offset },
});
return response.data;
},
create: async (data: { content: string; channel_id: number; snippet_id?: number | null; reply_to_id?: number | null }) => {
const response = await api.post('/messages/', data);
return response.data;
},
delete: async (messageId: number) => {
const response = await api.delete(`/messages/${messageId}`);
return response.data;
},
};
export const filesAPI = {
upload: async (messageId: number, file: File, permission: string = 'read') => {
const formData = new FormData();
formData.append('file', file);
formData.append('permission', permission);
const response = await api.post(`/files/upload/${messageId}`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return response.data;
},
uploadWithMessage: async (channelId: number, file: File, permission: string = 'read', content: string = '', replyToId?: number) => {
const formData = new FormData();
formData.append('file', file);
formData.append('permission', permission);
formData.append('content', content);
if (replyToId) {
formData.append('reply_to_id', replyToId.toString());
}
const response = await api.post(`/files/upload-with-message/${channelId}`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return response.data;
},
download: async (fileId: number) => {
const response = await api.get(`/files/download/${fileId}`, {
responseType: 'blob',
});
return response.data;
},
getOfficeUri: async (fileId: number) => {
const response = await api.get(`/files/office-uri/${fileId}`);
return response.data;
},
updatePermission: async (fileId: number, permission: string) => {
const formData = new FormData();
formData.append('permission', permission);
const response = await api.put(`/files/${fileId}/permission`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return response.data;
},
};
export const snippetsAPI = {
getAll: async (params?: {
language?: string;
tags?: string;
search?: string;
visibility?: string;
}) => {
const response = await api.get('/snippets/', { params });
return response.data;
},
getById: async (id: number) => {
const response = await api.get(`/snippets/${id}`);
return response.data;
},
create: async (data: any) => {
const response = await api.post('/snippets/', data);
return response.data;
},
update: async (id: number, data: any) => {
const response = await api.put(`/snippets/${id}`, data);
return response.data;
},
delete: async (id: number) => {
const response = await api.delete(`/snippets/${id}`);
return response.data;
},
};
export const adminLanguagesAPI = {
getAll: async (): Promise<Language[]> => {
const response = await api.get('/admin/languages');
return response.data;
},
create: async (data: { code: string; name: string }): Promise<Language> => {
const response = await api.post('/admin/languages', data);
return response.data;
},
delete: async (id: number) => {
const response = await api.delete(`/admin/languages/${id}`);
return response.data;
},
};
export const adminTranslationsAPI = {
getAll: async (): Promise<TranslationGroup[]> => {
const response = await api.get('/admin/translations');
return response.data;
},
update: async (data: { translation_id: number; value: string }) => {
const response = await api.put('/admin/translations', data);
return response.data;
},
};
export const directMessagesAPI = {
getConversation: async (userId: number, limit: number = 50, offset: number = 0) => {
const response = await api.get(`/direct-messages/conversation/${userId}`, {
params: { limit, offset }
});
return response.data;
},
getConversations: async () => {
const response = await api.get('/direct-messages/conversations');
return response.data;
},
create: async (data: { content: string; receiver_id: number; snippet_id?: number }) => {
const response = await api.post('/direct-messages/', data);
return response.data;
},
};
export const kanbanAPI = {
// Board operations
createBoard: async (data: { channel_id: number; name?: string }) => {
const response = await api.post('/kanban/boards', data);
return response.data;
},
getBoardByChannel: async (channelId: number) => {
const response = await api.get(`/kanban/boards/${channelId}`);
return response.data;
},
updateBoard: async (boardId: number, data: { name?: string }) => {
const response = await api.put(`/kanban/boards/${boardId}`, data);
return response.data;
},
// Column operations
createColumn: async (data: { board_id: number; name: string; position: number; color?: string }) => {
const response = await api.post('/kanban/columns', data);
return response.data;
},
updateColumn: async (columnId: number, data: { name?: string; position?: number; color?: string }) => {
const response = await api.put(`/kanban/columns/${columnId}`, data);
return response.data;
},
deleteColumn: async (columnId: number) => {
const response = await api.delete(`/kanban/columns/${columnId}`);
return response.data;
},
// Card operations
createCard: async (data: {
column_id: number;
title: string;
description?: string;
assignee_id?: number;
position: number;
due_date?: string;
priority?: 'low' | 'medium' | 'high';
labels?: string;
}) => {
const response = await api.post('/kanban/cards', data);
return response.data;
},
updateCard: async (cardId: number, data: {
title?: string;
description?: string;
assignee_id?: number;
position?: number;
due_date?: string;
priority?: 'low' | 'medium' | 'high';
labels?: string;
}) => {
const response = await api.put(`/kanban/cards/${cardId}`, data);
return response.data;
},
deleteCard: async (cardId: number) => {
const response = await api.delete(`/kanban/cards/${cardId}`);
return response.data;
},
moveCard: async (cardId: number, targetColumnId: number, newPosition: number) => {
const response = await api.put(`/kanban/cards/${cardId}/move`, null, {
params: { target_column_id: targetColumnId, new_position: newPosition }
});
return response.data;
},
// Checklist API
createChecklist: async (data: { card_id: number; title: string; position: number }) => {
const response = await api.post('/kanban/checklists', data);
return response.data;
},
getCardChecklists: async (cardId: number) => {
const response = await api.get(`/kanban/cards/${cardId}/checklists`);
return response.data;
},
getChecklist: async (checklistId: number) => {
const response = await api.get(`/kanban/checklists/${checklistId}`);
return response.data;
},
updateChecklist: async (checklistId: number, data: { title?: string; position?: number }) => {
const response = await api.put(`/kanban/checklists/${checklistId}`, data);
return response.data;
},
deleteChecklist: async (checklistId: number) => {
const response = await api.delete(`/kanban/checklists/${checklistId}`);
return response.data;
},
// Checklist Item API
createChecklistItem: async (data: { checklist_id: number; title: string; is_completed?: boolean; position: number }) => {
const response = await api.post('/kanban/checklist-items', data);
return response.data;
},
updateChecklistItem: async (itemId: number, data: { title?: string; is_completed?: boolean; position?: number }) => {
const response = await api.put(`/kanban/checklist-items/${itemId}`, data);
return response.data;
},
deleteChecklistItem: async (itemId: number) => {
const response = await api.delete(`/kanban/checklist-items/${itemId}`);
return response.data;
},
};
export const userStatusAPI = {
getUserStatuses: async (): Promise<Array<{user_id: number, username: string, full_name: string, status: string}>> => {
const response = await api.get('/user-status');
return response.data;
},
};
export default api;