This commit is contained in:
seb
2026-10-10 00:39:23 +02:00
parent 2c36a705c4
commit ff54fe3a18
30 changed files with 2250 additions and 2256 deletions

118
src/api/category.js Normal file
View File

@@ -0,0 +1,118 @@
import { http, httpBinary, httpGetBinary } from './http.js';
export const category = {
/** GET /api/category/tree → { languageId, tree, articles } (company from session) */
getTree() {
return http('/api/category/tree');
},
/**
* GET /api/category/:id/articles → { articles: [...] }
* Article rows: sku, name, net, taxRate, fullHash, thumbW, thumbH, thumbHash, childCount, …
*/
getArticles(categoryId) {
return http(`/api/category/${categoryId}/articles`);
},
/** POST /api/category → 201 { category } */
create({ parentId, name }) {
return http('/api/category', {
method: 'POST',
body: { parentId: Number(parentId), name },
});
},
/**
* DELETE /api/category/:id → 204
* Query: ?recursive=true (cascades deletion of subcategories and articles)
*/
delete(categoryId, { recursive = false } = {}) {
const qs = recursive ? '?recursive=true' : '';
return http(`/api/category/${categoryId}${qs}`, { method: 'DELETE' });
},
/**
* PATCH /api/category/:id
* Body: { name } — renames and re-slugifies in the company default language.
* Empty name → 400 name is required.
* → 200 { category: { id, name, slug } }
*/
updateName(categoryId, name) {
return http(`/api/category/${categoryId}`, {
method: 'PATCH',
body: { name },
});
},
/**
* PUT /api/category/order
* Body: { parentId, categoryIds: number[] } — sibling order of the children
* under `parentId` (top-down). categoryIds must be exactly the current child
* set of parentId (same count, no foreign/duplicate ids) → 400 Invalid category order.
* → 200 { categoryIds: number[] }
*/
reorder(parentId, categoryIds) {
return http('/api/category/order', {
method: 'PUT',
body: { parentId, categoryIds },
});
},
/**
* PATCH /api/category/:id
* Body: { parentId } — moves the category under a new parent.
* → 200 { category: { id, parentId, sort } } (kein name/slug im Response)
*/
move(categoryId, parentId) {
return http(`/api/category/${categoryId}`, {
method: 'PATCH',
body: { parentId },
});
},
/**
* PATCH /api/category/:id
* Body: { pos: boolean } — toggles the POS (Point of Sale) flag.
* → 200 { category: { id, pos } }
*
* PROPOSED — backend needs to implement this field.
*/
updatePos(categoryId, pos) {
return http(`/api/category/${categoryId}`, {
method: 'PATCH',
body: { pos },
});
},
/**
* POST /api/category/:id/image
* Body: raw image bytes (Content-Type: image/webp)
* → 201 { category: { id, fullHash, thumbW, thumbH, thumbHash } }
*/
uploadImage(categoryId, file) {
return httpBinary(`/api/category/${categoryId}/image`, {
method: 'POST',
contentType: file?.type || 'image/webp',
body: file,
});
},
/**
* DELETE /api/category/:id/image
* → 200 { category: { id, thumbW: null, thumbH: null, thumbHash: null } }
*/
deleteImage(categoryId) {
return http(`/api/category/${categoryId}/image`, { method: 'DELETE' });
},
/**
* GET /api/category/export.zip → application/zip (binary download)
* `kategorien.zip` = kategorien.csv (semicolon-separated, Windows-1252,
* depth-first, `Ebene N` name column per depth) + one `<fullHash>.avif`
* entry per category image (content-addressed, deduplicated).
* Errors: 400 No company selected, 401, 403, 404 (JSON { error }).
*/
exportZip() {
return httpGetBinary('/api/category/export.zip');
},
};