- ConnectWise Manage Integration: - ConnectWiseModule with service, controller, entity - API endpoints for connection CRUD and sync - Syncs service tickets, project tickets, zero-ticket projects - Stores ConnectWise priority/SLA in task metadata - Intelligent Calendar Scheduling: - CalendarModule with connection and event entities - Support for CalDAV, Microsoft Graph, Google Calendar providers - CalendarService with sync methods for all providers - SchedulingModule with automatic scheduling engine - Finds available slots respecting working hours - Groups tasks by context, respects priority and due dates - Interactive Calendar Week View: - FullCalendar with timeGridWeek view - Drag-and-drop task rescheduling - Tasks auto-lock when manually moved - Color-coded by context - Regenerate Schedule button Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
139 lines
4.0 KiB
TypeScript
139 lines
4.0 KiB
TypeScript
import axios from 'axios';
|
|
import { useAuthStore } from '../store/auth';
|
|
|
|
const api = axios.create({
|
|
baseURL: '/api/v1',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
api.interceptors.request.use((config) => {
|
|
const token = useAuthStore.getState().token;
|
|
if (token) {
|
|
config.headers.Authorization = `Bearer ${token}`;
|
|
}
|
|
return config;
|
|
});
|
|
|
|
api.interceptors.response.use(
|
|
(response) => response,
|
|
(error) => {
|
|
if (error.response?.status === 401) {
|
|
useAuthStore.getState().logout();
|
|
window.location.href = '/login';
|
|
}
|
|
return Promise.reject(error);
|
|
},
|
|
);
|
|
|
|
export { api };
|
|
|
|
// Auth API
|
|
export const authApi = {
|
|
register: (data: { email: string; password: string; name: string; timezone: string }) =>
|
|
api.post('/auth/register', data),
|
|
login: (data: { email: string; password: string }) => api.post('/auth/login', data),
|
|
logout: () => api.post('/auth/logout'),
|
|
};
|
|
|
|
// Inbox API
|
|
export const inboxApi = {
|
|
getAll: () => api.get('/inbox'),
|
|
create: (content: string) => api.post('/inbox', { content }),
|
|
process: (
|
|
id: string,
|
|
data: {
|
|
action: string;
|
|
title?: string;
|
|
context?: string;
|
|
domain?: string;
|
|
priority?: number;
|
|
},
|
|
) => api.post(`/inbox/${id}/process`, data),
|
|
delete: (id: string) => api.delete(`/inbox/${id}`),
|
|
};
|
|
|
|
// Tasks API
|
|
export const tasksApi = {
|
|
getAll: (params?: { status?: string; context?: string; domain?: string }) =>
|
|
api.get('/tasks', { params }),
|
|
getOne: (id: string) => api.get(`/tasks/${id}`),
|
|
create: (data: {
|
|
title: string;
|
|
domain: string;
|
|
context?: string;
|
|
priority?: number;
|
|
estimatedDuration?: number;
|
|
dueDate?: string;
|
|
projectId?: string;
|
|
notes?: string;
|
|
status?: string;
|
|
}) => api.post('/tasks', data),
|
|
update: (id: string, data: Record<string, unknown>) => api.patch(`/tasks/${id}`, data),
|
|
delete: (id: string) => api.delete(`/tasks/${id}`),
|
|
lock: (id: string) => api.post(`/tasks/${id}/lock`),
|
|
unlock: (id: string) => api.post(`/tasks/${id}/unlock`),
|
|
};
|
|
|
|
// Projects API
|
|
export const projectsApi = {
|
|
getAll: (params?: { status?: string; domain?: string }) => api.get('/projects', { params }),
|
|
getOne: (id: string) => api.get(`/projects/${id}`),
|
|
getTasks: (id: string) => api.get(`/projects/${id}/tasks`),
|
|
create: (data: {
|
|
name: string;
|
|
domain: string;
|
|
description?: string;
|
|
desiredOutcome?: string;
|
|
}) => api.post('/projects', data),
|
|
update: (id: string, data: Record<string, unknown>) => api.patch(`/projects/${id}`, data),
|
|
delete: (id: string) => api.delete(`/projects/${id}`),
|
|
};
|
|
|
|
// User API
|
|
export const userApi = {
|
|
getMe: () => api.get('/users/me'),
|
|
getPreferences: () => api.get('/users/preferences'),
|
|
updatePreferences: (data: Record<string, unknown>) => api.patch('/users/preferences', data),
|
|
};
|
|
|
|
// Calendar API
|
|
export const calendarApi = {
|
|
getConnections: () => api.get('/connections/calendar'),
|
|
createConnection: (data: {
|
|
provider: string;
|
|
calendarUrl?: string;
|
|
credentials?: {
|
|
username?: string;
|
|
password?: string;
|
|
accessToken?: string;
|
|
refreshToken?: string;
|
|
};
|
|
}) => api.post('/connections/calendar', data),
|
|
deleteConnection: (id: string) => api.delete(`/connections/calendar/${id}`),
|
|
syncConnection: (id: string) => api.post(`/connections/calendar/${id}/sync`),
|
|
getEvents: (start: string, end: string) =>
|
|
api.get('/calendar/events', { params: { start, end } }),
|
|
};
|
|
|
|
// Schedule API
|
|
export const scheduleApi = {
|
|
regenerate: () => api.post('/schedule/regenerate'),
|
|
clear: () => api.delete('/schedule/clear'),
|
|
};
|
|
|
|
// ConnectWise API
|
|
export const connectWiseApi = {
|
|
getConnections: () => api.get('/connections/connectwise'),
|
|
createConnection: (data: {
|
|
companyId: string;
|
|
publicKey: string;
|
|
privateKey: string;
|
|
apiUrl: string;
|
|
memberId: string;
|
|
}) => api.post('/connections/connectwise', data),
|
|
deleteConnection: (id: string) => api.delete(`/connections/connectwise/${id}`),
|
|
syncConnection: (id: string) => api.post(`/connections/connectwise/${id}/sync`),
|
|
};
|