Initial commit: IT Nexus Web-App

This commit is contained in:
2026-06-01 20:49:07 +02:00
commit 8023765e6c
387 changed files with 106900 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
import api from './api';
const aiService = {
getStatus: async () => {
const response = await api.get('/ai/status');
return response.data.data;
},
chat: async (messages, userMode = false) => {
const response = await api.post('/ai/chat', { messages, userMode });
return response.data.data.reply;
},
getKnowledgeBase: async () => {
const response = await api.get('/ai/knowledge-base');
return response.data.data;
},
addKnowledgeEntry: async (data) => {
const response = await api.post('/ai/knowledge-base', data);
return response.data.data;
},
importTextToKb: async (text) => {
const response = await api.post('/ai/knowledge-base/import-text', { text });
return response.data.data;
},
importUrlToKb: async (url) => {
const response = await api.post('/ai/knowledge-base/import-url', { url });
return response.data.data;
},
importCrawlToKb: async (url, maxPages) => {
const response = await api.post('/ai/knowledge-base/import-crawl', { url, maxPages }, { timeout: 300000 });
return response.data.data;
},
importFileToKb: async (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = async () => {
try {
const response = await api.post('/ai/knowledge-base/import-text', {
file: reader.result,
filename: file.name,
});
resolve(response.data.data);
} catch (err) { reject(err); }
};
reader.onerror = reject;
reader.readAsDataURL(file);
});
},
uploadKbImage: async (id, file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = async () => {
try {
const response = await api.post(`/ai/knowledge-base/${id}/images`, {
image: reader.result,
filename: file.name,
});
resolve(response.data.data);
} catch (err) { reject(err); }
};
reader.onerror = reject;
reader.readAsDataURL(file);
});
},
deleteKbImage: async (id, filename) => {
const response = await api.delete(`/ai/knowledge-base/${id}/images/${encodeURIComponent(filename)}`);
return response.data;
},
updateKnowledgeEntry: async (id, data) => {
const response = await api.put(`/ai/knowledge-base/${id}`, data);
return response.data.data;
},
deleteKnowledgeEntry: async (id) => {
const response = await api.delete(`/ai/knowledge-base/${id}`);
return response.data;
},
};
export default aiService;

View File

@@ -0,0 +1,62 @@
import axios from 'axios';
const API_URL = process.env.REACT_APP_API_URL || '/api';
// Create axios instance
const api = axios.create({
baseURL: API_URL,
headers: {
'Content-Type': 'application/json',
},
});
// Request interceptor to add token to requests
api.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
if (token) {
if (typeof config.headers?.set === 'function') {
config.headers.set('Authorization', `Bearer ${token}`);
} else if (config.headers) {
config.headers['Authorization'] = `Bearer ${token}`;
} else {
config.headers = { 'Authorization': `Bearer ${token}` };
}
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// Response interceptor to handle errors globally
api.interceptors.response.use(
(response) => {
return response;
},
(error) => {
if (error.response) {
// Handle 401 Unauthorized - token expired or invalid
if (error.response.status === 401) {
localStorage.removeItem('token');
localStorage.removeItem('user');
window.location.href = '/login';
}
// Return the error response for handling in components
return Promise.reject(error.response.data);
} else if (error.request) {
// Network error
return Promise.reject({
status: 'error',
message: 'Network error. Please check your connection.',
});
} else {
// Re-throw original error
return Promise.reject(error);
}
}
);
export default api;

View File

@@ -0,0 +1,173 @@
import api from './api';
const assetService = {
/**
* Get all assets
*/
getAll: async () => {
const response = await api.get('/assets');
return response.data.data;
},
/**
* Get asset by ID
*/
getById: async (id) => {
const response = await api.get(`/assets/${id}`);
return response.data.data;
},
/**
* Get asset by serial number
*/
getBySerial: async (serialNumber) => {
const response = await api.get(`/assets/serial/${serialNumber}`);
return response.data.data;
},
/**
* Get assets by status
*/
getByStatus: async (status) => {
const response = await api.get(`/assets/status/${status}`);
return response.data.data;
},
/**
* Get assets by type
*/
getByType: async (type) => {
const response = await api.get(`/assets/type/${type}`);
return response.data.data;
},
/**
* Create new asset
*/
create: async (assetData) => {
const response = await api.post('/assets', assetData);
return response.data.data;
},
/**
* Update asset
*/
update: async (id, assetData) => {
const response = await api.put(`/assets/${id}`, assetData);
return response.data.data;
},
/**
* Delete asset
*/
delete: async (id) => {
const response = await api.delete(`/assets/${id}`);
return response.data;
},
/**
* Assign asset to user
*/
assign: async (id, userId, notes) => {
const response = await api.post(`/assets/${id}/assign`, {
user_id: userId,
notes: notes
});
return response.data.data;
},
/**
* Unassign asset from user
*/
unassign: async (id, newStatus) => {
const response = await api.post(`/assets/${id}/unassign`, {
new_status: newStatus
});
return response.data.data;
},
/**
* Get assignment history for an asset
*/
getAssignmentHistory: async (id) => {
const response = await api.get(`/assets/${id}/history`);
return response.data.data;
},
/**
* Get statistics
*/
getStatistics: async () => {
const response = await api.get('/assets/stats');
return response.data.data;
},
/**
* Open printable label PDF in new tab
*/
printLabel: async (id, copies = 1, size = 'medium') => {
const response = await api.get(`/assets/${id}/label`, {
params: { copies, size },
responseType: 'blob',
});
const blob = new Blob([response.data], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
window.open(url, '_blank');
setTimeout(() => URL.revokeObjectURL(url), 60000);
},
/**
* Import managed devices from Microsoft Intune
* Returns { imported, skipped, errors }
*/
importFromIntune: async () => {
const response = await api.post('/assets/import/intune');
return response.data.data;
},
/**
* Get all inspections for an asset
*/
getInspections: (assetId) => api.get(`/assets/${assetId}/inspections`).then(r => r.data.data),
/**
* Create an inspection for an asset
*/
createInspection: (assetId, data) => api.post(`/assets/${assetId}/inspections`, data).then(r => r.data.data),
/**
* Open handover protocol PDF in new tab
*/
printHandoverProtocol: async (id) => {
const response = await api.get(`/assets/${id}/handover-protocol`, {
responseType: 'blob',
});
const blob = new Blob([response.data], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
window.open(url, '_blank');
setTimeout(() => URL.revokeObjectURL(url), 60000);
},
// Asset Types
getTypes: async () => {
const response = await api.get('/asset-types');
return response.data;
},
createType: async (data) => {
const response = await api.post('/asset-types', data);
return response.data;
},
updateType: async (id, data) => {
const response = await api.put(`/asset-types/${id}`, data);
return response.data;
},
deleteType: async (id) => {
await api.delete(`/asset-types/${id}`);
},
syncFromAgent: async (id) => {
const response = await api.post(`/assets/${id}/sync-agent`);
return response.data;
},
};
export default assetService;

View File

@@ -0,0 +1,88 @@
import api from './api';
const authService = {
/**
* Login user
*/
login: async (username, password) => {
const response = await api.post('/auth/login', { username, password });
if (response.data.data.token) {
localStorage.setItem('token', response.data.data.token);
localStorage.setItem('user', JSON.stringify(response.data.data.user));
}
return response.data.data;
},
/**
* Logout user
*/
logout: async () => {
try {
await api.post('/auth/logout');
} catch (error) {
// Ignore errors on logout
} finally {
localStorage.removeItem('token');
localStorage.removeItem('user');
}
},
/**
* Get current user info
*/
getCurrentUser: async () => {
const response = await api.get('/auth/me');
return response.data.data;
},
/**
* Change password
*/
changePassword: async (currentPassword, newPassword) => {
const response = await api.post('/auth/change-password', {
currentPassword,
newPassword,
});
return response.data.data;
},
/**
* Get user from localStorage
*/
getStoredUser: () => {
const user = localStorage.getItem('user');
return user ? JSON.parse(user) : null;
},
/**
* Get token from localStorage
*/
getToken: () => {
return localStorage.getItem('token');
},
/**
* Check if user is authenticated
*/
isAuthenticated: () => {
return !!localStorage.getItem('token');
},
/**
* Fetch user data using a token (for kiosk URL-token login)
*/
fetchUserFromToken: async (token) => {
try {
const response = await fetch('/api/auth/me', {
headers: { Authorization: `Bearer ${token}` },
});
if (!response.ok) return null;
const data = await response.json();
return data.data || data.user || data;
} catch {
return null;
}
},
};
export default authService;

View File

@@ -0,0 +1,15 @@
import api from './api';
const BASE = '/entra';
const entraService = {
getUsers: async () => { const r = await api.get(`${BASE}/users`); return r.data.data; },
getUserGroups: async (userId) => { const r = await api.get(`${BASE}/users/${userId}/groups`); return r.data.data; },
getGroups: async () => { const r = await api.get(`${BASE}/groups`); return r.data.data; },
getGroupMembers: async (groupId) => { const r = await api.get(`${BASE}/groups/${groupId}/members`); return r.data.data; },
addGroupMember: async (groupId, userId) => { const r = await api.post(`${BASE}/groups/${groupId}/members`, { userId }); return r.data; },
removeGroupMember: async (groupId, userId) => { const r = await api.delete(`${BASE}/groups/${groupId}/members/${userId}`); return r.data; },
getRoles: async () => { const r = await api.get(`${BASE}/roles`); return r.data.data; },
};
export default entraService;

View File

@@ -0,0 +1,12 @@
import api from './api';
const base = '/external-alerts';
const externalAlertService = {
getAll: (params) => api.get(base, { params }).then(r => r.data.data),
acknowledge: (id) => api.post(`${base}/${id}/acknowledge`).then(r => r.data.data),
createTicket: (id) => api.post(`${base}/${id}/create-ticket`).then(r => r.data.data),
remove: (id) => api.delete(`${base}/${id}`).then(r => r.data),
};
export default externalAlertService;

View File

@@ -0,0 +1,77 @@
import api from './api';
const fidoKeyService = {
/**
* Get all FIDO keys
*/
getAll: async () => {
const response = await api.get('/fido-keys');
return response.data.data;
},
/**
* Get FIDO key by ID
*/
getById: async (id) => {
const response = await api.get(`/fido-keys/${id}`);
return response.data.data;
},
/**
* Get FIDO key by serial number
*/
getBySerial: async (serialNumber) => {
const response = await api.get(`/fido-keys/serial/${serialNumber}`);
return response.data.data;
},
/**
* Get FIDO keys by status
*/
getByStatus: async (status) => {
const response = await api.get(`/fido-keys/status/${status}`);
return response.data.data;
},
/**
* Create new FIDO key
*/
create: async (keyData) => {
const response = await api.post('/fido-keys', keyData);
return response.data.data;
},
/**
* Update FIDO key
*/
update: async (id, keyData) => {
const response = await api.put(`/fido-keys/${id}`, keyData);
return response.data.data;
},
/**
* Update FIDO key status
*/
updateStatus: async (id, status) => {
const response = await api.put(`/fido-keys/${id}/status`, { status });
return response.data.data;
},
/**
* Delete FIDO key
*/
delete: async (id) => {
const response = await api.delete(`/fido-keys/${id}`);
return response.data;
},
/**
* Get statistics
*/
getStatistics: async () => {
const response = await api.get('/fido-keys/stats');
return response.data.data;
},
};
export default fidoKeyService;

View File

@@ -0,0 +1,23 @@
import api from './api';
const BASE = '/iso-tasks';
const isoService = {
getAll: async (params = {}) => {
const res = await api.get(BASE, { params });
return res.data.data;
},
create: async (data) => {
const res = await api.post(BASE, data);
return res.data.data;
},
update: async (id, data) => {
const res = await api.put(`${BASE}/${id}`, data);
return res.data.data;
},
delete: async (id) => {
await api.delete(`${BASE}/${id}`);
},
};
export default isoService;

View File

@@ -0,0 +1,31 @@
import api from './api';
const BASE = '/it-topics';
const itTopicService = {
getAll: async (params = {}) => {
const res = await api.get(BASE, { params });
return res.data.data;
},
getOne: async (id) => {
const res = await api.get(`${BASE}/${id}`);
return res.data.data;
},
create: async (data) => {
const res = await api.post(BASE, data);
return res.data.data;
},
update: async (id, data) => {
const res = await api.put(`${BASE}/${id}`, data);
return res.data.data;
},
delete: async (id) => {
await api.delete(`${BASE}/${id}`);
},
syncToPlanner: async () => {
const res = await api.post(`${BASE}/planner/sync`);
return res.data.data;
},
};
export default itTopicService;

View File

@@ -0,0 +1,45 @@
import api from './api';
const licenseService = {
getAll: async () => {
const response = await api.get('/licenses');
return response.data.data;
},
getById: async (id) => {
const response = await api.get(`/licenses/${id}`);
return response.data.data;
},
create: async (data) => {
const response = await api.post('/licenses', data);
return response.data.data;
},
update: async (id, data) => {
const response = await api.put(`/licenses/${id}`, data);
return response.data.data;
},
delete: async (id) => {
const response = await api.delete(`/licenses/${id}`);
return response.data;
},
getStatistics: async () => {
const response = await api.get('/licenses/statistics');
return response.data.data;
},
importFromEntra: async () => {
const response = await api.post('/licenses/import/entra');
return response.data.data;
},
getLicenseUsers: async (id) => {
const response = await api.get(`/licenses/${id}/users`);
return response.data.data;
},
};
export default licenseService;

View File

@@ -0,0 +1,10 @@
import api from './api';
const monitoringService = {
getAll: () => api.get('/monitoring').then(r => r.data.data),
getStatistics: () => api.get('/monitoring/statistics').then(r => r.data.data),
getById: (id) => api.get(`/monitoring/${id}`).then(r => r.data.data),
delete: (id) => api.delete(`/monitoring/${id}`).then(r => r.data),
};
export default monitoringService;

View File

@@ -0,0 +1,24 @@
import api from './api';
const base = '/network-monitor';
const networkMonitorService = {
getAll: () => api.get(base).then(r => r.data.data),
getStats: () => api.get(`${base}/statistics`).then(r => r.data.data),
getChecks: (id, h) => api.get(`${base}/${id}/checks?hours=${h}`).then(r => r.data.data),
create: (data) => api.post(base, data).then(r => r.data.data),
update: (id, d) => api.put(`${base}/${id}`, d).then(r => r.data.data),
delete: (id) => api.delete(`${base}/${id}`),
checkNow: (id) => api.post(`${base}/${id}/check-now`).then(r => r.data.data),
discover: (subnet) => api.post(`${base}/discover`, { subnet }, { timeout: 120000 }).then(r => r.data),
getUptimeStats: () => api.get(`${base}/uptime-stats`).then(r => r.data.data),
createSSE: () => {
const token = localStorage.getItem('token');
const apiBase = process.env.REACT_APP_API_URL || '/api';
return new EventSource(`${apiBase}/network-monitor/sse?token=${token}`);
},
};
export default networkMonitorService;

View File

@@ -0,0 +1,78 @@
import api from './api';
const offboardingService = {
/**
* Get all offboarding protocols
*/
getAll: async () => {
const response = await api.get('/offboarding');
return response.data.data;
},
/**
* Get offboarding protocol by ID
*/
getById: async (id) => {
const response = await api.get(`/offboarding/${id}`);
return response.data.data;
},
/**
* Create new offboarding protocol
*/
create: async (protocolData) => {
const response = await api.post('/offboarding', protocolData);
return response.data.data;
},
/**
* Update offboarding protocol
*/
update: async (id, protocolData) => {
const response = await api.put(`/offboarding/${id}`, protocolData);
return response.data.data;
},
/**
* Return assets for offboarding
*/
returnAssets: async (id, assetReturns) => {
const response = await api.post(`/offboarding/${id}/return-assets`, {
asset_returns: assetReturns
});
return response.data.data;
},
/**
* Regenerate PDF for offboarding protocol
*/
regeneratePdf: async (id) => {
const response = await api.post(`/offboarding/${id}/regenerate-pdf`);
return response.data.data;
},
/**
* Delete offboarding protocol
*/
delete: async (id) => {
const response = await api.delete(`/offboarding/${id}`);
return response.data;
},
/**
* Get statistics
*/
getStatistics: async () => {
const response = await api.get('/offboarding/stats');
return response.data.data;
},
/**
* Download PDF
*/
downloadPdf: (pdfPath) => {
return `/${pdfPath}`;
},
};
export default offboardingService;

View File

@@ -0,0 +1,54 @@
import api from './api';
const BASE = '/onboarding-processes';
const onboardingProcessService = {
// Departments
getDepartments: async () => {
const res = await api.get(`${BASE}/departments`);
return res.data.data;
},
createDepartment: async (data) => {
const res = await api.post(`${BASE}/departments`, data);
return res.data.data;
},
updateDepartment: async (id, data) => {
const res = await api.put(`${BASE}/departments/${id}`, data);
return res.data.data;
},
deleteDepartment: async (id) => {
await api.delete(`${BASE}/departments/${id}`);
},
reorderDepartments: async (ids) => {
await api.put(`${BASE}/departments/reorder`, { ids });
},
// Processes
getProcesses: async (params = {}) => {
const res = await api.get(`${BASE}/processes`, { params });
return res.data.data;
},
getChecklistProcesses: async (appliesTo, departmentId) => {
// appliesTo: 'onboarding' or 'offboarding'; departmentId: optional filter
const params = { applies_to: appliesTo };
if (departmentId) params.department_id = departmentId;
const res = await api.get(`${BASE}/processes`, { params });
return res.data.data;
},
createProcess: async (data) => {
const res = await api.post(`${BASE}/processes`, data);
return res.data.data;
},
updateProcess: async (id, data) => {
const res = await api.put(`${BASE}/processes/${id}`, data);
return res.data.data;
},
deleteProcess: async (id) => {
await api.delete(`${BASE}/processes/${id}`);
},
reorderProcesses: async (department_id, ids) => {
await api.put(`${BASE}/processes/reorder`, { department_id, ids });
},
};
export default onboardingProcessService;

View File

@@ -0,0 +1,76 @@
import api from './api';
const onboardingService = {
/**
* Get all onboarding protocols
*/
getAll: async () => {
const response = await api.get('/onboarding');
return response.data.data;
},
/**
* Get onboarding protocol by ID
*/
getById: async (id) => {
const response = await api.get(`/onboarding/${id}`);
return response.data.data;
},
/**
* Create new onboarding protocol
*/
create: async (protocolData) => {
const response = await api.post('/onboarding', protocolData);
return response.data.data;
},
/**
* Update onboarding protocol
*/
update: async (id, protocolData) => {
const response = await api.put(`/onboarding/${id}`, protocolData);
return response.data.data;
},
/**
* Regenerate PDF for onboarding protocol
*/
regeneratePdf: async (id) => {
const response = await api.post(`/onboarding/${id}/regenerate-pdf`);
return response.data.data;
},
/**
* Send confirmation email with PDF to employee
*/
sendConfirmationEmail: async (id) => {
const response = await api.post(`/onboarding/${id}/send-confirmation`);
return response.data;
},
/**
* Delete onboarding protocol
*/
delete: async (id) => {
const response = await api.delete(`/onboarding/${id}`);
return response.data;
},
/**
* Get statistics
*/
getStatistics: async () => {
const response = await api.get('/onboarding/stats');
return response.data.data;
},
/**
* Download PDF
*/
downloadPdf: (pdfPath) => {
return `/${pdfPath}`;
},
};
export default onboardingService;

View File

@@ -0,0 +1,26 @@
import api from './api';
const portalGuideService = {
getAll: async () => {
const res = await api.get('/portal-guides');
return res.data;
},
getById: async (id) => {
const res = await api.get(`/portal-guides/${id}`);
return res.data;
},
getHtmlUrl: (id) => `/api/portal-guides/${id}/html`,
create: async (data) => {
const res = await api.post('/portal-guides', data);
return res.data;
},
update: async (id, data) => {
const res = await api.put(`/portal-guides/${id}`, data);
return res.data;
},
delete: async (id) => {
await api.delete(`/portal-guides/${id}`);
},
};
export default portalGuideService;

View File

@@ -0,0 +1,14 @@
import api from './api';
const BASE = '/risks';
const riskService = {
getAll: async (params = {}) => { const r = await api.get(BASE, { params }); return r.data.data; },
getStats: async () => { const r = await api.get(`${BASE}/stats`); return r.data.data; },
sync: async () => { const r = await api.post(`${BASE}/sync`); return r.data.data; },
create: async (data) => { const r = await api.post(BASE, data); return r.data.data; },
update: async (id, data) => { const r = await api.put(`${BASE}/${id}`, data); return r.data.data; },
delete: async (id) => { await api.delete(`${BASE}/${id}`); },
};
export default riskService;

View File

@@ -0,0 +1,10 @@
import api from './api';
const scannerService = {
getSites: () => api.get('/scanner/sites').then(r => r.data.data),
getAssets: (params) => api.get('/scanner/assets', { params }).then(r => r.data.data),
getAlerts: (params) => api.get('/scanner/alerts', { params }).then(r => r.data.data),
getStats: () => api.get('/scanner/stats').then(r => r.data.data),
};
export default scannerService;

View File

@@ -0,0 +1,60 @@
const API = process.env.REACT_APP_API_URL || '/api';
const getHeaders = () => ({
Authorization: `Bearer ${localStorage.getItem('token')}`,
});
export const createShare = async (formData) => {
const res = await fetch(`${API}/shares`, {
method: 'POST',
headers: { Authorization: `Bearer ${localStorage.getItem('token')}` },
body: formData, // FormData — kein Content-Type Header setzen!
});
if (!res.ok) {
const err = await res.json();
throw new Error(err.error || 'Fehler beim Erstellen');
}
return res.json();
};
export const getAllShares = async () => {
const res = await fetch(`${API}/shares`, { headers: getHeaders() });
if (!res.ok) throw new Error('Fehler beim Laden');
return res.json();
};
export const deleteShare = async (id) => {
const res = await fetch(`${API}/shares/${id}`, {
method: 'DELETE',
headers: getHeaders(),
});
if (!res.ok) throw new Error('Fehler beim Löschen');
return res.json();
};
export const getPublicShare = async (token) => {
const res = await fetch(`${API}/shares/public/${token}`);
if (!res.ok) {
const err = await res.json();
throw new Error(err.error || 'Nicht gefunden');
}
return res.json();
};
export const accessShare = async (token, password) => {
const res = await fetch(`${API}/shares/public/${token}/access`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ password }),
});
if (!res.ok) {
const err = await res.json();
throw new Error(err.error || 'Zugriff verweigert');
}
return res.json();
};
export const getFileDownloadUrl = (token, password) => {
const base = `${API}/shares/public/${token}/file`;
return password ? `${base}?password=${encodeURIComponent(password)}` : base;
};

View File

@@ -0,0 +1,8 @@
import api from './api';
const teamsActivityService = {
getNewChannels: () => api.get('/teams-activity/new-channels').then(r => r.data.data),
markRead: () => api.post('/teams-activity/mark-read'),
};
export default teamsActivityService;

View File

@@ -0,0 +1,106 @@
import api from './api';
const ticketService = {
getAll: async (filters = {}) => {
const params = {};
if (filters.status) params.status = filters.status;
if (filters.priority) params.priority = filters.priority;
if (filters.category) params.category = filters.category;
if (filters.assigned_to) params.assigned_to = filters.assigned_to;
if (filters.search) params.search = filters.search;
const response = await api.get('/tickets', { params });
return response.data.data;
},
getById: async (id) => {
const response = await api.get(`/tickets/${id}`);
return response.data.data;
},
getStats: async () => {
const response = await api.get('/tickets/stats');
return response.data.data;
},
getMetrics: async (days = 30) => {
const response = await api.get('/tickets/metrics', { params: { days } });
return response.data.data;
},
create: async (data) => {
const response = await api.post('/tickets', data);
return response.data.data;
},
update: async (id, data) => {
const response = await api.put(`/tickets/${id}`, data);
return response.data.data;
},
bulkUpdate: async (ids, data) => {
const response = await api.put('/tickets/bulk', { ids, data });
return response.data;
},
delete: async (id) => {
const response = await api.delete(`/tickets/${id}`);
return response.data;
},
addComment: async (id, comment, isInternal = false) => {
const response = await api.post(`/tickets/${id}/comments`, {
comment,
is_internal: isInternal,
});
return response.data.data;
},
aiReply: async (id, message, history = []) => {
const response = await api.post(`/tickets/${id}/ai-reply`, { message, history });
return response.data.data;
},
deleteComment: async (ticketId, commentId) => {
const response = await api.delete(`/tickets/${ticketId}/comments/${commentId}`);
return response.data;
},
getHistory: async (id) => {
const response = await api.get(`/tickets/${id}/history`);
return response.data.data;
},
getPdfUrl: (id) => `/api/tickets/${id}/pdf`,
getLinks: async (id) => {
const response = await api.get(`/tickets/${id}/links`);
return response.data.data;
},
addLink: async (id, linked_ticket_number, link_type = 'related') => {
const response = await api.post(`/tickets/${id}/links`, { linked_ticket_number, link_type });
return response.data.data;
},
removeLink: async (ticketId, linkId) => {
const response = await api.delete(`/tickets/${ticketId}/links/${linkId}`);
return response.data;
},
snooze: async (id, snoozed_until) => {
const response = await api.put(`/tickets/${id}/snooze`, { snoozed_until });
return response.data.data;
},
addAssignee: async (ticketId, userId) => {
const response = await api.post(`/tickets/${ticketId}/assignees`, { user_id: userId });
return response.data.data;
},
removeAssignee: async (ticketId, userId) => {
const response = await api.delete(`/tickets/${ticketId}/assignees/${userId}`);
return response.data.data;
},
};
export default ticketService;

View File

@@ -0,0 +1,9 @@
import api from './api';
const base = '/unifi';
const unifiService = {
getConfig: () => api.get(`${base}/config`).then(r => r.data.data),
saveConfig: (cfg) => api.post(`${base}/config`, cfg).then(r => r.data.data),
getDevices: () => api.get(`${base}/devices`).then(r => r.data.data),
sync: () => api.post(`${base}/sync`).then(r => r.data.data),
};
export default unifiService;

View File

@@ -0,0 +1,94 @@
import api from './api';
const userService = {
/**
* Get all users
*/
getAll: async () => {
const response = await api.get('/users');
return response.data.data;
},
/**
* Get user by ID
*/
getById: async (id) => {
const response = await api.get(`/users/${id}`);
return response.data.data;
},
/**
* Create new user
*/
create: async (userData) => {
const response = await api.post('/users', userData);
return response.data.data;
},
/**
* Update user
*/
update: async (id, userData) => {
const response = await api.put(`/users/${id}`, userData);
return response.data.data;
},
/**
* Delete user
*/
delete: async (id) => {
const response = await api.delete(`/users/${id}`);
return response.data;
},
/**
* Assign role to user
*/
assignRole: async (id, roleId) => {
const response = await api.put(`/users/${id}/role`, { role_id: roleId });
return response.data.data;
},
/**
* Activate/Deactivate user
*/
toggleStatus: async (id, isActive) => {
const response = await api.put(`/users/${id}/activate`, { is_active: isActive });
return response.data.data;
},
/**
* Get all roles
*/
getRoles: async () => {
const response = await api.get('/users/roles');
return response.data.data;
},
/**
* Get available Azure AD groups for import
*/
getAzureGroups: async () => {
const response = await api.get('/users/import/azure/groups');
return response.data.data;
},
/**
* Import users from an Azure AD group
* Returns { imported, skipped, errors }
*/
importFromAzure: async (groupId, roleId) => {
const response = await api.post('/users/import/azure', { group_id: groupId, role_id: roleId });
return response.data.data;
},
/**
* Get audit logs
*/
getAuditLogs: async (limit = 100, offset = 0) => {
const response = await api.get(`/users/audit-logs?limit=${limit}&offset=${offset}`);
return response.data.data;
},
};
export default userService;

View File

@@ -0,0 +1,35 @@
import api from './api';
const base = '/warehouse';
const warehouseService = {
// Summary
getSummary: () => api.get(`${base}/summary`).then(r => r.data),
getViolations: () => api.get(`${base}/violations`).then(r => r.data),
// Locations
getLocations: () => api.get(`${base}/locations`).then(r => r.data),
createLocation: (data) => api.post(`${base}/locations`, data).then(r => r.data),
updateLocation: (id, d) => api.put(`${base}/locations/${id}`, d).then(r => r.data),
deleteLocation: (id) => api.delete(`${base}/locations/${id}`).then(r => r.data),
// Movements
getMovements: (params) => api.get(`${base}/movements`, { params }).then(r => r.data),
createMovement: (data) => api.post(`${base}/movements`, data).then(r => r.data),
// Stock thresholds
getThresholds: () => api.get(`${base}/thresholds`).then(r => r.data),
upsertThreshold: (data) => api.post(`${base}/thresholds`, data).then(r => r.data),
deleteThreshold: (cat) => api.delete(`${base}/thresholds/${encodeURIComponent(cat)}`).then(r => r.data),
// Purchase orders
getOrders: (params) => api.get(`${base}/orders`, { params }).then(r => r.data),
createOrder: (data) => api.post(`${base}/orders`, data).then(r => r.data),
updateOrder: (id, d) => api.put(`${base}/orders/${id}`, d).then(r => r.data),
deleteOrder: (id) => api.delete(`${base}/orders/${id}`).then(r => r.data),
// QR Code URL
getQrUrl: (assetId) => `${api.defaults.baseURL}${base}/qr/${assetId}`,
};
export default warehouseService;