+ className="absolute top-[25%] left-1/2 transform -translate-x-1/2 bg-white p-10 rounded-xl shadow-2xl w-[clamp(280px,30vw,400px)] h-[clamp(500px,55vh,90vh)]">
Logowanie
administratora systemów
diff --git a/web_app/src/SystemAdmin/SystemAdminSettings.tsx b/web_app/src/SystemAdmin/SystemAdminSettings.tsx
new file mode 100644
index 00000000..d0da3cde
--- /dev/null
+++ b/web_app/src/SystemAdmin/SystemAdminSettings.tsx
@@ -0,0 +1,147 @@
+import React, {useState} from 'react';
+import {useNavigate} from 'react-router-dom';
+
+const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
+
+const SystemAdminSettings: React.FC = () => {
+ const [oldPassword, setOldPassword] = useState('');
+ const [newPassword, setNewPassword] = useState('');
+ const [repeatPassword, setRepeatPassword] = useState('');
+ const [message, setMessage] = useState('');
+ const [error, setError] = useState('');
+
+ const handleChangePassword = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setMessage('');
+ setError('');
+
+ if (newPassword !== repeatPassword) {
+ setError('Hasła nie pasują do siebie.');
+ return;
+ }
+
+ try {
+ const token = localStorage.getItem('access_token');
+ if (!token) throw new Error('Brak tokenu autoryzacyjnego.');
+
+ const response = await fetch(`${API_BASE_URL}/api/users/change-password`, {
+ method: 'PUT',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${token}`,
+ },
+ body: JSON.stringify({
+ oldPassword,
+ newPassword,
+ }),
+ });
+
+ const text = await response.text();
+
+ if (!response.ok) {
+ const errorData = text ? JSON.parse(text) : { message: 'Błąd zmiany hasła' };
+ throw new Error(errorData.message);
+ }
+
+ setMessage('Hasło zostało zmienione.');
+ setOldPassword('');
+ setNewPassword('');
+ setRepeatPassword('');
+ } catch (err: unknown) {
+ if (err instanceof Error) {
+ setError(err.message);
+ } else {
+ setError('Wystąpił nieznany błąd.');
+ }
+ }
+ };
+
+ const navigate = useNavigate();
+
+ function handleReturn() {
+ navigate('/system-admin-dashboard');
+ }
+
+ return (
+
+
+
+

+
+
+
+
+ );
+};
+
+export default SystemAdminSettings;
From cee8615fba575ac0f83beaaef6b5180bca6ec235 Mon Sep 17 00:00:00 2001
From: jpie02 <128189069+jpie02@users.noreply.github.com>
Date: Mon, 22 Sep 2025 16:49:40 +0200
Subject: [PATCH 4/4] Fix the cloned useWebSocketNotification.tsx file issue.
---
web_app/src/Librarian/LibrarianAddBook.tsx | 4 +-
web_app/src/Librarian/LibrarianHomePage.tsx | 4 +-
web_app/src/Librarian/LibrarianOrders.tsx | 4 +-
web_app/src/Librarian/LibrarianReaders.tsx | 4 +-
web_app/src/Librarian/LibrarianReturns.tsx | 4 +-
web_app/src/Librarian/LibrarianSettings.tsx | 4 +-
.../src/LibraryAdmin/LibraryAdminSettings.tsx | 4 +-
.../src/SystemAdmin/SystemAdminHomePage.tsx | 17 ++++++
.../useWebSocketNewLibraryNotification.tsx | 57 -------------------
.../useWebSocketNotification.tsx} | 2 +-
10 files changed, 32 insertions(+), 72 deletions(-)
delete mode 100644 web_app/src/SystemAdmin/useWebSocketNewLibraryNotification.tsx
rename web_app/src/{Librarian/useWebSocketNewOrderNotification.tsx => Utils/useWebSocketNotification.tsx} (97%)
diff --git a/web_app/src/Librarian/LibrarianAddBook.tsx b/web_app/src/Librarian/LibrarianAddBook.tsx
index 490f718b..4898b6c3 100644
--- a/web_app/src/Librarian/LibrarianAddBook.tsx
+++ b/web_app/src/Librarian/LibrarianAddBook.tsx
@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
-import {useWebSocketNewOrderNotification} from './useWebSocketNewOrderNotification.tsx';
+import {useWebSocketNotification} from '../Utils/useWebSocketNotification.tsx';
import {toast} from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
@@ -86,7 +86,7 @@ const LibrarianAddBook: React.FC = () => {
fetchDropdownData();
}, []);
- useWebSocketNewOrderNotification('librarian/orders/pending', () => {
+ useWebSocketNotification('librarian/orders/pending', () => {
toast.info("Otrzymano nowe zamówienie!", {
position: "bottom-right",
});
diff --git a/web_app/src/Librarian/LibrarianHomePage.tsx b/web_app/src/Librarian/LibrarianHomePage.tsx
index f352a040..c8c16357 100644
--- a/web_app/src/Librarian/LibrarianHomePage.tsx
+++ b/web_app/src/Librarian/LibrarianHomePage.tsx
@@ -1,6 +1,6 @@
import React, {useEffect, useState, useRef} from 'react';
import {Link, useNavigate} from 'react-router-dom';
-import {useWebSocketNewOrderNotification} from './useWebSocketNewOrderNotification.tsx';
+import {useWebSocketNotification} from '../Utils/useWebSocketNotification.tsx';
import {toast} from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
@@ -135,7 +135,7 @@ const LibrarianHomePage: React.FC = () => {
return () => window.removeEventListener('scroll', handleScroll);
}, [isLoading, hasMore, page, isUserLibraryChecked]);
- useWebSocketNewOrderNotification('librarian/orders/pending', () => {
+ useWebSocketNotification('librarian/orders/pending', () => {
toast.info("Otrzymano nowe zamówienie!", {
position: "bottom-right",
});
diff --git a/web_app/src/Librarian/LibrarianOrders.tsx b/web_app/src/Librarian/LibrarianOrders.tsx
index c5afcee7..8f3505f4 100644
--- a/web_app/src/Librarian/LibrarianOrders.tsx
+++ b/web_app/src/Librarian/LibrarianOrders.tsx
@@ -1,6 +1,6 @@
import React, {useState, useEffect } from 'react';
import {Link, useNavigate} from 'react-router-dom';
-import {useWebSocketNewOrderNotification} from './useWebSocketNewOrderNotification.tsx';
+import {useWebSocketNotification} from '../Utils/useWebSocketNotification.tsx';
import {toast} from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
@@ -69,7 +69,7 @@ const LibrarianOrders: React.FC = () => {
const navigate = useNavigate();
- useWebSocketNewOrderNotification('librarian/orders/pending', () => {
+ useWebSocketNotification('librarian/orders/pending', () => {
toast.info("Otrzymano nowe zamówienie!", {
position: "bottom-right",
});
diff --git a/web_app/src/Librarian/LibrarianReaders.tsx b/web_app/src/Librarian/LibrarianReaders.tsx
index 806db30c..0b538789 100644
--- a/web_app/src/Librarian/LibrarianReaders.tsx
+++ b/web_app/src/Librarian/LibrarianReaders.tsx
@@ -1,6 +1,6 @@
import React, {useState} from 'react';
import {Link, useNavigate} from 'react-router-dom';
-import {useWebSocketNewOrderNotification} from './useWebSocketNewOrderNotification.tsx';
+import {useWebSocketNotification} from '../Utils/useWebSocketNotification.tsx';
import {toast} from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
@@ -28,7 +28,7 @@ const LibrarianReaders: React.FC = () => {
const navigate = useNavigate();
- useWebSocketNewOrderNotification('librarian/orders/pending', () => {
+ useWebSocketNotification('librarian/orders/pending', () => {
toast.info("Otrzymano nowe zamówienie!", {
position: "bottom-right",
});
diff --git a/web_app/src/Librarian/LibrarianReturns.tsx b/web_app/src/Librarian/LibrarianReturns.tsx
index 53e0ed9d..a885d8b7 100644
--- a/web_app/src/Librarian/LibrarianReturns.tsx
+++ b/web_app/src/Librarian/LibrarianReturns.tsx
@@ -1,6 +1,6 @@
import React, {useEffect, useState} from 'react';
import {Link, useNavigate} from 'react-router-dom';
-import {useWebSocketNewOrderNotification} from './useWebSocketNewOrderNotification.tsx';
+import {useWebSocketNotification} from '../Utils/useWebSocketNotification.tsx';
import {toast} from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
@@ -10,7 +10,7 @@ const LibrarianReturns: React.FC = () => {
const [message, setMessage] = useState
(null);
const [messageType, setMessageType] = useState<'success' | 'error' | null>(null);
- useWebSocketNewOrderNotification('librarian/orders/pending', () => {
+ useWebSocketNotification('librarian/orders/pending', () => {
toast.info("Otrzymano nowe zamówienie!", {
position: "bottom-right",
});
diff --git a/web_app/src/Librarian/LibrarianSettings.tsx b/web_app/src/Librarian/LibrarianSettings.tsx
index 11b5d8e7..db863552 100644
--- a/web_app/src/Librarian/LibrarianSettings.tsx
+++ b/web_app/src/Librarian/LibrarianSettings.tsx
@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import {Link, useNavigate} from 'react-router-dom';
-import {useWebSocketNewOrderNotification} from './useWebSocketNewOrderNotification.tsx';
+import {useWebSocketNotification} from '../Utils/useWebSocketNotification.tsx';
import {toast} from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
@@ -13,7 +13,7 @@ const LibrarianSettings: React.FC = () => {
const [message, setMessage] = useState('');
const [error, setError] = useState('');
- useWebSocketNewOrderNotification('librarian/orders/pending', () => {
+ useWebSocketNotification('librarian/orders/pending', () => {
toast.info("Otrzymano nowe zamówienie!", {
position: "bottom-right",
});
diff --git a/web_app/src/LibraryAdmin/LibraryAdminSettings.tsx b/web_app/src/LibraryAdmin/LibraryAdminSettings.tsx
index b0c0dd91..c0ff1afe 100644
--- a/web_app/src/LibraryAdmin/LibraryAdminSettings.tsx
+++ b/web_app/src/LibraryAdmin/LibraryAdminSettings.tsx
@@ -1,6 +1,6 @@
import React, {useState} from 'react';
import {Link, useNavigate} from 'react-router-dom';
-import {useWebSocketNewOrderNotification} from "../Librarian/useWebSocketNewOrderNotification.tsx";
+import {useWebSocketNotification} from "../Utils/useWebSocketNotification.tsx";
import {toast} from "react-toastify";
import 'react-toastify/dist/ReactToastify.css';
@@ -13,7 +13,7 @@ const LibraryAdminSettings: React.FC = () => {
const [message, setMessage] = useState('');
const [error, setError] = useState('');
- useWebSocketNewOrderNotification('librarian/orders/pending', () => {
+ useWebSocketNotification('librarian/orders/pending', () => {
toast.info("Otrzymano nowe zamówienie!", {
position: "bottom-right",
});
diff --git a/web_app/src/SystemAdmin/SystemAdminHomePage.tsx b/web_app/src/SystemAdmin/SystemAdminHomePage.tsx
index e3ed3474..97b83a15 100644
--- a/web_app/src/SystemAdmin/SystemAdminHomePage.tsx
+++ b/web_app/src/SystemAdmin/SystemAdminHomePage.tsx
@@ -1,5 +1,8 @@
import React, {useEffect, useRef, useState} from 'react';
import {useNavigate} from 'react-router-dom';
+import {useWebSocketNotification} from '../Utils/useWebSocketNotification.tsx';
+import {toast} from 'react-toastify';
+import 'react-toastify/dist/ReactToastify.css';
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
@@ -41,6 +44,20 @@ const SystemAdminDashboard: React.FC = () => {
const firstLoad = useRef(true);
+ useWebSocketNotification('system-administrator/library-requests/pending', () => {
+ toast.info("Otrzymano nowe zgłoszenie biblioteki!", {
+ position: "bottom-right",
+ });
+ console.log("New library request received!");
+ });
+
+ useWebSocketNotification('system-administrator/driver-requests/pending', () => {
+ toast.info("Otrzymano nowe zgłoszenie kierowcy!", {
+ position: "bottom-right",
+ });
+ console.log("New driver request received!");
+ });
+
const handleChangePassword = ()=> {
navigate('/system-admin-settings');
}
diff --git a/web_app/src/SystemAdmin/useWebSocketNewLibraryNotification.tsx b/web_app/src/SystemAdmin/useWebSocketNewLibraryNotification.tsx
deleted file mode 100644
index b0ccb047..00000000
--- a/web_app/src/SystemAdmin/useWebSocketNewLibraryNotification.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import { useEffect, useRef } from "react";
-
-export function useWebSocketNewLibraryNotification(
- channel: string,
- onMessage: (msg: string) => void
-) {
- const wsRef = useRef(null);
- const keepAliveRef = useRef(null);
-
- useEffect(() => {
- const token = localStorage.getItem("access_token");
- if (!token) return;
-
- const apiBaseUrl = import.meta.env.VITE_API_BASE_URL?.replace(/^https?:\/\//, "") || "localhost";
- const wsUrl = `wss://${apiBaseUrl}/ws?token=${encodeURIComponent(token)}&channel=${encodeURIComponent(channel)}`;
-
- console.log("Connecting to:", wsUrl);
-
- const ws = new WebSocket(wsUrl);
- wsRef.current = ws;
-
- ws.onopen = () => {
- console.log("WebSocket opened:", wsUrl);
-
- // Keep-alive ping for the established WS connection
- keepAliveRef.current = setInterval(() => {
- if (ws.readyState === WebSocket.OPEN) {
- ws.send("ping");
- }
- }, 30000);
- };
-
- ws.onmessage = (event) => {
- onMessage(event.data);
- };
-
- ws.onerror = (err) => {
- console.error("WebSocket error:", err);
- };
-
- ws.onclose = (event) => {
- console.warn("WebSocket closed", event);
- if (keepAliveRef.current) {
- clearInterval(keepAliveRef.current);
- }
- };
-
- return () => {
- console.log("Cleaning up WebSocket connection");
- if (keepAliveRef.current) {
- clearInterval(keepAliveRef.current);
- }
- ws.close();
- wsRef.current = null;
- };
- }, [channel]);
-}
diff --git a/web_app/src/Librarian/useWebSocketNewOrderNotification.tsx b/web_app/src/Utils/useWebSocketNotification.tsx
similarity index 97%
rename from web_app/src/Librarian/useWebSocketNewOrderNotification.tsx
rename to web_app/src/Utils/useWebSocketNotification.tsx
index f44ed0e3..649e3e85 100644
--- a/web_app/src/Librarian/useWebSocketNewOrderNotification.tsx
+++ b/web_app/src/Utils/useWebSocketNotification.tsx
@@ -1,6 +1,6 @@
import { useEffect, useRef } from "react";
-export function useWebSocketNewOrderNotification(
+export function useWebSocketNotification(
channel: string,
onMessage: (msg: string) => void
) {