diff --git a/frontend/apps/cli/src/__tests__/hooks/useRoles.test.ts b/frontend/apps/cli/src/__tests__/hooks/useRoles.test.ts index 510d21d..53142e6 100644 --- a/frontend/apps/cli/src/__tests__/hooks/useRoles.test.ts +++ b/frontend/apps/cli/src/__tests__/hooks/useRoles.test.ts @@ -12,8 +12,8 @@ vi.mock('../../utils/api-client.js', () => ({ const { client } = await import('../../utils/api-client.js'); const mockRoles: RoleDTO[] = [ - { id: '1', name: 'ADMIN', permissions: [] }, - { id: '2', name: 'USER', permissions: [] }, + { id: '1', name: 'ADMIN', permissions: [], description: 'Administrator' }, + { id: '2', name: 'SALES_MANAGER', permissions: [], description: 'Sales Manager' }, ]; describe('useRoles – api-client integration', () => { diff --git a/frontend/apps/cli/src/components/masterdata/articles/ArticleDetailScreen.tsx b/frontend/apps/cli/src/components/masterdata/articles/ArticleDetailScreen.tsx index 87876a1..b82149f 100644 --- a/frontend/apps/cli/src/components/masterdata/articles/ArticleDetailScreen.tsx +++ b/frontend/apps/cli/src/components/masterdata/articles/ArticleDetailScreen.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useState } from 'react'; import { Box, Text, useInput } from 'ink'; -import type { ArticleDTO, SalesUnitDTO } from '@effigenix/api-client'; +import type { ArticleDTO, SalesUnitDTO, Unit, PriceModel } from '@effigenix/api-client'; import { UNIT_LABELS, PRICE_MODEL_LABELS } from '@effigenix/api-client'; import { useNavigation } from '../../../state/navigation-context.js'; import { useArticles } from '../../../hooks/useArticles.js'; @@ -114,7 +114,7 @@ export function ArticleDetailScreen() { setActionLoading(false); if (updated) { setArticle(updated); - setSuccessMessage(`Verkaufseinheit "${UNIT_LABELS[su.unit]}" entfernt.`); + setSuccessMessage(`Verkaufseinheit "${UNIT_LABELS[su.unit as Unit]}" entfernt.`); } }, [article, removeSalesUnit]); @@ -150,8 +150,8 @@ export function ArticleDetailScreen() { {article.salesUnits.map((su) => ( - {UNIT_LABELS[su.unit]} - ({PRICE_MODEL_LABELS[su.priceModel]}) + {UNIT_LABELS[su.unit as Unit]} + ({PRICE_MODEL_LABELS[su.priceModel as PriceModel]}) {su.price.toFixed(2)} € ))} @@ -181,7 +181,7 @@ export function ArticleDetailScreen() { {i === selectedSuIndex ? '▶ ' : ' '} - {UNIT_LABELS[su.unit]} – {su.price.toFixed(2)} € + {UNIT_LABELS[su.unit as Unit]} – {su.price.toFixed(2)} € ))} diff --git a/frontend/apps/cli/src/components/masterdata/customers/CustomerDetailScreen.tsx b/frontend/apps/cli/src/components/masterdata/customers/CustomerDetailScreen.tsx index 8e35838..ad26fe1 100644 --- a/frontend/apps/cli/src/components/masterdata/customers/CustomerDetailScreen.tsx +++ b/frontend/apps/cli/src/components/masterdata/customers/CustomerDetailScreen.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useState } from 'react'; import { Box, Text, useInput } from 'ink'; -import type { CustomerDTO } from '@effigenix/api-client'; +import type { CustomerDTO, CustomerPreference } from '@effigenix/api-client'; import { CUSTOMER_PREFERENCE_LABELS } from '@effigenix/api-client'; import { useNavigation } from '../../../state/navigation-context.js'; import { useCustomers } from '../../../hooks/useCustomers.js'; @@ -137,6 +137,8 @@ export function CustomerDetailScreen() { if (!customer) return Kunde nicht gefunden.; const statusColor = customer.status === 'ACTIVE' ? 'green' : 'red'; + const ba = customer.billingAddress; + const billingText = ba ? `${ba.street} ${ba.houseNumber}, ${ba.postalCode} ${ba.city}, ${ba.country}` : '–'; return ( @@ -164,7 +166,7 @@ export function CustomerDetailScreen() { )} Rechnungsadresse: - {`${customer.billingAddress.street} ${customer.billingAddress.houseNumber}, ${customer.billingAddress.postalCode} ${customer.billingAddress.city}, ${customer.billingAddress.country}`} + {billingText} {customer.paymentTerms && ( @@ -175,7 +177,7 @@ export function CustomerDetailScreen() { {customer.preferences.length > 0 && ( Präferenzen: - {customer.preferences.map((p) => CUSTOMER_PREFERENCE_LABELS[p]).join(', ')} + {customer.preferences.map((p) => CUSTOMER_PREFERENCE_LABELS[p as CustomerPreference]).join(', ')} )} {customer.deliveryAddresses.length > 0 && ( @@ -185,7 +187,7 @@ export function CustomerDetailScreen() { {addr.label}: - {`${addr.address.street} ${addr.address.houseNumber}, ${addr.address.city}, ${addr.address.country}`} + {addr.address ? `${addr.address.street} ${addr.address.houseNumber}, ${addr.address.city}, ${addr.address.country}` : '–'} ))} @@ -217,7 +219,7 @@ export function CustomerDetailScreen() { {customer.deliveryAddresses.map((addr, i) => ( - {i === selectedAddrIndex ? '▶ ' : ' '}{addr.label}: {addr.address.city} + {i === selectedAddrIndex ? '▶ ' : ' '}{addr.label}: {addr.address?.city ?? '–'} ))} diff --git a/frontend/apps/cli/src/components/masterdata/customers/SetPreferencesScreen.tsx b/frontend/apps/cli/src/components/masterdata/customers/SetPreferencesScreen.tsx index aa40293..17ad70f 100644 --- a/frontend/apps/cli/src/components/masterdata/customers/SetPreferencesScreen.tsx +++ b/frontend/apps/cli/src/components/masterdata/customers/SetPreferencesScreen.tsx @@ -28,7 +28,7 @@ export function SetPreferencesScreen() { useEffect(() => { client.customers.getById(customerId) - .then((c) => { setChecked(new Set(c.preferences)); setInitLoading(false); }) + .then((c) => { setChecked(new Set(c.preferences as CustomerPreference[])); setInitLoading(false); }) .catch((err: unknown) => { setInitError(errorMessage(err)); setInitLoading(false); }); }, [customerId]); diff --git a/frontend/apps/cli/src/components/masterdata/suppliers/SupplierListScreen.tsx b/frontend/apps/cli/src/components/masterdata/suppliers/SupplierListScreen.tsx index a2d202b..383a5ce 100644 --- a/frontend/apps/cli/src/components/masterdata/suppliers/SupplierListScreen.tsx +++ b/frontend/apps/cli/src/components/masterdata/suppliers/SupplierListScreen.tsx @@ -8,7 +8,7 @@ import type { SupplierStatus } from '@effigenix/api-client'; type Filter = 'ALL' | SupplierStatus; -function avgRating(rating: { qualityScore: number; deliveryScore: number; priceScore: number } | null): string { +function avgRating(rating: { qualityScore: number; deliveryScore: number; priceScore: number } | null | undefined): string { if (!rating) return '–'; const avg = (rating.qualityScore + rating.deliveryScore + rating.priceScore) / 3; return avg.toFixed(1); diff --git a/frontend/apps/cli/src/components/production/ProductionOrderCreateScreen.tsx b/frontend/apps/cli/src/components/production/ProductionOrderCreateScreen.tsx index 69a9786..8e01caf 100644 --- a/frontend/apps/cli/src/components/production/ProductionOrderCreateScreen.tsx +++ b/frontend/apps/cli/src/components/production/ProductionOrderCreateScreen.tsx @@ -82,8 +82,9 @@ export function ProductionOrderCreateScreen() { if (success) { if (_input.toLowerCase() === 'f' && productionOrder?.id) { + const orderId = productionOrder.id; void (async () => { - const result = await releaseProductionOrder(productionOrder.id); + const result = await releaseProductionOrder(orderId); if (result) setReleased(true); })(); return; diff --git a/frontend/apps/cli/src/hooks/useCategories.ts b/frontend/apps/cli/src/hooks/useCategories.ts index 970e645..fc6e759 100644 --- a/frontend/apps/cli/src/hooks/useCategories.ts +++ b/frontend/apps/cli/src/hooks/useCategories.ts @@ -32,8 +32,9 @@ export function useCategories() { const createCategory = useCallback(async (name: string, description?: string) => { setState((s) => ({ ...s, loading: true, error: null })); try { - const req = description ? { name, description } : { name }; - const cat = await client.categories.create(req); + const req: Record = { name }; + if (description) req.description = description; + const cat = await client.categories.create(req as { name: string; description?: string }); setState((s) => ({ categories: [...s.categories, cat], loading: false, error: null })); return cat; } catch (err) { @@ -45,7 +46,9 @@ export function useCategories() { const updateCategory = useCallback( async (id: string, name: string, description: string | null) => { try { - const updated = await client.categories.update(id, { name, description }); + const req: Record = { name }; + if (description !== null) req.description = description; + const updated = await client.categories.update(id, req as { name: string; description?: string }); setState((s) => ({ ...s, categories: s.categories.map((c) => (c.id === id ? updated : c)), diff --git a/frontend/apps/cli/src/hooks/useUsers.ts b/frontend/apps/cli/src/hooks/useUsers.ts index 3abc3d9..69403e0 100644 --- a/frontend/apps/cli/src/hooks/useUsers.ts +++ b/frontend/apps/cli/src/hooks/useUsers.ts @@ -1,7 +1,9 @@ import { useState, useCallback } from 'react'; -import type { UserDTO } from '@effigenix/api-client'; +import type { UserDTO, CreateUserRequest } from '@effigenix/api-client'; import { client } from '../utils/api-client.js'; +type RoleName = CreateUserRequest['roleNames'][number]; + interface UsersState { users: UserDTO[]; loading: boolean; @@ -37,7 +39,7 @@ export function useUsers() { username, email, password, - roleNames: roleName ? [roleName] : [], + roleNames: roleName ? [roleName as RoleName] : [], }); setState((s) => ({ users: [...s.users, user], loading: false, error: null })); return user; @@ -79,7 +81,7 @@ export function useUsers() { const assignRole = useCallback(async (id: string, roleName: string) => { try { - const user = await client.users.assignRole(id, { roleName }); + const user = await client.users.assignRole(id, { roleName: roleName as RoleName }); setState((s) => ({ ...s, users: s.users.map((u) => (u.id === id ? user : u)), diff --git a/frontend/packages/api-client/src/resources/roles.ts b/frontend/packages/api-client/src/resources/roles.ts index 99045a9..4ce7112 100644 --- a/frontend/packages/api-client/src/resources/roles.ts +++ b/frontend/packages/api-client/src/resources/roles.ts @@ -3,13 +3,10 @@ */ import type { AxiosInstance } from 'axios'; +import type { RoleDTO } from '@effigenix/types'; import { API_PATHS } from '@effigenix/config'; -export interface RoleDTO { - id: string; - name: string; - permissions: string[]; -} +export type { RoleDTO }; export function createRolesResource(client: AxiosInstance) { return {