Mobile Dev
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { API_BASE_URL } from '@/src/config/env';
|
||||
import { getApiBaseUrlSync } from '@/src/lib/server-config';
|
||||
|
||||
export type Tenant = {
|
||||
id: number;
|
||||
@@ -17,6 +17,9 @@ export type Task = {
|
||||
userId?: string | null;
|
||||
user_id?: string | null;
|
||||
profile?: string | null;
|
||||
project?: number | { id?: number; name?: string } | null;
|
||||
customer?: number | { id?: number; name?: string } | null;
|
||||
plant?: number | { id?: number; name?: string } | null;
|
||||
archived?: boolean;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
@@ -42,6 +45,73 @@ export type StaffTimeSpan = {
|
||||
description: string;
|
||||
};
|
||||
|
||||
export type Project = {
|
||||
id: number;
|
||||
name: string;
|
||||
notes?: string | null;
|
||||
projectNumber?: string | null;
|
||||
archived?: boolean;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
export type ProjectFile = {
|
||||
id: string;
|
||||
name?: string | null;
|
||||
path?: string | null;
|
||||
project?: number | { id?: number; name?: string };
|
||||
customer?: number | { id?: number; name?: string };
|
||||
plant?: number | { id?: number; name?: string };
|
||||
createddocument?: number | { id?: number; documentNumber?: string };
|
||||
mimeType?: string | null;
|
||||
url?: string;
|
||||
archived?: boolean;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
export type Customer = {
|
||||
id: number;
|
||||
name: string;
|
||||
customerNumber?: string | null;
|
||||
notes?: string | null;
|
||||
archived?: boolean;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
export type Plant = {
|
||||
id: number;
|
||||
name: string;
|
||||
description?: string | null;
|
||||
customer?: number | { id?: number; name?: string };
|
||||
archived?: boolean;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
export type CustomerInventoryItem = {
|
||||
id: number;
|
||||
name: string;
|
||||
customer?: number | { id?: number; name?: string } | null;
|
||||
customerInventoryId?: string | null;
|
||||
serialNumber?: string | null;
|
||||
description?: string | null;
|
||||
manufacturer?: string | null;
|
||||
manufacturerNumber?: string | null;
|
||||
quantity?: number | null;
|
||||
archived?: boolean;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
export type CreatedDocument = {
|
||||
id: number;
|
||||
documentNumber?: string | null;
|
||||
title?: string | null;
|
||||
type?: string | null;
|
||||
state?: string | null;
|
||||
documentDate?: string | null;
|
||||
customer?: number | { id?: number; name?: string };
|
||||
archived?: boolean;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
export type MeResponse = {
|
||||
user: {
|
||||
id: string;
|
||||
@@ -55,6 +125,52 @@ export type MeResponse = {
|
||||
permissions: string[];
|
||||
};
|
||||
|
||||
export type EncodedLabelRow = {
|
||||
dataType: 'pixels' | 'void' | 'check';
|
||||
rowNumber: number;
|
||||
repeat: number;
|
||||
rowData?: Uint8Array | number[] | Record<string, number>;
|
||||
blackPixelsCount: number;
|
||||
};
|
||||
|
||||
export type EncodedLabelImage = {
|
||||
cols: number;
|
||||
rows: number;
|
||||
rowsData: EncodedLabelRow[];
|
||||
};
|
||||
|
||||
export type PrintLabelResponse = {
|
||||
encoded: EncodedLabelImage;
|
||||
base64?: string;
|
||||
};
|
||||
|
||||
export type WikiTreeItem = {
|
||||
id: string;
|
||||
parentId?: string | null;
|
||||
title: string;
|
||||
isFolder?: boolean;
|
||||
isVirtual?: boolean;
|
||||
sortOrder?: number;
|
||||
entityType?: string | null;
|
||||
entityId?: number | null;
|
||||
entityUuid?: string | null;
|
||||
updatedAt?: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
export type WikiPage = {
|
||||
id: string;
|
||||
title: string;
|
||||
content?: unknown;
|
||||
parentId?: string | null;
|
||||
isFolder?: boolean;
|
||||
entityType?: string | null;
|
||||
entityId?: number | null;
|
||||
entityUuid?: string | null;
|
||||
updatedAt?: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
type RequestOptions = {
|
||||
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
||||
token?: string | null;
|
||||
@@ -67,7 +183,7 @@ function buildUrl(path: string): string {
|
||||
}
|
||||
|
||||
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
||||
return `${API_BASE_URL}${normalizedPath}`;
|
||||
return `${getApiBaseUrlSync()}${normalizedPath}`;
|
||||
}
|
||||
|
||||
async function parseJson(response: Response): Promise<unknown> {
|
||||
@@ -109,6 +225,23 @@ export async function checkBackendHealth(): Promise<{ status: string; [key: stri
|
||||
return apiRequest<{ status: string; [key: string]: unknown }>('/health');
|
||||
}
|
||||
|
||||
export async function renderPrintLabel(
|
||||
token: string,
|
||||
context: Record<string, unknown>,
|
||||
width = 584,
|
||||
height = 354
|
||||
): Promise<PrintLabelResponse> {
|
||||
return apiRequest<PrintLabelResponse>('/api/print/label', {
|
||||
method: 'POST',
|
||||
token,
|
||||
body: {
|
||||
context,
|
||||
width,
|
||||
height,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function loginWithEmailPassword(email: string, password: string): Promise<string> {
|
||||
const payload = await apiRequest<{ token?: string }>('/auth/login', {
|
||||
method: 'POST',
|
||||
@@ -154,6 +287,9 @@ export async function createTask(
|
||||
description?: string | null;
|
||||
categorie?: TaskStatus;
|
||||
userId?: string | null;
|
||||
project?: number | null;
|
||||
customer?: number | null;
|
||||
plant?: number | null;
|
||||
}
|
||||
): Promise<Task> {
|
||||
return apiRequest<Task>('/api/resource/tasks', {
|
||||
@@ -258,3 +394,523 @@ export async function rejectStaffTime(
|
||||
body: { eventIds, employeeUserId, reason },
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchProjects(token: string, includeArchived = false): Promise<Project[]> {
|
||||
const projects = await apiRequest<Project[]>('/api/resource/projects', { token });
|
||||
if (includeArchived) return projects || [];
|
||||
return (projects || []).filter((project) => !project.archived);
|
||||
}
|
||||
|
||||
export async function createProject(
|
||||
token: string,
|
||||
payload: {
|
||||
name: string;
|
||||
projectNumber?: string | null;
|
||||
customer?: number | null;
|
||||
plant?: number | null;
|
||||
notes?: string | null;
|
||||
}
|
||||
): Promise<Project> {
|
||||
return apiRequest<Project>('/api/resource/projects', {
|
||||
method: 'POST',
|
||||
token,
|
||||
body: payload,
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchCustomers(token: string, includeArchived = false): Promise<Customer[]> {
|
||||
const customers = await apiRequest<Customer[]>('/api/resource/customers', { token });
|
||||
if (includeArchived) return customers || [];
|
||||
return (customers || []).filter((customer) => !customer.archived);
|
||||
}
|
||||
|
||||
export async function createCustomer(
|
||||
token: string,
|
||||
payload: {
|
||||
name: string;
|
||||
customerNumber?: string | null;
|
||||
notes?: string | null;
|
||||
}
|
||||
): Promise<Customer> {
|
||||
return apiRequest<Customer>('/api/resource/customers', {
|
||||
method: 'POST',
|
||||
token,
|
||||
body: payload,
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchCustomerById(token: string, customerId: number): Promise<Customer> {
|
||||
return apiRequest<Customer>(`/api/resource/customers/${customerId}`, { token });
|
||||
}
|
||||
|
||||
function resolveCustomerIdFromCustomerInventoryItem(item: CustomerInventoryItem): number | null {
|
||||
const rawCustomer = item.customer;
|
||||
if (!rawCustomer) return null;
|
||||
if (typeof rawCustomer === 'object') {
|
||||
return rawCustomer.id ? Number(rawCustomer.id) : null;
|
||||
}
|
||||
return Number(rawCustomer);
|
||||
}
|
||||
|
||||
export async function fetchCustomerInventoryItems(
|
||||
token: string,
|
||||
customerId: number,
|
||||
includeArchived = false
|
||||
): Promise<CustomerInventoryItem[]> {
|
||||
const rows = await apiRequest<CustomerInventoryItem[]>('/api/resource/customerinventoryitems', { token });
|
||||
|
||||
return (rows || []).filter((item) => {
|
||||
if (!includeArchived && item.archived) return false;
|
||||
return resolveCustomerIdFromCustomerInventoryItem(item) === Number(customerId);
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchAllCustomerInventoryItems(
|
||||
token: string,
|
||||
includeArchived = false
|
||||
): Promise<CustomerInventoryItem[]> {
|
||||
const rows = await apiRequest<CustomerInventoryItem[]>('/api/resource/customerinventoryitems', { token });
|
||||
if (includeArchived) return rows || [];
|
||||
return (rows || []).filter((item) => !item.archived);
|
||||
}
|
||||
|
||||
export async function createCustomerInventoryItem(
|
||||
token: string,
|
||||
payload: {
|
||||
customer: number;
|
||||
name: string;
|
||||
customerInventoryId?: string | null;
|
||||
serialNumber?: string | null;
|
||||
description?: string | null;
|
||||
quantity?: number | null;
|
||||
}
|
||||
): Promise<CustomerInventoryItem> {
|
||||
const autoInventoryId = `MOB-${Date.now()}`;
|
||||
|
||||
return apiRequest<CustomerInventoryItem>('/api/resource/customerinventoryitems', {
|
||||
method: 'POST',
|
||||
token,
|
||||
body: {
|
||||
customer: payload.customer,
|
||||
name: payload.name,
|
||||
customerInventoryId: payload.customerInventoryId?.trim() || autoInventoryId,
|
||||
serialNumber: payload.serialNumber?.trim() || null,
|
||||
description: payload.description?.trim() || null,
|
||||
quantity: Number.isFinite(Number(payload.quantity)) ? Number(payload.quantity) : 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchPlants(token: string, includeArchived = false): Promise<Plant[]> {
|
||||
const plants = await apiRequest<Plant[]>('/api/resource/plants', { token });
|
||||
if (includeArchived) return plants || [];
|
||||
return (plants || []).filter((plant) => !plant.archived);
|
||||
}
|
||||
|
||||
export async function createPlant(
|
||||
token: string,
|
||||
payload: {
|
||||
name: string;
|
||||
description?: string | null;
|
||||
customer?: number | null;
|
||||
}
|
||||
): Promise<Plant> {
|
||||
return apiRequest<Plant>('/api/resource/plants', {
|
||||
method: 'POST',
|
||||
token,
|
||||
body: payload,
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchPlantById(token: string, plantId: number): Promise<Plant> {
|
||||
return apiRequest<Plant>(`/api/resource/plants/${plantId}`, { token });
|
||||
}
|
||||
|
||||
function toQueryString(params: Record<string, unknown>): string {
|
||||
const searchParams = new URLSearchParams();
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
if (value === undefined || value === null || value === '') return;
|
||||
searchParams.append(key, String(value));
|
||||
});
|
||||
const query = searchParams.toString();
|
||||
return query ? `?${query}` : '';
|
||||
}
|
||||
|
||||
export async function fetchWikiTree(
|
||||
token: string,
|
||||
filters: {
|
||||
entityType?: string;
|
||||
entityId?: number | null;
|
||||
entityUuid?: string | null;
|
||||
} = {}
|
||||
): Promise<WikiTreeItem[]> {
|
||||
const query = toQueryString({
|
||||
entityType: filters.entityType,
|
||||
entityId: filters.entityId,
|
||||
entityUuid: filters.entityUuid,
|
||||
});
|
||||
return apiRequest<WikiTreeItem[]>(`/api/wiki/tree${query}`, { token });
|
||||
}
|
||||
|
||||
export async function fetchWikiPageById(token: string, pageId: string): Promise<WikiPage> {
|
||||
return apiRequest<WikiPage>(`/api/wiki/${encodeURIComponent(pageId)}`, { token });
|
||||
}
|
||||
|
||||
export async function createWikiPage(
|
||||
token: string,
|
||||
payload: {
|
||||
title: string;
|
||||
parentId?: string | null;
|
||||
isFolder?: boolean;
|
||||
entityType?: string;
|
||||
entityId?: number | null;
|
||||
entityUuid?: string | null;
|
||||
}
|
||||
): Promise<WikiPage> {
|
||||
return apiRequest<WikiPage>('/api/wiki', {
|
||||
method: 'POST',
|
||||
token,
|
||||
body: payload,
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateWikiPage(
|
||||
token: string,
|
||||
pageId: string,
|
||||
payload: {
|
||||
title?: string;
|
||||
content?: unknown;
|
||||
parentId?: string | null;
|
||||
sortOrder?: number;
|
||||
isFolder?: boolean;
|
||||
}
|
||||
): Promise<WikiPage> {
|
||||
return apiRequest<WikiPage>(`/api/wiki/${encodeURIComponent(pageId)}`, {
|
||||
method: 'PATCH',
|
||||
token,
|
||||
body: payload,
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteWikiPage(token: string, pageId: string): Promise<{ success: boolean; deletedId?: string }> {
|
||||
return apiRequest<{ success: boolean; deletedId?: string }>(`/api/wiki/${encodeURIComponent(pageId)}`, {
|
||||
method: 'DELETE',
|
||||
token,
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchProjectById(token: string, projectId: number): Promise<Project> {
|
||||
return apiRequest<Project>(`/api/resource/projects/${projectId}`, { token });
|
||||
}
|
||||
|
||||
function resolveProjectIdFromTask(task: Task): number | null {
|
||||
const rawProject = task.project;
|
||||
if (!rawProject) return null;
|
||||
if (typeof rawProject === 'object') {
|
||||
return rawProject.id ? Number(rawProject.id) : null;
|
||||
}
|
||||
return Number(rawProject);
|
||||
}
|
||||
|
||||
export async function fetchProjectTasks(token: string, projectId: number): Promise<Task[]> {
|
||||
const tasks = await fetchTasks(token);
|
||||
return (tasks || []).filter((task) => resolveProjectIdFromTask(task) === Number(projectId));
|
||||
}
|
||||
|
||||
export async function createProjectTask(
|
||||
token: string,
|
||||
payload: {
|
||||
projectId: number;
|
||||
name: string;
|
||||
description?: string | null;
|
||||
userId?: string | null;
|
||||
categorie?: TaskStatus;
|
||||
}
|
||||
): Promise<Task> {
|
||||
return createTask(token, {
|
||||
name: payload.name,
|
||||
description: payload.description || null,
|
||||
userId: payload.userId || null,
|
||||
categorie: payload.categorie || 'Offen',
|
||||
project: payload.projectId,
|
||||
});
|
||||
}
|
||||
|
||||
function resolveProjectIdFromFile(file: ProjectFile): number | null {
|
||||
const rawProject = file.project;
|
||||
if (!rawProject) return null;
|
||||
if (typeof rawProject === 'object') {
|
||||
return rawProject.id ? Number(rawProject.id) : null;
|
||||
}
|
||||
return Number(rawProject);
|
||||
}
|
||||
|
||||
function resolveCustomerIdFromFile(file: ProjectFile): number | null {
|
||||
const rawCustomer = file.customer;
|
||||
if (!rawCustomer) return null;
|
||||
if (typeof rawCustomer === 'object') {
|
||||
return rawCustomer.id ? Number(rawCustomer.id) : null;
|
||||
}
|
||||
return Number(rawCustomer);
|
||||
}
|
||||
|
||||
function resolvePlantIdFromFile(file: ProjectFile): number | null {
|
||||
const rawPlant = file.plant;
|
||||
if (!rawPlant) return null;
|
||||
if (typeof rawPlant === 'object') {
|
||||
return rawPlant.id ? Number(rawPlant.id) : null;
|
||||
}
|
||||
return Number(rawPlant);
|
||||
}
|
||||
|
||||
function resolveCreatedDocumentIdFromFile(file: ProjectFile): number | null {
|
||||
const rawCreatedDocument = file.createddocument;
|
||||
if (!rawCreatedDocument) return null;
|
||||
if (typeof rawCreatedDocument === 'object') {
|
||||
return rawCreatedDocument.id ? Number(rawCreatedDocument.id) : null;
|
||||
}
|
||||
return Number(rawCreatedDocument);
|
||||
}
|
||||
|
||||
function resolveCustomerIdFromCreatedDocument(doc: CreatedDocument): number | null {
|
||||
const rawCustomer = doc.customer;
|
||||
if (!rawCustomer) return null;
|
||||
if (typeof rawCustomer === 'object') {
|
||||
return rawCustomer.id ? Number(rawCustomer.id) : null;
|
||||
}
|
||||
return Number(rawCustomer);
|
||||
}
|
||||
|
||||
export async function fetchProjectFiles(token: string, projectId: number): Promise<ProjectFile[]> {
|
||||
const files = await apiRequest<ProjectFile[]>('/api/resource/files', { token });
|
||||
const projectFiles = (files || []).filter((file) => {
|
||||
if (file.archived) return false;
|
||||
return resolveProjectIdFromFile(file) === Number(projectId);
|
||||
});
|
||||
|
||||
if (projectFiles.length === 0) return [];
|
||||
|
||||
const presigned = await apiRequest<{ files?: ProjectFile[] }>('/api/files/presigned', {
|
||||
method: 'POST',
|
||||
token,
|
||||
body: { ids: projectFiles.map((file) => file.id) },
|
||||
});
|
||||
|
||||
return presigned.files || [];
|
||||
}
|
||||
|
||||
export async function fetchCustomerFiles(token: string, customerId: number): Promise<ProjectFile[]> {
|
||||
const files = await apiRequest<ProjectFile[]>('/api/resource/files', { token });
|
||||
const customerFiles = (files || []).filter((file) => {
|
||||
if (file.archived) return false;
|
||||
return resolveCustomerIdFromFile(file) === Number(customerId);
|
||||
});
|
||||
|
||||
if (customerFiles.length === 0) return [];
|
||||
|
||||
const presigned = await apiRequest<{ files?: ProjectFile[] }>('/api/files/presigned', {
|
||||
method: 'POST',
|
||||
token,
|
||||
body: { ids: customerFiles.map((file) => file.id) },
|
||||
});
|
||||
|
||||
return presigned.files || [];
|
||||
}
|
||||
|
||||
export async function fetchPlantFiles(token: string, plantId: number): Promise<ProjectFile[]> {
|
||||
const files = await apiRequest<ProjectFile[]>('/api/resource/files', { token });
|
||||
const plantFiles = (files || []).filter((file) => {
|
||||
if (file.archived) return false;
|
||||
return resolvePlantIdFromFile(file) === Number(plantId);
|
||||
});
|
||||
|
||||
if (plantFiles.length === 0) return [];
|
||||
|
||||
const presigned = await apiRequest<{ files?: ProjectFile[] }>('/api/files/presigned', {
|
||||
method: 'POST',
|
||||
token,
|
||||
body: { ids: plantFiles.map((file) => file.id) },
|
||||
});
|
||||
|
||||
return presigned.files || [];
|
||||
}
|
||||
|
||||
export async function fetchCustomerCreatedDocuments(
|
||||
token: string,
|
||||
customerId: number
|
||||
): Promise<CreatedDocument[]> {
|
||||
const docs = await apiRequest<CreatedDocument[]>('/api/resource/createddocuments', { token });
|
||||
|
||||
return (docs || [])
|
||||
.filter((doc) => !doc.archived && resolveCustomerIdFromCreatedDocument(doc) === Number(customerId))
|
||||
.sort((a, b) => {
|
||||
const dateA = new Date(String(a.documentDate || '')).getTime();
|
||||
const dateB = new Date(String(b.documentDate || '')).getTime();
|
||||
return dateB - dateA;
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchCreatedDocumentFiles(
|
||||
token: string,
|
||||
createdDocumentId: number
|
||||
): Promise<ProjectFile[]> {
|
||||
const files = await apiRequest<ProjectFile[]>('/api/resource/files', { token });
|
||||
const createdDocumentFiles = (files || []).filter((file) => {
|
||||
if (file.archived) return false;
|
||||
return resolveCreatedDocumentIdFromFile(file) === Number(createdDocumentId);
|
||||
});
|
||||
|
||||
if (createdDocumentFiles.length === 0) return [];
|
||||
|
||||
const presigned = await apiRequest<{ files?: ProjectFile[] }>('/api/files/presigned', {
|
||||
method: 'POST',
|
||||
token,
|
||||
body: { ids: createdDocumentFiles.map((file) => file.id) },
|
||||
});
|
||||
|
||||
return presigned.files || [];
|
||||
}
|
||||
|
||||
export async function uploadProjectFile(
|
||||
token: string,
|
||||
payload: {
|
||||
projectId: number;
|
||||
uri: string;
|
||||
filename: string;
|
||||
mimeType?: string;
|
||||
}
|
||||
): Promise<ProjectFile> {
|
||||
const formData = new FormData();
|
||||
formData.append(
|
||||
'file',
|
||||
{
|
||||
uri: payload.uri,
|
||||
name: payload.filename,
|
||||
type: payload.mimeType || 'application/octet-stream',
|
||||
} as any
|
||||
);
|
||||
formData.append(
|
||||
'meta',
|
||||
JSON.stringify({
|
||||
project: payload.projectId,
|
||||
name: payload.filename,
|
||||
mimeType: payload.mimeType || 'application/octet-stream',
|
||||
})
|
||||
);
|
||||
|
||||
const response = await fetch(buildUrl('/api/files/upload'), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
Accept: 'application/json',
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
const parsed = await parseJson(response);
|
||||
if (!response.ok) {
|
||||
const message =
|
||||
(parsed as { message?: string; error?: string } | null)?.message ||
|
||||
(parsed as { message?: string; error?: string } | null)?.error ||
|
||||
'Upload fehlgeschlagen.';
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
return parsed as ProjectFile;
|
||||
}
|
||||
|
||||
export async function uploadCustomerFile(
|
||||
token: string,
|
||||
payload: {
|
||||
customerId: number;
|
||||
uri: string;
|
||||
filename: string;
|
||||
mimeType?: string;
|
||||
}
|
||||
): Promise<ProjectFile> {
|
||||
const formData = new FormData();
|
||||
formData.append(
|
||||
'file',
|
||||
{
|
||||
uri: payload.uri,
|
||||
name: payload.filename,
|
||||
type: payload.mimeType || 'application/octet-stream',
|
||||
} as any
|
||||
);
|
||||
formData.append(
|
||||
'meta',
|
||||
JSON.stringify({
|
||||
customer: payload.customerId,
|
||||
name: payload.filename,
|
||||
mimeType: payload.mimeType || 'application/octet-stream',
|
||||
})
|
||||
);
|
||||
|
||||
const response = await fetch(buildUrl('/api/files/upload'), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
Accept: 'application/json',
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
const parsed = await parseJson(response);
|
||||
if (!response.ok) {
|
||||
const message =
|
||||
(parsed as { message?: string; error?: string } | null)?.message ||
|
||||
(parsed as { message?: string; error?: string } | null)?.error ||
|
||||
'Upload fehlgeschlagen.';
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
return parsed as ProjectFile;
|
||||
}
|
||||
|
||||
export async function uploadPlantFile(
|
||||
token: string,
|
||||
payload: {
|
||||
plantId: number;
|
||||
uri: string;
|
||||
filename: string;
|
||||
mimeType?: string;
|
||||
}
|
||||
): Promise<ProjectFile> {
|
||||
const formData = new FormData();
|
||||
formData.append(
|
||||
'file',
|
||||
{
|
||||
uri: payload.uri,
|
||||
name: payload.filename,
|
||||
type: payload.mimeType || 'application/octet-stream',
|
||||
} as any
|
||||
);
|
||||
formData.append(
|
||||
'meta',
|
||||
JSON.stringify({
|
||||
plant: payload.plantId,
|
||||
name: payload.filename,
|
||||
mimeType: payload.mimeType || 'application/octet-stream',
|
||||
})
|
||||
);
|
||||
|
||||
const response = await fetch(buildUrl('/api/files/upload'), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
Accept: 'application/json',
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
const parsed = await parseJson(response);
|
||||
if (!response.ok) {
|
||||
const message =
|
||||
(parsed as { message?: string; error?: string } | null)?.message ||
|
||||
(parsed as { message?: string; error?: string } | null)?.error ||
|
||||
'Upload fehlgeschlagen.';
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
return parsed as ProjectFile;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user