diff --git a/src/components/Sidebar/sidebarData.tsx b/src/components/Sidebar/sidebarData.tsx
index f4bcb02..d7f3dde 100644
--- a/src/components/Sidebar/sidebarData.tsx
+++ b/src/components/Sidebar/sidebarData.tsx
@@ -6,11 +6,11 @@ import { BiInfoSquare } from "react-icons/bi";
import { GoGear } from "react-icons/go";
import { FaRegFileAlt } from "react-icons/fa";
import { TbLogs } from "react-icons/tb";
-import { useUserPrompts } from '../../auth/Hooks/use-user-prompts';
+
import { useMemo } from 'react';
export const useSidebarData = () => {
- const { prompts, loading } = useUserPrompts();
+
return useMemo(() => [
{
@@ -23,11 +23,7 @@ export const useSidebarData = () => {
id: '2',
name: 'Prompts',
icon: BsChatDots,
- submenu: loading ? [] : prompts.map(prompt => ({
- id: `prompt-${prompt.id}`,
- name: prompt.prompt_title.substring(0, 100),
- link: `/dashboard?expandedPrompt=${prompt.id}`,
- })),
+ submenu: [],
},
{
id: '3',
@@ -71,7 +67,7 @@ export const useSidebarData = () => {
link: '',
icon: BiInfoSquare,
},
- ], [prompts, loading]);
+ ], []);
}
export default useSidebarData;
\ No newline at end of file
diff --git a/src/hooks/use-file-operations.ts b/src/hooks/use-file-operations.ts
deleted file mode 100644
index cdb409e..0000000
--- a/src/hooks/use-file-operations.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import { useState } from 'react';
-import { useAuthToken } from '../auth/Hooks/use-auth-token';
-import { downloadFile } from '../api';
-import { authorizedDelete } from '../api';
-
-export type FileOperationState = {
- downloadingFiles: Set
;
- downloadError: string | null;
- deletingFiles: Set;
- deleteError: string | null;
-};
-
-export const useFileOperations = () => {
- const [downloadingFiles, setDownloadingFiles] = useState>(new Set());
- const [downloadError, setDownloadError] = useState(null);
- const [deletingFiles, setDeletingFiles] = useState>(new Set());
- const [deleteError, setDeleteError] = useState(null);
- const { getToken } = useAuthToken();
-
- const handleFileDownload = async (fileId: number, fileName: string) => {
- try {
- setDownloadError(null);
- setDownloadingFiles(prev => new Set(prev).add(fileId));
-
- await downloadFile(fileId, getToken);
-
- } catch (error) {
- console.error('Error downloading file:', error);
- setDownloadError('Failed to download file. Please try again.');
- } finally {
- setDownloadingFiles(prev => {
- const newSet = new Set(prev);
- newSet.delete(fileId);
- return newSet;
- });
- }
- };
-
- const handleFileDelete = async (fileId: number) => {
- try {
- setDeleteError(null);
- setDeletingFiles(prev => new Set(prev).add(fileId));
-
- await authorizedDelete(`/api/user/files/${fileId}`, getToken);
-
- // Return true to indicate successful deletion
- return true;
- } catch (error) {
- console.error('Error deleting file:', error);
- setDeleteError('Failed to delete file. Please try again.');
- return false;
- } finally {
- setDeletingFiles(prev => {
- const newSet = new Set(prev);
- newSet.delete(fileId);
- return newSet;
- });
- }
- };
-
- return {
- downloadingFiles,
- downloadError,
- deletingFiles,
- deleteError,
- handleFileDownload,
- handleFileDelete,
- clearDownloadError: () => setDownloadError(null),
- clearDeleteError: () => setDeleteError(null)
- };
-};
\ No newline at end of file
diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts
new file mode 100644
index 0000000..13fd158
--- /dev/null
+++ b/src/hooks/useAuth.ts
@@ -0,0 +1,92 @@
+import { useState } from 'react';
+import axios from 'axios';
+
+interface LoginResponse {
+ accessToken: string;
+ tokenType: string;
+ label?: any;
+ fieldLabels?: any;
+}
+
+interface UseAuthReturn {
+ login: (username: string, password: string) => Promise;
+ error: string | null;
+ isLoading: boolean;
+}
+
+export function useAuth(): UseAuthReturn {
+ const [error, setError] = useState(null);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const login = async (username: string, password: string): Promise => {
+ setIsLoading(true);
+ setError(null);
+
+ try {
+ // Create the form data in the exact format FastAPI expects
+ const params = new URLSearchParams();
+ params.append('username', username);
+ params.append('password', password);
+ params.append('grant_type', 'password');
+ params.append('scope', '');
+ params.append('client_id', '');
+ params.append('client_secret', '');
+
+ // Create a custom axios instance for this request
+ const instance = axios.create({
+ baseURL: 'http://127.0.0.1:8000',
+ withCredentials: true,
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded'
+ }
+ });
+
+ const response = await instance.post('/api/token', params);
+
+ console.log('Login response:', response.data);
+
+ // Store the entire auth response
+ if (response.data.accessToken) {
+ localStorage.setItem('auth_data', JSON.stringify(response.data));
+ }
+
+ return response.data;
+ } catch (error: any) {
+ let errorMessage = 'An error occurred during login';
+
+ if (error.response) {
+ // Log the complete error details including the request that was sent
+ console.error('Login error details:', {
+ status: error.response.status,
+ statusText: error.response.statusText,
+ data: error.response.data,
+ headers: error.response.headers,
+ request: {
+ url: error.config?.url,
+ method: error.config?.method,
+ data: error.config?.data,
+ params: error.config?.params
+ }
+ });
+ errorMessage = error.response.data?.detail || 'Invalid username or password';
+ } else if (error.request) {
+ console.error('No response received:', error.request);
+ errorMessage = 'No response received from server';
+ } else {
+ console.error('Error:', error.message);
+ errorMessage = error.message;
+ }
+
+ setError(errorMessage);
+ throw error;
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return {
+ login,
+ error,
+ isLoading
+ };
+}
\ No newline at end of file
diff --git a/src/hooks/useCurrentUser.ts b/src/hooks/useCurrentUser.ts
new file mode 100644
index 0000000..7d8c99d
--- /dev/null
+++ b/src/hooks/useCurrentUser.ts
@@ -0,0 +1,60 @@
+import { useState, useEffect } from 'react';
+import api from '../api';
+
+interface CurrentUser {
+ id: number;
+ username: string;
+ fullName: string;
+ email: string;
+ privilege: string;
+ mandateId: number;
+}
+
+interface UseCurrentUserReturn {
+ user: CurrentUser | null;
+ error: string | null;
+ isLoading: boolean;
+ refetch: () => Promise;
+}
+
+export function useCurrentUser(): UseCurrentUserReturn {
+ const [user, setUser] = useState(null);
+ const [error, setError] = useState(null);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const fetchCurrentUser = async () => {
+ setIsLoading(true);
+ setError(null);
+
+ try {
+ const response = await api.get('/api/user/me');
+ setUser(response.data);
+ } catch (error: any) {
+ let errorMessage = 'Fehler beim Abrufen des Benutzerprofils';
+
+ if (error.response) {
+ errorMessage = error.response.data?.detail || error.response.data?.message || errorMessage;
+ } else if (error.request) {
+ errorMessage = 'Keine Antwort vom Server erhalten';
+ } else {
+ errorMessage = error.message || errorMessage;
+ }
+
+ setError(errorMessage);
+ setUser(null);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ fetchCurrentUser();
+ }, []);
+
+ return {
+ user,
+ error,
+ isLoading,
+ refetch: fetchCurrentUser
+ };
+}
\ No newline at end of file
diff --git a/src/hooks/useMsalAuth.ts b/src/hooks/useMsalAuth.ts
new file mode 100644
index 0000000..89ba817
--- /dev/null
+++ b/src/hooks/useMsalAuth.ts
@@ -0,0 +1,102 @@
+import { useState } from 'react';
+import { useMsal } from '@azure/msal-react';
+import api from '../api';
+
+interface MsalAuthResponse {
+ accessToken: string;
+ tokenType: string;
+ user: {
+ username: string;
+ email: string;
+ fullName: string;
+ mandateId: number;
+ };
+}
+
+interface UseMsalAuthReturn {
+ loginWithMsal: () => Promise;
+ error: string | null;
+ isLoading: boolean;
+}
+
+export function useMsalAuth(): UseMsalAuthReturn {
+ const { instance, accounts } = useMsal();
+ const [error, setError] = useState(null);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const loginWithMsal = async (): Promise => {
+ setIsLoading(true);
+ setError(null);
+
+ try {
+ let msalToken;
+
+ // If we have an account, try to get the token silently
+ if (accounts.length > 0) {
+ const silentRequest = {
+ scopes: ['user.read'],
+ account: accounts[0]
+ };
+
+ try {
+ const response = await instance.acquireTokenSilent(silentRequest);
+ msalToken = response.accessToken;
+ } catch (e) {
+ // If silent token acquisition fails, fall back to popup
+ const response = await instance.acquireTokenPopup(silentRequest);
+ msalToken = response.accessToken;
+ }
+ } else {
+ // No account, do popup login
+ const response = await instance.loginPopup({
+ scopes: ['user.read']
+ });
+
+ if (response.account) {
+ const tokenResponse = await instance.acquireTokenSilent({
+ scopes: ['user.read'],
+ account: response.account
+ });
+ msalToken = tokenResponse.accessToken;
+ } else {
+ throw new Error('Failed to get account after login');
+ }
+ }
+
+ // Exchange MSAL token for backend token
+ const response = await api.post('/api/msft/token', null, {
+ headers: {
+ 'Authorization': `Bearer ${msalToken}`
+ }
+ });
+
+ // Store the backend token
+ if (response.data.accessToken) {
+ localStorage.setItem('auth_data', JSON.stringify(response.data));
+ }
+
+ return response.data;
+ } catch (error: any) {
+ let errorMessage = 'MSAL Login fehlgeschlagen';
+
+ if (error.response) {
+ errorMessage = error.response.data?.detail || error.response.data?.message || errorMessage;
+ } else if (error.request) {
+ errorMessage = 'Keine Antwort vom Server erhalten';
+ } else {
+ errorMessage = error.message || errorMessage;
+ }
+
+ setError(errorMessage);
+ throw new Error(errorMessage);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return {
+ loginWithMsal,
+ error,
+ isLoading
+ };
+}
\ No newline at end of file
diff --git a/src/hooks/useMsalRegister.ts b/src/hooks/useMsalRegister.ts
new file mode 100644
index 0000000..6f1a0ce
--- /dev/null
+++ b/src/hooks/useMsalRegister.ts
@@ -0,0 +1,94 @@
+import { useState } from 'react';
+import { useMsal } from '@azure/msal-react';
+import api from '../api';
+
+interface MsalRegisterData {
+ username: string;
+ email: string;
+ fullName: string;
+ language?: string;
+}
+
+interface MsalRegisterResponse {
+ success: boolean;
+ message?: string;
+ user?: {
+ username: string;
+ email: string;
+ fullName: string;
+ };
+}
+
+interface UseMsalRegisterReturn {
+ registerWithMsal: () => Promise;
+ error: string | null;
+ isLoading: boolean;
+}
+
+export function useMsalRegister(): UseMsalRegisterReturn {
+ const { instance, accounts } = useMsal();
+ const [error, setError] = useState(null);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const registerWithMsal = async (): Promise => {
+ setIsLoading(true);
+ setError(null);
+
+ try {
+ if (!accounts || accounts.length === 0) {
+ // If not signed in with Microsoft, sign in first
+ await instance.loginPopup({
+ scopes: ['user.read']
+ });
+ }
+
+ // Get the current account
+ const currentAccount = instance.getAllAccounts()[0];
+ if (!currentAccount) {
+ throw new Error('No Microsoft account found');
+ }
+
+ // Prepare user data from Microsoft account
+ const userData: MsalRegisterData = {
+ username: currentAccount.username,
+ email: currentAccount.username,
+ fullName: currentAccount.name || currentAccount.username,
+ language: 'de'
+ };
+
+ // Register the user through our backend
+ const response = await api.post('/api/users/register-with-msal', userData, {
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ });
+
+ return {
+ success: true,
+ message: 'Registration successful',
+ user: response.data
+ };
+ } catch (error: any) {
+ let errorMessage = 'MSAL Registrierung fehlgeschlagen';
+
+ if (error.response) {
+ errorMessage = error.response.data?.detail || error.response.data?.message || errorMessage;
+ } else if (error.request) {
+ errorMessage = 'Keine Antwort vom Server erhalten';
+ } else {
+ errorMessage = error.message || errorMessage;
+ }
+
+ setError(errorMessage);
+ throw new Error(errorMessage);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return {
+ registerWithMsal,
+ error,
+ isLoading
+ };
+}
\ No newline at end of file
diff --git a/src/hooks/useRegister.ts b/src/hooks/useRegister.ts
new file mode 100644
index 0000000..4417f00
--- /dev/null
+++ b/src/hooks/useRegister.ts
@@ -0,0 +1,82 @@
+import { useState } from 'react';
+import api from '../api';
+
+interface RegisterData {
+ username: string;
+ password: string;
+ email: string;
+ fullName: string;
+ language?: string;
+}
+
+interface RegisterResponse {
+ success: boolean;
+ message?: string;
+ user?: {
+ username: string;
+ email: string;
+ fullName: string;
+ };
+}
+
+interface UseRegisterReturn {
+ register: (data: RegisterData) => Promise;
+ error: string | null;
+ isLoading: boolean;
+}
+
+export function useRegister(): UseRegisterReturn {
+ const [error, setError] = useState(null);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const register = async (userData: RegisterData): Promise => {
+ setIsLoading(true);
+ setError(null);
+
+ try {
+ // Add default language if not provided
+ const dataToSend = {
+ ...userData,
+ language: userData.language || 'de'
+ };
+
+ const response = await api.post('/api/users/register', dataToSend, {
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ });
+
+ return {
+ success: true,
+ message: 'Registration successful',
+ user: response.data
+ };
+ } catch (error: any) {
+ let errorMessage = 'Registrierung fehlgeschlagen';
+
+ // Handle different types of errors
+ if (error.response) {
+ // The request was made and the server responded with a status code
+ // that falls out of the range of 2xx
+ errorMessage = error.response.data?.detail || error.response.data?.message || errorMessage;
+ } else if (error.request) {
+ // The request was made but no response was received
+ errorMessage = 'Keine Antwort vom Server erhalten';
+ } else {
+ // Something happened in setting up the request
+ errorMessage = error.message || errorMessage;
+ }
+
+ setError(errorMessage);
+ throw new Error(errorMessage);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return {
+ register,
+ error,
+ isLoading
+ };
+}
\ No newline at end of file
diff --git a/src/hooks/useUser.ts b/src/hooks/useUser.ts
new file mode 100644
index 0000000..aefd67d
--- /dev/null
+++ b/src/hooks/useUser.ts
@@ -0,0 +1,105 @@
+import { useState } from 'react';
+import api from '../api';
+
+interface User {
+ id: number;
+ username: string;
+ email: string;
+ fullName: string;
+ mandateId: number;
+}
+
+interface UseUserReturn {
+ deleteUser: (userId: number) => Promise;
+ updateUser: (userId: number, userData: Partial) => Promise;
+ getUser: (userId: number) => Promise;
+ error: string | null;
+ isLoading: boolean;
+}
+
+export function useUser(): UseUserReturn {
+ const [error, setError] = useState(null);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const deleteUser = async (userId: number): Promise => {
+ setIsLoading(true);
+ setError(null);
+
+ try {
+ await api.delete(`/api/users/${userId}`);
+ } catch (error: any) {
+ let errorMessage = 'Fehler beim Löschen des Benutzers';
+
+ if (error.response) {
+ errorMessage = error.response.data?.detail || error.response.data?.message || errorMessage;
+ } else if (error.request) {
+ errorMessage = 'Keine Antwort vom Server erhalten';
+ } else {
+ errorMessage = error.message || errorMessage;
+ }
+
+ setError(errorMessage);
+ throw new Error(errorMessage);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const updateUser = async (userId: number, userData: Partial): Promise => {
+ setIsLoading(true);
+ setError(null);
+
+ try {
+ const response = await api.put(`/api/users/${userId}`, userData);
+ return response.data;
+ } catch (error: any) {
+ let errorMessage = 'Fehler beim Aktualisieren des Benutzers';
+
+ if (error.response) {
+ errorMessage = error.response.data?.detail || error.response.data?.message || errorMessage;
+ } else if (error.request) {
+ errorMessage = 'Keine Antwort vom Server erhalten';
+ } else {
+ errorMessage = error.message || errorMessage;
+ }
+
+ setError(errorMessage);
+ throw new Error(errorMessage);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const getUser = async (userId: number): Promise => {
+ setIsLoading(true);
+ setError(null);
+
+ try {
+ const response = await api.get(`/api/users/${userId}`);
+ return response.data;
+ } catch (error: any) {
+ let errorMessage = 'Fehler beim Abrufen des Benutzers';
+
+ if (error.response) {
+ errorMessage = error.response.data?.detail || error.response.data?.message || errorMessage;
+ } else if (error.request) {
+ errorMessage = 'Keine Antwort vom Server erhalten';
+ } else {
+ errorMessage = error.message || errorMessage;
+ }
+
+ setError(errorMessage);
+ throw new Error(errorMessage);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return {
+ deleteUser,
+ updateUser,
+ getUser,
+ error,
+ isLoading
+ };
+}
\ No newline at end of file
diff --git a/src/main.tsx b/src/main.tsx
index dc9f4a9..19602fe 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,7 +1,7 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
-import { AuthProvider } from './auth/Hooks/auth-provider.tsx';
+import { AuthProvider } from './auth/auth-provider.tsx';
createRoot(document.getElementById('root')!).render(
diff --git a/src/pages/Home/Home.module.css b/src/pages/Home.module.css
similarity index 100%
rename from src/pages/Home/Home.module.css
rename to src/pages/Home.module.css
diff --git a/src/pages/Home/Home.tsx b/src/pages/Home.tsx
similarity index 95%
rename from src/pages/Home/Home.tsx
rename to src/pages/Home.tsx
index 287b752..7831a64 100644
--- a/src/pages/Home/Home.tsx
+++ b/src/pages/Home.tsx
@@ -3,7 +3,7 @@ import { Outlet, useLocation } from 'react-router-dom';
import styles from './Home.module.css'
-import Sidebar from '../../components/Sidebar';
+import Sidebar from '../components/Sidebar';
import { AnimatePresence, motion } from "framer-motion";
diff --git a/src/pages/Home/Dashboard/Dashboard.module.css b/src/pages/Home/Dashboard/Dashboard.module.css
deleted file mode 100644
index 9df9361..0000000
--- a/src/pages/Home/Dashboard/Dashboard.module.css
+++ /dev/null
@@ -1,4 +0,0 @@
-.dashboardContainer {
- margin: 51px 49px 0 36px;
-
-}
\ No newline at end of file
diff --git a/src/pages/Home/Dashboard/Dashboard.tsx b/src/pages/Home/Dashboard/Dashboard.tsx
deleted file mode 100644
index 9d9b929..0000000
--- a/src/pages/Home/Dashboard/Dashboard.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import DashboardPrompt from '../../../components/DashboardPrompts/DashboardPrompt';
-
-import styles from './Dashboard.module.css'
-
-function Dashboard () {
- return (
-
-
-
- );
-}
-
-export default Dashboard;
diff --git a/src/pages/Home/Dateien/Dateien.module.css b/src/pages/Home/Dateien/Dateien.module.css
deleted file mode 100644
index 8d545a0..0000000
--- a/src/pages/Home/Dateien/Dateien.module.css
+++ /dev/null
@@ -1,90 +0,0 @@
-.dateienContainer {
- margin: 51px 49px 0 36px;
- display: flex;
- padding: 0px 30px 30px 30px;
- flex-direction: column;
- align-self: stretch;
- border-radius: 30px;
- border: 1px solid var(--f-1-f-1-f-1, #F1F1F1);
- background: var(--Grayscale-True-White, #FFF);
- position: relative;
- box-shadow: 0px 2px 6px 0px rgba(194, 194, 194, 0.10);
- max-height: calc(100vh - 100px);
- overflow: hidden;
-}
-
-.horizontalLineLight {
- width: 100%;
- background-color: #F1F1F1;
- height: 1px;
- margin-top: 90px;
- margin-left: -30px;
- position: absolute;
-}
-
-.header {
- display: flex;
- gap: 30px;
- align-items: flex-start;
- height: 62px;
- color: var(--Grayscale-Black, #24262B);
- padding-top: 30px;
-}
-
-.datei_hinzufügen_button {
- border-radius: 30px;
- background: var(--Grayscale-Gray, #E9E9E9);
- border: none;
- outline: none;
- text-align: left;
- padding-left: 20px;
- padding-right: 20px;
- padding-top: 10px;
- padding-bottom: 10px;
- display: flex;
- gap: 10px;
- align-items: center;
-}
-
-.datei_hinzufügen_button:hover {
- cursor: pointer;
-
-}
-
-.add_icon {
- font-size: 16px;
-}
-
-.filesList {
- list-style: none;
- padding: 0;
- margin: 0;
- width: 100%;
- overflow-y: auto;
-}
-
-.filesList li {
- display: flex;
- align-items: center;
- height: 60px; /* Specific height for each item */
- padding: 0 16px;
- border-bottom: 1px solid #F1F1F1;
- font-size: 16px;
- transition: background-color 0.2s ease;
- }
-
-.actions {
- display: flex;
- gap: 10px;
- align-items: center;
- justify-content: center;
- }
-
-.error {
- color: #d32f2f;
- margin: 1rem 0;
- padding: 0.5rem;
- background-color: #ffebee;
- border-radius: 4px;
- text-align: center;
-}
\ No newline at end of file
diff --git a/src/pages/Home/Dateien/Dateien.tsx b/src/pages/Home/Dateien/Dateien.tsx
deleted file mode 100644
index 339c7d6..0000000
--- a/src/pages/Home/Dateien/Dateien.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import styles from './Dateien.module.css'
-import { useUserFiles } from '../../../auth/Hooks/use-user-files';
-import { IoAddCircleOutline } from "react-icons/io5";
-import DateienItem from '../../../components/Dateien/DateienItem';
-import DateienUpload from './DateienHinzufügen/DateienUpload';
-import { useState } from 'react';
-import { useAuthToken } from '../../../auth/Hooks/use-auth-token';
-import { useFileOperations } from '../../../hooks/use-file-operations';
-import axios from 'axios';
-
-function Dateien() {
- const { files, loading, error, refetch } = useUserFiles();
- const [isUploadOpen, setIsUploadOpen] = useState(false);
- const [uploadError, setUploadError] = useState(null);
- const { getToken } = useAuthToken();
- const { downloadError, deleteError } = useFileOperations();
-
- const handleFileUpload = async (file: File) => {
- try {
- setUploadError(null);
- console.log('Starting file upload for:', file.name);
-
- const token = await getToken();
- console.log('Got authentication token');
-
- const formData = new FormData();
- formData.append('file', file);
-
- console.log('Sending request to backend...');
- const response = await axios.post('http://localhost:8000/api/user/files/upload', formData, {
- headers: {
- 'Content-Type': 'multipart/form-data',
- 'Authorization': `Bearer ${token}`
- }
- });
-
- console.log('Upload successful:', response.data);
- await refetch();
- } catch (error: any) {
- console.error('Error uploading file:', error);
- console.error('Error response:', error.response?.data);
- setUploadError(error.response?.data?.detail || 'Failed to upload file. Please try again.');
- }
- };
-
- const handleFileDeleted = () => {
- refetch();
- };
-
- return (
-
-
-
-
-
-
-
setIsUploadOpen(false)}
- onFileUpload={handleFileUpload}
- />
-
- {(uploadError || downloadError || deleteError) && (
-
- {uploadError || downloadError || deleteError}
-
- )}
- {loading && Loading files...
}
- {error && Error: {error}
}
-
- {!loading && !error && files.length === 0 ? (
- No files found.
- ) : (
-
- {files.map(file => (
-
- ))}
-
- )}
-
- );
-}
-
-export default Dateien;
diff --git a/src/pages/Home/Dateien/DateienHinzufügen/DateienUpload.module.css b/src/pages/Home/Dateien/DateienHinzufügen/DateienUpload.module.css
deleted file mode 100644
index b894849..0000000
--- a/src/pages/Home/Dateien/DateienHinzufügen/DateienUpload.module.css
+++ /dev/null
@@ -1,101 +0,0 @@
-.overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.5);
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: 1000;
-}
-
-.modal {
- background: white;
- padding: 2rem;
- border-radius: 8px;
- width: 90%;
- max-width: 500px;
- position: relative;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
-}
-
-.closeButton {
- position: absolute;
- top: 1rem;
- right: 1rem;
- background: none;
- border: none;
- font-size: 1.5rem;
- cursor: pointer;
- color: #666;
-}
-
-.closeButton:hover {
- color: #333;
-}
-
-.dropzone {
- border: 2px dashed #ccc;
- border-radius: 4px;
- padding: 2rem;
- text-align: center;
- cursor: pointer;
- margin: 1rem 0;
- transition: all 0.3s ease;
-}
-
-.dropzone.active {
- border-color: #2196f3;
- background-color: rgba(33, 150, 243, 0.1);
-}
-
-.uploadIcon {
- font-size: 3rem;
- color: #666;
- margin-bottom: 1rem;
-}
-
-.dropzoneText {
- color: #666;
-}
-
-.dropzoneText p {
- margin: 0.5rem 0;
-}
-
-.browseButton {
- background-color: #2196f3;
- color: white;
- border: none;
- padding: 0.5rem 1rem;
- border-radius: 4px;
- cursor: pointer;
- margin-top: 0.5rem;
-}
-
-.browseButton:hover {
- background-color: #1976d2;
-}
-
-.selectedFile {
- margin-top: 1rem;
- padding: 1rem;
- background-color: #f5f5f5;
- border-radius: 4px;
-}
-
-.uploadButton {
- background-color: #4caf50;
- color: white;
- border: none;
- padding: 0.5rem 1rem;
- border-radius: 4px;
- cursor: pointer;
- margin-top: 0.5rem;
-}
-
-.uploadButton:hover {
- background-color: #388e3c;
-}
\ No newline at end of file
diff --git a/src/pages/Home/Dateien/DateienHinzufügen/DateienUpload.tsx b/src/pages/Home/Dateien/DateienHinzufügen/DateienUpload.tsx
deleted file mode 100644
index 29000b8..0000000
--- a/src/pages/Home/Dateien/DateienHinzufügen/DateienUpload.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import React, { useCallback, useState } from 'react';
-import { useDropzone } from 'react-dropzone';
-import styles from './DateienUpload.module.css';
-import { IoCloudUploadOutline } from "react-icons/io5";
-import { IoClose } from "react-icons/io5";
-
-interface DateienUploadProps {
- isOpen: boolean;
- onClose: () => void;
- onFileUpload: (file: File) => void;
-}
-
-function DateienUpload({ isOpen, onClose, onFileUpload }: DateienUploadProps) {
- const [selectedFile, setSelectedFile] = useState(null);
-
- const onDrop = useCallback((acceptedFiles: File[]) => {
- if (acceptedFiles.length > 0) {
- setSelectedFile(acceptedFiles[0]);
- }
- }, []);
-
- const { getRootProps, getInputProps, isDragActive } = useDropzone({
- onDrop,
- multiple: false
- });
-
- const handleUpload = () => {
- if (selectedFile) {
- onFileUpload(selectedFile);
- setSelectedFile(null);
- onClose();
- }
- };
-
- if (!isOpen) return null;
-
- return (
-
-
-
-
Datei hochladen
-
-
-
-
- {isDragActive ? (
-
Datei hier ablegen...
- ) : (
-
-
Dateien hierher ziehen
-
oder
-
-
- )}
-
-
- {selectedFile && (
-
-
Ausgewählte Datei: {selectedFile.name}
-
-
- )}
-
-
- );
-}
-
-export default DateienUpload;
\ No newline at end of file
diff --git a/src/pages/Home/Mitglieder/Mitglieder.module.css b/src/pages/Home/Mitglieder/Mitglieder.module.css
deleted file mode 100644
index b22b137..0000000
--- a/src/pages/Home/Mitglieder/Mitglieder.module.css
+++ /dev/null
@@ -1,85 +0,0 @@
-.mitgliederContainer {
- margin: 51px 49px 0 36px;
- display: flex;
- padding: 0px 30px 30px 30px;
- flex-direction: column;
- align-self: stretch;
- border-radius: 30px;
- border: 1px solid var(--f-1-f-1-f-1, #F1F1F1);
- background: var(--Grayscale-True-White, #FFF);
- position: relative;
- box-shadow: 0px 2px 6px 0px rgba(194, 194, 194, 0.10);
- max-height: calc(100vh - 100px);
- overflow: hidden;
-}
-
-.horizontalLineLight {
- width: 100%;
- background-color: #F1F1F1;
- height: 1px;
- margin-top: 90px;
- margin-left: -30px;
- position: absolute;
-}
-
-.header{
- display: flex;
- gap: 30px;
- align-items: flex-start;
- height: 62px;
- color: var(--Grayscale-Black, #24262B);
- padding-top: 30px;
- padding-bottom: 30px;
-}
-
-.mitglieder_hinzufügen_button {
-
- border-radius: 30px;
- background: var(--Grayscale-Gray, #E9E9E9);
-
- border: none;
- outline: none;
- text-align: left;
- padding-left: 20px;
- padding-right: 20px;
- padding-top: 10px;
- padding-bottom: 10px;
-
- display: flex;
- gap: 10px;
- align-items: center;
-}
-
-.mitglieder_hinzufügen_button:hover {
- cursor: pointer;
-}
-
-.add_icon {
- font-size: 16px;
-}
-
-.membersList {
- list-style: none;
- padding: 0;
- margin: 0;
- width: 100%;
- overflow-y: auto; /* Enable vertical scrolling */
- /* Space for the header line */
-}
-
-.membersList li {
- display: flex;
- align-items: center;
- height: 60px; /* Specific height for each item */
- padding: 0 16px;
- border-bottom: 1px solid #F1F1F1;
- font-size: 16px;
- transition: background-color 0.2s ease;
- }
-
-.actions {
- display: flex;
- gap: 10px;
- align-items: center;
- justify-content: center;
- }
\ No newline at end of file
diff --git a/src/pages/Home/Mitglieder/Mitglieder.tsx b/src/pages/Home/Mitglieder/Mitglieder.tsx
deleted file mode 100644
index b8060f0..0000000
--- a/src/pages/Home/Mitglieder/Mitglieder.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import styles from './Mitglieder.module.css'
-import { useOrgUsers } from '../../../auth/Hooks/get-all-users';
-import MitgliederItem from '../../../components/Mitglieder/MitgliederItem';
-import { IoPersonAddSharp } from "react-icons/io5";
-
-function Mitglieder () {
- const { users, loading, error, refetch } = useOrgUsers();
-
-
- return (
-
-
-
-
-
-
- {users.length === 0 ? (
-
No users found.
- ) : (
-
- {users.map(user => (
-
- ))}
-
- )}
-
-
- );
-}
-
-export default Mitglieder;
diff --git a/src/pages/Home/Organisation/Organisation.tsx b/src/pages/Home/Organisation/Organisation.tsx
deleted file mode 100644
index 6d6f1a8..0000000
--- a/src/pages/Home/Organisation/Organisation.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-function Organisation () {
-
-
- return(
-
-
Organisation
-
Hier sind die Infos über deine Organisation:
-
-
-
-
-
- )
-}
-
-export default Organisation;
diff --git a/src/pages/Home/index.ts b/src/pages/Home/index.ts
deleted file mode 100644
index bb0c3f5..0000000
--- a/src/pages/Home/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import Home from "./Home";
-
-export default Home;
\ No newline at end of file
diff --git a/src/pages/Login.module.css b/src/pages/Login.module.css
index 1cbf6cb..9cf55d6 100644
--- a/src/pages/Login.module.css
+++ b/src/pages/Login.module.css
@@ -1,108 +1,172 @@
.container {
display: flex;
- min-height: calc(100vh - 20pt);
- max-height: calc(100vh - 20pt);
- background: var(--Grayscale-True-White, #FFF);
- padding: 20pt;
- box-sizing: border-box;
+ min-height: 100vh;
+ background-color: #ffffff;
}
.leftPanel {
flex: 1;
display: flex;
flex-direction: column;
- justify-content: center;
- align-items: center;
- padding: 2rem;
- background-color: white;
- border-radius: 8px;
- margin-right: 20pt;
+ padding: 3rem;
+ background-color: #ffffff;
}
.rightPanel {
flex: 1;
+ background-color: #ffffff;
display: flex;
- justify-content: flex-end;
align-items: center;
+ justify-content: center;
}
.logo {
margin-bottom: 2rem;
- display: flex;
- justify-content: center;
- align-items: center;
}
.logo img {
height: 40px;
- width: auto;
}
.loginBox {
- width: 100%;
max-width: 400px;
- text-align: center;
+ margin: auto;
+ width: 100%;
}
.title {
font-size: 2rem;
- margin-bottom: 1.5rem;
- color: var(--Grayscale-Black, #24262B);
- font-family: Avenir, Helvetica, Arial, sans-serif;
+ font-weight: 600;
+ margin-bottom: 2rem;
+ color: #1a1a1a;
+}
+.loginForm {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.input {
+ width: 100%;
+ padding: 12px 16px;
+ border: 1px solid #e0e0e0;
+ border-radius: 8px;
+ font-size: 1rem;
+ transition: all 0.2s ease;
+ background-color: #ffffff;
+}
+
+.input:focus {
+ outline: none;
+ border-color: #0078d4;
+ box-shadow: 0 0 0 2px rgba(0, 120, 212, 0.1);
+}
+
+.input::placeholder {
+ color: #757575;
}
.button {
width: 100%;
- padding: 0.8rem;
- margin: 0.5rem 0;
- border: none;
- border-radius: 4px;
+ padding: 12px 20px;
+ border-radius: 8px;
font-size: 1rem;
+ font-weight: 500;
cursor: pointer;
- transition: all 0.3s ease;
+ transition: all 0.2s ease;
+ border: none;
+ text-align: center;
}
.primaryButton {
- background: var(--Brand-Purple-Purple, #5F59D4);
+ background-color: #0078d4;
color: white;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.primaryButton:hover {
+ background-color: #006cbd;
+}
+
+.microsoftButton {
+ background-color: #2f2f2f;
+ color: white;
+}
+
+.microsoftButton:hover {
+ background-color: #1f1f1f;
+}
+
+.divider {
+ display: flex;
+ align-items: center;
+ text-align: center;
+ margin: 1rem 0;
+}
+
+.divider::before,
+.divider::after {
+ content: '';
+ flex: 1;
+ border-bottom: 1px solid #e0e0e0;
+}
+
+.divider span {
+ padding: 0 1rem;
+ color: #757575;
+ font-size: 0.9rem;
+}
+
+.registerLink {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+ margin-top: 1rem;
+}
+
+.registerLink span {
+ color: #757575;
+ font-size: 0.9rem;
+}
+
+.textButton {
+ background: none;
+ border: none;
+ color: #0078d4;
+ font-weight: 500;
cursor: pointer;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
- transform: translateY(-1px);
+ padding: 0;
+ font-size: 0.9rem;
}
-.secondaryButton {
- background-color: #f0f0f0;
- color: #333;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+.textButton:hover {
+ text-decoration: underline;
}
-.secondaryButton:hover {
- background-color: #e0e0e0;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
- transform: translateY(-1px);
-}
-
-.button:disabled {
- background-color: #cccccc;
+button:disabled {
+ opacity: 0.7;
cursor: not-allowed;
}
.rightContent {
- max-width: 100%;
- height: 100%;
- display: flex;
- justify-content: flex-end;
- align-items: center;
+ max-width: 80%;
+ padding: 2rem;
}
.rightContent img {
- max-width: 100%;
- max-height: 100%;
- object-fit: contain;
+ width: 100%;
height: auto;
+ max-width: 500px;
+}
+
+.error {
+ color: #dc3545;
+ background-color: #f8d7da;
+ border: 1px solid #f5c6cb;
+ border-radius: 8px;
+ padding: 12px;
+ margin-bottom: 1rem;
+ font-size: 0.9rem;
+ text-align: center;
}
diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx
index 072380e..9aec3e4 100644
--- a/src/pages/Login.tsx
+++ b/src/pages/Login.tsx
@@ -5,37 +5,44 @@ import { useState, useEffect } from 'react';
import styles from './Login.module.css';
import agentDiagram from '../assets/Frame 43.png';
import logo from '../assets/LogoPowerOn.png';
+import { useAuth } from '../hooks/useAuth';
+import { useMsalAuth } from '../hooks/useMsalAuth';
function Login() {
const { instance, accounts, inProgress } = useMsal();
const navigate = useNavigate();
const location = useLocation();
- const [isLoggingIn, setIsLoggingIn] = useState(false);
+ const [username, setUsername] = useState('');
+ const [password, setPassword] = useState('');
+ const { login, error: loginError, isLoading: isLoginLoading } = useAuth();
+ const { loginWithMsal, error: msalError, isLoading: isMsalLoading } = useMsalAuth();
// Get the page the user was trying to visit
const from = location.state?.from?.pathname || "/";
useEffect(() => {
if (accounts.length > 0 && inProgress === "none") {
- console.log("User is already logged in, redirecting to:", from);
- setTimeout(() => {
- navigate(from, { replace: true });
- }, 300);
+ handleMsalLogin();
} else {
console.log("User not logged in or auth in progress:", inProgress);
}
- }, [accounts, inProgress, navigate, from]);
+ }, [accounts, inProgress]);
- const handleLoginRedirect = async () => {
- setIsLoggingIn(true);
+ const handleMsalLogin = async () => {
try {
- console.log("Starting login process...");
- // Use popup instead of redirect for easier debugging
- await instance.loginPopup(loginRequest);
- console.log("Login successful, auth should redirect shortly");
+ await loginWithMsal();
+ navigate(from, { replace: true });
+ } catch (error) {
+ console.error("MSAL login failed:", error);
+ }
+ };
+
+ const handleCredentialLogin = async () => {
+ try {
+ await login(username, password);
+ navigate(from, { replace: true });
} catch (error) {
console.error("Login failed:", error);
- setIsLoggingIn(false);
}
};
@@ -47,19 +54,55 @@ function Login() {
Sign In or Register Your Organisation
-
-
+
+
+ {(loginError || msalError) && (
+
{loginError || msalError}
+ )}
+
setUsername(e.target.value)}
+ className={styles.input}
+ />
+
setPassword(e.target.value)}
+ className={styles.input}
+ />
+
+
+
+ or continue with
+
+
+
+
+
+ Don't have an account?
+
+
+