fix: ready for build

This commit is contained in:
Ida Dittrich 2025-10-12 16:28:49 +02:00
parent 9519fed195
commit 8a0e5f88a1
27 changed files with 79 additions and 128 deletions

18
package-lock.json generated
View file

@ -30,6 +30,7 @@
},
"devDependencies": {
"@eslint/js": "^9.30.1",
"@types/node": "^24.7.2",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^4.6.0",
@ -1432,6 +1433,16 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
"version": "24.7.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.2.tgz",
"integrity": "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.14.0"
}
},
"node_modules/@types/react": {
"version": "19.1.8",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz",
@ -5083,6 +5094,13 @@
"typescript": ">=4.8.4 <5.9.0"
}
},
"node_modules/undici-types": {
"version": "7.14.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz",
"integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==",
"dev": true,
"license": "MIT"
},
"node_modules/universalify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",

View file

@ -36,6 +36,7 @@
},
"devDependencies": {
"@eslint/js": "^9.30.1",
"@types/node": "^24.7.2",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^4.6.0",

View file

@ -1,7 +1,6 @@
import { useMsal } from "@azure/msal-react";
import { Navigate, useLocation } from "react-router-dom";
import { ReactNode, useEffect, useState } from "react";
import api from "../api";
interface ProtectedRouteProps {
children: ReactNode;

View file

@ -6,7 +6,6 @@ import {
import { msalConfig } from "./authConfig";
import { MsalProvider } from "@azure/msal-react";
import { ReactNode, useEffect, useState } from "react";
import api from "../api";
interface AuthProviderProps {
children: ReactNode;

View file

@ -36,7 +36,7 @@ export function ConnectionsTable({
onRowSelect={onRowSelect}
onDelete={onDelete}
onDeleteMultiple={onDeleteMultiple}
actions={actions}
actionButtons={actions}
className={styles.connectionsTable}
/>
</div>

View file

@ -1,9 +1,6 @@
import { ColumnConfig } from '../FormGenerator';
import { EditFieldConfig } from '../ui/Popup';
// Import React for component types
import React from 'react';
// Re-export connection-related interfaces from hooks
export type { Connection, CreateConnectionData } from '../../hooks/useConnections';
import type { Connection } from '../../hooks/useConnections';
@ -37,9 +34,11 @@ export interface ConnectionsErrorDisplayProps {
// Table Action Interface
export interface TableAction {
label: string;
onClick?: (connection: Connection) => Promise<void> | void;
icon: React.ReactNode | ((connection: Connection) => React.ReactNode);
type: 'edit' | 'delete' | 'download' | 'view' | 'copy';
title?: string | ((connection: Connection) => string);
onAction?: (connection: Connection) => Promise<void> | void;
disabled?: (connection: Connection) => boolean | { disabled: boolean; message?: string };
loading?: (connection: Connection) => boolean;
}
// Connection Status Types

View file

@ -1,6 +1,4 @@
import { useEffect, useState } from 'react';
import { IoIosRefresh, IoIosTrash } from 'react-icons/io';
import { MdModeEdit } from 'react-icons/md';
@ -441,21 +439,16 @@ export function useConnectionsLogic(): ConnectionsLogicReturn {
// Table actions
const tableActions: TableAction[] = [
{
label: t('connections.action.edit', 'Edit'),
onClick: handleEditConnection,
icon: <MdModeEdit />
type: 'edit',
title: t('connections.action.edit', 'Edit'),
onAction: handleEditConnection
},
{
label: t('connections.action.update', 'Update'),
onClick: handleUpdateConnection,
icon: <IoIosRefresh />
},
{
label: t('connections.action.delete', 'Delete'),
icon: <IoIosTrash />,
// onClick is handled by FormGenerator for delete confirmation
type: 'delete',
title: t('connections.action.delete', 'Delete')
// onAction is handled by FormGenerator for delete confirmation
}
];
] as any;
return {
// Data

View file

@ -28,7 +28,7 @@ const FileAttachmentPopup: React.FC<FileAttachmentPopupProps> = ({
const [fileSubTab, setFileSubTab] = useState<'all' | 'uploads' | 'created' | 'shared'>('all');
const fileInputRef = useRef<HTMLInputElement>(null);
const { files: existingFiles, loading: filesLoading } = useUserFiles();
const { data: existingFiles, loading: filesLoading } = useUserFiles();
const handleDragEnter = (e: React.DragEvent) => {
e.preventDefault();

View file

@ -29,7 +29,6 @@ export function CopyActionButton<T = any>({
title,
isCopying = false,
hookData,
idField = 'id',
nameField = 'name',
contentField = 'content',
loadingStateName = 'creatingPrompt',

View file

@ -152,9 +152,6 @@ export function DeleteActionButton<T = any>({
const confirmButtonTitle = confirmTitle || t('formgen.delete.confirm', 'Confirm delete');
const cancelButtonTitle = cancelTitle || t('formgen.delete.cancel', 'Cancel delete');
// Use loading state from hookData if available
const isDeletingFromHook = loadingState?.has((row as any)[idField]) || false;
// Check if ANY deletion is in progress (not just this specific item)
const isAnyDeletionInProgress = loadingState && loadingState.size > 0;

View file

@ -40,8 +40,6 @@ export function EditActionButton<T = any>({
isEditing = false,
hookData,
idField = 'id',
nameField = 'name',
typeField = 'type',
operationName = 'handleFileUpdate',
loadingStateName = 'editingFiles',
editFields = [

View file

@ -165,7 +165,7 @@ function MitgliederTable({ className = '', showAddUser = false, onAddUserClose }
pageSize={10}
selectable={false}
loading={loading}
actions={actions}
actionButtons={actions}
onRefresh={refetch}
className={styles.mitgliederFormGenerator}
getRowDataAttributes={(row) => {

View file

@ -1,6 +1,4 @@
import { useMemo, useState } from 'react';
import { MdModeEdit } from 'react-icons/md';
import { IoIosTrash } from 'react-icons/io';
import { useOrgUsers } from '../../hooks/useUsers';
import { useLanguage } from '../../contexts/LanguageContext';
@ -230,16 +228,16 @@ export function useMitgliederLogic(): MitgliederLogicReturn {
// Configure action buttons
const actions: UserActionConfig[] = useMemo(() => [
{
label: t('users.actions.edit', 'Edit'),
icon: () => <MdModeEdit />,
onClick: (row: any) => handleEditUser(row)
type: 'edit',
title: t('users.actions.edit', 'Edit'),
onAction: (row: any) => handleEditUser(row)
},
{
label: t('users.actions.delete', 'Delete'),
icon: () => <IoIosTrash />,
onClick: (row: any) => handleDeleteUser(row)
type: 'delete',
title: t('users.actions.delete', 'Delete'),
onAction: (row: any) => handleDeleteUser(row)
}
], [t]);
] as any, [t]);
return {
// Data

View file

@ -10,9 +10,11 @@ export interface MitgliederTableProps {
// Action configuration for user actions
export interface UserActionConfig {
label: string;
icon: (row: User) => React.ReactElement;
onClick: (row: User) => void;
type: 'edit' | 'delete' | 'download' | 'view' | 'copy';
title?: string | ((row: User) => string);
onAction?: (row: User) => Promise<void> | void;
disabled?: (row: User) => boolean | { disabled: boolean; message?: string };
loading?: (row: User) => boolean;
}
// Column configuration for the users table

View file

@ -73,7 +73,7 @@ function PromptsTable({ className = '' }: PromptsTableProps) {
selectable={true}
isRowSelectable={isPromptSelectable}
loading={loading}
actions={actions}
actionButtons={actions}
onDelete={handleDeleteSingle}
onDeleteMultiple={handleDeleteMultiple}
onRefresh={refetch}

View file

@ -1,6 +1,4 @@
import { useState, useMemo } from 'react';
import { IoIosTrash, IoIosCopy } from 'react-icons/io';
import { MdModeEdit } from 'react-icons/md';
import { usePrompts, usePromptOperations, Prompt } from '../../hooks/usePrompts';
import { useLanguage } from '../../contexts/LanguageContext';
@ -260,44 +258,31 @@ export function usePromptsLogic(): PromptsLogicReturn {
// Configure action buttons
const actions: PromptActionConfig[] = useMemo(() => [
{
label: t('prompts.action.edit', 'Edit'),
icon: (_row: Prompt) => {
return <MdModeEdit />;
},
onClick: (row: Prompt) => {
type: 'edit',
title: t('prompts.action.edit', 'Edit'),
onAction: (row: Prompt) => {
handleEditPrompt(row);
}
},
{
label: t('prompts.action.copy', 'Copy'),
icon: (_row: Prompt) => {
return <IoIosCopy />;
},
onClick: (row: Prompt) => {
type: 'copy',
title: t('prompts.action.copy', 'Copy'),
onAction: (row: Prompt) => {
handleCopyPrompt(row);
}
},
{
label: (row: Prompt) => {
type: 'delete',
title: (row: Prompt) => {
const isDeletable = isPromptDeletable(row);
return isDeletable
? t('prompts.action.delete', 'Delete')
: t('prompts.action.delete.disabled', 'No permission to delete prompt');
},
icon: (row: Prompt) => {
const isDeletable = isPromptDeletable(row);
return (
<IoIosTrash
style={{
opacity: isDeletable ? 1 : 0.4,
cursor: isDeletable ? 'pointer' : 'not-allowed'
}}
/>
);
},
// onClick is handled by FormGenerator for delete confirmation
disabled: (row: Prompt) => !isPromptDeletable(row)
// onAction is handled by FormGenerator for delete confirmation
},
], [t, deletingPrompts, handleDeletePrompt, handleEditPrompt, handleCopyPrompt]);
] as any, [t, deletingPrompts, handleDeletePrompt, handleEditPrompt, handleCopyPrompt]);
return {
// Data

View file

@ -17,9 +17,11 @@ export interface PromptsTableProps {
// Action configuration for prompt actions
export interface PromptActionConfig {
label: string | ((row: Prompt) => string);
icon: (row: Prompt) => React.ReactElement;
onClick?: (row: Prompt) => void;
type: 'edit' | 'delete' | 'download' | 'view' | 'copy';
title?: string | ((row: Prompt) => string);
onAction?: (row: Prompt) => Promise<void> | void;
disabled?: (row: Prompt) => boolean | { disabled: boolean; message?: string };
loading?: (row: Prompt) => boolean;
}
// Column configuration for the prompts table

View file

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import { useState, useEffect } from 'react';
import { IoIosBusiness, IoIosContact, IoIosTime, IoIosRefresh } from 'react-icons/io';
import sharedStyles from '../../core/PageManager/pages.module.css';
import styles from './SpeechSettings.module.css';

View file

@ -62,7 +62,7 @@ export function TestSharepointTable({
showPageSizeSelector={true}
selectable={false}
onRowClick={onRowClick}
actions={actualActions}
actionButtons={actualActions}
className={styles.sharepointFormGenerator}
/>
</div>

View file

@ -35,7 +35,7 @@ function WorkflowsTable({ className = '' }: WorkflowsTableProps) {
pagination={true}
pageSize={10}
loading={logic.loading}
actions={logic.actions}
actionButtons={logic.actions}
onDelete={logic.handleDeleteSingle}
onDeleteMultiple={logic.handleDeleteMultiple}
onRefresh={logic.refetch}

View file

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import { useState, useEffect } from 'react';
import { IoIosBusiness, IoIosContact, IoIosTime, IoIosRefresh } from 'react-icons/io';
import { useNavigate } from 'react-router-dom';
import styles from './settingsSpeech.module.css';
@ -34,7 +34,6 @@ function SettingsSpeech({ onDataUpdate }: SettingsSpeechProps) {
const [isLoading, setIsLoading] = useState(true);
const [isSaving, setIsSaving] = useState(false);
const [saveMessage, setSaveMessage] = useState<{ type: 'success' | 'error', text: string } | null>(null);
const [focusedFields, setFocusedFields] = useState<Set<string>>(new Set());
// Load data from localStorage on component mount
useEffect(() => {
@ -94,17 +93,6 @@ function SettingsSpeech({ onDataUpdate }: SettingsSpeechProps) {
setSaveMessage(null);
};
const handleFocus = (field: string) => {
setFocusedFields(prev => new Set(prev).add(field));
};
const handleBlur = (field: string) => {
setFocusedFields(prev => {
const newSet = new Set(prev);
newSet.delete(field);
return newSet;
});
};
const handleSave = async () => {
if (!formData) return;
@ -200,8 +188,6 @@ function SettingsSpeech({ onDataUpdate }: SettingsSpeechProps) {
className={styles.formInput}
value={formData.mandate_general.company_name}
onChange={(e) => handleInputChange('mandate_general.company_name', e.target.value)}
onFocus={() => handleFocus('company_name')}
onBlur={() => handleBlur('company_name')}
required
/>
</div>
@ -215,8 +201,6 @@ function SettingsSpeech({ onDataUpdate }: SettingsSpeechProps) {
className={styles.formInput}
value={formData.mandate_general.industry}
onChange={(e) => handleInputChange('mandate_general.industry', e.target.value)}
onFocus={() => handleFocus('industry')}
onBlur={() => handleBlur('industry')}
required
/>
</div>
@ -240,8 +224,6 @@ function SettingsSpeech({ onDataUpdate }: SettingsSpeechProps) {
className={styles.formInput}
value={formData.mandate_general.contact_info.email}
onChange={(e) => handleInputChange('mandate_general.contact_info.email', e.target.value)}
onFocus={() => handleFocus('email')}
onBlur={() => handleBlur('email')}
required
/>
</div>
@ -255,8 +237,6 @@ function SettingsSpeech({ onDataUpdate }: SettingsSpeechProps) {
className={styles.formInput}
value={formData.mandate_general.contact_info.phone}
onChange={(e) => handleInputChange('mandate_general.contact_info.phone', e.target.value)}
onFocus={() => handleFocus('phone')}
onBlur={() => handleBlur('phone')}
required
/>
</div>
@ -272,8 +252,6 @@ function SettingsSpeech({ onDataUpdate }: SettingsSpeechProps) {
className={styles.formInput}
value={formData.mandate_general.contact_info.street}
onChange={(e) => handleInputChange('mandate_general.contact_info.street', e.target.value)}
onFocus={() => handleFocus('street')}
onBlur={() => handleBlur('street')}
required
/>
</div>
@ -287,8 +265,6 @@ function SettingsSpeech({ onDataUpdate }: SettingsSpeechProps) {
className={styles.formInput}
value={formData.mandate_general.contact_info.postal_code}
onChange={(e) => handleInputChange('mandate_general.contact_info.postal_code', e.target.value)}
onFocus={() => handleFocus('postal_code')}
onBlur={() => handleBlur('postal_code')}
required
/>
</div>
@ -304,8 +280,6 @@ function SettingsSpeech({ onDataUpdate }: SettingsSpeechProps) {
className={styles.formInput}
value={formData.mandate_general.contact_info.city}
onChange={(e) => handleInputChange('mandate_general.contact_info.city', e.target.value)}
onFocus={() => handleFocus('city')}
onBlur={() => handleBlur('city')}
required
/>
</div>
@ -319,8 +293,6 @@ function SettingsSpeech({ onDataUpdate }: SettingsSpeechProps) {
className={styles.formInput}
value={formData.mandate_general.contact_info.country}
onChange={(e) => handleInputChange('mandate_general.contact_info.country', e.target.value)}
onFocus={() => handleFocus('country')}
onBlur={() => handleBlur('country')}
required
/>
</div>
@ -344,8 +316,6 @@ function SettingsSpeech({ onDataUpdate }: SettingsSpeechProps) {
className={styles.formInput}
value={formData.mandate_general.business_hours}
onChange={(e) => handleInputChange('mandate_general.business_hours', e.target.value)}
onFocus={() => handleFocus('business_hours')}
onBlur={() => handleBlur('business_hours')}
required
/>
</div>
@ -358,8 +328,6 @@ function SettingsSpeech({ onDataUpdate }: SettingsSpeechProps) {
className={styles.formSelect}
value={formData.mandate_general.timezone}
onChange={(e) => handleInputChange('mandate_general.timezone', e.target.value)}
onFocus={() => handleFocus('timezone')}
onBlur={() => handleBlur('timezone')}
required
>
<option value="">{t('speech.signup.select_timezone')}</option>

View file

@ -3,9 +3,6 @@ import { useLanguage, Language } from '../../contexts/LanguageContext';
import { useCurrentUser, useUser, User } from '../../hooks/useUsers';
import styles from './settingsUser.module.css';
// Add a check to ensure we're in the right context
const isClient = typeof window !== 'undefined';
interface SettingsUserProps {
className?: string;
}

View file

@ -935,7 +935,7 @@ export function useLogout() {
try {
// Call logout endpoint to clear JWT tokens on server
const logoutResponse = await api.post('/api/local/logout');
await api.post('/api/local/logout');
console.log('✅ Logout API call completed, waiting for browser to process cookies...');

View file

@ -151,7 +151,7 @@ export function useCurrentUser() {
logoutEndpoint = '/api/local/logout';
}
const logoutResponse = await request({
await request({
url: logoutEndpoint,
method: 'post'
});

View file

@ -2,7 +2,6 @@ import { useState, useEffect } from 'react';
import sharedStyles from '../../core/PageManager/pages.module.css';
import { useLanguage } from '../../contexts/LanguageContext';
import { FormGenerator, ColumnConfig } from '../../components/FormGenerator/FormGenerator';
import { IoIosEye, IoIosDownload } from 'react-icons/io';
interface CallTranscript {
id: string;
@ -235,22 +234,22 @@ function SpeechTranscripts() {
// Handle row click - could open a modal with transcript details
console.log('Selected transcript:', transcript);
}}
actions={[
actionButtons={[
{
label: t('speech.transcripts.view', 'View'),
onClick: (transcript) => {
type: 'view',
title: t('speech.transcripts.view', 'View'),
onAction: (transcript: CallTranscript) => {
// Handle view action
console.log('View transcript:', transcript);
},
icon: <IoIosEye />
}
},
{
label: t('speech.transcripts.download', 'Download'),
onClick: (transcript) => {
type: 'download',
title: t('speech.transcripts.download', 'Download'),
onAction: (transcript: CallTranscript) => {
// Handle download action
console.log('Download transcript:', transcript);
},
icon: <IoIosDownload />
}
}
]}
/>

View file

@ -1,4 +1,4 @@
import { PrivilegeChecker } from '../components/PageManager/pageConfigInterface';
import { PrivilegeChecker } from '../core/PageManager/pageInterface';
// Function to get current user privilege from localStorage (where it's cached)
const getCurrentUserPrivilege = (): string | null => {

View file

@ -18,9 +18,6 @@ export default defineConfig(({ mode }) => {
}),
],
envPrefix: 'VITE_',
server: {
https: false,
},
css: {
modules: {
scopeBehaviour: 'local', // Default behavior for CSS modules