This commit is contained in:
2026-08-11 23:17:04 +07:00
parent bc37ab90f6
commit d7e0d81462
49 changed files with 9023 additions and 91 deletions
+38
View File
@@ -0,0 +1,38 @@
import axios, { type AxiosInstance } from 'axios'
export const api: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:2000',
headers: {
'Content-Type': 'application/json',
},
})
api.interceptors.request.use((config) => {
const token = localStorage.getItem('mws_token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
api.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
localStorage.removeItem('mws_token')
localStorage.removeItem('mws_user')
if (!window.location.pathname.startsWith('/login')) {
window.location.href = '/login'
}
}
return Promise.reject(error)
},
)
export function errorMessage(error: unknown): string {
if (axios.isAxiosError(error)) {
const data = error.response?.data as { message?: string } | undefined
return data?.message ?? error.message ?? 'Request failed'
}
return 'Request failed'
}
+127
View File
@@ -0,0 +1,127 @@
import { api } from './api'
import type { LoginResponse, Project, ProjectMember, MemberRole, Account, MenuItem, Role, SaveRoleRequest } from '../types'
export async function login(username: string, password: string): Promise<LoginResponse> {
const { data } = await api.post<LoginResponse>('/api/auth/login', { username, password })
return data
}
export async function getMenu(): Promise<MenuItem[]> {
const { data } = await api.get<MenuItem[]>('/api/menu')
return data
}
export async function getRoles(): Promise<Role[]> {
const { data } = await api.get<Role[]>('/api/roles')
return data
}
export async function getRole(id: string): Promise<Role> {
const { data } = await api.get<Role>(`/api/roles/${id}`)
return data
}
export async function createRole(payload: SaveRoleRequest): Promise<Role> {
const { data } = await api.post<Role>('/api/roles', payload)
return data
}
export async function updateRole(id: string, payload: SaveRoleRequest): Promise<Role> {
const { data } = await api.put<Role>(`/api/roles/${id}`, payload)
return data
}
export async function deleteRole(id: string): Promise<void> {
await api.delete(`/api/roles/${id}`)
}
export async function getProjects(): Promise<Project[]> {
const { data } = await api.get<Project[]>('/api/projects')
return data
}
export async function searchProjects(q: string): Promise<Project[]> {
const { data } = await api.get<Project[]>('/api/projects/search', { params: { q } })
return data
}
export async function getProject(id: string): Promise<Project> {
const { data } = await api.get<Project>(`/api/projects/${id}`)
return data
}
export async function getProjectOverview(id: string) {
const { data } = await api.get(`/api/projects/${id}/overview`)
return data
}
export async function createProject(name: string, description?: string): Promise<Project> {
const { data } = await api.post<Project>('/api/projects', { name, description })
return data
}
export async function updateProject(
id: string,
payload: { name: string; description: string | null; status: string },
): Promise<Project> {
const { data } = await api.put<Project>(`/api/projects/${id}`, payload)
return data
}
export async function deleteProject(id: string): Promise<void> {
await api.delete(`/api/projects/${id}`)
}
export async function getMembers(projectId: string): Promise<ProjectMember[]> {
const { data } = await api.get<ProjectMember[]>(`/api/projects/${projectId}/members`)
return data
}
export async function addMember(
projectId: string,
userId: string,
role: MemberRole,
): Promise<ProjectMember> {
const { data } = await api.post<ProjectMember>(`/api/projects/${projectId}/members`, { userId, role })
return data
}
export async function removeMember(projectId: string, userId: string): Promise<void> {
await api.delete(`/api/projects/${projectId}/members/${userId}`)
}
export async function getUsers(q?: string) {
const { data } = await api.get('/api/users', { params: { q } })
return data
}
export async function getAccounts(q?: string): Promise<Account[]> {
const { data } = await api.get<Account[]>('/api/accounts', { params: { q } })
return data
}
export async function createAccount(payload: {
username: string
displayName: string
password: string
roleId: string
}): Promise<Account> {
const { data } = await api.post<Account>('/api/accounts', payload)
return data
}
export async function updateAccount(
id: string,
payload: { displayName: string; roleId: string; isActive: boolean },
): Promise<Account> {
const { data } = await api.put<Account>(`/api/accounts/${id}`, payload)
return data
}
export async function deleteAccount(id: string): Promise<void> {
await api.delete(`/api/accounts/${id}`)
}
export async function resetAccountPassword(id: string, newPassword: string): Promise<void> {
await api.post(`/api/accounts/${id}/reset-password`, { newPassword })
}
+94
View File
@@ -0,0 +1,94 @@
import { api } from './api'
import type { DocumentItem, DocumentNode, DocumentType, Task, TaskPriority, TaskStatus } from '../types'
export async function getDocumentTree(projectId: string): Promise<DocumentNode[]> {
const { data } = await api.get<DocumentNode[]>(`/api/projects/${projectId}/documents`)
return data
}
export async function getDocument(id: string): Promise<DocumentItem> {
const { data } = await api.get<DocumentItem>(`/api/documents/${id}`)
return data
}
export async function createDocument(
projectId: string,
payload: { title: string; type: DocumentType; parentId: string | null; content?: string | null },
): Promise<DocumentItem> {
const { data } = await api.post<DocumentItem>(`/api/projects/${projectId}/documents`, payload)
return data
}
export async function updateDocument(
id: string,
payload: { title: string; content?: string | null },
): Promise<DocumentItem> {
const { data } = await api.put<DocumentItem>(`/api/documents/${id}`, payload)
return data
}
export async function moveDocument(id: string, newParentId: string | null): Promise<DocumentItem> {
const { data } = await api.put<DocumentItem>(`/api/documents/${id}/move`, { newParentId })
return data
}
export async function deleteDocument(id: string): Promise<void> {
await api.delete(`/api/documents/${id}`)
}
export async function searchDocuments(q: string): Promise<DocumentNode[]> {
const { data } = await api.get<DocumentNode[]>('/api/documents/search', { params: { q } })
return data
}
export async function getTasks(
projectId: string,
filters?: { status?: string; priority?: string; assigneeId?: string },
): Promise<Task[]> {
const { data } = await api.get<Task[]>(`/api/projects/${projectId}/tasks`, { params: filters })
return data
}
export async function getTask(id: string): Promise<Task> {
const { data } = await api.get<Task>(`/api/tasks/${id}`)
return data
}
export async function createTask(
projectId: string,
payload: {
title: string
description?: string | null
status?: TaskStatus
priority?: TaskPriority
assigneeId?: string | null
dueDate?: string | null
},
): Promise<Task> {
const { data } = await api.post<Task>(`/api/projects/${projectId}/tasks`, payload)
return data
}
export async function updateTask(
id: string,
payload: {
title: string
description: string | null
status: TaskStatus
priority: TaskPriority
assigneeId: string | null
dueDate: string | null
},
): Promise<Task> {
const { data } = await api.put<Task>(`/api/tasks/${id}`, payload)
return data
}
export async function deleteTask(id: string): Promise<void> {
await api.delete(`/api/tasks/${id}`)
}
export async function searchTasks(q: string): Promise<Task[]> {
const { data } = await api.get<Task[]>('/api/tasks/search', { params: { q } })
return data
}