From 50ec9b64fdbd19fcffe5fe8db91f5f4641d3db0e Mon Sep 17 00:00:00 2001 From: jpie02 <128189069+jpie02@users.noreply.github.com> Date: Thu, 8 Jan 2026 17:15:08 +0100 Subject: [PATCH 1/7] Change the default date to be the current date in the Readers section of the librarian dashboard. --- web_app/src/Librarian/LibrarianReaders.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web_app/src/Librarian/LibrarianReaders.tsx b/web_app/src/Librarian/LibrarianReaders.tsx index 0b538789..95c4ec7c 100644 --- a/web_app/src/Librarian/LibrarianReaders.tsx +++ b/web_app/src/Librarian/LibrarianReaders.tsx @@ -12,7 +12,7 @@ const LibrarianReaders: React.FC = () => { const [cardId, setCardId] = useState(''); const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); - const [expirationDate, setExpirationDate] = useState('2025-01-01'); + const [expirationDate, setExpirationDate] = useState(new Date().toLocaleDateString('en-CA')); const [libraryCardSearchId, setLibraryCardSearchId] = useState(''); // User @@ -65,7 +65,7 @@ const LibrarianReaders: React.FC = () => { setCardId(''); setFirstName(''); setLastName(''); - setExpirationDate('2025-01-01'); + setExpirationDate(new Date().toLocaleDateString('en-CA')); } else { throw new Error('Error creating library card'); } From 269c34be7646fc23d6e7f5afef448154f642725a Mon Sep 17 00:00:00 2001 From: jpie02 <128189069+jpie02@users.noreply.github.com> Date: Thu, 8 Jan 2026 17:36:31 +0100 Subject: [PATCH 2/7] Fix the success and error message display in the Readers and Returns tabs of the librarian dashboard. --- web_app/src/Librarian/LibrarianReaders.tsx | 40 +++++++++++++++++----- web_app/src/Librarian/LibrarianReturns.tsx | 6 ++-- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/web_app/src/Librarian/LibrarianReaders.tsx b/web_app/src/Librarian/LibrarianReaders.tsx index 95c4ec7c..a1e2d06c 100644 --- a/web_app/src/Librarian/LibrarianReaders.tsx +++ b/web_app/src/Librarian/LibrarianReaders.tsx @@ -28,6 +28,10 @@ const LibrarianReaders: React.FC = () => { const navigate = useNavigate(); + const [message, setMessage] = useState(null); + const [messageSearch, setMessageSearch] = useState(null); + const [messageType, setMessageType] = useState<'success' | 'error' | null>(null); + useWebSocketNotification('librarian/orders/pending', () => { toast.info("Otrzymano nowe zamówienie!", { position: "bottom-right", @@ -60,7 +64,8 @@ const LibrarianReaders: React.FC = () => { }); if (response.ok) { - alert('Library card created successfully'); + setMessage('Konto czytelnika zostało pomyślnie dodane.'); + setMessageType('success'); setUserId(''); setCardId(''); setFirstName(''); @@ -71,6 +76,8 @@ const LibrarianReaders: React.FC = () => { } } catch (error) { console.error('Error creating library card: ', error); + setMessage('Nastąpił błąd podczas dodawania czytelnika.'); + setMessageType('error'); } }; @@ -99,6 +106,8 @@ const LibrarianReaders: React.FC = () => { } catch (error) { console.error('Error searching for library card: ', error); setLibraryCardDetails(null); + setMessageSearch('Nie znaleziono czytelnika o podanym numerze ID.'); + setMessageType('error'); } }; @@ -221,6 +230,17 @@ const LibrarianReaders: React.FC = () => { + {message && ( +
+ {message} +
+ )} @@ -252,6 +272,17 @@ const LibrarianReaders: React.FC = () => { + {messageSearch && ( +
+ {messageSearch} +
+ )} {libraryCardDetails && ( @@ -268,13 +299,6 @@ const LibrarianReaders: React.FC = () => { )} - - {/*{activeSection === 'settings' && (*/} - {/*
*/} - {/*

Ustawienia

*/} - {/*
*/} - {/*)}*/} - ); diff --git a/web_app/src/Librarian/LibrarianReturns.tsx b/web_app/src/Librarian/LibrarianReturns.tsx index a885d8b7..300772cc 100644 --- a/web_app/src/Librarian/LibrarianReturns.tsx +++ b/web_app/src/Librarian/LibrarianReturns.tsx @@ -108,15 +108,15 @@ const LibrarianReturns: React.FC = () => { if (response.ok) { //setReturnStatus('COMPLETED'); - setMessage('Return completed successfully.'); + //setMessage('Return completed successfully.'); setMessageType('success'); } else { - setMessage('Failed to complete the return.'); + //setMessage('Failed to complete the return.'); setMessageType('error'); } } catch (error) { console.error('Error:', error); - setMessage('Error completing the return.'); + setMessage('Podczas realizacji zwrotu nastąpił błąd.'); setMessageType('error'); } }; From 454e0d4f998fc49240831b9f7b282ffb7aa82d49 Mon Sep 17 00:00:00 2001 From: jpie02 <128189069+jpie02@users.noreply.github.com> Date: Wed, 14 Jan 2026 11:17:06 +0100 Subject: [PATCH 3/7] Add client-side filtering to the librarian search. Add new message display for failed librarian searches in the Library Admin home page. --- .../src/LibraryAdmin/LibraryAdminHomePage.tsx | 85 ++++++++++--------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/web_app/src/LibraryAdmin/LibraryAdminHomePage.tsx b/web_app/src/LibraryAdmin/LibraryAdminHomePage.tsx index cd02983a..e414cb35 100644 --- a/web_app/src/LibraryAdmin/LibraryAdminHomePage.tsx +++ b/web_app/src/LibraryAdmin/LibraryAdminHomePage.tsx @@ -20,8 +20,10 @@ interface PasswordResetResponse { const LibraryAdminHomePage: React.FC = () => { const [usernameSearch, setUsernameSearch] = useState(''); - const [librarians, setLibrarians] = useState([]); + const [librarians, setLibrarians] = useState([]); // displayed list ("fake") + const [allLibrarians, setAllLibrarians] = useState([]); // master list ("real") const [message, setMessage] = useState(''); + const [notif, setNotif] = useState(''); const navigate = useNavigate(); @@ -31,12 +33,11 @@ const LibraryAdminHomePage: React.FC = () => { try { const response = await fetch(`${API_BASE_URL}/api/library-admins/librarians`, { method: 'GET', - headers: { - Authorization: `Bearer ${token}`, - }, + headers: { Authorization: `Bearer ${token}` }, }); if (response.ok) { const data = await response.json(); + setAllLibrarians(data); setLibrarians(data); setMessage(''); } else { @@ -47,38 +48,38 @@ const LibraryAdminHomePage: React.FC = () => { setMessage('Error fetching librarian list'); } }; + fetchAll(); + }, []); - if (usernameSearch.trim() === '') { - fetchAll(); + const handleSearch = () => { + const term = usernameSearch.trim().toLowerCase(); + + if (!term) { + setLibrarians(allLibrarians); + setMessage(''); + return; } - }, [usernameSearch]); - const fetchLibrarian = async () => { - const token = localStorage.getItem('access_token'); - if (!usernameSearch.trim()) return; + const filtered = allLibrarians.filter(lib => + lib.username.toLowerCase().includes(term) + ); - try { - const response = await fetch(`${API_BASE_URL}/api/library-admins/librarians?username=${usernameSearch}`, { - method: 'GET', - headers: { - Authorization: `Bearer ${token}`, - }, - }); + setLibrarians(filtered); - if (response.ok) { - const data = await response.json(); - setLibrarians(Array.isArray(data) ? data : [data]); - setMessage(''); - } else { - setLibrarians([]); - setMessage('Nie znaleziono bibliotekarza.'); - } - } catch (err) { - console.error(err); - setMessage('Error fetching librarian'); + if (filtered.length === 0) { + setNotif('Bibliotekarz o podanej nazwie użytkownika nie istnieje.'); + } else { + setNotif(''); } }; + useEffect(() => { + if (usernameSearch === '') { + setLibrarians(allLibrarians); + setMessage(''); + } + }, [usernameSearch, allLibrarians]); + const resetPassword = async (username: string) => { if (!window.confirm(`Czy na pewno chcesz zresetować hasło dla użytkownika "${username}"?`)) { return; @@ -121,14 +122,14 @@ const LibraryAdminHomePage: React.FC = () => { }, }); if (res.ok) { - setLibrarians(librarians.filter(lib => lib.username !== username)); + setAllLibrarians(prev => prev.filter(lib => lib.username !== username)); + setLibrarians(prev => prev.filter(lib => lib.username !== username)); + setMessage('Usunięto bibliotekarza o nazwie użytkownika ' + username + '.'); - } else { - setMessage('Nie udało się usunąć bibliotekarza.'); } } catch (err) { console.error(err); - setMessage('Error deleting librarian'); + setMessage('Usuwanie biblkiotekarza nie powiodło się.'); } }; @@ -184,20 +185,23 @@ const LibraryAdminHomePage: React.FC = () => { placeholder="Nazwa użytkownika" value={usernameSearch} onChange={(e) => setUsernameSearch(e.target.value)} + onKeyDown={(e) => e.key === 'Enter' && handleSearch()} className="w-full p-2 rounded-lg border-2 outline-none bg-white text-[#3b4248] focus:outline-none focus:ring-2 focus:ring-[#3B576C]" /> {usernameSearch && ( )} @@ -217,14 +221,12 @@ const LibraryAdminHomePage: React.FC = () => {
@@ -235,6 +237,7 @@ const LibraryAdminHomePage: React.FC = () => { )} {message &&

{message}

} + {notif &&

{notif}

} From a9ca2c193f7f3be5a9a9cc40e8e9bd4a3b61b81b Mon Sep 17 00:00:00 2001 From: jpie02 <128189069+jpie02@users.noreply.github.com> Date: Wed, 14 Jan 2026 11:35:41 +0100 Subject: [PATCH 4/7] Replaced JS alert() confirmation windows with SweetAlert2 notifications for the librarian account deletion and password reset functionalities. --- web_app/package.json | 3 +- .../src/LibraryAdmin/LibraryAdminHomePage.tsx | 34 ++++++++++++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/web_app/package.json b/web_app/package.json index c81d3bb5..15273324 100644 --- a/web_app/package.json +++ b/web_app/package.json @@ -17,7 +17,8 @@ "react-router-dom": "^7.0.2", "react-toastify": "^11.0.5", "swagger-ui": "^5.18.2", - "swagger-ui-react": "^5.18.2" + "swagger-ui-react": "^5.18.2", + "sweetalert2": "^11.26.17" }, "devDependencies": { "@eslint/js": "^9.13.0", diff --git a/web_app/src/LibraryAdmin/LibraryAdminHomePage.tsx b/web_app/src/LibraryAdmin/LibraryAdminHomePage.tsx index e414cb35..e6248a3f 100644 --- a/web_app/src/LibraryAdmin/LibraryAdminHomePage.tsx +++ b/web_app/src/LibraryAdmin/LibraryAdminHomePage.tsx @@ -1,5 +1,7 @@ import React, { useEffect, useState } from 'react'; import {Link, useNavigate} from "react-router-dom"; +import Swal from 'sweetalert2'; +import 'sweetalert2/dist/sweetalert2.min.css'; const API_BASE_URL = import.meta.env.VITE_API_BASE_URL; @@ -20,8 +22,8 @@ interface PasswordResetResponse { const LibraryAdminHomePage: React.FC = () => { const [usernameSearch, setUsernameSearch] = useState(''); - const [librarians, setLibrarians] = useState([]); // displayed list ("fake") - const [allLibrarians, setAllLibrarians] = useState([]); // master list ("real") + const [librarians, setLibrarians] = useState([]); // displayed list (filtered) + const [allLibrarians, setAllLibrarians] = useState([]); // master list (real) const [message, setMessage] = useState(''); const [notif, setNotif] = useState(''); @@ -81,7 +83,19 @@ const LibraryAdminHomePage: React.FC = () => { }, [usernameSearch, allLibrarians]); const resetPassword = async (username: string) => { - if (!window.confirm(`Czy na pewno chcesz zresetować hasło dla użytkownika "${username}"?`)) { + const result = await Swal.fire({ + title: 'Na pewno?', + text: `Czy na pewno chcesz zresetować hasło dla użytkownika "${username}"?`, + icon: 'warning', + showCancelButton: true, + confirmButtonColor: '#3B576C', + cancelButtonColor: '#d33', + confirmButtonText: 'Tak, zresetuj', + cancelButtonText: 'Anuluj' + }); + + // if cancelled + if (!result.isConfirmed) { return; } @@ -109,7 +123,19 @@ const LibraryAdminHomePage: React.FC = () => { }; const deleteLibrarian = async (username: string) => { - if (!window.confirm(`Czy na pewno chcesz konto użytkownika "${username}"? Tej operacji nie można cofnąć.`)) { + const result = await Swal.fire({ + title: 'Na pewno?', + text: `Czy na pewno chcesz usunąć konto użytkownika "${username}"? Tej operacji nie można cofnąć.`, + icon: 'warning', + showCancelButton: true, + confirmButtonColor: '#3B576C', + cancelButtonColor: '#d33', + confirmButtonText: 'Tak, usuń', + cancelButtonText: 'Anuluj' + }); + + // if cancelled + if (!result.isConfirmed) { return; } From 038302e6f138b9c0aa1a6a4e0b6b3a9abbec8cfa Mon Sep 17 00:00:00 2001 From: jpie02 <128189069+jpie02@users.noreply.github.com> Date: Wed, 14 Jan 2026 11:43:23 +0100 Subject: [PATCH 5/7] Replaced old on-the-page success/error messages for the librarian password reset/delete account functionalities with SweetAlert2 notifications. --- .../src/LibraryAdmin/LibraryAdminHomePage.tsx | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/web_app/src/LibraryAdmin/LibraryAdminHomePage.tsx b/web_app/src/LibraryAdmin/LibraryAdminHomePage.tsx index e6248a3f..8bf15f24 100644 --- a/web_app/src/LibraryAdmin/LibraryAdminHomePage.tsx +++ b/web_app/src/LibraryAdmin/LibraryAdminHomePage.tsx @@ -112,13 +112,48 @@ const LibraryAdminHomePage: React.FC = () => { const data: PasswordResetResponse = await res.json(); const newPassword = data.tempPassword; - setMessage(`Hasło zresetowane dla ${username}. Nowe hasło: ${newPassword}`); + const reset = await Swal.fire({ + title: 'Hasło zostało zresetowane', + text: `Hasło zresetowane dla ${username}. Nowe hasło: ${newPassword}`, + icon: 'info', + showCancelButton: false, + confirmButtonColor: '#3B576C', + confirmButtonText: 'OK', + }); + + if (!reset.isConfirmed) { + return; + } + } else { - setMessage('Nie udało się zresetować hasła bibliotekarza.'); + const reset = await Swal.fire({ + title: 'Nie udało się zresetować hasła', + text: `Spróbuj ponownie później.`, + icon: 'warning', + showCancelButton: false, + confirmButtonColor: '#3B576C', + confirmButtonText: 'OK', + }); + + if (!reset.isConfirmed) { + return; + } } } catch (err) { console.error(err); - setMessage('Error resetting password'); + + const reset = await Swal.fire({ + title: 'Nie udało się zresetować hasła', + text: `Spróbuj ponownie później.`, + icon: 'warning', + showCancelButton: false, + confirmButtonColor: '#3B576C', + confirmButtonText: 'OK', + }); + + if (!reset.isConfirmed) { + return; + } } }; From f306abcc03feb727112c8a3136a46c6afc7cf77d Mon Sep 17 00:00:00 2001 From: jpie02 <128189069+jpie02@users.noreply.github.com> Date: Wed, 14 Jan 2026 12:09:53 +0100 Subject: [PATCH 6/7] Increase the testing pagination limit of submission display from 1 to 5. --- web_app/src/SystemAdmin/SystemAdminHomePage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web_app/src/SystemAdmin/SystemAdminHomePage.tsx b/web_app/src/SystemAdmin/SystemAdminHomePage.tsx index 5e08e861..beff760d 100644 --- a/web_app/src/SystemAdmin/SystemAdminHomePage.tsx +++ b/web_app/src/SystemAdmin/SystemAdminHomePage.tsx @@ -113,7 +113,7 @@ const SystemAdminDashboard: React.FC = () => { if (data.length > 0) { setDriverApplications((prev) => [...prev, ...data]); - setDriverPage(page + 1); + setDriverPage(page + 5); } else { setDriverHasMore(false); } @@ -142,7 +142,7 @@ const SystemAdminDashboard: React.FC = () => { if (data.length > 0) { setLibraryRequests((prev) => [...prev, ...data]); - setLibraryPage(page + 1); + setLibraryPage(page + 5); } else { setLibraryHasMore(false); } From b3f02e4a42ba65ceb015b609b5396cec7d0a1041 Mon Sep 17 00:00:00 2001 From: jpie02 <128189069+jpie02@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:02:32 +0100 Subject: [PATCH 7/7] Fix the submission status error for the fetching of library and driver submission entries to include both PENDING and UNDER_REVIEW. --- .../src/SystemAdmin/SystemAdminHomePage.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/web_app/src/SystemAdmin/SystemAdminHomePage.tsx b/web_app/src/SystemAdmin/SystemAdminHomePage.tsx index beff760d..d266696e 100644 --- a/web_app/src/SystemAdmin/SystemAdminHomePage.tsx +++ b/web_app/src/SystemAdmin/SystemAdminHomePage.tsx @@ -97,7 +97,13 @@ const SystemAdminDashboard: React.FC = () => { } try { - const response = await fetch(`${API_BASE_URL}/api/driver-applications?statuses=PENDING,UNDER_REVIEW&page=${page}&size=1`, { + const params = new URLSearchParams(); + params.append('statuses', 'PENDING'); + params.append('statuses', 'UNDER_REVIEW'); + params.append('page', page.toString()); + params.append('size', '5'); + + const response = await fetch(`${API_BASE_URL}/api/driver-applications?${params.toString()}`, { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, @@ -128,7 +134,13 @@ const SystemAdminDashboard: React.FC = () => { if (!token) return; try { - const response = await fetch(`${API_BASE_URL}/api/library-requests?statuses=PENDING,UNDER_REVIEW&page=${page}&size=1`, { + const params = new URLSearchParams(); + params.append('statuses', 'PENDING'); + params.append('statuses', 'UNDER_REVIEW'); + params.append('page', page.toString()); + params.append('size', '5'); + + const response = await fetch(`${API_BASE_URL}/api/library-requests?${params.toString()}`, { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, @@ -142,7 +154,7 @@ const SystemAdminDashboard: React.FC = () => { if (data.length > 0) { setLibraryRequests((prev) => [...prev, ...data]); - setLibraryPage(page + 5); + setLibraryPage(page + 2); } else { setLibraryHasMore(false); }