1
0
Fork 0
mirror of https://github.com/s-frick/effigenix.git synced 2026-03-28 15:29:34 +01:00

fix(tui): TypeScript-Fehler durch strikte generierte OpenAPI-Typen beheben

RoleDTO auf generierten Typ umgestellt, exactOptionalPropertyTypes-Konflikte
gelöst, Null-Checks für nullable AddressResponse ergänzt und Enum-Casts
für string-basierte SalesUnit-Felder hinzugefügt.
This commit is contained in:
Sebastian Frick 2026-02-25 17:34:14 +01:00
parent 7d721f9ef0
commit c89ee359d1
9 changed files with 31 additions and 26 deletions

View file

@ -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', () => {

View file

@ -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) => (
<Box key={su.id} paddingLeft={2} gap={1}>
<Text color="yellow"></Text>
<Text>{UNIT_LABELS[su.unit]}</Text>
<Text color="gray">({PRICE_MODEL_LABELS[su.priceModel]})</Text>
<Text>{UNIT_LABELS[su.unit as Unit]}</Text>
<Text color="gray">({PRICE_MODEL_LABELS[su.priceModel as PriceModel]})</Text>
<Text color="green">{su.price.toFixed(2)} </Text>
</Box>
))}
@ -181,7 +181,7 @@ export function ArticleDetailScreen() {
<Box key={su.id}>
<Text color={i === selectedSuIndex ? 'cyan' : 'white'}>
{i === selectedSuIndex ? '▶ ' : ' '}
{UNIT_LABELS[su.unit]} {su.price.toFixed(2)}
{UNIT_LABELS[su.unit as Unit]} {su.price.toFixed(2)}
</Text>
</Box>
))}

View file

@ -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 <Text color="red">Kunde nicht gefunden.</Text>;
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 (
<Box flexDirection="column" gap={1}>
@ -164,7 +166,7 @@ export function CustomerDetailScreen() {
)}
<Box gap={2}>
<Text color="gray">Rechnungsadresse:</Text>
<Text>{`${customer.billingAddress.street} ${customer.billingAddress.houseNumber}, ${customer.billingAddress.postalCode} ${customer.billingAddress.city}, ${customer.billingAddress.country}`}</Text>
<Text>{billingText}</Text>
</Box>
{customer.paymentTerms && (
<Box gap={2}>
@ -175,7 +177,7 @@ export function CustomerDetailScreen() {
{customer.preferences.length > 0 && (
<Box gap={2}>
<Text color="gray">Präferenzen:</Text>
<Text>{customer.preferences.map((p) => CUSTOMER_PREFERENCE_LABELS[p]).join(', ')}</Text>
<Text>{customer.preferences.map((p) => CUSTOMER_PREFERENCE_LABELS[p as CustomerPreference]).join(', ')}</Text>
</Box>
)}
{customer.deliveryAddresses.length > 0 && (
@ -185,7 +187,7 @@ export function CustomerDetailScreen() {
<Box key={addr.label} paddingLeft={2} gap={1}>
<Text color="yellow"></Text>
<Text bold>{addr.label}:</Text>
<Text>{`${addr.address.street} ${addr.address.houseNumber}, ${addr.address.city}, ${addr.address.country}`}</Text>
<Text>{addr.address ? `${addr.address.street} ${addr.address.houseNumber}, ${addr.address.city}, ${addr.address.country}` : ''}</Text>
</Box>
))}
</Box>
@ -217,7 +219,7 @@ export function CustomerDetailScreen() {
{customer.deliveryAddresses.map((addr, i) => (
<Box key={addr.label}>
<Text color={i === selectedAddrIndex ? 'cyan' : 'white'}>
{i === selectedAddrIndex ? '▶ ' : ' '}{addr.label}: {addr.address.city}
{i === selectedAddrIndex ? '▶ ' : ' '}{addr.label}: {addr.address?.city ?? ''}
</Text>
</Box>
))}

View file

@ -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]);

View file

@ -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);

View file

@ -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;

View file

@ -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<string, string> = { 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<string, string> = { 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)),

View file

@ -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)),