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:
parent
7d721f9ef0
commit
c89ee359d1
9 changed files with 31 additions and 26 deletions
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue