- Bug 1: No fix needed - frontend already uses PUT for document updates - Bug 2: Changed folders API to use 'project' param (matches documents) - Bug 3: GET /folders now works without project filter (lists all folders) Changes: - folders.js: Accept 'project' instead of 'projectId', make it optional - folderService.js: Support listing all folders when projectId is null - api.js: Updated getFolders() to use 'project' param consistently
210 lines
4.5 KiB
JavaScript
210 lines
4.5 KiB
JavaScript
// API Client for SimpleNote Web
|
|
|
|
const API_BASE = '/api/v1';
|
|
|
|
class ApiClient {
|
|
constructor() {
|
|
this.token = localStorage.getItem('sn_token');
|
|
}
|
|
|
|
setToken(token) {
|
|
this.token = token;
|
|
if (token) {
|
|
localStorage.setItem('sn_token', token);
|
|
} else {
|
|
localStorage.removeItem('sn_token');
|
|
}
|
|
}
|
|
|
|
getHeaders() {
|
|
const headers = {
|
|
'Content-Type': 'application/json'
|
|
};
|
|
if (this.token) {
|
|
headers['Authorization'] = `Bearer ${this.token}`;
|
|
}
|
|
return headers;
|
|
}
|
|
|
|
async request(method, path, body = null) {
|
|
const options = {
|
|
method,
|
|
headers: this.getHeaders()
|
|
};
|
|
if (body) {
|
|
options.body = JSON.stringify(body);
|
|
}
|
|
|
|
const response = await fetch(`${API_BASE}${path}`, options);
|
|
|
|
if (!response.ok) {
|
|
const error = await response.json().catch(() => ({ message: 'Request failed' }));
|
|
throw new Error(error.message || `HTTP ${response.status}`);
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
get(path) { return this.request('GET', path); }
|
|
post(path, body) { return this.request('POST', path, body); }
|
|
put(path, body) { return this.request('PUT', path, body); }
|
|
delete(path) { return this.request('DELETE', path); }
|
|
|
|
// ===== Auth =====
|
|
async login(token) {
|
|
try {
|
|
this.setToken(token); // Set token BEFORE making request
|
|
const data = await this.get('/auth/verify');
|
|
return data;
|
|
} catch (e) {
|
|
this.setToken(null);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
// ===== Documents =====
|
|
getDocuments(params = {}) {
|
|
const query = new URLSearchParams(params).toString();
|
|
return this.get(`/documents${query ? '?' + query : ''}`);
|
|
}
|
|
|
|
getDocument(id) {
|
|
return this.get(`/documents/${id}`);
|
|
}
|
|
|
|
createDocument(data) {
|
|
return this.post('/documents', data);
|
|
}
|
|
|
|
updateDocument(id, data) {
|
|
return this.put(`/documents/${id}`, data);
|
|
}
|
|
|
|
deleteDocument(id) {
|
|
return this.delete(`/documents/${id}`);
|
|
}
|
|
|
|
exportDocument(id) {
|
|
return fetch(`${API_BASE}/documents/${id}/export`, {
|
|
headers: this.getHeaders()
|
|
}).then(r => r.text());
|
|
}
|
|
|
|
addDocumentTags(documentId, tags) {
|
|
return this.post(`/documents/${documentId}/tags`, { tags });
|
|
}
|
|
|
|
moveDocumentToFolder(documentId, folderId) {
|
|
return this.put(`/documents/${documentId}`, { folderId });
|
|
}
|
|
|
|
// ===== Tags =====
|
|
getTags() {
|
|
return this.get('/tags');
|
|
}
|
|
|
|
// GET /tags/:tag - get documents by tag
|
|
getDocumentsByTag(tag) {
|
|
return this.get(`/tags/${encodeURIComponent(tag)}`);
|
|
}
|
|
|
|
// ===== Libraries =====
|
|
getLibraries() {
|
|
return this.get('/libraries');
|
|
}
|
|
|
|
getLibrary(id) {
|
|
return this.get(`/libraries/${id}`);
|
|
}
|
|
|
|
createLibrary(data) {
|
|
return this.post('/libraries', data);
|
|
}
|
|
|
|
updateLibrary(id, data) {
|
|
return this.put(`/libraries/${id}`, data);
|
|
}
|
|
|
|
deleteLibrary(id) {
|
|
return this.delete(`/libraries/${id}`);
|
|
}
|
|
|
|
// GET /libraries/:id/tree
|
|
getLibraryTree(id) {
|
|
return this.get(`/libraries/${id}/tree`);
|
|
}
|
|
|
|
// GET /libraries/:id/documents
|
|
getLibraryDocuments(id) {
|
|
return this.get(`/libraries/${id}/documents`);
|
|
}
|
|
|
|
// ===== Projects =====
|
|
getProjects() {
|
|
return this.get('/projects');
|
|
}
|
|
|
|
getProject(id) {
|
|
return this.get(`/projects/${id}`);
|
|
}
|
|
|
|
createProject(data) {
|
|
return this.post('/projects', data);
|
|
}
|
|
|
|
updateProject(id, data) {
|
|
return this.put(`/projects/${id}`, data);
|
|
}
|
|
|
|
deleteProject(id) {
|
|
return this.delete(`/projects/${id}`);
|
|
}
|
|
|
|
// GET /projects/:id/tree
|
|
getProjectTree(id) {
|
|
return this.get(`/projects/${id}/tree`);
|
|
}
|
|
|
|
// GET /projects/:id/documents
|
|
getProjectDocuments(id) {
|
|
return this.get(`/projects/${id}/documents`);
|
|
}
|
|
|
|
// ===== Folders =====
|
|
getFolders(project = null, parentId = null) {
|
|
const params = new URLSearchParams();
|
|
if (project) params.append('project', project);
|
|
if (parentId) params.append('parentId', parentId);
|
|
const query = params.toString();
|
|
return this.get(`/folders${query ? '?' + query : ''}`);
|
|
}
|
|
|
|
getFolder(id) {
|
|
return this.get(`/folders/${id}`);
|
|
}
|
|
|
|
createFolder(data) {
|
|
return this.post('/folders', data);
|
|
}
|
|
|
|
updateFolder(id, data) {
|
|
return this.put(`/folders/${id}`, data);
|
|
}
|
|
|
|
deleteFolder(id) {
|
|
return this.delete(`/folders/${id}`);
|
|
}
|
|
|
|
// GET /folders/:id/documents
|
|
getFolderDocuments(id) {
|
|
return this.get(`/folders/${id}/documents`);
|
|
}
|
|
|
|
// GET /folders/:id/tree
|
|
getFolderTree(id) {
|
|
return this.get(`/folders/${id}/tree`);
|
|
}
|
|
}
|
|
|
|
export const api = new ApiClient();
|