diff --git a/README.md b/README.md index 36fc528..1384bda 100644 Binary files a/README.md and b/README.md differ diff --git a/src/components/Connections/ConnectionsTable.tsx b/src/components/Connections/ConnectionsTable.tsx index 5ea1543..6251469 100644 --- a/src/components/Connections/ConnectionsTable.tsx +++ b/src/components/Connections/ConnectionsTable.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +// import React from 'react'; import { FormGenerator } from '../FormGenerator'; import styles from './ConnectionsTable.module.css'; import { ConnectionsTableProps } from './connectionsInterfaces'; @@ -11,7 +11,9 @@ export function ConnectionsTable({ isLoading = false, isConnecting = false, isDisconnecting = false, - onRowSelect + onRowSelect, + onDelete, + onDeleteMultiple }: ConnectionsTableProps) { const { t } = useLanguage(); @@ -30,8 +32,10 @@ export function ConnectionsTable({ resizable={true} pagination={true} pageSize={10} - selectable={false} + selectable={true} onRowSelect={onRowSelect} + onDelete={onDelete} + onDeleteMultiple={onDeleteMultiple} actions={actions} className={styles.connectionsTable} /> diff --git a/src/components/Connections/connectionsInterfaces.ts b/src/components/Connections/connectionsInterfaces.ts index 6003b51..61b85cb 100644 --- a/src/components/Connections/connectionsInterfaces.ts +++ b/src/components/Connections/connectionsInterfaces.ts @@ -16,6 +16,8 @@ export interface ConnectionsTableProps { isConnecting?: boolean; isDisconnecting?: boolean; onRowSelect?: (selectedRows: Connection[]) => void; + onDelete?: (connection: Connection) => Promise; + onDeleteMultiple?: (connections: Connection[]) => Promise; } export interface ConnectionEditModalProps { @@ -49,6 +51,7 @@ export interface ConnectionHandlers { handleConnect: (connection: Connection) => Promise; handleDisconnect: (connection: Connection) => Promise; handleDelete: (connection: Connection) => Promise; + handleDeleteMultiple: (connections: Connection[]) => Promise; handleConnectOrDisconnect: (connection: Connection) => Promise; handleEditConnection: (connection: Connection) => Promise; handleSaveConnection: (updatedConnection: Connection) => Promise; diff --git a/src/components/Connections/connectionsLogic.tsx b/src/components/Connections/connectionsLogic.tsx index 8268ae6..872f176 100644 --- a/src/components/Connections/connectionsLogic.tsx +++ b/src/components/Connections/connectionsLogic.tsx @@ -254,6 +254,20 @@ export function useConnectionsLogic(): ConnectionsLogicReturn { } }; + const handleDeleteMultiple = async (connections: Connection[]) => { + const confirmMessage = t('connections.confirm_delete_multiple', 'Are you sure you want to delete {count} connections?').replace('{count}', connections.length.toString()); + + if (window.confirm(confirmMessage)) { + try { + // Delete all connections in parallel + await Promise.all(connections.map(connection => deleteConnection(connection.id))); + await fetchConnections(); + } catch (error) { + console.error('Error deleting multiple connections:', error); + } + } + }; + const handleConnectOrDisconnect = async (connection: Connection) => { if (connection.status === 'active') { await handleDisconnect(connection); @@ -331,6 +345,7 @@ export function useConnectionsLogic(): ConnectionsLogicReturn { handleConnect, handleDisconnect, handleDelete, + handleDeleteMultiple, handleConnectOrDisconnect, handleEditConnection, handleSaveConnection, diff --git a/src/components/Dashboard/DashboardChat/DashboardChatArea.tsx b/src/components/Dashboard/DashboardChat/DashboardChatArea.tsx index bdc84fb..60c2fba 100644 --- a/src/components/Dashboard/DashboardChat/DashboardChatArea.tsx +++ b/src/components/Dashboard/DashboardChat/DashboardChatArea.tsx @@ -23,10 +23,11 @@ const DashboardChatArea: React.FC = ({ /> - {/* Top Right: File Preview */} + {/*Top Right: File Preview (disabled for now)
+ */} {/* Bottom Left: Input Area */}
diff --git a/src/components/Dashboard/DashboardChat/DashboardChatAreaMessageItem.tsx b/src/components/Dashboard/DashboardChat/DashboardChatAreaMessageItem.tsx index 2e75440..f868c14 100644 --- a/src/components/Dashboard/DashboardChat/DashboardChatAreaMessageItem.tsx +++ b/src/components/Dashboard/DashboardChat/DashboardChatAreaMessageItem.tsx @@ -110,6 +110,7 @@ const MessageItem: React.FC = ({ message, onFilePreview }) => )}
+ {/* Preview and Download buttons disabled for now
+ */} ))} diff --git a/src/components/FormGenerator/FormGenerator.tsx b/src/components/FormGenerator/FormGenerator.tsx index aa20456..802673a 100644 --- a/src/components/FormGenerator/FormGenerator.tsx +++ b/src/components/FormGenerator/FormGenerator.tsx @@ -397,7 +397,7 @@ export function FormGenerator>({ title={t('formgen.delete.multiple', `Delete ${selectedRows.size} selected items`)} > - {t('formgen.delete.multiple', `Delete All (${selectedRows.size})`)} + {t('formgen.delete.multiple', `Delete ${selectedRows.size} selected items`).replace('{count}', selectedRows.size.toString())} )} diff --git a/src/components/Mitglieder/MitgliederItem.module.css b/src/components/Mitglieder/MitgliederItem.module.css deleted file mode 100644 index 3b6cf50..0000000 --- a/src/components/Mitglieder/MitgliederItem.module.css +++ /dev/null @@ -1,57 +0,0 @@ -.memberItem { - display: flex; - align-items: center; - height: 70px; - padding: 0px 16px; - justify-content: space-between; - color: var(--color-text); - font-family: var(--font-family); - } - - .userProfile { - margin-right: 12px; - } - - .profileIcon { - font-size: 36px; - color: var(--color-gray-disabled); - } - - .userInfo { - display: grid; - grid-template-columns: 200px 250px 100px; - gap: 16px; - flex-grow: 1; - align-items: center; - } - - .userName { - margin: 0; - font-size: 14px; - color: var(--color-text); - font-family: var(--font-family); - } - - .userEmail, - .userRole { - margin: 0; - font-size: 12px; - font-weight: light; - color: var(--color-gray); - font-family: var(--font-family); - } - - .actions { - display: flex; - align-items: center; - justify-content: center; - } - - .editBtn:hover { - color: var(--color-secondary); - } - - .deleteBtn:hover { - color: var(--color-red); - } - \ No newline at end of file diff --git a/src/components/Mitglieder/MitgliederItem.tsx b/src/components/Mitglieder/MitgliederItem.tsx deleted file mode 100644 index b41d6aa..0000000 --- a/src/components/Mitglieder/MitgliederItem.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { FaUserCircle } from "react-icons/fa"; -import styles from "./MitgliederItem.module.css"; -import MitgliederItemDelete from "./MitgliederItemDelete/MitgliederItemDelete"; -import MitgliederItemEdit from "./MitgliederItemEdit/MitgliederItemEdit"; -import { User } from "../../hooks/useUsers"; - -type MitgliederItemProps = { - user: User; - refetchUsers: () => Promise; - totalUsers: number; - }; - - const MitgliederItem = ({ user, refetchUsers, totalUsers }: MitgliederItemProps) => { - return ( -
  • -
    - -
    -
    - {user.fullName || user.username} - {user.email} - {user.privilege} -
    -
    - - -
    -
  • - ); - }; - - export default MitgliederItem; \ No newline at end of file diff --git a/src/components/Mitglieder/MitgliederItemDelete/DeletePopUp.module.css b/src/components/Mitglieder/MitgliederItemDelete/DeletePopUp.module.css deleted file mode 100644 index b529250..0000000 --- a/src/components/Mitglieder/MitgliederItemDelete/DeletePopUp.module.css +++ /dev/null @@ -1,92 +0,0 @@ -.popupHeader { - display: flex; - justify-content: space-between; - align-items: center; - margin-top:10px; - margin-left: 10px; - margin-right: 10px; - margin-bottom: 5px; - width: 300px; - height: 20px; - color: gray; - font-size: 10px; - -} - -.closeButton { - display: flex; - align-items: center; - background: none; - border: none; - cursor: pointer; - width: 20px; /* Increased button size */ - height: 20px; - line-height: 0; - padding: 0; - margin:0; - -} - -.closeIcon { - width: 100%; /* Make the icon fill the button's width */ - height: 100%; - padding: 0; - margin:0; - display: block; -} - -.horizontalLineLight { - width: 100%; - background-color: #F1F1F1; - height: 1px; -} - -.userInfo { - display: grid; - grid-column: 1; - padding: none; - margin: none; - align-items: center; - justify-content: center; /* Center horizontally */ -} - -.userInfoParagraph{ - display: flex; - color: gray; - font-size: 10px; - margin:0px; - justify-content: center; - gap: 10px; -} -.userInfo h2{ - display: flex; - justify-content: center; - margin: 0; - margin-top:10px; - justify-content: center; -} - -.submitButtonDiv { - margin: 10px; - display: flex; /* Use Flexbox */ - justify-content: center; /* Center horizontally */ - align-items: center; -} -.submitButton { - background: none; - border: 1px solid black; - border-radius: 5px; - padding: 5px 20px; /* Optional: Adds some padding for better button size */ - cursor: pointer; - width: 80% -} - -.submitButton:hover { - background: rgb(168, 18, 18); - border: 1px solid rgb(168, 18, 18); - border-radius: 5px; - padding: 5px 20px; /* Optional: Adds some padding for better button size */ - cursor: pointer; - color: white; - transition: 0.2s; -} \ No newline at end of file diff --git a/src/components/Mitglieder/MitgliederItemDelete/DeletePopUp.tsx b/src/components/Mitglieder/MitgliederItemDelete/DeletePopUp.tsx deleted file mode 100644 index 925ad7d..0000000 --- a/src/components/Mitglieder/MitgliederItemDelete/DeletePopUp.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { IoCloseOutline } from "react-icons/io5"; -import styles from "./DeletePopUp.module.css"; -import { User, useOrgUsers } from "../../../hooks/useUsers"; -import { useState } from "react"; - -type DeletePopUpProps = { - closePopup: () => void; - refetchUsers: () => Promise; - user: User; -}; - -const DeletePopUp = ({ closePopup, refetchUsers, user }: DeletePopUpProps) => { - const { deleteUser } = useOrgUsers(); - const [isDeleting, setIsDeleting] = useState(false); - const [error, setError] = useState(null); - - const handleDelete = async () => { - setIsDeleting(true); - setError(null); - - try { - await deleteUser(user.id); - // Refresh the users list and close the popup - await refetchUsers(); - closePopup(); - } catch (error: any) { - setError(error.message || "Failed to delete user"); - setIsDeleting(false); - } - }; - - return ( -
    -
    -
    -

    Delete User...

    - - -
    -
    - {error &&
    {error}
    } -
    -

    {user.fullName || user.username}

    -
    -

    Email: {user.email}

    -

    Privilege: {user.privilege}

    -
    -
    -
    -
    - -
    - -
    -
    - ) -} - -const popupStyles: { overlay: React.CSSProperties; popup: React.CSSProperties } = { - overlay: { - position: "fixed", - top: 0, - left: 0, - right: 0, - bottom: 0, - backgroundColor: "rgba(0,0,0,0.5)", - display: "flex", - justifyContent: "center", - alignItems: "center", - - }, - popup: { - backgroundColor: "#fff", - borderRadius: "8px", - boxShadow: "0 5px 15px rgba(0,0,0,0.3)", - position: "relative" - } -}; - -export default DeletePopUp; \ No newline at end of file diff --git a/src/components/Mitglieder/MitgliederItemDelete/MitgliederItemDelete.module.css b/src/components/Mitglieder/MitgliederItemDelete/MitgliederItemDelete.module.css deleted file mode 100644 index 6a4c4bf..0000000 --- a/src/components/Mitglieder/MitgliederItemDelete/MitgliederItemDelete.module.css +++ /dev/null @@ -1,33 +0,0 @@ -.deleteBtn { - background: none; - border: none; - cursor: pointer; - font-size: 18px; - color: #444; - height: 100; -} - -.deleteBtn:hover { - color: var(--Brand-Green-Green, #3A8088); -} - -.deleteBtn.disabled { - cursor: not-allowed; - opacity: 0.5; - background: none; - border: none; - cursor: pointer; - font-size: 18px; - color: #444; -} - -.deleteBtn.disabled:hover { - color: #444; -} - -.deleteBtnContainer { - display: flex; - align-items: center; - justify-content: center; - -} diff --git a/src/components/Mitglieder/MitgliederItemDelete/MitgliederItemDelete.tsx b/src/components/Mitglieder/MitgliederItemDelete/MitgliederItemDelete.tsx deleted file mode 100644 index 4bb686f..0000000 --- a/src/components/Mitglieder/MitgliederItemDelete/MitgliederItemDelete.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { FaTrash } from "react-icons/fa"; -import styles from "./MitgliederItemDelete.module.css"; -import { useState } from "react"; -import DeletePopUp from "./DeletePopUp"; -import { User } from "../../../hooks/useUsers"; - -type MitgliederItemDeleteProps = { - user: User; - refetchUsers: () => Promise; - isDisabled?: boolean; -}; - -const MitgliederItemDelete = ({ user, refetchUsers, isDisabled = false }: MitgliederItemDeleteProps) => { - const [deleteWindow, setDeleteWindow] = useState(false); - - return ( -
    - - - {deleteWindow && ( - setDeleteWindow(false)} - refetchUsers={refetchUsers} - /> - )} -
    - ); - }; - - export default MitgliederItemDelete; \ No newline at end of file diff --git a/src/components/Mitglieder/MitgliederItemEdit/EditPopUp.module.css b/src/components/Mitglieder/MitgliederItemEdit/EditPopUp.module.css deleted file mode 100644 index 0faf35d..0000000 --- a/src/components/Mitglieder/MitgliederItemEdit/EditPopUp.module.css +++ /dev/null @@ -1,89 +0,0 @@ -.popupHeader { - display: flex; - justify-content: space-between; - align-items: center; - padding: 15px 20px; -} - -.popupHeader p { - font-size: 1.2rem; - font-weight: 600; - margin: 0; -} - -.closeButton { - background: none; - border: none; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; -} - -.closeIcon { - font-size: 1.5rem; - color: #666; -} - -.horizontalLineLight { - height: 1px; - background-color: #e0e0e0; - width: 100%; - margin: 0; -} - -.form { - box-sizing: border-box; - max-width: 100%; - padding: 20px; -} - -.formGroup { - margin-bottom: 15px; - box-sizing: border-box; -} - -.formGroup label { - display: block; - margin-bottom: 5px; - font-weight: 500; -} - -.formGroup input, -.formGroup select { - width: 100%; - padding: 8px 12px; - border: 1px solid #ddd; - border-radius: 4px; - font-size: 1rem; - box-sizing: border-box; -} - -.submitButtonDiv { - display: flex; - justify-content: flex-end; - padding: 15px 0 10px; -} - -.submitButton { - background-color: #4c9aff; - color: white; - border: none; - border-radius: 4px; - padding: 8px 16px; - font-size: 1rem; - cursor: pointer; - transition: background-color 0.2s; -} - -.submitButton:hover { - background-color: #3d8df5; -} - -.userInfo h2 { - margin-top: 0; - margin-bottom: 10px; -} - - - diff --git a/src/components/Mitglieder/MitgliederItemEdit/EditPopUp.tsx b/src/components/Mitglieder/MitgliederItemEdit/EditPopUp.tsx deleted file mode 100644 index 2041f95..0000000 --- a/src/components/Mitglieder/MitgliederItemEdit/EditPopUp.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import { IoCloseOutline } from "react-icons/io5"; -import { useState } from "react"; -import styles from "./EditPopUp.module.css"; -import { User, useOrgUsers } from "../../../hooks/useUsers"; - -type EditPopUpProps = { - closePopup: () => void; - refetchUsers: () => Promise; - user: User; -}; - -const EditPopUp = ({ closePopup, refetchUsers, user }: EditPopUpProps) => { - const { updateUser } = useOrgUsers(); - const [formData, setFormData] = useState({ - fullName: user.fullName || "", - email: user.email || "", - privilege: user.privilege || "", - username: user.username || "" - }); - const [isSubmitting, setIsSubmitting] = useState(false); - const [error, setError] = useState(null); - - const handleChange = (e: React.ChangeEvent) => { - const { name, value } = e.target; - setFormData(prev => ({ - ...prev, - [name]: value - })); - }; - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setIsSubmitting(true); - setError(null); - - try { - await updateUser(user.id, { - fullName: formData.fullName, - email: formData.email, - privilege: formData.privilege, - username: formData.username - }); - - // Refresh the users list and close the popup - await refetchUsers(); - closePopup(); - } catch (error: any) { - setError(error.message || "Failed to update user"); - } finally { - setIsSubmitting(false); - } - }; - - return ( -
    -
    -
    -

    Edit User

    - -
    -
    - {error &&
    {error}
    } -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    - -
    -
    -
    -
    - ); -}; - -const popupStyles: { overlay: React.CSSProperties; popup: React.CSSProperties } = { - overlay: { - position: "fixed", - top: 0, - left: 0, - right: 0, - bottom: 0, - backgroundColor: "rgba(0,0,0,0.5)", - display: "flex", - justifyContent: "center", - alignItems: "center", - - }, - popup: { - backgroundColor: "#fff", - borderRadius: "8px", - boxShadow: "0 5px 15px rgba(0,0,0,0.3)", - position: "relative", - width: "400px", - maxWidth: "90%" - } -}; - -export default EditPopUp; \ No newline at end of file diff --git a/src/components/Mitglieder/MitgliederItemEdit/MitgliederItemEdit.module.css b/src/components/Mitglieder/MitgliederItemEdit/MitgliederItemEdit.module.css deleted file mode 100644 index 7c91679..0000000 --- a/src/components/Mitglieder/MitgliederItemEdit/MitgliederItemEdit.module.css +++ /dev/null @@ -1,12 +0,0 @@ -.editBtn { - background: none; - border: none; - cursor: pointer; - font-size: 18px; - color: #444; - height: 100; -} - -.editBtn:hover { - color: #3d8df5; -} \ No newline at end of file diff --git a/src/components/Mitglieder/MitgliederItemEdit/MitgliederItemEdit.tsx b/src/components/Mitglieder/MitgliederItemEdit/MitgliederItemEdit.tsx deleted file mode 100644 index aa21877..0000000 --- a/src/components/Mitglieder/MitgliederItemEdit/MitgliederItemEdit.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { FaEdit } from "react-icons/fa"; -import { useState } from "react"; -import styles from "./MitgliederItemEdit.module.css"; -import EditPopUp from "./EditPopUp"; -import { User } from "../../../hooks/useUsers"; - -type MitgliederItemEditProps = { - user: User; - refetchUsers: () => Promise; -}; - -const MitgliederItemEdit = ({ user, refetchUsers }: MitgliederItemEditProps) => { - const [editWindow, setEditWindow] = useState(false); - - return ( -
    - - - {editWindow && ( - setEditWindow(false)} - refetchUsers={refetchUsers} - /> - )} -
    - ); -}; - -export default MitgliederItemEdit; \ No newline at end of file diff --git a/src/components/Mitglieder/MitgliederTable.module.css b/src/components/Mitglieder/MitgliederTable.module.css new file mode 100644 index 0000000..cf676b0 --- /dev/null +++ b/src/components/Mitglieder/MitgliederTable.module.css @@ -0,0 +1,64 @@ +/* Main table container */ +.mitgliederTable { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + gap: 20px; +} + +/* FormGenerator container */ +.mitgliederFormGenerator { + flex: 1; + min-height: 0; +} + +/* Error state styling */ +.errorState { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 40px; + gap: 20px; + color: var(--color-text); + font-family: var(--font-family); + text-align: center; +} + +.retryButton { + padding: 10px 20px; + border: 1px solid var(--color-primary); + border-radius: 20px; + background: var(--color-bg); + color: var(--color-text); + cursor: pointer; + transition: all 0.2s ease; + font-family: var(--font-family); +} + +.retryButton:hover { + background: var(--color-primary); + color: var(--color-bg); +} + +/* User-specific formatting */ +.userName { + font-weight: 500; + color: var(--color-text); +} + +.userFullName { + color: var(--color-text); +} + +.userEmail { + color: var(--color-gray); + font-size: 0.9em; +} + +.userLanguage { + color: var(--color-text); + font-size: 0.85em; +} + \ No newline at end of file diff --git a/src/components/Mitglieder/MitgliederTable.tsx b/src/components/Mitglieder/MitgliederTable.tsx new file mode 100644 index 0000000..9b3d7fa --- /dev/null +++ b/src/components/Mitglieder/MitgliederTable.tsx @@ -0,0 +1,50 @@ +import { FormGenerator } from '../FormGenerator/FormGenerator'; +import { useMitgliederLogic } from './mitgliederLogic'; +import { MitgliederTableProps } from './mitgliederTypes'; +import { useLanguage } from '../../contexts/LanguageContext'; +import styles from './MitgliederTable.module.css'; + +function MitgliederTable({ className = '' }: MitgliederTableProps) { + const { t } = useLanguage(); + const { + users, + loading, + error, + columns, + actions, + refetch + } = useMitgliederLogic(); + + if (error) { + return ( +
    +

    {t('users.error.loading', 'Error loading users:')} {error}

    + +
    + ); + } + + return ( +
    + +
    + ); +} + +export default MitgliederTable; \ No newline at end of file diff --git a/src/components/Mitglieder/index.ts b/src/components/Mitglieder/index.ts new file mode 100644 index 0000000..82b1d4f --- /dev/null +++ b/src/components/Mitglieder/index.ts @@ -0,0 +1,3 @@ +export { default as MitgliederTable } from './MitgliederTable'; +export { useMitgliederLogic } from './mitgliederLogic'; +export type * from './mitgliederTypes'; diff --git a/src/components/Mitglieder/mitgliederLogic.tsx b/src/components/Mitglieder/mitgliederLogic.tsx new file mode 100644 index 0000000..e188a73 --- /dev/null +++ b/src/components/Mitglieder/mitgliederLogic.tsx @@ -0,0 +1,107 @@ +import React, { useMemo } from 'react'; + +import { useOrgUsers, User } from '../../hooks/useUsers'; +import { useLanguage } from '../../contexts/LanguageContext'; + +import type { + MitgliederLogicReturn, + UserActionConfig, + UserColumnConfig +} from './mitgliederTypes'; + +export function useMitgliederLogic(): MitgliederLogicReturn { + const { users, loading, error, refetch, deleteUser } = useOrgUsers(); + const { t } = useLanguage(); + + // Configure columns for the users table + const columns: UserColumnConfig[] = useMemo(() => [ + { + key: 'username', + label: t('users.column.username', 'Username'), + type: 'string', + width: 150, + minWidth: 120, + maxWidth: 200, + sortable: true, + filterable: true, + searchable: true, + formatter: (value: string | undefined) => ( + + {value || t('users.noUsername', 'No Username')} + + ) + }, + { + key: 'fullName', + label: t('users.column.name', 'Name'), + type: 'string', + width: 200, + minWidth: 150, + maxWidth: 300, + sortable: true, + filterable: true, + searchable: true, + formatter: (value: string | undefined) => ( + + {value || t('users.noName', 'No Name')} + + ) + }, + { + key: 'email', + label: t('users.column.email', 'Email'), + type: 'string', + width: 250, + minWidth: 200, + maxWidth: 350, + sortable: true, + filterable: true, + searchable: true, + formatter: (value: string | undefined) => ( + + {value || t('users.noEmail', 'No Email')} + + ) + }, + { + key: 'language', + label: t('users.column.language', 'Language'), + type: 'enum', + width: 120, + minWidth: 100, + maxWidth: 150, + sortable: true, + filterable: true, + filterOptions: ['en', 'de', 'fr'], + formatter: (value: string | undefined) => { + const languageMap: Record = { + 'en': t('language.english', 'English'), + 'de': t('language.german', 'Deutsch'), + 'fr': t('language.french', 'Français') + }; + return ( + + {value ? languageMap[value] || value : t('users.noLanguage', 'No Language')} + + ); + } + } + ], [t]); + + // Configure action buttons (empty for now) + const actions: UserActionConfig[] = useMemo(() => [], []); + + return { + // Data + users, + loading, + error, + + // Refetch function + refetch, + + // Additional data for rendering + columns, + actions + }; +} diff --git a/src/components/Mitglieder/mitgliederTypes.ts b/src/components/Mitglieder/mitgliederTypes.ts new file mode 100644 index 0000000..4e8c4f2 --- /dev/null +++ b/src/components/Mitglieder/mitgliederTypes.ts @@ -0,0 +1,44 @@ +import React from 'react'; +import { User } from '../../hooks/useUsers'; + +// Props for the MitgliederTable component +export interface MitgliederTableProps { + className?: string; +} + +// Action configuration for user actions +export interface UserActionConfig { + label: string; + icon: (row: User) => React.ReactElement; + onClick: (row: User) => void; +} + +// Column configuration for the users table +export interface UserColumnConfig { + key: string; + label: string; + type: 'string' | 'number' | 'date' | 'boolean' | 'enum'; + width: number; + minWidth: number; + maxWidth: number; + sortable: boolean; + filterable: boolean; + searchable?: boolean; + filterOptions?: string[]; + formatter: (value: any, row?: any) => React.ReactElement | string; +} + +// Return type for the mitglieder logic hook +export interface MitgliederLogicReturn { + // Data + users: User[]; + loading: boolean; + error: string | null; + + // Refetch function + refetch: () => Promise; + + // Additional data for rendering + columns: UserColumnConfig[]; + actions: UserActionConfig[]; +} diff --git a/src/components/PageManager/pageConfigs.ts b/src/components/PageManager/pageConfigs.ts index d59441e..13930c3 100644 --- a/src/components/PageManager/pageConfigs.ts +++ b/src/components/PageManager/pageConfigs.ts @@ -6,6 +6,7 @@ import { MdOutlineWorkOutline } from 'react-icons/md'; import { LuWorkflow, LuTicket } from "react-icons/lu"; import { GoGear } from "react-icons/go"; import { FaPlug, FaRegFileAlt, FaShare } from "react-icons/fa"; +import { LuMessageSquareText } from "react-icons/lu"; // Lazy load components for better performance const Dashboard = lazy(() => import('../../pages/Home/Dashboard')); @@ -15,6 +16,7 @@ const Connections = lazy(() => import('../../pages/Home/Connections')); const Workflows = lazy(() => import('../../pages/Home/Workflows')); const Einstellungen = lazy(() => import('../../pages/Home/Einstellungen')); const TestSharepoint = lazy(() => import('../../pages/Home/TestSharepoint')); +const Prompts = lazy(() => import('../../pages/Home/Prompts')); // Page configuration with caching and lifecycle settings export const pageConfigs: PageConfig[] = [ @@ -61,6 +63,28 @@ export const pageConfigs: PageConfig[] = [ if (import.meta.env.DEV) console.log('Dateien unloaded - cleanup file references'); } }, + { + path: 'prompts', + component: Prompts, + persistent: false, + preload: true, + moduleEnabled: true, + // Sidebar properties + id: '4', + name: 'Prompts', + icon: LuMessageSquareText , + order: 3, + showInSidebar: true, + onActivate: async () => { + if (import.meta.env.DEV) console.log('Prompts activated'); + }, + onLoad: async () => { + if (import.meta.env.DEV) console.log('Prompts loaded - can initialize prompts here'); + }, + onUnload: async () => { + if (import.meta.env.DEV) console.log('Prompts unloaded - cleanup prompts references'); + } + }, { path: 'team-bereich', component: TeamBereich, @@ -103,7 +127,7 @@ export const pageConfigs: PageConfig[] = [ preload: true, // Preload workflows for better performance moduleEnabled: true, // Sidebar properties - id: '4', + id: '6', name: 'Workflows', icon: LuWorkflow, order: 3, diff --git a/src/components/Popup/EditForm.module.css b/src/components/Popup/EditForm.module.css index 05e8290..1f3f3c4 100644 --- a/src/components/Popup/EditForm.module.css +++ b/src/components/Popup/EditForm.module.css @@ -44,6 +44,35 @@ box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1); } +/* Textarea styling */ +.fieldTextarea { + width: 100%; + padding: 12px 12px 8px 12px; + border: 1px solid var(--color-primary); + border-radius: 25px; + font-size: 14px; + transition: all 0.2s ease; + background-color: var(--color-bg); + box-sizing: border-box; + color: var(--color-text); + font-family: inherit; + line-height: 1.5; + overflow-y: auto; + resize: vertical; + min-height: 4em; + max-height: 8em; +} + +.fieldTextarea:focus { + outline: none; + border-color: var(--color-secondary); +} + +.fieldTextarea.fieldError { + border-color: #ef4444; + box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1); +} + /* Floating label styles */ .label { position: absolute; diff --git a/src/components/Popup/EditForm.tsx b/src/components/Popup/EditForm.tsx index 25d8a39..22974fb 100644 --- a/src/components/Popup/EditForm.tsx +++ b/src/components/Popup/EditForm.tsx @@ -5,13 +5,15 @@ import styles from './EditForm.module.css'; export interface EditFieldConfig { key: string; label: string; - type: 'string' | 'email' | 'date' | 'enum' | 'boolean' | 'readonly'; + type: 'string' | 'email' | 'date' | 'enum' | 'boolean' | 'readonly' | 'textarea'; editable: boolean; required?: boolean; options?: string[]; // For enum types formatter?: (value: any) => string; // For display formatting validator?: (value: any) => string | null; // Returns error message or null placeholder?: string; + minRows?: number; // For textarea types + maxRows?: number; // For textarea types } // EditForm props @@ -46,7 +48,29 @@ export function EditForm>({ setEditedData({ ...data }); setErrors({}); setFieldFocused({}); - }, [data]); + + // Initialize textarea heights for textarea fields + setTimeout(() => { + fields.forEach(field => { + if (field.type === 'textarea') { + const textarea = document.querySelector(`textarea[name="${field.key}"]`) as HTMLTextAreaElement; + if (textarea) { + const minRows = field.minRows || 4; + const maxRows = field.maxRows || 8; + textarea.style.height = 'auto'; + const newHeight = Math.max( + minRows * 1.5 * 16, + Math.min( + textarea.scrollHeight, + maxRows * 1.5 * 16 + ) + ); + textarea.style.height = `${newHeight}px`; + } + } + }); + }, 0); + }, [data, fields]); // Handle field focus const handleFieldFocus = (fieldKey: string, focused: boolean) => { @@ -194,6 +218,44 @@ export function EditForm>({ ); } + // Handle textarea type + if (field.type === 'textarea') { + const minRows = field.minRows || 4; + const maxRows = field.maxRows || 8; + + return ( +
    +